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 <eiseljulian@gmail.com>2020-01-06 16:59:25 +0300
committerJulian Eisel <eiseljulian@gmail.com>2020-01-06 16:59:25 +0300
commitfcc6e94897a6891c73be00ac2cdfa268e95a3e4e (patch)
treecd8c241285e53ec9d02562bd20d47c5aa3b24bae
parentf426d3a00282650dc2976cd3cc1bf3a7439024b6 (diff)
parentd6cce8bc8e3bbe1226f18236eeb05c8966655c9f (diff)
Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside
-rw-r--r--CMakeLists.txt143
-rw-r--r--build_files/build_environment/CMakeLists.txt1
-rw-r--r--build_files/build_environment/cmake/harvest.cmake3
-rw-r--r--build_files/build_environment/cmake/usd.cmake101
-rw-r--r--build_files/build_environment/cmake/versions.cmake4
-rwxr-xr-xbuild_files/build_environment/install_deps.sh4
-rw-r--r--build_files/build_environment/patches/usd.diff111
-rw-r--r--build_files/buildbot/codesign/windows_code_signer.py2
-rw-r--r--build_files/buildbot/slave_pack.py25
-rw-r--r--build_files/cmake/Modules/FindUSD.cmake75
-rw-r--r--build_files/cmake/Modules/GTestTesting.cmake43
-rw-r--r--build_files/cmake/config/blender_developer.cmake3
-rw-r--r--build_files/cmake/config/blender_full.cmake21
-rw-r--r--build_files/cmake/config/blender_headless.cmake1
-rw-r--r--build_files/cmake/config/blender_lite.cmake12
-rw-r--r--build_files/cmake/config/blender_release.cmake21
-rw-r--r--build_files/cmake/config/bpy_module.cmake1
-rw-r--r--build_files/cmake/macros.cmake24
-rw-r--r--build_files/cmake/packaging.cmake2
-rw-r--r--build_files/cmake/platform/platform_apple.cmake11
-rw-r--r--build_files/cmake/platform/platform_unix.cmake8
-rw-r--r--build_files/cmake/platform/platform_win32.cmake27
-rw-r--r--build_files/cmake/platform/platform_win32_bundle_crt.cmake35
-rwxr-xr-xbuild_files/package_spec/build_archive.py10
-rw-r--r--doc/doxygen/doxygen.intern.h4
-rw-r--r--doc/python_api/sphinx_doc_gen.py1
-rw-r--r--extern/CMakeLists.txt4
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic.c17
-rw-r--r--extern/draco/CMakeLists.txt2
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc5
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/geometry_indices.h6
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/point_attribute.cc2
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/point_attribute.h4
-rw-r--r--extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector.h2
-rw-r--r--extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h9
-rw-r--r--extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc2
-rw-r--r--extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h17
-rw-r--r--extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc4
-rw-r--r--extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc6
-rw-r--r--extern/draco/dracoenc/src/draco/compression/decode.cc14
-rw-r--r--extern/draco/dracoenc/src/draco/compression/decode.h2
-rw-r--r--extern/draco/dracoenc/src/draco/compression/encode_base.h19
-rw-r--r--extern/draco/dracoenc/src/draco/compression/entropy/ans.h189
-rw-r--r--extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_coding.h4
-rw-r--r--extern/draco/dracoenc/src/draco/compression/expert_encode.cc10
-rw-r--r--extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc6
-rw-r--r--extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.h2
-rw-r--r--extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc16
-rw-r--r--extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h2
-rw-r--r--extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h2
-rw-r--r--extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.cc7
-rw-r--r--extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.h4
-rw-r--r--extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_test.cc4
-rw-r--r--extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.cc6
-rw-r--r--extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.h2
-rw-r--r--extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h5
-rw-r--r--extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h8
-rw-r--r--extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h2
-rw-r--r--extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.cc12
-rw-r--r--extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.cc13
-rw-r--r--extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.h2
-rw-r--r--extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc4
-rw-r--r--extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h2
-rw-r--r--extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc4
-rw-r--r--extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h2
-rw-r--r--extern/draco/dracoenc/src/draco/core/data_buffer.cc1
-rw-r--r--extern/draco/dracoenc/src/draco/core/draco_test_utils.cc2
-rw-r--r--extern/draco/dracoenc/src/draco/core/draco_test_utils.h5
-rw-r--r--extern/draco/dracoenc/src/draco/core/draco_types.cc17
-rw-r--r--extern/draco/dracoenc/src/draco/core/draco_types.h5
-rw-r--r--extern/draco/dracoenc/src/draco/core/draco_version.h2
-rw-r--r--extern/draco/dracoenc/src/draco/core/macros.h17
-rw-r--r--extern/draco/dracoenc/src/draco/core/math_utils.h2
-rw-r--r--extern/draco/dracoenc/src/draco/core/math_utils_test.cc3
-rw-r--r--extern/draco/dracoenc/src/draco/core/options.cc6
-rw-r--r--extern/draco/dracoenc/src/draco/core/options.h5
-rw-r--r--extern/draco/dracoenc/src/draco/core/status.h2
-rw-r--r--extern/draco/dracoenc/src/draco/core/status_or.h81
-rw-r--r--extern/draco/dracoenc/src/draco/core/status_test.cc4
-rw-r--r--extern/draco/dracoenc/src/draco/core/vector_d.h173
-rw-r--r--extern/draco/dracoenc/src/draco/core/vector_d_test.cc72
-rw-r--r--extern/draco/dracoenc/src/draco/io/mesh_io.cc33
-rw-r--r--extern/draco/dracoenc/src/draco/io/mesh_io.h8
-rw-r--r--extern/draco/dracoenc/src/draco/io/obj_decoder.cc48
-rw-r--r--extern/draco/dracoenc/src/draco/io/obj_encoder.h2
-rw-r--r--extern/draco/dracoenc/src/draco/io/parser_utils.cc2
-rw-r--r--extern/draco/dracoenc/src/draco/io/ply_decoder.cc76
-rw-r--r--extern/draco/dracoenc/src/draco/io/ply_decoder.h18
-rw-r--r--extern/draco/dracoenc/src/draco/io/ply_decoder_test.cc5
-rw-r--r--extern/draco/dracoenc/src/draco/io/ply_reader.cc60
-rw-r--r--extern/draco/dracoenc/src/draco/io/ply_reader.h11
-rw-r--r--extern/draco/dracoenc/src/draco/io/ply_reader_test.cc15
-rw-r--r--extern/draco/dracoenc/src/draco/io/point_cloud_io.cc7
-rw-r--r--extern/draco/dracoenc/src/draco/mesh/corner_table.cc107
-rw-r--r--extern/draco/dracoenc/src/draco/mesh/corner_table.h9
-rw-r--r--extern/draco/dracoenc/src/draco/mesh/mesh.cc2
-rw-r--r--extern/draco/dracoenc/src/draco/mesh/mesh.h6
-rw-r--r--extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.h19
-rw-r--r--extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.cc4
-rw-r--r--extern/draco/dracoenc/src/draco/metadata/metadata.h28
-rw-r--r--extern/draco/dracoenc/src/draco/metadata/metadata_encoder.cc7
-rw-r--r--extern/draco/dracoenc/src/draco/metadata/metadata_encoder_test.cc6
-rw-r--r--extern/draco/dracoenc/src/draco/point_cloud/point_cloud.cc31
-rw-r--r--extern/draco/dracoenc/src/draco/point_cloud/point_cloud.h15
-rw-r--r--extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.cc6
-rw-r--r--extern/draco/dracoenc/src/draco/tools/draco_decoder.cc6
-rw-r--r--extern/draco/dracoenc/src/draco/tools/draco_encoder.cc2
-rw-r--r--extern/draco/src/draco-compressor.cpp362
-rw-r--r--extern/draco/src/draco-compressor.h173
-rw-r--r--extern/mantaflow/CMakeLists.txt211
-rw-r--r--extern/mantaflow/LICENSE222
-rw-r--r--extern/mantaflow/README.md11
-rw-r--r--extern/mantaflow/UPDATE.sh102
-rw-r--r--extern/mantaflow/dependencies/cnpy/LICENSE21
-rw-r--r--extern/mantaflow/dependencies/cnpy/cnpy.cpp385
-rw-r--r--extern/mantaflow/dependencies/cnpy/cnpy.h310
-rw-r--r--extern/mantaflow/helper/pwrapper/manta.h31
-rw-r--r--extern/mantaflow/helper/pwrapper/numpyWrap.cpp132
-rw-r--r--extern/mantaflow/helper/pwrapper/numpyWrap.h86
-rw-r--r--extern/mantaflow/helper/pwrapper/pclass.cpp220
-rw-r--r--extern/mantaflow/helper/pwrapper/pclass.h126
-rw-r--r--extern/mantaflow/helper/pwrapper/pconvert.cpp568
-rw-r--r--extern/mantaflow/helper/pwrapper/pconvert.h251
-rw-r--r--extern/mantaflow/helper/pwrapper/pvec3.cpp414
-rw-r--r--extern/mantaflow/helper/pwrapper/pythonInclude.h48
-rw-r--r--extern/mantaflow/helper/pwrapper/registry.cpp784
-rw-r--r--extern/mantaflow/helper/pwrapper/registry.h106
-rw-r--r--extern/mantaflow/helper/util/integrator.h79
-rw-r--r--extern/mantaflow/helper/util/interpol.h324
-rw-r--r--extern/mantaflow/helper/util/interpolHigh.h204
-rw-r--r--extern/mantaflow/helper/util/matrixbase.h394
-rw-r--r--extern/mantaflow/helper/util/mcubes.h308
-rw-r--r--extern/mantaflow/helper/util/quaternion.h103
-rw-r--r--extern/mantaflow/helper/util/randomstream.h429
-rw-r--r--extern/mantaflow/helper/util/rcmatrix.h1112
-rw-r--r--extern/mantaflow/helper/util/simpleimage.cpp312
-rw-r--r--extern/mantaflow/helper/util/simpleimage.h205
-rw-r--r--extern/mantaflow/helper/util/solvana.h214
-rw-r--r--extern/mantaflow/helper/util/vector4d.cpp50
-rw-r--r--extern/mantaflow/helper/util/vector4d.h515
-rw-r--r--extern/mantaflow/helper/util/vectorbase.cpp49
-rw-r--r--extern/mantaflow/helper/util/vectorbase.h679
-rw-r--r--extern/mantaflow/preprocessed/commonkernels.h1300
-rw-r--r--extern/mantaflow/preprocessed/commonkernels.h.reg.cpp13
-rw-r--r--extern/mantaflow/preprocessed/conjugategrad.cpp719
-rw-r--r--extern/mantaflow/preprocessed/conjugategrad.h479
-rw-r--r--extern/mantaflow/preprocessed/conjugategrad.h.reg.cpp13
-rw-r--r--extern/mantaflow/preprocessed/edgecollapse.cpp700
-rw-r--r--extern/mantaflow/preprocessed/edgecollapse.h51
-rw-r--r--extern/mantaflow/preprocessed/edgecollapse.h.reg.cpp13
-rw-r--r--extern/mantaflow/preprocessed/fastmarch.cpp1200
-rw-r--r--extern/mantaflow/preprocessed/fastmarch.h241
-rw-r--r--extern/mantaflow/preprocessed/fastmarch.h.reg.cpp13
-rw-r--r--extern/mantaflow/preprocessed/fileio/iogrids.cpp1524
-rw-r--r--extern/mantaflow/preprocessed/fileio/iomeshes.cpp490
-rw-r--r--extern/mantaflow/preprocessed/fileio/ioparticles.cpp342
-rw-r--r--extern/mantaflow/preprocessed/fileio/mantaio.h81
-rw-r--r--extern/mantaflow/preprocessed/fileio/mantaio.h.reg.cpp13
-rw-r--r--extern/mantaflow/preprocessed/fluidsolver.cpp397
-rw-r--r--extern/mantaflow/preprocessed/fluidsolver.h395
-rw-r--r--extern/mantaflow/preprocessed/fluidsolver.h.reg.cpp70
-rw-r--r--extern/mantaflow/preprocessed/general.cpp167
-rw-r--r--extern/mantaflow/preprocessed/general.h247
-rw-r--r--extern/mantaflow/preprocessed/general.h.reg.cpp13
-rw-r--r--extern/mantaflow/preprocessed/gitinfo.h3
-rw-r--r--extern/mantaflow/preprocessed/grid.cpp2939
-rw-r--r--extern/mantaflow/preprocessed/grid.h2260
-rw-r--r--extern/mantaflow/preprocessed/grid.h.reg.cpp246
-rw-r--r--extern/mantaflow/preprocessed/grid4d.cpp1798
-rw-r--r--extern/mantaflow/preprocessed/grid4d.h1558
-rw-r--r--extern/mantaflow/preprocessed/grid4d.h.reg.cpp204
-rw-r--r--extern/mantaflow/preprocessed/kernel.cpp61
-rw-r--r--extern/mantaflow/preprocessed/kernel.h99
-rw-r--r--extern/mantaflow/preprocessed/kernel.h.reg.cpp13
-rw-r--r--extern/mantaflow/preprocessed/levelset.cpp876
-rw-r--r--extern/mantaflow/preprocessed/levelset.h245
-rw-r--r--extern/mantaflow/preprocessed/levelset.h.reg.cpp32
-rw-r--r--extern/mantaflow/preprocessed/mesh.cpp2733
-rw-r--r--extern/mantaflow/preprocessed/mesh.h1690
-rw-r--r--extern/mantaflow/preprocessed/mesh.h.reg.cpp239
-rw-r--r--extern/mantaflow/preprocessed/movingobs.cpp112
-rw-r--r--extern/mantaflow/preprocessed/movingobs.h164
-rw-r--r--extern/mantaflow/preprocessed/movingobs.h.reg.cpp26
-rw-r--r--extern/mantaflow/preprocessed/multigrid.cpp1857
-rw-r--r--extern/mantaflow/preprocessed/multigrid.h186
-rw-r--r--extern/mantaflow/preprocessed/multigrid.h.reg.cpp13
-rw-r--r--extern/mantaflow/preprocessed/noisefield.cpp325
-rw-r--r--extern/mantaflow/preprocessed/noisefield.h635
-rw-r--r--extern/mantaflow/preprocessed/noisefield.h.reg.cpp60
-rw-r--r--extern/mantaflow/preprocessed/particle.cpp1620
-rw-r--r--extern/mantaflow/preprocessed/particle.h2582
-rw-r--r--extern/mantaflow/preprocessed/particle.h.reg.cpp437
-rw-r--r--extern/mantaflow/preprocessed/plugin/advection.cpp1521
-rw-r--r--extern/mantaflow/preprocessed/plugin/apic.cpp496
-rw-r--r--extern/mantaflow/preprocessed/plugin/extforces.cpp1559
-rw-r--r--extern/mantaflow/preprocessed/plugin/fire.cpp435
-rw-r--r--extern/mantaflow/preprocessed/plugin/flip.cpp2819
-rw-r--r--extern/mantaflow/preprocessed/plugin/fluidguiding.cpp802
-rw-r--r--extern/mantaflow/preprocessed/plugin/initplugins.cpp2317
-rw-r--r--extern/mantaflow/preprocessed/plugin/kepsilon.cpp578
-rw-r--r--extern/mantaflow/preprocessed/plugin/meshplugins.cpp780
-rw-r--r--extern/mantaflow/preprocessed/plugin/pressure.cpp1511
-rw-r--r--extern/mantaflow/preprocessed/plugin/ptsplugins.cpp502
-rw-r--r--extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp3065
-rw-r--r--extern/mantaflow/preprocessed/plugin/surfaceturbulence.cpp2189
-rw-r--r--extern/mantaflow/preprocessed/plugin/vortexplugins.cpp695
-rw-r--r--extern/mantaflow/preprocessed/plugin/waveletturbulence.cpp1292
-rw-r--r--extern/mantaflow/preprocessed/plugin/waves.cpp483
-rw-r--r--extern/mantaflow/preprocessed/python/defines.py11
-rw-r--r--extern/mantaflow/preprocessed/python/defines.py.reg.cpp24
-rw-r--r--extern/mantaflow/preprocessed/registration.cpp382
-rw-r--r--extern/mantaflow/preprocessed/shapes.cpp1010
-rw-r--r--extern/mantaflow/preprocessed/shapes.h665
-rw-r--r--extern/mantaflow/preprocessed/shapes.h.reg.cpp73
-rw-r--r--extern/mantaflow/preprocessed/test.cpp133
-rw-r--r--extern/mantaflow/preprocessed/timing.cpp128
-rw-r--r--extern/mantaflow/preprocessed/timing.h157
-rw-r--r--extern/mantaflow/preprocessed/timing.h.reg.cpp24
-rw-r--r--extern/mantaflow/preprocessed/turbulencepart.cpp288
-rw-r--r--extern/mantaflow/preprocessed/turbulencepart.h210
-rw-r--r--extern/mantaflow/preprocessed/turbulencepart.h.reg.cpp89
-rw-r--r--extern/mantaflow/preprocessed/vortexpart.cpp251
-rw-r--r--extern/mantaflow/preprocessed/vortexpart.h138
-rw-r--r--extern/mantaflow/preprocessed/vortexpart.h.reg.cpp76
-rw-r--r--extern/mantaflow/preprocessed/vortexsheet.cpp116
-rw-r--r--extern/mantaflow/preprocessed/vortexsheet.h251
-rw-r--r--extern/mantaflow/preprocessed/vortexsheet.h.reg.cpp26
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt2
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake2
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt1
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt1
-rw-r--r--intern/CMakeLists.txt12
-rw-r--r--intern/cycles/blender/addon/engine.py124
-rw-r--r--intern/cycles/blender/addon/operators.py32
-rw-r--r--intern/cycles/blender/addon/properties.py38
-rw-r--r--intern/cycles/blender/addon/ui.py40
-rw-r--r--intern/cycles/blender/blender_mesh.cpp21
-rw-r--r--intern/cycles/blender/blender_session.cpp59
-rw-r--r--intern/cycles/blender/blender_session.h2
-rw-r--r--intern/cycles/blender/blender_shader.cpp24
-rw-r--r--intern/cycles/blender/blender_sync.cpp34
-rw-r--r--intern/cycles/blender/blender_util.h65
-rw-r--r--intern/cycles/bvh/bvh_optix.cpp2
-rw-r--r--intern/cycles/device/device.h2
-rw-r--r--intern/cycles/device/device_memory.cpp25
-rw-r--r--intern/cycles/device/device_memory.h12
-rw-r--r--intern/cycles/device/device_multi.cpp12
-rw-r--r--intern/cycles/device/device_optix.cpp155
-rw-r--r--intern/cycles/device/opencl/memory_manager.cpp2
-rw-r--r--intern/cycles/device/opencl/opencl.h1
-rw-r--r--intern/cycles/device/opencl/opencl_split.cpp19
-rw-r--r--intern/cycles/kernel/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h35
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h12
-rw-r--r--intern/cycles/kernel/kernel_accumulate.h146
-rw-r--r--intern/cycles/kernel/kernel_bake.h20
-rw-r--r--intern/cycles/kernel/kernel_compat_opencl.h2
-rw-r--r--intern/cycles/kernel/kernel_emission.h23
-rw-r--r--intern/cycles/kernel/kernel_passes.h86
-rw-r--r--intern/cycles/kernel/kernel_path.h29
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h10
-rw-r--r--intern/cycles/kernel/kernel_path_surface.h12
-rw-r--r--intern/cycles/kernel/kernel_path_volume.h4
-rw-r--r--intern/cycles/kernel/kernel_shader.h7
-rw-r--r--intern/cycles/kernel/kernel_shadow.h2
-rw-r--r--intern/cycles/kernel/kernel_subsurface.h2
-rw-r--r--intern/cycles/kernel/kernel_types.h9
-rw-r--r--intern/cycles/kernel/kernel_volume.h4
-rw-r--r--intern/cycles/kernel/kernel_write_passes.h95
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp1
-rw-r--r--intern/cycles/kernel/shaders/node_clamp.osl8
-rw-r--r--intern/cycles/kernel/shaders/node_image_texture.osl19
-rw-r--r--intern/cycles/kernel/shaders/node_map_range.osl33
-rw-r--r--intern/cycles/kernel/shaders/node_math.osl62
-rw-r--r--intern/cycles/kernel/shaders/node_noise_texture.osl20
-rw-r--r--intern/cycles/kernel/shaders/node_wave_texture.osl2
-rw-r--r--intern/cycles/kernel/split/kernel_branched.h2
-rw-r--r--intern/cycles/kernel/split/kernel_buffer_update.h2
-rw-r--r--intern/cycles/kernel/split/kernel_indirect_background.h4
-rw-r--r--intern/cycles/kernel/split/kernel_path_init.h3
-rw-r--r--intern/cycles/kernel/split/kernel_shader_eval.h4
-rw-r--r--intern/cycles/kernel/split/kernel_shadow_blocked_dl.h2
-rw-r--r--intern/cycles/kernel/svm/svm.h15
-rw-r--r--intern/cycles/kernel/svm/svm_aov.h49
-rw-r--r--intern/cycles/kernel/svm/svm_bevel.h2
-rw-r--r--intern/cycles/kernel/svm/svm_clamp.h11
-rw-r--r--intern/cycles/kernel/svm/svm_image.h53
-rw-r--r--intern/cycles/kernel/svm/svm_map_range.h38
-rw-r--r--intern/cycles/kernel/svm/svm_math.h7
-rw-r--r--intern/cycles/kernel/svm/svm_math_util.h34
-rw-r--r--intern/cycles/kernel/svm/svm_noisetex.h20
-rw-r--r--intern/cycles/kernel/svm/svm_types.h37
-rw-r--r--intern/cycles/kernel/svm/svm_wave.h2
-rw-r--r--intern/cycles/render/buffers.cpp14
-rw-r--r--intern/cycles/render/buffers.h8
-rw-r--r--intern/cycles/render/film.cpp76
-rw-r--r--intern/cycles/render/film.h3
-rw-r--r--intern/cycles/render/graph.cpp35
-rw-r--r--intern/cycles/render/graph.h5
-rw-r--r--intern/cycles/render/image.cpp2
-rw-r--r--intern/cycles/render/image.h2
-rw-r--r--intern/cycles/render/integrator.cpp7
-rw-r--r--intern/cycles/render/light.cpp3
-rw-r--r--intern/cycles/render/mesh.cpp51
-rw-r--r--intern/cycles/render/mesh.h3
-rw-r--r--intern/cycles/render/mesh_subdivision.cpp2
-rw-r--r--intern/cycles/render/nodes.cpp424
-rw-r--r--intern/cycles/render/nodes.h44
-rw-r--r--intern/cycles/render/osl.cpp15
-rw-r--r--intern/cycles/render/osl.h8
-rw-r--r--intern/cycles/render/scene.h3
-rw-r--r--intern/cycles/render/shader.cpp7
-rw-r--r--intern/cycles/render/svm.cpp80
-rw-r--r--intern/cycles/render/svm.h14
-rw-r--r--intern/cycles/util/util_math.h44
-rw-r--r--intern/elbeem/CMakeLists.txt130
-rw-r--r--intern/elbeem/COPYING358
-rw-r--r--intern/elbeem/COPYING_trimesh2303
-rw-r--r--intern/elbeem/extern/elbeem.h273
-rw-r--r--intern/elbeem/intern/attributes.cpp362
-rw-r--r--intern/elbeem/intern/attributes.h248
-rw-r--r--intern/elbeem/intern/controlparticles.cpp1465
-rw-r--r--intern/elbeem/intern/controlparticles.h327
-rw-r--r--intern/elbeem/intern/elbeem.cpp430
-rw-r--r--intern/elbeem/intern/elbeem_control.cpp28
-rw-r--r--intern/elbeem/intern/elbeem_control.h65
-rw-r--r--intern/elbeem/intern/globals.h10
-rw-r--r--intern/elbeem/intern/isosurface.cpp1122
-rw-r--r--intern/elbeem/intern/isosurface.h244
-rw-r--r--intern/elbeem/intern/loop_tools.h186
-rw-r--r--intern/elbeem/intern/mcubes_tables.h300
-rw-r--r--intern/elbeem/intern/mvmcoords.cpp205
-rw-r--r--intern/elbeem/intern/mvmcoords.h108
-rw-r--r--intern/elbeem/intern/ntl_blenderdumper.cpp270
-rw-r--r--intern/elbeem/intern/ntl_blenderdumper.h42
-rw-r--r--intern/elbeem/intern/ntl_bsptree.cpp945
-rw-r--r--intern/elbeem/intern/ntl_bsptree.h135
-rw-r--r--intern/elbeem/intern/ntl_geometryclass.h127
-rw-r--r--intern/elbeem/intern/ntl_geometrymodel.cpp477
-rw-r--r--intern/elbeem/intern/ntl_geometrymodel.h104
-rw-r--r--intern/elbeem/intern/ntl_geometryobject.cpp806
-rw-r--r--intern/elbeem/intern/ntl_geometryobject.h255
-rw-r--r--intern/elbeem/intern/ntl_geometryshader.h73
-rw-r--r--intern/elbeem/intern/ntl_lighting.cpp184
-rw-r--r--intern/elbeem/intern/ntl_lighting.h254
-rw-r--r--intern/elbeem/intern/ntl_matrices.h790
-rw-r--r--intern/elbeem/intern/ntl_ray.cpp915
-rw-r--r--intern/elbeem/intern/ntl_ray.h438
-rw-r--r--intern/elbeem/intern/ntl_vector3dim.h1105
-rw-r--r--intern/elbeem/intern/ntl_world.cpp934
-rw-r--r--intern/elbeem/intern/ntl_world.h411
-rw-r--r--intern/elbeem/intern/paraloopend.h45
-rw-r--r--intern/elbeem/intern/parametrizer.cpp597
-rw-r--r--intern/elbeem/intern/parametrizer.h322
-rw-r--r--intern/elbeem/intern/particletracer.cpp470
-rw-r--r--intern/elbeem/intern/particletracer.h296
-rw-r--r--intern/elbeem/intern/simulation_object.cpp471
-rw-r--r--intern/elbeem/intern/simulation_object.h206
-rw-r--r--intern/elbeem/intern/solver_adap.cpp1281
-rw-r--r--intern/elbeem/intern/solver_class.h1036
-rw-r--r--intern/elbeem/intern/solver_control.cpp876
-rw-r--r--intern/elbeem/intern/solver_control.h199
-rw-r--r--intern/elbeem/intern/solver_init.cpp2396
-rw-r--r--intern/elbeem/intern/solver_interface.cpp753
-rw-r--r--intern/elbeem/intern/solver_interface.h639
-rw-r--r--intern/elbeem/intern/solver_main.cpp1723
-rw-r--r--intern/elbeem/intern/solver_relax.h1169
-rw-r--r--intern/elbeem/intern/solver_util.cpp1753
-rw-r--r--intern/elbeem/intern/utilities.cpp498
-rw-r--r--intern/elbeem/intern/utilities.h205
-rw-r--r--intern/ghost/GHOST_Types.h1
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm2
-rw-r--r--intern/ghost/intern/GHOST_EventPrinter.cpp3
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm3
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp1
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp14
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp1
-rw-r--r--intern/mantaflow/CMakeLists.txt67
-rw-r--r--intern/mantaflow/extern/manta_fluid_API.h226
-rw-r--r--intern/mantaflow/extern/manta_python_API.h (renamed from intern/elbeem/extern/LBM_fluidsim.h)22
-rw-r--r--intern/mantaflow/intern/MANTA_main.cpp2670
-rw-r--r--intern/mantaflow/intern/MANTA_main.h844
-rw-r--r--intern/mantaflow/intern/manta_fluid_API.cpp866
-rw-r--r--intern/mantaflow/intern/manta_python_API.cpp30
-rw-r--r--intern/mantaflow/intern/strings/fluid_script.h799
-rw-r--r--intern/mantaflow/intern/strings/liquid_script.h455
-rw-r--r--intern/mantaflow/intern/strings/smoke_script.h575
-rw-r--r--intern/opencolorio/gpu_shader_display_transform.glsl10
-rw-r--r--intern/opencolorio/ocio_capi.h6
-rw-r--r--intern/opencolorio/ocio_impl_glsl.cc4
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc5
-rw-r--r--intern/smoke/CMakeLists.txt99
-rw-r--r--intern/smoke/extern/smoke_API.h111
-rw-r--r--intern/smoke/intern/EIGENVALUE_HELPER.cpp888
-rw-r--r--intern/smoke/intern/EIGENVALUE_HELPER.h77
-rw-r--r--intern/smoke/intern/FFT_NOISE.h183
-rw-r--r--intern/smoke/intern/FLUID_3D.cpp1792
-rw-r--r--intern/smoke/intern/FLUID_3D.h269
-rw-r--r--intern/smoke/intern/FLUID_3D_SOLVERS.cpp328
-rw-r--r--intern/smoke/intern/FLUID_3D_STATIC.cpp646
-rw-r--r--intern/smoke/intern/IMAGE.h289
-rw-r--r--intern/smoke/intern/INTERPOLATE.h230
-rw-r--r--intern/smoke/intern/LICENSE.txt674
-rw-r--r--intern/smoke/intern/LU_HELPER.cpp139
-rw-r--r--intern/smoke/intern/LU_HELPER.h54
-rw-r--r--intern/smoke/intern/MERSENNETWISTER.h432
-rw-r--r--intern/smoke/intern/Makefile.FFT22
-rw-r--r--intern/smoke/intern/Makefile.cygwin23
-rw-r--r--intern/smoke/intern/Makefile.linux23
-rw-r--r--intern/smoke/intern/Makefile.mac35
-rw-r--r--intern/smoke/intern/OBSTACLE.h46
-rw-r--r--intern/smoke/intern/SPHERE.cpp53
-rw-r--r--intern/smoke/intern/SPHERE.h44
-rw-r--r--intern/smoke/intern/VEC3.h991
-rw-r--r--intern/smoke/intern/WAVELET_NOISE.h519
-rw-r--r--intern/smoke/intern/WTURBULENCE.cpp1198
-rw-r--r--intern/smoke/intern/WTURBULENCE.h150
-rw-r--r--intern/smoke/intern/smoke_API.cpp495
-rw-r--r--intern/smoke/intern/tnt/jama_eig.h1053
-rw-r--r--intern/smoke/intern/tnt/jama_lu.h322
-rw-r--r--intern/smoke/intern/tnt/tnt.h67
-rw-r--r--intern/smoke/intern/tnt/tnt_array1d.h281
-rw-r--r--intern/smoke/intern/tnt/tnt_array1d_utils.h233
-rw-r--r--intern/smoke/intern/tnt/tnt_array2d.h318
-rw-r--r--intern/smoke/intern/tnt/tnt_array2d_utils.h290
-rw-r--r--intern/smoke/intern/tnt/tnt_array3d.h299
-rw-r--r--intern/smoke/intern/tnt/tnt_array3d_utils.h239
-rw-r--r--intern/smoke/intern/tnt/tnt_cmat.h583
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array1d.h270
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array1d_utils.h245
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array2d.h228
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array2d_utils.h239
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array3d.h226
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array3d_utils.h252
-rw-r--r--intern/smoke/intern/tnt/tnt_i_refvec.h246
-rw-r--r--intern/smoke/intern/tnt/tnt_math_utils.h35
-rw-r--r--intern/smoke/intern/tnt/tnt_sparse_matrix_csr.h106
-rw-r--r--intern/smoke/intern/tnt/tnt_stopwatch.h98
-rw-r--r--intern/smoke/intern/tnt/tnt_subscript.h57
-rw-r--r--intern/smoke/intern/tnt/tnt_vec.h407
-rw-r--r--intern/smoke/intern/tnt/tnt_version.h42
-rw-r--r--release/darwin/Blender.app/Contents/Info.plist2
-rw-r--r--release/darwin/README.txt7
-rwxr-xr-xrelease/darwin/bundle.sh9
-rw-r--r--release/datafiles/blender_icons.svg27
-rw-r--r--release/datafiles/blender_icons16/icon16_disc.dat (renamed from release/datafiles/blender_icons16/icon16_disk.dat)bin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_mod_fluid.dat (renamed from release/datafiles/blender_icons16/icon16_mod_smoke.dat)bin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_ndof_dom.datbin1048 -> 0 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_ndof_fly.datbin1048 -> 0 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_ndof_trans.datbin1048 -> 0 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_ndof_turn.datbin1048 -> 0 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_disc.dat (renamed from release/datafiles/blender_icons32/icon32_disk.dat)bin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_mod_fluid.dat (renamed from release/datafiles/blender_icons32/icon32_mod_smoke.dat)bin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_ndof_dom.datbin4120 -> 0 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_ndof_fly.datbin4120 -> 0 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_ndof_trans.datbin4120 -> 0 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_ndof_turn.datbin4120 -> 0 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.multiplane_scrape.datbin0 -> 7640 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.topology.datbin0 -> 7964 bytes
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/userdef/userdef_default.c15
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c2
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/freestyle/modules/parameter_editor.py2
-rw-r--r--release/scripts/modules/bpy_extras/io_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/object_utils.py5
-rw-r--r--release/scripts/modules/console_python.py31
-rw-r--r--release/scripts/presets/fluid/honey.py4
-rw-r--r--release/scripts/presets/fluid/oil.py4
-rw-r--r--release/scripts/presets/fluid/water.py4
-rw-r--r--release/scripts/presets/keyconfig/blender.py1
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py92
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py480
-rw-r--r--release/scripts/startup/bl_operators/__init__.py1
-rw-r--r--release/scripts/startup/bl_operators/freestyle.py6
-rw-r--r--release/scripts/startup/bl_operators/mask.py40
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py140
-rw-r--r--release/scripts/startup/bl_operators/presets.py10
-rw-r--r--release/scripts/startup/bl_operators/rigidbody.py3
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_smart_project.py14
-rw-r--r--release/scripts/startup/bl_operators/vertexpaint_dirt.py9
-rw-r--r--release/scripts/startup/bl_operators/wm.py60
-rw-r--r--release/scripts/startup/bl_ui/__init__.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_gpencil.py74
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lightprobe.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py275
-rw-r--r--release/scripts/startup/bl_ui/properties_mask_common.py41
-rw-r--r--release/scripts/startup/bl_ui/properties_material_gpencil.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py1050
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py10
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_cloth.py84
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py21
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py1206
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_smoke.py692
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py36
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py94
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py15
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py23
-rw-r--r--release/scripts/startup/bl_ui/space_image.py623
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py10
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py2
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py8
-rw-r--r--release/scripts/startup/bl_ui/space_time.py11
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py436
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py128
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py179
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py863
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py370
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py1065
-rw-r--r--release/scripts/startup/keyingsets_builtins.py8
-rw-r--r--release/scripts/startup/nodeitems_builtins.py6
-rw-r--r--release/windows/icons/blender.exe.manifest10
-rw-r--r--release/windows/icons/winblender.rc1
-rw-r--r--release/windows/manifest/Blender.CRT.MANIFEST.in4
-rw-r--r--release/windows/manifest/blender.exe.manifest.in37
-rw-r--r--source/blender/CMakeLists.txt7
-rw-r--r--source/blender/alembic/ABC_alembic.h2
-rw-r--r--source/blender/alembic/intern/abc_customdata.h3
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc17
-rw-r--r--source/blender/alembic/intern/abc_exporter.h2
-rw-r--r--source/blender/alembic/intern/abc_transform.cc5
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc2
-rw-r--r--source/blender/blenfont/BLF_api.h2
-rw-r--r--source/blender/blenfont/intern/blf.c13
-rw-r--r--source/blender/blenfont/intern/blf_font.c11
-rw-r--r--source/blender/blenkernel/BKE_action.h12
-rw-r--r--source/blender/blenkernel/BKE_animsys.h15
-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_cloth.h18
-rw-r--r--source/blender/blenkernel/BKE_colortools.h4
-rw-r--r--source/blender/blenkernel/BKE_context.h3
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h17
-rw-r--r--source/blender/blenkernel/BKE_fluid.h92
-rw-r--r--source/blender/blenkernel/BKE_fluidsim.h51
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h1
-rw-r--r--source/blender/blenkernel/BKE_image.h36
-rw-r--r--source/blender/blenkernel/BKE_kelvinlet.h77
-rw-r--r--source/blender/blenkernel/BKE_library.h2
-rw-r--r--source/blender/blenkernel/BKE_material.h1
-rw-r--r--source/blender/blenkernel/BKE_modifier.h8
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/BKE_paint.h5
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h3
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h4
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h9
-rw-r--r--source/blender/blenkernel/BKE_smoke.h62
-rw-r--r--source/blender/blenkernel/BKE_sound.h8
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt25
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c19
-rw-r--r--source/blender/blenkernel/intern/action.c37
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c34
-rw-r--r--source/blender/blenkernel/intern/armature.c53
-rw-r--r--source/blender/blenkernel/intern/blendfile.c4
-rw-r--r--source/blender/blenkernel/intern/bpath.c13
-rw-r--r--source/blender/blenkernel/intern/brush.c68
-rw-r--r--source/blender/blenkernel/intern/cloth.c248
-rw-r--r--source/blender/blenkernel/intern/colortools.c68
-rw-r--r--source/blender/blenkernel/intern/constraint.c66
-rw-r--r--source/blender/blenkernel/intern/context.c12
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c6
-rw-r--r--source/blender/blenkernel/intern/curve_decimate.c4
-rw-r--r--source/blender/blenkernel/intern/curveprofile.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c9
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c548
-rw-r--r--source/blender/blenkernel/intern/editmesh.c82
-rw-r--r--source/blender/blenkernel/intern/effect.c13
-rw-r--r--source/blender/blenkernel/intern/fluid.c4966
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c90
-rw-r--r--source/blender/blenkernel/intern/gpencil.c129
-rw-r--r--source/blender/blenkernel/intern/image.c569
-rw-r--r--source/blender/blenkernel/intern/image_save.c62
-rw-r--r--source/blender/blenkernel/intern/kelvinlet.c215
-rw-r--r--source/blender/blenkernel/intern/library.c427
-rw-r--r--source/blender/blenkernel/intern/material.c5
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c4
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c2
-rw-r--r--source/blender/blenkernel/intern/modifier.c2
-rw-r--r--source/blender/blenkernel/intern/nla.c4
-rw-r--r--source/blender/blenkernel/intern/node.c8
-rw-r--r--source/blender/blenkernel/intern/object.c24
-rw-r--r--source/blender/blenkernel/intern/packedFile.c4
-rw-r--r--source/blender/blenkernel/intern/paint.c64
-rw-r--r--source/blender/blenkernel/intern/paint_toolslots.c4
-rw-r--r--source/blender/blenkernel/intern/particle.c19
-rw-r--r--source/blender/blenkernel/intern/particle_system.c532
-rw-r--r--source/blender/blenkernel/intern/pointcache.c496
-rw-r--r--source/blender/blenkernel/intern/scene.c26
-rw-r--r--source/blender/blenkernel/intern/sequencer.c1
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c73
-rw-r--r--source/blender/blenkernel/intern/smoke.c3654
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c2
-rw-r--r--source/blender/blenkernel/intern/texture.c2
-rw-r--r--source/blender/blenkernel/intern/workspace.c7
-rw-r--r--source/blender/blenlib/BLI_dial_2d.h2
-rw-r--r--source/blender/blenlib/BLI_ghash.h3
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h4
-rw-r--r--source/blender/blenlib/BLI_math_geom.h5
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h2
-rw-r--r--source/blender/blenlib/BLI_math_vector.h2
-rw-r--r--source/blender/blenlib/BLI_task.h1
-rw-r--r--source/blender/blenlib/intern/BLI_ghash_utils.c9
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c87
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c586
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c40
-rw-r--r--source/blender/blenlib/intern/math_geom.c21
-rw-r--r--source/blender/blenlib/intern/math_matrix.c21
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c5
-rw-r--r--source/blender/blenloader/intern/readfile.c352
-rw-r--r--source/blender/blenloader/intern/versioning_250.c28
-rw-r--r--source/blender/blenloader/intern/versioning_260.c80
-rw-r--r--source/blender/blenloader/intern/versioning_270.c26
-rw-r--r--source/blender/blenloader/intern/versioning_280.c394
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c54
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c26
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c2
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c42
-rw-r--r--source/blender/blenloader/intern/writefile.c42
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c226
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.h10
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c697
-rw-r--r--source/blender/collada/AnimationClipExporter.h5
-rw-r--r--source/blender/collada/AnimationExporter.h6
-rw-r--r--source/blender/collada/BCAnimationCurve.h6
-rw-r--r--source/blender/collada/BCAnimationSampler.h6
-rw-r--r--source/blender/collada/BCMath.h6
-rw-r--r--source/blender/collada/BCSampleData.h6
-rw-r--r--source/blender/collada/ErrorHandler.h5
-rw-r--r--source/blender/collada/ExtraHandler.h5
-rw-r--r--source/blender/collada/ExtraTags.h5
-rw-r--r--source/blender/collada/Materials.h6
-rw-r--r--source/blender/compositor/nodes/COM_DenoiseNode.cpp6
-rw-r--r--source/blender/compositor/nodes/COM_DenoiseNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_MathNode.cpp49
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.cpp5
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.h5
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.cpp271
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.h126
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cpp3
-rw-r--r--source/blender/depsgraph/CMakeLists.txt18
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_physics.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc552
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc101
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h55
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc49
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h58
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc61
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h (renamed from source/blender/modifiers/intern/MOD_fluidsim_util.h)37
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc182
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h59
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc28
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h (renamed from source/blender/draw/modes/edit_mesh_mode_intern.h)28
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc82
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h58
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc58
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h47
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc72
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h49
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc64
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h47
-rw-r--r--source/blender/draw/CMakeLists.txt209
-rw-r--r--source/blender/draw/DRW_engine.h11
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c50
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c36
-rw-r--r--source/blender/draw/engines/eevee/eevee_mist.c7
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c12
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h29
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c271
-rw-r--r--source/blender/draw/engines/eevee/eevee_renderpasses.c278
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c21
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c57
-rw-r--r--source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl64
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c144
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h3
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c2
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl4
-rw-r--r--source/blender/draw/engines/overlay/overlay_antialiasing.c202
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c2357
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_curve.c132
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_mesh.c412
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_text.c205
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c485
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.h28
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c1626
-rw-r--r--source/blender/draw/engines/overlay/overlay_facing.c59
-rw-r--r--source/blender/draw/engines/overlay/overlay_grid.c216
-rw-r--r--source/blender/draw/engines/overlay/overlay_image.c481
-rw-r--r--source/blender/draw/engines/overlay/overlay_lattice.c83
-rw-r--r--source/blender/draw/engines/overlay/overlay_metaball.c143
-rw-r--r--source/blender/draw/engines/overlay/overlay_motion_path.c231
-rw-r--r--source/blender/draw/engines/overlay/overlay_outline.c182
-rw-r--r--source/blender/draw/engines/overlay/overlay_paint.c209
-rw-r--r--source/blender/draw/engines/overlay/overlay_particle.c222
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h574
-rw-r--r--source/blender/draw/engines/overlay/overlay_sculpt.c70
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c1317
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c243
-rw-r--r--source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl150
-rw-r--r--source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl11
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl43
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl (renamed from source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl)35
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl27
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl (renamed from source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl (renamed from source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl)87
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl (renamed from source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl)17
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl (renamed from source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl (renamed from source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl)13
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl29
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl (renamed from source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl)60
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl (renamed from source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl)8
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl (renamed from source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl)19
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl (renamed from source/blender/draw/modes/shaders/armature_stick_frag.glsl)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl (renamed from source/blender/draw/modes/shaders/armature_stick_vert.glsl)13
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl13
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl22
-rw-r--r--source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl (renamed from source/blender/draw/modes/shaders/pose_selection_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl (renamed from source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl)5
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl (renamed from source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl)1
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl (renamed from source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl)3
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl (renamed from source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl)5
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl32
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl38
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl (renamed from source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl (renamed from source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl (renamed from source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl (renamed from source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl (renamed from source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl (renamed from source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl)10
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl (renamed from source/blender/draw/modes/shaders/edit_mesh_overlay_geom.glsl)7
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl53
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl25
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl (renamed from source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl)22
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl19
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl42
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_frag.glsl13
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl30
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl70
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl (renamed from source/blender/draw/modes/shaders/object_loose_points_frag.glsl)5
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl20
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl30
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_vert.glsl227
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl31
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl40
-rw-r--r--source/blender/draw/engines/overlay/shaders/facing_frag.glsl6
-rw-r--r--source/blender/draw/engines/overlay/shaders/facing_vert.glsl (renamed from source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/grid_frag.glsl (renamed from source/blender/draw/modes/shaders/object_grid_frag.glsl)3
-rw-r--r--source/blender/draw/engines/overlay/shaders/grid_vert.glsl (renamed from source/blender/draw/modes/shaders/object_grid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/image_frag.glsl34
-rw-r--r--source/blender/draw/engines/overlay/shaders/image_vert.glsl21
-rw-r--r--source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl (renamed from source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl)15
-rw-r--r--source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl (renamed from source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl)29
-rw-r--r--source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl (renamed from source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl)22
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl335
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl10
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl (renamed from source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl70
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl (renamed from source/blender/draw/modes/shaders/paint_face_selection_vert.glsl)9
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl32
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl23
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl (renamed from source/blender/draw/modes/shaders/paint_texture_vert.glsl)6
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl (renamed from source/blender/draw/modes/shaders/paint_vertex_frag.glsl)16
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl (renamed from source/blender/draw/modes/shaders/paint_vertex_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl (renamed from source/blender/draw/modes/shaders/paint_weight_frag.glsl)15
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl (renamed from source/blender/draw/modes/shaders/paint_weight_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl (renamed from source/blender/draw/modes/shaders/paint_wire_vert.glsl)40
-rw-r--r--source/blender/draw/engines/overlay/shaders/particle_frag.glsl16
-rw-r--r--source/blender/draw/engines/overlay/shaders/particle_vert.glsl68
-rw-r--r--source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl19
-rw-r--r--source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl (renamed from source/blender/draw/modes/shaders/volume_velocity_vert.glsl)6
-rw-r--r--source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl25
-rw-r--r--source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl154
-rw-r--r--source/blender/draw/engines/select/select_engine.c18
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c117
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c154
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c83
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c87
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h55
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c75
-rw-r--r--source/blender/draw/intern/DRW_render.h49
-rw-r--r--source/blender/draw/intern/draw_anim_viz.c336
-rw-r--r--source/blender/draw/intern/draw_armature.c2168
-rw-r--r--source/blender/draw/intern/draw_cache.c2308
-rw-r--r--source/blender/draw/intern/draw_cache.h32
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h5
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c93
-rw-r--r--source/blender/draw/intern/draw_cache_impl_lattice.c75
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c14
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c6
-rw-r--r--source/blender/draw/intern/draw_cache_inline.h6
-rw-r--r--source/blender/draw/intern/draw_common.c922
-rw-r--r--source/blender/draw/intern/draw_common.h138
-rw-r--r--source/blender/draw/intern/draw_instance_data.c31
-rw-r--r--source/blender/draw/intern/draw_instance_data.h1
-rw-r--r--source/blender/draw/intern/draw_manager.c153
-rw-r--r--source/blender/draw/intern/draw_manager.h3
-rw-r--r--source/blender/draw/intern/draw_manager_data.c131
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c71
-rw-r--r--source/blender/draw/intern/draw_manager_text.c361
-rw-r--r--source/blender/draw/intern/draw_manager_text.h11
-rw-r--r--source/blender/draw/intern/shaders/common_colormanagement_lib.glsl (renamed from source/blender/draw/modes/shaders/common_colormanagement_lib.glsl)0
-rw-r--r--source/blender/draw/intern/shaders/common_fullscreen_vert.glsl (renamed from source/blender/draw/modes/shaders/common_fullscreen_vert.glsl)0
-rw-r--r--source/blender/draw/intern/shaders/common_fxaa_lib.glsl (renamed from source/blender/draw/modes/shaders/common_fxaa_lib.glsl)2
-rw-r--r--source/blender/draw/intern/shaders/common_globals_lib.glsl (renamed from source/blender/draw/modes/shaders/common_globals_lib.glsl)13
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl (renamed from source/blender/draw/modes/shaders/common_hair_lib.glsl)0
-rw-r--r--source/blender/draw/intern/shaders/common_hair_refine_vert.glsl (renamed from source/blender/draw/modes/shaders/common_hair_refine_vert.glsl)0
-rw-r--r--source/blender/draw/intern/shaders/common_smaa_lib.glsl1436
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl (renamed from source/blender/draw/modes/shaders/common_view_lib.glsl)56
-rw-r--r--source/blender/draw/intern/smaa_textures.h15086
-rw-r--r--source/blender/draw/modes/draw_mode_engines.h42
-rw-r--r--source/blender/draw/modes/edit_armature_mode.c203
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c375
-rw-r--r--source/blender/draw/modes/edit_lattice_mode.c297
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c903
-rw-r--r--source/blender/draw/modes/edit_mesh_mode_text.c379
-rw-r--r--source/blender/draw/modes/edit_metaball_mode.c231
-rw-r--r--source/blender/draw/modes/edit_text_mode.c419
-rw-r--r--source/blender/draw/modes/object_mode.c3930
-rw-r--r--source/blender/draw/modes/overlay_mode.c533
-rw-r--r--source/blender/draw/modes/paint_texture_mode.c355
-rw-r--r--source/blender/draw/modes/paint_vertex_mode.c408
-rw-r--r--source/blender/draw/modes/particle_mode.c243
-rw-r--r--source/blender/draw/modes/pose_mode.c355
-rw-r--r--source/blender/draw/modes/sculpt_mode.c197
-rw-r--r--source/blender/draw/modes/shaders/armature_axes_vert.glsl35
-rw-r--r--source/blender/draw/modes/shaders/armature_dof_vert.glsl30
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl15
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl18
-rw-r--r--source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl19
-rw-r--r--source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl44
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl7
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl22
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl30
-rw-r--r--source/blender/draw/modes/shaders/edit_normals_geom.glsl18
-rw-r--r--source/blender/draw/modes/shaders/edit_normals_vert.glsl36
-rw-r--r--source/blender/draw/modes/shaders/object_camera_image_frag.glsl25
-rw-r--r--source/blender/draw/modes/shaders/object_camera_image_vert.glsl18
-rw-r--r--source/blender/draw/modes/shaders/object_color_axes_vert.glsl35
-rw-r--r--source/blender/draw/modes/shaders/object_empty_axes_vert.glsl35
-rw-r--r--source/blender/draw/modes/shaders/object_empty_image_frag.glsl53
-rw-r--r--source/blender/draw/modes/shaders/object_empty_image_vert.glsl36
-rw-r--r--source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl31
-rw-r--r--source/blender/draw/modes/shaders/object_mball_handles_vert.glsl36
-rw-r--r--source/blender/draw/modes/shaders/object_outline_detect_frag.glsl87
-rw-r--r--source/blender/draw/modes/shaders/object_outline_expand_frag.glsl51
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl18
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl29
-rw-r--r--source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl21
-rw-r--r--source/blender/draw/modes/shaders/object_particle_dot_frag.glsl53
-rw-r--r--source/blender/draw/modes/shaders/object_particle_dot_vert.glsl36
-rw-r--r--source/blender/draw/modes/shaders/object_particle_prim_vert.glsl60
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl9
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl23
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl60
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl42
-rw-r--r--source/blender/draw/modes/shaders/paint_face_vert.glsl11
-rw-r--r--source/blender/draw/modes/shaders/paint_texture_frag.glsl25
-rw-r--r--source/blender/draw/modes/shaders/paint_vert_frag.glsl17
-rw-r--r--source/blender/draw/modes/shaders/paint_wire_frag.glsl8
-rw-r--r--source/blender/draw/modes/shaders/particle_strand_frag.glsl22
-rw-r--r--source/blender/draw/modes/shaders/particle_strand_vert.glsl71
-rw-r--r--source/blender/draw/modes/shaders/sculpt_mask_vert.glsl16
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c81
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c25
-rw-r--r--source/blender/editors/animation/anim_filter.c12
-rw-r--r--source/blender/editors/animation/anim_markers.c106
-rw-r--r--source/blender/editors/animation/keyframes_general.c133
-rw-r--r--source/blender/editors/armature/armature_add.c8
-rw-r--r--source/blender/editors/armature/armature_edit.c13
-rw-r--r--source/blender/editors/armature/armature_relations.c89
-rw-r--r--source/blender/editors/armature/armature_select.c21
-rw-r--r--source/blender/editors/armature/armature_utils.c15
-rw-r--r--source/blender/editors/armature/pose_transform.c2
-rw-r--r--source/blender/editors/curve/editcurve.c11
-rw-r--r--source/blender/editors/curve/editfont.c34
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt9
-rw-r--r--source/blender/editors/gizmo_library/CMakeLists.txt1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c218
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c39
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c51
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c8
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c8
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c11
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c18
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c21
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c1
-rw-r--r--source/blender/editors/include/ED_fileselect.h5
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h6
-rw-r--r--source/blender/editors/include/ED_image.h2
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h2
-rw-r--r--source/blender/editors/include/ED_mball.h1
-rw-r--r--source/blender/editors/include/ED_mesh.h19
-rw-r--r--source/blender/editors/include/ED_object.h10
-rw-r--r--source/blender/editors/include/ED_paint.h20
-rw-r--r--source/blender/editors/include/ED_screen.h2
-rw-r--r--source/blender/editors/include/ED_transform.h29
-rw-r--r--source/blender/editors/include/ED_uvedit.h60
-rw-r--r--source/blender/editors/include/ED_view3d.h2
-rw-r--r--source/blender/editors/include/UI_icons.h10
-rw-r--r--source/blender/editors/include/UI_resources.h2
-rw-r--r--source/blender/editors/include/UI_view2d.h1
-rw-r--r--source/blender/editors/interface/interface_draw.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c10
-rw-r--r--source/blender/editors/interface/interface_icons.c3
-rw-r--r--source/blender/editors/interface/interface_ops.c82
-rw-r--r--source/blender/editors/interface/interface_region_hud.c8
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c125
-rw-r--r--source/blender/editors/interface/interface_templates.c18
-rw-r--r--source/blender/editors/interface/interface_widgets.c75
-rw-r--r--source/blender/editors/interface/resources.c6
-rw-r--r--source/blender/editors/interface/view2d.c34
-rw-r--r--source/blender/editors/io/CMakeLists.txt10
-rw-r--r--source/blender/editors/io/io_alembic.c10
-rw-r--r--source/blender/editors/io/io_ops.c7
-rw-r--r--source/blender/editors/io/io_usd.c240
-rw-r--r--source/blender/editors/io/io_usd.h31
-rw-r--r--source/blender/editors/mesh/editface.c2
-rw-r--r--source/blender/editors/mesh/editmesh_automerge.c52
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c11
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c17
-rw-r--r--source/blender/editors/mesh/editmesh_select.c35
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c9
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c1
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c36
-rw-r--r--source/blender/editors/object/object_bake_api.c9
-rw-r--r--source/blender/editors/object/object_data_transform.c99
-rw-r--r--source/blender/editors/object/object_edit.c5
-rw-r--r--source/blender/editors/object/object_intern.h8
-rw-r--r--source/blender/editors/object/object_random.c2
-rw-r--r--source/blender/editors/object/object_transform.c38
-rw-r--r--source/blender/editors/physics/CMakeLists.txt14
-rw-r--r--source/blender/editors/physics/particle_edit.c1
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c5
-rw-r--r--source/blender/editors/physics/particle_edit_utildefines.h6
-rw-r--r--source/blender/editors/physics/particle_object.c2
-rw-r--r--source/blender/editors/physics/physics_fluid.c1647
-rw-r--r--source/blender/editors/physics/physics_intern.h14
-rw-r--r--source/blender/editors/physics/physics_ops.c14
-rw-r--r--source/blender/editors/render/CMakeLists.txt4
-rw-r--r--source/blender/editors/render/render_internal.c2
-rw-r--r--source/blender/editors/render/render_opengl.c146
-rw-r--r--source/blender/editors/render/render_preview.c14
-rw-r--r--source/blender/editors/screen/area.c15
-rw-r--r--source/blender/editors/screen/area_utils.c29
-rw-r--r--source/blender/editors/screen/screen_edit.c4
-rw-r--r--source/blender/editors/screen/screen_ops.c55
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c22
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c23
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c733
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c120
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c13
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c16
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c539
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c8
-rw-r--r--source/blender/editors/space_action/space_action.c8
-rw-r--r--source/blender/editors/space_api/spacetypes.c1
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c17
-rw-r--r--source/blender/editors/space_clip/clip_draw.c4
-rw-r--r--source/blender/editors/space_console/console_draw.c70
-rw-r--r--source/blender/editors/space_console/console_intern.h6
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_file/file_ops.c6
-rw-r--r--source/blender/editors/space_file/filelist.c6
-rw-r--r--source/blender/editors/space_file/filesel.c8
-rw-r--r--source/blender/editors/space_file/fsmenu.c67
-rw-r--r--source/blender/editors/space_file/fsmenu.h1
-rw-r--r--source/blender/editors/space_graph/graph_edit.c431
-rw-r--r--source/blender/editors/space_graph/space_graph.c10
-rw-r--r--source/blender/editors/space_image/image_draw.c164
-rw-r--r--source/blender/editors/space_image/image_edit.c9
-rw-r--r--source/blender/editors/space_image/image_intern.h4
-rw-r--r--source/blender/editors/space_image/image_ops.c551
-rw-r--r--source/blender/editors/space_image/image_undo.c82
-rw-r--r--source/blender/editors/space_image/space_image.c78
-rw-r--r--source/blender/editors/space_info/info_draw.c52
-rw-r--r--source/blender/editors/space_info/info_intern.h10
-rw-r--r--source/blender/editors/space_info/info_stats.c4
-rw-r--r--source/blender/editors/space_info/textview.c302
-rw-r--r--source/blender/editors/space_info/textview.h29
-rw-r--r--source/blender/editors/space_nla/space_nla.c7
-rw-r--r--source/blender/editors/space_node/drawnode.c27
-rw-r--r--source/blender/editors/space_node/node_edit.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c10
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c21
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c11
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c2
-rw-r--r--source/blender/editors/space_text/space_text.c7
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c10
-rw-r--r--source/blender/editors/space_text/text_draw.c249
-rw-r--r--source/blender/editors/space_text/text_intern.h9
-rw-r--r--source/blender/editors/space_text/text_ops.c60
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c28
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt7
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c68
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c224
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c258
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c4
-rw-r--r--source/blender/editors/transform/CMakeLists.txt2
-rw-r--r--source/blender/editors/transform/transform.c351
-rw-r--r--source/blender/editors/transform/transform.h2
-rw-r--r--source/blender/editors/transform/transform_convert.c16
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c65
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c2
-rw-r--r--source/blender/editors/transform/transform_convert_object.c84
-rw-r--r--source/blender/editors/transform/transform_draw.c114
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.c344
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.h (renamed from source/blender/editors/include/BIF_gl.h)27
-rw-r--r--source/blender/editors/transform/transform_generics.c91
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c390
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c101
-rw-r--r--source/blender/editors/transform/transform_gizmo_extrude_3d.c67
-rw-r--r--source/blender/editors/transform/transform_orientations.c2
-rw-r--r--source/blender/editors/transform/transform_snap.c6
-rw-r--r--source/blender/editors/transform/transform_snap.h2
-rw-r--r--source/blender/editors/transform/transform_snap_object.c2
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c10
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c131
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c5
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c125
-rw-r--r--source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp4
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp28
-rw-r--r--source/blender/freestyle/intern/python/BPy_Id.cpp4
-rw-r--r--source/blender/freestyle/intern/python/BPy_Interface0D.cpp38
-rw-r--r--source/blender/freestyle/intern/python/BPy_Interface1D.cpp22
-rw-r--r--source/blender/freestyle/intern/python/BPy_Iterator.cpp14
-rw-r--r--source/blender/freestyle/intern/python/BPy_SShape.cpp22
-rw-r--r--source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp16
-rw-r--r--source/blender/freestyle/intern/python/BPy_StrokeShader.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewMap.cpp4
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewShape.cpp22
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp16
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp32
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp18
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp10
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp34
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp10
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp20
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp50
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp32
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp18
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp8
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp12
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp16
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp20
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp18
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp20
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp16
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.cpp4
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c7
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c10
-rw-r--r--source/blender/gpu/CMakeLists.txt23
-rw-r--r--source/blender/gpu/GPU_batch.h4
-rw-r--r--source/blender/gpu/GPU_buffers.h2
-rw-r--r--source/blender/gpu/GPU_draw.h14
-rw-r--r--source/blender/gpu/GPU_element.h4
-rw-r--r--source/blender/gpu/GPU_material.h2
-rw-r--r--source/blender/gpu/GPU_shader.h19
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h2
-rw-r--r--source/blender/gpu/GPU_viewport.h1
-rw-r--r--source/blender/gpu/intern/gpu_batch.c76
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c42
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h2
-rw-r--r--source/blender/gpu/intern/gpu_draw.c455
-rw-r--r--source/blender/gpu/intern/gpu_draw_smoke.c416
-rw-r--r--source/blender/gpu/intern/gpu_element.c10
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h2
-rw-r--r--source/blender/gpu/intern/gpu_matrix.c5
-rw-r--r--source/blender/gpu/intern/gpu_platform.c3
-rw-r--r--source/blender/gpu/intern/gpu_shader.c112
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.c13
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl65
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl60
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl25
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl27
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl55
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl31
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl68
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl71
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl26
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl43
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl32
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl29
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_vert.glsl13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_frag.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_geom.glsl37
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl36
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl22
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_vert.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl69
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math.glsl138
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl7
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl65
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl20
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl2
-rw-r--r--source/blender/imbuf/IMB_moviecache.h1
-rw-r--r--source/blender/imbuf/intern/colormanagement.c11
-rw-r--r--source/blender/imbuf/intern/moviecache.c8
-rw-r--r--source/blender/imbuf/intern/rectop.c2
-rw-r--r--source/blender/makesdna/DNA_action_types.h12
-rw-r--r--source/blender/makesdna/DNA_armature_types.h6
-rw-r--r--source/blender/makesdna/DNA_brush_defaults.h4
-rw-r--r--source/blender/makesdna/DNA_brush_types.h4
-rw-r--r--source/blender/makesdna/DNA_camera_types.h2
-rw-r--r--source/blender/makesdna/DNA_cloth_types.h34
-rw-r--r--source/blender/makesdna/DNA_color_types.h23
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h16
-rw-r--r--source/blender/makesdna/DNA_curveprofile_types.h6
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h4
-rw-r--r--source/blender/makesdna/DNA_fluid_types.h590
-rw-r--r--source/blender/makesdna/DNA_image_types.h30
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h10
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h48
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h8
-rw-r--r--source/blender/makesdna/DNA_node_types.h36
-rw-r--r--source/blender/makesdna/DNA_object_types.h3
-rw-r--r--source/blender/makesdna/DNA_particle_types.h38
-rw-r--r--source/blender/makesdna/DNA_scene_types.h53
-rw-r--r--source/blender/makesdna/DNA_screen_types.h3
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h8
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h346
-rw-r--r--source/blender/makesdna/DNA_sound_types.h2
-rw-r--r--source/blender/makesdna/DNA_space_types.h105
-rw-r--r--source/blender/makesdna/DNA_text_types.h3
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h27
-rw-r--r--source/blender/makesdna/DNA_view3d_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h7
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h6
-rw-r--r--source/blender/makesdna/DNA_world_types.h3
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h7
-rw-r--r--source/blender/makesdna/intern/makesdna.c7
-rw-r--r--source/blender/makesrna/RNA_access.h14
-rw-r--r--source/blender/makesrna/RNA_enum_types.h3
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt13
-rw-r--r--source/blender/makesrna/intern/makesrna.c3
-rw-r--r--source/blender/makesrna/intern/rna_access.c30
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c3
-rw-r--r--source/blender/makesrna/intern/rna_armature.c7
-rw-r--r--source/blender/makesrna/intern/rna_brush.c49
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c249
-rw-r--r--source/blender/makesrna/intern/rna_color.c99
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c50
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c2530
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c792
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c33
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c4
-rw-r--r--source/blender/makesrna/intern/rna_image.c189
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c25
-rw-r--r--source/blender/makesrna/intern/rna_internal.h3
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c17
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c356
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c101
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c8
-rw-r--r--source/blender/makesrna/intern/rna_particle.c13
-rw-r--r--source/blender/makesrna/intern/rna_pose.c4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c49
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c1218
-rw-r--r--source/blender/makesrna/intern/rna_space.c103
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c67
-rw-r--r--source/blender/makesrna/intern/rna_wm.c1
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c5
-rw-r--r--source/blender/makesrna/intern/rna_workspace_api.c16
-rw-r--r--source/blender/modifiers/CMakeLists.txt9
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h3
-rw-r--r--source/blender/modifiers/intern/MOD_fluid.c (renamed from source/blender/modifiers/intern/MOD_smoke.c)128
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim.c150
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c588
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_util.h6
-rw-r--r--source/blender/modifiers/intern/MOD_util.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c1918
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.c8
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_math.c39
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.c33
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c37
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c28
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_aov.c51
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c137
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c141
-rw-r--r--source/blender/physics/BPH_mass_spring.h1
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp163
-rw-r--r--source/blender/physics/intern/implicit.h9
-rw-r--r--source/blender/physics/intern/implicit_blender.c26
-rw-r--r--source/blender/physics/intern/implicit_eigen.cpp2
-rw-r--r--source/blender/python/BPY_extern.h6
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops.c2
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c274
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c110
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c30
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.c4
-rw-r--r--source/blender/python/generic/bgl.c2
-rw-r--r--source/blender/python/generic/idprop_py_api.c6
-rw-r--r--source/blender/python/generic/imbuf_py_api.c16
-rw-r--r--source/blender/python/generic/py_capi_utils.c19
-rw-r--r--source/blender/python/generic/py_capi_utils.h5
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c10
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c6
-rw-r--r--source/blender/python/intern/CMakeLists.txt13
-rw-r--r--source/blender/python/intern/bpy_app.c193
-rw-r--r--source/blender/python/intern/bpy_app_alembic.c12
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c90
-rw-r--r--source/blender/python/intern/bpy_app_ffmpeg.c12
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c55
-rw-r--r--source/blender/python/intern/bpy_app_ocio.c11
-rw-r--r--source/blender/python/intern/bpy_app_oiio.c14
-rw-r--r--source/blender/python/intern/bpy_app_opensubdiv.c13
-rw-r--r--source/blender/python/intern/bpy_app_openvdb.c12
-rw-r--r--source/blender/python/intern/bpy_app_sdl.c20
-rw-r--r--source/blender/python/intern/bpy_app_translations.c24
-rw-r--r--source/blender/python/intern/bpy_interface.c35
-rw-r--r--source/blender/python/intern/bpy_rna.c22
-rw-r--r--source/blender/python/intern/bpy_utils_units.c12
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c46
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c24
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c32
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c28
-rw-r--r--source/blender/python/mathutils/mathutils_bvhtree.c12
-rw-r--r--source/blender/python/mathutils/mathutils_kdtree.c10
-rw-r--r--source/blender/render/CMakeLists.txt6
-rw-r--r--source/blender/render/intern/include/texture.h1
-rw-r--r--source/blender/render/intern/source/imagetexture.c44
-rw-r--r--source/blender/render/intern/source/render_texture.c2
-rw-r--r--source/blender/shader_fx/CMakeLists.txt1
-rw-r--r--source/blender/usd/CMakeLists.txt81
-rw-r--r--source/blender/usd/intern/abstract_hierarchy_iterator.cc559
-rw-r--r--source/blender/usd/intern/abstract_hierarchy_iterator.h248
-rw-r--r--source/blender/usd/intern/usd_capi.cc218
-rw-r--r--source/blender/usd/intern/usd_exporter_context.h44
-rw-r--r--source/blender/usd/intern/usd_hierarchy_iterator.cc150
-rw-r--r--source/blender/usd/intern/usd_hierarchy_iterator.h71
-rw-r--r--source/blender/usd/intern/usd_writer_abstract.cc147
-rw-r--r--source/blender/usd/intern/usd_writer_abstract.h78
-rw-r--r--source/blender/usd/intern/usd_writer_camera.cc111
-rw-r--r--source/blender/usd/intern/usd_writer_camera.h38
-rw-r--r--source/blender/usd/intern/usd_writer_hair.cc90
-rw-r--r--source/blender/usd/intern/usd_writer_hair.h38
-rw-r--r--source/blender/usd/intern/usd_writer_light.cc112
-rw-r--r--source/blender/usd/intern/usd_writer_light.h37
-rw-r--r--source/blender/usd/intern/usd_writer_mesh.cc489
-rw-r--r--source/blender/usd/intern/usd_writer_mesh.h66
-rw-r--r--source/blender/usd/intern/usd_writer_transform.cc64
-rw-r--r--source/blender/usd/intern/usd_writer_transform.h42
-rw-r--r--source/blender/usd/usd.h62
-rw-r--r--source/blender/windowmanager/WM_api.h5
-rw-r--r--source/blender/windowmanager/WM_types.h2
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h11
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_types.h31
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo.c3
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c69
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c58
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c3
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c112
-rw-r--r--source/blender/windowmanager/intern/wm_files.c2
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c2
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c6
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operator_utils.c4
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c4
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c3
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c4
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c19
-rw-r--r--source/blender/windowmanager/intern/wm_tooltip.c32
-rw-r--r--source/blender/windowmanager/intern/wm_window.c9
-rw-r--r--source/blender/windowmanager/wm_event_types.h6
-rw-r--r--source/creator/CMakeLists.txt43
-rw-r--r--source/creator/creator.c22
-rw-r--r--tests/gtests/CMakeLists.txt4
-rw-r--r--tests/gtests/blenlib/BLI_delaunay_2d_test.cc272
-rw-r--r--tests/gtests/blenlib/BLI_listbase_test.cc10
-rw-r--r--tests/gtests/blenlib/BLI_path_util_test.cc3
-rw-r--r--tests/gtests/blenloader/CMakeLists.txt90
-rw-r--r--tests/gtests/blenloader/blendfile_load_test.cc31
-rw-r--r--tests/gtests/blenloader/blendfile_loading_base_test.cc172
-rw-r--r--tests/gtests/blenloader/blendfile_loading_base_test.h64
-rw-r--r--tests/gtests/usd/CMakeLists.txt101
-rw-r--r--tests/gtests/usd/abstract_hierarchy_iterator_test.cc202
-rw-r--r--tests/gtests/usd/hierarchy_context_order_test.cc123
-rw-r--r--tests/gtests/usd/usd_stage_creation_test.cc62
-rw-r--r--tests/python/CMakeLists.txt8
-rwxr-xr-xtests/python/alembic_tests.py14
-rw-r--r--tests/python/bl_id_management.py184
1343 files changed, 142136 insertions, 84286 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c43377833e9..7d63db5ff24 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -131,79 +131,6 @@ get_blender_version()
#-----------------------------------------------------------------------------
-# Platform Specific Defaults
-
-# list of var-names
-set(_init_vars)
-
-# initialize to ON
-macro(option_defaults_init)
- foreach(_var ${ARGV})
- set(${_var} ON)
- list(APPEND _init_vars "${_var}")
- endforeach()
- unset(_var)
-endmacro()
-
-# remove from namespace
-macro(option_defaults_clear)
- foreach(_var ${_init_vars})
- unset(${_var})
- endforeach()
- unset(_var)
- unset(_init_vars)
-endmacro()
-
-
-# values to initialize WITH_****
-option_defaults_init(
- _init_BUILDINFO
- _init_CODEC_FFMPEG
- _init_CYCLES_OSL
- _init_IMAGE_OPENEXR
- _init_INPUT_NDOF
- _init_JACK
- _init_OPENCOLLADA
- _init_OPENCOLORIO
- _init_SDL
- _init_FFTW3
- _init_OPENSUBDIV
- _init_OPENXR
-)
-
-# TBB malloc is only supported on for windows currently
-if(WIN32)
- set(_init_TBB_MALLOC_PROXY ON)
-else()
- set(_init_TBB_MALLOC_PROXY OFF)
-endif()
-
-
-# customize...
-if(UNIX AND NOT APPLE)
- # some of these libraries are problematic on Linux
- # disable less important dependencies by default
- set(_init_CODEC_FFMPEG OFF)
- set(_init_CYCLES_OSL OFF)
- set(_init_IMAGE_OPENEXR OFF)
- set(_init_JACK OFF)
- set(_init_OPENCOLLADA OFF)
- set(_init_OPENCOLORIO OFF)
- set(_init_SDL OFF)
- set(_init_FFTW3 OFF)
- set(_init_OPENSUBDIV OFF)
- set(_init_OPENVDB OFF)
- set(_init_OPENIMAGEDENOISE OFF)
-elseif(WIN32)
- set(_init_JACK OFF)
-elseif(APPLE)
- set(_init_JACK OFF)
- # No OpenXR compatible XR runtime in sight on Apple, so why bother compiling XR support?
- set(_init_OPENXR OFF)
-endif()
-
-
-#-----------------------------------------------------------------------------
# Options
# First platform specific non-cached vars
@@ -229,7 +156,7 @@ if(APPLE)
option(WITH_PYTHON_FRAMEWORK "Enable building using the Python available in the framework (OSX only)" OFF)
endif()
-option(WITH_BUILDINFO "Include extra build details (only disable for development & faster builds)" ${_init_BUILDINFO})
+option(WITH_BUILDINFO "Include extra build details (only disable for development & faster builds)" ON)
if(${CMAKE_VERSION} VERSION_LESS 2.8.8)
# add_library OBJECT arg unsupported
set(WITH_BUILDINFO OFF)
@@ -243,21 +170,27 @@ mark_as_advanced(BUILDINFO_OVERRIDE_TIME)
option(WITH_IK_ITASC "Enable ITASC IK solver (only disable for development & for incompatible C++ compilers)" ON)
option(WITH_IK_SOLVER "Enable Legacy IK solver (only disable for development)" ON)
-option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke, ocean sim, and audio effects)" ${_init_FFTW3})
+option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke, ocean sim, and audio effects)" ON)
option(WITH_BULLET "Enable Bullet (Physics Engine)" ON)
option(WITH_SYSTEM_BULLET "Use the systems bullet library (currently unsupported due to missing features in upstream!)" )
mark_as_advanced(WITH_SYSTEM_BULLET)
-option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ${_init_OPENCOLORIO})
-option(WITH_OPENXR "Enable VR features through the OpenXR specification" ${_init_OPENXR})
+option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ON)
+if(APPLE)
+ # There's no OpenXR runtime in sight for macOS, neither is code well
+ # tested there -> disable it by default.
+ option(WITH_OPENXR "Enable VR features through the OpenXR specification" OFF)
+else()
+ option(WITH_OPENXR "Enable VR features through the OpenXR specification" ON)
+endif()
# Compositor
option(WITH_COMPOSITOR "Enable the tile based nodal compositor" ON)
-option(WITH_OPENIMAGEDENOISE "Enable the OpenImageDenoise compositing node" ${_init_OPENIMAGEDENOISE})
+option(WITH_OPENIMAGEDENOISE "Enable the OpenImageDenoise compositing node" ON)
-option(WITH_OPENSUBDIV "Enable OpenSubdiv for surface subdivision" ${_init_OPENSUBDIV})
+option(WITH_OPENSUBDIV "Enable OpenSubdiv for surface subdivision" ON)
-option(WITH_OPENVDB "Enable features relying on OpenVDB" ${_init_OPENVDB})
-option(WITH_OPENVDB_BLOSC "Enable blosc compression for OpenVDB, only enable if OpenVDB was built with blosc support" ${_init_OPENVDB})
+option(WITH_OPENVDB "Enable features relying on OpenVDB" ON)
+option(WITH_OPENVDB_BLOSC "Enable blosc compression for OpenVDB, only enable if OpenVDB was built with blosc support" ON)
option(WITH_OPENVDB_3_ABI_COMPATIBLE "Assume OpenVDB library has been compiled with version 3 ABI compatibility" OFF)
mark_as_advanced(WITH_OPENVDB_3_ABI_COMPATIBLE)
@@ -316,14 +249,13 @@ endif()
# Modifiers
-option(WITH_MOD_FLUID "Enable Elbeem Modifier (Fluid Simulation)" ON)
-option(WITH_MOD_SMOKE "Enable Smoke Modifier (Smoke Simulation)" ON)
+option(WITH_MOD_FLUID "Enable Mantaflow Fluid Simulation Framework" ON)
option(WITH_MOD_REMESH "Enable Remesh Modifier" ON)
-option(WITH_MOD_OCEANSIM "Enable Ocean Modifier" OFF)
+option(WITH_MOD_OCEANSIM "Enable Ocean Modifier" ON)
# Image format support
option(WITH_OPENIMAGEIO "Enable OpenImageIO Support (http://www.openimageio.org)" ON)
-option(WITH_IMAGE_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" ${_init_IMAGE_OPENEXR})
+option(WITH_IMAGE_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" ON)
option(WITH_IMAGE_OPENJPEG "Enable OpenJpeg Support (http://www.openjpeg.org)" ON)
option(WITH_IMAGE_TIFF "Enable LibTIFF Support" ON)
option(WITH_IMAGE_DDS "Enable DDS Image Support" ON)
@@ -332,23 +264,28 @@ option(WITH_IMAGE_HDR "Enable HDR Image Support" ON)
# Audio/Video format support
option(WITH_CODEC_AVI "Enable Blenders own AVI file support (raw/jpeg)" ON)
-option(WITH_CODEC_FFMPEG "Enable FFMPeg Support (http://ffmpeg.org)" ${_init_CODEC_FFMPEG})
-option(WITH_CODEC_SNDFILE "Enable libsndfile Support (http://www.mega-nerd.com/libsndfile)" OFF)
+option(WITH_CODEC_FFMPEG "Enable FFMPeg Support (http://ffmpeg.org)" ON)
+option(WITH_CODEC_SNDFILE "Enable libsndfile Support (http://www.mega-nerd.com/libsndfile)" ON)
# Alembic support
-option(WITH_ALEMBIC "Enable Alembic Support" OFF)
+option(WITH_ALEMBIC "Enable Alembic Support" ON)
option(WITH_ALEMBIC_HDF5 "Enable Legacy Alembic Support (not officially supported)" OFF)
+# Universal Scene Description support
+option(WITH_USD "Enable Universal Scene Description (USD) Support" OFF)
+
# 3D format support
# Disable opencollada when we don't have precompiled libs
-option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.org)" ${_init_OPENCOLLADA})
+option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.org)" ON)
# Sound output
-option(WITH_SDL "Enable SDL for sound and joystick support" ${_init_SDL})
+option(WITH_SDL "Enable SDL for sound and joystick support" ON)
option(WITH_OPENAL "Enable OpenAL Support (http://www.openal.org)" ON)
-option(WITH_JACK "Enable JACK Support (http://www.jackaudio.org)" ${_init_JACK})
-if(UNIX AND NOT APPLE)
- option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF)
+if(NOT WIN32)
+ option(WITH_JACK "Enable JACK Support (http://www.jackaudio.org)" ON)
+ if(UNIX AND NOT APPLE)
+ option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF)
+ endif()
endif()
if(UNIX AND NOT APPLE)
option(WITH_SDL_DYNLOAD "Enable runtime dynamic SDL libraries loading" OFF)
@@ -364,7 +301,7 @@ option(WITH_DRACO "Enable Draco mesh compression Python module (used for
# Camera/motion tracking
option(WITH_LIBMV "Enable Libmv structure from motion library" ON)
-option(WITH_LIBMV_SCHUR_SPECIALIZATIONS "Enable fixed-size schur specializations." OFF)
+option(WITH_LIBMV_SCHUR_SPECIALIZATIONS "Enable fixed-size schur specializations." ON)
mark_as_advanced(WITH_LIBMV_SCHUR_SPECIALIZATIONS)
# Logging/unbit test libraries.
@@ -380,7 +317,7 @@ option(WITH_FREESTYLE "Enable Freestyle (advanced edges rendering)" ON)
if(WIN32)
option(WITH_INPUT_IME "Enable Input Method Editor (IME) for complex Asian character input" ON)
endif()
-option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ${_init_INPUT_NDOF})
+option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ON)
if(UNIX AND NOT APPLE)
option(WITH_INSTALL_PORTABLE "Install redistributeable runtime, otherwise install into CMAKE_INSTALL_PREFIX" ON)
option(WITH_STATIC_LIBS "Try to link with static libraries, as much as possible, to make blender more portable across distributions" OFF)
@@ -416,7 +353,7 @@ mark_as_advanced(WITH_CPU_SSE)
option(WITH_CYCLES "Enable Cycles Render Engine" ON)
option(WITH_CYCLES_STANDALONE "Build Cycles standalone application" OFF)
option(WITH_CYCLES_STANDALONE_GUI "Build Cycles standalone with GUI" OFF)
-option(WITH_CYCLES_OSL "Build Cycles with OSL support" ${_init_CYCLES_OSL})
+option(WITH_CYCLES_OSL "Build Cycles with OSL support" ON)
option(WITH_CYCLES_EMBREE "Build Cycles with Embree support" OFF)
option(WITH_CYCLES_CUDA_BINARIES "Build Cycles CUDA binaries" OFF)
option(WITH_CYCLES_CUBIN_COMPILER "Build cubins with nvrtc based compiler instead of nvcc" OFF)
@@ -472,7 +409,11 @@ mark_as_advanced(WITH_ASSERT_ABORT)
option(WITH_BOOST "Enable features depending on boost" ON)
option(WITH_TBB "Enable features depending on TBB (OpenVDB, OpenImageDenoise, sculpt multithreading)" ON)
-option(WITH_TBB_MALLOC_PROXY "Enable the TBB malloc replacement" ${_init_TBB_MALLOC_PROXY})
+
+# TBB malloc is only supported on for windows currently
+if(WIN32)
+ option(WITH_TBB_MALLOC_PROXY "Enable the TBB malloc replacement" ON)
+endif()
# Unit testsing
option(WITH_GTESTS "Enable GTest unit testing" OFF)
@@ -576,6 +517,10 @@ if(WIN32)
option(WINDOWS_PYTHON_DEBUG "Include the files needed for debugging python scripts with visual studio 2017+." OFF)
mark_as_advanced(WINDOWS_PYTHON_DEBUG)
+
+ option(WITH_WINDOWS_BUNDLE_CRT "Bundle the C runtime for install free distribution." ON)
+ mark_as_advanced(WITH_WINDOWS_BUNDLE_CRT)
+
endif()
# The following only works with the Ninja generator in CMake >= 3.0.
@@ -595,9 +540,6 @@ endif()
option(POSTINSTALL_SCRIPT "Run given CMake script after installation process" OFF)
mark_as_advanced(POSTINSTALL_SCRIPT)
-# avoid using again
-option_defaults_clear()
-
# end option(...)
@@ -1796,6 +1738,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_OPENVDB)
info_cfg_option(WITH_ALEMBIC)
info_cfg_option(WITH_QUADRIFLOW)
+ info_cfg_option(WITH_USD)
info_cfg_text("Compiler Options:")
info_cfg_option(WITH_BUILDINFO)
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index 623acbf4c18..2557e215afd 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -92,6 +92,7 @@ include(cmake/python.cmake)
include(cmake/python_site_packages.cmake)
include(cmake/package_python.cmake)
include(cmake/numpy.cmake)
+include(cmake/usd.cmake)
if(UNIX AND NOT APPLE)
# Rely on PugiXML compiled with OpenImageIO
else()
diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake
index 4152c0c9b94..4c6c1171562 100644
--- a/build_files/build_environment/cmake/harvest.cmake
+++ b/build_files/build_environment/cmake/harvest.cmake
@@ -199,6 +199,9 @@ harvest(x264/lib ffmpeg/lib "*.a")
harvest(xvidcore/lib ffmpeg/lib "*.a")
harvest(embree/include embree/include "*.h")
harvest(embree/lib embree/lib "*.a")
+harvest(usd/include usd/include "*.h")
+harvest(usd/lib/usd usd/lib/usd "*")
+harvest(usd/plugin usd/plugin "*")
if(UNIX AND NOT APPLE)
harvest(libglu/lib mesa/lib "*.so*")
diff --git a/build_files/build_environment/cmake/usd.cmake b/build_files/build_environment/cmake/usd.cmake
new file mode 100644
index 00000000000..c3594390f80
--- /dev/null
+++ b/build_files/build_environment/cmake/usd.cmake
@@ -0,0 +1,101 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(USD_EXTRA_ARGS
+ -DBoost_COMPILER:STRING=${BOOST_COMPILER_STRING}
+ -DBoost_USE_MULTITHREADED=ON
+ -DBoost_USE_STATIC_LIBS=ON
+ -DBoost_USE_STATIC_RUNTIME=OFF
+ -DBOOST_ROOT=${LIBDIR}/boost
+ -DTBB_INCLUDE_DIRS=${LIBDIR}/tbb/include
+ -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/${LIBPREFIX}tbb_static${LIBEXT}
+ -DTbb_TBB_LIBRARY=${LIBDIR}/tbb/lib/${LIBPREFIX}tbb_static${LIBEXT}
+
+ # This is a preventative measure that avoids possible conflicts when add-ons
+ # try to load another USD library into the same process space.
+ -DPXR_SET_INTERNAL_NAMESPACE=usdBlender
+
+ -DPXR_ENABLE_PYTHON_SUPPORT=OFF
+ -DPXR_BUILD_IMAGING=OFF
+ -DPXR_BUILD_TESTS=OFF
+ -DBUILD_SHARED_LIBS=OFF
+ -DPYTHON_EXECUTABLE=${PYTHON_BINARY}
+ -DPXR_BUILD_MONOLITHIC=ON
+
+ # The PXR_BUILD_USD_TOOLS argument is patched-in by usd.diff. An upstream pull request
+ # can be found at https://github.com/PixarAnimationStudios/USD/pull/1048.
+ -DPXR_BUILD_USD_TOOLS=OFF
+
+ -DCMAKE_DEBUG_POSTFIX=_d
+ # USD is hellbound on making a shared lib, unless you point this variable to a valid cmake file
+ # doesn't have to make sense, but as long as it points somewhere valid it will skip the shared lib.
+ -DPXR_MONOLITHIC_IMPORT=${BUILD_DIR}/usd/src/external_usd/cmake/defaults/Version.cmake
+)
+
+ExternalProject_Add(external_usd
+ URL ${USD_URI}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH MD5=${USD_HASH}
+ PREFIX ${BUILD_DIR}/usd
+ PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/usd/src/external_usd < ${PATCH_DIR}/usd.diff
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/usd -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${USD_EXTRA_ARGS}
+ INSTALL_DIR ${LIBDIR}/usd
+)
+
+add_dependencies(
+ external_usd
+ external_tbb
+ external_boost
+)
+
+if(WIN32)
+ # USD currently demands python be available at build time
+ # and then proceeds not to use it, but still checks that the
+ # version of the interpreter it is not going to use is atleast 2.7
+ # so we need this dep currently since there is no system python
+ # on windows.
+ add_dependencies(
+ external_usd
+ external_python
+ )
+ if(BUILD_MODE STREQUAL Release)
+ ExternalProject_Add_Step(external_usd after_install
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/usd/ ${HARVEST_TARGET}/usd
+ COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/Release/libusd_m.lib ${HARVEST_TARGET}/usd/lib/libusd_m.lib
+ DEPENDEES install
+ )
+ endif()
+ if(BUILD_MODE STREQUAL Debug)
+ ExternalProject_Add_Step(external_usd after_install
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/usd/lib ${HARVEST_TARGET}/usd/lib
+ COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/Debug/libusd_m_d.lib ${HARVEST_TARGET}/usd/lib/libusd_m_d.lib
+ DEPENDEES install
+ )
+ endif()
+else()
+ # USD has two build options. The default build creates lots of small libraries,
+ # whereas the 'monolithic' build produces only a single library. The latter
+ # makes linking simpler, so that's what we use in Blender. However, running
+ # 'make install' in the USD sources doesn't install the static library in that
+ # case (only the shared library). As a result, we need to grab the `libusd_m.a`
+ # file from the build directory instead of from the install directory.
+ ExternalProject_Add_Step(external_usd after_install
+ COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/libusd_m.a ${HARVEST_TARGET}/usd/lib/libusd_m.a
+ DEPENDEES install
+ )
+endif()
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index 519b11d2b9d..2c0091d2129 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -307,6 +307,10 @@ set(EMBREE_VERSION 3.2.4)
set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip)
set(EMBREE_HASH 3d4a1147002ff43939d45140aa9d6fb8)
+set(USD_VERSION 19.11)
+set(USD_URI https://github.com/PixarAnimationStudios/USD/archive/v${USD_VERSION}.tar.gz)
+set(USD_HASH 79ff176167b3fe85f4953abd6cc5e0cc)
+
set(OIDN_VERSION 1.0.0)
set(OIDN_URI https://github.com/OpenImageDenoise/oidn/releases/download/v${OIDN_VERSION}/oidn-${OIDN_VERSION}.src.zip)
set(OIDN_HASH 19fe67b0164e8f020ac8a4f520defe60)
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index f56653bbecd..20d2e1ae781 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -800,7 +800,7 @@ while true; do
;;
*)
PRINT ""
- ERROR "Wrong parameter! Usage:"
+ ERROR "Wrong parameter '$1'; Usage:"
PRINT ""
PRINT "`eval _echo "$COMMON_INFO"`"
PRINT ""
@@ -2392,7 +2392,7 @@ compile_ALEMBIC() {
prepare_opt
- if [ ! -d $_src -o true ]; then
+ if [ ! -d $_src ]; then
mkdir -p $SRC
download ALEMBIC_SOURCE[@] "$_src.tar.gz"
diff --git a/build_files/build_environment/patches/usd.diff b/build_files/build_environment/patches/usd.diff
new file mode 100644
index 00000000000..8afd9700e59
--- /dev/null
+++ b/build_files/build_environment/patches/usd.diff
@@ -0,0 +1,111 @@
+diff -x .git -ur usd.orig/cmake/defaults/Options.cmake external_usd/cmake/defaults/Options.cmake
+--- usd.orig/cmake/defaults/Options.cmake 2019-10-24 22:39:53.000000000 +0200
++++ external_usd/cmake/defaults/Options.cmake 2019-11-28 13:00:33.197957712 +0100
+@@ -25,6 +25,7 @@
+ option(PXR_VALIDATE_GENERATED_CODE "Validate script generated code" OFF)
+ option(PXR_HEADLESS_TEST_MODE "Disallow GUI based tests, useful for running under headless CI systems." OFF)
+ option(PXR_BUILD_TESTS "Build tests" ON)
++option(PXR_BUILD_USD_TOOLS "Build commandline tools" ON)
+ option(PXR_BUILD_IMAGING "Build imaging components" ON)
+ option(PXR_BUILD_EMBREE_PLUGIN "Build embree imaging plugin" OFF)
+ option(PXR_BUILD_OPENIMAGEIO_PLUGIN "Build OpenImageIO plugin" OFF)
+diff -x .git -ur usd.orig/cmake/defaults/Packages.cmake external_usd/cmake/defaults/Packages.cmake
+--- usd.orig/cmake/defaults/Packages.cmake 2019-10-24 22:39:53.000000000 +0200
++++ external_usd/cmake/defaults/Packages.cmake 2019-11-28 13:00:33.185957483 +0100
+@@ -64,7 +64,7 @@
+ endif()
+
+ # --TBB
+-find_package(TBB REQUIRED COMPONENTS tbb)
++find_package(TBB)
+ add_definitions(${TBB_DEFINITIONS})
+
+ # --math
+diff -x .git -ur usd.orig/pxr/base/lib/plug/initConfig.cpp external_usd/pxr/base/lib/plug/initConfig.cpp
+--- usd.orig/pxr/base/lib/plug/initConfig.cpp 2019-10-24 22:39:53.000000000 +0200
++++ external_usd/pxr/base/lib/plug/initConfig.cpp 2019-12-11 11:00:37.643323127 +0100
+@@ -69,8 +69,38 @@
+
+ ARCH_CONSTRUCTOR(Plug_InitConfig, 2, void)
+ {
++ /* The contents of this constructor have been moved to usd_initialise_plugin_path(...) */
++}
++
++}; // end of anonymous namespace
++
++/**
++ * The contents of this function used to be in the static constructor Plug_InitConfig.
++ * This static constructor made it impossible for Blender to pass a path to the USD
++ * library at runtime, as the constructor would run before Blender's main() function.
++ *
++ * This function is wrapped in a C function of the same name (defined below),
++ * so that it can be called from Blender's main() function.
++ *
++ * The datafiles_usd_path path is used to point to the USD plugin path when Blender
++ * has been installed. The fallback_usd_path path should point to the build-time
++ * location of the USD plugin files so that Blender can be run on a development machine
++ * without requiring an installation step.
++ */
++void
++usd_initialise_plugin_path(const char *datafiles_usd_path)
++{
+ std::vector<std::string> result;
+
++ // Add Blender-specific paths. They MUST end in a slash, or symlinks will not be treated as directory.
++ if (datafiles_usd_path != NULL && datafiles_usd_path[0] != '\0') {
++ std::string datafiles_usd_path_str(datafiles_usd_path);
++ if (datafiles_usd_path_str.back() != '/') {
++ datafiles_usd_path_str += "/";
++ }
++ result.push_back(datafiles_usd_path_str);
++ }
++
+ // Determine the absolute path to the Plug shared library.
+ // Any relative paths specified in the plugin search path will be
+ // anchored to this directory, to allow for relocatability.
+@@ -94,9 +124,24 @@
+ _AppendPathList(&result, installLocation, sharedLibPath);
+ #endif // PXR_INSTALL_LOCATION
+
+- Plug_SetPaths(result);
+-}
++ if (!TfGetenv("PXR_PATH_DEBUG").empty()) {
++ printf("USD Plugin paths: (%zu in total):\n", result.size());
++ for(const std::string &path : result) {
++ printf(" %s\n", path.c_str());
++ }
++ }
+
++ Plug_SetPaths(result);
+ }
+
+ PXR_NAMESPACE_CLOSE_SCOPE
++
++/* Workaround to make it possible to pass a path at runtime to USD. */
++extern "C" {
++void
++usd_initialise_plugin_path(
++ const char *datafiles_usd_path)
++{
++ PXR_NS::usd_initialise_plugin_path(datafiles_usd_path);
++}
++}
+diff -x .git -ur usd.orig/pxr/usd/CMakeLists.txt external_usd/pxr/usd/CMakeLists.txt
+--- usd.orig/pxr/usd/CMakeLists.txt 2019-10-24 22:39:53.000000000 +0200
++++ external_usd/pxr/usd/CMakeLists.txt 2019-11-28 13:00:33.197957712 +0100
+@@ -1,6 +1,5 @@
+ set(DIRS
+ lib
+- bin
+ plugin
+ )
+
+@@ -8,3 +7,8 @@
+ add_subdirectory(${d})
+ endforeach()
+
++if (PXR_BUILD_USD_TOOLS)
++ add_subdirectory(bin)
++else()
++ message(STATUS "Skipping commandline tools because PXR_BUILD_USD_TOOLS=OFF")
++endif()
diff --git a/build_files/buildbot/codesign/windows_code_signer.py b/build_files/buildbot/codesign/windows_code_signer.py
index 9481b66ee1e..638f098d8bc 100644
--- a/build_files/buildbot/codesign/windows_code_signer.py
+++ b/build_files/buildbot/codesign/windows_code_signer.py
@@ -53,7 +53,7 @@ class WindowsCodeSigner(BaseCodeSigner):
return [
'signtool', 'sign', '/v',
'/f', self.config.CERTIFICATE_FILEPATH,
- '/t', self.config.TIMESTAMP_AUTHORITY_URL]
+ '/tr', self.config.TIMESTAMP_AUTHORITY_URL]
def sign_all_files(self, files: List[AbsoluteAndRelativeFileName]) -> None:
# NOTE: Sign files one by one to avoid possible command line length
diff --git a/build_files/buildbot/slave_pack.py b/build_files/buildbot/slave_pack.py
index 19dac236762..bbacedca0ce 100644
--- a/build_files/buildbot/slave_pack.py
+++ b/build_files/buildbot/slave_pack.py
@@ -64,7 +64,7 @@ def create_buildbot_upload_zip(builder, package_files):
sys.stderr.write('Create buildbot_upload.zip failed: ' + str(ex) + '\n')
sys.exit(1)
-def create_tar_bz2(src, dest, package_name):
+def create_tar_xz(src, dest, package_name):
# One extra to remove leading os.sep when cleaning root for package_root
ln = len(src) + 1
flist = list()
@@ -75,9 +75,20 @@ def create_tar_bz2(src, dest, package_name):
flist.extend([(os.path.join(root, file), os.path.join(package_root, file)) for file in files])
import tarfile
- package = tarfile.open(dest, 'w:bz2')
+
+ # Set UID/GID of archived files to 0, otherwise they'd be owned by whatever
+ # user compiled the package. If root then unpacks it to /usr/local/ you get
+ # a security issue.
+ def _fakeroot(tarinfo):
+ tarinfo.gid = 0
+ tarinfo.gname = "root"
+ tarinfo.uid = 0
+ tarinfo.uname = "root"
+ return tarinfo
+
+ package = tarfile.open(dest, 'w:xz', preset=9)
for entry in flist:
- package.add(entry[0], entry[1], recursive=False)
+ package.add(entry[0], entry[1], recursive=False, filter=_fakeroot)
package.close()
def cleanup_files(dirpath, extension):
@@ -163,11 +174,11 @@ def pack_linux(builder):
# Construct package name
platform_name = 'linux-' + blender_glibc + '-' + blender_arch
package_name = get_package_name(builder, platform_name)
- package_filename = package_name + ".tar.bz2"
+ package_filename = package_name + ".tar.xz"
- print("Creating .tar.bz2 archive")
- package_filepath = builder.install_dir + '.tar.bz2'
- create_tar_bz2(builder.install_dir, package_filepath, package_name)
+ print("Creating .tar.xz archive")
+ package_filepath = builder.install_dir + '.tar.xz'
+ create_tar_xz(builder.install_dir, package_filepath, package_name)
# Create buildbot_upload.zip
create_buildbot_upload_zip(builder, [(package_filepath, package_filename)])
diff --git a/build_files/cmake/Modules/FindUSD.cmake b/build_files/cmake/Modules/FindUSD.cmake
new file mode 100644
index 00000000000..3ebcbb178c6
--- /dev/null
+++ b/build_files/cmake/Modules/FindUSD.cmake
@@ -0,0 +1,75 @@
+# - Find Universal Scene Description (USD) library
+# Find the native USD includes and libraries
+# This module defines
+# USD_INCLUDE_DIRS, where to find USD headers, Set when
+# USD_INCLUDE_DIR is found.
+# USD_LIBRARIES, libraries to link against to use USD.
+# USD_ROOT_DIR, The base directory to search for USD.
+# This can also be an environment variable.
+# USD_FOUND, If false, do not try to use USD.
+#
+
+#=============================================================================
+# Copyright 2019 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If USD_ROOT_DIR was defined in the environment, use it.
+IF(NOT USD_ROOT_DIR AND NOT $ENV{USD_ROOT_DIR} STREQUAL "")
+ SET(USD_ROOT_DIR $ENV{USD_ROOT_DIR})
+ENDIF()
+
+SET(_usd_SEARCH_DIRS
+ ${USD_ROOT_DIR}
+ /usr/local
+ /opt/lib/usd
+ /opt/usd
+)
+
+FIND_PATH(USD_INCLUDE_DIR
+ NAMES
+ pxr/usd/usd/api.h
+ HINTS
+ ${_usd_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+ DOC "Universal Scene Description (USD) header files"
+)
+
+FIND_LIBRARY(USD_LIBRARY
+ NAMES
+ usd_m
+ HINTS
+ ${_usd_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib64 lib lib/static
+ DOC "Universal Scene Description (USD) monolithic library"
+)
+
+IF(${USD_LIBRARY_NOTFOUND})
+ set(USD_FOUND FALSE)
+ELSE()
+ # handle the QUIETLY and REQUIRED arguments and set USD_FOUND to TRUE if
+ # all listed variables are TRUE
+ INCLUDE(FindPackageHandleStandardArgs)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(USD DEFAULT_MSG USD_LIBRARY USD_INCLUDE_DIR)
+
+ IF(USD_FOUND)
+ get_filename_component(USD_LIBRARY_DIR ${USD_LIBRARY} DIRECTORY)
+ SET(USD_INCLUDE_DIRS ${USD_INCLUDE_DIR})
+ set(USD_LIBRARIES ${USD_LIBRARY})
+ ENDIF(USD_FOUND)
+ENDIF()
+
+MARK_AS_ADVANCED(
+ USD_INCLUDE_DIR
+ USD_LIBRARY_DIR
+)
+
+UNSET(_usd_SEARCH_DIRS)
diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake
index a93e829e6b0..30b10ae5980 100644
--- a/build_files/cmake/Modules/GTestTesting.cmake
+++ b/build_files/cmake/Modules/GTestTesting.cmake
@@ -12,9 +12,14 @@
#
#=============================================================================
-macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
+macro(BLENDER_SRC_GTEST_EX)
if(WITH_GTESTS)
- set(TARGET_NAME ${NAME}_test)
+ set(options SKIP_ADD_TEST)
+ set(oneValueArgs NAME)
+ set(multiValueArgs SRC EXTRA_LIBS COMMAND_ARGS)
+ cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ set(TARGET_NAME ${ARG_NAME}_test)
get_property(_current_include_directories
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
PROPERTY INCLUDE_DIRECTORIES)
@@ -29,12 +34,14 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
${CMAKE_SOURCE_DIR}/extern/gmock/include
)
unset(_current_include_directories)
-
- add_executable(${TARGET_NAME} ${SRC})
+ if(WIN32)
+ set(MANIFEST "${CMAKE_BINARY_DIR}/tests.exe.manifest")
+ endif()
+ add_executable(${TARGET_NAME} ${ARG_SRC} ${MANIFEST})
target_include_directories(${TARGET_NAME} PUBLIC "${TEST_INC}")
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC "${TEST_INC_SYS}")
target_link_libraries(${TARGET_NAME}
- ${EXTRA_LIBS}
+ ${ARG_EXTRA_LIBS}
${PLATFORM_LINKLIBS}
bf_testing_main
bf_intern_eigen
@@ -60,13 +67,19 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
RUNTIME_OUTPUT_DIRECTORY "${TESTS_OUTPUT_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TESTS_OUTPUT_DIR}"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TESTS_OUTPUT_DIR}")
- if(${DO_ADD_TEST})
- add_test(NAME ${TARGET_NAME} COMMAND ${TESTS_OUTPUT_DIR}/${TARGET_NAME} WORKING_DIRECTORY ${TEST_INSTALL_DIR})
+ if(NOT ARG_SKIP_ADD_TEST)
+ add_test(
+ NAME ${TARGET_NAME}
+ COMMAND ${TESTS_OUTPUT_DIR}/${TARGET_NAME} ${ARG_COMMAND_ARGS}
+ WORKING_DIRECTORY ${TEST_INSTALL_DIR})
# Don't fail tests on leaks since these often happen in external libraries
# that we can't fix.
set_tests_properties(${TARGET_NAME} PROPERTIES ENVIRONMENT LSAN_OPTIONS=exitcode=0)
endif()
+ if(WIN32)
+ unset(MANIFEST)
+ endif()
unset(TEST_INC)
unset(TEST_INC_SYS)
unset(TARGET_NAME)
@@ -74,13 +87,23 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
endmacro()
macro(BLENDER_SRC_GTEST NAME SRC EXTRA_LIBS)
- BLENDER_SRC_GTEST_EX("${NAME}" "${SRC}" "${EXTRA_LIBS}" "TRUE")
+ BLENDER_SRC_GTEST_EX(
+ NAME "${NAME}"
+ SRC "${SRC}"
+ EXTRA_LIBS "${EXTRA_LIBS}")
endmacro()
macro(BLENDER_TEST NAME EXTRA_LIBS)
- BLENDER_SRC_GTEST_EX("${NAME}" "${NAME}_test.cc" "${EXTRA_LIBS}" "TRUE")
+ BLENDER_SRC_GTEST_EX(
+ NAME "${NAME}"
+ SRC "${NAME}_test.cc"
+ EXTRA_LIBS "${EXTRA_LIBS}")
endmacro()
macro(BLENDER_TEST_PERFORMANCE NAME EXTRA_LIBS)
- BLENDER_SRC_GTEST_EX("${NAME}" "${NAME}_test.cc" "${EXTRA_LIBS}" "FALSE")
+ BLENDER_SRC_GTEST_EX(
+ NAME "${NAME}"
+ SRC "${NAME}_test.cc"
+ EXTRA_LIBS "${EXTRA_LIBS}"
+ SKIP_ADD_TEST)
endmacro()
diff --git a/build_files/cmake/config/blender_developer.cmake b/build_files/cmake/config/blender_developer.cmake
index 5209ce4ed25..29092b8c7c8 100644
--- a/build_files/cmake/config/blender_developer.cmake
+++ b/build_files/cmake/config/blender_developer.cmake
@@ -13,6 +13,9 @@ set(WITH_GTESTS ON CACHE BOOL "" FORCE)
set(WITH_LIBMV_SCHUR_SPECIALIZATIONS OFF CACHE BOOL "" FORCE)
set(WITH_PYTHON_SAFETY ON CACHE BOOL "" FORCE)
set(WITH_DOC_MANPAGE OFF CACHE BOOL "" FORCE)
+if(WIN32)
+ set(WITH_WINDOWS_BUNDLE_CRT OFF CACHE BOOL "" FORCE)
+endif()
# This may have issues with C++ initialization order, needs to be tested
# on all platforms to be sure this is safe to enable.
diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake
index 58a987018a0..34428fc0929 100644
--- a/build_files/cmake/config/blender_full.cmake
+++ b/build_files/cmake/config/blender_full.cmake
@@ -18,7 +18,6 @@ set(WITH_LIBMV ON CACHE BOOL "" FORCE)
set(WITH_LIBMV_SCHUR_SPECIALIZATIONS ON CACHE BOOL "" FORCE)
set(WITH_COMPOSITOR ON CACHE BOOL "" FORCE)
set(WITH_FREESTYLE ON CACHE BOOL "" FORCE)
-set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)
set(WITH_IK_SOLVER ON CACHE BOOL "" FORCE)
set(WITH_IK_ITASC ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_CINEON ON CACHE BOOL "" FORCE)
@@ -29,12 +28,10 @@ set(WITH_IMAGE_OPENJPEG ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_TIFF ON CACHE BOOL "" FORCE)
set(WITH_INPUT_NDOF ON CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL ON CACHE BOOL "" FORCE)
-set(WITH_JACK ON CACHE BOOL "" FORCE)
set(WITH_LZMA ON CACHE BOOL "" FORCE)
set(WITH_LZO ON CACHE BOOL "" FORCE)
-set(WITH_MOD_FLUID ON CACHE BOOL "" FORCE)
set(WITH_MOD_REMESH ON CACHE BOOL "" FORCE)
-set(WITH_MOD_SMOKE ON CACHE BOOL "" FORCE)
+set(WITH_MOD_FLUID ON CACHE BOOL "" FORCE)
set(WITH_MOD_OCEANSIM ON CACHE BOOL "" FORCE)
set(WITH_AUDASPACE ON CACHE BOOL "" FORCE)
set(WITH_OPENAL ON CACHE BOOL "" FORCE)
@@ -50,20 +47,18 @@ set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE)
set(WITH_QUADRIFLOW ON CACHE BOOL "" FORCE)
set(WITH_SDL ON CACHE BOOL "" FORCE)
set(WITH_TBB ON CACHE BOOL "" FORCE)
-set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
-set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE)
+set(WITH_USD ON CACHE BOOL "" FORCE)
set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE)
# platform dependent options
-if(UNIX AND NOT APPLE)
+if(NOT WIN32)
set(WITH_JACK ON CACHE BOOL "" FORCE)
+endif()
+if(UNIX AND NOT APPLE)
set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE)
-elseif(WIN32)
- set(WITH_JACK OFF CACHE BOOL "" FORCE)
-elseif(APPLE)
- set(WITH_JACK ON CACHE BOOL "" FORCE)
-
-# include("${CMAKE_CURRENT_SOURCE_DIR}/../platform/platform_apple_xcode.cmake")
+ set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)
+ set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
+ set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE)
endif()
diff --git a/build_files/cmake/config/blender_headless.cmake b/build_files/cmake/config/blender_headless.cmake
index a07a3a7f66c..53163986b7a 100644
--- a/build_files/cmake/config/blender_headless.cmake
+++ b/build_files/cmake/config/blender_headless.cmake
@@ -10,7 +10,6 @@ set(WITH_HEADLESS ON CACHE BOOL "" FORCE)
# disable audio, its possible some devs may want this but for now disable
# so the python module doesn't hold the audio device and loads quickly.
set(WITH_AUDASPACE OFF CACHE BOOL "" FORCE)
-set(WITH_FFTW3 OFF CACHE BOOL "" FORCE)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 808f0e4e679..91cc9e8c140 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -24,7 +24,6 @@ set(WITH_LIBMV OFF CACHE BOOL "" FORCE)
set(WITH_LLVM OFF CACHE BOOL "" FORCE)
set(WITH_COMPOSITOR OFF CACHE BOOL "" FORCE)
set(WITH_FREESTYLE OFF CACHE BOOL "" FORCE)
-set(WITH_GHOST_XDND OFF CACHE BOOL "" FORCE)
set(WITH_IK_SOLVER OFF CACHE BOOL "" FORCE)
set(WITH_IK_ITASC OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_CINEON OFF CACHE BOOL "" FORCE)
@@ -38,9 +37,8 @@ set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
set(WITH_LZMA OFF CACHE BOOL "" FORCE)
set(WITH_LZO OFF CACHE BOOL "" FORCE)
-set(WITH_MOD_FLUID OFF CACHE BOOL "" FORCE)
set(WITH_MOD_REMESH OFF CACHE BOOL "" FORCE)
-set(WITH_MOD_SMOKE OFF CACHE BOOL "" FORCE)
+set(WITH_MOD_FLUID OFF CACHE BOOL "" FORCE)
set(WITH_MOD_OCEANSIM OFF CACHE BOOL "" FORCE)
set(WITH_AUDASPACE OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
@@ -55,5 +53,9 @@ set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
set(WITH_QUADRIFLOW OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_TBB OFF CACHE BOOL "" FORCE)
-set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE)
-set(WITH_X11_XF86VMODE OFF CACHE BOOL "" FORCE)
+
+if(UNIX AND NOT APPLE)
+ set(WITH_GHOST_XDND OFF CACHE BOOL "" FORCE)
+ set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE)
+ set(WITH_X11_XF86VMODE OFF CACHE BOOL "" FORCE)
+endif()
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
index 376e765cc3e..f432435111f 100644
--- a/build_files/cmake/config/blender_release.cmake
+++ b/build_files/cmake/config/blender_release.cmake
@@ -19,7 +19,6 @@ set(WITH_LIBMV ON CACHE BOOL "" FORCE)
set(WITH_LIBMV_SCHUR_SPECIALIZATIONS ON CACHE BOOL "" FORCE)
set(WITH_COMPOSITOR ON CACHE BOOL "" FORCE)
set(WITH_FREESTYLE ON CACHE BOOL "" FORCE)
-set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)
set(WITH_IK_SOLVER ON CACHE BOOL "" FORCE)
set(WITH_IK_ITASC ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_CINEON ON CACHE BOOL "" FORCE)
@@ -30,12 +29,10 @@ set(WITH_IMAGE_OPENJPEG ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_TIFF ON CACHE BOOL "" FORCE)
set(WITH_INPUT_NDOF ON CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL ON CACHE BOOL "" FORCE)
-set(WITH_JACK ON CACHE BOOL "" FORCE)
set(WITH_LZMA ON CACHE BOOL "" FORCE)
set(WITH_LZO ON CACHE BOOL "" FORCE)
-set(WITH_MOD_FLUID ON CACHE BOOL "" FORCE)
set(WITH_MOD_REMESH ON CACHE BOOL "" FORCE)
-set(WITH_MOD_SMOKE ON CACHE BOOL "" FORCE)
+set(WITH_MOD_FLUID ON CACHE BOOL "" FORCE)
set(WITH_MOD_OCEANSIM ON CACHE BOOL "" FORCE)
set(WITH_AUDASPACE ON CACHE BOOL "" FORCE)
set(WITH_OPENAL ON CACHE BOOL "" FORCE)
@@ -51,8 +48,7 @@ set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE)
set(WITH_QUADRIFLOW ON CACHE BOOL "" FORCE)
set(WITH_SDL ON CACHE BOOL "" FORCE)
set(WITH_TBB ON CACHE BOOL "" FORCE)
-set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
-set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE)
+set(WITH_USD ON CACHE BOOL "" FORCE)
set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_CUDA_BINARIES ON CACHE BOOL "" FORCE)
@@ -61,13 +57,12 @@ set(CYCLES_CUDA_BINARIES_ARCH sm_30;sm_35;sm_37;sm_50;sm_52;sm_60;sm_61;sm_70;sm
set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE)
# platform dependent options
-if(UNIX AND NOT APPLE)
+if(NOT WIN32)
set(WITH_JACK ON CACHE BOOL "" FORCE)
+endif()
+if(UNIX AND NOT APPLE)
set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE)
-elseif(WIN32)
- set(WITH_JACK OFF CACHE BOOL "" FORCE)
-elseif(APPLE)
- set(WITH_JACK ON CACHE BOOL "" FORCE)
-
-# include("${CMAKE_CURRENT_SOURCE_DIR}/../platform/platform_apple_xcode.cmake")
+ set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)
+ set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
+ set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE)
endif()
diff --git a/build_files/cmake/config/bpy_module.cmake b/build_files/cmake/config/bpy_module.cmake
index 99bf17475c8..188315f58f2 100644
--- a/build_files/cmake/config/bpy_module.cmake
+++ b/build_files/cmake/config/bpy_module.cmake
@@ -15,7 +15,6 @@ set(WITH_PYTHON_INSTALL OFF CACHE BOOL "" FORCE)
# disable audio, its possible some devs may want this but for now disable
# so the python module doesn't hold the audio device and loads quickly.
set(WITH_AUDASPACE OFF CACHE BOOL "" FORCE)
-set(WITH_FFTW3 OFF CACHE BOOL "" FORCE)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 48c196d6983..70aacaa686c 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -466,6 +466,22 @@ function(setup_liblinks
if(WITH_OPENVDB)
target_link_libraries(${target} ${OPENVDB_LIBRARIES} ${BLOSC_LIBRARIES})
endif()
+ if(WITH_USD)
+ # Source: https://github.com/PixarAnimationStudios/USD/blob/master/BUILDING.md#linking-whole-archives
+ if(WIN32)
+ target_link_libraries(${target} ${USD_LIBRARIES})
+ set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG " /WHOLEARCHIVE:libusd_m_d.lib")
+ set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS_RELEASE " /WHOLEARCHIVE:libusd_m.lib")
+ set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO " /WHOLEARCHIVE:libusd_m.lib")
+ set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL " /WHOLEARCHIVE:libusd_m.lib")
+ elseif(CMAKE_COMPILER_IS_GNUCXX)
+ target_link_libraries(${target} -Wl,--whole-archive ${USD_LIBRARIES} -Wl,--no-whole-archive)
+ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+ target_link_libraries(${target} -Wl,-force_load ${USD_LIBRARIES})
+ else()
+ message(FATAL_ERROR "Unknown how to link USD with your compiler ${CMAKE_CXX_COMPILER_ID}")
+ endif()
+ endif()
if(WITH_OPENIMAGEIO)
target_link_libraries(${target} ${OPENIMAGEIO_LIBRARIES})
endif()
@@ -1223,10 +1239,10 @@ macro(openmp_delayload
else()
set(OPENMP_DLL_NAME "vcomp140")
endif()
- SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_RELEASE "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
- SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_DEBUG "/DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib")
- SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
- SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_MINSIZEREL "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
+ set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_RELEASE " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
+ set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG " /DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib")
+ set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
+ set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
endif()
endif()
endmacro()
diff --git a/build_files/cmake/packaging.cmake b/build_files/cmake/packaging.cmake
index 5ace42646c5..0e530463659 100644
--- a/build_files/cmake/packaging.cmake
+++ b/build_files/cmake/packaging.cmake
@@ -135,7 +135,7 @@ elseif(UNIX)
add_package_archive(
"${PROJECT_NAME}-${BLENDER_VERSION}-${BUILD_REV}-${PACKAGE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}"
- "tar.bz2")
+ "tar.xz")
endif()
unset(MAJOR_VERSION)
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index 8bd8d361493..b418097d5de 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -56,6 +56,13 @@ if(WITH_ALEMBIC)
set(ALEMBIC_FOUND ON)
endif()
+if(WITH_USD)
+ find_package(USD)
+ if(NOT USD_FOUND)
+ set(WITH_USD OFF)
+ endif()
+endif()
+
if(WITH_OPENSUBDIV)
set(OPENSUBDIV ${LIBDIR}/opensubdiv)
set(OPENSUBDIV_LIBPATH ${OPENSUBDIV}/lib)
@@ -404,6 +411,10 @@ if(NOT WITH_TBB OR NOT TBB_FOUND)
message(STATUS "TBB not found, disabling OpenVDB")
set(WITH_OPENVDB OFF)
endif()
+ if(WITH_MOD_FLUID)
+ message(STATUS "TBB not found, disabling Fluid modifier")
+ set(WITH_MOD_FLUID OFF)
+ endif()
endif()
# CMake FindOpenMP doesn't know about AppleClang before 3.12, so provide custom flags.
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 13fff9bd8c8..adf9d8e029c 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -285,6 +285,14 @@ if(WITH_ALEMBIC)
endif()
endif()
+if(WITH_USD)
+ find_package_wrapper(USD)
+
+ if(NOT USD_FOUND)
+ set(WITH_USD OFF)
+ endif()
+endif()
+
if(WITH_BOOST)
# uses in build instructions to override include and library variables
if(NOT BOOST_CUSTOM)
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index 8a93b68e38f..d49287da851 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -113,7 +113,7 @@ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
list(APPEND PLATFORM_LINKLIBS
ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32
- advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp
+ advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp Shlwapi
)
if(WITH_INPUT_IME)
@@ -133,14 +133,7 @@ add_definitions(-D_ALLOW_KEYWORD_MACROS)
# We want to support Vista level ABI
add_definitions(-D_WIN32_WINNT=0x600)
-
-# Make cmake find the msvc redistributables
-set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP FALSE)
-set(CMAKE_INSTALL_UCRT_LIBRARIES TRUE)
-set(CMAKE_INSTALL_OPENMP_LIBRARIES ${WITH_OPENMP})
-set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION .)
-include(InstallRequiredSystemLibraries)
-
+include(build_files/cmake/platform/platform_win32_bundle_crt.cmake)
remove_cc_flag("/MDd" "/MD")
if(MSVC_CLANG) # Clangs version of cl doesn't support all flags
@@ -574,6 +567,10 @@ else()
message(STATUS "TBB disabled, also disabling OpenVDB")
set(WITH_OPENVDB OFF)
endif()
+ if(WITH_MOD_FLUID)
+ message(STATUS "TBB disabled, disabling Fluid modifier")
+ set(WITH_MOD_FLUID OFF)
+ endif()
endif()
# used in many places so include globally, like OpenGL
@@ -658,6 +655,18 @@ if(WITH_CYCLES_EMBREE)
endif()
endif()
+if(WITH_USD)
+ windows_find_package(USD)
+ if(NOT USD_FOUND)
+ set(USD_FOUND ON)
+ set(USD_INCLUDE_DIRS ${LIBDIR}/usd/include)
+ set(USD_LIBRARIES
+ debug ${LIBDIR}/usd/lib/libusd_m_d.lib
+ optimized ${LIBDIR}/usd/lib/libusd_m.lib
+ )
+ endif()
+endif()
+
if(WINDOWS_PYTHON_DEBUG)
# Include the system scripts in the blender_python_system_scripts project.
FILE(GLOB_RECURSE inFiles "${CMAKE_SOURCE_DIR}/release/scripts/*.*" )
diff --git a/build_files/cmake/platform/platform_win32_bundle_crt.cmake b/build_files/cmake/platform/platform_win32_bundle_crt.cmake
new file mode 100644
index 00000000000..abadaa112a2
--- /dev/null
+++ b/build_files/cmake/platform/platform_win32_bundle_crt.cmake
@@ -0,0 +1,35 @@
+# First generate the manifest for tests since it will not need the dependency on the CRT.
+configure_file(${CMAKE_SOURCE_DIR}/release/windows/manifest/blender.exe.manifest.in ${CMAKE_CURRENT_BINARY_DIR}/tests.exe.manifest @ONLY)
+
+if(WITH_WINDOWS_BUNDLE_CRT)
+ set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
+ set(CMAKE_INSTALL_UCRT_LIBRARIES TRUE)
+ set(CMAKE_INSTALL_OPENMP_LIBRARIES ${WITH_OPENMP})
+ include(InstallRequiredSystemLibraries)
+
+ # Install the CRT to the blender.crt Sub folder.
+ install(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ./blender.crt COMPONENT Libraries)
+
+ # Generating the manifest is a relativly expensive operation since
+ # it is collecting an sha1 hash for every file required. so only do
+ # this work when the libs have either changed or the manifest does
+ # not exist yet.
+
+ string(SHA1 libshash "${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}")
+ set(manifest_trigger_file "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/crt_${libshash}")
+
+ if(NOT EXISTS ${manifest_trigger_file})
+ set(CRTLIBS "")
+ foreach(lib ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS})
+ get_filename_component(filename ${lib} NAME)
+ file(SHA1 "${lib}" sha1_file)
+ set(CRTLIBS "${CRTLIBS} <file name=\"${filename}\" hash=\"${sha1_file}\" hashalg=\"SHA1\" />\n")
+ endforeach()
+ configure_file(${CMAKE_SOURCE_DIR}/release/windows/manifest/blender.crt.manifest.in ${CMAKE_CURRENT_BINARY_DIR}/blender.crt.manifest @ONLY)
+ file(TOUCH ${manifest_trigger_file})
+ endif()
+
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/blender.crt.manifest DESTINATION ./blender.crt)
+ set(BUNDLECRT "<dependency><dependentAssembly><assemblyIdentity type=\"win32\" name=\"blender.crt\" version=\"1.0.0.0\" /></dependentAssembly></dependency>")
+endif()
+configure_file(${CMAKE_SOURCE_DIR}/release/windows/manifest/blender.exe.manifest.in ${CMAKE_CURRENT_BINARY_DIR}/blender.exe.manifest @ONLY)
diff --git a/build_files/package_spec/build_archive.py b/build_files/package_spec/build_archive.py
index 5ca2f319d87..d8d3c29ea48 100755
--- a/build_files/package_spec/build_archive.py
+++ b/build_files/package_spec/build_archive.py
@@ -49,15 +49,19 @@ try:
if not os.path.exists(output_dir):
os.mkdir(output_dir)
+ archive_env = os.environ.copy()
+
if extension == 'zip':
archive_cmd = ['zip', '-9', '-r', package_archive, package_dir]
- elif extension == 'tar.bz2':
- archive_cmd = ['tar', 'cjf', package_archive, package_dir]
+ elif extension == 'tar.xz':
+ archive_cmd = ['tar', '-cf', package_archive, '--owner=0', '--group=0',
+ '--use-compress-program=xz', package_dir]
+ archive_env['XZ_OPT'] = '-9'
else:
sys.stderr.write('Unknown archive extension: ' + extension)
sys.exit(-1)
- subprocess.call(archive_cmd)
+ subprocess.check_call(archive_cmd, env=archive_env)
except Exception as ex:
sys.stderr.write('Failed to create package archive: ' + str(ex) + '\n')
sys.exit(1)
diff --git a/doc/doxygen/doxygen.intern.h b/doc/doxygen/doxygen.intern.h
index 8e51cb01df0..98fb039c90b 100644
--- a/doc/doxygen/doxygen.intern.h
+++ b/doc/doxygen/doxygen.intern.h
@@ -18,10 +18,6 @@
* \ingroup intern
*/
-/** \defgroup elbeem elbeem
- * \ingroup intern
- */
-
/** \defgroup iksolver iksolver
* \ingroup intern
*/
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index c334ffd798f..278a2700f27 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -1055,7 +1055,6 @@ context_type_map = {
"selected_sequences": ("Sequence", True),
"selected_visible_fcurves": ("FCurve", True),
"sequences": ("Sequence", True),
- "smoke": ("SmokeModifier", False),
"soft_body": ("SoftBodyModifier", False),
"speaker": ("Speaker", False),
"texture": ("Texture", False),
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index b985a39106b..e79aba0e988 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -105,3 +105,7 @@ if(WITH_QUADRIFLOW)
set(QUADRIFLOW_CMAKE_CFG ${CMAKE_CURRENT_SOURCE_DIR}/quadriflow/blender_config.cmake)
add_subdirectory(quadriflow)
endif()
+
+if(WITH_MOD_FLUID)
+ add_subdirectory(mantaflow)
+endif()
diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic.c b/extern/curve_fit_nd/intern/curve_fit_cubic.c
index 0005cbe5a93..47c5344c821 100644
--- a/extern/curve_fit_nd/intern/curve_fit_cubic.c
+++ b/extern/curve_fit_nd/intern/curve_fit_cubic.c
@@ -611,13 +611,26 @@ static void cubic_from_points_offset_fallback(
}
}
+ /* The value of 'dists[..] / 0.75' is the length to use when the tangents
+ * are perpendicular to the direction defined by the two points.
+ *
+ * Project tangents onto these perpendicular lengths.
+ * Note that this can cause divide by zero in the case of co-linear tangents.
+ * The limits check afterwards accounts for this.
+ *
+ * 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)
+ * 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));
double alpha_r = (dists[1] / 0.75) / fabs(dot_vnvn(tan_r, a[1], dims));
- if (!(alpha_l > 0.0)) {
+
+ if (!(alpha_l > 0.0) || (alpha_l > dists[0] + dir_dist)) {
alpha_l = dir_dist / 3.0;
}
- if (!(alpha_r > 0.0)) {
+ if (!(alpha_r > 0.0) || (alpha_r > dists[1] + dir_dist)) {
alpha_r = dir_dist / 3.0;
}
diff --git a/extern/draco/CMakeLists.txt b/extern/draco/CMakeLists.txt
index c51af24c9a4..1355766960a 100644
--- a/extern/draco/CMakeLists.txt
+++ b/extern/draco/CMakeLists.txt
@@ -24,6 +24,6 @@ set(CMAKE_CXX_STANDARD 14)
add_subdirectory(dracoenc)
# Build blender-draco-exporter module.
-add_library(extern_draco SHARED src/draco-compressor.cpp)
+add_library(extern_draco SHARED src/draco-compressor.cpp src/draco-compressor.h)
target_include_directories(extern_draco PUBLIC dracoenc/src)
target_link_libraries(extern_draco PUBLIC dracoenc)
diff --git a/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc b/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc
index 41193f1452f..237becefc61 100644
--- a/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc
+++ b/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc
@@ -92,6 +92,11 @@ bool AttributeQuantizationTransform::ComputeParameters(
range_ = dif;
}
+ // In case all values are the same, initialize the range to unit length. This
+ // will ensure that all values are quantized properly to the same value.
+ if (range_ == 0.f)
+ range_ = 1.f;
+
return true;
}
diff --git a/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h b/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h
index 5244056f0aa..80e43e30a13 100644
--- a/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h
+++ b/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h
@@ -28,11 +28,11 @@ DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, AttributeValueIndex)
// Index of a point in a PointCloud.
DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, PointIndex)
// Vertex index in a Mesh or CornerTable.
-DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, VertexIndex);
+DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, VertexIndex)
// Corner index that identifies a corner in a Mesh or CornerTable.
-DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, CornerIndex);
+DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, CornerIndex)
// Face index for Mesh and CornerTable.
-DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, FaceIndex);
+DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, FaceIndex)
// Constants denoting invalid indices.
static constexpr AttributeValueIndex kInvalidAttributeValueIndex(
diff --git a/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc b/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc
index 4428f332b93..0c4e8e1c738 100644
--- a/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc
+++ b/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc
@@ -64,7 +64,7 @@ bool PointAttribute::Reset(size_t num_attribute_values) {
return true;
}
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
AttributeValueIndex::ValueType PointAttribute::DeduplicateValues(
const GeometryAttribute &in_att) {
return DeduplicateValues(in_att, AttributeValueIndex(0));
diff --git a/extern/draco/dracoenc/src/draco/attributes/point_attribute.h b/extern/draco/dracoenc/src/draco/attributes/point_attribute.h
index dffde50356d..46e58a40aa1 100644
--- a/extern/draco/dracoenc/src/draco/attributes/point_attribute.h
+++ b/extern/draco/dracoenc/src/draco/attributes/point_attribute.h
@@ -105,7 +105,7 @@ class PointAttribute : public GeometryAttribute {
return GetValue(mapped_index(point_index), out_data);
}
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
// Deduplicate |in_att| values into |this| attribute. |in_att| can be equal
// to |this|.
// Returns -1 if the deduplication failed.
@@ -130,7 +130,7 @@ class PointAttribute : public GeometryAttribute {
}
private:
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
template <typename T>
AttributeValueIndex::ValueType DeduplicateTypedValues(
const GeometryAttribute &in_att, AttributeValueIndex in_att_offset);
diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector.h b/extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector.h
index 4148770fe77..ce99c8014d7 100644
--- a/extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector.h
+++ b/extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector.h
@@ -42,7 +42,7 @@ class PseudoPointD {
// Specifically copies referenced memory
void swap(PseudoPointD &other) noexcept {
- for (auto dim = 0; dim < dimension_; dim += 1)
+ for (internal_t dim = 0; dim < dimension_; dim += 1)
std::swap(mem_[dim], other.mem_[dim]);
}
diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h
index 3a00bda943c..db835554385 100644
--- a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h
+++ b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h
@@ -21,7 +21,9 @@
#include "draco/draco_features.h"
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_decoder.h"
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_decoder.h"
+#endif
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_decoder.h"
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_decoder.h"
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_decoder.h"
@@ -82,16 +84,20 @@ struct MeshPredictionSchemeDecoderFactory {
new MeshPredictionSchemeTexCoordsPortableDecoder<
DataTypeT, TransformT, MeshDataT>(attribute, transform,
mesh_data));
- } else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) {
+ }
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
+ else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) {
return std::unique_ptr<PredictionSchemeDecoder<DataTypeT, TransformT>>(
new MeshPredictionSchemeGeometricNormalDecoder<
DataTypeT, TransformT, MeshDataT>(attribute, transform,
mesh_data));
}
+#endif
return nullptr;
}
};
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
// Operator () specialized for normal octahedron transforms. These transforms
// are currently used only by the geometric normal prediction scheme (the
// transform is also used by delta coding, but delta predictor is not
@@ -128,6 +134,7 @@ struct MeshPredictionSchemeDecoderFactory {
return nullptr;
}
};
+#endif
template <class TransformT, class MeshDataT>
std::unique_ptr<PredictionSchemeDecoder<DataTypeT, TransformT>> operator()(
diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc
index 3144bdb9a6b..6b74e571c6d 100644
--- a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc
+++ b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc
@@ -32,10 +32,12 @@ PredictionSchemeMethod SelectPredictionMethod(
}
}
if (att->attribute_type() == GeometryAttribute::NORMAL) {
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
if (encoder->options()->GetSpeed() < 4) {
// Use geometric normal prediction for speeds 0, 1, 2, 3.
return MESH_PREDICTION_GEOMETRIC_NORMAL;
}
+#endif
return PREDICTION_DIFFERENCE; // default
}
// Handle other attribute types.
diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h
index cde5ba2435f..4cc40010773 100644
--- a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h
+++ b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h
@@ -19,7 +19,9 @@
#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_FACTORY_H_
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_encoder.h"
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_encoder.h"
+#endif
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_encoder.h"
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_encoder.h"
#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_encoder.h"
@@ -49,32 +51,25 @@ struct MeshPredictionSchemeEncoderFactory {
new MeshPredictionSchemeParallelogramEncoder<DataTypeT, TransformT,
MeshDataT>(
attribute, transform, mesh_data));
- } else if (method == MESH_PREDICTION_MULTI_PARALLELOGRAM) {
- return std::unique_ptr<PredictionSchemeEncoder<DataTypeT, TransformT>>(
- new MeshPredictionSchemeMultiParallelogramEncoder<
- DataTypeT, TransformT, MeshDataT>(attribute, transform,
- mesh_data));
} else if (method == MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM) {
return std::unique_ptr<PredictionSchemeEncoder<DataTypeT, TransformT>>(
new MeshPredictionSchemeConstrainedMultiParallelogramEncoder<
DataTypeT, TransformT, MeshDataT>(attribute, transform,
mesh_data));
- } else if (method == MESH_PREDICTION_TEX_COORDS_DEPRECATED) {
- return std::unique_ptr<PredictionSchemeEncoder<DataTypeT, TransformT>>(
- new MeshPredictionSchemeTexCoordsEncoder<DataTypeT, TransformT,
- MeshDataT>(
- attribute, transform, mesh_data));
} else if (method == MESH_PREDICTION_TEX_COORDS_PORTABLE) {
return std::unique_ptr<PredictionSchemeEncoder<DataTypeT, TransformT>>(
new MeshPredictionSchemeTexCoordsPortableEncoder<
DataTypeT, TransformT, MeshDataT>(attribute, transform,
mesh_data));
- } else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) {
+ }
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
+ else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) {
return std::unique_ptr<PredictionSchemeEncoder<DataTypeT, TransformT>>(
new MeshPredictionSchemeGeometricNormalEncoder<DataTypeT, TransformT,
MeshDataT>(
attribute, transform, mesh_data));
}
+#endif
return nullptr;
}
};
diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc b/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc
index fcd295039f6..2676eb7905c 100644
--- a/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc
+++ b/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc
@@ -13,7 +13,9 @@
// limitations under the License.
//
#include "draco/compression/attributes/sequential_attribute_decoders_controller.h"
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
#include "draco/compression/attributes/sequential_normal_attribute_decoder.h"
+#endif
#include "draco/compression/attributes/sequential_quantization_attribute_decoder.h"
#include "draco/compression/config/compression_shared.h"
@@ -123,9 +125,11 @@ SequentialAttributeDecodersController::CreateSequentialDecoder(
case SEQUENTIAL_ATTRIBUTE_ENCODER_QUANTIZATION:
return std::unique_ptr<SequentialAttributeDecoder>(
new SequentialQuantizationAttributeDecoder());
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
case SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS:
return std::unique_ptr<SequentialNormalAttributeDecoder>(
new SequentialNormalAttributeDecoder());
+#endif
default:
break;
}
diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc b/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc
index 467508b226f..b40cef842ae 100644
--- a/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc
+++ b/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc
@@ -13,7 +13,9 @@
// limitations under the License.
//
#include "draco/compression/attributes/sequential_attribute_encoders_controller.h"
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
#include "draco/compression/attributes/sequential_normal_attribute_encoder.h"
+#endif
#include "draco/compression/attributes/sequential_quantization_attribute_encoder.h"
#include "draco/compression/point_cloud/point_cloud_encoder.h"
@@ -121,15 +123,19 @@ SequentialAttributeEncodersController::CreateSequentialEncoder(int i) {
case DT_FLOAT32:
if (encoder()->options()->GetAttributeInt(att_id, "quantization_bits",
-1) > 0) {
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
if (att->attribute_type() == GeometryAttribute::NORMAL) {
// We currently only support normals with float coordinates
// and must be quantized.
return std::unique_ptr<SequentialAttributeEncoder>(
new SequentialNormalAttributeEncoder());
} else {
+#endif
return std::unique_ptr<SequentialAttributeEncoder>(
new SequentialQuantizationAttributeEncoder());
+#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
}
+#endif
}
break;
default:
diff --git a/extern/draco/dracoenc/src/draco/compression/decode.cc b/extern/draco/dracoenc/src/draco/compression/decode.cc
index a9ac2d5025f..ab70ef1ec60 100644
--- a/extern/draco/dracoenc/src/draco/compression/decode.cc
+++ b/extern/draco/dracoenc/src/draco/compression/decode.cc
@@ -37,7 +37,7 @@ StatusOr<std::unique_ptr<PointCloudDecoder>> CreatePointCloudDecoder(
} else if (method == POINT_CLOUD_KD_TREE_ENCODING) {
return std::unique_ptr<PointCloudDecoder>(new PointCloudKdTreeDecoder());
}
- return Status(Status::ERROR, "Unsupported encoding method.");
+ return Status(Status::DRACO_ERROR, "Unsupported encoding method.");
}
#endif
@@ -48,7 +48,7 @@ StatusOr<std::unique_ptr<MeshDecoder>> CreateMeshDecoder(uint8_t method) {
} else if (method == MESH_EDGEBREAKER_ENCODING) {
return std::unique_ptr<MeshDecoder>(new MeshEdgebreakerDecoder());
}
- return Status(Status::ERROR, "Unsupported encoding method.");
+ return Status(Status::DRACO_ERROR, "Unsupported encoding method.");
}
#endif
@@ -77,7 +77,7 @@ StatusOr<std::unique_ptr<PointCloud>> Decoder::DecodePointCloudFromBuffer(
return static_cast<std::unique_ptr<PointCloud>>(std::move(mesh));
#endif
}
- return Status(Status::ERROR, "Unsupported geometry type.");
+ return Status(Status::DRACO_ERROR, "Unsupported geometry type.");
}
StatusOr<std::unique_ptr<Mesh>> Decoder::DecodeMeshFromBuffer(
@@ -94,7 +94,7 @@ Status Decoder::DecodeBufferToGeometry(DecoderBuffer *in_buffer,
DracoHeader header;
DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header))
if (header.encoder_type != POINT_CLOUD) {
- return Status(Status::ERROR, "Input is not a point cloud.");
+ return Status(Status::DRACO_ERROR, "Input is not a point cloud.");
}
DRACO_ASSIGN_OR_RETURN(std::unique_ptr<PointCloudDecoder> decoder,
CreatePointCloudDecoder(header.encoder_method))
@@ -102,7 +102,7 @@ Status Decoder::DecodeBufferToGeometry(DecoderBuffer *in_buffer,
DRACO_RETURN_IF_ERROR(decoder->Decode(options_, in_buffer, out_geometry))
return OkStatus();
#else
- return Status(Status::ERROR, "Unsupported geometry type.");
+ return Status(Status::DRACO_ERROR, "Unsupported geometry type.");
#endif
}
@@ -113,7 +113,7 @@ Status Decoder::DecodeBufferToGeometry(DecoderBuffer *in_buffer,
DracoHeader header;
DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header))
if (header.encoder_type != TRIANGULAR_MESH) {
- return Status(Status::ERROR, "Input is not a mesh.");
+ return Status(Status::DRACO_ERROR, "Input is not a mesh.");
}
DRACO_ASSIGN_OR_RETURN(std::unique_ptr<MeshDecoder> decoder,
CreateMeshDecoder(header.encoder_method))
@@ -121,7 +121,7 @@ Status Decoder::DecodeBufferToGeometry(DecoderBuffer *in_buffer,
DRACO_RETURN_IF_ERROR(decoder->Decode(options_, in_buffer, out_geometry))
return OkStatus();
#else
- return Status(Status::ERROR, "Unsupported geometry type.");
+ return Status(Status::DRACO_ERROR, "Unsupported geometry type.");
#endif
}
diff --git a/extern/draco/dracoenc/src/draco/compression/decode.h b/extern/draco/dracoenc/src/draco/compression/decode.h
index 9e24ce8d5d6..0216d72586a 100644
--- a/extern/draco/dracoenc/src/draco/compression/decode.h
+++ b/extern/draco/dracoenc/src/draco/compression/decode.h
@@ -20,7 +20,7 @@
#include "draco/compression/config/compression_shared.h"
#include "draco/compression/config/decoder_options.h"
#include "draco/core/decoder_buffer.h"
-#include "draco/core/statusor.h"
+#include "draco/core/status_or.h"
#include "draco/mesh/mesh.h"
namespace draco {
diff --git a/extern/draco/dracoenc/src/draco/compression/encode_base.h b/extern/draco/dracoenc/src/draco/compression/encode_base.h
index fa263f8fa3d..451d970eb6f 100644
--- a/extern/draco/dracoenc/src/draco/compression/encode_base.h
+++ b/extern/draco/dracoenc/src/draco/compression/encode_base.h
@@ -68,23 +68,28 @@ class EncoderBase {
Status CheckPredictionScheme(GeometryAttribute::Type att_type,
int prediction_scheme) const {
// Out of bound checks:
- if (prediction_scheme < 0)
- return Status(Status::ERROR, "Invalid prediction scheme requested.");
+ if (prediction_scheme < PREDICTION_NONE)
+ return Status(Status::DRACO_ERROR,
+ "Invalid prediction scheme requested.");
if (prediction_scheme >= NUM_PREDICTION_SCHEMES)
- return Status(Status::ERROR, "Invalid prediction scheme requested.");
+ return Status(Status::DRACO_ERROR,
+ "Invalid prediction scheme requested.");
// Deprecated prediction schemes:
if (prediction_scheme == MESH_PREDICTION_TEX_COORDS_DEPRECATED)
- return Status(Status::ERROR,
+ return Status(Status::DRACO_ERROR,
"MESH_PREDICTION_TEX_COORDS_DEPRECATED is deprecated.");
+ if (prediction_scheme == MESH_PREDICTION_MULTI_PARALLELOGRAM)
+ return Status(Status::DRACO_ERROR,
+ "MESH_PREDICTION_MULTI_PARALLELOGRAM is deprecated.");
// Attribute specific checks:
if (prediction_scheme == MESH_PREDICTION_TEX_COORDS_PORTABLE) {
if (att_type != GeometryAttribute::TEX_COORD)
- return Status(Status::ERROR,
+ return Status(Status::DRACO_ERROR,
"Invalid prediction scheme for attribute type.");
}
if (prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL) {
if (att_type != GeometryAttribute::NORMAL) {
- return Status(Status::ERROR,
+ return Status(Status::DRACO_ERROR,
"Invalid prediction scheme for attribute type.");
}
}
@@ -92,7 +97,7 @@ class EncoderBase {
if (att_type == GeometryAttribute::NORMAL) {
if (!(prediction_scheme == PREDICTION_DIFFERENCE ||
prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL)) {
- return Status(Status::ERROR,
+ return Status(Status::DRACO_ERROR,
"Invalid prediction scheme for attribute type.");
}
}
diff --git a/extern/draco/dracoenc/src/draco/compression/entropy/ans.h b/extern/draco/dracoenc/src/draco/compression/entropy/ans.h
index 40b08ed33c6..310ae256667 100644
--- a/extern/draco/dracoenc/src/draco/compression/entropy/ans.h
+++ b/extern/draco/dracoenc/src/draco/compression/entropy/ans.h
@@ -20,29 +20,29 @@
#include <vector>
-#define ANS_DIVIDE_BY_MULTIPLY 1
-#if ANS_DIVIDE_BY_MULTIPLY
+#define DRACO_ANS_DIVIDE_BY_MULTIPLY 1
+#if DRACO_ANS_DIVIDE_BY_MULTIPLY
#include "draco/core/divide.h"
#endif
#include "draco/core/macros.h"
namespace draco {
-#if ANS_DIVIDE_BY_MULTIPLY
+#if DRACO_ANS_DIVIDE_BY_MULTIPLY
-#define ANS_DIVREM(quotient, remainder, dividend, divisor) \
- do { \
- quotient = fastdiv(dividend, divisor); \
- remainder = dividend - quotient * divisor; \
+#define DRACO_ANS_DIVREM(quotient, remainder, dividend, divisor) \
+ do { \
+ quotient = fastdiv(dividend, divisor); \
+ remainder = dividend - quotient * divisor; \
} while (0)
-#define ANS_DIV(dividend, divisor) fastdiv(dividend, divisor)
+#define DRACO_ANS_DIV(dividend, divisor) fastdiv(dividend, divisor)
#else
-#define ANS_DIVREM(quotient, remainder, dividend, divisor) \
- do { \
- quotient = dividend / divisor; \
- remainder = dividend % divisor; \
+#define DRACO_ANS_DIVREM(quotient, remainder, dividend, divisor) \
+ do { \
+ quotient = dividend / divisor; \
+ remainder = dividend % divisor; \
} while (0)
-#define ANS_DIV(dividend, divisor) ((dividend) / (divisor))
+#define DRACO_ANS_DIV(dividend, divisor) ((dividend) / (divisor))
#endif
struct AnsCoder {
@@ -60,13 +60,9 @@ struct AnsDecoder {
};
typedef uint8_t AnsP8;
-#define ans_p8_precision 256u
-#define ans_p8_shift 8
-#define ans_p10_precision 1024u
-
-#define l_base (ans_p10_precision * 4) // l_base % precision must be 0
-#define io_base 256
-// Range I = { l_base, l_base + 1, ..., l_base * io_base - 1 }
+#define DRACO_ANS_P8_PRECISION 256u
+#define DRACO_ANS_L_BASE (4096u)
+#define DRACO_ANS_IO_BASE 256
static uint32_t mem_get_le16(const void *vmem) {
uint32_t val;
@@ -126,14 +122,14 @@ static inline void ans_write_init(struct AnsCoder *const ans,
uint8_t *const buf) {
ans->buf = buf;
ans->buf_offset = 0;
- ans->state = l_base;
+ ans->state = DRACO_ANS_L_BASE;
}
static inline int ans_write_end(struct AnsCoder *const ans) {
uint32_t state;
- DRACO_DCHECK_GE(ans->state, l_base);
- DRACO_DCHECK_LT(ans->state, l_base * io_base);
- state = ans->state - l_base;
+ DRACO_DCHECK_GE(ans->state, DRACO_ANS_L_BASE);
+ DRACO_DCHECK_LT(ans->state, DRACO_ANS_L_BASE * DRACO_ANS_IO_BASE);
+ state = ans->state - DRACO_ANS_L_BASE;
if (state < (1 << 6)) {
ans->buf[ans->buf_offset] = (0x00 << 6) + state;
return ans->buf_offset + 1;
@@ -149,43 +145,44 @@ static inline int ans_write_end(struct AnsCoder *const ans) {
}
}
-// rABS with descending spread
-// p or p0 takes the place of l_s from the paper
-// ans_p8_precision is m
+// rABS with descending spread.
+// p or p0 takes the place of l_s from the paper.
+// DRACO_ANS_P8_PRECISION is m.
static inline void rabs_desc_write(struct AnsCoder *ans, int val, AnsP8 p0) {
- const AnsP8 p = ans_p8_precision - p0;
+ const AnsP8 p = DRACO_ANS_P8_PRECISION - p0;
const unsigned l_s = val ? p : p0;
unsigned quot, rem;
- if (ans->state >= l_base / ans_p8_precision * io_base * l_s) {
- ans->buf[ans->buf_offset++] = ans->state % io_base;
- ans->state /= io_base;
+ if (ans->state >=
+ DRACO_ANS_L_BASE / DRACO_ANS_P8_PRECISION * DRACO_ANS_IO_BASE * l_s) {
+ ans->buf[ans->buf_offset++] = ans->state % DRACO_ANS_IO_BASE;
+ ans->state /= DRACO_ANS_IO_BASE;
}
- ANS_DIVREM(quot, rem, ans->state, l_s);
- ans->state = quot * ans_p8_precision + rem + (val ? 0 : p);
+ DRACO_ANS_DIVREM(quot, rem, ans->state, l_s);
+ ans->state = quot * DRACO_ANS_P8_PRECISION + rem + (val ? 0 : p);
}
-#define ANS_IMPL1 0
+#define DRACO_ANS_IMPL1 0
#define UNPREDICTABLE(x) x
static inline int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) {
int val;
-#if ANS_IMPL1
+#if DRACO_ANS_IMPL1
unsigned l_s;
#else
unsigned quot, rem, x, xn;
#endif
- const AnsP8 p = ans_p8_precision - p0;
- if (ans->state < l_base && ans->buf_offset > 0) {
- ans->state = ans->state * io_base + ans->buf[--ans->buf_offset];
+ const AnsP8 p = DRACO_ANS_P8_PRECISION - p0;
+ if (ans->state < DRACO_ANS_L_BASE && ans->buf_offset > 0) {
+ ans->state = ans->state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset];
}
-#if ANS_IMPL1
- val = ans->state % ans_p8_precision < p;
+#if DRACO_ANS_IMPL1
+ val = ans->state % DRACO_ANS_P8_PRECISION < p;
l_s = val ? p : p0;
- ans->state = (ans->state / ans_p8_precision) * l_s +
- ans->state % ans_p8_precision - (!val * p);
+ ans->state = (ans->state / DRACO_ANS_P8_PRECISION) * l_s +
+ ans->state % DRACO_ANS_P8_PRECISION - (!val * p);
#else
x = ans->state;
- quot = x / ans_p8_precision;
- rem = x % ans_p8_precision;
+ quot = x / DRACO_ANS_P8_PRECISION;
+ rem = x % DRACO_ANS_P8_PRECISION;
xn = quot * p;
val = rem < p;
if (UNPREDICTABLE(val)) {
@@ -198,41 +195,42 @@ static inline int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) {
return val;
}
-// rABS with ascending spread
-// p or p0 takes the place of l_s from the paper
-// ans_p8_precision is m
+// rABS with ascending spread.
+// p or p0 takes the place of l_s from the paper.
+// DRACO_ANS_P8_PRECISION is m.
static inline void rabs_asc_write(struct AnsCoder *ans, int val, AnsP8 p0) {
- const AnsP8 p = ans_p8_precision - p0;
+ const AnsP8 p = DRACO_ANS_P8_PRECISION - p0;
const unsigned l_s = val ? p : p0;
unsigned quot, rem;
- if (ans->state >= l_base / ans_p8_precision * io_base * l_s) {
- ans->buf[ans->buf_offset++] = ans->state % io_base;
- ans->state /= io_base;
+ if (ans->state >=
+ DRACO_ANS_L_BASE / DRACO_ANS_P8_PRECISION * DRACO_ANS_IO_BASE * l_s) {
+ ans->buf[ans->buf_offset++] = ans->state % DRACO_ANS_IO_BASE;
+ ans->state /= DRACO_ANS_IO_BASE;
}
- ANS_DIVREM(quot, rem, ans->state, l_s);
- ans->state = quot * ans_p8_precision + rem + (val ? p0 : 0);
+ DRACO_ANS_DIVREM(quot, rem, ans->state, l_s);
+ ans->state = quot * DRACO_ANS_P8_PRECISION + rem + (val ? p0 : 0);
}
static inline int rabs_asc_read(struct AnsDecoder *ans, AnsP8 p0) {
int val;
-#if ANS_IMPL1
+#if DRACO_ANS_IMPL1
unsigned l_s;
#else
unsigned quot, rem, x, xn;
#endif
- const AnsP8 p = ans_p8_precision - p0;
- if (ans->state < l_base) {
- ans->state = ans->state * io_base + ans->buf[--ans->buf_offset];
+ const AnsP8 p = DRACO_ANS_P8_PRECISION - p0;
+ if (ans->state < DRACO_ANS_L_BASE) {
+ ans->state = ans->state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset];
}
-#if ANS_IMPL1
- val = ans->state % ans_p8_precision < p;
+#if DRACO_ANS_IMPL1
+ val = ans->state % DRACO_ANS_P8_PRECISION < p;
l_s = val ? p : p0;
- ans->state = (ans->state / ans_p8_precision) * l_s +
- ans->state % ans_p8_precision - (!val * p);
+ ans->state = (ans->state / DRACO_ANS_P8_PRECISION) * l_s +
+ ans->state % DRACO_ANS_P8_PRECISION - (!val * p);
#else
x = ans->state;
- quot = x / ans_p8_precision;
- rem = x % ans_p8_precision;
+ quot = x / DRACO_ANS_P8_PRECISION;
+ rem = x % DRACO_ANS_P8_PRECISION;
xn = quot * p;
val = rem >= p0;
if (UNPREDICTABLE(val)) {
@@ -248,32 +246,34 @@ static inline int rabs_asc_read(struct AnsDecoder *ans, AnsP8 p0) {
#define rabs_read rabs_desc_read
#define rabs_write rabs_desc_write
-// uABS with normalization
+// uABS with normalization.
static inline void uabs_write(struct AnsCoder *ans, int val, AnsP8 p0) {
- AnsP8 p = ans_p8_precision - p0;
+ AnsP8 p = DRACO_ANS_P8_PRECISION - p0;
const unsigned l_s = val ? p : p0;
- while (ans->state >= l_base / ans_p8_precision * io_base * l_s) {
- ans->buf[ans->buf_offset++] = ans->state % io_base;
- ans->state /= io_base;
+ while (ans->state >=
+ DRACO_ANS_L_BASE / DRACO_ANS_P8_PRECISION * DRACO_ANS_IO_BASE * l_s) {
+ ans->buf[ans->buf_offset++] = ans->state % DRACO_ANS_IO_BASE;
+ ans->state /= DRACO_ANS_IO_BASE;
}
if (!val)
- ans->state = ANS_DIV(ans->state * ans_p8_precision, p0);
+ ans->state = DRACO_ANS_DIV(ans->state * DRACO_ANS_P8_PRECISION, p0);
else
- ans->state = ANS_DIV((ans->state + 1) * ans_p8_precision + p - 1, p) - 1;
+ ans->state =
+ DRACO_ANS_DIV((ans->state + 1) * DRACO_ANS_P8_PRECISION + p - 1, p) - 1;
}
static inline int uabs_read(struct AnsDecoder *ans, AnsP8 p0) {
- AnsP8 p = ans_p8_precision - p0;
+ AnsP8 p = DRACO_ANS_P8_PRECISION - p0;
int s;
// unsigned int xp1;
unsigned xp, sp;
unsigned state = ans->state;
- while (state < l_base && ans->buf_offset > 0) {
- state = state * io_base + ans->buf[--ans->buf_offset];
+ while (state < DRACO_ANS_L_BASE && ans->buf_offset > 0) {
+ state = state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset];
}
sp = state * p;
- // xp1 = (sp + p) / ans_p8_precision;
- xp = sp / ans_p8_precision;
+ // xp1 = (sp + p) / DRACO_ANS_P8_PRECISION;
+ xp = sp / DRACO_ANS_P8_PRECISION;
// s = xp1 - xp;
s = (sp & 0xFF) >= p0;
if (UNPREDICTABLE(s))
@@ -286,8 +286,8 @@ static inline int uabs_read(struct AnsDecoder *ans, AnsP8 p0) {
static inline int uabs_read_bit(struct AnsDecoder *ans) {
int s;
unsigned state = ans->state;
- while (state < l_base && ans->buf_offset > 0) {
- state = state * io_base + ans->buf[--ans->buf_offset];
+ while (state < DRACO_ANS_L_BASE && ans->buf_offset > 0) {
+ state = state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset];
}
s = static_cast<int>(state & 1);
ans->state = state >> 1;
@@ -317,23 +317,23 @@ static inline int ans_read_init(struct AnsDecoder *const ans,
} else {
return 1;
}
- ans->state += l_base;
- if (ans->state >= l_base * io_base)
+ ans->state += DRACO_ANS_L_BASE;
+ if (ans->state >= DRACO_ANS_L_BASE * DRACO_ANS_IO_BASE)
return 1;
return 0;
}
static inline int ans_read_end(struct AnsDecoder *const ans) {
- return ans->state == l_base;
+ return ans->state == DRACO_ANS_L_BASE;
}
static inline int ans_reader_has_error(const struct AnsDecoder *const ans) {
- return ans->state < l_base && ans->buf_offset == 0;
+ return ans->state < DRACO_ANS_L_BASE && ans->buf_offset == 0;
}
struct rans_sym {
uint32_t prob;
- uint32_t cum_prob; // not-inclusive
+ uint32_t cum_prob; // not-inclusive.
};
// Class for performing rANS encoding using a desired number of precision bits.
@@ -356,7 +356,7 @@ class RAnsEncoder {
inline int write_end() {
uint32_t state;
DRACO_DCHECK_GE(ans_.state, l_rans_base);
- DRACO_DCHECK_LT(ans_.state, l_rans_base * io_base);
+ DRACO_DCHECK_LT(ans_.state, l_rans_base * DRACO_ANS_IO_BASE);
state = ans_.state - l_rans_base;
if (state < (1 << 6)) {
ans_.buf[ans_.buf_offset] = (0x00 << 6) + state;
@@ -376,14 +376,14 @@ class RAnsEncoder {
}
}
- // rANS with normalization
- // sym->prob takes the place of l_s from the paper
- // rans_precision is m
+ // rANS with normalization.
+ // sym->prob takes the place of l_s from the paper.
+ // rans_precision is m.
inline void rans_write(const struct rans_sym *const sym) {
const uint32_t p = sym->prob;
- while (ans_.state >= l_rans_base / rans_precision * io_base * p) {
- ans_.buf[ans_.buf_offset++] = ans_.state % io_base;
- ans_.state /= io_base;
+ while (ans_.state >= l_rans_base / rans_precision * DRACO_ANS_IO_BASE * p) {
+ 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 =
@@ -399,7 +399,7 @@ class RAnsEncoder {
struct rans_dec_sym {
uint32_t val;
uint32_t prob;
- uint32_t cum_prob; // not-inclusive
+ uint32_t cum_prob; // not-inclusive.
};
// Class for performing rANS decoding using a desired number of precision bits.
@@ -439,7 +439,7 @@ class RAnsDecoder {
return 1;
}
ans_.state += l_rans_base;
- if (ans_.state >= l_rans_base * io_base)
+ if (ans_.state >= l_rans_base * DRACO_ANS_IO_BASE)
return 1;
return 0;
}
@@ -455,7 +455,7 @@ class RAnsDecoder {
unsigned quo;
struct rans_dec_sym sym;
while (ans_.state < l_rans_base && ans_.buf_offset > 0) {
- ans_.state = ans_.state * io_base + ans_.buf[--ans_.buf_offset];
+ ans_.state = ans_.state * DRACO_ANS_IO_BASE + ans_.buf[--ans_.buf_offset];
}
// |rans_precision| is a power of two compile time constant, and the below
// division and modulo are going to be optimized by the compiler.
@@ -507,7 +507,10 @@ class RAnsDecoder {
AnsDecoder ans_;
};
-#undef ANS_DIVREM
+#undef DRACO_ANS_DIVREM
+#undef DRACO_ANS_P8_PRECISION
+#undef DRACO_ANS_L_BASE
+#undef DRACO_ANS_IO_BASE
} // namespace draco
diff --git a/extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_coding.h b/extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_coding.h
index 8d06644a9b9..0a68e29fe26 100644
--- a/extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_coding.h
+++ b/extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_coding.h
@@ -40,8 +40,8 @@ constexpr int ComputeRAnsPrecisionFromUniqueSymbolsBitLength(
// Compute approximate frequency table size needed for storing the provided
// symbols.
-static int64_t ApproximateRAnsFrequencyTableBits(int32_t max_value,
- int num_unique_symbols) {
+static inline int64_t ApproximateRAnsFrequencyTableBits(
+ int32_t max_value, int num_unique_symbols) {
// Approximate number of bits for storing zero frequency entries using the
// run length encoding (with max length of 64).
const int64_t table_zero_frequency_bits =
diff --git a/extern/draco/dracoenc/src/draco/compression/expert_encode.cc b/extern/draco/dracoenc/src/draco/compression/expert_encode.cc
index f62d16630cb..112e6ae3d3e 100644
--- a/extern/draco/dracoenc/src/draco/compression/expert_encode.cc
+++ b/extern/draco/dracoenc/src/draco/compression/expert_encode.cc
@@ -16,8 +16,10 @@
#include "draco/compression/mesh/mesh_edgebreaker_encoder.h"
#include "draco/compression/mesh/mesh_sequential_encoder.h"
+#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED
#include "draco/compression/point_cloud/point_cloud_kd_tree_encoder.h"
#include "draco/compression/point_cloud/point_cloud_sequential_encoder.h"
+#endif
namespace draco {
@@ -29,7 +31,7 @@ ExpertEncoder::ExpertEncoder(const Mesh &mesh)
Status ExpertEncoder::EncodeToBuffer(EncoderBuffer *out_buffer) {
if (point_cloud_ == nullptr)
- return Status(Status::ERROR, "Invalid input geometry.");
+ return Status(Status::DRACO_ERROR, "Invalid input geometry.");
if (mesh_ == nullptr) {
return EncodePointCloudToBuffer(*point_cloud_, out_buffer);
}
@@ -38,6 +40,7 @@ Status ExpertEncoder::EncodeToBuffer(EncoderBuffer *out_buffer) {
Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc,
EncoderBuffer *out_buffer) {
+#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED
std::unique_ptr<PointCloudEncoder> encoder;
const int encoding_method = options().GetGlobalInt("encoding_method", -1);
@@ -74,7 +77,7 @@ Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc,
} else if (encoding_method == POINT_CLOUD_KD_TREE_ENCODING) {
// Encoding method was explicitly specified but we cannot use it for
// the given input (some of the checks above failed).
- return Status(Status::ERROR, "Invalid encoding method.");
+ return Status(Status::DRACO_ERROR, "Invalid encoding method.");
}
}
if (!encoder) {
@@ -87,6 +90,9 @@ Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc,
set_num_encoded_points(encoder->num_encoded_points());
set_num_encoded_faces(0);
return OkStatus();
+#else
+ return Status(Status::DRACO_ERROR, "Point cloud encoding is not enabled.");
+#endif
}
Status ExpertEncoder::EncodeMeshToBuffer(const Mesh &m,
diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc
index ad87f9403af..54fd55a483c 100644
--- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc
+++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc
@@ -31,9 +31,7 @@ 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(ostava): For now we have a set limit for forcing the basic edgebreaker
- // based on the number of faces, but a more complex heuristic may be used if
- // needed.
+ // TODO(b/111065939): Check if this can be improved.
const bool is_tiny_mesh = mesh()->num_faces() < 1000;
int selected_edgebreaker_method =
@@ -81,7 +79,7 @@ bool MeshEdgebreakerEncoder::EncodeAttributesEncoderIdentifier(
return true;
}
-bool MeshEdgebreakerEncoder::EncodeConnectivity() {
+Status MeshEdgebreakerEncoder::EncodeConnectivity() {
return impl_->EncodeConnectivity();
}
diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.h b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.h
index 78615fb0287..70d4d5061a7 100644
--- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.h
+++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.h
@@ -51,7 +51,7 @@ class MeshEdgebreakerEncoder : public MeshEncoder {
protected:
bool InitializeEncoder() override;
- bool EncodeConnectivity() override;
+ Status EncodeConnectivity() override;
bool GenerateAttributesEncoder(int32_t att_id) override;
bool EncodeAttributesEncoderIdentifier(int32_t att_encoder_id) override;
void ComputeNumberOfEncodedPoints() override;
diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc
index 89e6f0b5b12..f69ec993f9e 100644
--- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc
+++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc
@@ -263,7 +263,7 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::
}
template <class TraversalEncoder>
-bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
+Status MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
// To encode the mesh, we need face connectivity data stored in a corner
// table. To compute the connectivity we must use indices associated with
// POSITION attribute, because they define which edges can be connected
@@ -279,7 +279,7 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
corner_table_->num_faces() == corner_table_->NumDegeneratedFaces()) {
// Failed to construct the corner table.
// TODO(ostava): Add better error reporting.
- return false;
+ return Status(Status::DRACO_ERROR, "All triangles are degenerate.");
}
traversal_encoder_.Init(this);
@@ -317,10 +317,10 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
pos_encoding_data_.num_values = 0;
if (!FindHoles())
- return false;
+ return Status(Status::DRACO_ERROR, "Failed to process mesh holes.");
if (!InitAttributeData())
- return false;
+ return Status(Status::DRACO_ERROR, "Failed to initialize attribute data.");
const uint8_t num_attribute_data =
static_cast<uint8_t>(attribute_data_.size());
@@ -376,7 +376,7 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
if (opp_face_id != kInvalidFaceIndex &&
!visited_faces_[opp_face_id.value()]) {
if (!EncodeConnectivityFromCorner(opp_id))
- return false;
+ return Status(Status::DRACO_ERROR, "Failed to encode mesh component.");
}
} else {
// Boundary configuration. We start on a boundary rather than on a face.
@@ -385,7 +385,7 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
// Start processing the face opposite to the boundary edge (the face
// containing the start_corner).
if (!EncodeConnectivityFromCorner(start_corner))
- return false;
+ return Status(Status::DRACO_ERROR, "Failed to encode mesh component.");
}
}
// Reverse the order of connectivity corners to match the order in which
@@ -417,11 +417,11 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
// Append the traversal buffer.
if (!EncodeSplitData())
- return false;
+ return Status(Status::DRACO_ERROR, "Failed to encode split data.");
encoder_->buffer()->Encode(traversal_encoder_.buffer().data(),
traversal_encoder_.buffer().size());
- return true;
+ return OkStatus();
}
template <class TraversalEncoder>
diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h
index 997bd1565e3..fb33771637e 100644
--- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h
+++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h
@@ -45,7 +45,7 @@ class MeshEdgebreakerEncoderImpl : public MeshEdgebreakerEncoderImplInterface {
bool GenerateAttributesEncoder(int32_t att_id) override;
bool EncodeAttributesEncoderIdentifier(int32_t att_encoder_id) override;
- bool EncodeConnectivity() override;
+ Status EncodeConnectivity() override;
const CornerTable *GetCornerTable() const override {
return corner_table_.get();
diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h
index 8da3541ec86..627d5126296 100644
--- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h
+++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h
@@ -41,7 +41,7 @@ class MeshEdgebreakerEncoderImplInterface {
int att_id) const = 0;
virtual bool GenerateAttributesEncoder(int32_t att_id) = 0;
virtual bool EncodeAttributesEncoderIdentifier(int32_t att_encoder_id) = 0;
- virtual bool EncodeConnectivity() = 0;
+ virtual Status EncodeConnectivity() = 0;
// Returns corner table of the encoded mesh.
virtual const CornerTable *GetCornerTable() const = 0;
diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.cc b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.cc
index 19d1355a443..2da5de1fc82 100644
--- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.cc
+++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.cc
@@ -23,12 +23,11 @@ void MeshEncoder::SetMesh(const Mesh &m) {
SetPointCloud(m);
}
-bool MeshEncoder::EncodeGeometryData() {
- if (!EncodeConnectivity())
- return false;
+Status MeshEncoder::EncodeGeometryData() {
+ DRACO_RETURN_IF_ERROR(EncodeConnectivity());
if (options()->GetGlobalBool("store_number_of_encoded_faces", false))
ComputeNumberOfEncodedFaces();
- return true;
+ return OkStatus();
}
} // namespace draco
diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.h b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.h
index 41387d569c6..30ec4fa3492 100644
--- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.h
+++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.h
@@ -61,10 +61,10 @@ class MeshEncoder : public PointCloudEncoder {
const Mesh *mesh() const { return mesh_; }
protected:
- bool EncodeGeometryData() override;
+ Status EncodeGeometryData() override;
// Needs to be implemented by the derived classes.
- virtual bool EncodeConnectivity() = 0;
+ virtual Status EncodeConnectivity() = 0;
// Computes and sets the num_encoded_faces_ for the encoder.
virtual void ComputeNumberOfEncodedFaces() = 0;
diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_test.cc b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_test.cc
index e67861a2ec2..9f056fc22e3 100644
--- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_test.cc
+++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_test.cc
@@ -87,7 +87,7 @@ TEST_P(MeshEncoderTest, EncodeGoldenMesh) {
}
}
-INSTANTIATE_TEST_CASE_P(MeshEncoderTests, MeshEncoderTest,
- ::testing::Values("sequential", "edgebreaker"));
+INSTANTIATE_TEST_SUITE_P(MeshEncoderTests, MeshEncoderTest,
+ ::testing::Values("sequential", "edgebreaker"));
} // namespace draco
diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.cc b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.cc
index 44b3b20b63c..b53ff0c25a6 100644
--- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.cc
+++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.cc
@@ -25,7 +25,7 @@ namespace draco {
MeshSequentialEncoder::MeshSequentialEncoder() {}
-bool MeshSequentialEncoder::EncodeConnectivity() {
+Status MeshSequentialEncoder::EncodeConnectivity() {
// Serialize indices.
const uint32_t num_faces = mesh()->num_faces();
EncodeVarint(num_faces, buffer());
@@ -38,7 +38,7 @@ bool MeshSequentialEncoder::EncodeConnectivity() {
// 0 = Encode compressed indices.
buffer()->Encode(static_cast<uint8_t>(0));
if (!CompressAndEncodeIndices())
- return false;
+ return Status(Status::DRACO_ERROR, "Failed to compress connectivity.");
} else {
// 1 = Encode indices directly.
buffer()->Encode(static_cast<uint8_t>(1));
@@ -77,7 +77,7 @@ bool MeshSequentialEncoder::EncodeConnectivity() {
}
}
}
- return true;
+ return OkStatus();
}
bool MeshSequentialEncoder::GenerateAttributesEncoder(int32_t att_id) {
diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.h b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.h
index 47a4fec837c..672609642b0 100644
--- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.h
+++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.h
@@ -42,7 +42,7 @@ class MeshSequentialEncoder : public MeshEncoder {
}
protected:
- bool EncodeConnectivity() override;
+ Status EncodeConnectivity() override;
bool GenerateAttributesEncoder(int32_t att_id) override;
void ComputeNumberOfEncodedPoints() override;
void ComputeNumberOfEncodedFaces() override;
diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h
index e220a2ab166..61a153560ae 100644
--- a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h
+++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h
@@ -95,8 +95,11 @@ class DynamicIntegerPointsKdTreeDecoder {
// Decodes a integer point cloud from |buffer|.
template <class OutputIteratorT>
bool DecodePoints(DecoderBuffer *buffer, OutputIteratorT &oit);
+
+#ifndef DRACO_OLD_GCC
template <class OutputIteratorT>
bool DecodePoints(DecoderBuffer *buffer, OutputIteratorT &&oit);
+#endif // DRACO_OLD_GCC
const uint32_t dimension() const { return dimension_; }
@@ -138,6 +141,7 @@ class DynamicIntegerPointsKdTreeDecoder {
};
// Decodes a point cloud from |buffer|.
+#ifndef DRACO_OLD_GCC
template <int compression_level_t>
template <class OutputIteratorT>
bool DynamicIntegerPointsKdTreeDecoder<compression_level_t>::DecodePoints(
@@ -145,6 +149,7 @@ bool DynamicIntegerPointsKdTreeDecoder<compression_level_t>::DecodePoints(
OutputIteratorT local = std::forward<OutputIteratorT>(oit);
return DecodePoints(buffer, local);
}
+#endif // DRACO_OLD_GCC
template <int compression_level_t>
template <class OutputIteratorT>
diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h
index 80be0c9d373..d3425696a5a 100644
--- a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h
+++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h
@@ -33,8 +33,12 @@ class FloatPointsTreeDecoder {
// Decodes a point cloud from |buffer|.
template <class OutputIteratorT>
bool DecodePointCloud(DecoderBuffer *buffer, OutputIteratorT &out);
+
+#ifndef DRACO_OLD_GCC
template <class OutputIteratorT>
bool DecodePointCloud(DecoderBuffer *buffer, OutputIteratorT &&out);
+#endif // DRACO_OLD_GCC
+
// Initializes a DecoderBuffer from |data|, and calls function above.
template <class OutputIteratorT>
bool DecodePointCloud(const char *data, size_t data_size,
@@ -72,12 +76,16 @@ class FloatPointsTreeDecoder {
uint32_t compression_level_;
};
+#ifndef DRACO_OLD_GCC
+// TODO(vytyaz): Reenable once USD migrates from GCC 4.8 to a higher version
+// that can disambiguate calls to overloaded methods taking rvalue reference.
template <class OutputIteratorT>
bool FloatPointsTreeDecoder::DecodePointCloud(DecoderBuffer *buffer,
OutputIteratorT &&out) {
OutputIteratorT local = std::forward<OutputIteratorT>(out);
return DecodePointCloud(buffer, local);
}
+#endif // DRACO_OLD_GCC
template <class OutputIteratorT>
bool FloatPointsTreeDecoder::DecodePointCloud(DecoderBuffer *buffer,
diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h
index 18307b57209..9541c966856 100644
--- a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h
+++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h
@@ -23,7 +23,7 @@ enum PointCloudCompressionMethod {
// Generalized version of Encoding using the Octree method by Olivier
// Devillers to d dimensions.
// "Progressive lossless compression of arbitrary simplicial complexes"
- // http://dx.doi.org/10.1145/566570.566591
+ // https://doi.org/10.1145/566570.566591
KDTREE = 1,
RESERVED_POINT_CLOUD_METHOD_2 = 2, // Reserved for internal use.
RESERVED_POINT_CLOUD_METHOD_3 = 0, // Reserved for internal use.
diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.cc b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.cc
index 5f3bff4bbc9..cf5d997e67a 100644
--- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.cc
+++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.cc
@@ -31,7 +31,7 @@ Status PointCloudDecoder::DecodeHeader(DecoderBuffer *buffer,
if (!buffer->Decode(out_header->draco_string, 5))
return Status(Status::IO_ERROR, kIoErrorMsg);
if (memcmp(out_header->draco_string, "DRACO", 5) != 0)
- return Status(Status::ERROR, "Not a Draco file.");
+ return Status(Status::DRACO_ERROR, "Not a Draco file.");
if (!buffer->Decode(&(out_header->version_major)))
return Status(Status::IO_ERROR, kIoErrorMsg);
if (!buffer->Decode(&(out_header->version_minor)))
@@ -50,7 +50,7 @@ Status PointCloudDecoder::DecodeMetadata() {
std::unique_ptr<GeometryMetadata>(new GeometryMetadata());
MetadataDecoder metadata_decoder;
if (!metadata_decoder.DecodeGeometryMetadata(buffer_, metadata.get()))
- return Status(Status::ERROR, "Failed to decode metadata.");
+ return Status(Status::DRACO_ERROR, "Failed to decode metadata.");
point_cloud_->AddMetadata(std::move(metadata));
return OkStatus();
}
@@ -66,7 +66,7 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options,
// Sanity check that we are really using the right decoder (mostly for cases
// where the Decode method was called manually outside of our main API.
if (header.encoder_type != GetGeometryType())
- return Status(Status::ERROR,
+ return Status(Status::DRACO_ERROR,
"Using incompatible decoder for the input geometry.");
// TODO(ostava): We should check the method as well, but currently decoders
// don't expose the decoding method id.
@@ -93,11 +93,11 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options,
DRACO_RETURN_IF_ERROR(DecodeMetadata())
}
if (!InitializeDecoder())
- return Status(Status::ERROR, "Failed to initialize the decoder.");
+ return Status(Status::DRACO_ERROR, "Failed to initialize the decoder.");
if (!DecodeGeometryData())
- return Status(Status::ERROR, "Failed to decode geometry data.");
+ return Status(Status::DRACO_ERROR, "Failed to decode geometry data.");
if (!DecodePointAttributes())
- return Status(Status::ERROR, "Failed to decode point attributes.");
+ return Status(Status::DRACO_ERROR, "Failed to decode point attributes.");
return OkStatus();
}
diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.cc b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.cc
index edf0e4ab20a..986706582f0 100644
--- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.cc
+++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.cc
@@ -36,17 +36,16 @@ Status PointCloudEncoder::Encode(const EncoderOptions &options,
attributes_encoder_ids_order_.clear();
if (!point_cloud_)
- return Status(Status::ERROR, "Invalid input geometry.");
+ return Status(Status::DRACO_ERROR, "Invalid input geometry.");
DRACO_RETURN_IF_ERROR(EncodeHeader())
DRACO_RETURN_IF_ERROR(EncodeMetadata())
if (!InitializeEncoder())
- return Status(Status::ERROR, "Failed to initialize encoder.");
+ return Status(Status::DRACO_ERROR, "Failed to initialize encoder.");
if (!EncodeEncoderData())
- return Status(Status::ERROR, "Failed to encode internal data.");
- if (!EncodeGeometryData())
- return Status(Status::ERROR, "Failed to encode geometry data.");
+ return Status(Status::DRACO_ERROR, "Failed to encode internal data.");
+ DRACO_RETURN_IF_ERROR(EncodeGeometryData());
if (!EncodePointAttributes())
- return Status(Status::ERROR, "Failed to encode point attributes.");
+ return Status(Status::DRACO_ERROR, "Failed to encode point attributes.");
if (options.GetGlobalBool("store_number_of_encoded_points", false))
ComputeNumberOfEncodedPoints();
return OkStatus();
@@ -87,7 +86,7 @@ Status PointCloudEncoder::EncodeMetadata() {
MetadataEncoder metadata_encoder;
if (!metadata_encoder.EncodeGeometryMetadata(buffer_,
point_cloud_->GetMetadata())) {
- return Status(Status::ERROR, "Failed to encode metadata.");
+ return Status(Status::DRACO_ERROR, "Failed to encode metadata.");
}
return OkStatus();
}
diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.h
index b15d1401a57..8883f17a789 100644
--- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.h
+++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.h
@@ -85,7 +85,7 @@ class PointCloudEncoder {
virtual bool EncodeEncoderData() { return true; }
// Encodes any global geometry data (such as the number of points).
- virtual bool EncodeGeometryData() { return true; }
+ virtual Status EncodeGeometryData() { return OkStatus(); }
// encode all attribute values. The attribute encoders are sorted to resolve
// any attribute dependencies and all the encoded data is stored into the
diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc
index 7ecfca2b456..6d0446baad1 100644
--- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc
+++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc
@@ -17,10 +17,10 @@
namespace draco {
-bool PointCloudKdTreeEncoder::EncodeGeometryData() {
+Status PointCloudKdTreeEncoder::EncodeGeometryData() {
const int32_t num_points = point_cloud()->num_points();
buffer()->Encode(num_points);
- return true;
+ return OkStatus();
}
bool PointCloudKdTreeEncoder::GenerateAttributesEncoder(int32_t att_id) {
diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h
index 98bc3d67fde..6acbb949d40 100644
--- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h
+++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h
@@ -35,7 +35,7 @@ class PointCloudKdTreeEncoder : public PointCloudEncoder {
}
protected:
- bool EncodeGeometryData() override;
+ Status EncodeGeometryData() override;
bool GenerateAttributesEncoder(int32_t att_id) override;
void ComputeNumberOfEncodedPoints() override;
};
diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc
index 9b92994b7a6..fa7b6fd905c 100644
--- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc
+++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc
@@ -19,10 +19,10 @@
namespace draco {
-bool PointCloudSequentialEncoder::EncodeGeometryData() {
+Status PointCloudSequentialEncoder::EncodeGeometryData() {
const int32_t num_points = point_cloud()->num_points();
buffer()->Encode(num_points);
- return true;
+ return OkStatus();
}
bool PointCloudSequentialEncoder::GenerateAttributesEncoder(int32_t att_id) {
diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h
index f73b5a551e4..40d8edcdbb0 100644
--- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h
+++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h
@@ -33,7 +33,7 @@ class PointCloudSequentialEncoder : public PointCloudEncoder {
}
protected:
- bool EncodeGeometryData() override;
+ Status EncodeGeometryData() override;
bool GenerateAttributesEncoder(int32_t att_id) override;
void ComputeNumberOfEncodedPoints() override;
};
diff --git a/extern/draco/dracoenc/src/draco/core/data_buffer.cc b/extern/draco/dracoenc/src/draco/core/data_buffer.cc
index 3b57367bbf1..867760a6fcc 100644
--- a/extern/draco/dracoenc/src/draco/core/data_buffer.cc
+++ b/extern/draco/dracoenc/src/draco/core/data_buffer.cc
@@ -13,6 +13,7 @@
// limitations under the License.
//
#include "draco/core/data_buffer.h"
+#include <algorithm>
namespace draco {
diff --git a/extern/draco/dracoenc/src/draco/core/draco_test_utils.cc b/extern/draco/dracoenc/src/draco/core/draco_test_utils.cc
index fa225576d9c..a39e19f6b15 100644
--- a/extern/draco/dracoenc/src/draco/core/draco_test_utils.cc
+++ b/extern/draco/dracoenc/src/draco/core/draco_test_utils.cc
@@ -48,7 +48,7 @@ bool GenerateGoldenFile(const std::string &golden_file_name, const void *data,
bool CompareGoldenFile(const std::string &golden_file_name, const void *data,
int data_size) {
const std::string golden_path = GetTestFileFullPath(golden_file_name);
- std::ifstream in_file(golden_path);
+ std::ifstream in_file(golden_path, std::ios::binary);
if (!in_file || data_size < 0)
return false;
const char *const data_c8 = static_cast<const char *>(data);
diff --git a/extern/draco/dracoenc/src/draco/core/draco_test_utils.h b/extern/draco/dracoenc/src/draco/core/draco_test_utils.h
index 2ed93cd960b..3113a5d2676 100644
--- a/extern/draco/dracoenc/src/draco/core/draco_test_utils.h
+++ b/extern/draco/dracoenc/src/draco/core/draco_test_utils.h
@@ -53,6 +53,11 @@ inline std::unique_ptr<Mesh> ReadMeshFromTestFile(const std::string &file_name,
const std::string path = GetTestFileFullPath(file_name);
return ReadMeshFromFile(path, use_metadata).value();
}
+inline std::unique_ptr<Mesh> ReadMeshFromTestFile(const std::string &file_name,
+ const Options &options) {
+ const std::string path = GetTestFileFullPath(file_name);
+ return ReadMeshFromFile(path, options).value();
+}
inline std::unique_ptr<PointCloud> ReadPointCloudFromTestFile(
const std::string &file_name) {
diff --git a/extern/draco/dracoenc/src/draco/core/draco_types.cc b/extern/draco/dracoenc/src/draco/core/draco_types.cc
index 45b22470057..9bde05fda80 100644
--- a/extern/draco/dracoenc/src/draco/core/draco_types.cc
+++ b/extern/draco/dracoenc/src/draco/core/draco_types.cc
@@ -41,4 +41,21 @@ int32_t DataTypeLength(DataType dt) {
}
}
+bool IsDataTypeIntegral(DataType dt) {
+ switch (dt) {
+ case DT_INT8:
+ case DT_UINT8:
+ case DT_INT16:
+ case DT_UINT16:
+ case DT_INT32:
+ case DT_UINT32:
+ case DT_INT64:
+ case DT_UINT64:
+ case DT_BOOL:
+ return true;
+ default:
+ return false;
+ }
+}
+
} // namespace draco
diff --git a/extern/draco/dracoenc/src/draco/core/draco_types.h b/extern/draco/dracoenc/src/draco/core/draco_types.h
index 4a34d7045a3..f5a21e4f1d0 100644
--- a/extern/draco/dracoenc/src/draco/core/draco_types.h
+++ b/extern/draco/dracoenc/src/draco/core/draco_types.h
@@ -41,6 +41,11 @@ enum DataType {
int32_t DataTypeLength(DataType dt);
+// Equivalent to std::is_integral for draco::DataType. Returns true for all
+// signed and unsigned integer types (including DT_BOOL). Returns false
+// otherwise.
+bool IsDataTypeIntegral(DataType dt);
+
} // namespace draco
#endif // DRACO_CORE_DRACO_TYPES_H_
diff --git a/extern/draco/dracoenc/src/draco/core/draco_version.h b/extern/draco/dracoenc/src/draco/core/draco_version.h
index 45dce22a1d8..9d3a67e4f8e 100644
--- a/extern/draco/dracoenc/src/draco/core/draco_version.h
+++ b/extern/draco/dracoenc/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.4";
+static const char kDracoVersion[] = "1.3.5";
const char *Version() { return kDracoVersion; }
diff --git a/extern/draco/dracoenc/src/draco/core/macros.h b/extern/draco/dracoenc/src/draco/core/macros.h
index e968cbb330b..09819e63969 100644
--- a/extern/draco/dracoenc/src/draco/core/macros.h
+++ b/extern/draco/dracoenc/src/draco/core/macros.h
@@ -32,12 +32,27 @@
#include <iostream>
namespace draco {
+#ifndef DISALLOW_COPY_AND_ASSIGN
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName &) = delete; \
void operator=(const TypeName &) = delete;
+#endif
+
+#ifndef FALLTHROUGH_INTENDED
+#if defined(__clang__) && defined(__has_warning)
+#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#define FALLTHROUGH_INTENDED [[clang::fallthrough]]
+#endif
+#elif defined(__GNUC__) && __GNUC__ >= 7
+#define FALLTHROUGH_INTENDED [[gnu::fallthrough]]
+#endif
+// If FALLTHROUGH_INTENDED is still not defined, define it.
#ifndef FALLTHROUGH_INTENDED
-#define FALLTHROUGH_INTENDED void(0);
+#define FALLTHROUGH_INTENDED \
+ do { \
+ } while (0)
+#endif
#endif
#ifndef LOG
diff --git a/extern/draco/dracoenc/src/draco/core/math_utils.h b/extern/draco/dracoenc/src/draco/core/math_utils.h
index 6bf237d4560..50cf5d57199 100644
--- a/extern/draco/dracoenc/src/draco/core/math_utils.h
+++ b/extern/draco/dracoenc/src/draco/core/math_utils.h
@@ -17,6 +17,8 @@
#include <inttypes.h>
+#include "draco/core/vector_d.h"
+
#define DRACO_INCREMENT_MOD(I, M) (((I) == ((M)-1)) ? 0 : ((I) + 1))
// Returns floor(sqrt(x)) where x is an integer number. The main intend of this
diff --git a/extern/draco/dracoenc/src/draco/core/math_utils_test.cc b/extern/draco/dracoenc/src/draco/core/math_utils_test.cc
index b12b3431e66..8c255d04680 100644
--- a/extern/draco/dracoenc/src/draco/core/math_utils_test.cc
+++ b/extern/draco/dracoenc/src/draco/core/math_utils_test.cc
@@ -1,9 +1,12 @@
#include "draco/core/math_utils.h"
+#include <cmath>
#include <random>
#include "draco/core/draco_test_base.h"
+using draco::Vector3f;
+
TEST(MathUtils, Mod) { EXPECT_EQ(DRACO_INCREMENT_MOD(1, 1 << 1), 0); }
TEST(MathUtils, IntSqrt) {
diff --git a/extern/draco/dracoenc/src/draco/core/options.cc b/extern/draco/dracoenc/src/draco/core/options.cc
index c4f6d6a66aa..a9ce14b9837 100644
--- a/extern/draco/dracoenc/src/draco/core/options.cc
+++ b/extern/draco/dracoenc/src/draco/core/options.cc
@@ -16,11 +16,17 @@
#include <cstdlib>
#include <string>
+#include <utility>
namespace draco {
Options::Options() {}
+void Options::MergeAndReplace(const Options &other_options) {
+ for (const auto &item : other_options.options_)
+ options_[item.first] = item.second;
+}
+
void Options::SetInt(const std::string &name, int val) {
options_[name] = std::to_string(val);
}
diff --git a/extern/draco/dracoenc/src/draco/core/options.h b/extern/draco/dracoenc/src/draco/core/options.h
index 0e69844911d..4995299633c 100644
--- a/extern/draco/dracoenc/src/draco/core/options.h
+++ b/extern/draco/dracoenc/src/draco/core/options.h
@@ -28,6 +28,11 @@ namespace draco {
class Options {
public:
Options();
+
+ // Merges |other_options| on top of the existing options of this instance
+ // replacing all entries that are present in both options instances.
+ void MergeAndReplace(const Options &other_options);
+
void SetInt(const std::string &name, int val);
void SetFloat(const std::string &name, float val);
void SetBool(const std::string &name, bool val);
diff --git a/extern/draco/dracoenc/src/draco/core/status.h b/extern/draco/dracoenc/src/draco/core/status.h
index 0a483f09369..9ac3def7cd1 100644
--- a/extern/draco/dracoenc/src/draco/core/status.h
+++ b/extern/draco/dracoenc/src/draco/core/status.h
@@ -25,7 +25,7 @@ class Status {
public:
enum Code {
OK = 0,
- ERROR = -1, // Used for general errors.
+ DRACO_ERROR = -1, // Used for general errors.
IO_ERROR = -2, // Error when handling input or output stream.
INVALID_PARAMETER = -3, // Invalid parameter passed to a function.
UNSUPPORTED_VERSION = -4, // Input not compatible with the current version.
diff --git a/extern/draco/dracoenc/src/draco/core/status_or.h b/extern/draco/dracoenc/src/draco/core/status_or.h
new file mode 100644
index 00000000000..156b9bc02a7
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/core/status_or.h
@@ -0,0 +1,81 @@
+// Copyright 2017 The Draco Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef DRACO_CORE_STATUS_OR_H_
+#define DRACO_CORE_STATUS_OR_H_
+
+#include "draco/core/macros.h"
+#include "draco/core/status.h"
+
+namespace draco {
+
+// Class StatusOr is used to wrap a Status along with a value of a specified
+// type |T|. StatusOr is intended to be returned from functions in situations
+// where it is desirable to carry over more information about the potential
+// errors encountered during the function execution. If there are not errors,
+// the caller can simply use the return value, otherwise the Status object
+// provides more info about the encountered problem.
+template <class T>
+class StatusOr {
+ public:
+ StatusOr() {}
+ // Note: Constructors are intentionally not explicit to allow returning
+ // Status or the return value directly from functions.
+ StatusOr(const StatusOr &) = default;
+ StatusOr(StatusOr &&) = default;
+ StatusOr(const Status &status) : status_(status) {}
+ StatusOr(const T &value) : status_(OkStatus()), value_(value) {}
+ StatusOr(T &&value) : status_(OkStatus()), value_(std::move(value)) {}
+ StatusOr(const Status &status, const T &value)
+ : status_(status), value_(value) {}
+
+ const Status &status() const { return status_; }
+ const T &value() const & { return value_; }
+ const T &&value() const && { return std::move(value_); }
+ T &&value() && { return std::move(value_); }
+
+ // For consistency with existing Google StatusOr API we also include
+ // ValueOrDie() that currently returns the value().
+ const T &ValueOrDie() const & { return value(); }
+ T &&ValueOrDie() && { return std::move(value()); }
+
+ bool ok() const { return status_.ok(); }
+
+ private:
+ Status status_;
+ T value_;
+};
+
+// In case StatusOr<T> is ok(), this macro assigns value stored in StatusOr<T>
+// to |lhs|, otherwise it returns the error Status.
+//
+// DRACO_ASSIGN_OR_RETURN(lhs, expression)
+//
+#define DRACO_ASSIGN_OR_RETURN(lhs, expression) \
+ DRACO_ASSIGN_OR_RETURN_IMPL_(DRACO_MACROS_IMPL_CONCAT_(_statusor, __LINE__), \
+ lhs, expression, _status)
+
+// The actual implementation of the above macro.
+#define DRACO_ASSIGN_OR_RETURN_IMPL_(statusor, lhs, expression, error_expr) \
+ auto statusor = (expression); \
+ if (!statusor.ok()) { \
+ auto _status = std::move(statusor.status()); \
+ (void)_status; /* error_expression may not use it */ \
+ return error_expr; \
+ } \
+ lhs = std::move(statusor).value();
+
+} // namespace draco
+
+#endif // DRACO_CORE_STATUS_OR_H_
diff --git a/extern/draco/dracoenc/src/draco/core/status_test.cc b/extern/draco/dracoenc/src/draco/core/status_test.cc
index 451ebe2bfab..c1ad4ab30f4 100644
--- a/extern/draco/dracoenc/src/draco/core/status_test.cc
+++ b/extern/draco/dracoenc/src/draco/core/status_test.cc
@@ -27,8 +27,8 @@ class StatusTest : public ::testing::Test {
TEST_F(StatusTest, TestStatusOutput) {
// Tests that the Status can be stored in a provided std::ostream.
- const draco::Status status(draco::Status::ERROR, "Error msg.");
- ASSERT_EQ(status.code(), draco::Status::ERROR);
+ const draco::Status status(draco::Status::DRACO_ERROR, "Error msg.");
+ ASSERT_EQ(status.code(), draco::Status::DRACO_ERROR);
std::stringstream str;
str << status;
diff --git a/extern/draco/dracoenc/src/draco/core/vector_d.h b/extern/draco/dracoenc/src/draco/core/vector_d.h
index 57dcd102663..189517f3928 100644
--- a/extern/draco/dracoenc/src/draco/core/vector_d.h
+++ b/extern/draco/dracoenc/src/draco/core/vector_d.h
@@ -24,16 +24,20 @@
namespace draco {
// D-dimensional vector class with basic operations.
-template <class CoeffT, int dimension_t>
+template <class ScalarT, int dimension_t>
class VectorD {
public:
- typedef VectorD<CoeffT, dimension_t> Self;
- typedef CoeffT CoefficientType;
static constexpr int dimension = dimension_t;
+ typedef ScalarT Scalar;
+ typedef VectorD<Scalar, dimension_t> Self;
+
+ // TODO(hemmer): Deprecate.
+ typedef ScalarT CoefficientType;
+
VectorD() {
- for (int i = 0; i < dimension_t; ++i)
- (*this)[i] = CoeffT(0);
+ for (int i = 0; i < dimension; ++i)
+ (*this)[i] = Scalar(0);
}
// The following constructor does not compile in opt mode, which for now led
@@ -42,58 +46,75 @@ class VectorD {
// template <typename... Args>
// explicit VectorD(Args... args) : v_({args...}) {}
- VectorD(const CoeffT &c0, const CoeffT &c1) : v_({{c0, c1}}) {
- DRACO_DCHECK_EQ(dimension_t, 2);
+ VectorD(const Scalar &c0, const Scalar &c1) : v_({{c0, c1}}) {
+ DRACO_DCHECK_EQ(dimension, 2);
v_[0] = c0;
v_[1] = c1;
}
- VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2)
+ VectorD(const Scalar &c0, const Scalar &c1, const Scalar &c2)
: v_({{c0, c1, c2}}) {
- DRACO_DCHECK_EQ(dimension_t, 3);
+ DRACO_DCHECK_EQ(dimension, 3);
}
- VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2,
- const CoeffT &c3)
+ VectorD(const Scalar &c0, const Scalar &c1, const Scalar &c2,
+ const Scalar &c3)
: v_({{c0, c1, c2, c3}}) {
- DRACO_DCHECK_EQ(dimension_t, 4);
+ DRACO_DCHECK_EQ(dimension, 4);
}
- VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2,
- const CoeffT &c3, const CoeffT &c4)
+ VectorD(const Scalar &c0, const Scalar &c1, const Scalar &c2,
+ const Scalar &c3, const Scalar &c4)
: v_({{c0, c1, c2, c3, c4}}) {
- DRACO_DCHECK_EQ(dimension_t, 5);
+ DRACO_DCHECK_EQ(dimension, 5);
}
- VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2,
- const CoeffT &c3, const CoeffT &c4, const CoeffT &c5)
+ VectorD(const Scalar &c0, const Scalar &c1, const Scalar &c2,
+ const Scalar &c3, const Scalar &c4, const Scalar &c5)
: v_({{c0, c1, c2, c3, c4, c5}}) {
- DRACO_DCHECK_EQ(dimension_t, 6);
+ DRACO_DCHECK_EQ(dimension, 6);
}
- VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2,
- const CoeffT &c3, const CoeffT &c4, const CoeffT &c5,
- const CoeffT &c6)
+ VectorD(const Scalar &c0, const Scalar &c1, const Scalar &c2,
+ const Scalar &c3, const Scalar &c4, const Scalar &c5,
+ const Scalar &c6)
: v_({{c0, c1, c2, c3, c4, c5, c6}}) {
- DRACO_DCHECK_EQ(dimension_t, 7);
+ DRACO_DCHECK_EQ(dimension, 7);
}
VectorD(const Self &o) {
- for (int i = 0; i < dimension_t; ++i)
+ for (int i = 0; i < dimension; ++i)
(*this)[i] = o[i];
}
- CoeffT &operator[](int i) { return v_[i]; }
- const CoeffT &operator[](int i) const { return v_[i]; }
+ // Constructs the vector from another vector with a different data type or a
+ // different number of components. If the |src_vector| has more components
+ // than |this| vector, the excess components are truncated. If the
+ // |src_vector| has fewer components than |this| vector, the remaining
+ // components are padded with 0.
+ // Note that the constructor is intentionally explicit to avoid accidental
+ // conversions between different vector types.
+ template <class OtherScalarT, int other_dimension_t>
+ explicit VectorD(const VectorD<OtherScalarT, other_dimension_t> &src_vector) {
+ for (int i = 0; i < dimension; ++i) {
+ if (i < other_dimension_t)
+ v_[i] = Scalar(src_vector[i]);
+ else
+ v_[i] = Scalar(0);
+ }
+ }
+
+ Scalar &operator[](int i) { return v_[i]; }
+ const Scalar &operator[](int i) const { return v_[i]; }
// TODO(hemmer): remove.
// Similar to interface of Eigen library.
- CoeffT &operator()(int i) { return v_[i]; }
- const CoeffT &operator()(int i) const { return v_[i]; }
+ Scalar &operator()(int i) { return v_[i]; }
+ const Scalar &operator()(int i) const { return v_[i]; }
// Unary operators.
Self operator-() const {
Self ret;
- for (int i = 0; i < dimension_t; ++i) {
+ for (int i = 0; i < dimension; ++i) {
ret[i] = -(*this)[i];
}
return ret;
@@ -102,7 +123,7 @@ class VectorD {
// Binary operators.
Self operator+(const Self &o) const {
Self ret;
- for (int i = 0; i < dimension_t; ++i) {
+ for (int i = 0; i < dimension; ++i) {
ret[i] = (*this)[i] + o[i];
}
return ret;
@@ -110,30 +131,46 @@ class VectorD {
Self operator-(const Self &o) const {
Self ret;
- for (int i = 0; i < dimension_t; ++i) {
+ for (int i = 0; i < dimension; ++i) {
ret[i] = (*this)[i] - o[i];
}
return ret;
}
- Self operator*(const CoeffT &o) const {
+ Self operator*(const Scalar &o) const {
Self ret;
- for (int i = 0; i < dimension_t; ++i) {
+ for (int i = 0; i < dimension; ++i) {
ret[i] = (*this)[i] * o;
}
return ret;
}
- Self operator/(const CoeffT &o) const {
+ Self operator/(const Scalar &o) const {
Self ret;
- for (int i = 0; i < dimension_t; ++i) {
+ for (int i = 0; i < dimension; ++i) {
ret[i] = (*this)[i] / o;
}
return ret;
}
+ Self operator+(const Scalar &o) const {
+ Self ret;
+ for (int i = 0; i < dimension; ++i) {
+ ret[i] = (*this)[i] + o;
+ }
+ return ret;
+ }
+
+ Self operator-(const Scalar &o) const {
+ Self ret;
+ for (int i = 0; i < dimension; ++i) {
+ ret[i] = (*this)[i] - o;
+ }
+ return ret;
+ }
+
bool operator==(const Self &o) const {
- for (int i = 0; i < dimension_t; ++i) {
+ for (int i = 0; i < dimension; ++i) {
if ((*this)[i] != o[i])
return false;
}
@@ -143,67 +180,75 @@ class VectorD {
bool operator!=(const Self &x) const { return !((*this) == x); }
bool operator<(const Self &x) const {
- for (int i = 0; i < dimension_t - 1; ++i) {
+ for (int i = 0; i < dimension - 1; ++i) {
if (v_[i] < x.v_[i])
return true;
if (v_[i] > x.v_[i])
return false;
}
// Only one check needed for the last dimension.
- if (v_[dimension_t - 1] < x.v_[dimension_t - 1])
+ if (v_[dimension - 1] < x.v_[dimension - 1])
return true;
return false;
}
// Functions.
- CoeffT SquaredNorm() const { return this->Dot(*this); }
+ Scalar SquaredNorm() const { return this->Dot(*this); }
// Computes L1, the sum of absolute values of all entries.
- CoeffT AbsSum() const {
- CoeffT result(0);
- for (int i = 0; i < dimension_t; ++i) {
+ Scalar AbsSum() const {
+ Scalar result(0);
+ for (int i = 0; i < dimension; ++i) {
result += std::abs(v_[i]);
}
return result;
}
- CoeffT Dot(const Self &o) const {
- CoeffT ret(0);
- for (int i = 0; i < dimension_t; ++i) {
+ Scalar Dot(const Self &o) const {
+ Scalar ret(0);
+ for (int i = 0; i < dimension; ++i) {
ret += (*this)[i] * o[i];
}
return ret;
}
void Normalize() {
- const CoeffT magnitude = std::sqrt(this->SquaredNorm());
+ const Scalar magnitude = std::sqrt(this->SquaredNorm());
if (magnitude == 0) {
return;
}
- for (int i = 0; i < dimension_t; ++i) {
+ for (int i = 0; i < dimension; ++i) {
(*this)[i] /= magnitude;
}
}
- CoeffT *data() { return &(v_[0]); }
+ const Scalar &MaxCoeff() const {
+ return *std::max_element(v_.begin(), v_.end());
+ }
+
+ const Scalar &MinCoeff() const {
+ return *std::min_element(v_.begin(), v_.end());
+ }
+
+ Scalar *data() { return &(v_[0]); }
private:
- std::array<CoeffT, dimension_t> v_;
+ std::array<Scalar, dimension> v_;
};
// Scalar multiplication from the other side too.
-template <class CoeffT, int dimension_t>
-VectorD<CoeffT, dimension_t> operator*(const CoeffT &o,
- const VectorD<CoeffT, dimension_t> &v) {
+template <class ScalarT, int dimension_t>
+VectorD<ScalarT, dimension_t> operator*(
+ const ScalarT &o, const VectorD<ScalarT, dimension_t> &v) {
return v * o;
}
// Calculates the squared distance between two points.
-template <class CoeffT, int dimension_t>
-CoeffT SquaredDistance(const VectorD<CoeffT, dimension_t> &v1,
- const VectorD<CoeffT, dimension_t> &v2) {
- CoeffT difference;
- CoeffT squared_distance = 0;
+template <class ScalarT, int dimension_t>
+ScalarT SquaredDistance(const VectorD<ScalarT, dimension_t> &v1,
+ const VectorD<ScalarT, dimension_t> &v2) {
+ ScalarT difference;
+ ScalarT squared_distance = 0;
// Check each index separately so difference is never negative and underflow
// is avoided for unsigned types.
for (int i = 0; i < dimension_t; ++i) {
@@ -218,22 +263,22 @@ CoeffT SquaredDistance(const VectorD<CoeffT, dimension_t> &v1,
}
// Global function computing the cross product of two 3D vectors.
-template <class CoeffT>
-VectorD<CoeffT, 3> CrossProduct(const VectorD<CoeffT, 3> &u,
- const VectorD<CoeffT, 3> &v) {
+template <class ScalarT>
+VectorD<ScalarT, 3> CrossProduct(const VectorD<ScalarT, 3> &u,
+ const VectorD<ScalarT, 3> &v) {
// Preventing accidental use with uint32_t and the like.
- static_assert(std::is_signed<CoeffT>::value,
- "CoeffT must be a signed type. ");
- VectorD<CoeffT, 3> r;
+ static_assert(std::is_signed<ScalarT>::value,
+ "ScalarT must be a signed type. ");
+ VectorD<ScalarT, 3> r;
r[0] = (u[1] * v[2]) - (u[2] * v[1]);
r[1] = (u[2] * v[0]) - (u[0] * v[2]);
r[2] = (u[0] * v[1]) - (u[1] * v[0]);
return r;
}
-template <class CoeffT, int dimension_t>
+template <class ScalarT, int dimension_t>
inline std::ostream &operator<<(
- std::ostream &out, const draco::VectorD<CoeffT, dimension_t> &vec) {
+ std::ostream &out, const draco::VectorD<ScalarT, dimension_t> &vec) {
for (int i = 0; i < dimension_t - 1; ++i) {
out << vec[i] << " ";
}
diff --git a/extern/draco/dracoenc/src/draco/core/vector_d_test.cc b/extern/draco/dracoenc/src/draco/core/vector_d_test.cc
index 967043bb926..bc2bdadaa9f 100644
--- a/extern/draco/dracoenc/src/draco/core/vector_d_test.cc
+++ b/extern/draco/dracoenc/src/draco/core/vector_d_test.cc
@@ -32,20 +32,17 @@ typedef draco::Vector5ui Vector5ui;
typedef draco::VectorD<int32_t, 3> Vector3i;
typedef draco::VectorD<int32_t, 4> Vector4i;
-class VectorDTest : public ::testing::Test {
- protected:
- template <class CoeffT, int dimension_t>
- void TestSquaredDistance(const draco::VectorD<CoeffT, dimension_t> v1,
- const draco::VectorD<CoeffT, dimension_t> v2,
- const CoeffT result) {
- CoeffT squared_distance = SquaredDistance(v1, v2);
- ASSERT_EQ(squared_distance, result);
- squared_distance = SquaredDistance(v2, v1);
- ASSERT_EQ(squared_distance, result);
- }
-};
+template <class CoeffT, int dimension_t>
+void TestSquaredDistance(const draco::VectorD<CoeffT, dimension_t> v1,
+ const draco::VectorD<CoeffT, dimension_t> v2,
+ const CoeffT result) {
+ CoeffT squared_distance = SquaredDistance(v1, v2);
+ ASSERT_EQ(squared_distance, result);
+ squared_distance = SquaredDistance(v2, v1);
+ ASSERT_EQ(squared_distance, result);
+}
-TEST_F(VectorDTest, TestOperators) {
+TEST(VectorDTest, TestOperators) {
{
const Vector3f v;
ASSERT_EQ(v[0], 0);
@@ -58,10 +55,8 @@ TEST_F(VectorDTest, TestOperators) {
ASSERT_EQ(v[2], 3);
Vector3f w = v;
- bool comp = (v == w);
- ASSERT_TRUE(comp);
- comp = (v != w);
- ASSERT_TRUE(!comp);
+ ASSERT_TRUE(v == w);
+ ASSERT_FALSE(v != w);
ASSERT_EQ(w[0], 1);
ASSERT_EQ(w[1], 2);
ASSERT_EQ(w[2], 3);
@@ -81,10 +76,15 @@ TEST_F(VectorDTest, TestOperators) {
ASSERT_EQ(w[1], 2);
ASSERT_EQ(w[2], 3);
+ // Scalar multiplication from left and right.
w = v * 2.f;
ASSERT_EQ(w[0], 2);
ASSERT_EQ(w[1], 4);
ASSERT_EQ(w[2], 6);
+ w = 2.f * v;
+ ASSERT_EQ(w[0], 2);
+ ASSERT_EQ(w[1], 4);
+ ASSERT_EQ(w[2], 6);
ASSERT_EQ(v.SquaredNorm(), 14);
ASSERT_EQ(v.Dot(v), 14);
@@ -109,7 +109,7 @@ TEST_F(VectorDTest, TestOperators) {
}
}
-TEST_F(VectorDTest, TestSquaredDistance) {
+TEST(VectorDTest, TestSquaredDistance) {
// Test Vector2f: float, 2D.
Vector2f v1_2f(5.5, 10.5);
Vector2f v2_2f(3.5, 15.5);
@@ -158,7 +158,8 @@ TEST_F(VectorDTest, TestSquaredDistance) {
result_ui = 158;
TestSquaredDistance(v1_5ui, v2_5ui, result_ui);
}
-TEST_F(VectorDTest, TestCrossProduct3D) {
+
+TEST(VectorDTest, TestCrossProduct3D) {
const Vector3i e1(1, 0, 0);
const Vector3i e2(0, 1, 0);
const Vector3i e3(0, 0, 1);
@@ -181,7 +182,7 @@ TEST_F(VectorDTest, TestCrossProduct3D) {
ASSERT_EQ(0, v2.Dot(orth));
}
-TEST_F(VectorDTest, TestAbsSum) {
+TEST(VectorDTest, TestAbsSum) {
// Testing const of function and zero.
const Vector3i v(0, 0, 0);
ASSERT_EQ(v.AbsSum(), 0);
@@ -194,7 +195,18 @@ TEST_F(VectorDTest, TestAbsSum) {
ASSERT_EQ(Vector4i(-2, 4, -8, 3).AbsSum(), 17);
}
-TEST_F(VectorDTest, TestOstream) {
+TEST(VectorDTest, TestMinMaxCoeff) {
+ // Test verifies that MinCoeff() and MaxCoeff() functions work as intended.
+ const Vector4i vi(-10, 5, 2, 3);
+ ASSERT_EQ(vi.MinCoeff(), -10);
+ ASSERT_EQ(vi.MaxCoeff(), 5);
+
+ const Vector3f vf(6.f, 1000.f, -101.f);
+ ASSERT_EQ(vf.MinCoeff(), -101.f);
+ ASSERT_EQ(vf.MaxCoeff(), 1000.f);
+}
+
+TEST(VectorDTest, TestOstream) {
// Tests that the vector can be stored in a provided std::ostream.
const draco::VectorD<int64_t, 3> vector(1, 2, 3);
std::stringstream str;
@@ -202,4 +214,22 @@ TEST_F(VectorDTest, TestOstream) {
ASSERT_EQ(str.str(), "1 2 3 ");
}
+TEST(VectorDTest, TestConvertConstructor) {
+ // Tests that a vector can be constructed from another vector with a different
+ // type.
+ const draco::VectorD<int64_t, 3> vector(1, 2, 3);
+
+ const draco::VectorD<float, 3> vector3f(vector);
+ ASSERT_EQ(vector3f, draco::Vector3f(1.f, 2.f, 3.f));
+
+ const draco::VectorD<float, 2> vector2f(vector);
+ ASSERT_EQ(vector2f, draco::Vector2f(1.f, 2.f));
+
+ const draco::VectorD<float, 4> vector4f(vector3f);
+ ASSERT_EQ(vector4f, draco::Vector4f(1.f, 2.f, 3.f, 0.f));
+
+ const draco::VectorD<double, 1> vector1d(vector3f);
+ ASSERT_EQ(vector1d[0], 1.0);
+}
+
} // namespace
diff --git a/extern/draco/dracoenc/src/draco/io/mesh_io.cc b/extern/draco/dracoenc/src/draco/io/mesh_io.cc
index 807dcfbe06b..5e2f9f51d7a 100644
--- a/extern/draco/dracoenc/src/draco/io/mesh_io.cc
+++ b/extern/draco/dracoenc/src/draco/io/mesh_io.cc
@@ -16,37 +16,33 @@
#include <fstream>
+#include "draco/io/file_utils.h"
#include "draco/io/obj_decoder.h"
-#include "draco/io/parser_utils.h"
#include "draco/io/ply_decoder.h"
namespace draco {
-namespace {
-
-// Returns the file extension in lowercase if present, else ""
-inline std::string LowercaseFileExtension(const std::string &filename) {
- size_t pos = filename.find_last_of('.');
- if (pos == std::string::npos || pos >= filename.length() - 1)
- return "";
- return parser::ToLower(filename.substr(pos + 1));
-}
-
-} // namespace
-
StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name) {
- return ReadMeshFromFile(file_name, false);
+ const Options options;
+ return ReadMeshFromFile(file_name, options);
}
StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name,
bool use_metadata) {
+ Options options;
+ options.SetBool("use_metadata", use_metadata);
+ return ReadMeshFromFile(file_name, options);
+}
+
+StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name,
+ const Options &options) {
std::unique_ptr<Mesh> mesh(new Mesh());
// Analyze file extension.
const std::string extension = LowercaseFileExtension(file_name);
if (extension == "obj") {
// Wavefront OBJ file format.
ObjDecoder obj_decoder;
- obj_decoder.set_use_metadata(use_metadata);
+ obj_decoder.set_use_metadata(options.GetBool("use_metadata", false));
const Status obj_status = obj_decoder.DecodeFromFile(file_name, mesh.get());
if (!obj_status.ok())
return obj_status;
@@ -55,8 +51,7 @@ StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name,
if (extension == "ply") {
// Wavefront PLY file format.
PlyDecoder ply_decoder;
- if (!ply_decoder.DecodeFromFile(file_name, mesh.get()))
- return Status(Status::ERROR, "Unknown error.");
+ DRACO_RETURN_IF_ERROR(ply_decoder.DecodeFromFile(file_name, mesh.get()));
return std::move(mesh);
}
@@ -64,9 +59,9 @@ StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name,
// draco encoding methods.
std::ifstream is(file_name.c_str(), std::ios::binary);
if (!is)
- return Status(Status::ERROR, "Invalid input stream.");
+ return Status(Status::DRACO_ERROR, "Invalid input stream.");
if (!ReadMeshFromStream(&mesh, is).good())
- return Status(Status::ERROR,
+ return Status(Status::DRACO_ERROR,
"Unknown error."); // Error reading the stream.
return std::move(mesh);
}
diff --git a/extern/draco/dracoenc/src/draco/io/mesh_io.h b/extern/draco/dracoenc/src/draco/io/mesh_io.h
index 7649a736265..15cfbb30b97 100644
--- a/extern/draco/dracoenc/src/draco/io/mesh_io.h
+++ b/extern/draco/dracoenc/src/draco/io/mesh_io.h
@@ -18,6 +18,7 @@
#include "draco/compression/config/compression_shared.h"
#include "draco/compression/decode.h"
#include "draco/compression/expert_encode.h"
+#include "draco/core/options.h"
namespace draco {
@@ -89,6 +90,13 @@ StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name);
StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name,
bool use_metadata);
+// Reads a mesh from a file. Reading is configured with |options|:
+// use_metadata : Read obj file info like material names and object names into
+// metadata. Default is false.
+// Returns nullptr with an error status if the decoding failed.
+StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name,
+ const Options &options);
+
} // namespace draco
#endif // DRACO_MESH_MESH_IO_H_
diff --git a/extern/draco/dracoenc/src/draco/io/obj_decoder.cc b/extern/draco/dracoenc/src/draco/io/obj_decoder.cc
index 5aaa9f72888..88f470f8b4a 100644
--- a/extern/draco/dracoenc/src/draco/io/obj_decoder.cc
+++ b/extern/draco/dracoenc/src/draco/io/obj_decoder.cc
@@ -18,6 +18,7 @@
#include <cmath>
#include <fstream>
+#include "draco/io/file_utils.h"
#include "draco/io/parser_utils.h"
#include "draco/metadata/geometry_metadata.h"
@@ -103,12 +104,12 @@ Status ObjDecoder::DecodeInternal() {
// Ensure the number of all entries is same for all attributes.
if (num_positions_ == 0)
- return Status(Status::ERROR, "No position attribute");
+ return Status(Status::DRACO_ERROR, "No position attribute");
if (num_tex_coords_ > 0 && num_tex_coords_ != num_positions_)
- return Status(Status::ERROR,
+ return Status(Status::DRACO_ERROR,
"Invalid number of texture coordinates for a point cloud");
if (num_normals_ > 0 && num_normals_ != num_positions_)
- return Status(Status::ERROR,
+ return Status(Status::DRACO_ERROR,
"Invalid number of normals for a point cloud");
out_mesh_ = nullptr; // Treat the output geometry as a point cloud.
@@ -151,12 +152,13 @@ Status ObjDecoder::DecodeInternal() {
}
if (num_materials_ > 0 && num_obj_faces_ > 0) {
GeometryAttribute va;
+ const auto geometry_attribute_type = GeometryAttribute::GENERIC;
if (num_materials_ < 256) {
- va.Init(GeometryAttribute::GENERIC, nullptr, 1, DT_UINT8, false, 1, 0);
+ va.Init(geometry_attribute_type, nullptr, 1, DT_UINT8, false, 1, 0);
} else if (num_materials_ < (1 << 16)) {
- va.Init(GeometryAttribute::GENERIC, nullptr, 1, DT_UINT16, false, 2, 0);
+ va.Init(geometry_attribute_type, nullptr, 1, DT_UINT16, false, 2, 0);
} else {
- va.Init(GeometryAttribute::GENERIC, nullptr, 1, DT_UINT32, false, 4, 0);
+ va.Init(geometry_attribute_type, nullptr, 1, DT_UINT32, false, 4, 0);
}
material_att_id_ =
out_point_cloud_->AddAttribute(va, false, num_materials_);
@@ -234,10 +236,13 @@ Status ObjDecoder::DecodeInternal() {
out_mesh_->SetFace(i, face);
}
}
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+
+#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
if (deduplicate_input_values_) {
out_point_cloud_->DeduplicateAttributeValues();
}
+#endif
+#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
out_point_cloud_->DeduplicatePointIds();
#endif
return status;
@@ -298,7 +303,7 @@ bool ObjDecoder::ParseVertexPosition(Status *status) {
for (int i = 0; i < 3; ++i) {
parser::SkipWhitespace(buffer());
if (!parser::ParseFloat(buffer(), val + i)) {
- *status = Status(Status::ERROR, "Failed to parse a float number");
+ *status = Status(Status::DRACO_ERROR, "Failed to parse a float number");
// The definition is processed so return true.
return true;
}
@@ -326,7 +331,7 @@ bool ObjDecoder::ParseNormal(Status *status) {
for (int i = 0; i < 3; ++i) {
parser::SkipWhitespace(buffer());
if (!parser::ParseFloat(buffer(), val + i)) {
- *status = Status(Status::ERROR, "Failed to parse a float number");
+ *status = Status(Status::DRACO_ERROR, "Failed to parse a float number");
// The definition is processed so return true.
return true;
}
@@ -354,7 +359,7 @@ bool ObjDecoder::ParseTexCoord(Status *status) {
for (int i = 0; i < 2; ++i) {
parser::SkipWhitespace(buffer());
if (!parser::ParseFloat(buffer(), val + i)) {
- *status = Status(Status::ERROR, "Failed to parse a float number");
+ *status = Status(Status::DRACO_ERROR, "Failed to parse a float number");
// The definition is processed so return true.
return true;
}
@@ -385,7 +390,7 @@ bool ObjDecoder::ParseFace(Status *status) {
if (i == 3) {
break; // It's OK if there is no fourth vertex index.
}
- *status = Status(Status::ERROR, "Failed to parse vertex indices");
+ *status = Status(Status::DRACO_ERROR, "Failed to parse vertex indices");
return true;
}
++num_valid_indices;
@@ -430,7 +435,8 @@ bool ObjDecoder::ParseFace(Status *status) {
}
}
if (num_indices < 3 || num_indices > 4) {
- *status = Status(Status::ERROR, "Invalid number of indices on a face");
+ *status =
+ Status(Status::DRACO_ERROR, "Invalid number of indices on a face");
return false;
}
// Either one or two new triangles.
@@ -455,7 +461,7 @@ bool ObjDecoder::ParseMaterialLib(Status *status) {
parser::SkipWhitespace(&line_buffer);
material_file_name_.clear();
if (!parser::ParseString(&line_buffer, &material_file_name_)) {
- *status = Status(Status::ERROR, "Failed to parse material file name");
+ *status = Status(Status::DRACO_ERROR, "Failed to parse material file name");
return true;
}
parser::SkipLine(&line_buffer);
@@ -492,6 +498,7 @@ bool ObjDecoder::ParseMaterial(Status * /* status */) {
// will be added to the list.
last_material_id_ = num_materials_;
material_name_to_id_[mat_name] = num_materials_++;
+
return true;
}
last_material_id_ = it->second;
@@ -626,15 +633,7 @@ void ObjDecoder::MapPointToVertexIndices(
bool ObjDecoder::ParseMaterialFile(const std::string &file_name,
Status *status) {
- // Get the correct path to the |file_name| using the folder from
- // |input_file_name_| as the root folder.
- const auto pos = input_file_name_.find_last_of("/\\");
- std::string full_path;
- if (pos != std::string::npos) {
- full_path = input_file_name_.substr(0, pos + 1);
- }
- full_path += file_name;
-
+ const std::string full_path = GetFullPath(file_name, input_file_name_);
std::ifstream file(full_path, std::ios::binary);
if (!file)
return false;
@@ -676,15 +675,14 @@ bool ObjDecoder::ParseMaterialFileDefinition(Status * /* status */) {
std::string str;
if (!parser::ParseString(buffer(), &str))
return false;
- if (str.compare("newmtl") == 0) {
+ if (str == "newmtl") {
parser::SkipWhitespace(buffer());
parser::ParseLine(buffer(), &str);
- if (str.length() == 0)
+ if (str.empty())
return false;
// Add new material to our map.
material_name_to_id_[str] = num_materials_++;
}
- parser::SkipLine(buffer());
return true;
}
diff --git a/extern/draco/dracoenc/src/draco/io/obj_encoder.h b/extern/draco/dracoenc/src/draco/io/obj_encoder.h
index 352a04774c2..509d39baf39 100644
--- a/extern/draco/dracoenc/src/draco/io/obj_encoder.h
+++ b/extern/draco/dracoenc/src/draco/io/obj_encoder.h
@@ -15,6 +15,8 @@
#ifndef DRACO_IO_OBJ_ENCODER_H_
#define DRACO_IO_OBJ_ENCODER_H_
+#include <unordered_map>
+
#include "draco/core/encoder_buffer.h"
#include "draco/mesh/mesh.h"
diff --git a/extern/draco/dracoenc/src/draco/io/parser_utils.cc b/extern/draco/dracoenc/src/draco/io/parser_utils.cc
index e68abb1f263..0a22ba114ab 100644
--- a/extern/draco/dracoenc/src/draco/io/parser_utils.cc
+++ b/extern/draco/dracoenc/src/draco/io/parser_utils.cc
@@ -128,7 +128,7 @@ bool ParseFloat(DecoderBuffer *buffer, float *value) {
return false;
// Apply exponent scaling to value.
- v *= pow(10.0, exponent);
+ v *= pow(static_cast<double>(10.0), exponent);
}
}
diff --git a/extern/draco/dracoenc/src/draco/io/ply_decoder.cc b/extern/draco/dracoenc/src/draco/io/ply_decoder.cc
index 01a97e3dacc..69a1c546cf7 100644
--- a/extern/draco/dracoenc/src/draco/io/ply_decoder.cc
+++ b/extern/draco/dracoenc/src/draco/io/ply_decoder.cc
@@ -17,28 +17,30 @@
#include <fstream>
#include "draco/core/macros.h"
+#include "draco/core/status.h"
#include "draco/io/ply_property_reader.h"
namespace draco {
PlyDecoder::PlyDecoder() : out_mesh_(nullptr), out_point_cloud_(nullptr) {}
-bool PlyDecoder::DecodeFromFile(const std::string &file_name, Mesh *out_mesh) {
+Status PlyDecoder::DecodeFromFile(const std::string &file_name,
+ Mesh *out_mesh) {
out_mesh_ = out_mesh;
return DecodeFromFile(file_name, static_cast<PointCloud *>(out_mesh));
}
-bool PlyDecoder::DecodeFromFile(const std::string &file_name,
- PointCloud *out_point_cloud) {
+Status PlyDecoder::DecodeFromFile(const std::string &file_name,
+ PointCloud *out_point_cloud) {
std::ifstream file(file_name, std::ios::binary);
if (!file)
- return false;
+ return Status(Status::IO_ERROR, "Couldn't open file");
// Read the whole file into a buffer.
auto pos0 = file.tellg();
file.seekg(0, std::ios::end);
auto file_size = file.tellg() - pos0;
if (file_size == 0)
- return false;
+ return Status(Status::IO_ERROR, "Zero file size");
file.seekg(0, std::ios::beg);
std::vector<char> data(file_size);
file.read(&data[0], file_size);
@@ -47,44 +49,46 @@ bool PlyDecoder::DecodeFromFile(const std::string &file_name,
return DecodeFromBuffer(&buffer_, out_point_cloud);
}
-bool PlyDecoder::DecodeFromBuffer(DecoderBuffer *buffer, Mesh *out_mesh) {
+Status PlyDecoder::DecodeFromBuffer(DecoderBuffer *buffer, Mesh *out_mesh) {
out_mesh_ = out_mesh;
return DecodeFromBuffer(buffer, static_cast<PointCloud *>(out_mesh));
}
-bool PlyDecoder::DecodeFromBuffer(DecoderBuffer *buffer,
- PointCloud *out_point_cloud) {
+Status PlyDecoder::DecodeFromBuffer(DecoderBuffer *buffer,
+ PointCloud *out_point_cloud) {
out_point_cloud_ = out_point_cloud;
buffer_.Init(buffer->data_head(), buffer->remaining_size());
return DecodeInternal();
}
-bool PlyDecoder::DecodeInternal() {
+Status PlyDecoder::DecodeInternal() {
PlyReader ply_reader;
- if (!ply_reader.Read(buffer()))
- return false;
+ DRACO_RETURN_IF_ERROR(ply_reader.Read(buffer()));
// First, decode the connectivity data.
- if (out_mesh_ && !DecodeFaceData(ply_reader.GetElementByName("face")))
- return false;
+ if (out_mesh_)
+ DRACO_RETURN_IF_ERROR(DecodeFaceData(ply_reader.GetElementByName("face")));
// Decode all attributes.
- if (!DecodeVertexData(ply_reader.GetElementByName("vertex")))
- return false;
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+ DRACO_RETURN_IF_ERROR(
+ DecodeVertexData(ply_reader.GetElementByName("vertex")));
// In case there are no faces this is just a point cloud which does
// not require deduplication.
if (out_mesh_ && out_mesh_->num_faces() != 0) {
+#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
if (!out_point_cloud_->DeduplicateAttributeValues())
- return false;
+ return Status(Status::DRACO_ERROR,
+ "Could not deduplicate attribute values");
+#endif
+#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
out_point_cloud_->DeduplicatePointIds();
- }
#endif
- return true;
+ }
+ return OkStatus();
}
-bool PlyDecoder::DecodeFaceData(const PlyElement *face_element) {
+Status PlyDecoder::DecodeFaceData(const PlyElement *face_element) {
// We accept point clouds now.
if (face_element == nullptr) {
- return true;
+ return Status(Status::INVALID_PARAMETER, "face_element is null");
}
const int64_t num_faces = face_element->num_entries();
out_mesh_->SetNumFaces(num_faces);
@@ -95,7 +99,7 @@ bool PlyDecoder::DecodeFaceData(const PlyElement *face_element) {
vertex_indices = face_element->GetPropertyByName("vertex_index");
}
if (vertex_indices == nullptr || !vertex_indices->is_list()) {
- return false; // No faces defined.
+ return Status(Status::DRACO_ERROR, "No faces defined");
}
PlyPropertyReader<PointIndex::ValueType> vertex_index_reader(vertex_indices);
@@ -114,7 +118,7 @@ bool PlyDecoder::DecodeFaceData(const PlyElement *face_element) {
face_index++;
}
out_mesh_->SetNumFaces(face_index.value());
- return true;
+ return OkStatus();
}
template <typename DataTypeT>
@@ -138,9 +142,9 @@ bool PlyDecoder::ReadPropertiesToAttribute(
return true;
}
-bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
+Status PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
if (vertex_element == nullptr)
- return false;
+ return Status(Status::INVALID_PARAMETER, "vertex_element is null");
// TODO(ostava): For now, try to load x,y,z vertices and red,green,blue,alpha
// colors. We need to add other properties later.
const PlyProperty *const x_prop = vertex_element->GetPropertyByName("x");
@@ -149,7 +153,7 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
if (!x_prop || !y_prop || !z_prop) {
// Currently, we require 3 vertex coordinates (this should be generalized
// later on).
- return false;
+ return Status(Status::INVALID_PARAMETER, "x, y, or z property is missing");
}
const PointIndex::ValueType num_vertices = vertex_element->num_entries();
out_point_cloud_->set_num_points(num_vertices);
@@ -158,12 +162,14 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
// All properties must have the same type.
if (x_prop->data_type() != y_prop->data_type() ||
y_prop->data_type() != z_prop->data_type()) {
- return false;
+ return Status(Status::INVALID_PARAMETER,
+ "x, y, and z properties must have the same type");
}
// TODO(ostava): For now assume the position types are float32 or int32.
const DataType dt = x_prop->data_type();
if (dt != DT_FLOAT32 && dt != DT_INT32)
- return false;
+ return Status(Status::INVALID_PARAMETER,
+ "x, y, and z properties must be of type float32 or int32");
GeometryAttribute va;
va.Init(GeometryAttribute::POSITION, nullptr, 3, dt, false,
@@ -232,7 +238,8 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
// TODO(ostava): For now ensure the data type of all components is uint8.
DRACO_DCHECK_EQ(true, p->data_type() == DT_UINT8);
if (p->data_type() != DT_UINT8)
- return false;
+ return Status(Status::INVALID_PARAMETER,
+ "Type of 'red' property must be uint8");
color_readers.push_back(std::unique_ptr<PlyPropertyReader<uint8_t>>(
new PlyPropertyReader<uint8_t>(p)));
}
@@ -241,7 +248,8 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
// TODO(ostava): For now ensure the data type of all components is uint8.
DRACO_DCHECK_EQ(true, p->data_type() == DT_UINT8);
if (p->data_type() != DT_UINT8)
- return false;
+ return Status(Status::INVALID_PARAMETER,
+ "Type of 'green' property must be uint8");
color_readers.push_back(std::unique_ptr<PlyPropertyReader<uint8_t>>(
new PlyPropertyReader<uint8_t>(p)));
}
@@ -250,7 +258,8 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
// TODO(ostava): For now ensure the data type of all components is uint8.
DRACO_DCHECK_EQ(true, p->data_type() == DT_UINT8);
if (p->data_type() != DT_UINT8)
- return false;
+ return Status(Status::INVALID_PARAMETER,
+ "Type of 'blue' property must be uint8");
color_readers.push_back(std::unique_ptr<PlyPropertyReader<uint8_t>>(
new PlyPropertyReader<uint8_t>(p)));
}
@@ -259,7 +268,8 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
// TODO(ostava): For now ensure the data type of all components is uint8.
DRACO_DCHECK_EQ(true, p->data_type() == DT_UINT8);
if (p->data_type() != DT_UINT8)
- return false;
+ return Status(Status::INVALID_PARAMETER,
+ "Type of 'alpha' property must be uint8");
color_readers.push_back(std::unique_ptr<PlyPropertyReader<uint8_t>>(
new PlyPropertyReader<uint8_t>(p)));
}
@@ -279,7 +289,7 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
}
}
- return true;
+ return OkStatus();
}
} // namespace draco
diff --git a/extern/draco/dracoenc/src/draco/io/ply_decoder.h b/extern/draco/dracoenc/src/draco/io/ply_decoder.h
index 60a48de730e..9e667ab192f 100644
--- a/extern/draco/dracoenc/src/draco/io/ply_decoder.h
+++ b/extern/draco/dracoenc/src/draco/io/ply_decoder.h
@@ -20,6 +20,7 @@
#include "draco/draco_features.h"
#include "draco/core/decoder_buffer.h"
+#include "draco/core/status.h"
#include "draco/io/ply_reader.h"
#include "draco/mesh/mesh.h"
@@ -35,21 +36,20 @@ class PlyDecoder {
PlyDecoder();
// Decodes an obj file stored in the input file.
- // Returns nullptr if the decoding failed.
- bool DecodeFromFile(const std::string &file_name, Mesh *out_mesh);
- bool DecodeFromFile(const std::string &file_name,
- PointCloud *out_point_cloud);
+ Status DecodeFromFile(const std::string &file_name, Mesh *out_mesh);
+ Status DecodeFromFile(const std::string &file_name,
+ PointCloud *out_point_cloud);
- bool DecodeFromBuffer(DecoderBuffer *buffer, Mesh *out_mesh);
- bool DecodeFromBuffer(DecoderBuffer *buffer, PointCloud *out_point_cloud);
+ Status DecodeFromBuffer(DecoderBuffer *buffer, Mesh *out_mesh);
+ Status DecodeFromBuffer(DecoderBuffer *buffer, PointCloud *out_point_cloud);
protected:
- bool DecodeInternal();
+ Status DecodeInternal();
DecoderBuffer *buffer() { return &buffer_; }
private:
- bool DecodeFaceData(const PlyElement *face_element);
- bool DecodeVertexData(const PlyElement *vertex_element);
+ Status DecodeFaceData(const PlyElement *face_element);
+ Status DecodeVertexData(const PlyElement *vertex_element);
template <typename DataTypeT>
bool ReadPropertiesToAttribute(
diff --git a/extern/draco/dracoenc/src/draco/io/ply_decoder_test.cc b/extern/draco/dracoenc/src/draco/io/ply_decoder_test.cc
index 39a52274ce6..647324ea904 100644
--- a/extern/draco/dracoenc/src/draco/io/ply_decoder_test.cc
+++ b/extern/draco/dracoenc/src/draco/io/ply_decoder_test.cc
@@ -26,8 +26,11 @@ class PlyDecoderTest : public ::testing::Test {
const std::string path = GetTestFileFullPath(file_name);
PlyDecoder decoder;
std::unique_ptr<Geometry> geometry(new Geometry());
- if (!decoder.DecodeFromFile(path, geometry.get()))
+ Status status = decoder.DecodeFromFile(path, geometry.get());
+ if (!status.ok()) {
+ LOG(DRACO_ERROR) << "Failed to decode " << file_name << ": " << status;
return nullptr;
+ }
return geometry;
}
diff --git a/extern/draco/dracoenc/src/draco/io/ply_reader.cc b/extern/draco/dracoenc/src/draco/io/ply_reader.cc
index f924550e23f..772c4381176 100644
--- a/extern/draco/dracoenc/src/draco/io/ply_reader.cc
+++ b/extern/draco/dracoenc/src/draco/io/ply_reader.cc
@@ -17,6 +17,7 @@
#include <array>
#include <regex>
+#include "draco/core/status.h"
#include "draco/io/parser_utils.h"
#include "draco/io/ply_property_writer.h"
@@ -34,13 +35,11 @@ PlyElement::PlyElement(const std::string &name, int64_t num_entries)
PlyReader::PlyReader() : format_(kLittleEndian) {}
-bool PlyReader::Read(DecoderBuffer *buffer) {
- error_message_.clear();
+Status PlyReader::Read(DecoderBuffer *buffer) {
std::string value;
// The first line needs to by "ply".
if (!parser::ParseString(buffer, &value) || value != "ply") {
- error_message_ = "Not a valid ply file.";
- return false;
+ return Status(Status::INVALID_PARAMETER, "Not a valid ply file");
}
parser::SkipLine(buffer);
@@ -52,52 +51,49 @@ bool PlyReader::Read(DecoderBuffer *buffer) {
format = words[1];
version = words[2];
} else {
- error_message_ = "Missing or wrong format line.";
- return false;
+ return Status(Status::INVALID_PARAMETER, "Missing or wrong format line");
}
if (version != "1.0") {
- error_message_ = "Unsupported PLY version.";
- return false; // Wrong version.
+ return Status(Status::UNSUPPORTED_VERSION, "Unsupported PLY version");
}
if (format == "binary_big_endian") {
- error_message_ =
- "Unsupported format. Currently we support only ascii and"
- " binary_little_endian format.";
- return false;
+ return Status(Status::UNSUPPORTED_VERSION,
+ "Unsupported format. Currently we support only ascii and"
+ " binary_little_endian format.");
}
if (format == "ascii") {
format_ = kAscii;
} else {
format_ = kLittleEndian;
}
- if (!ParseHeader(buffer))
- return false;
- if (!ParsePropertiesData(buffer))
- return false;
- return true;
+ DRACO_RETURN_IF_ERROR(ParseHeader(buffer));
+ if (!ParsePropertiesData(buffer)) {
+ return Status(Status::INVALID_PARAMETER, "Couldn't parse properties");
+ }
+ return OkStatus();
}
-bool PlyReader::ParseHeader(DecoderBuffer *buffer) {
- while (error_message_.length() == 0 && !ParseEndHeader(buffer)) {
+Status PlyReader::ParseHeader(DecoderBuffer *buffer) {
+ while (true) {
+ DRACO_ASSIGN_OR_RETURN(bool end, ParseEndHeader(buffer));
+ if (end)
+ break;
if (ParseElement(buffer))
continue;
- if (ParseProperty(buffer))
+ DRACO_ASSIGN_OR_RETURN(bool property_parsed, ParseProperty(buffer));
+ if (property_parsed)
continue;
parser::SkipLine(buffer);
}
- if (error_message_.length() > 0) {
- printf("ERROR %s\n", error_message_.c_str());
- return false;
- }
- return true;
+ return OkStatus();
}
-bool PlyReader::ParseEndHeader(DecoderBuffer *buffer) {
+StatusOr<bool> PlyReader::ParseEndHeader(DecoderBuffer *buffer) {
parser::SkipWhitespace(buffer);
std::array<char, 10> c;
if (!buffer->Peek(&c)) {
- error_message_ = "End of file reached before the end_header.";
- return false;
+ return Status(Status::INVALID_PARAMETER,
+ "End of file reached before the end_header");
}
if (std::memcmp(&c[0], "end_header", 10) != 0)
return false;
@@ -126,7 +122,7 @@ bool PlyReader::ParseElement(DecoderBuffer *buffer) {
return true;
}
-bool PlyReader::ParseProperty(DecoderBuffer *buffer) {
+StatusOr<bool> PlyReader::ParseProperty(DecoderBuffer *buffer) {
if (elements_.empty())
return false; // Ignore properties if there is no active element.
DecoderBuffer line_buffer(*buffer);
@@ -154,15 +150,13 @@ bool PlyReader::ParseProperty(DecoderBuffer *buffer) {
}
const DataType data_type = GetDataTypeFromString(data_type_str);
if (data_type == DT_INVALID) {
- error_message_ = "Wrong property data type.";
- return true; // Parsed.
+ return Status(Status::INVALID_PARAMETER, "Wrong property data type");
}
DataType list_type = DT_INVALID;
if (property_list_search) {
list_type = GetDataTypeFromString(list_type_str);
if (list_type == DT_INVALID) {
- error_message_ = "Wrong property list type.";
- return true; // Parsed.
+ return Status(Status::INVALID_PARAMETER, "Wrong property list type");
}
}
elements_.back().AddProperty(
diff --git a/extern/draco/dracoenc/src/draco/io/ply_reader.h b/extern/draco/dracoenc/src/draco/io/ply_reader.h
index 8d0f21ff1cb..845ef2326ae 100644
--- a/extern/draco/dracoenc/src/draco/io/ply_reader.h
+++ b/extern/draco/dracoenc/src/draco/io/ply_reader.h
@@ -26,6 +26,8 @@
#include "draco/core/decoder_buffer.h"
#include "draco/core/draco_types.h"
+#include "draco/core/status.h"
+#include "draco/core/status_or.h"
namespace draco {
@@ -111,7 +113,7 @@ class PlyElement {
class PlyReader {
public:
PlyReader();
- bool Read(DecoderBuffer *buffer);
+ Status Read(DecoderBuffer *buffer);
const PlyElement *GetElementByName(const std::string &name) const {
const auto it = element_index_.find(name);
@@ -128,10 +130,10 @@ class PlyReader {
private:
enum Format { kLittleEndian = 0, kAscii };
- bool ParseHeader(DecoderBuffer *buffer);
- bool ParseEndHeader(DecoderBuffer *buffer);
+ Status ParseHeader(DecoderBuffer *buffer);
+ StatusOr<bool> ParseEndHeader(DecoderBuffer *buffer);
bool ParseElement(DecoderBuffer *buffer);
- bool ParseProperty(DecoderBuffer *buffer);
+ StatusOr<bool> ParseProperty(DecoderBuffer *buffer);
bool ParsePropertiesData(DecoderBuffer *buffer);
bool ParseElementData(DecoderBuffer *buffer, int element_index);
bool ParseElementDataAscii(DecoderBuffer *buffer, int element_index);
@@ -141,7 +143,6 @@ class PlyReader {
DataType GetDataTypeFromString(const std::string &name) const;
std::vector<PlyElement> elements_;
- std::string error_message_;
std::map<std::string, int> element_index_;
Format format_;
};
diff --git a/extern/draco/dracoenc/src/draco/io/ply_reader_test.cc b/extern/draco/dracoenc/src/draco/io/ply_reader_test.cc
index 98f9c601971..6804dc33de3 100644
--- a/extern/draco/dracoenc/src/draco/io/ply_reader_test.cc
+++ b/extern/draco/dracoenc/src/draco/io/ply_reader_test.cc
@@ -45,7 +45,8 @@ TEST_F(PlyReaderTest, TestReader) {
DecoderBuffer buf;
buf.Init(data.data(), data.size());
PlyReader reader;
- ASSERT_TRUE(reader.Read(&buf));
+ Status status = reader.Read(&buf);
+ ASSERT_TRUE(status.ok()) << status;
ASSERT_EQ(reader.num_elements(), 2);
ASSERT_EQ(reader.element(0).num_properties(), 7);
ASSERT_EQ(reader.element(1).num_properties(), 1);
@@ -68,13 +69,15 @@ TEST_F(PlyReaderTest, TestReaderAscii) {
DecoderBuffer buf;
buf.Init(data.data(), data.size());
PlyReader reader;
- ASSERT_TRUE(reader.Read(&buf));
+ Status status = reader.Read(&buf);
+ ASSERT_TRUE(status.ok()) << status;
const std::string file_name_ascii = "test_pos_color_ascii.ply";
const std::vector<char> data_ascii = ReadPlyFile(file_name_ascii);
buf.Init(data_ascii.data(), data_ascii.size());
PlyReader reader_ascii;
- ASSERT_TRUE(reader_ascii.Read(&buf));
+ status = reader_ascii.Read(&buf);
+ ASSERT_TRUE(status.ok()) << status;
ASSERT_EQ(reader.num_elements(), reader_ascii.num_elements());
ASSERT_EQ(reader.element(0).num_properties(),
reader_ascii.element(0).num_properties());
@@ -97,7 +100,8 @@ TEST_F(PlyReaderTest, TestReaderExtraWhitespace) {
DecoderBuffer buf;
buf.Init(data.data(), data.size());
PlyReader reader;
- ASSERT_TRUE(reader.Read(&buf));
+ Status status = reader.Read(&buf);
+ ASSERT_TRUE(status.ok()) << status;
ASSERT_EQ(reader.num_elements(), 2);
ASSERT_EQ(reader.element(0).num_properties(), 7);
@@ -121,7 +125,8 @@ TEST_F(PlyReaderTest, TestReaderMoreDataTypes) {
DecoderBuffer buf;
buf.Init(data.data(), data.size());
PlyReader reader;
- ASSERT_TRUE(reader.Read(&buf));
+ Status status = reader.Read(&buf);
+ ASSERT_TRUE(status.ok()) << status;
ASSERT_EQ(reader.num_elements(), 2);
ASSERT_EQ(reader.element(0).num_properties(), 7);
diff --git a/extern/draco/dracoenc/src/draco/io/point_cloud_io.cc b/extern/draco/dracoenc/src/draco/io/point_cloud_io.cc
index 068f7a139e4..e91142eaaea 100644
--- a/extern/draco/dracoenc/src/draco/io/point_cloud_io.cc
+++ b/extern/draco/dracoenc/src/draco/io/point_cloud_io.cc
@@ -40,8 +40,7 @@ StatusOr<std::unique_ptr<PointCloud>> ReadPointCloudFromFile(
if (extension == ".ply") {
// Wavefront PLY file format.
PlyDecoder ply_decoder;
- if (!ply_decoder.DecodeFromFile(file_name, pc.get()))
- return Status(Status::ERROR, "Unknown error.");
+ DRACO_RETURN_IF_ERROR(ply_decoder.DecodeFromFile(file_name, pc.get()));
return std::move(pc);
}
@@ -49,9 +48,9 @@ StatusOr<std::unique_ptr<PointCloud>> ReadPointCloudFromFile(
// draco encoding methods.
std::ifstream is(file_name.c_str(), std::ios::binary);
if (!is)
- return Status(Status::ERROR, "Invalid input stream.");
+ return Status(Status::DRACO_ERROR, "Invalid input stream.");
if (!ReadPointCloudFromStream(&pc, is).good())
- return Status(Status::ERROR,
+ return Status(Status::DRACO_ERROR,
"Unknown error."); // Error reading the stream.
return std::move(pc);
}
diff --git a/extern/draco/dracoenc/src/draco/mesh/corner_table.cc b/extern/draco/dracoenc/src/draco/mesh/corner_table.cc
index e4608fe8f9d..dcfd7967c0b 100644
--- a/extern/draco/dracoenc/src/draco/mesh/corner_table.cc
+++ b/extern/draco/dracoenc/src/draco/mesh/corner_table.cc
@@ -16,6 +16,7 @@
#include <limits>
+#include "draco/attributes/geometry_indices.h"
#include "draco/mesh/corner_table_iterators.h"
namespace draco {
@@ -46,6 +47,8 @@ bool CornerTable::Init(const IndexTypeVector<FaceIndex, FaceType> &faces) {
int num_vertices = -1;
if (!ComputeOppositeCorners(&num_vertices))
return false;
+ if (!BreakNonManifoldEdges())
+ return false;
if (!ComputeVertexCorners(num_vertices))
return false;
return true;
@@ -193,6 +196,110 @@ bool CornerTable::ComputeOppositeCorners(int *num_vertices) {
return true;
}
+bool CornerTable::BreakNonManifoldEdges() {
+ // This function detects and breaks non-manifold edges that are caused by
+ // folds in 1-ring neighborhood around a vertex. Non-manifold edges can occur
+ // when the 1-ring surface around a vertex self-intersects in a common edge.
+ // For example imagine a surface around a pivot vertex 0, where the 1-ring
+ // is defined by vertices |1, 2, 3, 1, 4|. The surface passes edge <0, 1>
+ // twice which would result in a non-manifold edge that needs to be broken.
+ // For now all faces connected to these non-manifold edges are disconnected
+ // resulting in open boundaries on the mesh. New vertices will be created
+ // automatically for each new disjoint patch in the ComputeVertexCorners()
+ // method.
+ // Note that all other non-manifold edges are implicitly handled by the
+ // function ComputeVertexCorners() that automatically creates new vertices
+ // on disjoint 1-ring surface patches.
+
+ std::vector<bool> visited_corners(num_corners(), false);
+ std::vector<std::pair<VertexIndex, CornerIndex>> sink_vertices;
+ bool mesh_connectivity_updated = false;
+ do {
+ mesh_connectivity_updated = false;
+ for (CornerIndex c(0); c < num_corners(); ++c) {
+ if (visited_corners[c.value()])
+ continue;
+ sink_vertices.clear();
+
+ // First swing all the way to find the left-most corner connected to the
+ // corner's vertex.
+ CornerIndex first_c = c;
+ CornerIndex current_c = c;
+ CornerIndex next_c;
+ while (next_c = SwingLeft(current_c),
+ next_c != first_c && next_c != kInvalidCornerIndex &&
+ !visited_corners[next_c.value()]) {
+ current_c = next_c;
+ }
+
+ first_c = current_c;
+
+ // Swing right from the first corner and check if all visited edges
+ // are unique.
+ do {
+ visited_corners[current_c.value()] = true;
+ // Each new edge is defined by the pivot vertex (that is the same for
+ // all faces) and by the sink vertex (that is the |next| vertex from the
+ // currently processed pivot corner. I.e., each edge is uniquely defined
+ // by the sink vertex index.
+ const CornerIndex sink_c = Next(current_c);
+ const VertexIndex sink_v = corner_to_vertex_map_[sink_c];
+
+ // Corner that defines the edge on the face.
+ const CornerIndex edge_corner = Previous(current_c);
+ bool vertex_connectivity_updated = false;
+ // Go over all processed edges (sink vertices). If the current sink
+ // vertex has been already encountered before it may indicate a
+ // non-manifold edge that needs to be broken.
+ for (auto &&attached_sink_vertex : sink_vertices) {
+ if (attached_sink_vertex.first == sink_v) {
+ // Sink vertex has been already processed.
+ const CornerIndex other_edge_corner = attached_sink_vertex.second;
+ const CornerIndex opp_edge_corner = Opposite(edge_corner);
+
+ if (opp_edge_corner == other_edge_corner) {
+ // We are closing the loop so no need to change the connectivity.
+ continue;
+ }
+
+ // Break the connectivity on the non-manifold edge.
+ // TODO(ostava): It may be possible to reconnect the faces in a way
+ // that the final surface would be manifold.
+ const CornerIndex opp_other_edge_corner =
+ Opposite(other_edge_corner);
+ if (opp_edge_corner != kInvalidCornerIndex)
+ SetOppositeCorner(opp_edge_corner, kInvalidCornerIndex);
+ if (opp_other_edge_corner != kInvalidCornerIndex)
+ SetOppositeCorner(opp_other_edge_corner, kInvalidCornerIndex);
+
+ SetOppositeCorner(edge_corner, kInvalidCornerIndex);
+ SetOppositeCorner(other_edge_corner, kInvalidCornerIndex);
+
+ vertex_connectivity_updated = true;
+ break;
+ }
+ }
+ if (vertex_connectivity_updated) {
+ // Because of the updated connectivity, not all corners connected to
+ // this vertex have been processed and we need to go over them again.
+ // TODO(ostava): This can be optimized as we don't really need to
+ // iterate over all corners.
+ mesh_connectivity_updated = true;
+ break;
+ }
+ // Insert new sink vertex information <sink vertex index, edge corner>.
+ std::pair<VertexIndex, CornerIndex> new_sink_vert;
+ new_sink_vert.first = corner_to_vertex_map_[Previous(current_c)];
+ new_sink_vert.second = sink_c;
+ sink_vertices.push_back(new_sink_vert);
+
+ current_c = SwingRight(current_c);
+ } while (current_c != first_c && current_c != kInvalidCornerIndex);
+ }
+ } while (mesh_connectivity_updated);
+ return true;
+}
+
bool CornerTable::ComputeVertexCorners(int num_vertices) {
DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
num_original_vertices_ = num_vertices;
diff --git a/extern/draco/dracoenc/src/draco/mesh/corner_table.h b/extern/draco/dracoenc/src/draco/mesh/corner_table.h
index b916b995f66..704a7b1b5c4 100644
--- a/extern/draco/dracoenc/src/draco/mesh/corner_table.h
+++ b/extern/draco/dracoenc/src/draco/mesh/corner_table.h
@@ -51,7 +51,6 @@ namespace draco {
// non-manifold edges and vertices are automatically split.
class CornerTable {
public:
- // TODO(hemmer): rename to Face.
// Corner table face type.
typedef std::array<VertexIndex, 3> FaceType;
@@ -333,10 +332,14 @@ class CornerTable {
private:
// Computes opposite corners mapping from the data stored in
- // |corner_to_vertex_map_|. Any non-manifold edge will be split so the result
- // is always a 2-manifold surface.
+ // |corner_to_vertex_map_|.
bool ComputeOppositeCorners(int *num_vertices);
+ // Finds and breaks non-manifold edges in the 1-ring neighborhood around
+ // vertices (vertices themselves will be split in the ComputeVertexCorners()
+ // function if necessary).
+ bool BreakNonManifoldEdges();
+
// Computes the lookup map for going from a vertex to a corner. This method
// can handle non-manifold vertices by splitting them into multiple manifold
// vertices.
diff --git a/extern/draco/dracoenc/src/draco/mesh/mesh.cc b/extern/draco/dracoenc/src/draco/mesh/mesh.cc
index dd37a88d1fa..a78a6ec96a8 100644
--- a/extern/draco/dracoenc/src/draco/mesh/mesh.cc
+++ b/extern/draco/dracoenc/src/draco/mesh/mesh.cc
@@ -27,7 +27,7 @@ using conditional_t = typename std::conditional<B, T, F>::type;
Mesh::Mesh() {}
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
void Mesh::ApplyPointIdDeduplication(
const IndexTypeVector<PointIndex, PointIndex> &id_map,
const std::vector<PointIndex> &unique_point_ids) {
diff --git a/extern/draco/dracoenc/src/draco/mesh/mesh.h b/extern/draco/dracoenc/src/draco/mesh/mesh.h
index dd41f6cde4a..b8ca5353a81 100644
--- a/extern/draco/dracoenc/src/draco/mesh/mesh.h
+++ b/extern/draco/dracoenc/src/draco/mesh/mesh.h
@@ -17,11 +17,11 @@
#include <memory>
-#include "draco/draco_features.h"
-
#include "draco/attributes/geometry_indices.h"
#include "draco/core/hash_utils.h"
#include "draco/core/macros.h"
+#include "draco/core/status.h"
+#include "draco/draco_features.h"
#include "draco/point_cloud/point_cloud.h"
namespace draco {
@@ -109,7 +109,7 @@ class Mesh : public PointCloud {
};
protected:
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
// Extends the point deduplication to face corners. This method is called from
// the PointCloud::DeduplicatePointIds() and it remaps all point ids stored in
// |faces_| to the new deduplicated point ids using the map |id_map|.
diff --git a/extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.h b/extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.h
index fc038bd7445..b972109e679 100644
--- a/extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.h
+++ b/extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.h
@@ -56,6 +56,25 @@ inline bool IsCornerOppositeToAttributeSeam(CornerIndex ci,
return false;
}
+// 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,
+ const std::array<float, 3> &barycentric_coord) {
+ const Mesh::Face &face = mesh.face(fi);
+ // Get values for all three corners of the face.
+ InterpolatedVectorT val[3];
+ for (int c = 0; c < 3; ++c) {
+ attribute.GetMappedValue(face[c], &(val[c][0]));
+ }
+ // Return an interpolated value.
+ return barycentric_coord[0] * val[0] + barycentric_coord[1] * val[1] +
+ barycentric_coord[2] * val[2];
+}
+
} // namespace draco
#endif // DRACO_MESH_MESH_MISC_FUNCTIONS_H_
diff --git a/extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.cc b/extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.cc
index a21d5e77cf7..7a76745342b 100644
--- a/extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.cc
+++ b/extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.cc
@@ -65,10 +65,12 @@ void TriangleSoupMeshBuilder::SetPerFaceAttributeValueForFace(
}
std::unique_ptr<Mesh> TriangleSoupMeshBuilder::Finalize() {
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
// First deduplicate attribute values.
if (!mesh_->DeduplicateAttributeValues())
return nullptr;
+#endif
+#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
// Also deduplicate vertex indices.
mesh_->DeduplicatePointIds();
#endif
diff --git a/extern/draco/dracoenc/src/draco/metadata/metadata.h b/extern/draco/dracoenc/src/draco/metadata/metadata.h
index b4dd202c991..bf0be36f3b1 100644
--- a/extern/draco/dracoenc/src/draco/metadata/metadata.h
+++ b/extern/draco/dracoenc/src/draco/metadata/metadata.h
@@ -18,7 +18,7 @@
#include <cstring>
#include <memory>
#include <string>
-#include <unordered_map>
+#include <map>
#include <vector>
#include "draco/core/hash_utils.h"
@@ -101,27 +101,45 @@ class Metadata {
// accessing entries of common data types. For now, developers need to know
// the type of entries they are requesting.
void AddEntryInt(const std::string &name, int32_t value);
+
+ // Returns false if Metadata does not contain an entry with a key of |name|.
+ // This function does not guarantee that entry's type is int32_t.
bool GetEntryInt(const std::string &name, int32_t *value) const;
void AddEntryIntArray(const std::string &name,
const std::vector<int32_t> &value);
+
+ // Returns false if Metadata does not contain an entry with a key of |name|.
+ // This function does not guarantee that entry's type is a vector of int32_t.
bool GetEntryIntArray(const std::string &name,
std::vector<int32_t> *value) const;
void AddEntryDouble(const std::string &name, double value);
+
+ // Returns false if Metadata does not contain an entry with a key of |name|.
+ // This function does not guarantee that entry's type is double.
bool GetEntryDouble(const std::string &name, double *value) const;
void AddEntryDoubleArray(const std::string &name,
const std::vector<double> &value);
+
+ // Returns false if Metadata does not contain an entry with a key of |name|.
+ // This function does not guarantee that entry's type is a vector of double.
bool GetEntryDoubleArray(const std::string &name,
std::vector<double> *value) const;
void AddEntryString(const std::string &name, const std::string &value);
+
+ // Returns false if Metadata does not contain an entry with a key of |name|.
+ // This function does not guarantee that entry's type is std::string.
bool GetEntryString(const std::string &name, std::string *value) const;
// Add a blob of data as an entry.
void AddEntryBinary(const std::string &name,
const std::vector<uint8_t> &value);
+
+ // Returns false if Metadata does not contain an entry with a key of |name|.
+ // This function does not guarantee that entry's type is a vector of uint8_t.
bool GetEntryBinary(const std::string &name,
std::vector<uint8_t> *value) const;
@@ -132,10 +150,10 @@ class Metadata {
void RemoveEntry(const std::string &name);
int num_entries() const { return static_cast<int>(entries_.size()); }
- const std::unordered_map<std::string, EntryValue> &entries() const {
+ const std::map<std::string, EntryValue> &entries() const {
return entries_;
}
- const std::unordered_map<std::string, std::unique_ptr<Metadata>>
+ const std::map<std::string, std::unique_ptr<Metadata>>
&sub_metadatas() const {
return sub_metadatas_;
}
@@ -160,8 +178,8 @@ class Metadata {
return itr->second.GetValue(entry_value);
}
- std::unordered_map<std::string, EntryValue> entries_;
- std::unordered_map<std::string, std::unique_ptr<Metadata>> sub_metadatas_;
+ std::map<std::string, EntryValue> entries_;
+ std::map<std::string, std::unique_ptr<Metadata>> sub_metadatas_;
friend struct MetadataHasher;
};
diff --git a/extern/draco/dracoenc/src/draco/metadata/metadata_encoder.cc b/extern/draco/dracoenc/src/draco/metadata/metadata_encoder.cc
index c98a334b003..6e85ce6f9d9 100644
--- a/extern/draco/dracoenc/src/draco/metadata/metadata_encoder.cc
+++ b/extern/draco/dracoenc/src/draco/metadata/metadata_encoder.cc
@@ -20,8 +20,7 @@ namespace draco {
bool MetadataEncoder::EncodeMetadata(EncoderBuffer *out_buffer,
const Metadata *metadata) {
- const std::unordered_map<std::string, EntryValue> &entries =
- metadata->entries();
+ const std::map<std::string, EntryValue> &entries = metadata->entries();
// Encode number of entries.
EncodeVarint(static_cast<uint32_t>(metadata->num_entries()), out_buffer);
// Encode all entries.
@@ -33,8 +32,8 @@ bool MetadataEncoder::EncodeMetadata(EncoderBuffer *out_buffer,
EncodeVarint(data_size, out_buffer);
out_buffer->Encode(entry_value.data(), data_size);
}
- const std::unordered_map<std::string, std::unique_ptr<Metadata>>
- &sub_metadatas = metadata->sub_metadatas();
+ const std::map<std::string, std::unique_ptr<Metadata>> &sub_metadatas =
+ metadata->sub_metadatas();
// Encode number of sub-metadata
EncodeVarint(static_cast<uint32_t>(sub_metadatas.size()), out_buffer);
// Encode each sub-metadata
diff --git a/extern/draco/dracoenc/src/draco/metadata/metadata_encoder_test.cc b/extern/draco/dracoenc/src/draco/metadata/metadata_encoder_test.cc
index fbda6137c39..d8f7f2f6649 100644
--- a/extern/draco/dracoenc/src/draco/metadata/metadata_encoder_test.cc
+++ b/extern/draco/dracoenc/src/draco/metadata/metadata_encoder_test.cc
@@ -75,9 +75,9 @@ class MetadataEncoderTest : public ::testing::Test {
void CheckMetadatasAreEqual(const draco::Metadata &metadata0,
const draco::Metadata &metadata1) {
ASSERT_EQ(metadata0.num_entries(), metadata1.num_entries());
- const std::unordered_map<std::string, draco::EntryValue> &entries0 =
+ const std::map<std::string, draco::EntryValue> &entries0 =
metadata0.entries();
- const std::unordered_map<std::string, draco::EntryValue> &entries1 =
+ const std::map<std::string, draco::EntryValue> &entries1 =
metadata1.entries();
for (const auto &entry : entries0) {
const std::string &entry_name = entry.first;
@@ -90,7 +90,7 @@ class MetadataEncoderTest : public ::testing::Test {
// Check nested metadata.
ASSERT_EQ(metadata0.sub_metadatas().size(),
metadata1.sub_metadatas().size());
- const std::unordered_map<std::string, std::unique_ptr<draco::Metadata>>
+ const std::map<std::string, std::unique_ptr<draco::Metadata>>
&sub_metadatas0 = metadata0.sub_metadatas();
// Encode each sub-metadata
for (auto &&sub_metadata_entry0 : sub_metadatas0) {
diff --git a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.cc b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.cc
index 63eee27417e..9552654be16 100644
--- a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.cc
+++ b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.cc
@@ -87,23 +87,32 @@ int PointCloud::AddAttribute(std::unique_ptr<PointAttribute> pa) {
int PointCloud::AddAttribute(
const GeometryAttribute &att, bool identity_mapping,
AttributeValueIndex::ValueType num_attribute_values) {
- const GeometryAttribute::Type type = att.attribute_type();
- if (type == GeometryAttribute::INVALID)
+ auto pa = CreateAttribute(att, identity_mapping, num_attribute_values);
+ if (!pa)
return -1;
- const int32_t att_id =
- AddAttribute(std::unique_ptr<PointAttribute>(new PointAttribute(att)));
+ const int32_t att_id = AddAttribute(std::move(pa));
+ return att_id;
+}
+
+std::unique_ptr<PointAttribute> PointCloud::CreateAttribute(
+ const GeometryAttribute &att, bool identity_mapping,
+ AttributeValueIndex::ValueType num_attribute_values) const {
+ if (att.attribute_type() == GeometryAttribute::INVALID)
+ return nullptr;
+ std::unique_ptr<PointAttribute> pa =
+ std::unique_ptr<PointAttribute>(new PointAttribute(att));
// Initialize point cloud specific attribute data.
if (!identity_mapping) {
// First create mapping between indices.
- attribute(att_id)->SetExplicitMapping(num_points_);
+ pa->SetExplicitMapping(num_points_);
} else {
- attribute(att_id)->SetIdentityMapping();
- attribute(att_id)->Resize(num_points_);
+ pa->SetIdentityMapping();
+ pa->Resize(num_points_);
}
if (num_attribute_values > 0) {
- attribute(att_id)->Reset(num_attribute_values);
+ pa->Reset(num_attribute_values);
}
- return att_id;
+ return pa;
}
void PointCloud::SetAttribute(int att_id, std::unique_ptr<PointAttribute> pa) {
@@ -148,7 +157,7 @@ void PointCloud::DeleteAttribute(int att_id) {
}
}
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
void PointCloud::DeduplicatePointIds() {
// Hashing function for a single vertex.
auto point_hash = [this](PointIndex p) {
@@ -214,7 +223,9 @@ void PointCloud::ApplyPointIdDeduplication(
attribute(a)->SetExplicitMapping(num_unique_points);
}
}
+#endif
+#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
bool PointCloud::DeduplicateAttributeValues() {
// Go over all attributes and create mapping between duplicate entries.
if (num_points() == 0)
diff --git a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.h b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.h
index 0ea057dcf54..e15206f17c4 100644
--- a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.h
+++ b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.h
@@ -89,10 +89,17 @@ class PointCloud {
// PointAttribute::SetPointMapEntry() method. |num_attribute_values| can be
// used to specify the number of attribute values that are going to be
// stored in the newly created attribute. Returns attribute id of the newly
- // created attribute.
+ // created attribute or -1 in case of failure.
int AddAttribute(const GeometryAttribute &att, bool identity_mapping,
AttributeValueIndex::ValueType num_attribute_values);
+ // Creates and returns a new attribute or nullptr in case of failure. This
+ // method is similar to AddAttribute(), except that it returns the new
+ // attribute instead of adding it to the point cloud.
+ std::unique_ptr<PointAttribute> CreateAttribute(
+ const GeometryAttribute &att, bool identity_mapping,
+ AttributeValueIndex::ValueType num_attribute_values) const;
+
// Assigns an attribute id to a given PointAttribute. If an attribute with
// the same attribute id already exists, it is deleted.
virtual void SetAttribute(int att_id, std::unique_ptr<PointAttribute> pa);
@@ -101,11 +108,13 @@ class PointCloud {
// attribute ids of all subsequent attributes.
virtual void DeleteAttribute(int att_id);
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
// Deduplicates all attribute values (all attribute entries with the same
// value are merged into a single entry).
virtual bool DeduplicateAttributeValues();
+#endif
+#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
// Removes duplicate point ids (two point ids are duplicate when all of their
// attributes are mapped to the same entry ids).
virtual void DeduplicatePointIds();
@@ -173,7 +182,7 @@ class PointCloud {
void set_num_points(PointIndex::ValueType num) { num_points_ = num; }
protected:
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
// Applies id mapping of deduplicated points (called by DeduplicatePointIds).
virtual void ApplyPointIdDeduplication(
const IndexTypeVector<PointIndex, PointIndex> &id_map,
diff --git a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.cc b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.cc
index 455d9a931db..a0381631cfd 100644
--- a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.cc
+++ b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.cc
@@ -61,12 +61,14 @@ void PointCloudBuilder::SetAttributeValuesForAllPoints(
std::unique_ptr<PointCloud> PointCloudBuilder::Finalize(
bool deduplicate_points) {
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
if (deduplicate_points) {
+#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
point_cloud_->DeduplicateAttributeValues();
+#endif
+#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
point_cloud_->DeduplicatePointIds();
- }
#endif
+ }
return std::move(point_cloud_);
}
diff --git a/extern/draco/dracoenc/src/draco/tools/draco_decoder.cc b/extern/draco/dracoenc/src/draco/tools/draco_decoder.cc
index d96575223d7..5b06e8caa3b 100644
--- a/extern/draco/dracoenc/src/draco/tools/draco_decoder.cc
+++ b/extern/draco/dracoenc/src/draco/tools/draco_decoder.cc
@@ -134,7 +134,7 @@ int main(int argc, char **argv) {
}
// Save the decoded geometry into a file.
- // TODO(ostava): Currently only .ply and .obj are supported.
+ // TODO(fgalligan): Change extension code to look for '.'.
const std::string extension = draco::parser::ToLower(
options.output.size() >= 4
? options.output.substr(options.output.size() - 4)
@@ -167,7 +167,9 @@ int main(int argc, char **argv) {
}
}
} else {
- printf("Invalid extension of the output file. Use either .ply or .obj\n");
+ printf(
+ "Invalid extension of the output file. Use either .ply, .obj, or "
+ ".gltf\n");
return -1;
}
printf("Decoded geometry saved to %s (%" PRId64 " ms to decode)\n",
diff --git a/extern/draco/dracoenc/src/draco/tools/draco_encoder.cc b/extern/draco/dracoenc/src/draco/tools/draco_encoder.cc
index 05458fbbdf6..e44d0939048 100644
--- a/extern/draco/dracoenc/src/draco/tools/draco_encoder.cc
+++ b/extern/draco/dracoenc/src/draco/tools/draco_encoder.cc
@@ -316,7 +316,7 @@ int main(int argc, char **argv) {
pc->GetNamedAttributeId(draco::GeometryAttribute::GENERIC, 0));
}
}
-#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
// If any attribute has been deleted, run deduplication of point indices again
// as some points can be possibly combined.
if (options.tex_coords_deleted || options.normals_deleted ||
diff --git a/extern/draco/src/draco-compressor.cpp b/extern/draco/src/draco-compressor.cpp
index 3262a2c4d4d..4ae528888fe 100644
--- a/extern/draco/src/draco-compressor.cpp
+++ b/extern/draco/src/draco-compressor.cpp
@@ -13,234 +13,147 @@
*/
/**
- * Implemententation for the Draco exporter from the C++ side.
- *
- * The python side uses the CTypes libary to open the DLL, load function
- * pointers add pass the data to the compressor as raw bytes.
- *
- * The compressor intercepts the regular GLTF exporter after data has been
- * gathered and right before the data is converted to a JSON representation,
- * which is going to be written out.
- *
- * The original uncompressed data is removed and replaces an extension,
- * pointing to the newly created buffer containing the compressed data.
- *
* @author Jim Eckerlein <eckerlein@ux3d.io>
- * @date 2019-01-15
+ * @date 2019-11-29
*/
-#include <iostream>
-#include <fstream>
+#include "draco-compressor.h"
+
#include <memory>
-#include <sstream>
+#include <vector>
#include "draco/mesh/mesh.h"
-#include "draco/point_cloud/point_cloud.h"
-#include "draco/core/vector_d.h"
-#include "draco/io/mesh_io.h"
+#include "draco/core/encoder_buffer.h"
#include "draco/compression/encode.h"
-#if defined(_MSC_VER)
-#define DLL_EXPORT(retType) extern "C" __declspec(dllexport) retType __cdecl
-#else
-#define DLL_EXPORT(retType) extern "C" retType
-#endif
-
-const char *logTag = "DRACO-COMPRESSOR";
-
/**
- * This tuple is opaquely exposed to Python through a pointer.
- * It encapsulates the complete current compressor state.
- *
- * A single instance is only intended to compress a single primitive.
+ * Prefix used for logging messages.
*/
-struct DracoCompressor {
+const char *logTag = "DRACO-COMPRESSOR";
- /**
- * All positions, normals and texture coordinates are appended to this mesh.
- */
+struct DracoCompressor {
draco::Mesh mesh;
- /**
- * One data buffer per attribute.
- */
+ // One data buffer per attribute.
std::vector<std::unique_ptr<draco::DataBuffer>> buffers;
- /**
- * The buffer the mesh is compressed into.
- */
+ // The buffer the mesh is compressed into.
draco::EncoderBuffer encoderBuffer;
- /**
- * The id Draco assigns to the position attribute.
- * Required to be reported in the GLTF file.
- */
- uint32_t positionAttributeId = (uint32_t) -1;
-
- /**
- * The id Draco assigns to the normal attribute.
- * Required to be reported in the GLTF file.
- */
- uint32_t normalAttributeId = (uint32_t) -1;
-
- /**
- * The ids Draco assigns to the texture coordinate attributes.
- * Required to be reported in the GLTF file.
- */
- std::vector<uint32_t> texCoordAttributeIds;
-
- /**
- * Level of compression [0-10].
- * Higher values mean slower encoding.
- */
+ // Level of compression [0-10].
+ // Higher values mean slower encoding.
uint32_t compressionLevel = 7;
- uint32_t quantizationBitsPosition = 14;
- uint32_t quantizationBitsNormal = 10;
- uint32_t quantizationBitsTexCoord = 12;
+ struct {
+ uint32_t positions = 14;
+ uint32_t normals = 10;
+ uint32_t uvs = 12;
+ uint32_t generic = 12;
+ } quantization;
};
-draco::GeometryAttribute createAttribute(
- draco::GeometryAttribute::Type type,
- draco::DataBuffer &buffer,
- uint8_t components
-) {
- draco::GeometryAttribute attribute;
- attribute.Init(
- type,
- &buffer,
- components,
- draco::DataType::DT_FLOAT32,
- false,
- sizeof(float) * components,
- 0
- );
- return attribute;
-}
-
-DLL_EXPORT(DracoCompressor *) createCompressor() {
+DracoCompressor *create_compressor() {
return new DracoCompressor;
}
-DLL_EXPORT(void) setCompressionLevel(
- DracoCompressor *compressor,
- uint32_t compressionLevel
+void set_compression_level(
+ DracoCompressor *const compressor,
+ uint32_t const compressionLevel
) {
compressor->compressionLevel = compressionLevel;
}
-DLL_EXPORT(void) setPositionQuantizationBits(
- DracoCompressor *compressor,
- uint32_t quantizationBitsPosition
+void set_position_quantization(
+ DracoCompressor *const compressor,
+ uint32_t const quantizationBitsPosition
) {
- compressor->quantizationBitsPosition = quantizationBitsPosition;
+ compressor->quantization.positions = quantizationBitsPosition;
}
-DLL_EXPORT(void) setNormalQuantizationBits(
- DracoCompressor *compressor,
- uint32_t quantizationBitsNormal
+void set_normal_quantization(
+ DracoCompressor *const compressor,
+ uint32_t const quantizationBitsNormal
) {
- compressor->quantizationBitsNormal = quantizationBitsNormal;
+ compressor->quantization.normals = quantizationBitsNormal;
}
-DLL_EXPORT(void) setTexCoordQuantizationBits(
- DracoCompressor *compressor,
- uint32_t quantizationBitsTexCoord
+void set_uv_quantization(
+ DracoCompressor *const compressor,
+ uint32_t const quantizationBitsTexCoord
) {
- compressor->quantizationBitsTexCoord = quantizationBitsTexCoord;
+ compressor->quantization.uvs = quantizationBitsTexCoord;
}
-DLL_EXPORT(bool) compress(
- DracoCompressor *compressor
+void set_generic_quantization(
+ DracoCompressor *const compressor,
+ uint32_t const bits
) {
- printf("%s: Compressing primitive:\n", logTag);
- printf("%s: Compression level [0-10]: %d\n", logTag, compressor->compressionLevel);
- printf("%s: Position quantization bits: %d\n", logTag, compressor->quantizationBitsPosition);
- printf("%s: Normal quantization bits: %d\n", logTag, compressor->quantizationBitsNormal);
- printf("%s: Position quantization bits: %d\n", logTag, compressor->quantizationBitsTexCoord);
+ compressor->quantization.generic = bits;
+}
+bool compress(
+ DracoCompressor *const compressor
+) {
draco::Encoder encoder;
- encoder.SetSpeedOptions(10 - compressor->compressionLevel, 10 - compressor->compressionLevel);
- encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, compressor->quantizationBitsPosition);
- encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, compressor->quantizationBitsNormal);
- encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, compressor->quantizationBitsTexCoord);
-
- draco::Status result = encoder.EncodeMeshToBuffer(compressor->mesh, &compressor->encoderBuffer);
+ encoder.SetSpeedOptions(10 - (int)compressor->compressionLevel, 10 - (int)compressor->compressionLevel);
+ encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, compressor->quantization.positions);
+ encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, compressor->quantization.normals);
+ encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, compressor->quantization.uvs);
+ encoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, compressor->quantization.generic);
- if(!result.ok()) {
- printf("%s: Could not compress mesh: %s\n", logTag, result.error_msg());
- return false;
- }
- else {
- return true;
- }
+ return encoder.EncodeMeshToBuffer(compressor->mesh, &compressor->encoderBuffer).ok();
}
-/**
- * Returns the size of the compressed data in bytes.
- */
-DLL_EXPORT(uint64_t) compressedSize(
- DracoCompressor *compressor
+bool compress_morphed(
+ DracoCompressor *const compressor
) {
- return compressor->encoderBuffer.size();
-}
+ draco::Encoder encoder;
-/**
- * Copies the compressed mesh into the given byte buffer.
- * @param[o_data] A Python `bytes` object.
- *
- */
-DLL_EXPORT(void) copyToBytes(
- DracoCompressor *compressor,
- uint8_t *o_data
-) {
- memcpy(o_data, compressor->encoderBuffer.data(), compressedSize(compressor));
-}
+ encoder.SetSpeedOptions(10 - (int)compressor->compressionLevel, 10 - (int)compressor->compressionLevel);
-DLL_EXPORT(uint32_t) getPositionAttributeId(
- DracoCompressor *compressor
-) {
- return compressor->positionAttributeId;
-}
+ // For some reason, `EncodeMeshToBuffer` crashes when not disabling prediction or when enabling quantization
+ // for attributes other position.
+ encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, compressor->quantization.positions);
+ encoder.SetAttributePredictionScheme(draco::GeometryAttribute::POSITION, draco::PREDICTION_NONE);
+ encoder.SetAttributePredictionScheme(draco::GeometryAttribute::NORMAL, draco::PREDICTION_NONE);
+ encoder.SetAttributePredictionScheme(draco::GeometryAttribute::TEX_COORD, draco::PREDICTION_NONE);
+ encoder.SetAttributePredictionScheme(draco::GeometryAttribute::GENERIC, draco::PREDICTION_NONE);
-DLL_EXPORT(uint32_t) getNormalAttributeId(
- DracoCompressor *compressor
-) {
- return compressor->normalAttributeId;
+ // Enforce triangle order preservation.
+ encoder.SetEncodingMethod(draco::MESH_SEQUENTIAL_ENCODING);
+
+ return encoder.EncodeMeshToBuffer(compressor->mesh, &compressor->encoderBuffer).ok();
}
-DLL_EXPORT(uint32_t) getTexCoordAttributeIdCount(
- DracoCompressor *compressor
+uint64_t get_compressed_size(
+ DracoCompressor const *const compressor
) {
- return (uint32_t) compressor->texCoordAttributeIds.size();
+ return compressor->encoderBuffer.size();
}
-DLL_EXPORT(uint32_t) getTexCoordAttributeId(
- DracoCompressor *compressor,
- uint32_t index
+void copy_to_bytes(
+ DracoCompressor const *const compressor,
+ uint8_t *const o_data
) {
- return compressor->texCoordAttributeIds[index];
+ memcpy(o_data, compressor->encoderBuffer.data(), compressor->encoderBuffer.size());
}
-/**
- * Releases all memory allocated by the compressor.
- */
-DLL_EXPORT(void) disposeCompressor(
- DracoCompressor *compressor
+void destroy_compressor(
+ DracoCompressor *const compressor
) {
delete compressor;
}
template<class T>
-void setFaces(
- draco::Mesh &mesh,
- int numIndices,
- T *indices
+void set_faces_impl(
+ draco::Mesh &mesh,
+ int const index_count,
+ T const *const indices
) {
- mesh.SetNumFaces((size_t) numIndices / 3);
+ mesh.SetNumFaces((size_t) index_count / 3);
- for (int i = 0; i < numIndices; i += 3)
+ for (int i = 0; i < index_count; i += 3)
{
const auto a = draco::PointIndex(indices[i]);
const auto b = draco::PointIndex(indices[i + 1]);
@@ -249,97 +162,116 @@ void setFaces(
}
}
-DLL_EXPORT(void) setFaces(
- DracoCompressor *compressor,
- uint32_t numIndices,
- uint32_t bytesPerIndex,
- void *indices
+void set_faces(
+ DracoCompressor *const compressor,
+ uint32_t const index_count,
+ uint32_t const index_byte_length,
+ uint8_t const *const indices
) {
- switch (bytesPerIndex)
+ switch (index_byte_length)
{
case 1:
{
- setFaces(compressor->mesh, numIndices, (uint8_t *) indices);
+ set_faces_impl(compressor->mesh, index_count, (uint8_t *) indices);
break;
}
case 2:
{
- setFaces(compressor->mesh, numIndices, (uint16_t *) indices);
+ set_faces_impl(compressor->mesh, index_count, (uint16_t *) indices);
break;
}
case 4:
{
- setFaces(compressor->mesh, numIndices, (uint32_t *) indices);
+ set_faces_impl(compressor->mesh, index_count, (uint32_t *) indices);
break;
}
default:
{
- printf("%s: Unsupported index size %d\n", logTag, bytesPerIndex);
+ printf("%s: Unsupported index size %d\n", logTag, index_byte_length);
break;
}
}
}
-void addFloatAttribute(
- DracoCompressor *compressor,
- draco::GeometryAttribute::Type type,
- uint32_t count,
- uint8_t componentCount,
- float *source
+uint32_t add_attribute_to_mesh(
+ DracoCompressor *const compressor,
+ draco::GeometryAttribute::Type const semantics,
+ draco::DataType const data_type,
+ uint32_t const count,
+ uint8_t const component_count,
+ uint8_t const component_size,
+ uint8_t const *const data
) {
auto buffer = std::make_unique<draco::DataBuffer>();
- const auto attribute = createAttribute(type, *buffer, componentCount);
+ draco::GeometryAttribute attribute;
- const auto id = (const uint32_t) compressor->mesh.AddAttribute(attribute, false, count);
- compressor->mesh.attribute(id)->SetIdentityMapping();
+ attribute.Init(
+ semantics,
+ &*buffer,
+ component_count,
+ data_type,
+ false,
+ component_size * component_count,
+ 0
+ );
- switch (type)
- {
- case draco::GeometryAttribute::POSITION:
- compressor->positionAttributeId = id;
- break;
- case draco::GeometryAttribute::NORMAL:
- compressor->normalAttributeId = id;
- break;
- case draco::GeometryAttribute::TEX_COORD:
- compressor->texCoordAttributeIds.push_back(id);
- break;
- default:
- break;
- }
+ auto const id = (uint32_t)compressor->mesh.AddAttribute(attribute, true, count);
for (uint32_t i = 0; i < count; i++)
{
compressor->mesh.attribute(id)->SetAttributeValue(
- draco::AttributeValueIndex(i),
- source + i * componentCount
+ draco::AttributeValueIndex(i),
+ data + i * component_count * component_size
);
}
compressor->buffers.emplace_back(std::move(buffer));
+
+ return id;
+}
+
+uint32_t add_positions_f32(
+ DracoCompressor *const compressor,
+ uint32_t const count,
+ uint8_t const *const data
+) {
+ return add_attribute_to_mesh(compressor, draco::GeometryAttribute::POSITION,
+ draco::DT_FLOAT32, count, 3, sizeof(float), data);
+}
+
+uint32_t add_normals_f32(
+ DracoCompressor *const compressor,
+ uint32_t const count,
+ uint8_t const *const data
+) {
+ return add_attribute_to_mesh(compressor, draco::GeometryAttribute::NORMAL,
+ draco::DT_FLOAT32, count, 3, sizeof(float), data);
}
-DLL_EXPORT(void) addPositionAttribute(
- DracoCompressor *compressor,
- uint32_t count,
- float *source
+uint32_t add_uvs_f32(
+ DracoCompressor *const compressor,
+ uint32_t const count,
+ uint8_t const *const data
) {
- addFloatAttribute(compressor, draco::GeometryAttribute::POSITION, count, 3, source);
+ return add_attribute_to_mesh(compressor, draco::GeometryAttribute::TEX_COORD,
+ draco::DT_FLOAT32, count, 2, sizeof(float), data);
}
-DLL_EXPORT(void) addNormalAttribute(
- DracoCompressor *compressor,
- uint32_t count,
- float *source
+uint32_t add_joints_u16(
+ DracoCompressor *compressor,
+ uint32_t const count,
+ uint8_t const *const data
) {
- addFloatAttribute(compressor, draco::GeometryAttribute::NORMAL, count, 3, source);
+ return add_attribute_to_mesh(compressor, draco::GeometryAttribute::GENERIC,
+ draco::DT_UINT16, count, 4, sizeof(uint16_t), data);
}
-DLL_EXPORT(void) addTexCoordAttribute(
- DracoCompressor *compressor,
- uint32_t count,
- float *source
+uint32_t add_weights_f32(
+ DracoCompressor *compressor,
+ uint32_t const count,
+ uint8_t const *const data
) {
- addFloatAttribute(compressor, draco::GeometryAttribute::TEX_COORD, count, 2, source);
+ return add_attribute_to_mesh(compressor, draco::GeometryAttribute::GENERIC,
+ draco::DT_FLOAT32, count, 4, sizeof(float), data);
}
diff --git a/extern/draco/src/draco-compressor.h b/extern/draco/src/draco-compressor.h
new file mode 100644
index 00000000000..fb6168a61af
--- /dev/null
+++ b/extern/draco/src/draco-compressor.h
@@ -0,0 +1,173 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * C++ library for the Draco compression feature inside the glTF-Blender-IO project.
+ *
+ * The python side uses the CTypes library to open the DLL, load function
+ * pointers add pass the data to the compressor as raw bytes.
+ *
+ * The compressor intercepts the regular glTF exporter after data has been
+ * gathered and right before the data is converted to a JSON representation,
+ * which is going to be written out.
+ *
+ * The original uncompressed data is removed and replaces an extension,
+ * pointing to the newly created buffer containing the compressed data.
+ *
+ * @author Jim Eckerlein <eckerlein@ux3d.io>
+ * @date 2019-11-29
+ */
+
+#include <cstdint>
+
+#if defined(_MSC_VER)
+#define DLL_EXPORT(retType) extern "C" __declspec(dllexport) retType __cdecl
+#else
+#define DLL_EXPORT(retType) extern "C" retType
+#endif
+
+/**
+ * This tuple is opaquely exposed to Python through a pointer.
+ * It encapsulates the complete current compressor state.
+ *
+ * A single instance is only intended to compress a single primitive.
+ */
+struct DracoCompressor;
+
+DLL_EXPORT(DracoCompressor *)
+create_compressor ();
+
+DLL_EXPORT(void)
+set_compression_level (
+ DracoCompressor *compressor,
+ uint32_t compressionLevel
+);
+
+DLL_EXPORT(void)
+set_position_quantization (
+ DracoCompressor *compressor,
+ uint32_t quantizationBitsPosition
+);
+
+DLL_EXPORT(void)
+set_normal_quantization (
+ DracoCompressor *compressor,
+ uint32_t quantizationBitsNormal
+);
+
+DLL_EXPORT(void)
+set_uv_quantization (
+ DracoCompressor *compressor,
+ uint32_t quantizationBitsTexCoord
+);
+
+DLL_EXPORT(void)
+set_generic_quantization (
+ DracoCompressor *compressor,
+ uint32_t bits
+);
+
+/// Compresses a mesh.
+/// Use `compress_morphed` when compressing primitives which have morph targets.
+DLL_EXPORT(bool)
+compress (
+ DracoCompressor *compressor
+);
+
+/// Compresses the mesh.
+/// Use this instead of `compress`, because this procedure takes into account that mesh triangles must not be reordered.
+DLL_EXPORT(bool)
+compress_morphed (
+ DracoCompressor *compressor
+);
+
+/**
+ * Returns the size of the compressed data in bytes.
+ */
+DLL_EXPORT(uint64_t)
+get_compressed_size (
+ DracoCompressor const *compressor
+);
+
+/**
+ * Copies the compressed mesh into the given byte buffer.
+ *
+ * @param[o_data] A Python `bytes` object.
+ */
+DLL_EXPORT(void)
+copy_to_bytes (
+ DracoCompressor const *compressor,
+ uint8_t *o_data
+);
+
+/**
+ * Releases all memory allocated by the compressor.
+ */
+DLL_EXPORT(void)
+destroy_compressor (
+ DracoCompressor *compressor
+);
+
+DLL_EXPORT(void)
+set_faces (
+ DracoCompressor *compressor,
+ uint32_t index_count,
+ uint32_t index_byte_length,
+ uint8_t const *indices
+);
+
+/// Adds a `float` position attribute to the current mesh.
+/// Returns the id Draco has assigned to this attribute.
+DLL_EXPORT(uint32_t)
+add_positions_f32 (
+ DracoCompressor *compressor,
+ uint32_t count,
+ uint8_t const *data
+);
+
+/// Adds a `float` normal attribute to the current mesh.
+/// Returns the id Draco has assigned to this attribute.
+DLL_EXPORT(uint32_t)
+add_normals_f32 (
+ DracoCompressor *compressor,
+ uint32_t count,
+ uint8_t const *data
+);
+
+/// Adds a `float` texture coordinate attribute to the current mesh.
+/// Returns the id Draco has assigned to this attribute.
+DLL_EXPORT(uint32_t)
+add_uvs_f32 (
+ DracoCompressor *compressor,
+ uint32_t count,
+ uint8_t const *data
+);
+
+/// Adds a `unsigned short` joint attribute to the current mesh.
+/// Returns the id Draco has assigned to this attribute.
+DLL_EXPORT(uint32_t)
+add_joints_u16 (
+ DracoCompressor *compressor,
+ uint32_t count,
+ uint8_t const *data
+);
+
+/// Adds a `float` weight attribute to the current mesh.
+/// Returns the id Draco has assigned to this attribute.
+DLL_EXPORT(uint32_t)
+add_weights_f32 (
+ DracoCompressor *compressor,
+ uint32_t count,
+ uint8_t const *data
+);
diff --git a/extern/mantaflow/CMakeLists.txt b/extern/mantaflow/CMakeLists.txt
new file mode 100644
index 00000000000..f4eefbb4d04
--- /dev/null
+++ b/extern/mantaflow/CMakeLists.txt
@@ -0,0 +1,211 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2016, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Sebastian Barschkis (sebbas)
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# Mantaflow triggers a clang-cl compiler error with versions before 9.0.1
+# Since mantaflow does not appear to be using OpenMP at this point in time,
+# disable the flag for now. See https://bugs.llvm.org/show_bug.cgi?id=43175 for details.
+
+if(MSVC_CLANG AND WITH_OPENMP AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.1")
+ remove_cc_flag("-fopenmp")
+endif()
+
+set(MANTAVERSION "0.12")
+
+add_definitions(-DWITH_FLUID=1)
+
+set(MANTA_DEP
+ dependencies
+)
+set(MANTA_HLP
+ helper
+)
+set(MANTA_PP
+ preprocessed
+)
+
+if(WITH_TBB)
+ add_definitions(-DTBB=1)
+endif()
+
+if(WITH_OPENVDB)
+ add_definitions(-DOPENVDB=1)
+endif()
+
+set(INC
+ ${MANTA_PP}
+ ${MANTA_PP}/fileio
+ ${MANTA_PP}/python
+ ${MANTA_PP}/plugin
+ ${MANTA_HLP}/pwrapper
+ ${MANTA_HLP}/util
+ ${MANTA_DEP}/cnpy
+)
+
+set(INC_SYS
+ ${PYTHON_INCLUDE_DIRS}
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+if(WITH_TBB)
+ list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+ )
+endif()
+
+if(WITH_OPENVDB)
+ list(APPEND INC_SYS
+ ${BOOST_INCLUDE_DIR}
+ ${OPENEXR_INCLUDE_DIRS}
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+endif()
+
+set(SRC
+ ${MANTA_DEP}/cnpy/cnpy.cpp
+ ${MANTA_DEP}/cnpy/cnpy.h
+
+ ${MANTA_PP}/commonkernels.h
+ ${MANTA_PP}/commonkernels.h.reg.cpp
+ ${MANTA_PP}/conjugategrad.cpp
+ ${MANTA_PP}/conjugategrad.h
+ ${MANTA_PP}/conjugategrad.h.reg.cpp
+ ${MANTA_PP}/edgecollapse.cpp
+ ${MANTA_PP}/edgecollapse.h
+ ${MANTA_PP}/edgecollapse.h.reg.cpp
+ ${MANTA_PP}/fastmarch.cpp
+ ${MANTA_PP}/fastmarch.h
+ ${MANTA_PP}/fastmarch.h.reg.cpp
+ ${MANTA_PP}/fileio/iogrids.cpp
+ ${MANTA_PP}/fileio/iomeshes.cpp
+ ${MANTA_PP}/fileio/ioparticles.cpp
+ ${MANTA_PP}/fileio/mantaio.h
+ ${MANTA_PP}/fileio/mantaio.h.reg.cpp
+ ${MANTA_PP}/fluidsolver.cpp
+ ${MANTA_PP}/fluidsolver.h
+ ${MANTA_PP}/fluidsolver.h.reg.cpp
+ ${MANTA_PP}/general.cpp
+ ${MANTA_PP}/general.h
+ ${MANTA_PP}/general.h.reg.cpp
+ ${MANTA_PP}/gitinfo.h
+ ${MANTA_PP}/grid.cpp
+ ${MANTA_PP}/grid.h
+ ${MANTA_PP}/grid.h.reg.cpp
+ ${MANTA_PP}/grid4d.cpp
+ ${MANTA_PP}/grid4d.h
+ ${MANTA_PP}/grid4d.h.reg.cpp
+ ${MANTA_PP}/kernel.cpp
+ ${MANTA_PP}/kernel.h
+ ${MANTA_PP}/kernel.h.reg.cpp
+ ${MANTA_PP}/levelset.cpp
+ ${MANTA_PP}/levelset.h
+ ${MANTA_PP}/levelset.h.reg.cpp
+ ${MANTA_PP}/mesh.cpp
+ ${MANTA_PP}/mesh.h
+ ${MANTA_PP}/mesh.h.reg.cpp
+ ${MANTA_PP}/movingobs.cpp
+ ${MANTA_PP}/movingobs.h
+ ${MANTA_PP}/movingobs.h.reg.cpp
+ ${MANTA_PP}/multigrid.cpp
+ ${MANTA_PP}/multigrid.h
+ ${MANTA_PP}/multigrid.h.reg.cpp
+ ${MANTA_PP}/noisefield.cpp
+ ${MANTA_PP}/noisefield.h
+ ${MANTA_PP}/noisefield.h.reg.cpp
+ ${MANTA_PP}/particle.cpp
+ ${MANTA_PP}/particle.h
+ ${MANTA_PP}/particle.h.reg.cpp
+ ${MANTA_PP}/plugin/advection.cpp
+ ${MANTA_PP}/plugin/apic.cpp
+ ${MANTA_PP}/plugin/extforces.cpp
+ ${MANTA_PP}/plugin/fire.cpp
+ ${MANTA_PP}/plugin/flip.cpp
+ ${MANTA_PP}/plugin/fluidguiding.cpp
+ ${MANTA_PP}/plugin/initplugins.cpp
+ ${MANTA_PP}/plugin/kepsilon.cpp
+ ${MANTA_PP}/plugin/meshplugins.cpp
+# TODO (sebbas): add numpy to libraries
+# ${MANTA_PP}/plugin/numpyconvert.cpp
+ ${MANTA_PP}/plugin/pressure.cpp
+ ${MANTA_PP}/plugin/ptsplugins.cpp
+ ${MANTA_PP}/plugin/secondaryparticles.cpp
+ ${MANTA_PP}/plugin/surfaceturbulence.cpp
+# TODO (sebbas): add numpy to libraries
+# ${MANTA_PP}/plugin/tfplugins.cpp
+ ${MANTA_PP}/plugin/vortexplugins.cpp
+ ${MANTA_PP}/plugin/waveletturbulence.cpp
+ ${MANTA_PP}/plugin/waves.cpp
+ ${MANTA_PP}/python/defines.py
+ ${MANTA_PP}/python/defines.py.reg.cpp
+ ${MANTA_PP}/registration.cpp
+ ${MANTA_PP}/shapes.cpp
+ ${MANTA_PP}/shapes.h
+ ${MANTA_PP}/shapes.h.reg.cpp
+ ${MANTA_PP}/test.cpp
+ ${MANTA_PP}/timing.cpp
+ ${MANTA_PP}/timing.h
+ ${MANTA_PP}/timing.h.reg.cpp
+ ${MANTA_PP}/turbulencepart.cpp
+ ${MANTA_PP}/turbulencepart.h
+ ${MANTA_PP}/turbulencepart.h.reg.cpp
+ ${MANTA_PP}/vortexpart.cpp
+ ${MANTA_PP}/vortexpart.h
+ ${MANTA_PP}/vortexpart.h.reg.cpp
+ ${MANTA_PP}/vortexsheet.cpp
+ ${MANTA_PP}/vortexsheet.h
+ ${MANTA_PP}/vortexsheet.h.reg.cpp
+
+ ${MANTA_HLP}/pwrapper/manta.h
+# TODO (sebbas): add numpy to libraries
+# ${MANTA_HLP}/pwrapper/numpyWrap.cpp
+# ${MANTA_HLP}/pwrapper/numpyWrap.h
+ ${MANTA_HLP}/pwrapper/pclass.cpp
+ ${MANTA_HLP}/pwrapper/pclass.h
+ ${MANTA_HLP}/pwrapper/pconvert.cpp
+ ${MANTA_HLP}/pwrapper/pconvert.h
+ ${MANTA_HLP}/pwrapper/pvec3.cpp
+ ${MANTA_HLP}/pwrapper/pythonInclude.h
+ ${MANTA_HLP}/pwrapper/registry.cpp
+ ${MANTA_HLP}/pwrapper/registry.h
+ ${MANTA_HLP}/util/integrator.h
+ ${MANTA_HLP}/util/interpol.h
+ ${MANTA_HLP}/util/interpolHigh.h
+ ${MANTA_HLP}/util/matrixbase.h
+ ${MANTA_HLP}/util/mcubes.h
+ ${MANTA_HLP}/util/quaternion.h
+ ${MANTA_HLP}/util/randomstream.h
+ ${MANTA_HLP}/util/rcmatrix.h
+ ${MANTA_HLP}/util/simpleimage.cpp
+ ${MANTA_HLP}/util/simpleimage.h
+ ${MANTA_HLP}/util/solvana.h
+ ${MANTA_HLP}/util/vector4d.cpp
+ ${MANTA_HLP}/util/vector4d.h
+ ${MANTA_HLP}/util/vectorbase.cpp
+ ${MANTA_HLP}/util/vectorbase.h
+)
+
+set(LIB
+)
+
+blender_add_lib(extern_mantaflow "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/extern/mantaflow/LICENSE b/extern/mantaflow/LICENSE
new file mode 100644
index 00000000000..a5e3b509f7d
--- /dev/null
+++ b/extern/mantaflow/LICENSE
@@ -0,0 +1,222 @@
+
+Copyright 2018, the mantaflow team. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------------
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+-------------------------------------------------------------------------
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+------------------------------------------------------------------------------
+
+APPENDIX: HOW TO APPLY THE APACHE LICENSE TO YOUR WORK
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "[]" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification
+within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
diff --git a/extern/mantaflow/README.md b/extern/mantaflow/README.md
new file mode 100644
index 00000000000..d5753d07689
--- /dev/null
+++ b/extern/mantaflow/README.md
@@ -0,0 +1,11 @@
+# Mantaflow #
+
+Mantaflow is an open-source framework targeted at fluid simulation research in Computer Graphics.
+Its parallelized C++ solver core, python scene definition interface and plugin system allow for quickly prototyping and testing new algorithms.
+
+In addition, it provides a toolbox of examples for deep learning experiments with fluids. E.g., it contains examples
+how to build convolutional neural network setups in conjunction with the [tensorflow framework](https://www.tensorflow.org).
+
+For more information on how to install, run and code with Mantaflow, please head over to our home page at
+[http://mantaflow.com](http://mantaflow.com)
+
diff --git a/extern/mantaflow/UPDATE.sh b/extern/mantaflow/UPDATE.sh
new file mode 100644
index 00000000000..28d96cdf6d8
--- /dev/null
+++ b/extern/mantaflow/UPDATE.sh
@@ -0,0 +1,102 @@
+#!/bin/bash
+#
+# ========================================================================================
+# UPDATING MANTAFLOW INSIDE BLENDER
+# ========================================================================================
+
+# ==================== 1) ENVIRONMENT SETUP =============================================
+
+# YOUR INSTALLATION PATHS GO HERE:
+MANTA_INSTALLATION=/Users/sebbas/Developer/Mantaflow/mantaflowDevelop
+BLENDER_INSTALLATION=/Users/sebbas/Developer/Blender/fluid-mantaflow
+
+# Try to check out Mantaflow repository before building?
+CLEAN_REPOSITORY=0
+
+# Choose which multithreading platform to use for Mantaflow preprocessing
+USE_OMP=0
+USE_TBB=1
+
+if [[ "$USE_OMP" -eq "1" && "$USE_TBB" -eq "1" ]]; then
+ echo "Cannot build Mantaflow for OpenMP and TBB at the same time"
+ exit 1
+elif [[ "$USE_OMP" -eq "0" && "$USE_TBB" -eq "0" ]]; then
+ echo "WARNING: Building Mantaflow without multithreading"
+else
+ if [[ "$USE_OMP" -eq "1" ]]; then
+ echo "Building Mantaflow with OpenMP multithreading"
+ elif [[ "$USE_TBB" -eq "1" ]]; then
+ echo "Building Mantaflow with TBB multithreading"
+ fi
+fi
+
+# ==================== 2) BUILD MANTAFLOW ================================================
+
+# For OpenMP, we need non-default compiler to build Mantaflow on OSX
+if [[ "$USE_OMP" -eq "1" && "$OSTYPE" == "darwin"* ]]; then
+ export CC=/usr/local/opt/llvm/bin/clang
+ export CXX=/usr/local/opt/llvm/bin/clang++
+ export LDFLAGS=-L/usr/local/opt/llvm/lib
+fi
+
+cd $MANTA_INSTALLATION
+
+# Check-out manta repo from git?
+if [[ "$CLEAN_REPOSITORY" -eq "1" ]]; then
+ if cd mantaflowgit/; then git pull; else git clone git@bitbucket.org:thunil/mantaflowgit.git; cd mantaflowgit; fi
+ git checkout develop
+fi
+
+MANTA_BUILD_PATH=$MANTA_INSTALLATION/mantaflowgit/build_blender/
+mkdir -p $MANTA_BUILD_PATH
+cd $MANTA_BUILD_PATH
+cmake .. -DGUI=OFF -DOPENMP=$USE_OMP -DTBB=$USE_TBB -DBLENDER=ON -DPREPDEBUG=ON && make -j8
+
+# ==================== 3) COPY MANTAFLOW FILES TO BLENDER ROOT ===========================
+
+mkdir -p $BLENDER_INSTALLATION/blender/tmp/dependencies/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/dependencies/cnpy "$_"
+mkdir -p $BLENDER_INSTALLATION/blender/tmp/helper/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/source/util "$_"
+mkdir -p $BLENDER_INSTALLATION/blender/tmp/helper/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/source/pwrapper "$_"
+mkdir -p $BLENDER_INSTALLATION/blender/tmp/preprocessed/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/build_blender/pp/source/. "$_"
+
+# Remove some files that are not need in Blender
+rm $BLENDER_INSTALLATION/blender/tmp/dependencies/cnpy/example1.cpp
+rm $BLENDER_INSTALLATION/blender/tmp/helper/pwrapper/pymain.cpp
+rm $BLENDER_INSTALLATION/blender/tmp/preprocessed/*.reg
+rm $BLENDER_INSTALLATION/blender/tmp/preprocessed/python/*.reg
+rm $BLENDER_INSTALLATION/blender/tmp/preprocessed/fileio/*.reg
+
+# ==================== 4) CLANG-FORMAT ===================================================
+
+cd $BLENDER_INSTALLATION/blender/tmp/
+
+echo "Applying clang format to Mantaflow source files"
+find . -iname *.h -o -iname *.cpp | xargs clang-format --verbose -i -style=file
+find . -iname *.h -o -iname *.cpp | xargs dos2unix --verbose
+
+# ==================== 5) MOVE MANTAFLOW FILES TO EXTERN/ ================================
+
+BLENDER_MANTA_EXTERN=$BLENDER_INSTALLATION/blender/extern/mantaflow/
+BLENDER_TMP=$BLENDER_INSTALLATION/blender/tmp
+BLENDER_TMP_DEP=$BLENDER_TMP/dependencies
+BLENDER_TMP_HLP=$BLENDER_TMP/helper
+BLENDER_TMP_PP=$BLENDER_TMP/preprocessed
+
+# Move files from tmp dir to extern/
+cp -Rf $BLENDER_TMP_DEP $BLENDER_MANTA_EXTERN
+cp -Rf $BLENDER_TMP_HLP $BLENDER_MANTA_EXTERN
+cp -Rf $BLENDER_TMP_PP $BLENDER_MANTA_EXTERN
+
+# Copy the Mantaflow license and readme files as well
+cp -Rf $MANTA_INSTALLATION/mantaflowgit/LICENSE $BLENDER_MANTA_EXTERN
+cp -Rf $MANTA_INSTALLATION/mantaflowgit/README.md $BLENDER_MANTA_EXTERN
+
+# Cleanup left over dir
+rm -r $BLENDER_TMP
+
+echo "Successfully copied new Mantaflow files to" $BLENDER_INSTALLATION/blender/extern/mantaflow/
+
+# ==================== 6) CHECK CMAKE SETUP ==============================================
+
+# Make sure that all files copied from Mantaflow are listed in intern/mantaflow/CMakeLists.txt
+# Especially if new source files / plugins were added to Mantaflow.
diff --git a/extern/mantaflow/dependencies/cnpy/LICENSE b/extern/mantaflow/dependencies/cnpy/LICENSE
new file mode 100644
index 00000000000..e60eadbccb3
--- /dev/null
+++ b/extern/mantaflow/dependencies/cnpy/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) Carl Rogers, 2011
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/extern/mantaflow/dependencies/cnpy/cnpy.cpp b/extern/mantaflow/dependencies/cnpy/cnpy.cpp
new file mode 100644
index 00000000000..7f0ce21ece8
--- /dev/null
+++ b/extern/mantaflow/dependencies/cnpy/cnpy.cpp
@@ -0,0 +1,385 @@
+// Copyright (C) 2011 Carl Rogers
+// Released under MIT License
+// license available in LICENSE file, or at http://www.opensource.org/licenses/mit-license.php
+
+#include "cnpy.h"
+#include <complex>
+#include <cstdlib>
+#include <algorithm>
+#include <cstring>
+#include <iomanip>
+#include <stdint.h>
+#include <stdexcept>
+#include <regex>
+
+char cnpy::BigEndianTest()
+{
+ int x = 1;
+ return (((char *)&x)[0]) ? '<' : '>';
+}
+
+char cnpy::map_type(const std::type_info &t)
+{
+ if (t == typeid(float))
+ return 'f';
+ if (t == typeid(double))
+ return 'f';
+ if (t == typeid(long double))
+ return 'f';
+
+ if (t == typeid(int))
+ return 'i';
+ if (t == typeid(char))
+ return 'i';
+ if (t == typeid(short))
+ return 'i';
+ if (t == typeid(long))
+ return 'i';
+ if (t == typeid(long long))
+ return 'i';
+
+ if (t == typeid(unsigned char))
+ return 'u';
+ if (t == typeid(unsigned short))
+ return 'u';
+ if (t == typeid(unsigned long))
+ return 'u';
+ if (t == typeid(unsigned long long))
+ return 'u';
+ if (t == typeid(unsigned int))
+ return 'u';
+
+ if (t == typeid(bool))
+ return 'b';
+
+ if (t == typeid(std::complex<float>))
+ return 'c';
+ if (t == typeid(std::complex<double>))
+ return 'c';
+ if (t == typeid(std::complex<long double>))
+ return 'c';
+
+ else
+ return '?';
+}
+
+template<> std::vector<char> &cnpy::operator+=(std::vector<char> &lhs, const std::string rhs)
+{
+ lhs.insert(lhs.end(), rhs.begin(), rhs.end());
+ return lhs;
+}
+
+template<> std::vector<char> &cnpy::operator+=(std::vector<char> &lhs, const char *rhs)
+{
+ // write in little endian
+ size_t len = strlen(rhs);
+ lhs.reserve(len);
+ for (size_t byte = 0; byte < len; byte++) {
+ lhs.push_back(rhs[byte]);
+ }
+ return lhs;
+}
+
+void cnpy::parse_npy_header(unsigned char *buffer,
+ size_t &word_size,
+ std::vector<size_t> &shape,
+ bool &fortran_order)
+{
+ // std::string magic_string(buffer,6);
+ uint8_t major_version = *reinterpret_cast<uint8_t *>(buffer + 6);
+ uint8_t minor_version = *reinterpret_cast<uint8_t *>(buffer + 7);
+ uint16_t header_len = *reinterpret_cast<uint16_t *>(buffer + 8);
+ std::string header(reinterpret_cast<char *>(buffer + 9), header_len);
+
+ size_t loc1, loc2;
+
+ // fortran order
+ loc1 = header.find("fortran_order") + 16;
+ fortran_order = (header.substr(loc1, 4) == "True" ? true : false);
+
+ // shape
+ loc1 = header.find("(");
+ loc2 = header.find(")");
+
+ std::regex num_regex("[0-9][0-9]*");
+ std::smatch sm;
+ shape.clear();
+
+ std::string str_shape = header.substr(loc1 + 1, loc2 - loc1 - 1);
+ while (std::regex_search(str_shape, sm, num_regex)) {
+ shape.push_back(std::stoi(sm[0].str()));
+ str_shape = sm.suffix().str();
+ }
+
+ // endian, word size, data type
+ // byte order code | stands for not applicable.
+ // not sure when this applies except for byte array
+ loc1 = header.find("descr") + 9;
+ bool littleEndian = (header[loc1] == '<' || header[loc1] == '|' ? true : false);
+ assert(littleEndian);
+
+ // char type = header[loc1+1];
+ // assert(type == map_type(T));
+
+ std::string str_ws = header.substr(loc1 + 2);
+ loc2 = str_ws.find("'");
+ word_size = atoi(str_ws.substr(0, loc2).c_str());
+}
+
+void cnpy::parse_npy_header(FILE *fp,
+ size_t &word_size,
+ std::vector<size_t> &shape,
+ bool &fortran_order)
+{
+ char buffer[256];
+ size_t res = fread(buffer, sizeof(char), 11, fp);
+ if (res != 11)
+ throw std::runtime_error("parse_npy_header: failed fread");
+ std::string header = fgets(buffer, 256, fp);
+ assert(header[header.size() - 1] == '\n');
+
+ size_t loc1, loc2;
+
+ // fortran order
+ loc1 = header.find("fortran_order");
+ if (loc1 == std::string::npos)
+ throw std::runtime_error("parse_npy_header: failed to find header keyword: 'fortran_order'");
+ loc1 += 16;
+ fortran_order = (header.substr(loc1, 4) == "True" ? true : false);
+
+ // shape
+ loc1 = header.find("(");
+ loc2 = header.find(")");
+ if (loc1 == std::string::npos || loc2 == std::string::npos)
+ throw std::runtime_error("parse_npy_header: failed to find header keyword: '(' or ')'");
+
+ std::regex num_regex("[0-9][0-9]*");
+ std::smatch sm;
+ shape.clear();
+
+ std::string str_shape = header.substr(loc1 + 1, loc2 - loc1 - 1);
+ while (std::regex_search(str_shape, sm, num_regex)) {
+ shape.push_back(std::stoi(sm[0].str()));
+ str_shape = sm.suffix().str();
+ }
+
+ // endian, word size, data type
+ // byte order code | stands for not applicable.
+ // not sure when this applies except for byte array
+ loc1 = header.find("descr");
+ if (loc1 == std::string::npos)
+ throw std::runtime_error("parse_npy_header: failed to find header keyword: 'descr'");
+ loc1 += 9;
+ bool littleEndian = (header[loc1] == '<' || header[loc1] == '|' ? true : false);
+ assert(littleEndian);
+
+ // char type = header[loc1+1];
+ // assert(type == map_type(T));
+
+ std::string str_ws = header.substr(loc1 + 2);
+ loc2 = str_ws.find("'");
+ word_size = atoi(str_ws.substr(0, loc2).c_str());
+}
+
+void cnpy::parse_zip_footer(FILE *fp,
+ uint16_t &nrecs,
+ size_t &global_header_size,
+ size_t &global_header_offset)
+{
+ std::vector<char> footer(22);
+ fseek(fp, -22, SEEK_END);
+ size_t res = fread(&footer[0], sizeof(char), 22, fp);
+ if (res != 22)
+ throw std::runtime_error("parse_zip_footer: failed fread");
+
+ uint16_t disk_no, disk_start, nrecs_on_disk, comment_len;
+ disk_no = *(uint16_t *)&footer[4];
+ disk_start = *(uint16_t *)&footer[6];
+ nrecs_on_disk = *(uint16_t *)&footer[8];
+ nrecs = *(uint16_t *)&footer[10];
+ global_header_size = *(uint32_t *)&footer[12];
+ global_header_offset = *(uint32_t *)&footer[16];
+ comment_len = *(uint16_t *)&footer[20];
+
+ assert(disk_no == 0);
+ assert(disk_start == 0);
+ assert(nrecs_on_disk == nrecs);
+ assert(comment_len == 0);
+}
+
+cnpy::NpyArray load_the_npy_file(FILE *fp)
+{
+ std::vector<size_t> shape;
+ size_t word_size;
+ bool fortran_order;
+ cnpy::parse_npy_header(fp, word_size, shape, fortran_order);
+
+ cnpy::NpyArray arr(shape, word_size, fortran_order);
+ size_t nread = fread(arr.data<char>(), 1, arr.num_bytes(), fp);
+ if (nread != arr.num_bytes())
+ throw std::runtime_error("load_the_npy_file: failed fread");
+ return arr;
+}
+
+cnpy::NpyArray load_the_npz_array(FILE *fp, uint32_t compr_bytes, uint32_t uncompr_bytes)
+{
+
+ std::vector<unsigned char> buffer_compr(compr_bytes);
+ std::vector<unsigned char> buffer_uncompr(uncompr_bytes);
+ size_t nread = fread(&buffer_compr[0], 1, compr_bytes, fp);
+ if (nread != compr_bytes)
+ throw std::runtime_error("load_the_npy_file: failed fread");
+
+ int err;
+ z_stream d_stream;
+
+ d_stream.zalloc = Z_NULL;
+ d_stream.zfree = Z_NULL;
+ d_stream.opaque = Z_NULL;
+ d_stream.avail_in = 0;
+ d_stream.next_in = Z_NULL;
+ err = inflateInit2(&d_stream, -MAX_WBITS);
+
+ d_stream.avail_in = compr_bytes;
+ d_stream.next_in = &buffer_compr[0];
+ d_stream.avail_out = uncompr_bytes;
+ d_stream.next_out = &buffer_uncompr[0];
+
+ err = inflate(&d_stream, Z_FINISH);
+ err = inflateEnd(&d_stream);
+
+ std::vector<size_t> shape;
+ size_t word_size;
+ bool fortran_order;
+ cnpy::parse_npy_header(&buffer_uncompr[0], word_size, shape, fortran_order);
+
+ cnpy::NpyArray array(shape, word_size, fortran_order);
+
+ size_t offset = uncompr_bytes - array.num_bytes();
+ memcpy(array.data<unsigned char>(), &buffer_uncompr[0] + offset, array.num_bytes());
+
+ return array;
+}
+
+cnpy::npz_t cnpy::npz_load(std::string fname)
+{
+ FILE *fp = fopen(fname.c_str(), "rb");
+
+ if (!fp) {
+ throw std::runtime_error("npz_load: Error! Unable to open file " + fname + "!");
+ }
+
+ cnpy::npz_t arrays;
+
+ while (1) {
+ std::vector<char> local_header(30);
+ size_t headerres = fread(&local_header[0], sizeof(char), 30, fp);
+ if (headerres != 30)
+ throw std::runtime_error("npz_load: failed fread");
+
+ // if we've reached the global header, stop reading
+ if (local_header[2] != 0x03 || local_header[3] != 0x04)
+ break;
+
+ // read in the variable name
+ uint16_t name_len = *(uint16_t *)&local_header[26];
+ std::string varname(name_len, ' ');
+ size_t vname_res = fread(&varname[0], sizeof(char), name_len, fp);
+ if (vname_res != name_len)
+ throw std::runtime_error("npz_load: failed fread");
+
+ // erase the lagging .npy
+ varname.erase(varname.end() - 4, varname.end());
+
+ // read in the extra field
+ uint16_t extra_field_len = *(uint16_t *)&local_header[28];
+ if (extra_field_len > 0) {
+ std::vector<char> buff(extra_field_len);
+ size_t efield_res = fread(&buff[0], sizeof(char), extra_field_len, fp);
+ if (efield_res != extra_field_len)
+ throw std::runtime_error("npz_load: failed fread");
+ }
+
+ uint16_t compr_method = *reinterpret_cast<uint16_t *>(&local_header[0] + 8);
+ uint32_t compr_bytes = *reinterpret_cast<uint32_t *>(&local_header[0] + 18);
+ uint32_t uncompr_bytes = *reinterpret_cast<uint32_t *>(&local_header[0] + 22);
+
+ if (compr_method == 0) {
+ arrays[varname] = load_the_npy_file(fp);
+ }
+ else {
+ arrays[varname] = load_the_npz_array(fp, compr_bytes, uncompr_bytes);
+ }
+ }
+
+ fclose(fp);
+ return arrays;
+}
+
+cnpy::NpyArray cnpy::npz_load(std::string fname, std::string varname)
+{
+ FILE *fp = fopen(fname.c_str(), "rb");
+
+ if (!fp)
+ throw std::runtime_error("npz_load: Unable to open file " + fname);
+
+ while (1) {
+ std::vector<char> local_header(30);
+ size_t header_res = fread(&local_header[0], sizeof(char), 30, fp);
+ if (header_res != 30)
+ throw std::runtime_error("npz_load: failed fread");
+
+ // if we've reached the global header, stop reading
+ if (local_header[2] != 0x03 || local_header[3] != 0x04)
+ break;
+
+ // read in the variable name
+ uint16_t name_len = *(uint16_t *)&local_header[26];
+ std::string vname(name_len, ' ');
+ size_t vname_res = fread(&vname[0], sizeof(char), name_len, fp);
+ if (vname_res != name_len)
+ throw std::runtime_error("npz_load: failed fread");
+ vname.erase(vname.end() - 4, vname.end()); // erase the lagging .npy
+
+ // read in the extra field
+ uint16_t extra_field_len = *(uint16_t *)&local_header[28];
+ fseek(fp, extra_field_len, SEEK_CUR); // skip past the extra field
+
+ uint16_t compr_method = *reinterpret_cast<uint16_t *>(&local_header[0] + 8);
+ uint32_t compr_bytes = *reinterpret_cast<uint32_t *>(&local_header[0] + 18);
+ uint32_t uncompr_bytes = *reinterpret_cast<uint32_t *>(&local_header[0] + 22);
+
+ if (vname == varname) {
+ NpyArray array = (compr_method == 0) ? load_the_npy_file(fp) :
+ load_the_npz_array(fp, compr_bytes, uncompr_bytes);
+ fclose(fp);
+ return array;
+ }
+ else {
+ // skip past the data
+ // uint32_t size = *(uint32_t*) &local_header[22];
+ uint32_t size = *(uint32_t *)&local_header[18]; // using index 18 instead of 22 enables
+ // support for compressed data
+ fseek(fp, size, SEEK_CUR);
+ }
+ }
+
+ fclose(fp);
+
+ // if we get here, we haven't found the variable in the file
+ throw std::runtime_error("npz_load: Variable name " + varname + " not found in " + fname);
+}
+
+cnpy::NpyArray cnpy::npy_load(std::string fname)
+{
+
+ FILE *fp = fopen(fname.c_str(), "rb");
+
+ if (!fp)
+ throw std::runtime_error("npy_load: Unable to open file " + fname);
+
+ NpyArray arr = load_the_npy_file(fp);
+
+ fclose(fp);
+ return arr;
+}
diff --git a/extern/mantaflow/dependencies/cnpy/cnpy.h b/extern/mantaflow/dependencies/cnpy/cnpy.h
new file mode 100644
index 00000000000..e4b6365cb6f
--- /dev/null
+++ b/extern/mantaflow/dependencies/cnpy/cnpy.h
@@ -0,0 +1,310 @@
+// Copyright (C) 2011 Carl Rogers
+// Released under MIT License
+// license available in LICENSE file, or at http://www.opensource.org/licenses/mit-license.php
+
+#ifndef LIBCNPY_H_
+#define LIBCNPY_H_
+
+#include <string>
+#include <stdexcept>
+#include <sstream>
+#include <vector>
+#include <cstdio>
+#include <typeinfo>
+#include <iostream>
+#include <cassert>
+#include <zlib.h>
+#include <map>
+#include <memory>
+#include <stdint.h>
+#include <numeric>
+
+namespace cnpy {
+
+struct NpyArray {
+ NpyArray(const std::vector<size_t> &_shape, size_t _word_size, bool _fortran_order)
+ : shape(_shape), word_size(_word_size), fortran_order(_fortran_order)
+ {
+ num_vals = 1;
+ for (size_t i = 0; i < shape.size(); i++)
+ num_vals *= shape[i];
+ data_holder = std::shared_ptr<std::vector<char>>(new std::vector<char>(num_vals * word_size));
+ }
+
+ NpyArray() : shape(0), word_size(0), fortran_order(0), num_vals(0)
+ {
+ }
+
+ template<typename T> T *data()
+ {
+ return reinterpret_cast<T *>(&(*data_holder)[0]);
+ }
+
+ template<typename T> const T *data() const
+ {
+ return reinterpret_cast<T *>(&(*data_holder)[0]);
+ }
+
+ template<typename T> std::vector<T> as_vec() const
+ {
+ const T *p = data<T>();
+ return std::vector<T>(p, p + num_vals);
+ }
+
+ size_t num_bytes() const
+ {
+ return data_holder->size();
+ }
+
+ std::shared_ptr<std::vector<char>> data_holder;
+ std::vector<size_t> shape;
+ size_t word_size;
+ bool fortran_order;
+ size_t num_vals;
+};
+
+using npz_t = std::map<std::string, NpyArray>;
+
+char BigEndianTest();
+char map_type(const std::type_info &t);
+template<typename T> std::vector<char> create_npy_header(const std::vector<size_t> &shape);
+void parse_npy_header(FILE *fp,
+ size_t &word_size,
+ std::vector<size_t> &shape,
+ bool &fortran_order);
+void parse_npy_header(unsigned char *buffer,
+ size_t &word_size,
+ std::vector<size_t> &shape,
+ bool &fortran_order);
+void parse_zip_footer(FILE *fp,
+ uint16_t &nrecs,
+ size_t &global_header_size,
+ size_t &global_header_offset);
+npz_t npz_load(std::string fname);
+NpyArray npz_load(std::string fname, std::string varname);
+NpyArray npy_load(std::string fname);
+
+template<typename T> std::vector<char> &operator+=(std::vector<char> &lhs, const T rhs)
+{
+ // write in little endian
+ for (size_t byte = 0; byte < sizeof(T); byte++) {
+ char val = *((char *)&rhs + byte);
+ lhs.push_back(val);
+ }
+ return lhs;
+}
+
+template<> std::vector<char> &operator+=(std::vector<char> &lhs, const std::string rhs);
+template<> std::vector<char> &operator+=(std::vector<char> &lhs, const char *rhs);
+
+template<typename T>
+void npy_save(std::string fname,
+ const T *data,
+ const std::vector<size_t> shape,
+ std::string mode = "w")
+{
+ FILE *fp = NULL;
+ std::vector<size_t> true_data_shape; // if appending, the shape of existing + new data
+
+ if (mode == "a")
+ fp = fopen(fname.c_str(), "r+b");
+
+ if (fp) {
+ // file exists. we need to append to it. read the header, modify the array size
+ size_t word_size;
+ bool fortran_order;
+ parse_npy_header(fp, word_size, true_data_shape, fortran_order);
+ assert(!fortran_order);
+
+ if (word_size != sizeof(T)) {
+ std::cout << "libnpy error: " << fname << " has word size " << word_size
+ << " but npy_save appending data sized " << sizeof(T) << "\n";
+ assert(word_size == sizeof(T));
+ }
+ if (true_data_shape.size() != shape.size()) {
+ std::cout << "libnpy error: npy_save attempting to append misdimensioned data to " << fname
+ << "\n";
+ assert(true_data_shape.size() != shape.size());
+ }
+
+ for (size_t i = 1; i < shape.size(); i++) {
+ if (shape[i] != true_data_shape[i]) {
+ std::cout << "libnpy error: npy_save attempting to append misshaped data to " << fname
+ << "\n";
+ assert(shape[i] == true_data_shape[i]);
+ }
+ }
+ true_data_shape[0] += shape[0];
+ }
+ else {
+ fp = fopen(fname.c_str(), "wb");
+ true_data_shape = shape;
+ }
+
+ std::vector<char> header = create_npy_header<T>(true_data_shape);
+ size_t nels = std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<size_t>());
+
+ fseek(fp, 0, SEEK_SET);
+ fwrite(&header[0], sizeof(char), header.size(), fp);
+ fseek(fp, 0, SEEK_END);
+ fwrite(data, sizeof(T), nels, fp);
+ fclose(fp);
+}
+
+template<typename T>
+void npz_save(std::string zipname,
+ std::string fname,
+ const T *data,
+ const std::vector<size_t> &shape,
+ std::string mode = "w")
+{
+ // first, append a .npy to the fname
+ fname += ".npy";
+
+ // now, on with the show
+ FILE *fp = NULL;
+ uint16_t nrecs = 0;
+ size_t global_header_offset = 0;
+ std::vector<char> global_header;
+
+ if (mode == "a")
+ fp = fopen(zipname.c_str(), "r+b");
+
+ if (fp) {
+ // zip file exists. we need to add a new npy file to it.
+ // first read the footer. this gives us the offset and size of the global header
+ // then read and store the global header.
+ // below, we will write the the new data at the start of the global header then append the
+ // global header and footer below it
+ size_t global_header_size;
+ parse_zip_footer(fp, nrecs, global_header_size, global_header_offset);
+ fseek(fp, global_header_offset, SEEK_SET);
+ global_header.resize(global_header_size);
+ size_t res = fread(&global_header[0], sizeof(char), global_header_size, fp);
+ if (res != global_header_size) {
+ throw std::runtime_error("npz_save: header read error while adding to existing zip");
+ }
+ fseek(fp, global_header_offset, SEEK_SET);
+ }
+ else {
+ fp = fopen(zipname.c_str(), "wb");
+ }
+
+ std::vector<char> npy_header = create_npy_header<T>(shape);
+
+ size_t nels = std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<size_t>());
+ size_t nbytes = nels * sizeof(T) + npy_header.size();
+
+ // get the CRC of the data to be added
+ uint32_t crc = crc32(0L, (uint8_t *)&npy_header[0], npy_header.size());
+ crc = crc32(crc, (uint8_t *)data, nels * sizeof(T));
+
+ // build the local header
+ std::vector<char> local_header;
+ local_header += "PK"; // first part of sig
+ local_header += (uint16_t)0x0403; // second part of sig
+ local_header += (uint16_t)20; // min version to extract
+ local_header += (uint16_t)0; // general purpose bit flag
+ local_header += (uint16_t)0; // compression method
+ local_header += (uint16_t)0; // file last mod time
+ local_header += (uint16_t)0; // file last mod date
+ local_header += (uint32_t)crc; // crc
+ local_header += (uint32_t)nbytes; // compressed size
+ local_header += (uint32_t)nbytes; // uncompressed size
+ local_header += (uint16_t)fname.size(); // fname length
+ local_header += (uint16_t)0; // extra field length
+ local_header += fname;
+
+ // build global header
+ global_header += "PK"; // first part of sig
+ global_header += (uint16_t)0x0201; // second part of sig
+ global_header += (uint16_t)20; // version made by
+ global_header.insert(global_header.end(), local_header.begin() + 4, local_header.begin() + 30);
+ global_header += (uint16_t)0; // file comment length
+ global_header += (uint16_t)0; // disk number where file starts
+ global_header += (uint16_t)0; // internal file attributes
+ global_header += (uint32_t)0; // external file attributes
+ global_header += (uint32_t)
+ global_header_offset; // relative offset of local file header, since it begins where the
+ // global header used to begin
+ global_header += fname;
+
+ // build footer
+ std::vector<char> footer;
+ footer += "PK"; // first part of sig
+ footer += (uint16_t)0x0605; // second part of sig
+ footer += (uint16_t)0; // number of this disk
+ footer += (uint16_t)0; // disk where footer starts
+ footer += (uint16_t)(nrecs + 1); // number of records on this disk
+ footer += (uint16_t)(nrecs + 1); // total number of records
+ footer += (uint32_t)global_header.size(); // nbytes of global headers
+ footer += (uint32_t)(global_header_offset + nbytes +
+ local_header.size()); // offset of start of global headers, since global
+ // header now starts after newly written array
+ footer += (uint16_t)0; // zip file comment length
+
+ // write everything
+ fwrite(&local_header[0], sizeof(char), local_header.size(), fp);
+ fwrite(&npy_header[0], sizeof(char), npy_header.size(), fp);
+ fwrite(data, sizeof(T), nels, fp);
+ fwrite(&global_header[0], sizeof(char), global_header.size(), fp);
+ fwrite(&footer[0], sizeof(char), footer.size(), fp);
+ fclose(fp);
+}
+
+template<typename T>
+void npy_save(std::string fname, const std::vector<T> data, std::string mode = "w")
+{
+ std::vector<size_t> shape;
+ shape.push_back(data.size());
+ npy_save(fname, &data[0], shape, mode);
+}
+
+template<typename T>
+void npz_save(std::string zipname,
+ std::string fname,
+ const std::vector<T> data,
+ std::string mode = "w")
+{
+ std::vector<size_t> shape;
+ shape.push_back(data.size());
+ npz_save(zipname, fname, &data[0], shape, mode);
+}
+
+template<typename T> std::vector<char> create_npy_header(const std::vector<size_t> &shape)
+{
+
+ std::vector<char> dict;
+ dict += "{'descr': '";
+ dict += BigEndianTest();
+ dict += map_type(typeid(T));
+ dict += std::to_string(sizeof(T));
+ dict += "', 'fortran_order': False, 'shape': (";
+ dict += std::to_string(shape[0]);
+ for (size_t i = 1; i < shape.size(); i++) {
+ dict += ", ";
+ dict += std::to_string(shape[i]);
+ }
+ if (shape.size() == 1)
+ dict += ",";
+ dict += "), }";
+ // pad with spaces so that preamble+dict is modulo 16 bytes. preamble is 10 bytes. dict needs to
+ // end with \n
+ int remainder = 16 - (10 + dict.size()) % 16;
+ dict.insert(dict.end(), remainder, ' ');
+ dict.back() = '\n';
+
+ std::vector<char> header;
+ header += (char)0x93;
+ header += "NUMPY";
+ header += (char)0x01; // major version of numpy format
+ header += (char)0x00; // minor version of numpy format
+ header += (uint16_t)dict.size();
+ header.insert(header.end(), dict.begin(), dict.end());
+
+ return header;
+}
+
+} // namespace cnpy
+
+#endif
diff --git a/extern/mantaflow/helper/pwrapper/manta.h b/extern/mantaflow/helper/pwrapper/manta.h
new file mode 100644
index 00000000000..efbca6cc493
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/manta.h
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Include pwrapper headers
+ *
+ ******************************************************************************/
+
+#ifndef _MANTA_H
+#define _MANTA_H
+
+// Remove preprocessor keywords, so there won't infere with autocompletion etc.
+#define KERNEL(...) extern int i, j, k, idx, X, Y, Z;
+#define PYTHON(...)
+#define returns(X) extern X;
+#define alias typedef
+
+#include "general.h"
+#include "vectorbase.h"
+#include "vector4d.h"
+#include "registry.h"
+#include "pclass.h"
+#include "pconvert.h"
+#include "fluidsolver.h"
+
+#endif
diff --git a/extern/mantaflow/helper/pwrapper/numpyWrap.cpp b/extern/mantaflow/helper/pwrapper/numpyWrap.cpp
new file mode 100644
index 00000000000..d2ddb21be70
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/numpyWrap.cpp
@@ -0,0 +1,132 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2017-2018 Steffen Wiewel, Moritz Becher, Rachel Chu
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Convert mantaflow grids to/from numpy arrays
+ *
+ ******************************************************************************/
+
+#include "manta.h"
+#include "pythonInclude.h"
+
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+#include "numpy/arrayobject.h"
+
+namespace Manta {
+
+#if PY_VERSION_HEX < 0x03000000
+PyMODINIT_FUNC initNumpy()
+{
+ import_array();
+}
+#endif
+
+// ------------------------------------------------------------------------
+// Class Functions
+// ------------------------------------------------------------------------
+PyArrayContainer::PyArrayContainer(void *_pParentPyArray) : pParentPyArray(_pParentPyArray)
+{
+ ExtractData(pParentPyArray);
+}
+// ------------------------------------------------------------------------
+PyArrayContainer::PyArrayContainer(const PyArrayContainer &_Other)
+ : pParentPyArray(_Other.pParentPyArray)
+{
+ ExtractData(pParentPyArray);
+ Py_INCREF(pParentPyArray);
+}
+// ------------------------------------------------------------------------
+PyArrayContainer::~PyArrayContainer()
+{
+ Py_DECREF(pParentPyArray);
+}
+// ------------------------------------------------------------------------
+PyArrayContainer &PyArrayContainer::operator=(const PyArrayContainer &_Other)
+{
+ if (this != &_Other) {
+ // DecRef the existing resource
+ Py_DECREF(pParentPyArray);
+
+ // Relink new data
+ pParentPyArray = _Other.pParentPyArray;
+ ExtractData(pParentPyArray);
+ Py_INCREF(pParentPyArray);
+ }
+ return *this;
+}
+// ------------------------------------------------------------------------
+void PyArrayContainer::ExtractData(void *_pParentPyArray)
+{
+ PyArrayObject *pParent = reinterpret_cast<PyArrayObject *>(pParentPyArray);
+
+ int numDims = PyArray_NDIM(pParent);
+ long *pDims = (long *)PyArray_DIMS(pParent);
+
+ pData = PyArray_DATA(pParent);
+ TotalSize = PyArray_SIZE(pParent);
+ Dims = std::vector<long>(&pDims[0], &pDims[numDims]);
+
+ int iDataType = PyArray_TYPE(pParent);
+ switch (iDataType) {
+ case NPY_FLOAT:
+ DataType = N_FLOAT;
+ break;
+ case NPY_DOUBLE:
+ DataType = N_DOUBLE;
+ break;
+ case NPY_INT:
+ DataType = N_INT;
+ break;
+ default:
+ errMsg("unknown type of Numpy array");
+ break;
+ }
+}
+
+// ------------------------------------------------------------------------
+// Conversion Functions
+// ------------------------------------------------------------------------
+
+template<> PyArrayContainer fromPy<PyArrayContainer>(PyObject *obj)
+{
+ if (PyArray_API == NULL) {
+ // python 3 uses the return value
+#if PY_VERSION_HEX >= 0x03000000
+ import_array();
+#else
+ initNumpy();
+#endif
+ }
+
+ if (!PyArray_Check(obj)) {
+ errMsg("argument is not an numpy array");
+ }
+
+ PyArrayObject *obj_p = reinterpret_cast<PyArrayObject *>(
+ PyArray_CheckFromAny(obj,
+ NULL,
+ 0,
+ 0,
+ /*NPY_ARRAY_ENSURECOPY*/ NPY_ARRAY_C_CONTIGUOUS |
+ NPY_ARRAY_ENSUREARRAY | NPY_ARRAY_NOTSWAPPED,
+ NULL));
+ PyArrayContainer container = PyArrayContainer(obj_p);
+
+ return container;
+}
+
+// template<> PyArrayContainer* fromPyPtr<PyArrayContainer>(PyObject* obj, std::vector<void*>* tmp)
+// {
+// if (!tmp) throw Error("dynamic de-ref not supported for this type");
+// void* ptr = malloc(sizeof(PyArrayContainer));
+// tmp->push_back(ptr);
+
+// *((PyArrayContainer*) ptr) = fromPy<PyArrayContainer>(obj);
+// return (PyArrayContainer*) ptr;
+// }
+} // namespace Manta
diff --git a/extern/mantaflow/helper/pwrapper/numpyWrap.h b/extern/mantaflow/helper/pwrapper/numpyWrap.h
new file mode 100644
index 00000000000..c92a2eaaa97
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/numpyWrap.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2017 Steffen Wiewel, Moritz Baecher, Rachel Chu
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Convert mantaflow grids to/from numpy arrays
+ *
+ ******************************************************************************/
+
+#ifdef _PCONVERT_H
+# ifndef _NUMPYCONVERT_H
+# define _NUMPYCONVERT_H
+
+enum NumpyTypes {
+ N_BOOL = 0,
+ N_BYTE,
+ N_UBYTE,
+ N_SHORT,
+ N_USHORT,
+ N_INT,
+ N_UINT,
+ N_LONG,
+ N_ULONG,
+ N_LONGLONG,
+ N_ULONGLONG,
+ N_FLOAT,
+ N_DOUBLE,
+ N_LONGDOUBLE,
+ N_CFLOAT,
+ N_CDOUBLE,
+ N_CLONGDOUBLE,
+ N_OBJECT = 17,
+ N_STRING,
+ N_UNICODE,
+ N_VOID,
+ /*
+ * New 1.6 types appended, may be integrated
+ * into the above in 2.0.
+ */
+ N_DATETIME,
+ N_TIMEDELTA,
+ N_HALF,
+
+ N_NTYPES,
+ N_NOTYPE,
+ N_CHAR, /* special flag */
+ N_USERDEF = 256, /* leave room for characters */
+
+ /* The number of types not including the new 1.6 types */
+ N_NTYPES_ABI_COMPATIBLE = 21
+};
+
+namespace Manta {
+class PyArrayContainer {
+ public:
+ /// Constructors
+ PyArrayContainer(void *_pParentPyArray);
+ PyArrayContainer(const PyArrayContainer &_Other);
+ ~PyArrayContainer();
+ /// Operators
+ PyArrayContainer &operator=(const PyArrayContainer &_Other);
+
+ private:
+ void ExtractData(void *_pParentPyArray);
+
+ public:
+ void *pData;
+ NumpyTypes DataType;
+ unsigned int TotalSize;
+ std::vector<long> Dims;
+
+ private:
+ void *pParentPyArray;
+};
+
+// template<> PyArrayContainer* fromPyPtr<PyArrayContainer>(PyObject* obj, std::vector<void*>*
+// tmp);
+template<> PyArrayContainer fromPy<PyArrayContainer>(PyObject *obj);
+} // namespace Manta
+
+# endif
+#endif
diff --git a/extern/mantaflow/helper/pwrapper/pclass.cpp b/extern/mantaflow/helper/pwrapper/pclass.cpp
new file mode 100644
index 00000000000..a95254ebe11
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/pclass.cpp
@@ -0,0 +1,220 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Functions for property setting/getting via python
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include "structmember.h"
+#include "manta.h"
+#include "general.h"
+#include "timing.h"
+
+#ifdef GUI
+# include <QMutex>
+#else
+class QMutex {
+ public:
+ void lock(){};
+ void unlock(){};
+ bool tryLock()
+ {
+ return true;
+ };
+};
+#endif
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// Free functions
+
+void pbPreparePlugin(FluidSolver *parent, const string &name, bool doTime)
+{
+ if (doTime)
+ TimingData::instance().start(parent, name);
+}
+
+void pbFinalizePlugin(FluidSolver *parent, const string &name, bool doTime)
+{
+ if (doTime)
+ TimingData::instance().stop(parent, name);
+
+ // GUI update, also print name of parent if there's more than one
+ std::ostringstream msg;
+ if (name != "FluidSolver::step") {
+ if (parent && (parent->getNumInstances() > 0))
+ msg << parent->getName() << string(".");
+ msg << name;
+ }
+ updateQtGui(false, 0, 0., msg.str());
+
+ debMsg(name << " done", 3);
+ // name unnamed PbClass Objects from var name
+ PbClass::renameObjects();
+}
+
+void pbSetError(const string &fn, const string &ex)
+{
+ debMsg("Error in " << fn, 1);
+ if (!ex.empty())
+ PyErr_SetString(PyExc_RuntimeError, ex.c_str());
+}
+
+//******************************************************************************
+// Helpers
+
+string PbTypeVec::str() const
+{
+ if (T.empty())
+ return "";
+ string s = "<";
+ for (int i = 0; i < (int)T.size(); i++) {
+ s += T[i].str();
+ s += (i != (int)T.size() - 1) ? ',' : '>';
+ }
+ return s;
+}
+string PbType::str() const
+{
+ if (S == "float")
+ return "Real";
+ if (S == "manta.vec3")
+ return "Vec3";
+ return S;
+}
+
+//******************************************************************************
+// PbClass
+
+vector<PbClass *> PbClass::mInstances;
+
+PbClass::PbClass(FluidSolver *parent, const string &name, PyObject *obj)
+ : mMutex(NULL), mParent(parent), mPyObject(obj), mName(name), mHidden(false)
+{
+ mMutex = new QMutex();
+}
+
+PbClass::PbClass(const PbClass &a)
+ : mMutex(NULL), mParent(a.mParent), mPyObject(0), mName("_unnamed"), mHidden(false)
+{
+ mMutex = new QMutex();
+}
+
+PbClass::~PbClass()
+{
+ for (vector<PbClass *>::iterator it = mInstances.begin(); it != mInstances.end(); ++it) {
+ if (*it == this) {
+ mInstances.erase(it);
+ break;
+ }
+ }
+ delete mMutex;
+}
+
+void PbClass::lock()
+{
+ mMutex->lock();
+}
+void PbClass::unlock()
+{
+ mMutex->unlock();
+}
+bool PbClass::tryLock()
+{
+ return mMutex->tryLock();
+}
+
+PbClass *PbClass::getInstance(int idx)
+{
+ if (idx < 0 || idx > (int)mInstances.size())
+ errMsg("PbClass::getInstance(): invalid index");
+ return mInstances[idx];
+}
+
+int PbClass::getNumInstances()
+{
+ return mInstances.size();
+}
+
+bool PbClass::isNullRef(PyObject *obj)
+{
+ return PyLong_Check(obj) && PyLong_AsDouble(obj) == 0;
+}
+
+bool PbClass::isNoneRef(PyObject *obj)
+{
+ return (obj == Py_None);
+}
+
+void PbClass::registerObject(PyObject *obj, PbArgs *args)
+{
+ // cross link
+ Pb::setReference(this, obj);
+ mPyObject = obj;
+
+ mInstances.push_back(this);
+
+ if (args) {
+ string _name = args->getOpt<std::string>("name", -1, "");
+ if (!_name.empty())
+ setName(_name);
+ }
+}
+
+PbClass *PbClass::createPyObject(const string &classname,
+ const string &name,
+ PbArgs &args,
+ PbClass *parent)
+{
+ return Pb::createPy(classname, name, args, parent);
+}
+
+void PbClass::checkParent()
+{
+ if (getParent() == NULL) {
+ errMsg("New class " + mName + ": no parent given -- specify using parent=xxx !");
+ }
+}
+//! Assign unnamed PbClass objects their Python variable name
+void PbClass::renameObjects()
+{
+ PyObject *sys_mod_dict = PyImport_GetModuleDict();
+ PyObject *loc_mod = PyMapping_GetItemString(sys_mod_dict, (char *)"__main__");
+ if (!loc_mod)
+ return;
+ PyObject *locdict = PyObject_GetAttrString(loc_mod, "__dict__");
+ if (!locdict)
+ return;
+
+ // iterate all PbClass instances
+ for (size_t i = 0; i < mInstances.size(); i++) {
+ PbClass *obj = mInstances[i];
+ if (obj->getName().empty()) {
+ // empty, try to find instance in module local dictionary
+
+ PyObject *lkey, *lvalue;
+ Py_ssize_t lpos = 0;
+ while (PyDict_Next(locdict, &lpos, &lkey, &lvalue)) {
+ if (lvalue == obj->mPyObject) {
+ string varName = fromPy<string>(PyObject_Str(lkey));
+ obj->setName(varName);
+ // cout << "assigning variable name '" << varName << "' to unnamed instance" << endl;
+ break;
+ }
+ }
+ }
+ }
+ Py_DECREF(locdict);
+ Py_DECREF(loc_mod);
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/helper/pwrapper/pclass.h b/extern/mantaflow/helper/pwrapper/pclass.h
new file mode 100644
index 00000000000..b34103ca9a7
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/pclass.h
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Base class for all Python-exposed classes
+ *
+ ******************************************************************************/
+
+// -----------------------------------------------------------------
+// NOTE:
+// Do not include this file in user code, include "manta.h" instead
+// -----------------------------------------------------------------
+
+#ifdef _MANTA_H
+# ifndef _PTYPE_H
+# define _PTYPE_H
+
+# include <string>
+# include <vector>
+# include <map>
+
+class QMutex;
+
+namespace Manta {
+struct PbClassData;
+class FluidSolver;
+class PbArgs;
+
+struct PbType {
+ std::string S;
+ std::string str() const;
+};
+struct PbTypeVec {
+ std::vector<PbType> T;
+ std::string str() const;
+};
+
+//! Base class for all classes exposed to Python
+class PbClass {
+ public:
+ PbClass(FluidSolver *parent, const std::string &name = "", PyObject *obj = NULL);
+ PbClass(const PbClass &a);
+ virtual ~PbClass();
+
+ // basic property setter/getters
+ void setName(const std::string &name)
+ {
+ mName = name;
+ }
+ std::string getName() const
+ {
+ return mName;
+ }
+ PyObject *getPyObject() const
+ {
+ return mPyObject;
+ }
+ void registerObject(PyObject *obj, PbArgs *args);
+ FluidSolver *getParent() const
+ {
+ return mParent;
+ }
+ void setParent(FluidSolver *v)
+ {
+ mParent = v;
+ }
+ void checkParent();
+
+ // hidden flag for GUI, debug output
+ inline bool isHidden()
+ {
+ return mHidden;
+ }
+ inline void setHidden(bool v)
+ {
+ mHidden = v;
+ }
+
+ void lock();
+ void unlock();
+ bool tryLock();
+
+ // PbClass instance registry
+ static int getNumInstances();
+ static PbClass *getInstance(int index);
+ static void renameObjects();
+
+ // converters
+ static bool isNullRef(PyObject *o);
+ static bool isNoneRef(PyObject *o);
+ static PbClass *createPyObject(const std::string &classname,
+ const std::string &name,
+ PbArgs &args,
+ PbClass *parent);
+ inline bool canConvertTo(const std::string &classname)
+ {
+ return Pb::canConvert(mPyObject, classname);
+ }
+
+ protected:
+ QMutex *mMutex;
+ FluidSolver *mParent;
+ PyObject *mPyObject;
+ std::string mName;
+ bool mHidden;
+
+ static std::vector<PbClass *> mInstances;
+};
+
+//!\cond Register
+
+void pbFinalizePlugin(FluidSolver *parent, const std::string &name, bool doTime = true);
+void pbPreparePlugin(FluidSolver *parent, const std::string &name, bool doTime = true);
+void pbSetError(const std::string &fn, const std::string &ex);
+
+//!\endcond
+
+} // namespace Manta
+
+# endif
+#endif
diff --git a/extern/mantaflow/helper/pwrapper/pconvert.cpp b/extern/mantaflow/helper/pwrapper/pconvert.cpp
new file mode 100644
index 00000000000..c8c92cbf585
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/pconvert.cpp
@@ -0,0 +1,568 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Python argument wrappers and conversion tools
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include <sstream>
+#include <algorithm>
+#include "vectorbase.h"
+#include "manta.h"
+
+using namespace std;
+
+//******************************************************************************
+// Explicit definition and instantiation of python object converters
+
+namespace Manta {
+
+extern PyTypeObject PbVec3Type;
+extern PyTypeObject PbVec4Type;
+
+struct PbVec3 {
+ PyObject_HEAD float data[3];
+};
+
+struct PbVec4 {
+ PyObject_HEAD float data[4];
+};
+
+PyObject *getPyNone()
+{
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+PyObject *incref(PyObject *obj)
+{
+ Py_INCREF(obj);
+ return obj;
+}
+
+/*template<> PyObject* toPy<PyObject*>(PyObject* obj) {
+ return obj;
+}*/
+template<> PyObject *toPy<int>(const int &v)
+{
+ return PyLong_FromLong(v);
+}
+/*template<> PyObject* toPy<char*>(const (char*) & val) {
+ return PyUnicode_DecodeLatin1(val,strlen(val),"replace");
+}*/
+template<> PyObject *toPy<string>(const string &val)
+{
+ return PyUnicode_DecodeLatin1(val.c_str(), val.length(), "replace");
+}
+template<> PyObject *toPy<float>(const float &v)
+{
+ return PyFloat_FromDouble(v);
+}
+template<> PyObject *toPy<double>(const double &v)
+{
+ return PyFloat_FromDouble(v);
+}
+template<> PyObject *toPy<bool>(const bool &v)
+{
+ return PyBool_FromLong(v);
+}
+template<> PyObject *toPy<Vec3i>(const Vec3i &v)
+{
+ float x = (float)v.x, y = (float)v.y, z = (float)v.z;
+ return PyObject_CallFunction((PyObject *)&PbVec3Type, (char *)"fff", x, y, z);
+}
+template<> PyObject *toPy<Vec3>(const Vec3 &v)
+{
+ float x = (float)v.x, y = (float)v.y, z = (float)v.z;
+ return PyObject_CallFunction((PyObject *)&PbVec3Type, (char *)"fff", x, y, z);
+}
+template<> PyObject *toPy<Vec4i>(const Vec4i &v)
+{
+ float x = (float)v.x, y = (float)v.y, z = (float)v.z;
+ return PyObject_CallFunction((PyObject *)&PbVec4Type, (char *)"ffff", x, y, z);
+}
+template<> PyObject *toPy<Vec4>(const Vec4 &v)
+{
+ float x = (float)v.x, y = (float)v.y, z = (float)v.z;
+ return PyObject_CallFunction((PyObject *)&PbVec4Type, (char *)"ffff", x, y, z);
+}
+template<> PyObject *toPy<PbClass *>(const PbClass_Ptr &obj)
+{
+ return obj->getPyObject();
+}
+
+template<> float fromPy<float>(PyObject *obj)
+{
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj))
+ return PyInt_AsLong(obj);
+#endif
+ if (PyFloat_Check(obj))
+ return PyFloat_AsDouble(obj);
+ if (PyLong_Check(obj))
+ return PyLong_AsDouble(obj);
+ errMsg("argument is not a float");
+}
+template<> double fromPy<double>(PyObject *obj)
+{
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj))
+ return PyInt_AsLong(obj);
+#endif
+ if (PyFloat_Check(obj))
+ return PyFloat_AsDouble(obj);
+ if (PyLong_Check(obj))
+ return PyLong_AsDouble(obj);
+ errMsg("argument is not a double");
+}
+template<> PyObject *fromPy<PyObject *>(PyObject *obj)
+{
+ return obj;
+}
+template<> int fromPy<int>(PyObject *obj)
+{
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj))
+ return PyInt_AsLong(obj);
+#endif
+ if (PyLong_Check(obj))
+ return PyLong_AsDouble(obj);
+ if (PyFloat_Check(obj)) {
+ double a = PyFloat_AsDouble(obj);
+ if (fabs(a - floor(a + 0.5)) > 1e-5)
+ errMsg("argument is not an int");
+ return (int)(a + 0.5);
+ }
+ errMsg("argument is not an int");
+}
+template<> string fromPy<string>(PyObject *obj)
+{
+ if (PyUnicode_Check(obj))
+ return PyBytes_AsString(PyUnicode_AsLatin1String(obj));
+#if PY_MAJOR_VERSION <= 2
+ else if (PyString_Check(obj))
+ return PyString_AsString(obj);
+#endif
+ else
+ errMsg("argument is not a string");
+}
+template<> const char *fromPy<const char *>(PyObject *obj)
+{
+ if (PyUnicode_Check(obj))
+ return PyBytes_AsString(PyUnicode_AsLatin1String(obj));
+#if PY_MAJOR_VERSION <= 2
+ else if (PyString_Check(obj))
+ return PyString_AsString(obj);
+#endif
+ else
+ errMsg("argument is not a string");
+}
+template<> bool fromPy<bool>(PyObject *obj)
+{
+ if (!PyBool_Check(obj))
+ errMsg("argument is not a boolean");
+ return PyLong_AsLong(obj) != 0;
+}
+template<> Vec3 fromPy<Vec3>(PyObject *obj)
+{
+ if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type)) {
+ return Vec3(((PbVec3 *)obj)->data);
+ }
+ else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
+ return Vec3(fromPy<Real>(PyTuple_GetItem(obj, 0)),
+ fromPy<Real>(PyTuple_GetItem(obj, 1)),
+ fromPy<Real>(PyTuple_GetItem(obj, 2)));
+ }
+ errMsg("argument is not a Vec3");
+}
+template<> Vec3i fromPy<Vec3i>(PyObject *obj)
+{
+ if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type)) {
+ return toVec3iChecked(((PbVec3 *)obj)->data);
+ }
+ else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
+ return Vec3i(fromPy<int>(PyTuple_GetItem(obj, 0)),
+ fromPy<int>(PyTuple_GetItem(obj, 1)),
+ fromPy<int>(PyTuple_GetItem(obj, 2)));
+ }
+ errMsg("argument is not a Vec3i");
+}
+template<> Vec4 fromPy<Vec4>(PyObject *obj)
+{
+ if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type)) {
+ return Vec4(((PbVec4 *)obj)->data);
+ }
+ else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
+ return Vec4(fromPy<Real>(PyTuple_GetItem(obj, 0)),
+ fromPy<Real>(PyTuple_GetItem(obj, 1)),
+ fromPy<Real>(PyTuple_GetItem(obj, 2)),
+ fromPy<Real>(PyTuple_GetItem(obj, 3)));
+ }
+ errMsg("argument is not a Vec4");
+}
+template<> Vec4i fromPy<Vec4i>(PyObject *obj)
+{
+ if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type)) {
+ return toVec4i(((PbVec4 *)obj)->data);
+ }
+ else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
+ return Vec4i(fromPy<int>(PyTuple_GetItem(obj, 0)),
+ fromPy<int>(PyTuple_GetItem(obj, 1)),
+ fromPy<int>(PyTuple_GetItem(obj, 2)),
+ fromPy<int>(PyTuple_GetItem(obj, 3)));
+ }
+ errMsg("argument is not a Vec4i");
+}
+template<> PbType fromPy<PbType>(PyObject *obj)
+{
+ PbType pb = {""};
+ if (!PyType_Check(obj))
+ return pb;
+
+ const char *tname = ((PyTypeObject *)obj)->tp_name;
+ pb.S = tname;
+ return pb;
+}
+template<> PbTypeVec fromPy<PbTypeVec>(PyObject *obj)
+{
+ PbTypeVec vec;
+ if (PyType_Check(obj)) {
+ vec.T.push_back(fromPy<PbType>(obj));
+ }
+ else if (PyTuple_Check(obj)) {
+ int sz = PyTuple_Size(obj);
+ for (int i = 0; i < sz; i++)
+ vec.T.push_back(fromPy<PbType>(PyTuple_GetItem(obj, i)));
+ }
+ else
+ errMsg("argument is not a type tuple");
+ return vec;
+}
+
+template<class T> T *tmpAlloc(PyObject *obj, std::vector<void *> *tmp)
+{
+ if (!tmp)
+ throw Error("dynamic de-ref not supported for this type");
+ void *ptr = malloc(sizeof(T));
+ tmp->push_back(ptr);
+
+ *((T *)ptr) = fromPy<T>(obj);
+ return (T *)ptr;
+}
+template<> float *fromPyPtr<float>(PyObject *obj, std::vector<void *> *tmp)
+{
+ return tmpAlloc<float>(obj, tmp);
+}
+template<> double *fromPyPtr<double>(PyObject *obj, std::vector<void *> *tmp)
+{
+ return tmpAlloc<double>(obj, tmp);
+}
+template<> int *fromPyPtr<int>(PyObject *obj, std::vector<void *> *tmp)
+{
+ return tmpAlloc<int>(obj, tmp);
+}
+template<> std::string *fromPyPtr<std::string>(PyObject *obj, std::vector<void *> *tmp)
+{
+ return tmpAlloc<std::string>(obj, tmp);
+}
+template<> bool *fromPyPtr<bool>(PyObject *obj, std::vector<void *> *tmp)
+{
+ return tmpAlloc<bool>(obj, tmp);
+}
+template<> Vec3 *fromPyPtr<Vec3>(PyObject *obj, std::vector<void *> *tmp)
+{
+ return tmpAlloc<Vec3>(obj, tmp);
+}
+template<> Vec3i *fromPyPtr<Vec3i>(PyObject *obj, std::vector<void *> *tmp)
+{
+ return tmpAlloc<Vec3i>(obj, tmp);
+}
+template<> Vec4 *fromPyPtr<Vec4>(PyObject *obj, std::vector<void *> *tmp)
+{
+ return tmpAlloc<Vec4>(obj, tmp);
+}
+template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<void *> *tmp)
+{
+ return tmpAlloc<Vec4i>(obj, tmp);
+}
+
+template<> bool isPy<float>(PyObject *obj)
+{
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj))
+ return true;
+#endif
+ return PyFloat_Check(obj) || PyLong_Check(obj);
+}
+template<> bool isPy<double>(PyObject *obj)
+{
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj))
+ return true;
+#endif
+ return PyFloat_Check(obj) || PyLong_Check(obj);
+}
+template<> bool isPy<PyObject *>(PyObject *obj)
+{
+ return true;
+}
+template<> bool isPy<int>(PyObject *obj)
+{
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj))
+ return true;
+#endif
+ if (PyLong_Check(obj))
+ return true;
+ if (PyFloat_Check(obj)) {
+ double a = PyFloat_AsDouble(obj);
+ return fabs(a - floor(a + 0.5)) < 1e-5;
+ }
+ return false;
+}
+template<> bool isPy<string>(PyObject *obj)
+{
+ if (PyUnicode_Check(obj))
+ return true;
+#if PY_MAJOR_VERSION <= 2
+ if (PyString_Check(obj))
+ return true;
+#endif
+ return false;
+}
+template<> bool isPy<const char *>(PyObject *obj)
+{
+ if (PyUnicode_Check(obj))
+ return true;
+#if PY_MAJOR_VERSION <= 2
+ if (PyString_Check(obj))
+ return true;
+#endif
+ return false;
+}
+template<> bool isPy<bool>(PyObject *obj)
+{
+ return PyBool_Check(obj);
+}
+template<> bool isPy<Vec3>(PyObject *obj)
+{
+ if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type))
+ return true;
+ if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
+ return isPy<Real>(PyTuple_GetItem(obj, 0)) && isPy<Real>(PyTuple_GetItem(obj, 1)) &&
+ isPy<Real>(PyTuple_GetItem(obj, 2));
+ }
+ return false;
+}
+template<> bool isPy<Vec3i>(PyObject *obj)
+{
+ if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type))
+ return true;
+ if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
+ return isPy<int>(PyTuple_GetItem(obj, 0)) && isPy<int>(PyTuple_GetItem(obj, 1)) &&
+ isPy<int>(PyTuple_GetItem(obj, 2));
+ }
+ return false;
+}
+template<> bool isPy<Vec4>(PyObject *obj)
+{
+ if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type))
+ return true;
+ if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
+ return isPy<Real>(PyTuple_GetItem(obj, 0)) && isPy<Real>(PyTuple_GetItem(obj, 1)) &&
+ isPy<Real>(PyTuple_GetItem(obj, 2)) && isPy<Real>(PyTuple_GetItem(obj, 3));
+ }
+ return false;
+}
+template<> bool isPy<Vec4i>(PyObject *obj)
+{
+ if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type))
+ return true;
+ if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
+ return isPy<int>(PyTuple_GetItem(obj, 0)) && isPy<int>(PyTuple_GetItem(obj, 1)) &&
+ isPy<int>(PyTuple_GetItem(obj, 2)) && isPy<int>(PyTuple_GetItem(obj, 3));
+ }
+ return false;
+}
+template<> bool isPy<PbType>(PyObject *obj)
+{
+ return PyType_Check(obj);
+}
+
+//******************************************************************************
+// PbArgs class defs
+
+PbArgs PbArgs::EMPTY(NULL, NULL);
+
+PbArgs::PbArgs(PyObject *linarg, PyObject *dict) : mLinArgs(0), mKwds(0)
+{
+ setup(linarg, dict);
+}
+PbArgs::~PbArgs()
+{
+ for (int i = 0; i < (int)mTmpStorage.size(); i++)
+ free(mTmpStorage[i]);
+ mTmpStorage.clear();
+}
+
+void PbArgs::copy(PbArgs &a)
+{
+ mKwds = a.mKwds;
+ mData = a.mData;
+ mLinData = a.mLinData;
+ mLinArgs = a.mLinArgs;
+}
+void PbArgs::clear()
+{
+ mLinArgs = 0;
+ mKwds = 0;
+ mData.clear();
+ mLinData.clear();
+}
+
+PbArgs &PbArgs::operator=(const PbArgs &a)
+{
+ // mLinArgs = 0;
+ // mKwds = 0;
+ return *this;
+}
+
+void PbArgs::setup(PyObject *linarg, PyObject *dict)
+{
+ if (dict) {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ DataElement el;
+ el.obj = value;
+ el.visited = false;
+ mData[fromPy<string>(key)] = el;
+ }
+ mKwds = dict;
+ }
+ if (linarg) {
+ size_t len = PyTuple_Size(linarg);
+ for (size_t i = 0; i < len; i++) {
+ DataElement el;
+ el.obj = PyTuple_GetItem(linarg, i);
+ el.visited = false;
+ mLinData.push_back(el);
+ }
+ mLinArgs = linarg;
+ }
+}
+
+void PbArgs::addLinArg(PyObject *obj)
+{
+ DataElement el = {obj, false};
+ mLinData.push_back(el);
+}
+
+void PbArgs::check()
+{
+ if (has("nocheck"))
+ return;
+
+ for (map<string, DataElement>::iterator it = mData.begin(); it != mData.end(); it++) {
+ if (!it->second.visited)
+ errMsg("Argument '" + it->first + "' unknown");
+ }
+ for (size_t i = 0; i < mLinData.size(); i++) {
+ if (!mLinData[i].visited) {
+ stringstream s;
+ s << "Function does not read argument number #" << i;
+ errMsg(s.str());
+ }
+ }
+}
+
+FluidSolver *PbArgs::obtainParent()
+{
+ FluidSolver *solver = getPtrOpt<FluidSolver>("solver", -1, NULL);
+ if (solver != 0)
+ return solver;
+
+ for (map<string, DataElement>::iterator it = mData.begin(); it != mData.end(); it++) {
+ PbClass *obj = Pb::objFromPy(it->second.obj);
+
+ if (obj) {
+ if (solver == NULL)
+ solver = obj->getParent();
+ }
+ }
+ for (vector<DataElement>::iterator it = mLinData.begin(); it != mLinData.end(); it++) {
+ PbClass *obj = Pb::objFromPy(it->obj);
+
+ if (obj) {
+ if (solver == NULL)
+ solver = obj->getParent();
+ }
+ }
+
+ return solver;
+}
+
+void PbArgs::visit(int number, const string &key)
+{
+ if (number >= 0 && number < (int)mLinData.size())
+ mLinData[number].visited = true;
+ map<string, DataElement>::iterator lu = mData.find(key);
+ if (lu != mData.end())
+ lu->second.visited = true;
+}
+
+PyObject *PbArgs::getItem(const std::string &key, bool strict, ArgLocker *lk)
+{
+ map<string, DataElement>::iterator lu = mData.find(key);
+ if (lu == mData.end()) {
+ if (strict)
+ errMsg("Argument '" + key + "' is not defined.");
+ return NULL;
+ }
+ PbClass *pbo = Pb::objFromPy(lu->second.obj);
+ // try to lock
+ if (pbo && lk)
+ lk->add(pbo);
+ return lu->second.obj;
+}
+
+PyObject *PbArgs::getItem(size_t number, bool strict, ArgLocker *lk)
+{
+ if (number >= mLinData.size()) {
+ if (!strict)
+ return NULL;
+ stringstream s;
+ s << "Argument number #" << number << " not specified.";
+ errMsg(s.str());
+ }
+ PbClass *pbo = Pb::objFromPy(mLinData[number].obj);
+ // try to lock
+ if (pbo && lk)
+ lk->add(pbo);
+ return mLinData[number].obj;
+}
+
+//******************************************************************************
+// ArgLocker class defs
+
+void ArgLocker::add(PbClass *p)
+{
+ if (find(locks.begin(), locks.end(), p) == locks.end()) {
+ locks.push_back(p);
+ p->lock();
+ }
+}
+ArgLocker::~ArgLocker()
+{
+ for (size_t i = 0; i < locks.size(); i++)
+ locks[i]->unlock();
+ locks.clear();
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/helper/pwrapper/pconvert.h b/extern/mantaflow/helper/pwrapper/pconvert.h
new file mode 100644
index 00000000000..9c72b8b57b9
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/pconvert.h
@@ -0,0 +1,251 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Python argument wrappers and conversion tools
+ *
+ ******************************************************************************/
+
+// -----------------------------------------------------------------
+// NOTE:
+// Do not include this file in user code, include "manta.h" instead
+// -----------------------------------------------------------------
+
+#ifdef _MANTA_H
+# ifndef _PCONVERT_H
+# define _PCONVERT_H
+
+# include <string>
+# include <map>
+# include <vector>
+
+namespace Manta {
+template<class T> class Grid;
+
+//! Locks the given PbClass Arguments until ArgLocker goes out of scope
+struct ArgLocker {
+ void add(PbClass *p);
+ ~ArgLocker();
+ std::vector<PbClass *> locks;
+};
+
+PyObject *getPyNone();
+
+// for PbClass-derived classes
+template<class T> T *fromPyPtr(PyObject *obj, std::vector<void *> *tmp)
+{
+ if (PbClass::isNullRef(obj) || PbClass::isNoneRef(obj))
+ return 0;
+ PbClass *pbo = Pb::objFromPy(obj);
+ const std::string &type = Namify<T>::S;
+ if (!pbo || !(pbo->canConvertTo(type)))
+ throw Error("can't convert argument to " + type + "*");
+ return (T *)(pbo);
+}
+
+template<> float *fromPyPtr<float>(PyObject *obj, std::vector<void *> *tmp);
+template<> double *fromPyPtr<double>(PyObject *obj, std::vector<void *> *tmp);
+template<> int *fromPyPtr<int>(PyObject *obj, std::vector<void *> *tmp);
+template<> std::string *fromPyPtr<std::string>(PyObject *obj, std::vector<void *> *tmp);
+template<> bool *fromPyPtr<bool>(PyObject *obj, std::vector<void *> *tmp);
+template<> Vec3 *fromPyPtr<Vec3>(PyObject *obj, std::vector<void *> *tmp);
+template<> Vec3i *fromPyPtr<Vec3i>(PyObject *obj, std::vector<void *> *tmp);
+template<> Vec4 *fromPyPtr<Vec4>(PyObject *obj, std::vector<void *> *tmp);
+template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<void *> *tmp);
+
+PyObject *incref(PyObject *obj);
+template<class T> PyObject *toPy(const T &v)
+{
+ PyObject *obj = v.getPyObject();
+ if (obj) {
+ return incref(obj);
+ }
+ T *co = new T(v);
+ const std::string &type = Namify<typename remove_pointers<T>::type>::S;
+ return Pb::copyObject(co, type);
+}
+template<class T> bool isPy(PyObject *obj)
+{
+ if (PbClass::isNullRef(obj) || PbClass::isNoneRef(obj))
+ return false;
+ PbClass *pbo = Pb::objFromPy(obj);
+ const std::string &type = Namify<typename remove_pointers<T>::type>::S;
+ return pbo && pbo->canConvertTo(type);
+}
+
+template<class T> T fromPy(PyObject *obj)
+{
+ throw Error(
+ "Unknown type conversion. Did you pass a PbClass by value? Instead always pass "
+ "grids/particlesystems/etc. by reference or using a pointer.");
+}
+
+// builtin types
+template<> float fromPy<float>(PyObject *obj);
+template<> double fromPy<double>(PyObject *obj);
+template<> int fromPy<int>(PyObject *obj);
+template<> PyObject *fromPy<PyObject *>(PyObject *obj);
+template<> std::string fromPy<std::string>(PyObject *obj);
+template<> const char *fromPy<const char *>(PyObject *obj);
+template<> bool fromPy<bool>(PyObject *obj);
+template<> Vec3 fromPy<Vec3>(PyObject *obj);
+template<> Vec3i fromPy<Vec3i>(PyObject *obj);
+template<> Vec4 fromPy<Vec4>(PyObject *obj);
+template<> Vec4i fromPy<Vec4i>(PyObject *obj);
+template<> PbType fromPy<PbType>(PyObject *obj);
+template<> PbTypeVec fromPy<PbTypeVec>(PyObject *obj);
+
+template<> PyObject *toPy<int>(const int &v);
+template<> PyObject *toPy<std::string>(const std::string &val);
+template<> PyObject *toPy<float>(const float &v);
+template<> PyObject *toPy<double>(const double &v);
+template<> PyObject *toPy<bool>(const bool &v);
+template<> PyObject *toPy<Vec3i>(const Vec3i &v);
+template<> PyObject *toPy<Vec3>(const Vec3 &v);
+template<> PyObject *toPy<Vec4i>(const Vec4i &v);
+template<> PyObject *toPy<Vec4>(const Vec4 &v);
+typedef PbClass *PbClass_Ptr;
+template<> PyObject *toPy<PbClass *>(const PbClass_Ptr &obj);
+
+template<> bool isPy<float>(PyObject *obj);
+template<> bool isPy<double>(PyObject *obj);
+template<> bool isPy<int>(PyObject *obj);
+template<> bool isPy<PyObject *>(PyObject *obj);
+template<> bool isPy<std::string>(PyObject *obj);
+template<> bool isPy<const char *>(PyObject *obj);
+template<> bool isPy<bool>(PyObject *obj);
+template<> bool isPy<Vec3>(PyObject *obj);
+template<> bool isPy<Vec3i>(PyObject *obj);
+template<> bool isPy<Vec4>(PyObject *obj);
+template<> bool isPy<Vec4i>(PyObject *obj);
+template<> bool isPy<PbType>(PyObject *obj);
+
+//! Encapsulation of python arguments
+class PbArgs {
+ public:
+ PbArgs(PyObject *linargs = NULL, PyObject *dict = NULL);
+ ~PbArgs();
+ void setup(PyObject *linargs = NULL, PyObject *dict = NULL);
+
+ void check();
+ FluidSolver *obtainParent();
+
+ inline int numLinArgs()
+ {
+ return mLinData.size();
+ }
+
+ inline bool has(const std::string &key)
+ {
+ return getItem(key, false) != NULL;
+ }
+ inline void deleteItem(const std::string &key)
+ {
+ if (mData.find(key) != mData.end())
+ mData.erase(mData.find(key));
+ }
+
+ inline PyObject *linArgs()
+ {
+ return mLinArgs;
+ }
+ inline PyObject *kwds()
+ {
+ return mKwds;
+ }
+
+ void addLinArg(PyObject *obj);
+
+ template<class T> inline void add(const std::string &key, T arg)
+ {
+ DataElement el = {toPy(arg), false};
+ mData[key] = el;
+ }
+ template<class T> inline T get(const std::string &key, int number = -1, ArgLocker *lk = NULL)
+ {
+ visit(number, key);
+ PyObject *o = getItem(key, false, lk);
+ if (o)
+ return fromPy<T>(o);
+ o = getItem(number, false, lk);
+ if (o)
+ return fromPy<T>(o);
+ errMsg("Argument '" + key + "' is not defined.");
+ }
+ template<class T>
+ inline T getOpt(const std::string &key, int number, T defarg, ArgLocker *lk = NULL)
+ {
+ visit(number, key);
+ PyObject *o = getItem(key, false, lk);
+ if (o)
+ return fromPy<T>(o);
+ if (number >= 0)
+ o = getItem(number, false, lk);
+ return (o) ? fromPy<T>(o) : defarg;
+ }
+ template<class T>
+ inline T *getPtrOpt(const std::string &key, int number, T *defarg, ArgLocker *lk = NULL)
+ {
+ visit(number, key);
+ PyObject *o = getItem(key, false, lk);
+ if (o)
+ return fromPyPtr<T>(o, &mTmpStorage);
+ if (number >= 0)
+ o = getItem(number, false, lk);
+ return o ? fromPyPtr<T>(o, &mTmpStorage) : defarg;
+ }
+ template<class T> inline T *getPtr(const std::string &key, int number = -1, ArgLocker *lk = NULL)
+ {
+ visit(number, key);
+ PyObject *o = getItem(key, false, lk);
+ if (o)
+ return fromPyPtr<T>(o, &mTmpStorage);
+ o = getItem(number, false, lk);
+ if (o)
+ return fromPyPtr<T>(o, &mTmpStorage);
+ errMsg("Argument '" + key + "' is not defined.");
+ }
+
+ // automatic template type deduction
+ template<class T> bool typeCheck(int num, const std::string &name)
+ {
+ PyObject *o = getItem(name, false, 0);
+ if (!o)
+ o = getItem(num, false, 0);
+ return o ? isPy<typename remove_pointers<T>::type>(o) : false;
+ }
+
+ PbArgs &operator=(const PbArgs &a); // dummy
+ void copy(PbArgs &a);
+ void clear();
+ void visit(int num, const std::string &key);
+
+ static PbArgs EMPTY;
+
+ protected:
+ PyObject *getItem(const std::string &key, bool strict, ArgLocker *lk = NULL);
+ PyObject *getItem(size_t number, bool strict, ArgLocker *lk = NULL);
+
+ struct DataElement {
+ PyObject *obj;
+ bool visited;
+ };
+ std::map<std::string, DataElement> mData;
+ std::vector<DataElement> mLinData;
+ PyObject *mLinArgs, *mKwds;
+ std::vector<void *> mTmpStorage;
+};
+
+} // namespace Manta
+
+# if NUMPY == 1
+# include "numpyWrap.h"
+# endif
+
+# endif
+#endif
diff --git a/extern/mantaflow/helper/pwrapper/pvec3.cpp b/extern/mantaflow/helper/pwrapper/pvec3.cpp
new file mode 100644
index 00000000000..69bde2a2ad0
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/pvec3.cpp
@@ -0,0 +1,414 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vec3 class extension for python
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include <string>
+#include <sstream>
+#include "vectorbase.h"
+#include "structmember.h"
+#include "manta.h"
+
+using namespace std;
+
+namespace Manta {
+
+extern PyTypeObject PbVec3Type;
+
+struct PbVec3 {
+ PyObject_HEAD float data[3];
+};
+
+static void PbVec3Dealloc(PbVec3 *self)
+{
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static PyObject *PbVec3New(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ return type->tp_alloc(type, 0);
+}
+
+static int PbVec3Init(PbVec3 *self, PyObject *args, PyObject *kwds)
+{
+
+ float x1 = numeric_limits<float>::quiet_NaN(), x2 = x1, x3 = x1;
+ if (!PyArg_ParseTuple(args, "|fff", &x1, &x2, &x3))
+ return -1;
+
+ if (!c_isnan(x1)) {
+ self->data[0] = x1;
+ if (!c_isnan(x2) && !c_isnan(x3)) {
+ self->data[1] = x2;
+ self->data[2] = x3;
+ }
+ else {
+ if (!c_isnan(x2) || !c_isnan(x3)) {
+ errMsg("Invalid partial init of vec3");
+ }
+ self->data[1] = x1;
+ self->data[2] = x1;
+ }
+ }
+ else {
+ self->data[0] = 0;
+ self->data[1] = 0;
+ self->data[2] = 0;
+ }
+ return 0;
+}
+
+static PyObject *PbVec3Repr(PbVec3 *self)
+{
+ Manta::Vec3 v(self->data[0], self->data[1], self->data[2]);
+ return PyUnicode_FromFormat(v.toString().c_str());
+}
+
+static PyMemberDef PbVec3Members[] = {
+ {(char *)"x", T_FLOAT, offsetof(PbVec3, data), 0, (char *)"X"},
+ {(char *)"y", T_FLOAT, offsetof(PbVec3, data) + sizeof(float), 0, (char *)"Y"},
+ {(char *)"z", T_FLOAT, offsetof(PbVec3, data) + sizeof(float) * 2, 0, (char *)"Z"},
+ {NULL} // Sentinel
+};
+
+static PyMethodDef PbVec3Methods[] = {
+ //{"name", (PyCFunction)Noddy_name, METH_NOARGS, "Return the name, combining the first and last
+ //name" },
+ {NULL} // Sentinel
+};
+
+// operator overloads
+
+inline PyObject *PbNew(const Vec3 &a)
+{
+ PbVec3 *obj = (PbVec3 *)PbVec3New(&PbVec3Type, 0, 0);
+ obj->data[0] = a.x;
+ obj->data[1] = a.y;
+ obj->data[2] = a.z;
+ return (PyObject *)obj;
+}
+
+#define CONVERTVEC(obj) \
+ Vec3 v##obj; \
+ if (PyObject_TypeCheck(obj, &PbVec3Type)) \
+ v##obj = Vec3(&(((PbVec3 *)obj)->data[0])); \
+ else if (PyFloat_Check(obj)) \
+ v##obj = Vec3(PyFloat_AsDouble(obj)); \
+ else if (PyLong_Check(obj)) \
+ v##obj = Vec3(PyLong_AsDouble(obj)); \
+ else { \
+ Py_INCREF(Py_NotImplemented); \
+ return Py_NotImplemented; \
+ }
+
+#define OPHEADER \
+ if (!PyObject_TypeCheck(a, &PbVec3Type) && !PyObject_TypeCheck(b, &PbVec3Type)) { \
+ Py_INCREF(Py_NotImplemented); \
+ return Py_NotImplemented; \
+ } \
+ CONVERTVEC(a) \
+ CONVERTVEC(b)
+
+#define OPHEADER1 \
+ if (!PyObject_TypeCheck(a, &PbVec3Type)) { \
+ Py_INCREF(Py_NotImplemented); \
+ return Py_NotImplemented; \
+ } \
+ CONVERTVEC(a)
+
+PyObject *PbVec3Add(PyObject *a, PyObject *b)
+{
+ OPHEADER
+ return PbNew(va + vb);
+}
+
+PyObject *PbVec3Sub(PyObject *a, PyObject *b)
+{
+ OPHEADER
+ return PbNew(va - vb);
+}
+
+PyObject *PbVec3Mult(PyObject *a, PyObject *b)
+{
+ OPHEADER
+ return PbNew(va * vb);
+}
+
+PyObject *PbVec3Div(PyObject *a, PyObject *b)
+{
+ OPHEADER
+ return PbNew(va / vb);
+}
+
+PyObject *PbVec3Negative(PyObject *a)
+{
+ OPHEADER1
+ return PbNew(-va);
+}
+
+// numbers are defined subtely different in Py3 (WTF?)
+#if PY_MAJOR_VERSION >= 3
+static PyNumberMethods PbVec3NumberMethods = {
+ (binaryfunc)PbVec3Add, // binaryfunc nb_add;
+ (binaryfunc)PbVec3Sub, // binaryfunc nb_sub;
+ (binaryfunc)PbVec3Mult, // binaryfunc nb_mult;
+ 0, // binaryfunc nb_remainder;
+ 0, // binaryfunc nb_divmod;
+ 0, // ternaryfunc nb_power;
+ (unaryfunc)PbVec3Negative, // unaryfunc nb_negative;
+ 0, // unaryfunc nb_positive;
+ 0, // unaryfunc nb_absolute;
+ 0, // inquiry nb_bool;
+ 0, // unaryfunc nb_invert;
+ 0, // binaryfunc nb_lshift;
+ 0, // binaryfunc nb_rshift;
+ 0, // binaryfunc nb_and;
+ 0, // binaryfunc nb_xor;
+ 0, // binaryfunc nb_or;
+ 0, // unaryfunc nb_int;
+ 0, // void *nb_reserved;
+ 0, // unaryfunc nb_float;
+ 0, // binaryfunc nb_inplace_add;
+ 0, // binaryfunc nb_inplace_subtract;
+ 0, // binaryfunc nb_inplace_multiply;
+ 0, // binaryfunc nb_inplace_remainder;
+ 0, // ternaryfunc nb_inplace_power;
+ 0, // binaryfunc nb_inplace_lshift;
+ 0, // binaryfunc nb_inplace_rshift;
+ 0, // binaryfunc nb_inplace_and;
+ 0, // binaryfunc nb_inplace_xor;
+ 0, // binaryfunc nb_inplace_or;
+
+ 0, // binaryfunc nb_floor_divide;
+ (binaryfunc)PbVec3Div, // binaryfunc nb_true_divide;
+ 0, // binaryfunc nb_inplace_floor_divide;
+ 0, // binaryfunc nb_inplace_true_divide;
+
+ 0 // unaryfunc nb_index;
+};
+#else
+static PyNumberMethods PbVec3NumberMethods = {
+ (binaryfunc)PbVec3Add, // binaryfunc nb_add;
+ (binaryfunc)PbVec3Sub, // binaryfunc nb_sub;
+ (binaryfunc)PbVec3Mult, // binaryfunc nb_mult;
+ 0, // binaryfunc nb_divide;
+ 0, // binaryfunc nb_remainder;
+ 0, // binaryfunc nb_divmod;
+ 0, // ternaryfunc nb_power;
+ (unaryfunc)PbVec3Negative, // unaryfunc nb_negative;
+ 0, // unaryfunc nb_positive;
+ 0, // unaryfunc nb_absolute;
+ 0, // inquiry nb_nonzero;
+ 0, // unaryfunc nb_invert;
+ 0, // binaryfunc nb_lshift;
+ 0, // binaryfunc nb_rshift;
+ 0, // binaryfunc nb_and;
+ 0, // binaryfunc nb_xor;
+ 0, // binaryfunc nb_or;
+ 0, // coercion nb_coerce;
+ 0, // unaryfunc nb_int;
+ 0, // unaryfunc nb_long;
+ 0, // unaryfunc nb_float;
+ 0, // unaryfunc nb_oct;
+ 0, // unaryfunc nb_hex;
+ 0, // binaryfunc nb_inplace_add;
+ 0, // binaryfunc nb_inplace_subtract;
+ 0, // binaryfunc nb_inplace_multiply;
+ 0, // binaryfunc nb_inplace_divide;
+ 0, // binaryfunc nb_inplace_remainder;
+ 0, // ternaryfunc nb_inplace_power;
+ 0, // binaryfunc nb_inplace_lshift;
+ 0, // binaryfunc nb_inplace_rshift;
+ 0, // binaryfunc nb_inplace_and;
+ 0, // binaryfunc nb_inplace_xor;
+ 0, // binaryfunc nb_inplace_or;
+ 0, // binaryfunc nb_floor_divide;
+ (binaryfunc)PbVec3Div, // binaryfunc nb_true_divide;
+ 0, // binaryfunc nb_inplace_floor_divide;
+ 0, // binaryfunc nb_inplace_true_divide;
+ 0, // unaryfunc nb_index;
+};
+#endif
+
+PyTypeObject PbVec3Type = {
+ PyVarObject_HEAD_INIT(NULL, 0) "manta.vec3", /* tp_name */
+ sizeof(PbVec3), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)PbVec3Dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)PbVec3Repr, /* tp_repr */
+ &PbVec3NumberMethods, /* 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 */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ "float vector type", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ PbVec3Methods, /* tp_methods */
+ PbVec3Members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)PbVec3Init, /* tp_init */
+ 0, /* tp_alloc */
+ PbVec3New, /* tp_new */
+};
+
+inline PyObject *castPy(PyTypeObject *p)
+{
+ return reinterpret_cast<PyObject *>(static_cast<void *>(p));
+}
+
+// 4d vector
+
+extern PyTypeObject PbVec4Type;
+
+struct PbVec4 {
+ PyObject_HEAD float data[4];
+};
+
+static PyMethodDef PbVec4Methods[] = {
+ {NULL} // Sentinel
+};
+
+static PyMemberDef PbVec4Members[] = {
+ {(char *)"x", T_FLOAT, offsetof(PbVec4, data), 0, (char *)"X"},
+ {(char *)"y", T_FLOAT, offsetof(PbVec4, data) + sizeof(float) * 1, 0, (char *)"Y"},
+ {(char *)"z", T_FLOAT, offsetof(PbVec4, data) + sizeof(float) * 2, 0, (char *)"Z"},
+ {(char *)"t", T_FLOAT, offsetof(PbVec4, data) + sizeof(float) * 3, 0, (char *)"T"},
+ {NULL} // Sentinel
+};
+
+static void PbVec4Dealloc(PbVec4 *self)
+{
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static PyObject *PbVec4New(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ return type->tp_alloc(type, 0);
+}
+
+static int PbVec4Init(PbVec4 *self, PyObject *args, PyObject *kwds)
+{
+
+ float x1 = numeric_limits<float>::quiet_NaN(), x2 = x1, x3 = x1, x4 = x1;
+ if (!PyArg_ParseTuple(args, "|ffff", &x1, &x2, &x3, &x4))
+ return -1;
+
+ if (!c_isnan(x1)) {
+ self->data[0] = x1;
+ if (!c_isnan(x2) && !c_isnan(x3) && !c_isnan(x4)) {
+ self->data[1] = x2;
+ self->data[2] = x3;
+ self->data[3] = x4;
+ }
+ else {
+ if (!c_isnan(x2) || !c_isnan(x3) || !c_isnan(x4)) {
+ errMsg("Invalid partial init of vec4");
+ }
+ self->data[1] = self->data[2] = self->data[3] = x1;
+ }
+ }
+ else {
+ self->data[0] = self->data[1] = self->data[2] = self->data[3] = 0;
+ }
+ return 0;
+}
+
+static PyObject *PbVec4Repr(PbVec4 *self)
+{
+ Manta::Vec4 v(self->data[0], self->data[1], self->data[2], self->data[3]);
+ return PyUnicode_FromFormat(v.toString().c_str());
+}
+
+PyTypeObject PbVec4Type = {
+ PyVarObject_HEAD_INIT(NULL, 0) "manta.vec4", /* tp_name */
+ sizeof(PbVec4), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)PbVec4Dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)PbVec4Repr, /* tp_repr */
+ NULL, // &PbVec4NumberMethods, /* 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 */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ "float vector type", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ PbVec4Methods, /* tp_methods */
+ PbVec4Members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)PbVec4Init, /* tp_init */
+ 0, /* tp_alloc */
+ PbVec4New, /* tp_new */
+};
+
+// register
+
+void PbVecInitialize(PyObject *module)
+{
+ if (PyType_Ready(&PbVec3Type) < 0)
+ errMsg("can't initialize Vec3 type");
+ Py_INCREF(castPy(&PbVec3Type));
+ PyModule_AddObject(module, "vec3", (PyObject *)&PbVec3Type);
+
+ if (PyType_Ready(&PbVec4Type) < 0)
+ errMsg("can't initialize Vec4 type");
+ Py_INCREF(castPy(&PbVec4Type));
+ PyModule_AddObject(module, "vec4", (PyObject *)&PbVec4Type);
+}
+const static Pb::Register _REG(PbVecInitialize);
+
+} // namespace Manta
diff --git a/extern/mantaflow/helper/pwrapper/pythonInclude.h b/extern/mantaflow/helper/pwrapper/pythonInclude.h
new file mode 100644
index 00000000000..0f78c6641d2
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/pythonInclude.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Base class for particle systems
+ *
+ ******************************************************************************/
+
+#ifndef _PYTHONINCLUDE_H
+#define _PYTHONINCLUDE_H
+
+#if defined(WIN32) || defined(_WIN32)
+
+// note - we have to include these first!
+# include <string>
+# include <vector>
+# include <iostream>
+
+#endif
+
+// the PYTHON_DEBUG_WITH_RELEASE define enables linking with python debug libraries
+#if (defined(_DEBUG) || (DEBUG == 1)) && defined(DEBUG_PYTHON_WITH_RELEASE)
+
+// special handling, disable linking with debug version of python libs
+# undef _DEBUG
+# define NDEBUG
+# include <Python.h>
+# if NUMPY == 1
+# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+# include "numpy/arrayobject.h"
+# endif
+# define _DEBUG
+# undef NDEBUG
+
+#else
+# include <Python.h>
+# if NUMPY == 1
+# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+# include "numpy/arrayobject.h"
+# endif
+#endif
+
+#endif
diff --git a/extern/mantaflow/helper/pwrapper/registry.cpp b/extern/mantaflow/helper/pwrapper/registry.cpp
new file mode 100644
index 00000000000..332b9e158ac
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/registry.cpp
@@ -0,0 +1,784 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Auto python registry
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "pythonInclude.h"
+#include "structmember.h"
+#include "manta.h"
+
+using namespace std;
+
+const string gDefaultModuleName = "manta";
+
+namespace Pb {
+
+//******************************************************************************
+// Custom object definition
+
+struct Method {
+ Method(const string &n, const string &d, GenericFunction f) : name(n), doc(d), func(f)
+ {
+ }
+ string name, doc;
+ GenericFunction func;
+
+ PyMethodDef def()
+ {
+ PyMethodDef def = {&name[0], (PyCFunction)func, METH_VARARGS | METH_KEYWORDS, &doc[0]};
+ return def;
+ }
+};
+struct GetSet {
+ GetSet() : getter(0), setter(0)
+ {
+ }
+ GetSet(const string &n, const string &d, Getter g, Setter s)
+ : name(n), doc(d), getter(g), setter(s)
+ {
+ }
+ string name, doc;
+ Getter getter;
+ Setter setter;
+
+ PyGetSetDef def()
+ {
+ PyGetSetDef def = {&name[0], getter, setter, &doc[0], NULL};
+ return def;
+ }
+};
+
+struct ClassData {
+ string cName, pyName;
+ string cPureName, cTemplate;
+ InitFunc init;
+ PyTypeObject typeInfo;
+ PyNumberMethods numInfo;
+ // PySequenceMethods seqInfo;
+ vector<Method> methods;
+ map<string, GetSet> getset;
+ map<string, OperatorFunction> ops;
+ ClassData *baseclass;
+ string baseclassName;
+ Constructor constructor;
+
+ vector<PyMethodDef> genMethods;
+ vector<PyGetSetDef> genGetSet;
+};
+
+struct PbObject {
+ PyObject_HEAD Manta::PbClass *instance;
+ ClassData *classdef;
+};
+
+//******************************************************
+// Internal wrapper class
+
+//! Registers all classes and methods exposed to Python.
+/*! This class is only used internally by Pb:: framwork.
+ * Please use the functionality of PbClass to lookup and translate pointers. */
+class WrapperRegistry {
+ public:
+ static WrapperRegistry &instance();
+ void addClass(const std::string &name,
+ const std::string &internalName,
+ const std::string &baseclass);
+ void addEnumEntry(const std::string &name, int value);
+ void addExternalInitializer(InitFunc func);
+ void addMethod(const std::string &classname,
+ const std::string &methodname,
+ GenericFunction method);
+ void addOperator(const std::string &classname,
+ const std::string &methodname,
+ OperatorFunction method);
+ void addConstructor(const std::string &classname, Constructor method);
+ void addGetSet(const std::string &classname,
+ const std::string &property,
+ Getter getfunc,
+ Setter setfunc);
+ void addPythonPath(const std::string &path);
+ void addPythonCode(const std::string &file, const std::string &code);
+ PyObject *createPyObject(const std::string &classname,
+ const std::string &name,
+ Manta::PbArgs &args,
+ Manta::PbClass *parent);
+ void construct(const std::string &scriptname, const vector<string> &args);
+ void cleanup();
+ void renameObjects();
+ void runPreInit();
+ PyObject *initModule();
+ ClassData *lookup(const std::string &name);
+ bool canConvert(ClassData *from, ClassData *to);
+
+ private:
+ ClassData *getOrConstructClass(const string &name);
+ void registerBaseclasses();
+ void registerDummyTypes();
+ void registerMeta();
+ void addConstants(PyObject *module);
+ void registerOperators(ClassData *cls);
+ void addParentMethods(ClassData *cls, ClassData *base);
+ WrapperRegistry();
+ std::map<std::string, ClassData *> mClasses;
+ std::vector<ClassData *> mClassList;
+ std::vector<InitFunc> mExtInitializers;
+ std::vector<std::string> mPaths;
+ std::string mCode, mScriptName;
+ std::vector<std::string> args;
+ std::map<std::string, int> mEnumValues;
+};
+
+//******************************************************************************
+// Callback functions
+
+PyObject *cbGetClass(PbObject *self, void *cl)
+{
+ return Manta::toPy(self->classdef->cPureName);
+}
+
+PyObject *cbGetTemplate(PbObject *self, void *cl)
+{
+ return Manta::toPy(self->classdef->cTemplate);
+}
+
+PyObject *cbGetCName(PbObject *self, void *cl)
+{
+ return Manta::toPy(self->classdef->cName);
+}
+
+void cbDealloc(PbObject *self)
+{
+ // cout << "dealloc " << self->instance->getName() << " " << self->classdef->cName << endl;
+ if (self->instance) {
+#ifndef BLENDER
+ // don't delete top-level objects
+ if (self->instance->getParent() != self->instance)
+ delete self->instance;
+#else
+ // in Blender we *have* to delete all objects
+ delete self->instance;
+#endif
+ }
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+PyObject *cbNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PbObject *self = (PbObject *)type->tp_alloc(type, 0);
+ if (self != NULL) {
+ // lookup and link classdef
+ self->classdef = WrapperRegistry::instance().lookup(type->tp_name);
+ self->instance = NULL;
+ // cout << "creating " << self->classdef->cName << endl;
+ }
+ else
+ errMsg("can't allocate new python class object");
+ return (PyObject *)self;
+}
+
+int cbDisableConstructor(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ errMsg("Can't instantiate a class template without template arguments");
+ return -1;
+}
+
+PyMODINIT_FUNC PyInit_Main(void)
+{
+ MantaEnsureRegistration();
+#if PY_MAJOR_VERSION >= 3
+ return WrapperRegistry::instance().initModule();
+#else
+ WrapperRegistry::instance().initModule();
+#endif
+}
+
+//******************************************************
+// WrapperRegistry
+
+WrapperRegistry::WrapperRegistry()
+{
+ addClass("__modclass__", "__modclass__", "");
+ addClass("PbClass", "PbClass", "");
+}
+
+ClassData *WrapperRegistry::getOrConstructClass(const string &classname)
+{
+ map<string, ClassData *>::iterator it = mClasses.find(classname);
+
+ if (it != mClasses.end())
+ return it->second;
+ ClassData *data = new ClassData;
+ data->cName = classname;
+ data->cPureName = classname;
+ data->cTemplate = "";
+ size_t tplIdx = classname.find('<');
+ if (tplIdx != string::npos) {
+ data->cPureName = classname.substr(0, tplIdx);
+ data->cTemplate = classname.substr(tplIdx + 1, classname.find('>') - tplIdx - 1);
+ }
+ data->baseclass = NULL;
+ data->constructor = cbDisableConstructor;
+ mClasses[classname] = data;
+ mClassList.push_back(data);
+ return data;
+}
+
+void replaceAll(string &source, string const &find, string const &replace)
+{
+ for (string::size_type i = 0; (i = source.find(find, i)) != std::string::npos;) {
+ source.replace(i, find.length(), replace);
+ i += replace.length() - find.length() + 1;
+ }
+}
+
+void WrapperRegistry::addClass(const string &pyName,
+ const string &internalName,
+ const string &baseclass)
+{
+ ClassData *data = getOrConstructClass(internalName);
+
+ // regularize python name
+ string pythonName = pyName;
+ replaceAll(pythonName, "<", "_");
+ replaceAll(pythonName, ">", "");
+ replaceAll(pythonName, ",", "_");
+
+ if (data->pyName.empty())
+ data->pyName = pythonName;
+ mClasses[pythonName] = data;
+ if (!baseclass.empty())
+ data->baseclassName = baseclass;
+}
+
+void WrapperRegistry::addEnumEntry(const string &name, int value)
+{
+ /// Gather static definitions to add them as static python objects afterwards
+ if (mEnumValues.insert(std::make_pair(name, value)).second == false) {
+ errMsg("Enum entry '" + name + "' already existing...");
+ }
+}
+
+void WrapperRegistry::addExternalInitializer(InitFunc func)
+{
+ mExtInitializers.push_back(func);
+}
+
+void WrapperRegistry::addPythonPath(const string &path)
+{
+ mPaths.push_back(path);
+}
+
+void WrapperRegistry::addPythonCode(const string &file, const string &code)
+{
+ mCode += code + "\n";
+}
+
+void WrapperRegistry::addGetSet(const string &classname,
+ const string &property,
+ Getter getfunc,
+ Setter setfunc)
+{
+ ClassData *classdef = getOrConstructClass(classname);
+ GetSet &def = classdef->getset[property];
+ if (def.name.empty()) {
+ def.name = property;
+ def.doc = property;
+ }
+ if (getfunc)
+ def.getter = getfunc;
+ if (setfunc)
+ def.setter = setfunc;
+}
+
+void WrapperRegistry::addMethod(const string &classname,
+ const string &methodname,
+ GenericFunction func)
+{
+ string aclass = classname;
+ if (aclass.empty())
+ aclass = "__modclass__";
+
+ ClassData *classdef = getOrConstructClass(aclass);
+ for (int i = 0; i < (int)classdef->methods.size(); i++)
+ if (classdef->methods[i].name == methodname)
+ return; // avoid duplicates
+ classdef->methods.push_back(Method(methodname, methodname, func));
+}
+
+void WrapperRegistry::addOperator(const string &classname,
+ const string &methodname,
+ OperatorFunction func)
+{
+ if (classname.empty())
+ errMsg("PYTHON operators have to be defined within classes.");
+
+ string op = methodname.substr(8);
+ ClassData *classdef = getOrConstructClass(classname);
+ classdef->ops[op] = func;
+}
+
+void WrapperRegistry::addConstructor(const string &classname, Constructor func)
+{
+ ClassData *classdef = getOrConstructClass(classname);
+ classdef->constructor = func;
+}
+
+void WrapperRegistry::addParentMethods(ClassData *cur, ClassData *base)
+{
+ if (base == 0)
+ return;
+
+ for (vector<Method>::iterator it = base->methods.begin(); it != base->methods.end(); ++it)
+ addMethod(cur->cName, it->name, it->func);
+
+ for (map<string, GetSet>::iterator it = base->getset.begin(); it != base->getset.end(); ++it)
+ addGetSet(cur->cName, it->first, it->second.getter, it->second.setter);
+
+ for (map<string, OperatorFunction>::iterator it = base->ops.begin(); it != base->ops.end(); ++it)
+ cur->ops[it->first] = it->second;
+
+ addParentMethods(cur, base->baseclass);
+}
+
+void WrapperRegistry::registerBaseclasses()
+{
+ for (int i = 0; i < (int)mClassList.size(); i++) {
+ string bname = mClassList[i]->baseclassName;
+ if (!bname.empty()) {
+ mClassList[i]->baseclass = lookup(bname);
+ if (!mClassList[i]->baseclass)
+ errMsg("Registering class '" + mClassList[i]->cName + "' : Base class '" + bname +
+ "' not found");
+ }
+ }
+
+ for (int i = 0; i < (int)mClassList.size(); i++) {
+ addParentMethods(mClassList[i], mClassList[i]->baseclass);
+ }
+}
+
+void WrapperRegistry::registerMeta()
+{
+ for (int i = 0; i < (int)mClassList.size(); i++) {
+ mClassList[i]->getset["_class"] = GetSet("_class", "C class name", (Getter)cbGetClass, 0);
+ mClassList[i]->getset["_cname"] = GetSet("_cname", "Full C name", (Getter)cbGetCName, 0);
+ mClassList[i]->getset["_T"] = GetSet("_T", "C template argument", (Getter)cbGetTemplate, 0);
+ }
+}
+
+void WrapperRegistry::registerOperators(ClassData *cls)
+{
+ PyNumberMethods &num = cls->numInfo;
+ for (map<string, OperatorFunction>::iterator it = cls->ops.begin(); it != cls->ops.end(); it++) {
+ const string &op = it->first;
+ OperatorFunction func = it->second;
+ if (op == "+=")
+ num.nb_inplace_add = func;
+ else if (op == "-=")
+ num.nb_inplace_subtract = func;
+ else if (op == "*=")
+ num.nb_inplace_multiply = func;
+ else if (op == "+")
+ num.nb_add = func;
+ else if (op == "-")
+ num.nb_subtract = func;
+ else if (op == "*")
+ num.nb_multiply = func;
+#if PY_MAJOR_VERSION < 3
+ else if (op == "/=")
+ num.nb_inplace_divide = func;
+ else if (op == "/")
+ num.nb_divide = func;
+#else
+ else if (op == "/=")
+ num.nb_inplace_true_divide = func;
+ else if (op == "/")
+ num.nb_true_divide = func;
+#endif
+ else
+ errMsg("PYTHON operator " + op + " not supported");
+ }
+}
+
+void WrapperRegistry::registerDummyTypes()
+{
+ vector<string> add;
+ for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
+ string cName = (*it)->cName;
+ if (cName.find('<') != string::npos)
+ add.push_back(cName.substr(0, cName.find('<')));
+ }
+ for (int i = 0; i < (int)add.size(); i++)
+ addClass(add[i], add[i], "");
+}
+
+ClassData *WrapperRegistry::lookup(const string &name)
+{
+ for (map<string, ClassData *>::iterator it = mClasses.begin(); it != mClasses.end(); ++it) {
+ if (it->first == name || it->second->cName == name)
+ return it->second;
+ }
+ return NULL;
+}
+
+void WrapperRegistry::cleanup()
+{
+ for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
+ delete *it;
+ }
+ mClasses.clear();
+ mClassList.clear();
+}
+
+WrapperRegistry &WrapperRegistry::instance()
+{
+ static WrapperRegistry inst;
+ return inst;
+}
+
+bool WrapperRegistry::canConvert(ClassData *from, ClassData *to)
+{
+ if (from == to)
+ return true;
+ if (from->baseclass)
+ return canConvert(from->baseclass, to);
+ return false;
+}
+
+void WrapperRegistry::addConstants(PyObject *module)
+{
+ // expose arguments
+ PyObject *list = PyList_New(args.size());
+ for (int i = 0; i < (int)args.size(); i++)
+ PyList_SET_ITEM(list, i, Manta::toPy(args[i]));
+ PyModule_AddObject(module, "args", list);
+ PyModule_AddObject(module, "SCENEFILE", Manta::toPy(mScriptName));
+
+ // expose compile flags
+#ifdef DEBUG
+ PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(false));
+#endif
+#ifdef MANTA_MT
+ PyModule_AddObject(module, "MT", Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module, "MT", Manta::toPy<bool>(false));
+#endif
+#ifdef GUI
+ PyModule_AddObject(module, "GUI", Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module, "GUI", Manta::toPy<bool>(false));
+#endif
+#if FLOATINGPOINT_PRECISION == 2
+ PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(false));
+#endif
+ // cuda off for now
+ PyModule_AddObject(module, "CUDA", Manta::toPy<bool>(false));
+
+ // expose enum entries
+ std::map<std::string, int>::iterator it;
+ for (it = mEnumValues.begin(); it != mEnumValues.end(); it++) {
+ PyModule_AddObject(module, it->first.c_str(), Manta::toPy(it->second));
+ // Alternative would be:
+ // e.g. PyModule_AddIntConstant(module, "FlagFluid", 1);
+ }
+}
+
+void WrapperRegistry::runPreInit()
+{
+ // add python directories to path
+ PyObject *sys_path = PySys_GetObject((char *)"path");
+ for (size_t i = 0; i < mPaths.size(); i++) {
+ PyObject *path = Manta::toPy(mPaths[i]);
+ if (sys_path == NULL || path == NULL || PyList_Append(sys_path, path) < 0) {
+ errMsg("unable to set python path");
+ }
+ Py_DECREF(path);
+ }
+ if (!mCode.empty()) {
+ mCode = "from manta import *\n" + mCode;
+ PyRun_SimpleString(mCode.c_str());
+ }
+}
+
+PyObject *WrapperRegistry::createPyObject(const string &classname,
+ const string &name,
+ Manta::PbArgs &args,
+ Manta::PbClass *parent)
+{
+ ClassData *classdef = lookup(classname);
+ if (!classdef)
+ errMsg("Class " + classname + " doesn't exist.");
+
+ // create object
+ PyObject *obj = cbNew(&classdef->typeInfo, NULL, NULL);
+ PbObject *self = (PbObject *)obj;
+ PyObject *nkw = 0;
+
+ if (args.kwds())
+ nkw = PyDict_Copy(args.kwds());
+ else
+ nkw = PyDict_New();
+
+ PyObject *nocheck = Py_BuildValue("s", "yes");
+ PyDict_SetItemString(nkw, "nocheck", nocheck);
+ if (parent)
+ PyDict_SetItemString(nkw, "parent", parent->getPyObject());
+
+ // create instance
+ if (self->classdef->constructor(obj, args.linArgs(), nkw) < 0)
+ errMsg("error raised in constructor"); // assume condition is already set
+
+ Py_DECREF(nkw);
+ Py_DECREF(nocheck);
+ self->instance->setName(name);
+
+ return obj;
+}
+
+// prepare typeinfo and register python module
+void WrapperRegistry::construct(const string &scriptname, const vector<string> &args)
+{
+ mScriptName = scriptname;
+ this->args = args;
+
+ registerBaseclasses();
+ registerMeta();
+ registerDummyTypes();
+
+ // work around for certain gcc versions, cast to char*
+ PyImport_AppendInittab((char *)gDefaultModuleName.c_str(), PyInit_Main);
+}
+
+inline PyObject *castPy(PyTypeObject *p)
+{
+ return reinterpret_cast<PyObject *>(static_cast<void *>(p));
+}
+
+PyObject *WrapperRegistry::initModule()
+{
+ // generate and terminate all method lists
+ PyMethodDef sentinelFunc = {NULL, NULL, 0, NULL};
+ PyGetSetDef sentinelGetSet = {NULL, NULL, NULL, NULL, NULL};
+ for (int i = 0; i < (int)mClassList.size(); i++) {
+ ClassData *cls = mClassList[i];
+ cls->genMethods.clear();
+ cls->genGetSet.clear();
+ for (vector<Method>::iterator i2 = cls->methods.begin(); i2 != cls->methods.end(); ++i2)
+ cls->genMethods.push_back(i2->def());
+ for (map<string, GetSet>::iterator i2 = cls->getset.begin(); i2 != cls->getset.end(); ++i2)
+ cls->genGetSet.push_back(i2->second.def());
+
+ cls->genMethods.push_back(sentinelFunc);
+ cls->genGetSet.push_back(sentinelGetSet);
+ }
+
+ // prepare module info
+#if PY_MAJOR_VERSION >= 3
+ static PyModuleDef MainModule = {PyModuleDef_HEAD_INIT,
+ gDefaultModuleName.c_str(),
+ "Bridge module to the C++ solver",
+ -1,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL};
+ // get generic methods (plugin functions)
+ MainModule.m_methods = &mClasses["__modclass__"]->genMethods[0];
+
+ // create module
+ PyObject *module = PyModule_Create(&MainModule);
+#else
+ PyObject *module = Py_InitModule(gDefaultModuleName.c_str(),
+ &mClasses["__modclass__"]->genMethods[0]);
+#endif
+ if (module == NULL)
+ return NULL;
+
+ // load classes
+ for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
+ ClassData &data = **it;
+ char *nameptr = (char *)data.pyName.c_str();
+
+ // define numeric substruct
+ PyNumberMethods *num = 0;
+ if (!data.ops.empty()) {
+ num = &data.numInfo;
+ memset(num, 0, sizeof(PyNumberMethods));
+ registerOperators(&data);
+ }
+
+ // define python classinfo
+ PyTypeObject t = {
+ PyVarObject_HEAD_INIT(NULL, 0)(char *) data.pyName.c_str(), // tp_name
+ sizeof(PbObject), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)cbDealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_reserved
+ 0, // tp_repr
+ num, // 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
+ nameptr, // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ &data.genMethods[0], // tp_methods
+ 0, // tp_members
+ &data.genGetSet[0], // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)(data.constructor), // tp_init
+ 0, // tp_alloc
+ cbNew // tp_new
+ };
+ data.typeInfo = t;
+
+ if (PyType_Ready(&data.typeInfo) < 0)
+ continue;
+
+ for (map<string, ClassData *>::iterator i2 = mClasses.begin(); i2 != mClasses.end(); ++i2) {
+ if (*it != i2->second)
+ continue;
+ // register all aliases
+ Py_INCREF(castPy(&data.typeInfo));
+ PyModule_AddObject(module, (char *)i2->first.c_str(), (PyObject *)&data.typeInfo);
+ }
+ }
+
+ // externals
+ for (vector<InitFunc>::iterator it = mExtInitializers.begin(); it != mExtInitializers.end();
+ ++it) {
+ (*it)(module);
+ }
+
+ addConstants(module);
+
+ return module;
+}
+
+//******************************************************
+// Register members and exposed functions
+
+void setup(const std::string &filename, const std::vector<std::string> &args)
+{
+ WrapperRegistry::instance().construct(filename, args);
+ Py_Initialize();
+ WrapperRegistry::instance().runPreInit();
+}
+
+void finalize()
+{
+ Py_Finalize();
+ WrapperRegistry::instance().cleanup();
+}
+
+bool canConvert(PyObject *obj, const string &classname)
+{
+ ClassData *from = ((PbObject *)obj)->classdef;
+ ClassData *dest = WrapperRegistry::instance().lookup(classname);
+ if (!dest)
+ errMsg("Classname '" + classname + "' is not registered.");
+ return WrapperRegistry::instance().canConvert(from, dest);
+}
+
+Manta::PbClass *objFromPy(PyObject *obj)
+{
+ if (Py_TYPE(obj)->tp_dealloc != (destructor)cbDealloc) // not a manta object
+ return NULL;
+
+ return ((PbObject *)obj)->instance;
+}
+
+PyObject *copyObject(Manta::PbClass *cls, const string &classname)
+{
+ ClassData *classdef = WrapperRegistry::instance().lookup(classname);
+ assertMsg(classdef, "python class " + classname + " does not exist.");
+
+ // allocate new object
+ PbObject *obj = (PbObject *)classdef->typeInfo.tp_alloc(&(classdef->typeInfo), 0);
+ assertMsg(obj, "cannot allocate new python object");
+
+ obj->classdef = classdef;
+ cls->registerObject((PyObject *)obj, 0);
+
+ return cls->getPyObject();
+}
+
+Manta::PbClass *createPy(const std::string &classname,
+ const std::string &name,
+ Manta::PbArgs &args,
+ Manta::PbClass *parent)
+{
+ PyObject *obj = WrapperRegistry::instance().createPyObject(classname, name, args, parent);
+ return ((PbObject *)obj)->instance;
+}
+
+void setReference(Manta::PbClass *cls, PyObject *obj)
+{
+ ((PbObject *)obj)->instance = cls;
+}
+
+Register::Register(const string &className, const string &funcName, GenericFunction func)
+{
+ WrapperRegistry::instance().addMethod(className, funcName, func);
+}
+Register::Register(const string &className, const string &funcName, OperatorFunction func)
+{
+ WrapperRegistry::instance().addOperator(className, funcName, func);
+}
+Register::Register(const string &className, const string &funcName, Constructor func)
+{
+ WrapperRegistry::instance().addConstructor(className, func);
+}
+Register::Register(const string &className, const string &property, Getter getter, Setter setter)
+{
+ WrapperRegistry::instance().addGetSet(className, property, getter, setter);
+}
+Register::Register(const string &className, const string &pyName, const string &baseClass)
+{
+ WrapperRegistry::instance().addClass(pyName, className, baseClass);
+}
+Register::Register(const string &name, const int value)
+{
+ WrapperRegistry::instance().addEnumEntry(name, value);
+}
+Register::Register(const string &file, const string &pythonCode)
+{
+ WrapperRegistry::instance().addPythonCode(file, pythonCode);
+}
+Register::Register(InitFunc func)
+{
+ WrapperRegistry::instance().addExternalInitializer(func);
+}
+
+} // namespace Pb
diff --git a/extern/mantaflow/helper/pwrapper/registry.h b/extern/mantaflow/helper/pwrapper/registry.h
new file mode 100644
index 00000000000..139863df85d
--- /dev/null
+++ b/extern/mantaflow/helper/pwrapper/registry.h
@@ -0,0 +1,106 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Auto python registry
+ *
+ ******************************************************************************/
+
+#ifndef _REGISTRY_H
+#define _REGISTRY_H
+
+#include <string>
+#include <vector>
+
+// forward declaration to minimize Python.h includes
+#ifndef PyObject_HEAD
+# ifndef PyObject_Fake
+struct _object;
+typedef _object PyObject;
+# define PyObject_Fake
+# endif
+#endif
+
+namespace Manta {
+class PbClass;
+class PbArgs;
+} // namespace Manta
+
+// **************************************************
+// NOTE
+// Everything in this file is intend only for internal
+// use by the generated wrappers or pclass/pconvert.
+// For user code, use the functionality exposed in
+// pclass.h / pconvert.h instead.
+// **************************************************
+
+// Used to turn names into strings
+namespace Manta {
+template<class T> struct Namify {
+ static const char *S;
+};
+} // namespace Manta
+namespace Pb {
+
+// internal registry access
+void setup(const std::string &filename, const std::vector<std::string> &args);
+void finalize();
+bool canConvert(PyObject *obj, const std::string &to);
+Manta::PbClass *objFromPy(PyObject *obj);
+Manta::PbClass *createPy(const std::string &classname,
+ const std::string &name,
+ Manta::PbArgs &args,
+ Manta::PbClass *parent);
+void setReference(Manta::PbClass *cls, PyObject *obj);
+PyObject *copyObject(Manta::PbClass *cls, const std::string &classname);
+void MantaEnsureRegistration();
+
+#ifdef BLENDER
+# ifdef PyMODINIT_FUNC
+PyMODINIT_FUNC PyInit_Main(void);
+# endif
+#endif
+
+// callback type
+typedef void (*InitFunc)(PyObject *);
+typedef PyObject *(*GenericFunction)(PyObject *self, PyObject *args, PyObject *kwds);
+typedef PyObject *(*OperatorFunction)(PyObject *self, PyObject *o);
+typedef int (*Constructor)(PyObject *self, PyObject *args, PyObject *kwds);
+typedef PyObject *(*Getter)(PyObject *self, void *closure);
+typedef int (*Setter)(PyObject *self, PyObject *value, void *closure);
+
+//! Auto registry of python methods and classes
+struct Register {
+ //! register method
+ Register(const std::string &className, const std::string &funcName, GenericFunction func);
+ //! register operator
+ Register(const std::string &className, const std::string &funcName, OperatorFunction func);
+ //! register constructor
+ Register(const std::string &className, const std::string &funcName, Constructor func);
+ //! register getter/setter
+ Register(const std::string &className,
+ const std::string &property,
+ Getter getter,
+ Setter setter);
+ //! register class
+ Register(const std::string &className, const std::string &pyName, const std::string &baseClass);
+ //! register enum entry
+ Register(const std::string &name, const int value);
+ //! register python code
+ Register(const std::string &file, const std::string &pythonCode);
+ //! register external code
+ Register(InitFunc func);
+};
+
+#define KEEP_UNUSED(var) \
+ do { \
+ (void)var; \
+ } while (false);
+
+} // namespace Pb
+#endif
diff --git a/extern/mantaflow/helper/util/integrator.h b/extern/mantaflow/helper/util/integrator.h
new file mode 100644
index 00000000000..5b1b02a5197
--- /dev/null
+++ b/extern/mantaflow/helper/util/integrator.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Helper functions for simple integration
+ *
+ ******************************************************************************/
+
+#ifndef _INTEGRATE_H
+#define _INTEGRATE_H
+
+#include <vector>
+#include "vectorbase.h"
+#include "kernel.h"
+
+namespace Manta {
+
+enum IntegrationMode { IntEuler = 0, IntRK2, IntRK4 };
+
+//! Integrate a particle set with a given velocity kernel
+template<class VelKernel> void integratePointSet(VelKernel &k, int mode)
+{
+ typedef typename VelKernel::type0 PosType;
+ PosType &x = k.getArg0();
+ const std::vector<Vec3> &u = k.getRet();
+ const int N = x.size();
+
+ if (mode == IntEuler) {
+ for (int i = 0; i < N; i++)
+ x[i].pos += u[i];
+ }
+ else if (mode == IntRK2) {
+ PosType x0(x);
+
+ for (int i = 0; i < N; i++)
+ x[i].pos = x0[i].pos + 0.5 * u[i];
+
+ k.run();
+ for (int i = 0; i < N; i++)
+ x[i].pos = x0[i].pos + u[i];
+ }
+ else if (mode == IntRK4) {
+ PosType x0(x);
+ std::vector<Vec3> uTotal(u);
+
+ for (int i = 0; i < N; i++)
+ x[i].pos = x0[i].pos + 0.5 * u[i];
+
+ k.run();
+ for (int i = 0; i < N; i++) {
+ x[i].pos = x0[i].pos + 0.5 * u[i];
+ uTotal[i] += 2 * u[i];
+ }
+
+ k.run();
+ for (int i = 0; i < N; i++) {
+ x[i].pos = x0[i].pos + u[i];
+ uTotal[i] += 2 * u[i];
+ }
+
+ k.run();
+ for (int i = 0; i < N; i++)
+ x[i].pos = x0[i].pos + (Real)(1. / 6.) * (uTotal[i] + u[i]);
+ }
+ else
+ errMsg("unknown integration type");
+
+ // for(int i=0; i<N; i++) std::cout << x[i].pos.y-x[0].pos.y << std::endl;
+ // std::cout << "<><><>" << std::endl;
+}
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/helper/util/interpol.h b/extern/mantaflow/helper/util/interpol.h
new file mode 100644
index 00000000000..24d5d2ada06
--- /dev/null
+++ b/extern/mantaflow/helper/util/interpol.h
@@ -0,0 +1,324 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Helper functions for interpolation
+ *
+ ******************************************************************************/
+
+#ifndef _INTERPOL_H
+#define _INTERPOL_H
+
+#include "vectorbase.h"
+
+// Grid values are stored at i+0.5, j+0.5, k+0.5
+// MAC grid values are stored at i,j+0.5,k+0.5 (for x) ...
+
+namespace Manta {
+
+inline Vec3 fdTangent(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2)
+{
+ return 0.5 * (getNormalized(p2 - p1) + getNormalized(p1 - p0));
+}
+
+inline Vec3 crTangent(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2)
+{
+ return 0.5 * (p2 - p0);
+}
+
+inline Vec3 hermiteSpline(const Vec3 &p0, const Vec3 &p1, const Vec3 &m0, const Vec3 &m1, Real t)
+{
+ const Real t2 = t * t, t3 = t2 * t;
+ return (2.0 * t3 - 3.0 * t2 + 1.0) * p0 + (t3 - 2.0 * t2 + t) * m0 +
+ (-2.0 * t3 + 3.0 * t2) * p1 + (t3 - t2) * m1;
+}
+
+static inline void checkIndexInterpol(const Vec3i &size, IndexInt idx)
+{
+ if (idx < 0 || idx > (IndexInt)size.x * size.y * size.z) {
+ std::ostringstream s;
+ s << "Grid interpol dim " << size << " : index " << idx << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+// ----------------------------------------------------------------------
+// Grid interpolators
+// ----------------------------------------------------------------------
+
+#define BUILD_INDEX \
+ Real px = pos.x - 0.5f, py = pos.y - 0.5f, pz = pos.z - 0.5f; \
+ int xi = (int)px; \
+ int yi = (int)py; \
+ int zi = (int)pz; \
+ Real s1 = px - (Real)xi, s0 = 1. - s1; \
+ Real t1 = py - (Real)yi, t0 = 1. - t1; \
+ Real f1 = pz - (Real)zi, f0 = 1. - f1; \
+ /* clamp to border */ \
+ if (px < 0.) { \
+ xi = 0; \
+ s0 = 1.0; \
+ s1 = 0.0; \
+ } \
+ if (py < 0.) { \
+ yi = 0; \
+ t0 = 1.0; \
+ t1 = 0.0; \
+ } \
+ if (pz < 0.) { \
+ zi = 0; \
+ f0 = 1.0; \
+ f1 = 0.0; \
+ } \
+ if (xi >= size.x - 1) { \
+ xi = size.x - 2; \
+ s0 = 0.0; \
+ s1 = 1.0; \
+ } \
+ if (yi >= size.y - 1) { \
+ yi = size.y - 2; \
+ t0 = 0.0; \
+ t1 = 1.0; \
+ } \
+ if (size.z > 1) { \
+ if (zi >= size.z - 1) { \
+ zi = size.z - 2; \
+ f0 = 0.0; \
+ f1 = 1.0; \
+ } \
+ } \
+ const int X = 1; \
+ const int Y = size.x;
+
+template<class T> inline T interpol(const T *data, const Vec3i &size, const int Z, const Vec3 &pos)
+{
+ BUILD_INDEX
+ IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi;
+ DEBUG_ONLY(checkIndexInterpol(size, idx));
+ DEBUG_ONLY(checkIndexInterpol(size, idx + X + Y + Z));
+
+ return ((data[idx] * t0 + data[idx + Y] * t1) * s0 +
+ (data[idx + X] * t0 + data[idx + X + Y] * t1) * s1) *
+ f0 +
+ ((data[idx + Z] * t0 + data[idx + Y + Z] * t1) * s0 +
+ (data[idx + X + Z] * t0 + data[idx + X + Y + Z] * t1) * s1) *
+ f1;
+}
+
+template<int c>
+inline Real interpolComponent(const Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos)
+{
+ BUILD_INDEX
+ IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi;
+ DEBUG_ONLY(checkIndexInterpol(size, idx));
+ DEBUG_ONLY(checkIndexInterpol(size, idx + X + Y + Z));
+
+ return ((data[idx][c] * t0 + data[idx + Y][c] * t1) * s0 +
+ (data[idx + X][c] * t0 + data[idx + X + Y][c] * t1) * s1) *
+ f0 +
+ ((data[idx + Z][c] * t0 + data[idx + Y + Z][c] * t1) * s0 +
+ (data[idx + X + Z][c] * t0 + data[idx + X + Y + Z][c] * t1) * s1) *
+ f1;
+}
+
+template<class T>
+inline void setInterpol(
+ T *data, const Vec3i &size, const int Z, const Vec3 &pos, const T &v, Real *sumBuffer)
+{
+ BUILD_INDEX
+ IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi;
+ DEBUG_ONLY(checkIndexInterpol(size, idx));
+ DEBUG_ONLY(checkIndexInterpol(size, idx + X + Y + Z));
+
+ T *ref = &data[idx];
+ Real *sum = &sumBuffer[idx];
+ Real s0f0 = s0 * f0, s1f0 = s1 * f0, s0f1 = s0 * f1, s1f1 = s1 * f1;
+ Real w0 = t0 * s0f0, wx = t0 * s1f0, wy = t1 * s0f0, wxy = t1 * s1f0;
+ Real wz = t0 * s0f1, wxz = t0 * s1f1, wyz = t1 * s0f1, wxyz = t1 * s1f1;
+
+ sum[Z] += wz;
+ sum[X + Z] += wxz;
+ sum[Y + Z] += wyz;
+ sum[X + Y + Z] += wxyz;
+ ref[Z] += wz * v;
+ ref[X + Z] += wxz * v;
+ ref[Y + Z] += wyz * v;
+ ref[X + Y + Z] += wxyz * v;
+ sum[0] += w0;
+ sum[X] += wx;
+ sum[Y] += wy;
+ sum[X + Y] += wxy;
+ ref[0] += w0 * v;
+ ref[X] += wx * v;
+ ref[Y] += wy * v;
+ ref[X + Y] += wxy * v;
+}
+
+#define BUILD_INDEX_SHIFT \
+ BUILD_INDEX \
+ /* shifted coords */ \
+ int s_xi = (int)pos.x, s_yi = (int)pos.y, s_zi = (int)pos.z; \
+ Real s_s1 = pos.x - (Real)s_xi, s_s0 = 1. - s_s1; \
+ Real s_t1 = pos.y - (Real)s_yi, s_t0 = 1. - s_t1; \
+ Real s_f1 = pos.z - (Real)s_zi, s_f0 = 1. - s_f1; \
+ /* clamp to border */ \
+ if (pos.x < 0) { \
+ s_xi = 0; \
+ s_s0 = 1.0; \
+ s_s1 = 0.0; \
+ } \
+ if (pos.y < 0) { \
+ s_yi = 0; \
+ s_t0 = 1.0; \
+ s_t1 = 0.0; \
+ } \
+ if (pos.z < 0) { \
+ s_zi = 0; \
+ s_f0 = 1.0; \
+ s_f1 = 0.0; \
+ } \
+ if (s_xi >= size.x - 1) { \
+ s_xi = size.x - 2; \
+ s_s0 = 0.0; \
+ s_s1 = 1.0; \
+ } \
+ if (s_yi >= size.y - 1) { \
+ s_yi = size.y - 2; \
+ s_t0 = 0.0; \
+ s_t1 = 1.0; \
+ } \
+ if (size.z > 1) { \
+ if (s_zi >= size.z - 1) { \
+ s_zi = size.z - 2; \
+ s_f0 = 0.0; \
+ s_f1 = 1.0; \
+ } \
+ }
+
+inline Vec3 interpolMAC(const Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos)
+{
+ BUILD_INDEX_SHIFT;
+ DEBUG_ONLY(checkIndexInterpol(size, (zi * (IndexInt)size.y + yi) * (IndexInt)size.x + xi));
+ DEBUG_ONLY(checkIndexInterpol(
+ size, (s_zi * (IndexInt)size.y + s_yi) * (IndexInt)size.x + s_xi + X + Y + Z));
+
+ // process individual components
+ Vec3 ret(0.);
+ { // X
+ const Vec3 *ref = &data[((zi * size.y + yi) * size.x + s_xi)];
+ ret.x = f0 * ((ref[0].x * t0 + ref[Y].x * t1) * s_s0 +
+ (ref[X].x * t0 + ref[X + Y].x * t1) * s_s1) +
+ f1 * ((ref[Z].x * t0 + ref[Z + Y].x * t1) * s_s0 +
+ (ref[X + Z].x * t0 + ref[X + Y + Z].x * t1) * s_s1);
+ }
+ { // Y
+ const Vec3 *ref = &data[((zi * size.y + s_yi) * size.x + xi)];
+ ret.y = f0 * ((ref[0].y * s_t0 + ref[Y].y * s_t1) * s0 +
+ (ref[X].y * s_t0 + ref[X + Y].y * s_t1) * s1) +
+ f1 * ((ref[Z].y * s_t0 + ref[Z + Y].y * s_t1) * s0 +
+ (ref[X + Z].y * s_t0 + ref[X + Y + Z].y * s_t1) * s1);
+ }
+ { // Z
+ const Vec3 *ref = &data[((s_zi * size.y + yi) * size.x + xi)];
+ ret.z = s_f0 *
+ ((ref[0].z * t0 + ref[Y].z * t1) * s0 + (ref[X].z * t0 + ref[X + Y].z * t1) * s1) +
+ s_f1 * ((ref[Z].z * t0 + ref[Z + Y].z * t1) * s0 +
+ (ref[X + Z].z * t0 + ref[X + Y + Z].z * t1) * s1);
+ }
+ return ret;
+}
+
+inline void setInterpolMAC(
+ Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos, const Vec3 &val, Vec3 *sumBuffer)
+{
+ BUILD_INDEX_SHIFT;
+ DEBUG_ONLY(checkIndexInterpol(size, (zi * (IndexInt)size.y + yi) * (IndexInt)size.x + xi));
+ DEBUG_ONLY(checkIndexInterpol(
+ size, (s_zi * (IndexInt)size.y + s_yi) * (IndexInt)size.x + s_xi + X + Y + Z));
+
+ // process individual components
+ { // X
+ const IndexInt idx = (IndexInt)(zi * size.y + yi) * size.x + s_xi;
+ Vec3 *ref = &data[idx], *sum = &sumBuffer[idx];
+ Real s0f0 = s_s0 * f0, s1f0 = s_s1 * f0, s0f1 = s_s0 * f1, s1f1 = s_s1 * f1;
+ Real w0 = t0 * s0f0, wx = t0 * s1f0, wy = t1 * s0f0, wxy = t1 * s1f0;
+ Real wz = t0 * s0f1, wxz = t0 * s1f1, wyz = t1 * s0f1, wxyz = t1 * s1f1;
+
+ sum[Z].x += wz;
+ sum[X + Z].x += wxz;
+ sum[Y + Z].x += wyz;
+ sum[X + Y + Z].x += wxyz;
+ ref[Z].x += wz * val.x;
+ ref[X + Z].x += wxz * val.x;
+ ref[Y + Z].x += wyz * val.x;
+ ref[X + Y + Z].x += wxyz * val.x;
+ sum[0].x += w0;
+ sum[X].x += wx;
+ sum[Y].x += wy;
+ sum[X + Y].x += wxy;
+ ref[0].x += w0 * val.x;
+ ref[X].x += wx * val.x;
+ ref[Y].x += wy * val.x;
+ ref[X + Y].x += wxy * val.x;
+ }
+ { // Y
+ const IndexInt idx = (IndexInt)(zi * size.y + s_yi) * size.x + xi;
+ Vec3 *ref = &data[idx], *sum = &sumBuffer[idx];
+ Real s0f0 = s0 * f0, s1f0 = s1 * f0, s0f1 = s0 * f1, s1f1 = s1 * f1;
+ Real w0 = s_t0 * s0f0, wx = s_t0 * s1f0, wy = s_t1 * s0f0, wxy = s_t1 * s1f0;
+ Real wz = s_t0 * s0f1, wxz = s_t0 * s1f1, wyz = s_t1 * s0f1, wxyz = s_t1 * s1f1;
+
+ sum[Z].y += wz;
+ sum[X + Z].y += wxz;
+ sum[Y + Z].y += wyz;
+ sum[X + Y + Z].y += wxyz;
+ ref[Z].y += wz * val.y;
+ ref[X + Z].y += wxz * val.y;
+ ref[Y + Z].y += wyz * val.y;
+ ref[X + Y + Z].y += wxyz * val.y;
+ sum[0].y += w0;
+ sum[X].y += wx;
+ sum[Y].y += wy;
+ sum[X + Y].y += wxy;
+ ref[0].y += w0 * val.y;
+ ref[X].y += wx * val.y;
+ ref[Y].y += wy * val.y;
+ ref[X + Y].y += wxy * val.y;
+ }
+ { // Z
+ const IndexInt idx = (IndexInt)(s_zi * size.y + yi) * size.x + xi;
+ Vec3 *ref = &data[idx], *sum = &sumBuffer[idx];
+ Real s0f0 = s0 * s_f0, s1f0 = s1 * s_f0, s0f1 = s0 * s_f1, s1f1 = s1 * s_f1;
+ Real w0 = t0 * s0f0, wx = t0 * s1f0, wy = t1 * s0f0, wxy = t1 * s1f0;
+ Real wz = t0 * s0f1, wxz = t0 * s1f1, wyz = t1 * s0f1, wxyz = t1 * s1f1;
+
+ sum[0].z += w0;
+ sum[X].z += wx;
+ sum[Y].z += wy;
+ sum[X + Y].z += wxy;
+ sum[Z].z += wz;
+ sum[X + Z].z += wxz;
+ sum[Y + Z].z += wyz;
+ sum[X + Y + Z].z += wxyz;
+ ref[0].z += w0 * val.z;
+ ref[X].z += wx * val.z;
+ ref[Y].z += wy * val.z;
+ ref[X + Y].z += wxy * val.z;
+ ref[Z].z += wz * val.z;
+ ref[X + Z].z += wxz * val.z;
+ ref[Y + Z].z += wyz * val.z;
+ ref[X + Y + Z].z += wxyz * val.z;
+ }
+}
+
+#undef BUILD_INDEX
+#undef BUILD_INDEX_SHIFT
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/helper/util/interpolHigh.h b/extern/mantaflow/helper/util/interpolHigh.h
new file mode 100644
index 00000000000..c2a77442b9c
--- /dev/null
+++ b/extern/mantaflow/helper/util/interpolHigh.h
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Helper functions for higher order interpolation
+ *
+ ******************************************************************************/
+
+#ifndef _INTERPOLHIGH_H
+#define _INTERPOLHIGH_H
+
+#include "vectorbase.h"
+
+namespace Manta {
+
+template<class T> inline T cubicInterp(const Real interp, const T *points)
+{
+ T d0 = (points[2] - points[0]) * 0.5;
+ T d1 = (points[3] - points[1]) * 0.5;
+ T deltak = (points[2] - points[1]);
+
+ // disabled: if (deltak * d0 < 0.0) d0 = 0;
+ // disabled: if (deltak * d1 < 0.0) d1 = 0;
+
+ T a0 = points[1];
+ T a1 = d0;
+ T a2 = 3.0 * deltak - 2.0 * d0 - d1;
+ T a3 = -2.0 * deltak + d0 + d1;
+
+ Real squared = interp * interp;
+ Real cubed = squared * interp;
+ return a3 * cubed + a2 * squared + a1 * interp + a0;
+}
+
+template<class T> inline T interpolCubic2D(const T *data, const Vec3i &size, const Vec3 &pos)
+{
+ const Real px = pos.x - 0.5f, py = pos.y - 0.5f;
+
+ const int x1 = (int)px;
+ const int x2 = x1 + 1;
+ const int x3 = x1 + 2;
+ const int x0 = x1 - 1;
+
+ const int y1 = (int)py;
+ const int y2 = y1 + 1;
+ const int y3 = y1 + 2;
+ const int y0 = y1 - 1;
+
+ if (x0 < 0 || y0 < 0 || x3 >= size[0] || y3 >= size[1]) {
+ return interpol(data, size, 0, pos);
+ }
+
+ const Real xInterp = px - x1;
+ const Real yInterp = py - y1;
+
+ const int y0x = y0 * size[0];
+ const int y1x = y1 * size[0];
+ const int y2x = y2 * size[0];
+ const int y3x = y3 * size[0];
+
+ const T p0[] = {data[x0 + y0x], data[x1 + y0x], data[x2 + y0x], data[x3 + y0x]};
+ const T p1[] = {data[x0 + y1x], data[x1 + y1x], data[x2 + y1x], data[x3 + y1x]};
+ const T p2[] = {data[x0 + y2x], data[x1 + y2x], data[x2 + y2x], data[x3 + y2x]};
+ const T p3[] = {data[x0 + y3x], data[x1 + y3x], data[x2 + y3x], data[x3 + y3x]};
+
+ const T finalPoints[] = {cubicInterp(xInterp, p0),
+ cubicInterp(xInterp, p1),
+ cubicInterp(xInterp, p2),
+ cubicInterp(xInterp, p3)};
+
+ return cubicInterp(yInterp, finalPoints);
+}
+
+template<class T>
+inline T interpolCubic(const T *data, const Vec3i &size, const int Z, const Vec3 &pos)
+{
+ if (Z == 0)
+ return interpolCubic2D(data, size, pos);
+
+ const Real px = pos.x - 0.5f, py = pos.y - 0.5f, pz = pos.z - 0.5f;
+
+ const int x1 = (int)px;
+ const int x2 = x1 + 1;
+ const int x3 = x1 + 2;
+ const int x0 = x1 - 1;
+
+ const int y1 = (int)py;
+ const int y2 = y1 + 1;
+ const int y3 = y1 + 2;
+ const int y0 = y1 - 1;
+
+ const int z1 = (int)pz;
+ const int z2 = z1 + 1;
+ const int z3 = z1 + 2;
+ const int z0 = z1 - 1;
+
+ if (x0 < 0 || y0 < 0 || z0 < 0 || x3 >= size[0] || y3 >= size[1] || z3 >= size[2]) {
+ return interpol(data, size, Z, pos);
+ }
+
+ const Real xInterp = px - x1;
+ const Real yInterp = py - y1;
+ const Real zInterp = pz - z1;
+
+ const int slabsize = size[0] * size[1];
+ const int z0Slab = z0 * slabsize;
+ const int z1Slab = z1 * slabsize;
+ const int z2Slab = z2 * slabsize;
+ const int z3Slab = z3 * slabsize;
+
+ const int y0x = y0 * size[0];
+ const int y1x = y1 * size[0];
+ const int y2x = y2 * size[0];
+ const int y3x = y3 * size[0];
+
+ const int y0z0 = y0x + z0Slab;
+ const int y1z0 = y1x + z0Slab;
+ const int y2z0 = y2x + z0Slab;
+ const int y3z0 = y3x + z0Slab;
+
+ const int y0z1 = y0x + z1Slab;
+ const int y1z1 = y1x + z1Slab;
+ const int y2z1 = y2x + z1Slab;
+ const int y3z1 = y3x + z1Slab;
+
+ const int y0z2 = y0x + z2Slab;
+ const int y1z2 = y1x + z2Slab;
+ const int y2z2 = y2x + z2Slab;
+ const int y3z2 = y3x + z2Slab;
+
+ const int y0z3 = y0x + z3Slab;
+ const int y1z3 = y1x + z3Slab;
+ const int y2z3 = y2x + z3Slab;
+ const int y3z3 = y3x + z3Slab;
+
+ // get the z0 slice
+ const T p0[] = {data[x0 + y0z0], data[x1 + y0z0], data[x2 + y0z0], data[x3 + y0z0]};
+ const T p1[] = {data[x0 + y1z0], data[x1 + y1z0], data[x2 + y1z0], data[x3 + y1z0]};
+ const T p2[] = {data[x0 + y2z0], data[x1 + y2z0], data[x2 + y2z0], data[x3 + y2z0]};
+ const T p3[] = {data[x0 + y3z0], data[x1 + y3z0], data[x2 + y3z0], data[x3 + y3z0]};
+
+ // get the z1 slice
+ const T p4[] = {data[x0 + y0z1], data[x1 + y0z1], data[x2 + y0z1], data[x3 + y0z1]};
+ const T p5[] = {data[x0 + y1z1], data[x1 + y1z1], data[x2 + y1z1], data[x3 + y1z1]};
+ const T p6[] = {data[x0 + y2z1], data[x1 + y2z1], data[x2 + y2z1], data[x3 + y2z1]};
+ const T p7[] = {data[x0 + y3z1], data[x1 + y3z1], data[x2 + y3z1], data[x3 + y3z1]};
+
+ // get the z2 slice
+ const T p8[] = {data[x0 + y0z2], data[x1 + y0z2], data[x2 + y0z2], data[x3 + y0z2]};
+ const T p9[] = {data[x0 + y1z2], data[x1 + y1z2], data[x2 + y1z2], data[x3 + y1z2]};
+ const T p10[] = {data[x0 + y2z2], data[x1 + y2z2], data[x2 + y2z2], data[x3 + y2z2]};
+ const T p11[] = {data[x0 + y3z2], data[x1 + y3z2], data[x2 + y3z2], data[x3 + y3z2]};
+
+ // get the z3 slice
+ const T p12[] = {data[x0 + y0z3], data[x1 + y0z3], data[x2 + y0z3], data[x3 + y0z3]};
+ const T p13[] = {data[x0 + y1z3], data[x1 + y1z3], data[x2 + y1z3], data[x3 + y1z3]};
+ const T p14[] = {data[x0 + y2z3], data[x1 + y2z3], data[x2 + y2z3], data[x3 + y2z3]};
+ const T p15[] = {data[x0 + y3z3], data[x1 + y3z3], data[x2 + y3z3], data[x3 + y3z3]};
+
+ // interpolate
+ const T z0Points[] = {cubicInterp(xInterp, p0),
+ cubicInterp(xInterp, p1),
+ cubicInterp(xInterp, p2),
+ cubicInterp(xInterp, p3)};
+ const T z1Points[] = {cubicInterp(xInterp, p4),
+ cubicInterp(xInterp, p5),
+ cubicInterp(xInterp, p6),
+ cubicInterp(xInterp, p7)};
+ const T z2Points[] = {cubicInterp(xInterp, p8),
+ cubicInterp(xInterp, p9),
+ cubicInterp(xInterp, p10),
+ cubicInterp(xInterp, p11)};
+ const T z3Points[] = {cubicInterp(xInterp, p12),
+ cubicInterp(xInterp, p13),
+ cubicInterp(xInterp, p14),
+ cubicInterp(xInterp, p15)};
+
+ const T finalPoints[] = {cubicInterp(yInterp, z0Points),
+ cubicInterp(yInterp, z1Points),
+ cubicInterp(yInterp, z2Points),
+ cubicInterp(yInterp, z3Points)};
+
+ return cubicInterp(zInterp, finalPoints);
+}
+
+inline Vec3 interpolCubicMAC(const Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos)
+{
+ // warning - not yet optimized...
+ Real vx = interpolCubic<Vec3>(data, size, Z, pos + Vec3(0.5, 0, 0))[0];
+ Real vy = interpolCubic<Vec3>(data, size, Z, pos + Vec3(0, 0.5, 0))[1];
+ Real vz = 0.f;
+ if (Z != 0)
+ vz = interpolCubic<Vec3>(data, size, Z, pos + Vec3(0, 0, 0.5))[2];
+ return Vec3(vx, vy, vz);
+}
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/helper/util/matrixbase.h b/extern/mantaflow/helper/util/matrixbase.h
new file mode 100644
index 00000000000..9875998f0be
--- /dev/null
+++ b/extern/mantaflow/helper/util/matrixbase.h
@@ -0,0 +1,394 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2015 Kiwon Um, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * Matrix (3x3) class
+ *
+ ******************************************************************************/
+
+#ifndef MATRIXBASE_H
+#define MATRIXBASE_H
+
+#include "vectorbase.h"
+
+namespace Manta {
+
+template<typename T> class Matrix3x3 {
+ public:
+ // NOTE: default is the identity matrix!
+ explicit Matrix3x3(const T &p00 = 1,
+ const T &p01 = 0,
+ const T &p02 = 0,
+ const T &p10 = 0,
+ const T &p11 = 1,
+ const T &p12 = 0,
+ const T &p20 = 0,
+ const T &p21 = 0,
+ const T &p22 = 1)
+ {
+ v[0][0] = p00;
+ v[0][1] = p01;
+ v[0][2] = p02;
+ v[1][0] = p10;
+ v[1][1] = p11;
+ v[1][2] = p12;
+ v[2][0] = p20;
+ v[2][1] = p21;
+ v[2][2] = p22;
+ }
+
+ explicit Matrix3x3(const Vector3D<T> &diag)
+ {
+ v[0][0] = diag.x;
+ v[0][1] = 0;
+ v[0][2] = 0;
+ v[1][0] = 0;
+ v[1][1] = diag.y;
+ v[1][2] = 0;
+ v[2][0] = 0;
+ v[2][1] = 0;
+ v[2][2] = diag.z;
+ }
+
+ Matrix3x3(const Vector3D<T> &c0, const Vector3D<T> &c1, const Vector3D<T> &c2)
+ {
+ v[0][0] = c0.x;
+ v[0][1] = c1.x;
+ v[0][2] = c2.x;
+ v[1][0] = c0.y;
+ v[1][1] = c1.y;
+ v[1][2] = c2.y;
+ v[2][0] = c0.z;
+ v[2][1] = c1.z;
+ v[2][2] = c2.z;
+ }
+
+ // assignment operators
+ Matrix3x3 &operator+=(const Matrix3x3 &m)
+ {
+ v00 += m.v00;
+ v01 += m.v01;
+ v02 += m.v02;
+ v10 += m.v10;
+ v11 += m.v11;
+ v12 += m.v12;
+ v20 += m.v20;
+ v21 += m.v21;
+ v22 += m.v22;
+ return *this;
+ }
+ Matrix3x3 &operator-=(const Matrix3x3 &m)
+ {
+ v00 -= m.v00;
+ v01 -= m.v01;
+ v02 -= m.v02;
+ v10 -= m.v10;
+ v11 -= m.v11;
+ v12 -= m.v12;
+ v20 -= m.v20;
+ v21 -= m.v21;
+ v22 -= m.v22;
+ return *this;
+ }
+ Matrix3x3 &operator*=(const T s)
+ {
+ v00 *= s;
+ v01 *= s;
+ v02 *= s;
+ v10 *= s;
+ v11 *= s;
+ v12 *= s;
+ v20 *= s;
+ v21 *= s;
+ v22 *= s;
+ return *this;
+ }
+ Matrix3x3 &operator/=(const T s)
+ {
+ v00 /= s;
+ v01 /= s;
+ v02 /= s;
+ v10 /= s;
+ v11 /= s;
+ v12 /= s;
+ v20 /= s;
+ v21 /= s;
+ v22 /= s;
+ return *this;
+ }
+
+ // binary operators
+ Matrix3x3 operator+(const Matrix3x3 &m) const
+ {
+ return Matrix3x3(*this) += m;
+ }
+ Matrix3x3 operator-(const Matrix3x3 &m) const
+ {
+ return Matrix3x3(*this) -= m;
+ }
+ Matrix3x3 operator*(const Matrix3x3 &m) const
+ {
+ return Matrix3x3(v00 * m.v00 + v01 * m.v10 + v02 * m.v20,
+ v00 * m.v01 + v01 * m.v11 + v02 * m.v21,
+ v00 * m.v02 + v01 * m.v12 + v02 * m.v22,
+
+ v10 * m.v00 + v11 * m.v10 + v12 * m.v20,
+ v10 * m.v01 + v11 * m.v11 + v12 * m.v21,
+ v10 * m.v02 + v11 * m.v12 + v12 * m.v22,
+
+ v20 * m.v00 + v21 * m.v10 + v22 * m.v20,
+ v20 * m.v01 + v21 * m.v11 + v22 * m.v21,
+ v20 * m.v02 + v21 * m.v12 + v22 * m.v22);
+ }
+ Matrix3x3 operator*(const T s) const
+ {
+ return Matrix3x3(*this) *= s;
+ }
+ Vector3D<T> operator*(const Vector3D<T> &v) const
+ {
+ return Vector3D<T>(v00 * v.x + v01 * v.y + v02 * v.z,
+ v10 * v.x + v11 * v.y + v12 * v.z,
+ v20 * v.x + v21 * v.y + v22 * v.z);
+ }
+ Vector3D<T> transposedMul(const Vector3D<T> &v) const
+ {
+ // M^T*v
+ return Vector3D<T>(v00 * v.x + v10 * v.y + v20 * v.z,
+ v01 * v.x + v11 * v.y + v21 * v.z,
+ v02 * v.x + v12 * v.y + v22 * v.z);
+ }
+ Matrix3x3 transposedMul(const Matrix3x3 &m) const
+ {
+ // M^T*M
+ return Matrix3x3(v00 * m.v00 + v10 * m.v10 + v20 * m.v20,
+ v00 * m.v01 + v10 * m.v11 + v20 * m.v21,
+ v00 * m.v02 + v10 * m.v12 + v20 * m.v22,
+
+ v01 * m.v00 + v11 * m.v10 + v21 * m.v20,
+ v01 * m.v01 + v11 * m.v11 + v21 * m.v21,
+ v01 * m.v02 + v11 * m.v12 + v21 * m.v22,
+
+ v02 * m.v00 + v12 * m.v10 + v22 * m.v20,
+ v02 * m.v01 + v12 * m.v11 + v22 * m.v21,
+ v02 * m.v02 + v12 * m.v12 + v22 * m.v22);
+ }
+ Matrix3x3 mulTranspose(const Matrix3x3 &m) const
+ {
+ // M*m^T
+ return Matrix3x3(v00 * m.v00 + v01 * m.v01 + v02 * m.v02,
+ v00 * m.v10 + v01 * m.v11 + v02 * m.v12,
+ v00 * m.v20 + v01 * m.v21 + v02 * m.v22,
+
+ v10 * m.v00 + v11 * m.v01 + v12 * m.v02,
+ v10 * m.v10 + v11 * m.v11 + v12 * m.v12,
+ v10 * m.v20 + v11 * m.v21 + v12 * m.v22,
+
+ v20 * m.v00 + v21 * m.v01 + v22 * m.v02,
+ v20 * m.v10 + v21 * m.v11 + v22 * m.v12,
+ v20 * m.v20 + v21 * m.v21 + v22 * m.v22);
+ }
+
+ bool operator==(const Matrix3x3 &m) const
+ {
+ return (v00 == m.v00 && v01 == m.v01 && v02 == m.v02 && v10 == m.v10 && v11 == m.v11 &&
+ v12 == m.v12 && v20 == m.v20 && v21 == m.v21 && v22 == m.v22);
+ }
+
+ const T &operator()(const int r, const int c) const
+ {
+ return v[r][c];
+ }
+ T &operator()(const int r, const int c)
+ {
+ return const_cast<T &>(const_cast<const Matrix3x3 &>(*this)(r, c));
+ }
+
+ T trace() const
+ {
+ return v00 + v11 + v22;
+ }
+ T sumSqr() const
+ {
+ return (v00 * v00 + v01 * v01 + v02 * v02 + v10 * v10 + v11 * v11 + v12 * v12 + v20 * v20 +
+ v21 * v21 + v22 * v22);
+ }
+
+ Real determinant() const
+ {
+ return (v00 * v11 * v22 - v00 * v12 * v21 + v01 * v12 * v20 - v01 * v10 * v22 +
+ v02 * v10 * v21 - v02 * v11 * v20);
+ }
+ Matrix3x3 &transpose()
+ {
+ return *this = transposed();
+ }
+ Matrix3x3 transposed() const
+ {
+ return Matrix3x3(v00, v10, v20, v01, v11, v21, v02, v12, v22);
+ }
+ Matrix3x3 &invert()
+ {
+ return *this = inverse();
+ }
+ Matrix3x3 inverse() const
+ {
+ const Real det = determinant(); // FIXME: assert(det);
+ const Real idet = 1e0 / det;
+ return Matrix3x3(idet * (v11 * v22 - v12 * v21),
+ idet * (v02 * v21 - v01 * v22),
+ idet * (v01 * v12 - v02 * v11),
+ idet * (v12 * v20 - v10 * v22),
+ idet * (v00 * v22 - v02 * v20),
+ idet * (v02 * v10 - v00 * v12),
+ idet * (v10 * v21 - v11 * v20),
+ idet * (v01 * v20 - v00 * v21),
+ idet * (v00 * v11 - v01 * v10));
+ }
+ bool getInverse(Matrix3x3 &inv) const
+ {
+ const Real det = determinant();
+ if (det == 0e0)
+ return false; // FIXME: is it likely to happen the floating error?
+
+ const Real idet = 1e0 / det;
+ inv.v00 = idet * (v11 * v22 - v12 * v21);
+ inv.v01 = idet * (v02 * v21 - v01 * v22);
+ inv.v02 = idet * (v01 * v12 - v02 * v11);
+
+ inv.v10 = idet * (v12 * v20 - v10 * v22);
+ inv.v11 = idet * (v00 * v22 - v02 * v20);
+ inv.v12 = idet * (v02 * v10 - v00 * v12);
+
+ inv.v20 = idet * (v10 * v21 - v11 * v20);
+ inv.v21 = idet * (v01 * v20 - v00 * v21);
+ inv.v22 = idet * (v00 * v11 - v01 * v10);
+
+ return true;
+ }
+
+ Real normOne() const
+ {
+ // the maximum absolute column sum of the matrix
+ return max(std::fabs(v00) + std::fabs(v10) + std::fabs(v20),
+ std::fabs(v01) + std::fabs(v11) + std::fabs(v21),
+ std::fabs(v02) + std::fabs(v12) + std::fabs(v22));
+ }
+ Real normInf() const
+ {
+ // the maximum absolute row sum of the matrix
+ return max(std::fabs(v00) + std::fabs(v01) + std::fabs(v02),
+ std::fabs(v10) + std::fabs(v11) + std::fabs(v12),
+ std::fabs(v20) + std::fabs(v21) + std::fabs(v22));
+ }
+
+ Vector3D<T> eigenvalues() const
+ {
+ Vector3D<T> eigen;
+
+ const Real b = -v00 - v11 - v22;
+ const Real c = v00 * (v11 + v22) + v11 * v22 - v12 * v21 - v01 * v10 - v02 * v20;
+ Real d = -v00 * (v11 * v22 - v12 * v21) - v20 * (v01 * v12 - v11 * v02) -
+ v10 * (v02 * v21 - v22 * v01);
+ const Real f = (3.0 * c - b * b) / 3.0;
+ const Real g = (2.0 * b * b * b - 9.0 * b * c + 27.0 * d) / 27.0;
+ const Real h = g * g / 4.0 + f * f * f / 27.0;
+
+ Real sign;
+ if (h > 0) {
+ Real r = -g / 2.0 + std::sqrt(h);
+ if (r < 0) {
+ r = -r;
+ sign = -1.0;
+ }
+ else
+ sign = 1.0;
+ Real s = sign * std::pow(r, 1.0 / 3.0);
+ Real t = -g / 2.0 - std::sqrt(h);
+ if (t < 0) {
+ t = -t;
+ sign = -1.0;
+ }
+ else
+ sign = 1.0;
+ Real u = sign * std::pow(t, 1.0 / 3.0);
+ eigen[0] = (s + u) - b / 3.0;
+ eigen[1] = eigen[2] = 0;
+ }
+ else if (h == 0) {
+ if (d < 0) {
+ d = -d;
+ sign = -1.0;
+ }
+ sign = 1.0;
+ eigen[0] = -1.0 * sign * std::pow(d, 1.0 / 3.0);
+ eigen[1] = eigen[2] = 0;
+ }
+ else {
+ const Real i = std::sqrt(g * g / 4.0 - h);
+ const Real j = std::pow(i, 1.0 / 3.0);
+ const Real k = std::acos(-g / (2.0 * i));
+ const Real l = -j;
+ const Real m = std::cos(k / 3.0);
+ const Real n = std::sqrt(3.0) * std::sin(k / 3.0);
+ const Real p = -b / 3.0;
+ eigen[0] = 2e0 * j * m + p;
+ eigen[1] = l * (m + n) + p;
+ eigen[2] = l * (m - n) + p;
+ }
+
+ return eigen;
+ }
+
+ static Matrix3x3 I()
+ {
+ return Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
+ }
+
+#ifdef _WIN32
+# pragma warning(disable : 4201)
+#endif
+ union {
+ struct {
+ T v00, v01, v02, v10, v11, v12, v20, v21, v22;
+ };
+ T v[3][3];
+ T v1[9];
+ };
+#ifdef _WIN32
+# pragma warning(default : 4201)
+#endif
+};
+
+template<typename T1, typename T> inline Matrix3x3<T> operator*(const T1 s, const Matrix3x3<T> &m)
+{
+ return m * static_cast<T>(s);
+}
+
+template<typename T> inline Matrix3x3<T> crossProductMatrix(const Vector3D<T> &v)
+{
+ return Matrix3x3<T>(0, -v.z, v.y, v.z, 0, -v.x, -v.y, v.x, 0);
+}
+
+template<typename T> inline Matrix3x3<T> outerProduct(const Vector3D<T> &a, const Vector3D<T> &b)
+{
+ return Matrix3x3<T>(a.x * b.x,
+ a.x * b.y,
+ a.x * b.z,
+ a.y * b.x,
+ a.y * b.y,
+ a.y * b.z,
+ a.z * b.x,
+ a.z * b.y,
+ a.z * b.z);
+}
+
+typedef Matrix3x3<Real> Matrix3x3f;
+
+} // namespace Manta
+
+#endif /* MATRIXBASE_H */
diff --git a/extern/mantaflow/helper/util/mcubes.h b/extern/mantaflow/helper/util/mcubes.h
new file mode 100644
index 00000000000..bd1c780e932
--- /dev/null
+++ b/extern/mantaflow/helper/util/mcubes.h
@@ -0,0 +1,308 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Marching cubes lookup indices
+ *
+ ******************************************************************************/
+
+#ifndef _MCUBES_H_
+#define _MCUBES_H_
+
+static const int mcEdges[24] = {0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6,
+ 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7};
+
+static const int cubieOffsetX[8] = {0, 1, 1, 0, 0, 1, 1, 0};
+static const int cubieOffsetY[8] = {0, 0, 1, 1, 0, 0, 1, 1};
+static const int cubieOffsetZ[8] = {0, 0, 0, 0, 1, 1, 1, 1};
+
+/* which edges are needed ? */
+/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
+static const short mcEdgeTable[256] = {
+ 0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a,
+ 0xd03, 0xe09, 0xf00, 0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895,
+ 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435,
+ 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3, 0xaa,
+ 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460,
+ 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963,
+ 0xa69, 0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff,
+ 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,
+ 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6,
+ 0x2cf, 0x1c5, 0xcc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9,
+ 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9,
+ 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55, 0x35f, 0x256,
+ 0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc,
+ 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f,
+ 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460, 0xca0, 0xda9, 0xea3,
+ 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,
+ 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a,
+ 0x33, 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795,
+ 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905,
+ 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0};
+
+/* triangles for the 256 intersection possibilities */
+/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
+static const short mcTriTable[256][16] = {
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
+ {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
+ {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
+ {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
+ {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
+ {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
+ {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
+ {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
+ {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
+ {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
+ {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
+ {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
+ {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
+ {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
+ {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
+ {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
+ {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
+ {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
+ {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
+ {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
+ {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
+ {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
+ {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
+ {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
+ {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
+ {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
+ {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
+ {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
+ {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
+ {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
+ {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
+ {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
+ {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
+ {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
+ {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
+ {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
+ {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
+ {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
+ {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
+ {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
+ {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
+ {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
+ {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
+ {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
+ {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
+ {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
+ {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
+ {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
+ {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
+ {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
+ {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
+ {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
+ {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
+ {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
+ {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
+ {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
+ {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
+ {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
+ {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
+ {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
+ {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
+ {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
+ {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
+ {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
+ {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
+ {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
+ {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
+ {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
+ {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
+ {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
+ {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
+ {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
+ {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
+ {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
+ {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
+ {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
+ {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
+ {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
+ {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
+ {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
+ {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
+ {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
+ {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
+ {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
+ {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
+ {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
+ {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
+ {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
+ {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
+ {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
+ {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
+ {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
+ {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
+ {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
+ {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
+ {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
+ {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
+ {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
+ {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
+ {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
+ {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
+ {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
+
+#endif \ No newline at end of file
diff --git a/extern/mantaflow/helper/util/quaternion.h b/extern/mantaflow/helper/util/quaternion.h
new file mode 100644
index 00000000000..c4e161baee2
--- /dev/null
+++ b/extern/mantaflow/helper/util/quaternion.h
@@ -0,0 +1,103 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Basic quaternion class
+ *
+ ******************************************************************************/
+
+#ifndef _QUATERNION_H
+#define _QUATERNION_H
+
+#include "vectorbase.h"
+
+namespace Manta {
+
+//! Very basic quaternion class
+class Quaternion {
+ public:
+ //! default constructor
+ Quaternion() : x(0), y(0), z(0), w(0)
+ {
+ }
+
+ //! copy constructor
+ Quaternion(const Quaternion &q) : x(q.x), y(q.y), z(q.z), w(q.w)
+ {
+ }
+
+ //! construct a quaternion from members
+ Quaternion(Real _x, Real _y, Real _z, Real _w) : x(_x), y(_y), z(_z), w(_w)
+ {
+ }
+
+ //! construct a quaternion from imag/real parts
+ Quaternion(Vec3 i, Real r) : x(i.x), y(i.y), z(i.z), w(r)
+ {
+ }
+
+ //! Assign operator
+ inline Quaternion &operator=(const Quaternion &q)
+ {
+ x = q.x;
+ y = q.y;
+ z = q.z;
+ w = q.w;
+ return *this;
+ }
+
+ //! Assign multiplication operator
+ inline Quaternion &operator*=(const Real a)
+ {
+ x *= a;
+ y *= a;
+ z *= a;
+ w *= a;
+ return *this;
+ }
+
+ //! return inverse quaternion
+ inline Quaternion inverse() const
+ {
+ Real mag = 1.0 / (x * x + y * y + z * z + w * w);
+ return Quaternion(-x * mag, -y * mag, -z * mag, w * mag);
+ }
+
+ //! imaginary part accessor
+ inline Vec3 imag()
+ {
+ return Vec3(x, y, z);
+ }
+
+ // imaginary part
+ Real x;
+ Real y;
+ Real z;
+
+ // real part
+ Real w;
+};
+
+//! Multiplication operator
+inline Quaternion operator*(const Quaternion &q1, const Quaternion &q2)
+{
+ return Quaternion(q2.w * q1.x + q2.x * q1.w + q2.y * q1.z - q2.z * q1.y,
+ q2.w * q1.y + q2.y * q1.w + q2.z * q1.x - q2.x * q1.z,
+ q2.w * q1.z + q2.z * q1.w + q2.x * q1.y - q2.y * q1.x,
+ q2.w * q1.w - q2.x * q1.x - q2.y * q1.y - q2.z * q1.z);
+}
+
+//! Multiplication operator
+inline Quaternion operator*(const Quaternion &q, const Real a)
+{
+ return Quaternion(q.x * a, q.y * a, q.z * a, q.w * a);
+}
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/helper/util/randomstream.h b/extern/mantaflow/helper/util/randomstream.h
new file mode 100644
index 00000000000..35b9c7d8858
--- /dev/null
+++ b/extern/mantaflow/helper/util/randomstream.h
@@ -0,0 +1,429 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Random numbers
+ *
+ * Based on an example by Makoto Matsumoto, Takuji Nishimura, Shawn Cokus, and Richard J. Wagner
+ *
+ ******************************************************************************/
+
+#ifndef _RANDOMSTREAM_H
+#define _RANDOMSTREAM_H
+
+namespace Manta {
+
+#include <iostream>
+#include <stdio.h>
+#include <time.h>
+#include "vectorbase.h"
+
+class MTRand {
+ // Data
+ public:
+ typedef unsigned long uint32; // unsigned integer type, at least 32 bits
+
+ enum { N = 624 }; // length of state vector
+ enum { SAVE = N + 1 }; // length of array for save()
+
+ protected:
+ enum { M = 397 }; // period parameter
+
+ uint32 state[N]; // internal state
+ uint32 *pNext; // next value to get from state
+ int left; // number of values left before reload needed
+
+ // Methods
+ public:
+ MTRand(const uint32 &oneSeed); // initialize with a simple uint32
+ MTRand(uint32 *const bigSeed, uint32 const seedLength = N); // or an array
+ MTRand(); // auto-initialize with /dev/urandom or time() and clock()
+
+ // Do NOT use for CRYPTOGRAPHY without securely hashing several returned
+ // values together, otherwise the generator state can be learned after
+ // reading 624 consecutive values.
+
+ // Access to 32-bit random numbers
+ double rand(); // real number in [0,1]
+ double rand(const double &n); // real number in [0,n]
+ double randExc(); // real number in [0,1)
+ double randExc(const double &n); // real number in [0,n)
+ double randDblExc(); // real number in (0,1)
+ double randDblExc(const double &n); // real number in (0,n)
+ uint32 randInt(); // integer in [0,2^32-1]
+ uint32 randInt(const uint32 &n); // integer in [0,n] for n < 2^32
+ double operator()()
+ {
+ return rand();
+ } // same as rand()
+
+ // Access to 53-bit random numbers (capacity of IEEE double precision)
+ double rand53(); // real number in [0,1)
+
+ // Access to nonuniform random number distributions
+ double randNorm(const double &mean = 0.0, const double &variance = 1.0);
+
+ // Re-seeding functions with same behavior as initializers
+ void seed(const uint32 oneSeed);
+ void seed(uint32 *const bigSeed, const uint32 seedLength = N);
+ void seed();
+
+ // Saving and loading generator state
+ void save(uint32 *saveArray) const; // to array of size SAVE
+ void load(uint32 *const loadArray); // from such array
+ friend std::ostream &operator<<(std::ostream &os, const MTRand &mtrand);
+ friend std::istream &operator>>(std::istream &is, MTRand &mtrand);
+
+ protected:
+ void initialize(const uint32 oneSeed);
+ void reload();
+ uint32 hiBit(const uint32 &u) const
+ {
+ return u & 0x80000000UL;
+ }
+ uint32 loBit(const uint32 &u) const
+ {
+ return u & 0x00000001UL;
+ }
+ uint32 loBits(const uint32 &u) const
+ {
+ return u & 0x7fffffffUL;
+ }
+ uint32 mixBits(const uint32 &u, const uint32 &v) const
+ {
+ return hiBit(u) | loBits(v);
+ }
+ uint32 twist(const uint32 &m, const uint32 &s0, const uint32 &s1) const
+ {
+ return m ^ (mixBits(s0, s1) >> 1) ^ (-loBit(s1) & 0x9908b0dfUL);
+ }
+ static uint32 hash(time_t t, clock_t c);
+};
+
+inline MTRand::MTRand(const uint32 &oneSeed)
+{
+ seed(oneSeed);
+}
+
+inline MTRand::MTRand(uint32 *const bigSeed, const uint32 seedLength)
+{
+ seed(bigSeed, seedLength);
+}
+
+inline MTRand::MTRand()
+{
+ seed();
+}
+
+inline double MTRand::rand()
+{
+ return double(randInt()) * (1.0 / 4294967295.0);
+}
+
+inline double MTRand::rand(const double &n)
+{
+ return rand() * n;
+}
+
+inline double MTRand::randExc()
+{
+ return double(randInt()) * (1.0 / 4294967296.0);
+}
+
+inline double MTRand::randExc(const double &n)
+{
+ return randExc() * n;
+}
+
+inline double MTRand::randDblExc()
+{
+ return (double(randInt()) + 0.5) * (1.0 / 4294967296.0);
+}
+
+inline double MTRand::randDblExc(const double &n)
+{
+ return randDblExc() * n;
+}
+
+inline double MTRand::rand53()
+{
+ uint32 a = randInt() >> 5, b = randInt() >> 6;
+ return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); // by Isaku Wada
+}
+
+inline double MTRand::randNorm(const double &mean, const double &variance)
+{
+ // Return a real number from a normal (Gaussian) distribution with given
+ // mean and variance by Box-Muller method
+ double r = sqrt(-2.0 * log(1.0 - randDblExc())) * variance;
+ double phi = 2.0 * 3.14159265358979323846264338328 * randExc();
+ return mean + r * cos(phi);
+}
+
+inline MTRand::uint32 MTRand::randInt()
+{
+ // Pull a 32-bit integer from the generator state
+ // Every other access function simply transforms the numbers extracted here
+
+ if (left == 0)
+ reload();
+ --left;
+
+ uint32 s1;
+ s1 = *pNext++;
+ s1 ^= (s1 >> 11);
+ s1 ^= (s1 << 7) & 0x9d2c5680UL;
+ s1 ^= (s1 << 15) & 0xefc60000UL;
+ return (s1 ^ (s1 >> 18));
+}
+
+inline MTRand::uint32 MTRand::randInt(const uint32 &n)
+{
+ // Find which bits are used in n
+ // Optimized by Magnus Jonsson (magnus@smartelectronix.com)
+ uint32 used = n;
+ used |= used >> 1;
+ used |= used >> 2;
+ used |= used >> 4;
+ used |= used >> 8;
+ used |= used >> 16;
+
+ // Draw numbers until one is found in [0,n]
+ uint32 i;
+ do
+ i = randInt() & used; // toss unused bits to shorten search
+ while (i > n);
+ return i;
+}
+
+inline void MTRand::seed(const uint32 oneSeed)
+{
+ // Seed the generator with a simple uint32
+ initialize(oneSeed);
+ reload();
+}
+
+inline void MTRand::seed(uint32 *const bigSeed, const uint32 seedLength)
+{
+ // Seed the generator with an array of uint32's
+ // There are 2^19937-1 possible initial states. This function allows
+ // all of those to be accessed by providing at least 19937 bits (with a
+ // default seed length of N = 624 uint32's). Any bits above the lower 32
+ // in each element are discarded.
+ // Just call seed() if you want to get array from /dev/urandom
+ initialize(19650218UL);
+ const unsigned int Nenum = N;
+ int i = 1;
+ uint32 j = 0;
+ int k = (Nenum > seedLength ? Nenum : seedLength);
+ for (; k; --k) {
+ state[i] = state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL);
+ state[i] += (bigSeed[j] & 0xffffffffUL) + j;
+ state[i] &= 0xffffffffUL;
+ ++i;
+ ++j;
+ if (i >= N) {
+ state[0] = state[N - 1];
+ i = 1;
+ }
+ if (j >= seedLength)
+ j = 0;
+ }
+ for (k = N - 1; k; --k) {
+ state[i] = state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL);
+ state[i] -= i;
+ state[i] &= 0xffffffffUL;
+ ++i;
+ if (i >= N) {
+ state[0] = state[N - 1];
+ i = 1;
+ }
+ }
+ state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array
+ reload();
+}
+
+inline void MTRand::seed()
+{
+ // Seed the generator with an array from /dev/urandom if available
+ // Otherwise use a hash of time() and clock() values
+
+ // First try getting an array from /dev/urandom
+ FILE *urandom = fopen("/dev/urandom", "rb");
+ if (urandom) {
+ uint32 bigSeed[N];
+ uint32 *s = bigSeed;
+ int i = N;
+ bool success = true;
+ while (success && i--)
+ success = fread(s++, sizeof(uint32), 1, urandom);
+ fclose(urandom);
+ if (success) {
+ seed(bigSeed, N);
+ return;
+ }
+ }
+
+ // Was not successful, so use time() and clock() instead
+ seed(hash(time(NULL), clock()));
+}
+
+inline void MTRand::initialize(const uint32 intseed)
+{
+ // Initialize generator state with seed
+ // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
+ // In previous versions, most significant bits (MSBs) of the seed affect
+ // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
+ uint32 *s = state;
+ uint32 *r = state;
+ int i = 1;
+ *s++ = intseed & 0xffffffffUL;
+ for (; i < N; ++i) {
+ *s++ = (1812433253UL * (*r ^ (*r >> 30)) + i) & 0xffffffffUL;
+ r++;
+ }
+}
+
+inline void MTRand::reload()
+{
+ // Generate N new values in state
+ // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
+ uint32 *p = state;
+ int i;
+ for (i = N - M; i--; ++p)
+ *p = twist(p[M], p[0], p[1]);
+ for (i = M; --i; ++p)
+ *p = twist(p[M - N], p[0], p[1]);
+ *p = twist(p[M - N], p[0], state[0]);
+
+ left = N, pNext = state;
+}
+
+inline MTRand::uint32 MTRand::hash(time_t t, clock_t c)
+{
+ // Get a uint32 from t and c
+ // Better than uint32(x) in case x is floating point in [0,1]
+ // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
+
+ static uint32 differ = 0; // guarantee time-based seeds will change
+
+ uint32 h1 = 0;
+ unsigned char *p = (unsigned char *)&t;
+ for (size_t i = 0; i < sizeof(t); ++i) {
+ h1 *= std::numeric_limits<unsigned char>::max() + 2U;
+ h1 += p[i];
+ }
+ uint32 h2 = 0;
+ p = (unsigned char *)&c;
+ for (size_t j = 0; j < sizeof(c); ++j) {
+ h2 *= std::numeric_limits<unsigned char>::max() + 2U;
+ h2 += p[j];
+ }
+ return (h1 + differ++) ^ h2;
+}
+
+inline void MTRand::save(uint32 *saveArray) const
+{
+ uint32 *sa = saveArray;
+ const uint32 *s = state;
+ int i = N;
+ for (; i--; *sa++ = *s++) {
+ }
+ *sa = left;
+}
+
+inline void MTRand::load(uint32 *const loadArray)
+{
+ uint32 *s = state;
+ uint32 *la = loadArray;
+ int i = N;
+ for (; i--; *s++ = *la++) {
+ }
+ left = *la;
+ pNext = &state[N - left];
+}
+
+inline std::ostream &operator<<(std::ostream &os, const MTRand &mtrand)
+{
+ const MTRand::uint32 *s = mtrand.state;
+ int i = mtrand.N;
+ for (; i--; os << *s++ << "\t") {
+ }
+ return os << mtrand.left;
+}
+
+inline std::istream &operator>>(std::istream &is, MTRand &mtrand)
+{
+ MTRand::uint32 *s = mtrand.state;
+ int i = mtrand.N;
+ for (; i--; is >> *s++) {
+ }
+ is >> mtrand.left;
+ mtrand.pNext = &mtrand.state[mtrand.N - mtrand.left];
+ return is;
+}
+
+// simple interface to mersenne twister
+class RandomStream {
+ public:
+ inline RandomStream(long seed) : mtr(seed){};
+ ~RandomStream()
+ {
+ }
+
+ /*! get a random number from the stream */
+ inline double getDouble(void)
+ {
+ return mtr.rand();
+ };
+ inline float getFloat(void)
+ {
+ return (float)mtr.rand();
+ };
+
+ inline float getFloat(float min, float max)
+ {
+ return mtr.rand(max - min) + min;
+ };
+ inline float getRandNorm(float mean, float var)
+ {
+ return mtr.randNorm(mean, var);
+ };
+
+#if FLOATINGPOINT_PRECISION == 1
+ inline Real getReal()
+ {
+ return getFloat();
+ }
+
+#else
+ inline Real getReal()
+ {
+ return getDouble();
+ }
+#endif
+
+ inline Vec3 getVec3()
+ {
+ Real a = getReal(), b = getReal(), c = getReal();
+ return Vec3(a, b, c);
+ }
+ inline Vec3 getVec3Norm()
+ {
+ Vec3 a = getVec3();
+ normalize(a);
+ return a;
+ }
+
+ private:
+ MTRand mtr;
+};
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/helper/util/rcmatrix.h b/extern/mantaflow/helper/util/rcmatrix.h
new file mode 100644
index 00000000000..39951cece2e
--- /dev/null
+++ b/extern/mantaflow/helper/util/rcmatrix.h
@@ -0,0 +1,1112 @@
+//
+// Helper matrix class, RCMatrix.h
+// Required for PD optimizations (guiding)
+// Thanks to Ryoichi Ando, and Robert Bridson
+//
+
+#ifndef RCMATRIX3_H
+#define RCMATRIX3_H
+
+#include <iterator>
+#include <cassert>
+#include <vector>
+#include <fstream>
+
+// index type
+#define int_index long long
+
+// link to omp & tbb for now
+#if OPENMP == 1 || TBB == 1
+# define MANTA_ENABLE_PARALLEL 0
+// allow the preconditioner to be computed in parallel? (can lead to slightly non-deterministic
+// results)
+# define MANTA_ENABLE_PARALLEL_PC 0
+// use c++11 code?
+# define MANTA_USE_CPP11 1
+#else
+# define MANTA_ENABLE_PARALLEL 0
+# define MANTA_ENABLE_PARALLEL_PC 0
+# define MANTA_USE_CPP11 0
+#endif
+
+#if MANTA_ENABLE_PARALLEL == 1
+# include <thread>
+# include <algorithm>
+
+static const int manta_num_threads = std::thread::hardware_concurrency();
+
+// For clang
+# define parallel_for(total_size) \
+ { \
+ int_index parallel_array_size = (total_size); \
+ std::vector<std::thread> threads(manta_num_threads); \
+ for (int thread_number = 0; thread_number < manta_num_threads; thread_number++) { \
+ threads[thread_number] = std::thread([&](int_index parallel_array_size, int_index thread_number ) { \
+ for( int_index parallel_index=thread_number; parallel_index < parallel_array_size; parallel_index += manta_num_threads ) {
+
+# define parallel_end \
+ } \
+ },parallel_array_size,thread_number); \
+ } \
+ for (auto &thread : threads) \
+ thread.join(); \
+ }
+
+# define parallel_block \
+ { \
+ std::vector<std::thread> threads; \
+ {
+
+# define do_parallel threads.push_back( std::thread([&]() {
+# define do_end \
+ } ) );
+
+# define block_end \
+ } \
+ for (auto &thread : threads) { \
+ thread.join(); \
+ } \
+ }
+
+#else
+
+# define parallel_for(size) \
+ { \
+ int thread_number = 0; \
+ int_index parallel_index = 0; \
+ for (int_index parallel_index = 0; parallel_index < (int_index)size; parallel_index++) {
+# define parallel_end \
+ } \
+ thread_number = parallel_index = 0; \
+ }
+
+# define parallel_block
+# define do_parallel
+# define do_end
+# define block_end
+
+#endif
+
+#include "vectorbase.h"
+
+namespace Manta {
+
+static const unsigned default_expected_none_zeros = 7;
+
+template<class N, class T> struct RCMatrix {
+ struct RowEntry {
+ std::vector<N> index;
+ std::vector<T> value;
+ };
+ RCMatrix() : n(0), expected_none_zeros(default_expected_none_zeros)
+ {
+ }
+ RCMatrix(N size, N expected_none_zeros = default_expected_none_zeros)
+ : n(0), expected_none_zeros(expected_none_zeros)
+ {
+ resize(size);
+ }
+ RCMatrix(const RCMatrix &m) : n(0), expected_none_zeros(default_expected_none_zeros)
+ {
+ init(m);
+ }
+ RCMatrix &operator=(const RCMatrix &m)
+ {
+ expected_none_zeros = m.expected_none_zeros;
+ init(m);
+ return *this;
+ }
+ RCMatrix &operator=(RCMatrix &&m)
+ {
+ matrix = m.matrix;
+ offsets = m.offsets;
+ expected_none_zeros = m.expected_none_zeros;
+ n = m.n;
+ m.n = 0;
+ m.matrix.clear();
+ m.offsets.clear();
+ return *this;
+ }
+ RCMatrix(RCMatrix &&m)
+ : n(m.n), expected_none_zeros(m.expected_none_zeros), matrix(m.matrix), offsets(m.offsets)
+ {
+ m.n = 0;
+ m.matrix.clear();
+ m.offsets.clear();
+ }
+ void init(const RCMatrix &m)
+ {
+ expected_none_zeros = m.expected_none_zeros;
+ resize(m.n);
+ parallel_for(n)
+ {
+ N i = parallel_index;
+ if (m.matrix[i]) {
+ alloc_row(i);
+ matrix[i]->index = m.matrix[i]->index;
+ matrix[i]->value = m.matrix[i]->value;
+ }
+ else {
+ dealloc_row(i);
+ }
+ }
+ parallel_end
+ }
+ ~RCMatrix()
+ {
+ clear();
+ }
+ void clear()
+ {
+ for (N i = 0; i < n; i++) {
+ dealloc_row(i);
+ matrix[i] = NULL;
+ if (offsets.size())
+ offsets[i] = 0;
+ }
+ };
+ bool empty(N i) const
+ {
+ return matrix[i] == NULL;
+ }
+ N row_nonzero_size(N i) const
+ {
+ return matrix[i] == NULL ? 0 : matrix[i]->index.size();
+ }
+ void resize(N size, N expected_none_zeros = 0)
+ {
+ if (!expected_none_zeros) {
+ expected_none_zeros = this->expected_none_zeros;
+ }
+ if (n > size) {
+ // Shrinking
+ for (N i = size ? size - 1 : 0; i < n; i++)
+ dealloc_row(i);
+ matrix.resize(size);
+ }
+ else if (n < size) {
+ // Expanding
+ matrix.resize(size);
+ for (N i = n; i < size; i++) {
+ matrix[i] = NULL;
+ if (offsets.size())
+ offsets[i] = 0;
+ }
+ }
+ n = size;
+ }
+ void alloc_row(N i)
+ {
+ assert(i < n);
+ if (!matrix[i]) {
+ matrix[i] = new RowEntry;
+ matrix[i]->index.reserve(expected_none_zeros);
+ matrix[i]->value.reserve(expected_none_zeros);
+ if (offsets.size())
+ offsets[i] = 0;
+ }
+ }
+ void dealloc_row(N i)
+ {
+ assert(i < n);
+ if (matrix[i]) {
+ if (offsets.empty() || !offsets[i])
+ delete matrix[i];
+ matrix[i] = NULL;
+ if (offsets.size())
+ offsets[i] = 0;
+ }
+ }
+ T operator()(N i, N j) const
+ {
+ assert(i < n);
+ for (Iterator it = row_begin(i); it; ++it) {
+ if (it.index() == j)
+ return it.value();
+ }
+ return T(0.0);
+ }
+ void add_to_element_checked(N i, N j, T val)
+ {
+ if ((i < 0) || (j < 0) || (i >= n) || (j >= n))
+ return;
+ add_to_element(i, j, val);
+ }
+ void add_to_element(N i, N j, T increment_value)
+ {
+ if (std::abs(increment_value) > VECTOR_EPSILON) {
+ assert(i < n);
+ assert(offsets.empty() || offsets[i] == 0);
+ alloc_row(i);
+ std::vector<N> &index = matrix[i]->index;
+ std::vector<T> &value = matrix[i]->value;
+ for (N k = 0; k < (N)index.size(); ++k) {
+ if (index[k] == j) {
+ value[k] += increment_value;
+ return;
+ }
+ else if (index[k] > j) {
+ index.insert(index.begin() + k, j);
+ value.insert(value.begin() + k, increment_value);
+ return;
+ }
+ }
+ index.push_back(j);
+ value.push_back(increment_value);
+ }
+ }
+
+ void set_element(N i, N j, T v)
+ {
+ if (std::abs(v) > VECTOR_EPSILON) {
+ assert(i < n);
+ assert(offsets.empty() || offsets[i] == 0);
+ alloc_row(i);
+ std::vector<N> &index = matrix[i]->index;
+ std::vector<T> &value = matrix[i]->value;
+ for (N k = 0; k < (N)index.size(); ++k) {
+ if (index[k] == j) {
+ value[k] = v;
+ return;
+ }
+ else if (index[k] > j) {
+ index.insert(index.begin() + k, j);
+ value.insert(value.begin() + k, v);
+ return;
+ }
+ }
+ index.push_back(j);
+ value.push_back(v);
+ }
+ }
+
+ // Make sure that j is the biggest column in the row, no duplication allowed
+ void fix_element(N i, N j, T v)
+ {
+ if (std::abs(v) > VECTOR_EPSILON) {
+ assert(i < n);
+ assert(offsets.empty() || offsets[i] == 0);
+ alloc_row(i);
+ std::vector<N> &index = matrix[i]->index;
+ std::vector<T> &value = matrix[i]->value;
+ index.push_back(j);
+ value.push_back(v);
+ }
+ }
+ int_index trim_zero_entries(double e = VECTOR_EPSILON)
+ {
+ std::vector<int_index> deleted_entries(n, 0);
+ parallel_for(n)
+ {
+ N i = parallel_index;
+ if (matrix[i]) {
+ std::vector<N> &index = matrix[i]->index;
+ std::vector<T> &value = matrix[i]->value;
+ N head = 0;
+ N k = 0;
+ for (k = 0; k < index.size(); ++k) {
+ if (std::abs(value[k]) > e) {
+ index[head] = index[k];
+ value[head] = value[k];
+ ++head;
+ }
+ }
+ if (head != k) {
+ index.erase(index.begin() + head, index.end());
+ value.erase(value.begin() + head, value.end());
+ deleted_entries[i] += k - head;
+ }
+ if (!offsets.size() && !head) {
+ remove_row(i);
+ }
+ }
+ }
+ parallel_end
+ //
+ int_index sum_deleted(0);
+ for (int_index i = 0; i < n; i++)
+ sum_deleted += deleted_entries[i];
+ return sum_deleted;
+ }
+ void remove_reference(N i)
+ {
+ if (offsets.size() && offsets[i] && matrix[i]) {
+ RowEntry *save = matrix[i];
+ matrix[i] = new RowEntry;
+ *matrix[i] = *save;
+ for (N &index : matrix[i]->index)
+ index += offsets[i];
+ offsets[i] = 0;
+ }
+ }
+ void remove_row(N i)
+ {
+ dealloc_row(i);
+ }
+ bool is_symmetric(double e = VECTOR_EPSILON) const
+ {
+ std::vector<bool> flags(n, true);
+ parallel_for(n)
+ {
+ N i = parallel_index;
+ bool flag = true;
+ for (Iterator it = row_begin(i); it; ++it) {
+ N index = it.index();
+ T value = it.value();
+ if (std::abs(value) > e) {
+ bool found_entry = false;
+ for (Iterator it_i = row_begin(index); it_i; ++it_i) {
+ if (it_i.index() == i) {
+ found_entry = true;
+ if (std::abs(value - it_i.value()) > e) {
+ flag = false;
+ break;
+ }
+ }
+ }
+ if (!found_entry)
+ flag = false;
+ if (!flag)
+ break;
+ }
+ }
+ flags[i] = flag;
+ }
+ parallel_end for (N i = 0; i < matrix.size(); ++i)
+ {
+ if (!flags[i])
+ return false;
+ }
+ return true;
+ }
+
+ void expand()
+ {
+ if (offsets.empty())
+ return;
+ for (N i = 1; i < n; i++) {
+ if (offsets[i]) {
+ RowEntry *ref = matrix[i];
+ matrix[i] = new RowEntry;
+ *matrix[i] = *ref;
+ for (N j = 0; j < (N)matrix[i]->index.size(); j++) {
+ matrix[i]->index[j] += offsets[i];
+ }
+ }
+ }
+ offsets.resize(0);
+ }
+
+ N column(N i) const
+ {
+ return empty(i) ? 0 : row_begin(i, row_nonzero_size(i) - 1).index();
+ }
+ N getColumnSize() const
+ {
+ N max_column(0);
+ auto column = [&](N i) {
+ N max_column(0);
+ for (Iterator it = row_begin(i); it; ++it)
+ max_column = std::max(max_column, it.index());
+ return max_column + 1;
+ };
+ for (N i = 0; i < n; i++)
+ max_column = std::max(max_column, column(i));
+ return max_column;
+ }
+ N getNonzeroSize() const
+ {
+ N nonzeros(0);
+ for (N i = 0; i < n; ++i) {
+ nonzeros += row_nonzero_size(i);
+ }
+ return nonzeros;
+ }
+ class Iterator : std::iterator<std::input_iterator_tag, T> {
+ public:
+ Iterator(const RowEntry *rowEntry, N k, N offset) : rowEntry(rowEntry), k(k), offset(offset)
+ {
+ }
+ operator bool() const
+ {
+ return rowEntry != NULL && k < (N)rowEntry->index.size();
+ }
+ Iterator &operator++()
+ {
+ ++k;
+ return *this;
+ }
+ T value() const
+ {
+ return rowEntry->value[k];
+ }
+ N index() const
+ {
+ return rowEntry->index[k] + offset;
+ }
+ N index_raw() const
+ {
+ return rowEntry->index[k];
+ }
+ N size() const
+ {
+ return rowEntry == NULL ? 0 : rowEntry->index.size();
+ }
+
+ protected:
+ const RowEntry *rowEntry;
+ N k, offset;
+ };
+ Iterator row_begin(N n, N k = 0) const
+ {
+ return Iterator(matrix[n], k, offsets.size() ? offsets[n] : 0);
+ }
+ class DynamicIterator : public Iterator {
+ public:
+ DynamicIterator(RowEntry *rowEntry, N k, N offset)
+ : rowEntry(rowEntry), Iterator(rowEntry, k, offset)
+ {
+ }
+ void setValue(T value)
+ {
+ rowEntry->value[Iterator::k] = value;
+ }
+ void setIndex(N index)
+ {
+ rowEntry->index[Iterator::k] = index;
+ }
+
+ protected:
+ RowEntry *rowEntry;
+ };
+ DynamicIterator dynamic_row_begin(N n, N k = 0)
+ {
+ N offset = offsets.size() ? offsets[n] : 0;
+ if (offset) {
+ printf("---- Warning ----\n");
+ printf("Dynamic iterator is not allowed for referenced rows.\n");
+ printf("You should be very careful otherwise this causes some bugs.\n");
+ printf(
+ "We encourage you that you convert this row into a raw format, then loop over it...\n");
+ printf("-----------------\n");
+ exit(0);
+ }
+ return DynamicIterator(matrix[n], k, offset);
+ }
+ RCMatrix transpose(N rowsize = 0,
+ unsigned expected_none_zeros = default_expected_none_zeros) const
+ {
+ if (!rowsize)
+ rowsize = getColumnSize();
+ RCMatrix result(rowsize, expected_none_zeros);
+ for (N i = 0; i < n; i++) {
+ for (Iterator it = row_begin(i); it; ++it)
+ result.fix_element(it.index(), i, it.value());
+ }
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+
+ RCMatrix getKtK() const
+ {
+ RCMatrix m = transpose();
+ RCMatrix result(n, expected_none_zeros);
+ // Run in parallel
+ parallel_for(result.n)
+ {
+ N i = parallel_index;
+ for (Iterator it_A = m.row_begin(i); it_A; ++it_A) {
+ N j = it_A.index();
+ assert(j < n);
+ T a = it_A.value();
+ if (std::abs(a) > VECTOR_EPSILON) {
+ for (Iterator it_B = row_begin(j); it_B; ++it_B) {
+ // result.add_to_element(i,it_B.index(),it_B.value()*a);
+ double value = it_B.value() * a;
+ if (std::abs(value) > VECTOR_EPSILON)
+ result.add_to_element(i, it_B.index(), value);
+ }
+ }
+ }
+ }
+ parallel_end
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+
+ RCMatrix operator*(const RCMatrix &m) const
+ {
+ RCMatrix result(n, expected_none_zeros);
+ // Run in parallel
+ parallel_for(result.n)
+ {
+ N i = parallel_index;
+ for (Iterator it_A = row_begin(i); it_A; ++it_A) {
+ N j = it_A.index();
+ assert(j < m.n);
+ T a = it_A.value();
+ if (std::abs(a) > VECTOR_EPSILON) {
+ for (Iterator it_B = m.row_begin(j); it_B; ++it_B) {
+ // result.add_to_element(i,it_B.index(),it_B.value()*a);
+ double value = it_B.value() * a;
+ if (std::abs(value) > VECTOR_EPSILON)
+ result.add_to_element(i, it_B.index(), value);
+ }
+ }
+ }
+ }
+ parallel_end
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+
+ RCMatrix sqrt() const
+ {
+ RCMatrix result(n, expected_none_zeros);
+ // Run in parallel
+ parallel_for(result.n)
+ {
+ N i = parallel_index;
+ for (Iterator it_A = row_begin(i); it_A; ++it_A) {
+ N j = it_A.index();
+ result.set_element(i, j, std::sqrt(it_A.value()));
+ }
+ }
+ parallel_end
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+
+ RCMatrix operator*(const double k) const
+ {
+ RCMatrix result(n, expected_none_zeros);
+ // Run in parallel
+ parallel_for(result.n)
+ {
+ N i = parallel_index;
+ for (Iterator it_A = row_begin(i); it_A; ++it_A) {
+ N j = it_A.index();
+ result.add_to_element(i, j, it_A.value() * k);
+ }
+ }
+ parallel_end
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+
+ RCMatrix applyKernel(const RCMatrix &kernel, const int nx, const int ny) const
+ {
+ RCMatrix result(n, expected_none_zeros);
+ // find center position of kernel (half of kernel size)
+ int kCols = kernel.n, kRows = kernel.n, rows = nx, cols = ny;
+ int kCenterX = kCols / 2;
+ int kCenterY = kRows / 2;
+ // Run in parallel
+ parallel_for(result.n)
+ {
+ N i = parallel_index;
+ if (i >= rows)
+ break;
+ for (Iterator it_A = row_begin(i); it_A; ++it_A) {
+ N j = it_A.index();
+ if (j >= cols)
+ break;
+ for (int m = 0; m < kRows; ++m) { // kernel rows
+ int mm = kRows - 1 - m; // row index of flipped kernel
+ for (int n = 0; n < kCols; ++n) { // kernel columns
+ int nn = kCols - 1 - n; // column index of flipped kernel
+ // index of input signal, used for checking boundary
+ int ii = i + (m - kCenterY);
+ int jj = j + (n - kCenterX);
+ // ignore input samples which are out of bound
+ if (ii >= 0 && ii < rows && jj >= 0 && jj < cols)
+ result.add_to_element(i, j, (*this)(ii, jj) * kernel(mm, nn));
+ }
+ }
+ }
+ }
+ parallel_end
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+
+ RCMatrix applyHorizontalKernel(const RCMatrix &kernel, const int nx, const int ny) const
+ {
+ RCMatrix result(n, expected_none_zeros);
+ // find center position of kernel (half of kernel size)
+ int kCols = kernel.n, kRows = 1, rows = nx, cols = ny;
+ int kCenterX = kCols / 2;
+ int kCenterY = kRows / 2;
+ // Run in parallel
+ parallel_for(result.n)
+ {
+ N i = parallel_index;
+ if (i >= rows)
+ break;
+ for (Iterator it_A = row_begin(i); it_A; ++it_A) {
+ N j = it_A.index();
+ if (j >= cols)
+ break;
+ for (int m = 0; m < kRows; ++m) { // kernel rows
+ int mm = kRows - 1 - m; // row index of flipped kernel
+ for (int n = 0; n < kCols; ++n) { // kernel columns
+ int nn = kCols - 1 - n; // column index of flipped kernel
+ // index of input signal, used for checking boundary
+ int ii = i + (m - kCenterY);
+ int jj = j + (n - kCenterX);
+ // ignore input samples which are out of bound
+ if (ii >= 0 && ii < rows && jj >= 0 && jj < cols)
+ result.add_to_element(i, j, (*this)(ii, jj) * kernel(mm, nn));
+ }
+ }
+ }
+ }
+ parallel_end
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+
+ RCMatrix applyVerticalKernel(const RCMatrix &kernel, const int nx, const int ny) const
+ {
+ RCMatrix result(n, expected_none_zeros);
+ // find center position of kernel (half of kernel size)
+ int kCols = 1, kRows = kernel.n, rows = nx, cols = ny;
+ int kCenterX = kCols / 2;
+ int kCenterY = kRows / 2;
+ // Run in parallel
+ parallel_for(result.n)
+ {
+ N i = parallel_index;
+ if (i >= rows)
+ break;
+ for (Iterator it_A = row_begin(i); it_A; ++it_A) {
+ N j = it_A.index();
+ if (j >= cols)
+ break;
+ for (int m = 0; m < kRows; ++m) { // kernel rows
+ int mm = kRows - 1 - m; // row index of flipped kernel
+ for (int n = 0; n < kCols; ++n) { // kernel columns
+ int nn = kCols - 1 - n; // column index of flipped kernel
+ // index of input signal, used for checking boundary
+ int ii = i + (m - kCenterY);
+ int jj = j + (n - kCenterX);
+ // ignore input samples which are out of bound
+ if (ii >= 0 && ii < rows && jj >= 0 && jj < cols)
+ result.add_to_element(i, j, (*this)(ii, jj) * kernel(mm, nn));
+ }
+ }
+ }
+ }
+ parallel_end
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+
+ RCMatrix applySeparableKernel(const RCMatrix &kernelH,
+ const RCMatrix &kernelV,
+ const int nx,
+ const int ny) const
+ {
+ return applyHorizontalKernel(kernelH, nx, ny).applyVerticalKernel(kernelV, nx, ny);
+ }
+
+ RCMatrix applySeparableKernelTwice(const RCMatrix &kernelH,
+ const RCMatrix &kernelV,
+ const int nx,
+ const int ny) const
+ {
+ return applySeparableKernel(kernelH, kernelV, nx, ny)
+ .applySeparableKernel(kernelH, kernelV, nx, ny);
+ }
+
+ std::vector<T> operator*(const std::vector<T> &rhs) const
+ {
+ std::vector<T> result(n, 0.0);
+ multiply(rhs, result);
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+ void multiply(const std::vector<T> &rhs, std::vector<T> &result) const
+ {
+ result.resize(n);
+ for (N i = 0; i < n; i++) {
+ T new_value = 0.0;
+ for (Iterator it = row_begin(i); it; ++it) {
+ N j_index = it.index();
+ assert(j_index < rhs.size());
+ new_value += rhs[j_index] * it.value();
+ }
+ result[i] = new_value;
+ }
+ }
+ RCMatrix operator+(const RCMatrix &m) const
+ {
+ RCMatrix A(*this);
+ return std::move(A.add(m));
+ }
+ RCMatrix &add(const RCMatrix &m)
+ {
+ if (m.n > n)
+ resize(m.n);
+ parallel_for(m.n)
+ {
+ N i = parallel_index;
+ for (Iterator it = m.row_begin(i); it; ++it) {
+ add_to_element(i, it.index(), it.value());
+ }
+ }
+ parallel_end return *this;
+ }
+ RCMatrix operator-(const RCMatrix &m) const
+ {
+ RCMatrix A(*this);
+ return std::move(A.sub(m));
+ }
+ RCMatrix &sub(const RCMatrix &m)
+ {
+ if (m.n > n)
+ resize(m.n);
+ parallel_for(m.n)
+ {
+ N i = parallel_index;
+ for (Iterator it = m.row_begin(i); it; ++it) {
+ add_to_element(i, it.index(), -it.value());
+ }
+ }
+ parallel_end return *this;
+ }
+ RCMatrix &replace(const RCMatrix &m, int rowInd, int colInd)
+ {
+ if (m.n > n)
+ resize(m.n);
+ parallel_for(m.n)
+ {
+ N i = parallel_index;
+ for (Iterator it = m.row_begin(i); it; ++it) {
+ set_element(i + rowInd, it.index() + colInd, it.value());
+ }
+ }
+ parallel_end return *this;
+ }
+ Real max_residual(const std::vector<T> &lhs, const std::vector<T> &rhs) const
+ {
+ std::vector<T> r = operator*(lhs);
+ Real max_residual = 0.0;
+ for (N i = 0; i < rhs.size(); i++) {
+ if (!empty(i))
+ max_residual = std::max(max_residual, std::abs(r[i] - rhs[i]));
+ }
+ return max_residual;
+ }
+ std::vector<T> residual_vector(const std::vector<T> &lhs, const std::vector<T> &rhs) const
+ {
+ std::vector<T> result = operator*(lhs);
+ assert(result.size() == rhs.size());
+ for (N i = 0; i < result.size(); i++) {
+ result[i] = std::abs(result[i] - rhs[i]);
+ }
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+ T norm() const
+ {
+ T result(0.0);
+ for (N i = 0; i < n; ++i) {
+ for (Iterator it = row_begin(i); it; ++it) {
+ result = std::max(result, std::abs(it.value()));
+ }
+ }
+ return result;
+ }
+
+ T norm_L2_sqr() const
+ {
+ T result(0.0);
+ for (N i = 0; i < n; ++i) {
+ for (Iterator it = row_begin(i); it; ++it) {
+ result += (it.value()) * (it.value());
+ }
+ }
+ return result;
+ }
+
+ void write_matlab(std::ostream &output,
+ unsigned int rows,
+ unsigned int columns,
+ const char *variable_name)
+ {
+ output << variable_name << "=sparse([";
+ for (N i = 0; i < n; ++i) {
+ if (matrix[i]) {
+ const std::vector<N> &index = matrix[i]->index;
+ for (N j = 0; j < (N)index.size(); ++j) {
+ output << i + 1 << " ";
+ }
+ }
+ }
+ output << "],...\n [";
+ for (N i = 0; i < n; ++i) {
+ if (matrix[i]) {
+ const std::vector<N> &index = matrix[i]->index;
+ for (N j = 0; j < (N)index.size(); ++j) {
+ output << index[j] + (offsets.empty() ? 0 : offsets[i]) + 1 << " ";
+ }
+ }
+ }
+ output << "],...\n [";
+ for (N i = 0; i < n; ++i) {
+ if (matrix[i]) {
+ const std::vector<T> &value = matrix[i]->value;
+ for (N j = 0; j < value.size(); ++j) {
+ output << value[j] << " ";
+ }
+ }
+ }
+ output << "], " << rows << ", " << columns << ");" << std::endl;
+ };
+ void export_matlab(std::string filename, std::string name)
+ {
+ // Export this matrix
+ std::ofstream file;
+ file.open(filename.c_str());
+ write_matlab(file, n, getColumnSize(), name.c_str());
+ file.close();
+ }
+ void print_readable(std::string name, bool printNonZero = true)
+ {
+ std::cout << name << " \n";
+ for (int i = 0; i < n; ++i) {
+ for (int j = 0; j < n; ++j) {
+ if (printNonZero) {
+ if ((*this)(i, j) == 0) {
+ std::cout << " .";
+ continue;
+ }
+ }
+ else {
+ if ((*this)(i, j) == 0) {
+ continue;
+ }
+ }
+
+ if ((*this)(i, j) >= 0)
+ std::cout << " ";
+ std::cout << " " << (*this)(i, j);
+ }
+ std::cout << " \n";
+ }
+ }
+ ///
+ N n;
+ N expected_none_zeros;
+ std::vector<RowEntry *> matrix;
+ std::vector<int> offsets;
+};
+
+template<class N, class T>
+static inline RCMatrix<N, T> operator*(const std::vector<T> &diagonal, const RCMatrix<N, T> &A)
+{
+ RCMatrix<N, T> result(A);
+ parallel_for(result.n)
+ {
+ N row(parallel_index);
+ for (auto it = result.dynamic_row_begin(row); it; ++it) {
+ it.setValue(it.value() * diagonal[row]);
+ }
+ }
+ parallel_end return std::move(result);
+}
+
+template<class N, class T> struct RCFixedMatrix {
+ std::vector<N> rowstart;
+ std::vector<N> index;
+ std::vector<T> value;
+ N n;
+ N max_rowlength;
+ //
+ RCFixedMatrix() : n(0), max_rowlength(0)
+ {
+ }
+ RCFixedMatrix(const RCMatrix<N, T> &matrix)
+ {
+ n = matrix.n;
+ rowstart.resize(n + 1);
+ rowstart[0] = 0;
+ max_rowlength = 0;
+ for (N i = 0; i < n; i++) {
+ if (!matrix.empty(i)) {
+ rowstart[i + 1] = rowstart[i] + matrix.row_nonzero_size(i);
+ max_rowlength = std::max(max_rowlength, rowstart[i + 1] - rowstart[i]);
+ }
+ else {
+ rowstart[i + 1] = rowstart[i];
+ }
+ }
+ value.resize(rowstart[n]);
+ index.resize(rowstart[n]);
+ N j = 0;
+ for (N i = 0; i < n; i++) {
+ for (typename RCMatrix<N, T>::Iterator it = matrix.row_begin(i); it; ++it) {
+ value[j] = it.value();
+ index[j] = it.index();
+ ++j;
+ }
+ }
+ }
+ class Iterator : std::iterator<std::input_iterator_tag, T> {
+ public:
+ Iterator(N start, N end, const std::vector<N> &index, const std::vector<T> &value)
+ : index_array(index), value_array(value), k(start), start(start), end(end)
+ {
+ }
+ operator bool() const
+ {
+ return k < end;
+ }
+ Iterator &operator++()
+ {
+ ++k;
+ return *this;
+ }
+ T value() const
+ {
+ return value_array[k];
+ }
+ N index() const
+ {
+ return index_array[k];
+ }
+ N size() const
+ {
+ return end - start;
+ }
+
+ private:
+ const std::vector<N> &index_array;
+ const std::vector<T> &value_array;
+ N k, start, end;
+ };
+ Iterator row_begin(N n) const
+ {
+ return Iterator(rowstart[n], rowstart[n + 1], index, value);
+ }
+ std::vector<T> operator*(const std::vector<T> &rhs) const
+ {
+ std::vector<T> result(n, 0.0);
+ multiply(rhs, result);
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+ void multiply(const std::vector<T> &rhs, std::vector<T> &result) const
+ {
+ result.resize(n);
+ parallel_for(n)
+ {
+ N i = parallel_index;
+ T new_value = 0.0;
+ for (Iterator it = row_begin(i); it; ++it) {
+ N j_index = it.index();
+ assert(j_index < rhs.size());
+ new_value += rhs[j_index] * it.value();
+ }
+ result[i] = new_value;
+ }
+ parallel_end
+ }
+ RCMatrix<N, T> operator*(const RCFixedMatrix &m) const
+ {
+ RCMatrix<N, T> result(n, max_rowlength);
+ // Run in parallel
+ parallel_for(result.n)
+ {
+ N i = parallel_index;
+ for (Iterator it_A = row_begin(i); it_A; ++it_A) {
+ N j = it_A.index();
+ assert(j < m.n);
+ T a = it_A.value();
+ if (std::abs(a) > VECTOR_EPSILON) {
+ for (Iterator it_B = m.row_begin(j); it_B; ++it_B) {
+ result.add_to_element(i, it_B.index(), it_B.value() * a);
+ }
+ }
+ }
+ }
+ parallel_end
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+
+ RCMatrix<N, T> toRCMatrix() const
+ {
+ RCMatrix<N, T> result(n, 0);
+ parallel_for(n)
+ {
+ N i = parallel_index;
+ N size = rowstart[i + 1] - rowstart[i];
+ result.matrix[i] = new typename RCMatrix<N, T>::RowEntry;
+ result.matrix[i]->index.resize(size);
+ result.matrix[i]->value.resize(size);
+ for (N j = 0; j < size; j++) {
+ result.matrix[i]->index[j] = index[rowstart[i] + j];
+ result.matrix[i]->value[j] = value[rowstart[i] + j];
+ }
+ }
+ parallel_end
+#if MANTA_USE_CPP11 == 1
+ return std::move(result);
+#else
+ return result;
+#endif
+ }
+};
+
+typedef RCMatrix<int, Real> Matrix;
+typedef RCFixedMatrix<int, Real> FixedMatrix;
+
+} // namespace Manta
+
+#undef parallel_for
+#undef parallel_end
+
+#undef parallel_block
+#undef do_parallel
+#undef do_end
+#undef block_end
+
+#endif
diff --git a/extern/mantaflow/helper/util/simpleimage.cpp b/extern/mantaflow/helper/util/simpleimage.cpp
new file mode 100644
index 00000000000..9846fa5bd96
--- /dev/null
+++ b/extern/mantaflow/helper/util/simpleimage.cpp
@@ -0,0 +1,312 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Simple image IO
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "simpleimage.h"
+
+namespace Manta {
+
+// write rectangle to ppm
+bool SimpleImage::writePpm(
+ std::string filename, int minx, int miny, int maxx, int maxy, bool invertXY)
+{
+ int w = maxx - minx;
+ int h = maxy - miny;
+
+ if (w <= 0 || h <= 0 || w > mSize[0] || h > mSize[1]) {
+ errMsg("SimpleImage::WritePPM Invalid rect: w="
+ << w << ", h=" << h << ", size=" << mSize[0] << "," << mSize[1] << " min/max: " << minx
+ << "," << miny << " to " << maxx << "," << maxy << ", resetting... ");
+ minx = miny = 0;
+ maxx = mSize[0] - 1;
+ maxy = mSize[1] - 1;
+ w = mSize[0] - 1;
+ h = mSize[1] - 1;
+ }
+
+ FILE *fp = fopen(filename.c_str(), "wb");
+ if (fp == NULL) {
+ errMsg("SimpleImage::WritePPM Unable to open '" << filename << "' for writing");
+ return false;
+ }
+ fprintf(fp, "P6\n%d %d\n255\n", w, h);
+
+ int pixCnt = 0;
+ for (int j = maxy - 1; j >= miny; j--)
+ for (int i = minx; i < maxx; i++) {
+ unsigned char col[3];
+ for (int l = 0; l < 3; l++) {
+ float val;
+ if (invertXY)
+ val = (float)get(j, i)[l];
+ else
+ val = (float)get(i, j)[l];
+
+ val = clamp(val, (float)0., (float)1.);
+ col[l] = (unsigned char)(255. * val);
+ }
+ // col[1] = col[2] = col[0];
+ // if (fwrite(col,1,3, fp) != 3) errMsg("SimpleImage::writePpm fwrite failed");
+ fwrite(col, 1, 3, fp);
+ pixCnt++;
+ // fprintf(stderr,"%d %d %d \n",col[0],i,j);
+ }
+
+ fclose(fp);
+ // debMsg("WritePPM Wrote '"<<filename<<"', region="<<minx<<","<<miny<<" to
+ // "<<maxx<<","<<maxy<<"; "<<pixCnt, 1);
+
+ return true;
+}
+
+bool SimpleImage::writePpm(std::string filename)
+{
+ return writePpm(filename, 0, 0, getSize()[0], getSize()[1]);
+}
+
+// read in a ppm file, and init the image accordingly
+bool SimpleImage::initFromPpm(std::string filename)
+{
+ // maximum length of a line of text
+ const int MAXLINE = 1024;
+
+ int filetype = 0;
+ enum { PGM, PPM }; // possible file types
+
+ FILE *fp;
+ char line[MAXLINE];
+ int size, rowsize;
+
+ // Read in file type
+ fp = fopen(filename.c_str(), "rb");
+ if (!fp) {
+ if (mAbortOnError)
+ debMsg("SimpleImage Error - unable to open file '" << filename << "' for reading", 1);
+ return 0;
+ }
+
+ // 1st line: PPM or PGM
+ if (fgets(line, MAXLINE, fp) == NULL) {
+ if (mAbortOnError)
+ debMsg("SimpleImage::initFromPpm fgets failed", 1);
+ return 0;
+ }
+
+ if (line[1] == '5')
+ filetype = PGM;
+ else if (line[1] == '6')
+ filetype = PPM;
+ else {
+ if (mAbortOnError)
+ debMsg("SimpleImage Error: need PPM or PGM file as input!", 1);
+ return 0;
+ }
+
+ // Read in width and height, & allocate space
+ // 2nd line: width height
+ if (fgets(line, MAXLINE, fp) == NULL) {
+ if (mAbortOnError)
+ errMsg("SimpleImage::initFromPpm fgets failed");
+ return 0;
+ }
+ int windW = 0, windH = 0; // size of the window on the screen
+ int intsFound = sscanf(line, "%d %d", &windW, &windH);
+ if (intsFound == 1) {
+ // only X found, search on next line as well for Y...
+ if (sscanf(line, "%d", &windH) != 1) {
+ if (mAbortOnError)
+ errMsg("initFromPpm Ppm dimensions not found!" << windW << "," << windH);
+ return 0;
+ }
+ else {
+ // ok, found 2 lines
+ // debMsg("initFromPpm Ppm dimensions found!"<<windW<<","<<windH, 1);
+ }
+ }
+ else if (intsFound == 2) {
+ // ok!
+ }
+ else {
+ if (mAbortOnError)
+ errMsg("initFromPpm Ppm dimensions not found at all!" << windW << "," << windH);
+ return 0;
+ }
+
+ if (filetype == PGM) {
+ size = windH * windW; // greymap: 1 byte per pixel
+ rowsize = windW;
+ }
+ else {
+ // filetype == PPM
+ size = windH * windW * 3; // pixmap: 3 bytes per pixel
+ rowsize = windW * 3;
+ }
+
+ unsigned char *pic = new unsigned char[size]; // (GLubyte *)malloc (size);
+
+ // Read in maximum value (ignore) , could be scanned with sscanf as well, but this should be
+ // 255... 3rd line
+ if (fgets(line, MAXLINE, fp) == NULL) {
+ if (mAbortOnError)
+ errMsg("SimpleImage::initFromPpm fgets failed");
+ return 0;
+ }
+
+ // Read in the pixel array row-by-row: 1st row = top scanline */
+ unsigned char *ptr = NULL;
+ ptr = &pic[(windH - 1) * rowsize];
+ for (int i = windH; i > 0; i--) {
+ assertMsg(fread((void *)ptr, 1, rowsize, fp) == rowsize,
+ "SimpleImage::initFromPpm couldn't read data");
+ ptr -= rowsize;
+ }
+
+ // init image
+ this->init(windW, windH);
+ if (filetype == PGM) {
+ // grayscale
+ for (int i = 0; i < windW; i++) {
+ for (int j = 0; j < windH; j++) {
+ double r = (double)pic[(j * windW + i) * 1 + 0] / 255.;
+ (*this)(i, j) = Vec3(r, r, r);
+ }
+ }
+ }
+ else {
+ // convert grid to RGB vec's
+ for (int i = 0; i < windW; i++) {
+ for (int j = 0; j < windH; j++) {
+ // return mpData[y*mSize[0]+x];
+ double r = (double)pic[(j * windW + i) * 3 + 0] / 255.;
+ double g = (double)pic[(j * windW + i) * 3 + 1] / 255.;
+ double b = (double)pic[(j * windW + i) * 3 + 2] / 255.;
+
+ //(*this)(i,j) = Vec3(r,g,b);
+
+ // RGB values have to be rotated to get the right colors!?
+ // this might also be an artifact of photoshop export...?
+ (*this)(i, j) = Vec3(g, b, r);
+ }
+ }
+ }
+
+ delete[] pic;
+ fclose(fp);
+ return 1;
+}
+
+// check index is valid
+bool SimpleImage::indexIsValid(int i, int j)
+{
+ if (i < 0)
+ return false;
+ if (j < 0)
+ return false;
+ if (i >= mSize[0])
+ return false;
+ if (j >= mSize[1])
+ return false;
+ return true;
+}
+
+}; // namespace Manta
+
+//*****************************************************************************
+
+#include "grid.h"
+namespace Manta {
+
+// simple shaded output , note requires grid functionality!
+static void gridPrecompLight(const Grid<Real> &density, Grid<Real> &L, Vec3 light = Vec3(1, 1, 1))
+{
+ FOR_IJK(density)
+ {
+ Vec3 n = getGradient(density, i, j, k) * -1.;
+ normalize(n);
+
+ Real d = dot(light, n);
+ L(i, j, k) = d;
+ }
+}
+
+// simple shading with pre-computed gradient
+static inline void shadeCell(
+ Vec3 &dst, int shadeMode, Real src, Real light, int depthPos, Real depthInv)
+{
+ switch (shadeMode) {
+
+ case 1: {
+ // surfaces
+ Vec3 ambient = Vec3(0.1, 0.1, 0.1);
+ Vec3 diffuse = Vec3(0.9, 0.9, 0.9);
+ Real alpha = src;
+
+ // different color for depth?
+ diffuse[0] *= ((Real)depthPos * depthInv) * 0.7 + 0.3;
+ diffuse[1] *= ((Real)depthPos * depthInv) * 0.7 + 0.3;
+
+ Vec3 col = ambient + diffuse * light;
+
+ // img( 0+i, j ) = (1.-alpha) * img( 0+i, j ) + alpha * col;
+ dst = (1. - alpha) * dst + alpha * col;
+ } break;
+
+ default: {
+ // volumetrics / smoke
+ dst += depthInv * Vec3(src, src, src);
+ } break;
+ }
+}
+
+//! helper to project a grid intro an image (used for ppm export and GUI displauy)
+void projectImg(SimpleImage &img, const Grid<Real> &val, int shadeMode = 0, Real scale = 1.)
+{
+ Vec3i s = val.getSize();
+ Vec3 si = Vec3(1. / (Real)s[0], 1. / (Real)s[1], 1. / (Real)s[2]);
+
+ // init image size
+ int imgSx = s[0];
+ if (val.is3D())
+ imgSx += s[2] + s[0]; // mult views in 3D
+ img.init(imgSx, std::max(s[0], std::max(s[1], s[2])));
+
+ // precompute lighting
+ Grid<Real> L(val);
+ gridPrecompLight(val, L, Vec3(1, 1, 1));
+
+ FOR_IJK(val)
+ {
+ Vec3i idx(i, j, k);
+ shadeCell(img(0 + i, j), shadeMode, val(idx), L(idx), k, si[2]);
+ }
+
+ if (val.is3D()) {
+
+ FOR_IJK(val)
+ {
+ Vec3i idx(i, j, k);
+ shadeCell(img(s[0] + k, j), shadeMode, val(idx), L(idx), i, si[0]);
+ }
+
+ FOR_IJK(val)
+ {
+ Vec3i idx(i, j, k);
+ shadeCell(img(s[0] + s[2] + i, k), shadeMode, val(idx), L(idx), j, si[1]);
+ }
+
+ } // 3d
+
+ img.mapRange(1. / scale);
+}
+
+}; // namespace Manta
diff --git a/extern/mantaflow/helper/util/simpleimage.h b/extern/mantaflow/helper/util/simpleimage.h
new file mode 100644
index 00000000000..d7e88b83f74
--- /dev/null
+++ b/extern/mantaflow/helper/util/simpleimage.h
@@ -0,0 +1,205 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Simple image IO
+ *
+ ******************************************************************************/
+
+#ifndef MANTA_SIMPLEIMAGE_H
+#define MANTA_SIMPLEIMAGE_H
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "manta.h"
+#include "vectorbase.h"
+
+namespace Manta {
+
+//*****************************************************************************
+// simple 2d image class
+// template<class Scalar>
+class SimpleImage {
+ public:
+ // cons/des
+ SimpleImage() : mSize(-1), mpData(NULL), mAbortOnError(true){};
+ virtual ~SimpleImage()
+ {
+ if (mpData)
+ delete[] mpData;
+ };
+
+ //! set to constant
+ void reset(Real val = 0.)
+ {
+ const Vec3 v = Vec3(val);
+ for (int i = 0; i < mSize[0] * mSize[1]; i++)
+ mpData[i] = v;
+ }
+ //! init memory & reset to zero
+ void init(int x, int y)
+ {
+ mSize = Vec3i(x, y, 0);
+ mpData = new Vec3[x * y];
+ reset();
+ };
+
+ inline bool checkIndex(int x, int y)
+ {
+ if ((x < 0) || (y < 0) || (x > mSize[0] - 1) || (y > mSize[1] - 1)) {
+ errMsg("SimpleImage::operator() Invalid access to " << x << "," << y << ", size=" << mSize);
+ return false;
+ }
+ return true;
+ }
+
+ // access element
+ inline Vec3 &operator()(int x, int y)
+ {
+ DEBUG_ONLY(checkIndex(x, y));
+ return mpData[y * mSize[0] + x];
+ };
+ inline Vec3 &get(int x, int y)
+ {
+ return (*this)(x, y);
+ }
+ inline Vec3 &getMap(int x, int y, int z, int axis)
+ {
+ int i = x, j = y;
+ if (axis == 1)
+ j = z;
+ if (axis == 0) {
+ i = y;
+ j = z;
+ }
+ return get(i, j);
+ }
+
+ // output as string, debug
+ std::string toString()
+ {
+ std::ostringstream out;
+
+ for (int j = 0; j < mSize[1]; j++) {
+ for (int i = 0; i < mSize[0]; i++) {
+ // normal zyx order */
+ out << (*this)(i, j);
+ out << " ";
+ }
+ // if (format)
+ out << std::endl;
+ }
+
+ return out.str();
+ }
+
+ // multiply all values by f
+ void add(Vec3 f)
+ {
+ for (int j = 0; j < mSize[1]; j++)
+ for (int i = 0; i < mSize[0]; i++) {
+ get(i, j) += f;
+ }
+ }
+ // multiply all values by f
+ void multiply(Real f)
+ {
+ for (int j = 0; j < mSize[1]; j++)
+ for (int i = 0; i < mSize[0]; i++) {
+ get(i, j) *= f;
+ }
+ }
+ // map 0-f to 0-1 range, clamp
+ void mapRange(Real f)
+ {
+ for (int j = 0; j < mSize[1]; j++)
+ for (int i = 0; i < mSize[0]; i++) {
+ get(i, j) /= f;
+ for (int c = 0; c < 3; ++c)
+ get(i, j)[c] = clamp(get(i, j)[c], (Real)0., (Real)1.);
+ }
+ }
+
+ // normalize max values
+ void normalizeMax()
+ {
+ Real max = normSquare(get(0, 0));
+ for (int j = 0; j < mSize[1]; j++)
+ for (int i = 0; i < mSize[0]; i++) {
+ if (normSquare(get(i, j)) > max)
+ max = normSquare(get(i, j));
+ }
+ max = sqrt(max);
+ Real invMax = 1. / max;
+ for (int j = 0; j < mSize[1]; j++)
+ for (int i = 0; i < mSize[0]; i++) {
+ get(i, j) *= invMax;
+ }
+ };
+
+ // normalize min and max values
+ void normalizeMinMax()
+ {
+ Real max = normSquare(get(0, 0));
+ Real min = max;
+ for (int j = 0; j < mSize[1]; j++)
+ for (int i = 0; i < mSize[0]; i++) {
+ if (normSquare(get(i, j)) > max)
+ max = normSquare(get(i, j));
+ if (normSquare(get(i, j)) < min)
+ min = normSquare(get(i, j));
+ }
+ max = sqrt(max);
+ min = sqrt(min);
+ Real factor = 1. / (max - min);
+ for (int j = 0; j < mSize[1]; j++)
+ for (int i = 0; i < mSize[0]; i++) {
+ get(i, j) -= min;
+ get(i, j) *= factor;
+ }
+ };
+
+ void setAbortOnError(bool set)
+ {
+ mAbortOnError = set;
+ }
+
+ // ppm in/output
+
+ // write whole image
+ bool writePpm(std::string filename);
+ // write rectangle to ppm
+ bool writePpm(
+ std::string filename, int minx, int miny, int maxx, int maxy, bool invertXY = false);
+ // read in a ppm file, and init the image accordingly
+ bool initFromPpm(std::string filename);
+
+ // check index is valid
+ bool indexIsValid(int i, int j);
+
+ //! access
+ inline Vec3i getSize() const
+ {
+ return mSize;
+ }
+
+ protected:
+ //! size
+ Vec3i mSize;
+ //! data
+ Vec3 *mpData;
+ // make errors fatal, or continue?
+ bool mAbortOnError;
+
+}; // SimpleImage
+
+}; // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/helper/util/solvana.h b/extern/mantaflow/helper/util/solvana.h
new file mode 100644
index 00000000000..9dc1ec83654
--- /dev/null
+++ b/extern/mantaflow/helper/util/solvana.h
@@ -0,0 +1,214 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Analytical solutions to some problems
+ * generated using MATLAB symbolic math ccode
+ *
+ ******************************************************************************/
+
+#ifndef _SOLVANA_H
+#define _SOLVANA_H
+
+//! solves the equation [e1 e2 e3; 1 1 1]*x = g using least squares
+inline void SolveOverconstraint34(float e1x,
+ float e1y,
+ float e1z,
+ float e2x,
+ float e2y,
+ float e2z,
+ float e3x,
+ float e3y,
+ float e3z,
+ float g1,
+ float g2,
+ float g3,
+ float &x1,
+ float &x2,
+ float &x3)
+{
+ float e1x2 = e1x * e1x, e1y2 = e1y * e1y, e1z2 = e1z * e1z;
+ float e2x2 = e2x * e2x, e2y2 = e2y * e2y, e2z2 = e2z * e2z;
+ float e3x2 = e3x * e3x, e3y2 = e3y * e3y, e3z2 = e3z * e3z;
+ float e1xy = e1x * e1y, e1xz = e1x * e1z, e1yz = e1y * e1z;
+ float e2xy = e2x * e2y, e2xz = e2x * e2z, e2yz = e2y * e2z;
+ float e3xy = e3x * e3y, e3xz = e3x * e3z, e3yz = e3y * e3z;
+ float e12x = e1x * e2x, e12y = e1y * e2y, e12z = e1z * e2z;
+ float e13x = e1x * e3x, e13y = e1y * e3y, e13z = e1z * e3z;
+ float e23x = e2x * e3x, e23y = e2y * e3y, e23z = e2z * e3z;
+ float t1543 = e3y2 * e2x2;
+ float t1544 = e3x2 * e2y2;
+ float t1545 = e3z2 * e2x2;
+ float t1546 = e3x2 * e2z2;
+ float t1547 = e3z2 * e2y2;
+ float t1548 = e3y2 * e2z2;
+ float t1549 = e2y2 * e1x2;
+ float t1550 = e2x2 * e1y2;
+ float t1551 = e2z2 * e1x2;
+ float t1552 = e2x2 * e1z2;
+ float t1553 = e2z2 * e1y2;
+ float t1554 = e2y2 * e1z2;
+ float t1555 = e3y2 * e1x2;
+ float t1556 = e3x2 * e1y2;
+ float t1557 = e3z2 * e1x2;
+ float t1558 = e3x2 * e1z2;
+ float t1559 = e3z2 * e1y2;
+ float t1560 = e3y2 * e1z2;
+ float t1561 = e3z2 * e2y2 * e1x2;
+ float t1562 = e3y2 * e2z2 * e1x2;
+ float t1563 = e3z2 * e2x2 * e1y2;
+ float t1564 = e3x2 * e2z2 * e1y2;
+ float t1565 = e3y2 * e2x2 * e1z2;
+ float t1566 = e3x2 * e2y2 * e1z2;
+ float t1567 = e1xy * e2x * e3y * 2.0;
+ float t1568 = e1xy * e2y * e3x * 2.0;
+ float t1569 = e1xz * e2x * e3z * 2.0;
+ float t1570 = e1xz * e2z * e3x * 2.0;
+ float t1571 = e1yz * e2y * e3z * 2.0;
+ float t1572 = e1yz * e2z * e3y * 2.0;
+ float t1573 = e1x * e2xy * e3y * 2.0;
+ float t1574 = e1y * e2xy * e3x * 2.0;
+ float t1575 = e1x * e2xz * e3z * 2.0;
+ float t1576 = e1z * e2xz * e3x * 2.0;
+ float t1577 = e1y * e2yz * e3z * 2.0;
+ float t1578 = e1z * e2yz * e3y * 2.0;
+ float t1579 = e1x * e2y * e3xy * 2.0;
+ float t1580 = e1y * e2x * e3xy * 2.0;
+ float t1581 = e1x * e2z * e3xz * 2.0;
+ float t1582 = e1z * e2x * e3xz * 2.0;
+ float t1583 = e1y * e2z * e3yz * 2.0;
+ float t1584 = e1z * e2y * e3yz * 2.0;
+ float t1585 = e1xy * e2xz * e3yz * 2.0;
+ float t1586 = e1xy * e2yz * e3xz * 2.0;
+ float t1587 = e1xz * e2xy * e3yz * 2.0;
+ float t1588 = e1xz * e2yz * e3xy * 2.0;
+ float t1589 = e1yz * e2xy * e3xz * 2.0;
+ float t1590 = e1yz * e2xz * e3xy * 2.0;
+ float t1596 = e12x * e3y2 * 2.0;
+ float t1597 = e13x * e2y2 * 2.0;
+ float t1598 = e23x * e1y2 * 2.0;
+ float t1599 = e12x * e3z2 * 2.0;
+ float t1600 = e13x * e2z2 * 2.0;
+ float t1601 = e12y * e3x2 * 2.0;
+ float t1602 = e13y * e2x2 * 2.0;
+ float t1603 = e23y * e1x2 * 2.0;
+ float t1604 = e23x * e1z2 * 2.0;
+ float t1605 = e12y * e3z2 * 2.0;
+ float t1606 = e13y * e2z2 * 2.0;
+ float t1607 = e12z * e3x2 * 2.0;
+ float t1608 = e13z * e2x2 * 2.0;
+ float t1609 = e23z * e1x2 * 2.0;
+ float t1610 = e23y * e1z2 * 2.0;
+ float t1611 = e12z * e3y2 * 2.0;
+ float t1612 = e13z * e2y2 * 2.0;
+ float t1613 = e23z * e1y2 * 2.0;
+ float t1614 = e1xy * e2xy * 2.0;
+ float t1615 = e1xz * e2xz * 2.0;
+ float t1616 = e1yz * e2yz * 2.0;
+ float t1617 = e1xy * e3xy * 2.0;
+ float t1618 = e1xz * e3xz * 2.0;
+ float t1619 = e1yz * e3yz * 2.0;
+ float t1620 = e2xy * e3xy * 2.0;
+ float t1621 = e2xz * e3xz * 2.0;
+ float t1622 = e2yz * e3yz * 2.0;
+ float t1623 = e1xy * e2xy * e3z2 * 2.0;
+ float t1624 = e1xz * e2xz * e3y2 * 2.0;
+ float t1625 = e1yz * e2yz * e3x2 * 2.0;
+ float t1626 = e1xy * e3xy * e2z2 * 2.0;
+ float t1627 = e1xz * e3xz * e2y2 * 2.0;
+ float t1628 = e1yz * e3yz * e2x2 * 2.0;
+ float t1629 = e2xy * e3xy * e1z2 * 2.0;
+ float t1630 = e2xz * e3xz * e1y2 * 2.0;
+ float t1631 = e2yz * e3yz * e1x2 * 2.0;
+ float t1591 = t1550 + t1551 + t1560 + t1543 + t1552 + t1561 + t1570 + t1544 + t1553 + t1562 +
+ t1571 + t1580 + t1545 + t1554 + t1563 + t1572 + t1581 + t1590 + t1546 + t1555 +
+ t1564 + t1573 + t1582 + t1547 + t1556 + t1565 + t1574 + t1583 + t1548 + t1557 +
+ t1566 + t1575 + t1584 + t1549 + t1558 + t1567 + t1576 + t1585 + t1559 + t1568 +
+ t1577 + t1586 + t1569 + t1578 + t1587 - t1596 + t1579 + t1588 - t1597 + t1589 -
+ t1598 - t1599 - t1600 - t1601 - t1610 - t1602 - t1611 - t1620 - t1603 - t1612 -
+ t1621 - t1630 - t1604 - t1613 - t1622 - t1631 - t1605 - t1614 - t1623 - t1606 -
+ t1615 - t1624 - t1607 - t1616 - t1625 - t1608 - t1617 - t1626 - t1609 - t1618 -
+ t1627 - t1619 - t1628 - t1629;
+ float t1592 = 1.0 / t1591;
+ float t1635 = e13x * e2y2;
+ float t1636 = e13x * e2z2;
+ float t1637 = e13y * e2x2;
+ float t1638 = e13y * e2z2;
+ float t1639 = e13z * e2x2;
+ float t1640 = e13z * e2y2;
+ float t1653 = e23x * 2.0;
+ float t1654 = e23y * 2.0;
+ float t1655 = e23z * 2.0;
+ float t1641 = e3x2 + e3z2 + e3y2 + e2y2 + t1543 + e2z2 + t1544 + e2x2 + t1545 + t1546 + t1547 +
+ t1548 - t1620 - t1621 - t1622 - t1653 - t1654 - t1655;
+ float t1642 = e12x * e3y2;
+ float t1643 = e12x * e3z2;
+ float t1644 = e12y * e3x2;
+ float t1645 = e12y * e3z2;
+ float t1646 = e12z * e3x2;
+ float t1647 = e12z * e3y2;
+ float t1656 = e1x * e2y * e3xy;
+ float t1657 = e1y * e2x * e3xy;
+ float t1658 = e1x * e2z * e3xz;
+ float t1659 = e1z * e2x * e3xz;
+ float t1660 = e1y * e2z * e3yz;
+ float t1661 = e1z * e2y * e3yz;
+ float t1648 = e3x2 + e3z2 + e3y2 - e13x - e13y - e13z + e12x - e23y + e12y + t1642 - e23z -
+ t1660 + e12z + t1643 - t1661 + t1644 + t1645 + t1646 + t1647 - t1656 - t1657 -
+ e23x - t1658 - t1659;
+ float t1679 = e1x * e2xy * e3y;
+ float t1680 = e1y * e2xy * e3x;
+ float t1681 = e1x * e2xz * e3z;
+ float t1682 = e1z * e2xz * e3x;
+ float t1683 = e1y * e2yz * e3z;
+ float t1684 = e1z * e2yz * e3y;
+ float t1652 = e2y2 + e2z2 + e2x2 + e13x + e13y + e13z + t1640 - e12x - e23y - e12y - e23z -
+ e12z + t1635 - t1680 + t1636 - t1681 + t1637 - t1682 + t1638 - t1683 + t1639 -
+ t1684 - e23x - t1679;
+ float t1662 = e23x * e1y2;
+ float t1663 = e23y * e1x2;
+ float t1664 = e23x * e1z2;
+ float t1665 = e23z * e1x2;
+ float t1666 = e23y * e1z2;
+ float t1667 = e23z * e1y2;
+ float t1670 = e1xy * e2x * e3y;
+ float t1671 = e1xy * e2y * e3x;
+ float t1672 = e1xz * e2x * e3z;
+ float t1673 = e1xz * e2z * e3x;
+ float t1674 = e1yz * e2y * e3z;
+ float t1675 = e1yz * e2z * e3y;
+ float t1668 = e1x2 + e1y2 + e1z2 - e13x - e13y - e13z - e12x + e23y - e12y + e23z - e12z -
+ t1670 + t1662 - t1671 + t1663 - t1672 + t1664 - t1673 + t1665 - t1674 + t1666 -
+ t1675 + e23x + t1667;
+ float t1676 = e13x * 2.0;
+ float t1677 = e13y * 2.0;
+ float t1678 = e13z * 2.0;
+ float t1669 = e3x2 + e3z2 + e3y2 + t1560 + e1x2 + t1555 + e1y2 + t1556 + e1z2 + t1557 + t1558 +
+ t1559 - t1617 - t1618 - t1619 - t1676 - t1677 - t1678;
+ float t1686 = e12x * 2.0;
+ float t1687 = e12y * 2.0;
+ float t1688 = e12z * 2.0;
+ float t1685 = t1550 + t1551 + e2y2 + t1552 + e2z2 + t1553 + e2x2 + t1554 + e1x2 + e1y2 + e1z2 +
+ t1549 - t1614 - t1615 - t1616 - t1686 - t1687 - t1688;
+ x1 = -g2 * (-e1y * t1592 * t1641 + e2y * t1592 * t1648 + e3y * t1592 * t1652) -
+ g3 * (-e1z * t1592 * t1641 + e2z * t1592 * t1648 + e3z * t1592 * t1652) -
+ g1 * (-e1x * t1592 * t1641 + e2x * t1592 * t1648 +
+ e3x * t1592 *
+ (e2y2 + e2z2 + e2x2 + e13x + e13y + e13z + t1640 + t1635 + t1636 + t1637 + t1638 +
+ t1639 - e12x - e12y - e12z - e23x - e23y - e23z - e1x * e2xy * e3y -
+ e1y * e2xy * e3x - e1x * e2xz * e3z - e1z * e2xz * e3x - e1y * e2yz * e3z -
+ e1z * e2yz * e3y));
+ x2 = -g1 * (e1x * t1592 * t1648 - e2x * t1592 * t1669 + e3x * t1592 * t1668) -
+ g2 * (e1y * t1592 * t1648 - e2y * t1592 * t1669 + e3y * t1592 * t1668) -
+ g3 * (e1z * t1592 * t1648 - e2z * t1592 * t1669 + e3z * t1592 * t1668);
+ x3 = -g1 * (e1x * t1592 * t1652 + e2x * t1592 * t1668 - e3x * t1592 * t1685) -
+ g2 * (e1y * t1592 * t1652 + e2y * t1592 * t1668 - e3y * t1592 * t1685) -
+ g3 * (e1z * t1592 * t1652 + e2z * t1592 * t1668 - e3z * t1592 * t1685);
+}
+
+#endif \ No newline at end of file
diff --git a/extern/mantaflow/helper/util/vector4d.cpp b/extern/mantaflow/helper/util/vector4d.cpp
new file mode 100644
index 00000000000..d342df607f5
--- /dev/null
+++ b/extern/mantaflow/helper/util/vector4d.cpp
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Basic vector class
+ *
+ ******************************************************************************/
+
+#include "vector4d.h"
+
+using namespace std;
+
+namespace Manta {
+
+template<> const Vector4D<int> Vector4D<int>::Zero(0, 0, 0, 0);
+template<> const Vector4D<float> Vector4D<float>::Zero(0.f, 0.f, 0.f, 0.f);
+template<> const Vector4D<double> Vector4D<double>::Zero(0., 0., 0., 0.);
+template<>
+const Vector4D<float> Vector4D<float>::Invalid(numeric_limits<float>::quiet_NaN(),
+ numeric_limits<float>::quiet_NaN(),
+ numeric_limits<float>::quiet_NaN(),
+ numeric_limits<float>::quiet_NaN());
+template<>
+const Vector4D<double> Vector4D<double>::Invalid(numeric_limits<double>::quiet_NaN(),
+ numeric_limits<double>::quiet_NaN(),
+ numeric_limits<double>::quiet_NaN(),
+ numeric_limits<double>::quiet_NaN());
+template<> bool Vector4D<float>::isValid() const
+{
+ return !c_isnan(x) && !c_isnan(y) && !c_isnan(z) && !c_isnan(t);
+}
+template<> bool Vector4D<double>::isValid() const
+{
+ return !c_isnan(x) && !c_isnan(y) && !c_isnan(z) && !c_isnan(t);
+}
+
+//! Specialization for readable ints
+template<> std::string Vector4D<int>::toString() const
+{
+ char buf[256];
+ snprintf(buf, 256, "[%d,%d,%d,%d]", (*this)[0], (*this)[1], (*this)[2], (*this)[3]);
+ return std::string(buf);
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/helper/util/vector4d.h b/extern/mantaflow/helper/util/vector4d.h
new file mode 100644
index 00000000000..c3d72ac8aff
--- /dev/null
+++ b/extern/mantaflow/helper/util/vector4d.h
@@ -0,0 +1,515 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 4D vector class
+ *
+ ******************************************************************************/
+
+#ifndef _VECTOR4D_H
+#define _VECTOR4D_H
+
+#include "vectorbase.h"
+
+namespace Manta {
+
+//! Basic inlined vector class
+template<class S> class Vector4D {
+ public:
+ //! Constructor
+ inline Vector4D() : x(0), y(0), z(0), t(0)
+ {
+ }
+
+ //! Copy-Constructor
+ inline Vector4D(const Vector4D<S> &v) : x(v.x), y(v.y), z(v.z), t(v.t)
+ {
+ }
+
+ //! Copy-Constructor
+ inline Vector4D(const float *v) : x((S)v[0]), y((S)v[1]), z((S)v[2]), t((S)v[3])
+ {
+ }
+
+ //! Copy-Constructor
+ inline Vector4D(const double *v) : x((S)v[0]), y((S)v[1]), z((S)v[2]), t((S)v[3])
+ {
+ }
+
+ //! Construct a vector from one S
+ inline Vector4D(S v) : x(v), y(v), z(v), t(v)
+ {
+ }
+
+ //! Construct a vector from three Ss
+ inline Vector4D(S vx, S vy, S vz, S vw) : x(vx), y(vy), z(vz), t(vw)
+ {
+ }
+
+ // Operators
+
+ //! Assignment operator
+ inline const Vector4D<S> &operator=(const Vector4D<S> &v)
+ {
+ x = v.x;
+ y = v.y;
+ z = v.z;
+ t = v.t;
+ return *this;
+ }
+ //! Assignment operator
+ inline const Vector4D<S> &operator=(S s)
+ {
+ x = y = z = t = s;
+ return *this;
+ }
+ //! Assign and add operator
+ inline const Vector4D<S> &operator+=(const Vector4D<S> &v)
+ {
+ x += v.x;
+ y += v.y;
+ z += v.z;
+ t += v.t;
+ return *this;
+ }
+ //! Assign and add operator
+ inline const Vector4D<S> &operator+=(S s)
+ {
+ x += s;
+ y += s;
+ z += s;
+ t += s;
+ return *this;
+ }
+ //! Assign and sub operator
+ inline const Vector4D<S> &operator-=(const Vector4D<S> &v)
+ {
+ x -= v.x;
+ y -= v.y;
+ z -= v.z;
+ t -= v.t;
+ return *this;
+ }
+ //! Assign and sub operator
+ inline const Vector4D<S> &operator-=(S s)
+ {
+ x -= s;
+ y -= s;
+ z -= s;
+ t -= s;
+ return *this;
+ }
+ //! Assign and mult operator
+ inline const Vector4D<S> &operator*=(const Vector4D<S> &v)
+ {
+ x *= v.x;
+ y *= v.y;
+ z *= v.z;
+ t *= v.t;
+ return *this;
+ }
+ //! Assign and mult operator
+ inline const Vector4D<S> &operator*=(S s)
+ {
+ x *= s;
+ y *= s;
+ z *= s;
+ t *= s;
+ return *this;
+ }
+ //! Assign and div operator
+ inline const Vector4D<S> &operator/=(const Vector4D<S> &v)
+ {
+ x /= v.x;
+ y /= v.y;
+ z /= v.z;
+ t /= v.t;
+ return *this;
+ }
+ //! Assign and div operator
+ inline const Vector4D<S> &operator/=(S s)
+ {
+ x /= s;
+ y /= s;
+ z /= s;
+ t /= s;
+ return *this;
+ }
+ //! Negation operator
+ inline Vector4D<S> operator-() const
+ {
+ return Vector4D<S>(-x, -y, -z, -t);
+ }
+
+ //! Get smallest component
+ // inline S min() const { return ( x<y ) ? ( ( x<z ) ? x:z ) : ( ( y<z ) ? y:z ); }
+ //! Get biggest component
+ // inline S max() const { return ( x>y ) ? ( ( x>z ) ? x:z ) : ( ( y>z ) ? y:z ); }
+
+ //! Test if all components are zero
+ inline bool empty()
+ {
+ return x == 0 && y == 0 && z == 0 && t == 0;
+ }
+
+ //! access operator
+ inline S &operator[](unsigned int i)
+ {
+ return value[i];
+ }
+ //! constant access operator
+ inline const S &operator[](unsigned int i) const
+ {
+ return value[i];
+ }
+
+ //! debug output vector to a string
+ std::string toString() const;
+
+ //! test if nans are present
+ bool isValid() const;
+
+ //! actual values
+ union {
+ S value[4];
+ struct {
+ S x;
+ S y;
+ S z;
+ S t;
+ };
+ struct {
+ S X;
+ S Y;
+ S Z;
+ S T;
+ };
+ };
+
+ // zero element
+ static const Vector4D<S> Zero, Invalid;
+
+ protected:
+};
+
+//************************************************************************
+// Additional operators
+//************************************************************************
+
+//! Addition operator
+template<class S> inline Vector4D<S> operator+(const Vector4D<S> &v1, const Vector4D<S> &v2)
+{
+ return Vector4D<S>(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.t + v2.t);
+}
+//! Addition operator
+template<class S, class S2> inline Vector4D<S> operator+(const Vector4D<S> &v, S2 s)
+{
+ return Vector4D<S>(v.x + s, v.y + s, v.z + s, v.t + s);
+}
+//! Addition operator
+template<class S, class S2> inline Vector4D<S> operator+(S2 s, const Vector4D<S> &v)
+{
+ return Vector4D<S>(v.x + s, v.y + s, v.z + s, v.t + s);
+}
+
+//! Subtraction operator
+template<class S> inline Vector4D<S> operator-(const Vector4D<S> &v1, const Vector4D<S> &v2)
+{
+ return Vector4D<S>(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, v1.t - v2.t);
+}
+//! Subtraction operator
+template<class S, class S2> inline Vector4D<S> operator-(const Vector4D<S> &v, S2 s)
+{
+ return Vector4D<S>(v.x - s, v.y - s, v.z - s, v.t - s);
+}
+//! Subtraction operator
+template<class S, class S2> inline Vector4D<S> operator-(S2 s, const Vector4D<S> &v)
+{
+ return Vector4D<S>(s - v.x, s - v.y, s - v.z, s - v.t);
+}
+
+//! Multiplication operator
+template<class S> inline Vector4D<S> operator*(const Vector4D<S> &v1, const Vector4D<S> &v2)
+{
+ return Vector4D<S>(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z, v1.t * v2.t);
+}
+//! Multiplication operator
+template<class S, class S2> inline Vector4D<S> operator*(const Vector4D<S> &v, S2 s)
+{
+ return Vector4D<S>(v.x * s, v.y * s, v.z * s, v.t * s);
+}
+//! Multiplication operator
+template<class S, class S2> inline Vector4D<S> operator*(S2 s, const Vector4D<S> &v)
+{
+ return Vector4D<S>(s * v.x, s * v.y, s * v.z, s * v.t);
+}
+
+//! Division operator
+template<class S> inline Vector4D<S> operator/(const Vector4D<S> &v1, const Vector4D<S> &v2)
+{
+ return Vector4D<S>(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z, v1.t / v2.t);
+}
+//! Division operator
+template<class S, class S2> inline Vector4D<S> operator/(const Vector4D<S> &v, S2 s)
+{
+ return Vector4D<S>(v.x / s, v.y / s, v.z / s, v.t / s);
+}
+//! Division operator
+template<class S, class S2> inline Vector4D<S> operator/(S2 s, const Vector4D<S> &v)
+{
+ return Vector4D<S>(s / v.x, s / v.y, s / v.z, s / v.t);
+}
+
+//! Comparison operator
+template<class S> inline bool operator==(const Vector4D<S> &s1, const Vector4D<S> &s2)
+{
+ return s1.x == s2.x && s1.y == s2.y && s1.z == s2.z && s1.t == s2.t;
+}
+
+//! Comparison operator
+template<class S> inline bool operator!=(const Vector4D<S> &s1, const Vector4D<S> &s2)
+{
+ return s1.x != s2.x || s1.y != s2.y || s1.z != s2.z || s1.t != s2.t;
+}
+
+//************************************************************************
+// External functions
+//************************************************************************
+
+//! Dot product
+template<class S> inline S dot(const Vector4D<S> &t, const Vector4D<S> &v)
+{
+ return t.x * v.x + t.y * v.y + t.z * v.z + t.t * v.t;
+}
+
+//! Cross product
+/*template<class S>
+inline Vector4D<S> cross ( const Vector4D<S> &t, const Vector4D<S> &v ) {
+ NYI Vector4D<S> cp (
+ ( ( t.y*v.z ) - ( t.z*v.y ) ),
+ ( ( t.z*v.x ) - ( t.x*v.z ) ),
+ ( ( t.x*v.y ) - ( t.y*v.x ) ) );
+ return cp;
+}*/
+
+//! Compute the magnitude (length) of the vector
+template<class S> inline S norm(const Vector4D<S> &v)
+{
+ S l = v.x * v.x + v.y * v.y + v.z * v.z + v.t * v.t;
+ return (fabs(l - 1.) < VECTOR_EPSILON * VECTOR_EPSILON) ? 1. : sqrt(l);
+}
+
+//! Compute squared magnitude
+template<class S> inline S normSquare(const Vector4D<S> &v)
+{
+ return v.x * v.x + v.y * v.y + v.z * v.z + v.t * v.t;
+}
+
+//! Returns a normalized vector
+template<class S> inline Vector4D<S> getNormalized(const Vector4D<S> &v)
+{
+ S l = v.x * v.x + v.y * v.y + v.z * v.z + v.t * v.t;
+ if (fabs(l - 1.) < VECTOR_EPSILON * VECTOR_EPSILON)
+ return v; /* normalized "enough"... */
+ else if (l > VECTOR_EPSILON * VECTOR_EPSILON) {
+ S fac = 1. / sqrt(l);
+ return Vector4D<S>(v.x * fac, v.y * fac, v.z * fac, v.t * fac);
+ }
+ else
+ return Vector4D<S>((S)0);
+}
+
+//! Compute the norm of the vector and normalize it.
+/*! \return The value of the norm */
+template<class S> inline S normalize(Vector4D<S> &v)
+{
+ S norm;
+ S l = v.x * v.x + v.y * v.y + v.z * v.z + v.t * v.t;
+ if (fabs(l - 1.) < VECTOR_EPSILON * VECTOR_EPSILON) {
+ norm = 1.;
+ }
+ else if (l > VECTOR_EPSILON * VECTOR_EPSILON) {
+ norm = sqrt(l);
+ v *= 1. / norm;
+ }
+ else {
+ v = Vector4D<S>::Zero;
+ norm = 0.;
+ }
+ return (S)norm;
+}
+
+//! Outputs the object in human readable form as string
+template<class S> std::string Vector4D<S>::toString() const
+{
+ char buf[256];
+ snprintf(buf,
+ 256,
+ "[%+4.6f,%+4.6f,%+4.6f,%+4.6f]",
+ (double)(*this)[0],
+ (double)(*this)[1],
+ (double)(*this)[2],
+ (double)(*this)[3]);
+ // for debugging, optionally increase precision:
+ // snprintf ( buf,256,"[%+4.16f,%+4.16f,%+4.16f,%+4.16f]", ( double ) ( *this ) [0], ( double ) (
+ // *this ) [1], ( double ) ( *this ) [2], ( double ) ( *this ) [3] );
+ return std::string(buf);
+}
+
+template<> std::string Vector4D<int>::toString() const;
+
+//! Outputs the object in human readable form to stream
+template<class S> std::ostream &operator<<(std::ostream &os, const Vector4D<S> &i)
+{
+ os << i.toString();
+ return os;
+}
+
+//! Reads the contents of the object from a stream
+template<class S> std::istream &operator>>(std::istream &is, Vector4D<S> &i)
+{
+ char c;
+ char dummy[4];
+ is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> dummy >> i[3] >> c;
+ return is;
+}
+
+/**************************************************************************/
+// Define default vector alias
+/**************************************************************************/
+
+//! 3D vector class of type Real (typically float)
+typedef Vector4D<Real> Vec4;
+
+//! 3D vector class of type int
+typedef Vector4D<int> Vec4i;
+
+//! convert to Real Vector
+template<class T> inline Vec4 toVec4(T v)
+{
+ return Vec4(v[0], v[1], v[2], v[3]);
+}
+template<class T> inline Vec4i toVec4i(T v)
+{
+ return Vec4i(v[0], v[1], v[2], v[3]);
+}
+
+/**************************************************************************/
+// Specializations for common math functions
+/**************************************************************************/
+
+template<> inline Vec4 clamp<Vec4>(const Vec4 &a, const Vec4 &b, const Vec4 &c)
+{
+ return Vec4(
+ clamp(a.x, b.x, c.x), clamp(a.y, b.y, c.y), clamp(a.z, b.z, c.z), clamp(a.t, b.t, c.t));
+}
+template<> inline Vec4 safeDivide<Vec4>(const Vec4 &a, const Vec4 &b)
+{
+ return Vec4(
+ safeDivide(a.x, b.x), safeDivide(a.y, b.y), safeDivide(a.z, b.z), safeDivide(a.t, b.t));
+}
+template<> inline Vec4 nmod<Vec4>(const Vec4 &a, const Vec4 &b)
+{
+ return Vec4(nmod(a.x, b.x), nmod(a.y, b.y), nmod(a.z, b.z), nmod(a.t, b.t));
+}
+
+/**************************************************************************/
+// 4d interpolation (note only 4d here, 2d/3d interpolations are in interpol.h)
+/**************************************************************************/
+
+#define BUILD_INDEX_4D \
+ Real px = pos.x - 0.5f, py = pos.y - 0.5f, pz = pos.z - 0.5f, pt = pos.t - 0.5f; \
+ int xi = (int)px; \
+ int yi = (int)py; \
+ int zi = (int)pz; \
+ int ti = (int)pt; \
+ Real s1 = px - (Real)xi, s0 = 1. - s1; \
+ Real t1 = py - (Real)yi, t0 = 1. - t1; \
+ Real f1 = pz - (Real)zi, f0 = 1. - f1; \
+ Real g1 = pt - (Real)ti, g0 = 1. - g1; \
+ /* clamp to border */ \
+ if (px < 0.) { \
+ xi = 0; \
+ s0 = 1.0; \
+ s1 = 0.0; \
+ } \
+ if (py < 0.) { \
+ yi = 0; \
+ t0 = 1.0; \
+ t1 = 0.0; \
+ } \
+ if (pz < 0.) { \
+ zi = 0; \
+ f0 = 1.0; \
+ f1 = 0.0; \
+ } \
+ if (pt < 0.) { \
+ ti = 0; \
+ g0 = 1.0; \
+ g1 = 0.0; \
+ } \
+ if (xi >= size.x - 1) { \
+ xi = size.x - 2; \
+ s0 = 0.0; \
+ s1 = 1.0; \
+ } \
+ if (yi >= size.y - 1) { \
+ yi = size.y - 2; \
+ t0 = 0.0; \
+ t1 = 1.0; \
+ } \
+ if (zi >= size.z - 1) { \
+ zi = size.z - 2; \
+ f0 = 0.0; \
+ f1 = 1.0; \
+ } \
+ if (ti >= size.t - 1) { \
+ ti = size.t - 2; \
+ g0 = 0.0; \
+ g1 = 1.0; \
+ } \
+ const int sX = 1; \
+ const int sY = size.x;
+
+static inline void checkIndexInterpol4d(const Vec4i &size, int idx)
+{
+ if (idx < 0 || idx > size.x * size.y * size.z * size.t) {
+ std::ostringstream s;
+ s << "Grid interpol4d dim " << size << " : index " << idx << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+template<class T>
+inline T interpol4d(
+ const T *data, const Vec4i &size, const IndexInt sZ, const IndexInt sT, const Vec4 &pos)
+{
+ BUILD_INDEX_4D
+ IndexInt idx = (IndexInt)xi + sY * (IndexInt)yi + sZ * (IndexInt)zi + sT * (IndexInt)ti;
+ DEBUG_ONLY(checkIndexInterpol4d(size, idx));
+ DEBUG_ONLY(checkIndexInterpol4d(size, idx + sX + sY + sZ + sT));
+
+ return (((data[idx] * t0 + data[idx + sY] * t1) * s0 +
+ (data[idx + sX] * t0 + data[idx + sX + sY] * t1) * s1) *
+ f0 +
+ ((data[idx + sZ] * t0 + data[idx + sY + sZ] * t1) * s0 +
+ (data[idx + sX + sZ] * t0 + data[idx + sX + sY + sZ] * t1) * s1) *
+ f1) *
+ g0 +
+ (((data[idx + sT] * t0 + data[idx + sT + sY] * t1) * s0 +
+ (data[idx + sT + sX] * t0 + data[idx + sT + sX + sY] * t1) * s1) *
+ f0 +
+ ((data[idx + sT + sZ] * t0 + data[idx + sT + sY + sZ] * t1) * s0 +
+ (data[idx + sT + sX + sZ] * t0 + data[idx + sT + sX + sY + sZ] * t1) * s1) *
+ f1) *
+ g1;
+}
+
+}; // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/helper/util/vectorbase.cpp b/extern/mantaflow/helper/util/vectorbase.cpp
new file mode 100644
index 00000000000..413ae086d1c
--- /dev/null
+++ b/extern/mantaflow/helper/util/vectorbase.cpp
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Basic vector class
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+
+using namespace std;
+
+namespace Manta {
+
+template<> const Vector3D<int> Vector3D<int>::Zero(0, 0, 0);
+template<> const Vector3D<float> Vector3D<float>::Zero(0.f, 0.f, 0.f);
+template<> const Vector3D<double> Vector3D<double>::Zero(0., 0., 0.);
+template<>
+const Vector3D<float> Vector3D<float>::Invalid(numeric_limits<float>::quiet_NaN(),
+ numeric_limits<float>::quiet_NaN(),
+ numeric_limits<float>::quiet_NaN());
+template<>
+const Vector3D<double> Vector3D<double>::Invalid(numeric_limits<double>::quiet_NaN(),
+ numeric_limits<double>::quiet_NaN(),
+ numeric_limits<double>::quiet_NaN());
+
+template<> bool Vector3D<float>::isValid() const
+{
+ return !c_isnan(x) && !c_isnan(y) && !c_isnan(z);
+}
+template<> bool Vector3D<double>::isValid() const
+{
+ return !c_isnan(x) && !c_isnan(y) && !c_isnan(z);
+}
+
+//! Specialization for readable ints
+template<> std::string Vector3D<int>::toString() const
+{
+ char buf[256];
+ snprintf(buf, 256, "[%d,%d,%d]", (*this)[0], (*this)[1], (*this)[2]);
+ return std::string(buf);
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/helper/util/vectorbase.h b/extern/mantaflow/helper/util/vectorbase.h
new file mode 100644
index 00000000000..a3135431eb3
--- /dev/null
+++ b/extern/mantaflow/helper/util/vectorbase.h
@@ -0,0 +1,679 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Basic vector class
+ *
+ ******************************************************************************/
+
+#ifndef _VECTORBASE_H
+#define _VECTORBASE_H
+
+// get rid of windos min/max defines
+#if defined(WIN32) || defined(_WIN32)
+# define NOMINMAX
+#endif
+
+#include <stdio.h>
+#include <string>
+#include <limits>
+#include <iostream>
+#include "general.h"
+
+// if min/max are still around...
+#if defined(WIN32) || defined(_WIN32)
+# undef min
+# undef max
+#endif
+
+// redefine usage of some windows functions
+#if defined(WIN32) || defined(_WIN32)
+# ifndef snprintf
+# define snprintf _snprintf
+# endif
+#endif
+
+// use which fp-precision? 1=float, 2=double
+#ifndef FLOATINGPOINT_PRECISION
+# define FLOATINGPOINT_PRECISION 1
+#endif
+
+// VECTOR_EPSILON is the minimal vector length
+// In order to be able to discriminate floating point values near zero, and
+// to be sure not to fail a comparison because of roundoff errors, use this
+// value as a threshold.
+#if FLOATINGPOINT_PRECISION == 1
+typedef float Real;
+# define VECTOR_EPSILON (1e-6f)
+#else
+typedef double Real;
+# define VECTOR_EPSILON (1e-10)
+#endif
+
+#ifndef M_PI
+# define M_PI 3.1415926536
+#endif
+#ifndef M_E
+# define M_E 2.7182818284
+#endif
+
+namespace Manta {
+
+//! Basic inlined vector class
+template<class S> class Vector3D {
+ public:
+ //! Constructor
+ inline Vector3D() : x(0), y(0), z(0)
+ {
+ }
+
+ //! Copy-Constructor
+ inline Vector3D(const Vector3D<S> &v) : x(v.x), y(v.y), z(v.z)
+ {
+ }
+
+ //! Copy-Constructor
+ inline Vector3D(const int *v) : x((S)v[0]), y((S)v[1]), z((S)v[2])
+ {
+ }
+
+ //! Copy-Constructor
+ inline Vector3D(const float *v) : x((S)v[0]), y((S)v[1]), z((S)v[2])
+ {
+ }
+
+ //! Copy-Constructor
+ inline Vector3D(const double *v) : x((S)v[0]), y((S)v[1]), z((S)v[2])
+ {
+ }
+
+ //! Construct a vector from one S
+ inline Vector3D(S v) : x(v), y(v), z(v)
+ {
+ }
+
+ //! Construct a vector from three Ss
+ inline Vector3D(S vx, S vy, S vz) : x(vx), y(vy), z(vz)
+ {
+ }
+
+ // Operators
+
+ //! Assignment operator
+ inline const Vector3D<S> &operator=(const Vector3D<S> &v)
+ {
+ x = v.x;
+ y = v.y;
+ z = v.z;
+ return *this;
+ }
+ //! Assignment operator
+ inline const Vector3D<S> &operator=(S s)
+ {
+ x = y = z = s;
+ return *this;
+ }
+ //! Assign and add operator
+ inline const Vector3D<S> &operator+=(const Vector3D<S> &v)
+ {
+ x += v.x;
+ y += v.y;
+ z += v.z;
+ return *this;
+ }
+ //! Assign and add operator
+ inline const Vector3D<S> &operator+=(S s)
+ {
+ x += s;
+ y += s;
+ z += s;
+ return *this;
+ }
+ //! Assign and sub operator
+ inline const Vector3D<S> &operator-=(const Vector3D<S> &v)
+ {
+ x -= v.x;
+ y -= v.y;
+ z -= v.z;
+ return *this;
+ }
+ //! Assign and sub operator
+ inline const Vector3D<S> &operator-=(S s)
+ {
+ x -= s;
+ y -= s;
+ z -= s;
+ return *this;
+ }
+ //! Assign and mult operator
+ inline const Vector3D<S> &operator*=(const Vector3D<S> &v)
+ {
+ x *= v.x;
+ y *= v.y;
+ z *= v.z;
+ return *this;
+ }
+ //! Assign and mult operator
+ inline const Vector3D<S> &operator*=(S s)
+ {
+ x *= s;
+ y *= s;
+ z *= s;
+ return *this;
+ }
+ //! Assign and div operator
+ inline const Vector3D<S> &operator/=(const Vector3D<S> &v)
+ {
+ x /= v.x;
+ y /= v.y;
+ z /= v.z;
+ return *this;
+ }
+ //! Assign and div operator
+ inline const Vector3D<S> &operator/=(S s)
+ {
+ x /= s;
+ y /= s;
+ z /= s;
+ return *this;
+ }
+ //! Negation operator
+ inline Vector3D<S> operator-() const
+ {
+ return Vector3D<S>(-x, -y, -z);
+ }
+
+ //! Get smallest component
+ inline S min() const
+ {
+ return (x < y) ? ((x < z) ? x : z) : ((y < z) ? y : z);
+ }
+ //! Get biggest component
+ inline S max() const
+ {
+ return (x > y) ? ((x > z) ? x : z) : ((y > z) ? y : z);
+ }
+
+ //! Test if all components are zero
+ inline bool empty()
+ {
+ return x == 0 && y == 0 && z == 0;
+ }
+
+ //! access operator
+ inline S &operator[](unsigned int i)
+ {
+ return value[i];
+ }
+ //! constant access operator
+ inline const S &operator[](unsigned int i) const
+ {
+ return value[i];
+ }
+
+ //! debug output vector to a string
+ std::string toString() const;
+
+ //! test if nans are present
+ bool isValid() const;
+
+ //! actual values
+ union {
+ S value[3];
+ struct {
+ S x;
+ S y;
+ S z;
+ };
+ struct {
+ S X;
+ S Y;
+ S Z;
+ };
+ };
+
+ //! zero element
+ static const Vector3D<S> Zero, Invalid;
+
+ //! For compatibility with 4d vectors (discards 4th comp)
+ inline Vector3D(S vx, S vy, S vz, S vDummy) : x(vx), y(vy), z(vz)
+ {
+ }
+
+ protected:
+};
+
+//! helper to check whether float/double value is non-zero
+inline bool notZero(Real f)
+{
+ if (std::abs(f) > VECTOR_EPSILON)
+ return true;
+ return false;
+}
+
+//************************************************************************
+// Additional operators
+//************************************************************************
+
+//! Addition operator
+template<class S> inline Vector3D<S> operator+(const Vector3D<S> &v1, const Vector3D<S> &v2)
+{
+ return Vector3D<S>(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
+}
+//! Addition operator
+template<class S, class S2> inline Vector3D<S> operator+(const Vector3D<S> &v, S2 s)
+{
+ return Vector3D<S>(v.x + s, v.y + s, v.z + s);
+}
+//! Addition operator
+template<class S, class S2> inline Vector3D<S> operator+(S2 s, const Vector3D<S> &v)
+{
+ return Vector3D<S>(v.x + s, v.y + s, v.z + s);
+}
+
+//! Subtraction operator
+template<class S> inline Vector3D<S> operator-(const Vector3D<S> &v1, const Vector3D<S> &v2)
+{
+ return Vector3D<S>(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
+}
+//! Subtraction operator
+template<class S, class S2> inline Vector3D<S> operator-(const Vector3D<S> &v, S2 s)
+{
+ return Vector3D<S>(v.x - s, v.y - s, v.z - s);
+}
+//! Subtraction operator
+template<class S, class S2> inline Vector3D<S> operator-(S2 s, const Vector3D<S> &v)
+{
+ return Vector3D<S>(s - v.x, s - v.y, s - v.z);
+}
+
+//! Multiplication operator
+template<class S> inline Vector3D<S> operator*(const Vector3D<S> &v1, const Vector3D<S> &v2)
+{
+ return Vector3D<S>(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
+}
+//! Multiplication operator
+template<class S, class S2> inline Vector3D<S> operator*(const Vector3D<S> &v, S2 s)
+{
+ return Vector3D<S>(v.x * s, v.y * s, v.z * s);
+}
+//! Multiplication operator
+template<class S, class S2> inline Vector3D<S> operator*(S2 s, const Vector3D<S> &v)
+{
+ return Vector3D<S>(s * v.x, s * v.y, s * v.z);
+}
+
+//! Division operator
+template<class S> inline Vector3D<S> operator/(const Vector3D<S> &v1, const Vector3D<S> &v2)
+{
+ return Vector3D<S>(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z);
+}
+//! Division operator
+template<class S, class S2> inline Vector3D<S> operator/(const Vector3D<S> &v, S2 s)
+{
+ return Vector3D<S>(v.x / s, v.y / s, v.z / s);
+}
+//! Division operator
+template<class S, class S2> inline Vector3D<S> operator/(S2 s, const Vector3D<S> &v)
+{
+ return Vector3D<S>(s / v.x, s / v.y, s / v.z);
+}
+
+//! Comparison operator
+template<class S> inline bool operator==(const Vector3D<S> &s1, const Vector3D<S> &s2)
+{
+ return s1.x == s2.x && s1.y == s2.y && s1.z == s2.z;
+}
+
+//! Comparison operator
+template<class S> inline bool operator!=(const Vector3D<S> &s1, const Vector3D<S> &s2)
+{
+ return s1.x != s2.x || s1.y != s2.y || s1.z != s2.z;
+}
+
+//************************************************************************
+// External functions
+//************************************************************************
+
+//! Min operator
+template<class S> inline Vector3D<S> vmin(const Vector3D<S> &s1, const Vector3D<S> &s2)
+{
+ return Vector3D<S>(std::min(s1.x, s2.x), std::min(s1.y, s2.y), std::min(s1.z, s2.z));
+}
+
+//! Min operator
+template<class S, class S2> inline Vector3D<S> vmin(const Vector3D<S> &s1, S2 s2)
+{
+ return Vector3D<S>(std::min(s1.x, s2), std::min(s1.y, s2), std::min(s1.z, s2));
+}
+
+//! Min operator
+template<class S1, class S> inline Vector3D<S> vmin(S1 s1, const Vector3D<S> &s2)
+{
+ return Vector3D<S>(std::min(s1, s2.x), std::min(s1, s2.y), std::min(s1, s2.z));
+}
+
+//! Max operator
+template<class S> inline Vector3D<S> vmax(const Vector3D<S> &s1, const Vector3D<S> &s2)
+{
+ return Vector3D<S>(std::max(s1.x, s2.x), std::max(s1.y, s2.y), std::max(s1.z, s2.z));
+}
+
+//! Max operator
+template<class S, class S2> inline Vector3D<S> vmax(const Vector3D<S> &s1, S2 s2)
+{
+ return Vector3D<S>(std::max(s1.x, s2), std::max(s1.y, s2), std::max(s1.z, s2));
+}
+
+//! Max operator
+template<class S1, class S> inline Vector3D<S> vmax(S1 s1, const Vector3D<S> &s2)
+{
+ return Vector3D<S>(std::max(s1, s2.x), std::max(s1, s2.y), std::max(s1, s2.z));
+}
+
+//! Dot product
+template<class S> inline S dot(const Vector3D<S> &t, const Vector3D<S> &v)
+{
+ return t.x * v.x + t.y * v.y + t.z * v.z;
+}
+
+//! Cross product
+template<class S> inline Vector3D<S> cross(const Vector3D<S> &t, const Vector3D<S> &v)
+{
+ Vector3D<S> cp(
+ ((t.y * v.z) - (t.z * v.y)), ((t.z * v.x) - (t.x * v.z)), ((t.x * v.y) - (t.y * v.x)));
+ return cp;
+}
+
+//! Project a vector into a plane, defined by its normal
+/*! Projects a vector into a plane normal to the given vector, which must
+ have unit length. Self is modified.
+ \param v The vector to project
+ \param n The plane normal
+ \return The projected vector */
+template<class S>
+inline const Vector3D<S> &projectNormalTo(const Vector3D<S> &v, const Vector3D<S> &n)
+{
+ S sprod = dot(v, n);
+ return v - n * dot(v, n);
+}
+
+//! Compute the magnitude (length) of the vector
+//! (clamps to 0 and 1 with VECTOR_EPSILON)
+template<class S> inline S norm(const Vector3D<S> &v)
+{
+ S l = v.x * v.x + v.y * v.y + v.z * v.z;
+ if (l <= VECTOR_EPSILON * VECTOR_EPSILON)
+ return (0.);
+ return (fabs(l - 1.) < VECTOR_EPSILON * VECTOR_EPSILON) ? 1. : sqrt(l);
+}
+
+//! Compute squared magnitude
+template<class S> inline S normSquare(const Vector3D<S> &v)
+{
+ return v.x * v.x + v.y * v.y + v.z * v.z;
+}
+
+//! compatibility, allow use of int, Real and Vec inputs with norm/normSquare
+inline Real norm(const Real v)
+{
+ return fabs(v);
+}
+inline Real normSquare(const Real v)
+{
+ return square(v);
+}
+inline Real norm(const int v)
+{
+ return abs(v);
+}
+inline Real normSquare(const int v)
+{
+ return square(v);
+}
+
+//! Returns a normalized vector
+template<class S> inline Vector3D<S> getNormalized(const Vector3D<S> &v)
+{
+ S l = v.x * v.x + v.y * v.y + v.z * v.z;
+ if (fabs(l - 1.) < VECTOR_EPSILON * VECTOR_EPSILON)
+ return v; /* normalized "enough"... */
+ else if (l > VECTOR_EPSILON * VECTOR_EPSILON) {
+ S fac = 1. / sqrt(l);
+ return Vector3D<S>(v.x * fac, v.y * fac, v.z * fac);
+ }
+ else
+ return Vector3D<S>((S)0);
+}
+
+//! Compute the norm of the vector and normalize it.
+/*! \return The value of the norm */
+template<class S> inline S normalize(Vector3D<S> &v)
+{
+ S norm;
+ S l = v.x * v.x + v.y * v.y + v.z * v.z;
+ if (fabs(l - 1.) < VECTOR_EPSILON * VECTOR_EPSILON) {
+ norm = 1.;
+ }
+ else if (l > VECTOR_EPSILON * VECTOR_EPSILON) {
+ norm = sqrt(l);
+ v *= 1. / norm;
+ }
+ else {
+ v = Vector3D<S>::Zero;
+ norm = 0.;
+ }
+ return (S)norm;
+}
+
+//! Obtain an orthogonal vector
+/*! Compute a vector that is orthonormal to the given vector.
+ * Nothing else can be assumed for the direction of the new vector.
+ * \return The orthonormal vector */
+template<class S> Vector3D<S> getOrthogonalVector(const Vector3D<S> &v)
+{
+ // Determine the component with max. absolute value
+ int maxIndex = (fabs(v.x) > fabs(v.y)) ? 0 : 1;
+ maxIndex = (fabs(v[maxIndex]) > fabs(v.z)) ? maxIndex : 2;
+
+ // Choose another axis than the one with max. component and project
+ // orthogonal to self
+ Vector3D<S> o(0.0);
+ o[(maxIndex + 1) % 3] = 1;
+
+ Vector3D<S> c = cross(v, o);
+ normalize(c);
+ return c;
+}
+
+//! Convert vector to polar coordinates
+/*! Stable vector to angle conversion
+ *\param v vector to convert
+ \param phi unique angle [0,2PI]
+ \param theta unique angle [0,PI]
+ */
+template<class S> inline void vecToAngle(const Vector3D<S> &v, S &phi, S &theta)
+{
+ if (fabs(v.y) < VECTOR_EPSILON)
+ theta = M_PI / 2;
+ else if (fabs(v.x) < VECTOR_EPSILON && fabs(v.z) < VECTOR_EPSILON)
+ theta = (v.y >= 0) ? 0 : M_PI;
+ else
+ theta = atan(sqrt(v.x * v.x + v.z * v.z) / v.y);
+ if (theta < 0)
+ theta += M_PI;
+
+ if (fabs(v.x) < VECTOR_EPSILON)
+ phi = M_PI / 2;
+ else
+ phi = atan(v.z / v.x);
+ if (phi < 0)
+ phi += M_PI;
+ if (fabs(v.z) < VECTOR_EPSILON)
+ phi = (v.x >= 0) ? 0 : M_PI;
+ else if (v.z < 0)
+ phi += M_PI;
+}
+
+//! Compute vector reflected at a surface
+/*! Compute a vector, that is self (as an incoming vector)
+ * reflected at a surface with a distinct normal vector.
+ * Note that the normal is reversed, if the scalar product with it is positive.
+ \param t The incoming vector
+ \param n The surface normal
+ \return The new reflected vector
+ */
+template<class S> inline Vector3D<S> reflectVector(const Vector3D<S> &t, const Vector3D<S> &n)
+{
+ Vector3D<S> nn = (dot(t, n) > 0.0) ? (n * -1.0) : n;
+ return (t - nn * (2.0 * dot(nn, t)));
+}
+
+//! Compute vector refracted at a surface
+/*! \param t The incoming vector
+ * \param n The surface normal
+ * \param nt The "inside" refraction index
+ * \param nair The "outside" refraction index
+ * \param refRefl Set to 1 on total reflection
+ * \return The refracted vector
+ */
+template<class S>
+inline Vector3D<S> refractVector(
+ const Vector3D<S> &t, const Vector3D<S> &normal, S nt, S nair, int &refRefl)
+{
+ // from Glassner's book, section 5.2 (Heckberts method)
+ S eta = nair / nt;
+ S n = -dot(t, normal);
+ S tt = 1.0 + eta * eta * (n * n - 1.0);
+ if (tt < 0.0) {
+ // we have total reflection!
+ refRefl = 1;
+ }
+ else {
+ // normal reflection
+ tt = eta * n - sqrt(tt);
+ return (t * eta + normal * tt);
+ }
+ return t;
+}
+
+//! Outputs the object in human readable form as string
+template<class S> std::string Vector3D<S>::toString() const
+{
+ char buf[256];
+ snprintf(buf,
+ 256,
+ "[%+4.6f,%+4.6f,%+4.6f]",
+ (double)(*this)[0],
+ (double)(*this)[1],
+ (double)(*this)[2]);
+ // for debugging, optionally increase precision:
+ // snprintf ( buf,256,"[%+4.16f,%+4.16f,%+4.16f]", ( double ) ( *this ) [0], ( double ) ( *this )
+ // [1], ( double ) ( *this ) [2] );
+ return std::string(buf);
+}
+
+template<> std::string Vector3D<int>::toString() const;
+
+//! Outputs the object in human readable form to stream
+/*! Output format [x,y,z] */
+template<class S> std::ostream &operator<<(std::ostream &os, const Vector3D<S> &i)
+{
+ os << i.toString();
+ return os;
+}
+
+//! Reads the contents of the object from a stream
+/*! Input format [x,y,z] */
+template<class S> std::istream &operator>>(std::istream &is, Vector3D<S> &i)
+{
+ char c;
+ char dummy[3];
+ is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c;
+ return is;
+}
+
+/**************************************************************************/
+// Define default vector alias
+/**************************************************************************/
+
+//! 3D vector class of type Real (typically float)
+typedef Vector3D<Real> Vec3;
+
+//! 3D vector class of type int
+typedef Vector3D<int> Vec3i;
+
+//! convert to Real Vector
+template<class T> inline Vec3 toVec3(T v)
+{
+ return Vec3(v[0], v[1], v[2]);
+}
+
+//! convert to int Vector
+template<class T> inline Vec3i toVec3i(T v)
+{
+ return Vec3i((int)v[0], (int)v[1], (int)v[2]);
+}
+
+//! convert to int Vector
+template<class T> inline Vec3i toVec3i(T v0, T v1, T v2)
+{
+ return Vec3i((int)v0, (int)v1, (int)v2);
+}
+
+//! round, and convert to int Vector
+template<class T> inline Vec3i toVec3iRound(T v)
+{
+ return Vec3i((int)round(v[0]), (int)round(v[1]), (int)round(v[2]));
+}
+
+//! convert to int Vector if values are close enough to an int
+template<class T> inline Vec3i toVec3iChecked(T v)
+{
+ Vec3i ret;
+ for (size_t i = 0; i < 3; i++) {
+ Real a = v[i];
+ if (fabs(a - floor(a + 0.5)) > 1e-5)
+ errMsg("argument is not an int, cannot convert");
+ ret[i] = (int)(a + 0.5);
+ }
+ return ret;
+}
+
+//! convert to double Vector
+template<class T> inline Vector3D<double> toVec3d(T v)
+{
+ return Vector3D<double>(v[0], v[1], v[2]);
+}
+
+//! convert to float Vector
+template<class T> inline Vector3D<float> toVec3f(T v)
+{
+ return Vector3D<float>(v[0], v[1], v[2]);
+}
+
+/**************************************************************************/
+// Specializations for common math functions
+/**************************************************************************/
+
+template<> inline Vec3 clamp<Vec3>(const Vec3 &a, const Vec3 &b, const Vec3 &c)
+{
+ return Vec3(clamp(a.x, b.x, c.x), clamp(a.y, b.y, c.y), clamp(a.z, b.z, c.z));
+}
+template<> inline Vec3 safeDivide<Vec3>(const Vec3 &a, const Vec3 &b)
+{
+ return Vec3(safeDivide(a.x, b.x), safeDivide(a.y, b.y), safeDivide(a.z, b.z));
+}
+template<> inline Vec3 nmod<Vec3>(const Vec3 &a, const Vec3 &b)
+{
+ return Vec3(nmod(a.x, b.x), nmod(a.y, b.y), nmod(a.z, b.z));
+}
+
+}; // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/commonkernels.h b/extern/mantaflow/preprocessed/commonkernels.h
new file mode 100644
index 00000000000..7fa6f185146
--- /dev/null
+++ b/extern/mantaflow/preprocessed/commonkernels.h
@@ -0,0 +1,1300 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Common grid kernels
+ *
+ ******************************************************************************/
+
+#ifndef _COMMONKERNELS_H
+#define _COMMONKERNELS_H
+
+#include "general.h"
+#include "kernel.h"
+#include "grid.h"
+
+namespace Manta {
+
+//! Kernel: Invert real values, if positive and fluid
+
+struct InvertCheckFluid : public KernelBase {
+ InvertCheckFluid(const FlagGrid &flags, Grid<Real> &grid)
+ : KernelBase(&flags, 0), flags(flags), grid(grid)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const FlagGrid &flags, Grid<Real> &grid) const
+ {
+ if (flags.isFluid(idx) && grid[idx] > 0)
+ grid[idx] = 1.0 / grid[idx];
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return grid;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel InvertCheckFluid ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, flags, grid);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &grid;
+};
+
+//! Kernel: Squared sum over grid
+
+struct GridSumSqr : public KernelBase {
+ GridSumSqr(const Grid<Real> &grid) : KernelBase(&grid, 0), grid(grid), sum(0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Real> &grid, double &sum)
+ {
+ sum += square((double)grid[idx]);
+ }
+ inline operator double()
+ {
+ return sum;
+ }
+ inline double &getRet()
+ {
+ return sum;
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<Real> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel GridSumSqr ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, grid, sum);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ GridSumSqr(GridSumSqr &o, tbb::split) : KernelBase(o), grid(o.grid), sum(0)
+ {
+ }
+ void join(const GridSumSqr &o)
+ {
+ sum += o.sum;
+ }
+ const Grid<Real> &grid;
+ double sum;
+};
+
+//! Kernel: rotation operator \nabla x v for centered vector fields
+
+struct CurlOp : public KernelBase {
+ CurlOp(const Grid<Vec3> &grid, Grid<Vec3> &dst) : KernelBase(&grid, 1), grid(grid), dst(dst)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const Grid<Vec3> &grid, Grid<Vec3> &dst) const
+ {
+ Vec3 v = Vec3(0.,
+ 0.,
+ 0.5 * ((grid(i + 1, j, k).y - grid(i - 1, j, k).y) -
+ (grid(i, j + 1, k).x - grid(i, j - 1, k).x)));
+ if (dst.is3D()) {
+ v[0] = 0.5 * ((grid(i, j + 1, k).z - grid(i, j - 1, k).z) -
+ (grid(i, j, k + 1).y - grid(i, j, k - 1).y));
+ v[1] = 0.5 * ((grid(i, j, k + 1).x - grid(i, j, k - 1).x) -
+ (grid(i + 1, j, k).z - grid(i - 1, j, k).z));
+ }
+ dst(i, j, k) = v;
+ }
+ inline const Grid<Vec3> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<Vec3> type0;
+ inline Grid<Vec3> &getArg1()
+ {
+ return dst;
+ }
+ typedef Grid<Vec3> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel CurlOp ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, grid, dst);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, grid, dst);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const Grid<Vec3> &grid;
+ Grid<Vec3> &dst;
+};
+;
+
+//! Kernel: divergence operator (from MAC grid)
+
+struct DivergenceOpMAC : public KernelBase {
+ DivergenceOpMAC(Grid<Real> &div, const MACGrid &grid) : KernelBase(&div, 1), div(div), grid(grid)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Real> &div, const MACGrid &grid) const
+ {
+ Vec3 del = Vec3(grid(i + 1, j, k).x, grid(i, j + 1, k).y, 0.) - grid(i, j, k);
+ if (grid.is3D())
+ del[2] += grid(i, j, k + 1).z;
+ else
+ del[2] = 0.;
+ div(i, j, k) = del.x + del.y + del.z;
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return div;
+ }
+ typedef Grid<Real> type0;
+ inline const MACGrid &getArg1()
+ {
+ return grid;
+ }
+ typedef MACGrid type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel DivergenceOpMAC ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, div, grid);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, div, grid);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<Real> &div;
+ const MACGrid &grid;
+};
+
+//! Kernel: gradient operator for MAC grid
+struct GradientOpMAC : public KernelBase {
+ GradientOpMAC(MACGrid &gradient, const Grid<Real> &grid)
+ : KernelBase(&gradient, 1), gradient(gradient), grid(grid)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, MACGrid &gradient, const Grid<Real> &grid) const
+ {
+ Vec3 grad = (Vec3(grid(i, j, k)) - Vec3(grid(i - 1, j, k), grid(i, j - 1, k), 0.));
+ if (grid.is3D())
+ grad[2] -= grid(i, j, k - 1);
+ else
+ grad[2] = 0.;
+ gradient(i, j, k) = grad;
+ }
+ inline MACGrid &getArg0()
+ {
+ return gradient;
+ }
+ typedef MACGrid type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return grid;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel GradientOpMAC ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, gradient, grid);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, gradient, grid);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ MACGrid &gradient;
+ const Grid<Real> &grid;
+};
+
+//! Kernel: centered gradient operator
+struct GradientOp : public KernelBase {
+ GradientOp(Grid<Vec3> &gradient, const Grid<Real> &grid)
+ : KernelBase(&gradient, 1), gradient(gradient), grid(grid)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Vec3> &gradient, const Grid<Real> &grid) const
+ {
+ Vec3 grad = 0.5 * Vec3(grid(i + 1, j, k) - grid(i - 1, j, k),
+ grid(i, j + 1, k) - grid(i, j - 1, k),
+ 0.);
+ if (grid.is3D())
+ grad[2] = 0.5 * (grid(i, j, k + 1) - grid(i, j, k - 1));
+ gradient(i, j, k) = grad;
+ }
+ inline Grid<Vec3> &getArg0()
+ {
+ return gradient;
+ }
+ typedef Grid<Vec3> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return grid;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel GradientOp ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, gradient, grid);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, gradient, grid);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<Vec3> &gradient;
+ const Grid<Real> &grid;
+};
+
+//! Kernel: Laplace operator
+struct LaplaceOp : public KernelBase {
+ LaplaceOp(Grid<Real> &laplace, const Grid<Real> &grid)
+ : KernelBase(&laplace, 1), laplace(laplace), grid(grid)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Real> &laplace, const Grid<Real> &grid) const
+ {
+ laplace(i, j, k) = grid(i + 1, j, k) - 2.0 * grid(i, j, k) + grid(i - 1, j, k);
+ laplace(i, j, k) += grid(i, j + 1, k) - 2.0 * grid(i, j, k) + grid(i, j - 1, k);
+ if (grid.is3D()) {
+ laplace(i, j, k) += grid(i, j, k + 1) - 2.0 * grid(i, j, k) + grid(i, j, k - 1);
+ }
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return laplace;
+ }
+ typedef Grid<Real> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return grid;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel LaplaceOp ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, laplace, grid);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, laplace, grid);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<Real> &laplace;
+ const Grid<Real> &grid;
+};
+
+//! Kernel: Curvature operator
+struct CurvatureOp : public KernelBase {
+ CurvatureOp(Grid<Real> &curv, const Grid<Real> &grid, const Real h)
+ : KernelBase(&curv, 1), curv(curv), grid(grid), h(h)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Real> &curv, const Grid<Real> &grid, const Real h) const
+ {
+ const Real over_h = 1.0 / h;
+ const Real x = 0.5 * (grid(i + 1, j, k) - grid(i - 1, j, k)) * over_h;
+ const Real y = 0.5 * (grid(i, j + 1, k) - grid(i, j - 1, k)) * over_h;
+ const Real xx = (grid(i + 1, j, k) - 2.0 * grid(i, j, k) + grid(i - 1, j, k)) * over_h *
+ over_h;
+ const Real yy = (grid(i, j + 1, k) - 2.0 * grid(i, j, k) + grid(i, j - 1, k)) * over_h *
+ over_h;
+ const Real xy = 0.25 *
+ (grid(i + 1, j + 1, k) + grid(i - 1, j - 1, k) - grid(i - 1, j + 1, k) -
+ grid(i + 1, j - 1, k)) *
+ over_h * over_h;
+ curv(i, j, k) = x * x * yy + y * y * xx - 2.0 * x * y * xy;
+ Real denom = x * x + y * y;
+ if (grid.is3D()) {
+ const Real z = 0.5 * (grid(i, j, k + 1) - grid(i, j, k - 1)) * over_h;
+ const Real zz = (grid(i, j, k + 1) - 2.0 * grid(i, j, k) + grid(i, j, k - 1)) * over_h *
+ over_h;
+ const Real xz = 0.25 *
+ (grid(i + 1, j, k + 1) + grid(i - 1, j, k - 1) - grid(i - 1, j, k + 1) -
+ grid(i + 1, j, k - 1)) *
+ over_h * over_h;
+ const Real yz = 0.25 *
+ (grid(i, j + 1, k + 1) + grid(i, j - 1, k - 1) - grid(i, j + 1, k - 1) -
+ grid(i, j - 1, k + 1)) *
+ over_h * over_h;
+ curv(i, j, k) += x * x * zz + z * z * xx + y * y * zz + z * z * yy -
+ 2.0 * (x * z * xz + y * z * yz);
+ denom += z * z;
+ }
+ curv(i, j, k) /= std::pow(std::max(denom, VECTOR_EPSILON), 1.5);
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return curv;
+ }
+ typedef Grid<Real> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return grid;
+ }
+ typedef Grid<Real> type1;
+ inline const Real &getArg2()
+ {
+ return h;
+ }
+ typedef Real type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel CurvatureOp ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, curv, grid, h);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, curv, grid, h);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<Real> &curv;
+ const Grid<Real> &grid;
+ const Real h;
+};
+
+//! Kernel: get component at MAC positions
+struct GetShiftedComponent : public KernelBase {
+ GetShiftedComponent(const Grid<Vec3> &grid, Grid<Real> &comp, int dim)
+ : KernelBase(&grid, 1), grid(grid), comp(comp), dim(dim)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const Grid<Vec3> &grid, Grid<Real> &comp, int dim) const
+ {
+ Vec3i ishift(i, j, k);
+ ishift[dim]--;
+ comp(i, j, k) = 0.5 * (grid(i, j, k)[dim] + grid(ishift)[dim]);
+ }
+ inline const Grid<Vec3> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<Vec3> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return comp;
+ }
+ typedef Grid<Real> type1;
+ inline int &getArg2()
+ {
+ return dim;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel GetShiftedComponent ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, grid, comp, dim);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, grid, comp, dim);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const Grid<Vec3> &grid;
+ Grid<Real> &comp;
+ int dim;
+};
+;
+
+//! Kernel: get component (not shifted)
+struct GetComponent : public KernelBase {
+ GetComponent(const Grid<Vec3> &grid, Grid<Real> &comp, int dim)
+ : KernelBase(&grid, 0), grid(grid), comp(comp), dim(dim)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Vec3> &grid, Grid<Real> &comp, int dim) const
+ {
+ comp[idx] = grid[idx][dim];
+ }
+ inline const Grid<Vec3> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<Vec3> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return comp;
+ }
+ typedef Grid<Real> type1;
+ inline int &getArg2()
+ {
+ return dim;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel GetComponent ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, grid, comp, dim);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const Grid<Vec3> &grid;
+ Grid<Real> &comp;
+ int dim;
+};
+;
+
+//! Kernel: get norm of centered grid
+struct GridNorm : public KernelBase {
+ GridNorm(Grid<Real> &n, const Grid<Vec3> &grid) : KernelBase(&n, 0), n(n), grid(grid)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<Real> &n, const Grid<Vec3> &grid) const
+ {
+ n[idx] = norm(grid[idx]);
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return n;
+ }
+ typedef Grid<Real> type0;
+ inline const Grid<Vec3> &getArg1()
+ {
+ return grid;
+ }
+ typedef Grid<Vec3> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel GridNorm ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, n, grid);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Real> &n;
+ const Grid<Vec3> &grid;
+};
+;
+
+//! Kernel: set component (not shifted)
+struct SetComponent : public KernelBase {
+ SetComponent(Grid<Vec3> &grid, const Grid<Real> &comp, int dim)
+ : KernelBase(&grid, 0), grid(grid), comp(comp), dim(dim)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<Vec3> &grid, const Grid<Real> &comp, int dim) const
+ {
+ grid[idx][dim] = comp[idx];
+ }
+ inline Grid<Vec3> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<Vec3> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return comp;
+ }
+ typedef Grid<Real> type1;
+ inline int &getArg2()
+ {
+ return dim;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel SetComponent ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, grid, comp, dim);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Vec3> &grid;
+ const Grid<Real> &comp;
+ int dim;
+};
+;
+
+//! Kernel: compute centered velocity field from MAC
+struct GetCentered : public KernelBase {
+ GetCentered(Grid<Vec3> &center, const MACGrid &vel)
+ : KernelBase(&center, 1), center(center), vel(vel)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Vec3> &center, const MACGrid &vel) const
+ {
+ Vec3 v = 0.5 * (vel(i, j, k) + Vec3(vel(i + 1, j, k).x, vel(i, j + 1, k).y, 0.));
+ if (vel.is3D())
+ v[2] += 0.5 * vel(i, j, k + 1).z;
+ else
+ v[2] = 0.;
+ center(i, j, k) = v;
+ }
+ inline Grid<Vec3> &getArg0()
+ {
+ return center;
+ }
+ typedef Grid<Vec3> type0;
+ inline const MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel GetCentered ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, center, vel);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, center, vel);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<Vec3> &center;
+ const MACGrid &vel;
+};
+;
+
+//! Kernel: compute MAC from centered velocity field
+struct GetMAC : public KernelBase {
+ GetMAC(MACGrid &vel, const Grid<Vec3> &center) : KernelBase(&vel, 1), vel(vel), center(center)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, MACGrid &vel, const Grid<Vec3> &center) const
+ {
+ Vec3 v = 0.5 * (center(i, j, k) + Vec3(center(i - 1, j, k).x, center(i, j - 1, k).y, 0.));
+ if (vel.is3D())
+ v[2] += 0.5 * center(i, j, k - 1).z;
+ else
+ v[2] = 0.;
+ vel(i, j, k) = v;
+ }
+ inline MACGrid &getArg0()
+ {
+ return vel;
+ }
+ typedef MACGrid type0;
+ inline const Grid<Vec3> &getArg1()
+ {
+ return center;
+ }
+ typedef Grid<Vec3> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel GetMAC ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, center);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, center);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ MACGrid &vel;
+ const Grid<Vec3> &center;
+};
+;
+
+//! Fill in the domain boundary cells (i,j,k=0/size-1) from the neighboring cells
+struct FillInBoundary : public KernelBase {
+ FillInBoundary(Grid<Vec3> &grid, int g) : KernelBase(&grid, 0), grid(grid), g(g)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Vec3> &grid, int g) const
+ {
+ if (i == 0)
+ grid(i, j, k) = grid(i + 1, j, k);
+ if (j == 0)
+ grid(i, j, k) = grid(i, j + 1, k);
+ if (k == 0)
+ grid(i, j, k) = grid(i, j, k + 1);
+ if (i == grid.getSizeX() - 1)
+ grid(i, j, k) = grid(i - 1, j, k);
+ if (j == grid.getSizeY() - 1)
+ grid(i, j, k) = grid(i, j - 1, k);
+ if (k == grid.getSizeZ() - 1)
+ grid(i, j, k) = grid(i, j, k - 1);
+ }
+ inline Grid<Vec3> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<Vec3> type0;
+ inline int &getArg1()
+ {
+ return g;
+ }
+ typedef int type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel FillInBoundary ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, g);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, g);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<Vec3> &grid;
+ int g;
+};
+
+// ****************************************************************************
+
+// helper functions for converting mex data to manta grids and back (for matlab integration)
+
+// MAC grids
+
+struct kn_conv_mex_in_to_MAC : public KernelBase {
+ kn_conv_mex_in_to_MAC(const double *p_lin_array, MACGrid *p_result)
+ : KernelBase(p_result, 0), p_lin_array(p_lin_array), p_result(p_result)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const double *p_lin_array, MACGrid *p_result) const
+ {
+ int ijk = i + j * p_result->getSizeX() + k * p_result->getSizeX() * p_result->getSizeY();
+ const int n = p_result->getSizeX() * p_result->getSizeY() * p_result->getSizeZ();
+
+ p_result->get(i, j, k).x = p_lin_array[ijk];
+ p_result->get(i, j, k).y = p_lin_array[ijk + n];
+ p_result->get(i, j, k).z = p_lin_array[ijk + 2 * n];
+ }
+ inline const double *getArg0()
+ {
+ return p_lin_array;
+ }
+ typedef double type0;
+ inline MACGrid *getArg1()
+ {
+ return p_result;
+ }
+ typedef MACGrid type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn_conv_mex_in_to_MAC ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_lin_array, p_result);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_lin_array, p_result);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const double *p_lin_array;
+ MACGrid *p_result;
+};
+
+struct kn_conv_MAC_to_mex_out : public KernelBase {
+ kn_conv_MAC_to_mex_out(const MACGrid *p_mac, double *p_result)
+ : KernelBase(p_mac, 0), p_mac(p_mac), p_result(p_result)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const MACGrid *p_mac, double *p_result) const
+ {
+ int ijk = i + j * p_mac->getSizeX() + k * p_mac->getSizeX() * p_mac->getSizeY();
+ const int n = p_mac->getSizeX() * p_mac->getSizeY() * p_mac->getSizeZ();
+
+ p_result[ijk] = p_mac->get(i, j, k).x;
+ p_result[ijk + n] = p_mac->get(i, j, k).y;
+ p_result[ijk + 2 * n] = p_mac->get(i, j, k).z;
+ }
+ inline const MACGrid *getArg0()
+ {
+ return p_mac;
+ }
+ typedef MACGrid type0;
+ inline double *getArg1()
+ {
+ return p_result;
+ }
+ typedef double type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn_conv_MAC_to_mex_out ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_mac, p_result);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_mac, p_result);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const MACGrid *p_mac;
+ double *p_result;
+};
+
+// Vec3 Grids
+
+struct kn_conv_mex_in_to_Vec3 : public KernelBase {
+ kn_conv_mex_in_to_Vec3(const double *p_lin_array, Grid<Vec3> *p_result)
+ : KernelBase(p_result, 0), p_lin_array(p_lin_array), p_result(p_result)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const double *p_lin_array, Grid<Vec3> *p_result) const
+ {
+ int ijk = i + j * p_result->getSizeX() + k * p_result->getSizeX() * p_result->getSizeY();
+ const int n = p_result->getSizeX() * p_result->getSizeY() * p_result->getSizeZ();
+
+ p_result->get(i, j, k).x = p_lin_array[ijk];
+ p_result->get(i, j, k).y = p_lin_array[ijk + n];
+ p_result->get(i, j, k).z = p_lin_array[ijk + 2 * n];
+ }
+ inline const double *getArg0()
+ {
+ return p_lin_array;
+ }
+ typedef double type0;
+ inline Grid<Vec3> *getArg1()
+ {
+ return p_result;
+ }
+ typedef Grid<Vec3> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn_conv_mex_in_to_Vec3 ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_lin_array, p_result);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_lin_array, p_result);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const double *p_lin_array;
+ Grid<Vec3> *p_result;
+};
+
+struct kn_conv_Vec3_to_mex_out : public KernelBase {
+ kn_conv_Vec3_to_mex_out(const Grid<Vec3> *p_Vec3, double *p_result)
+ : KernelBase(p_Vec3, 0), p_Vec3(p_Vec3), p_result(p_result)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const Grid<Vec3> *p_Vec3, double *p_result) const
+ {
+ int ijk = i + j * p_Vec3->getSizeX() + k * p_Vec3->getSizeX() * p_Vec3->getSizeY();
+ const int n = p_Vec3->getSizeX() * p_Vec3->getSizeY() * p_Vec3->getSizeZ();
+
+ p_result[ijk] = p_Vec3->get(i, j, k).x;
+ p_result[ijk + n] = p_Vec3->get(i, j, k).y;
+ p_result[ijk + 2 * n] = p_Vec3->get(i, j, k).z;
+ }
+ inline const Grid<Vec3> *getArg0()
+ {
+ return p_Vec3;
+ }
+ typedef Grid<Vec3> type0;
+ inline double *getArg1()
+ {
+ return p_result;
+ }
+ typedef double type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn_conv_Vec3_to_mex_out ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_Vec3, p_result);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_Vec3, p_result);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const Grid<Vec3> *p_Vec3;
+ double *p_result;
+};
+
+// Real Grids
+
+struct kn_conv_mex_in_to_Real : public KernelBase {
+ kn_conv_mex_in_to_Real(const double *p_lin_array, Grid<Real> *p_result)
+ : KernelBase(p_result, 0), p_lin_array(p_lin_array), p_result(p_result)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const double *p_lin_array, Grid<Real> *p_result) const
+ {
+ int ijk = i + j * p_result->getSizeX() + k * p_result->getSizeX() * p_result->getSizeY();
+
+ p_result->get(i, j, k) = p_lin_array[ijk];
+ }
+ inline const double *getArg0()
+ {
+ return p_lin_array;
+ }
+ typedef double type0;
+ inline Grid<Real> *getArg1()
+ {
+ return p_result;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn_conv_mex_in_to_Real ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_lin_array, p_result);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_lin_array, p_result);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const double *p_lin_array;
+ Grid<Real> *p_result;
+};
+
+struct kn_conv_Real_to_mex_out : public KernelBase {
+ kn_conv_Real_to_mex_out(const Grid<Real> *p_grid, double *p_result)
+ : KernelBase(p_grid, 0), p_grid(p_grid), p_result(p_result)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const Grid<Real> *p_grid, double *p_result) const
+ {
+ int ijk = i + j * p_grid->getSizeX() + k * p_grid->getSizeX() * p_grid->getSizeY();
+
+ p_result[ijk] = p_grid->get(i, j, k);
+ }
+ inline const Grid<Real> *getArg0()
+ {
+ return p_grid;
+ }
+ typedef Grid<Real> type0;
+ inline double *getArg1()
+ {
+ return p_result;
+ }
+ typedef double type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn_conv_Real_to_mex_out ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_grid, p_result);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, p_grid, p_result);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const Grid<Real> *p_grid;
+ double *p_result;
+};
+
+} // namespace Manta
+#endif
diff --git a/extern/mantaflow/preprocessed/commonkernels.h.reg.cpp b/extern/mantaflow/preprocessed/commonkernels.h.reg.cpp
new file mode 100644
index 00000000000..0a7a55b7147
--- /dev/null
+++ b/extern/mantaflow/preprocessed/commonkernels.h.reg.cpp
@@ -0,0 +1,13 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "commonkernels.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_2()
+{
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/conjugategrad.cpp b/extern/mantaflow/preprocessed/conjugategrad.cpp
new file mode 100644
index 00000000000..ac317402a49
--- /dev/null
+++ b/extern/mantaflow/preprocessed/conjugategrad.cpp
@@ -0,0 +1,719 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Conjugate gradient solver, for pressure and viscosity
+ *
+ ******************************************************************************/
+
+#include "conjugategrad.h"
+#include "commonkernels.h"
+
+using namespace std;
+namespace Manta {
+
+const int CG_DEBUGLEVEL = 3;
+
+//*****************************************************************************
+// Precondition helpers
+
+//! Preconditioning a la Wavelet Turbulence (needs 4 add. grids)
+void InitPreconditionIncompCholesky(const FlagGrid &flags,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak,
+ Grid<Real> &orgA0,
+ Grid<Real> &orgAi,
+ Grid<Real> &orgAj,
+ Grid<Real> &orgAk)
+{
+ // compute IC according to Golub and Van Loan
+ A0.copyFrom(orgA0);
+ Ai.copyFrom(orgAi);
+ Aj.copyFrom(orgAj);
+ Ak.copyFrom(orgAk);
+
+ FOR_IJK(A0)
+ {
+ if (flags.isFluid(i, j, k)) {
+ const IndexInt idx = A0.index(i, j, k);
+ A0[idx] = sqrt(A0[idx]);
+
+ // correct left and top stencil in other entries
+ // for i = k+1:n
+ // if (A(i,k) != 0)
+ // A(i,k) = A(i,k) / A(k,k)
+ Real invDiagonal = 1.0f / A0[idx];
+ Ai[idx] *= invDiagonal;
+ Aj[idx] *= invDiagonal;
+ Ak[idx] *= invDiagonal;
+
+ // correct the right and bottom stencil in other entries
+ // for j = k+1:n
+ // for i = j:n
+ // if (A(i,j) != 0)
+ // A(i,j) = A(i,j) - A(i,k) * A(j,k)
+ A0(i + 1, j, k) -= square(Ai[idx]);
+ A0(i, j + 1, k) -= square(Aj[idx]);
+ A0(i, j, k + 1) -= square(Ak[idx]);
+ }
+ }
+
+ // invert A0 for faster computation later
+ InvertCheckFluid(flags, A0);
+};
+
+//! Preconditioning using modified IC ala Bridson (needs 1 add. grid)
+void InitPreconditionModifiedIncompCholesky2(const FlagGrid &flags,
+ Grid<Real> &Aprecond,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak)
+{
+ // compute IC according to Golub and Van Loan
+ Aprecond.clear();
+
+ FOR_IJK(flags)
+ {
+ if (!flags.isFluid(i, j, k))
+ continue;
+
+ const Real tau = 0.97;
+ const Real sigma = 0.25;
+
+ // compute modified incomplete cholesky
+ Real e = 0.;
+ e = A0(i, j, k) - square(Ai(i - 1, j, k) * Aprecond(i - 1, j, k)) -
+ square(Aj(i, j - 1, k) * Aprecond(i, j - 1, k)) -
+ square(Ak(i, j, k - 1) * Aprecond(i, j, k - 1));
+ e -= tau *
+ (Ai(i - 1, j, k) * (Aj(i - 1, j, k) + Ak(i - 1, j, k)) * square(Aprecond(i - 1, j, k)) +
+ Aj(i, j - 1, k) * (Ai(i, j - 1, k) + Ak(i, j - 1, k)) * square(Aprecond(i, j - 1, k)) +
+ Ak(i, j, k - 1) * (Ai(i, j, k - 1) + Aj(i, j, k - 1)) * square(Aprecond(i, j, k - 1)) +
+ 0.);
+
+ // stability cutoff
+ if (e < sigma * A0(i, j, k))
+ e = A0(i, j, k);
+
+ Aprecond(i, j, k) = 1. / sqrt(e);
+ }
+};
+
+//! Preconditioning using multigrid ala Dick et al.
+void InitPreconditionMultigrid(
+ GridMg *MG, Grid<Real> &A0, Grid<Real> &Ai, Grid<Real> &Aj, Grid<Real> &Ak, Real mAccuracy)
+{
+ // build multigrid hierarchy if necessary
+ if (!MG->isASet())
+ MG->setA(&A0, &Ai, &Aj, &Ak);
+ MG->setCoarsestLevelAccuracy(mAccuracy * 1E-4);
+ MG->setSmoothing(1, 1);
+};
+
+//! Apply WT-style ICP
+void ApplyPreconditionIncompCholesky(Grid<Real> &dst,
+ Grid<Real> &Var1,
+ const FlagGrid &flags,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak,
+ Grid<Real> &orgA0,
+ Grid<Real> &orgAi,
+ Grid<Real> &orgAj,
+ Grid<Real> &orgAk)
+{
+
+ // forward substitution
+ FOR_IJK(dst)
+ {
+ if (!flags.isFluid(i, j, k))
+ continue;
+ dst(i, j, k) = A0(i, j, k) *
+ (Var1(i, j, k) - dst(i - 1, j, k) * Ai(i - 1, j, k) -
+ dst(i, j - 1, k) * Aj(i, j - 1, k) - dst(i, j, k - 1) * Ak(i, j, k - 1));
+ }
+
+ // backward substitution
+ FOR_IJK_REVERSE(dst)
+ {
+ const IndexInt idx = A0.index(i, j, k);
+ if (!flags.isFluid(idx))
+ continue;
+ dst[idx] = A0[idx] * (dst[idx] - dst(i + 1, j, k) * Ai[idx] - dst(i, j + 1, k) * Aj[idx] -
+ dst(i, j, k + 1) * Ak[idx]);
+ }
+}
+
+//! Apply Bridson-style mICP
+void ApplyPreconditionModifiedIncompCholesky2(Grid<Real> &dst,
+ Grid<Real> &Var1,
+ const FlagGrid &flags,
+ Grid<Real> &Aprecond,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak)
+{
+ // forward substitution
+ FOR_IJK(dst)
+ {
+ if (!flags.isFluid(i, j, k))
+ continue;
+ const Real p = Aprecond(i, j, k);
+ dst(i, j, k) = p *
+ (Var1(i, j, k) - dst(i - 1, j, k) * Ai(i - 1, j, k) * Aprecond(i - 1, j, k) -
+ dst(i, j - 1, k) * Aj(i, j - 1, k) * Aprecond(i, j - 1, k) -
+ dst(i, j, k - 1) * Ak(i, j, k - 1) * Aprecond(i, j, k - 1));
+ }
+
+ // backward substitution
+ FOR_IJK_REVERSE(dst)
+ {
+ const IndexInt idx = A0.index(i, j, k);
+ if (!flags.isFluid(idx))
+ continue;
+ const Real p = Aprecond[idx];
+ dst[idx] = p * (dst[idx] - dst(i + 1, j, k) * Ai[idx] * p - dst(i, j + 1, k) * Aj[idx] * p -
+ dst(i, j, k + 1) * Ak[idx] * p);
+ }
+}
+
+//! Perform one Multigrid VCycle
+void ApplyPreconditionMultigrid(GridMg *pMG, Grid<Real> &dst, Grid<Real> &Var1)
+{
+ // one VCycle on "A*dst = Var1" with initial guess dst=0
+ pMG->setRhs(Var1);
+ pMG->doVCycle(dst);
+}
+
+//*****************************************************************************
+// Kernels
+
+//! Kernel: Compute the dot product between two Real grids
+/*! Uses double precision internally */
+
+struct GridDotProduct : public KernelBase {
+ GridDotProduct(const Grid<Real> &a, const Grid<Real> &b)
+ : KernelBase(&a, 0), a(a), b(b), result(0.0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Real> &a, const Grid<Real> &b, double &result)
+ {
+ result += (a[idx] * b[idx]);
+ }
+ inline operator double()
+ {
+ return result;
+ }
+ inline double &getRet()
+ {
+ return result;
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return a;
+ }
+ typedef Grid<Real> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return b;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel GridDotProduct ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, a, b, result);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ GridDotProduct(GridDotProduct &o, tbb::split) : KernelBase(o), a(o.a), b(o.b), result(0.0)
+ {
+ }
+ void join(const GridDotProduct &o)
+ {
+ result += o.result;
+ }
+ const Grid<Real> &a;
+ const Grid<Real> &b;
+ double result;
+};
+;
+
+//! Kernel: compute residual (init) and add to sigma
+
+struct InitSigma : public KernelBase {
+ InitSigma(const FlagGrid &flags, Grid<Real> &dst, Grid<Real> &rhs, Grid<Real> &temp)
+ : KernelBase(&flags, 0), flags(flags), dst(dst), rhs(rhs), temp(temp), sigma(0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const FlagGrid &flags,
+ Grid<Real> &dst,
+ Grid<Real> &rhs,
+ Grid<Real> &temp,
+ double &sigma)
+ {
+ const double res = rhs[idx] - temp[idx];
+ dst[idx] = (Real)res;
+
+ // only compute residual in fluid region
+ if (flags.isFluid(idx))
+ sigma += res * res;
+ }
+ inline operator double()
+ {
+ return sigma;
+ }
+ inline double &getRet()
+ {
+ return sigma;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return dst;
+ }
+ typedef Grid<Real> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return rhs;
+ }
+ typedef Grid<Real> type2;
+ inline Grid<Real> &getArg3()
+ {
+ return temp;
+ }
+ typedef Grid<Real> type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel InitSigma ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, flags, dst, rhs, temp, sigma);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ InitSigma(InitSigma &o, tbb::split)
+ : KernelBase(o), flags(o.flags), dst(o.dst), rhs(o.rhs), temp(o.temp), sigma(0)
+ {
+ }
+ void join(const InitSigma &o)
+ {
+ sigma += o.sigma;
+ }
+ const FlagGrid &flags;
+ Grid<Real> &dst;
+ Grid<Real> &rhs;
+ Grid<Real> &temp;
+ double sigma;
+};
+;
+
+//! Kernel: update search vector
+
+struct UpdateSearchVec : public KernelBase {
+ UpdateSearchVec(Grid<Real> &dst, Grid<Real> &src, Real factor)
+ : KernelBase(&dst, 0), dst(dst), src(src), factor(factor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<Real> &dst, Grid<Real> &src, Real factor) const
+ {
+ dst[idx] = src[idx] + factor * dst[idx];
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return dst;
+ }
+ typedef Grid<Real> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return src;
+ }
+ typedef Grid<Real> type1;
+ inline Real &getArg2()
+ {
+ return factor;
+ }
+ typedef Real type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel UpdateSearchVec ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, dst, src, factor);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Real> &dst;
+ Grid<Real> &src;
+ Real factor;
+};
+
+//*****************************************************************************
+// CG class
+
+template<class APPLYMAT>
+GridCg<APPLYMAT>::GridCg(Grid<Real> &dst,
+ Grid<Real> &rhs,
+ Grid<Real> &residual,
+ Grid<Real> &search,
+ const FlagGrid &flags,
+ Grid<Real> &tmp,
+ Grid<Real> *pA0,
+ Grid<Real> *pAi,
+ Grid<Real> *pAj,
+ Grid<Real> *pAk)
+ : GridCgInterface(),
+ mInited(false),
+ mIterations(0),
+ mDst(dst),
+ mRhs(rhs),
+ mResidual(residual),
+ mSearch(search),
+ mFlags(flags),
+ mTmp(tmp),
+ mpA0(pA0),
+ mpAi(pAi),
+ mpAj(pAj),
+ mpAk(pAk),
+ mPcMethod(PC_None),
+ mpPCA0(nullptr),
+ mpPCAi(nullptr),
+ mpPCAj(nullptr),
+ mpPCAk(nullptr),
+ mMG(nullptr),
+ mSigma(0.),
+ mAccuracy(VECTOR_EPSILON),
+ mResNorm(1e20)
+{
+}
+
+template<class APPLYMAT> void GridCg<APPLYMAT>::doInit()
+{
+ mInited = true;
+ mIterations = 0;
+
+ mDst.clear();
+ mResidual.copyFrom(mRhs); // p=0, residual = b
+
+ if (mPcMethod == PC_ICP) {
+ assertMsg(mDst.is3D(), "ICP only supports 3D grids so far");
+ InitPreconditionIncompCholesky(
+ mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
+ ApplyPreconditionIncompCholesky(
+ mTmp, mResidual, mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
+ }
+ else if (mPcMethod == PC_mICP) {
+ assertMsg(mDst.is3D(), "mICP only supports 3D grids so far");
+ InitPreconditionModifiedIncompCholesky2(mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
+ ApplyPreconditionModifiedIncompCholesky2(
+ mTmp, mResidual, mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
+ }
+ else if (mPcMethod == PC_MGP) {
+ InitPreconditionMultigrid(mMG, *mpA0, *mpAi, *mpAj, *mpAk, mAccuracy);
+ ApplyPreconditionMultigrid(mMG, mTmp, mResidual);
+ }
+ else {
+ mTmp.copyFrom(mResidual);
+ }
+
+ mSearch.copyFrom(mTmp);
+
+ mSigma = GridDotProduct(mTmp, mResidual);
+}
+
+template<class APPLYMAT> bool GridCg<APPLYMAT>::iterate()
+{
+ if (!mInited)
+ doInit();
+
+ mIterations++;
+
+ // create matrix application operator passed as template argument,
+ // this could reinterpret the mpA pointers (not so clean right now)
+ // tmp = applyMat(search)
+
+ APPLYMAT(mFlags, mTmp, mSearch, *mpA0, *mpAi, *mpAj, *mpAk);
+
+ // alpha = sigma/dot(tmp, search)
+ Real dp = GridDotProduct(mTmp, mSearch);
+ Real alpha = 0.;
+ if (fabs(dp) > 0.)
+ alpha = mSigma / (Real)dp;
+
+ gridScaledAdd<Real, Real>(mDst, mSearch, alpha); // dst += search * alpha
+ gridScaledAdd<Real, Real>(mResidual, mTmp, -alpha); // residual += tmp * -alpha
+
+ if (mPcMethod == PC_ICP)
+ ApplyPreconditionIncompCholesky(
+ mTmp, mResidual, mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
+ else if (mPcMethod == PC_mICP)
+ ApplyPreconditionModifiedIncompCholesky2(
+ mTmp, mResidual, mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
+ else if (mPcMethod == PC_MGP)
+ ApplyPreconditionMultigrid(mMG, mTmp, mResidual);
+ else
+ mTmp.copyFrom(mResidual);
+
+ // use the l2 norm of the residual for convergence check? (usually max norm is recommended
+ // instead)
+ if (this->mUseL2Norm) {
+ mResNorm = GridSumSqr(mResidual).sum;
+ }
+ else {
+ mResNorm = mResidual.getMaxAbs();
+ }
+
+ // abort here to safe some work...
+ if (mResNorm < mAccuracy) {
+ mSigma = mResNorm; // this will be returned later on to the caller...
+ return false;
+ }
+
+ Real sigmaNew = GridDotProduct(mTmp, mResidual);
+ Real beta = sigmaNew / mSigma;
+
+ // search = tmp + beta * search
+ UpdateSearchVec(mSearch, mTmp, beta);
+
+ debMsg("GridCg::iterate i=" << mIterations << " sigmaNew=" << sigmaNew << " sigmaLast=" << mSigma
+ << " alpha=" << alpha << " beta=" << beta << " ",
+ CG_DEBUGLEVEL);
+ mSigma = sigmaNew;
+
+ if (!(mResNorm < 1e35)) {
+ if (mPcMethod == PC_MGP) {
+ // diverging solves can be caused by the static multigrid mode, we cannot detect this here,
+ // though only the pressure solve call "knows" whether the MG is static or dynamics...
+ debMsg(
+ "GridCg::iterate: Warning - this diverging solve can be caused by the 'static' mode of "
+ "the MG preconditioner. If the static mode is active, try switching to dynamic.",
+ 1);
+ }
+ errMsg("GridCg::iterate: The CG solver diverged, residual norm > 1e30, stopping.");
+ }
+
+ // debMsg("PB-CG-Norms::p"<<sqrt( GridOpNormNosqrt(mpDst, mpFlags).getValue() ) <<"
+ // search"<<sqrt( GridOpNormNosqrt(mpSearch, mpFlags).getValue(), CG_DEBUGLEVEL ) <<" res"<<sqrt(
+ // GridOpNormNosqrt(mpResidual, mpFlags).getValue() ) <<" tmp"<<sqrt( GridOpNormNosqrt(mpTmp,
+ // mpFlags).getValue() ), CG_DEBUGLEVEL ); // debug
+ return true;
+}
+
+template<class APPLYMAT> void GridCg<APPLYMAT>::solve(int maxIter)
+{
+ for (int iter = 0; iter < maxIter; iter++) {
+ if (!iterate())
+ iter = maxIter;
+ }
+ return;
+}
+
+static bool gPrint2dWarning = true;
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::setICPreconditioner(
+ PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak)
+{
+ assertMsg(method == PC_ICP || method == PC_mICP,
+ "GridCg<APPLYMAT>::setICPreconditioner: Invalid method specified.");
+
+ mPcMethod = method;
+ if ((!A0->is3D())) {
+ if (gPrint2dWarning) {
+ debMsg("ICP/mICP pre-conditioning only supported in 3D for now, disabling it.", 1);
+ gPrint2dWarning = false;
+ }
+ mPcMethod = PC_None;
+ }
+ mpPCA0 = A0;
+ mpPCAi = Ai;
+ mpPCAj = Aj;
+ mpPCAk = Ak;
+}
+
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::setMGPreconditioner(PreconditionType method, GridMg *MG)
+{
+ assertMsg(method == PC_MGP, "GridCg<APPLYMAT>::setMGPreconditioner: Invalid method specified.");
+
+ mPcMethod = method;
+
+ mMG = MG;
+}
+
+// explicit instantiation
+template class GridCg<ApplyMatrix>;
+template class GridCg<ApplyMatrix2D>;
+
+//*****************************************************************************
+// diffusion for real and vec grids, e.g. for viscosity
+
+//! do a CG solve for diffusion; note: diffusion coefficient alpha given in grid space,
+// rescale in python file for discretization independence (or physical correspondence)
+// see lidDrivenCavity.py for an example
+
+void cgSolveDiffusion(const FlagGrid &flags,
+ GridBase &grid,
+ Real alpha = 0.25,
+ Real cgMaxIterFac = 1.0,
+ Real cgAccuracy = 1e-4)
+{
+ // reserve temp grids
+ FluidSolver *parent = flags.getParent();
+ Grid<Real> rhs(parent);
+ Grid<Real> residual(parent), search(parent), tmp(parent);
+ Grid<Real> A0(parent), Ai(parent), Aj(parent), Ak(parent);
+
+ // setup matrix and boundaries
+ FlagGrid flagsDummy(parent);
+ flagsDummy.setConst(FlagGrid::TypeFluid);
+ MakeLaplaceMatrix(flagsDummy, A0, Ai, Aj, Ak);
+
+ FOR_IJK(flags)
+ {
+ if (flags.isObstacle(i, j, k)) {
+ Ai(i, j, k) = Aj(i, j, k) = Ak(i, j, k) = 0.0;
+ A0(i, j, k) = 1.0;
+ }
+ else {
+ Ai(i, j, k) *= alpha;
+ Aj(i, j, k) *= alpha;
+ Ak(i, j, k) *= alpha;
+ A0(i, j, k) *= alpha;
+ A0(i, j, k) += 1.;
+ }
+ }
+
+ GridCgInterface *gcg;
+ // note , no preconditioning for now...
+ const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+
+ if (grid.getType() & GridBase::TypeReal) {
+ Grid<Real> &u = ((Grid<Real> &)grid);
+ rhs.copyFrom(u);
+ if (flags.is3D())
+ gcg = new GridCg<ApplyMatrix>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+ else
+ gcg = new GridCg<ApplyMatrix2D>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+
+ gcg->setAccuracy(cgAccuracy);
+ gcg->solve(maxIter);
+
+ debMsg("FluidSolver::solveDiffusion iterations:" << gcg->getIterations()
+ << ", res:" << gcg->getSigma(),
+ CG_DEBUGLEVEL);
+ }
+ else if ((grid.getType() & GridBase::TypeVec3) || (grid.getType() & GridBase::TypeVec3)) {
+ Grid<Vec3> &vec = ((Grid<Vec3> &)grid);
+ Grid<Real> u(parent);
+
+ // core solve is same as for a regular real grid
+ if (flags.is3D())
+ gcg = new GridCg<ApplyMatrix>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+ else
+ gcg = new GridCg<ApplyMatrix2D>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+ gcg->setAccuracy(cgAccuracy);
+
+ // diffuse every component separately
+ for (int component = 0; component < (grid.is3D() ? 3 : 2); ++component) {
+ getComponent(vec, u, component);
+ gcg->forceReinit();
+
+ rhs.copyFrom(u);
+ gcg->solve(maxIter);
+ debMsg("FluidSolver::solveDiffusion vec3, iterations:" << gcg->getIterations()
+ << ", res:" << gcg->getSigma(),
+ CG_DEBUGLEVEL);
+
+ setComponent(u, vec, component);
+ }
+ }
+ else {
+ errMsg("cgSolveDiffusion: Grid Type is not supported (only Real, Vec3, MAC, or Levelset)");
+ }
+
+ delete gcg;
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "cgSolveDiffusion", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ GridBase &grid = *_args.getPtr<GridBase>("grid", 1, &_lock);
+ Real alpha = _args.getOpt<Real>("alpha", 2, 0.25, &_lock);
+ Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 3, 1.0, &_lock);
+ Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 4, 1e-4, &_lock);
+ _retval = getPyNone();
+ cgSolveDiffusion(flags, grid, alpha, cgMaxIterFac, cgAccuracy);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "cgSolveDiffusion", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("cgSolveDiffusion", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_cgSolveDiffusion("", "cgSolveDiffusion", _W_0);
+extern "C" {
+void PbRegister_cgSolveDiffusion()
+{
+ KEEP_UNUSED(_RP_cgSolveDiffusion);
+}
+}
+
+}; // namespace Manta
diff --git a/extern/mantaflow/preprocessed/conjugategrad.h b/extern/mantaflow/preprocessed/conjugategrad.h
new file mode 100644
index 00000000000..58ccff28179
--- /dev/null
+++ b/extern/mantaflow/preprocessed/conjugategrad.h
@@ -0,0 +1,479 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Conjugate gradient solver
+ *
+ ******************************************************************************/
+
+#ifndef _CONJUGATEGRADIENT_H
+#define _CONJUGATEGRADIENT_H
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+#include "multigrid.h"
+
+namespace Manta {
+
+static const bool CG_DEBUG = false;
+
+//! Basic CG interface
+class GridCgInterface {
+ public:
+ enum PreconditionType { PC_None = 0, PC_ICP, PC_mICP, PC_MGP };
+
+ GridCgInterface() : mUseL2Norm(true){};
+ virtual ~GridCgInterface(){};
+
+ // solving functions
+ virtual bool iterate() = 0;
+ virtual void solve(int maxIter) = 0;
+
+ // precond
+ virtual void setICPreconditioner(
+ PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) = 0;
+ virtual void setMGPreconditioner(PreconditionType method, GridMg *MG) = 0;
+
+ // access
+ virtual Real getSigma() const = 0;
+ virtual Real getIterations() const = 0;
+ virtual Real getResNorm() const = 0;
+ virtual void setAccuracy(Real set) = 0;
+ virtual Real getAccuracy() const = 0;
+
+ //! force reinit upon next iterate() call, can be used for doing multiple solves
+ virtual void forceReinit() = 0;
+
+ void setUseL2Norm(bool set)
+ {
+ mUseL2Norm = set;
+ }
+
+ protected:
+ // use l2 norm of residualfor threshold? (otherwise uses max norm)
+ bool mUseL2Norm;
+};
+
+//! Run single iteration of the cg solver
+/*! the template argument determines the type of matrix multiplication,
+ typically a ApplyMatrix kernel, another one is needed e.g. for the
+ mesh-based wave equation solver */
+template<class APPLYMAT> class GridCg : public GridCgInterface {
+ public:
+ //! constructor
+ GridCg(Grid<Real> &dst,
+ Grid<Real> &rhs,
+ Grid<Real> &residual,
+ Grid<Real> &search,
+ const FlagGrid &flags,
+ Grid<Real> &tmp,
+ Grid<Real> *A0,
+ Grid<Real> *pAi,
+ Grid<Real> *pAj,
+ Grid<Real> *pAk);
+ ~GridCg()
+ {
+ }
+
+ void doInit();
+ bool iterate();
+ void solve(int maxIter);
+ //! init pointers, and copy values from "normal" matrix
+ void setICPreconditioner(
+ PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak);
+ void setMGPreconditioner(PreconditionType method, GridMg *MG);
+ void forceReinit()
+ {
+ mInited = false;
+ }
+
+ // Accessors
+ Real getSigma() const
+ {
+ return mSigma;
+ }
+ Real getIterations() const
+ {
+ return mIterations;
+ }
+
+ Real getResNorm() const
+ {
+ return mResNorm;
+ }
+
+ void setAccuracy(Real set)
+ {
+ mAccuracy = set;
+ }
+ Real getAccuracy() const
+ {
+ return mAccuracy;
+ }
+
+ protected:
+ bool mInited;
+ int mIterations;
+ // grids
+ Grid<Real> &mDst;
+ Grid<Real> &mRhs;
+ Grid<Real> &mResidual;
+ Grid<Real> &mSearch;
+ const FlagGrid &mFlags;
+ Grid<Real> &mTmp;
+
+ Grid<Real> *mpA0, *mpAi, *mpAj, *mpAk;
+
+ PreconditionType mPcMethod;
+ //! preconditioning grids
+ Grid<Real> *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk;
+ GridMg *mMG;
+
+ //! sigma / residual
+ Real mSigma;
+ //! accuracy of solver (max. residuum)
+ Real mAccuracy;
+ //! norm of the residual
+ Real mResNorm;
+}; // GridCg
+
+//! Kernel: Apply symmetric stored Matrix
+
+struct ApplyMatrix : public KernelBase {
+ ApplyMatrix(const FlagGrid &flags,
+ Grid<Real> &dst,
+ const Grid<Real> &src,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak)
+ : KernelBase(&flags, 0), flags(flags), dst(dst), src(src), A0(A0), Ai(Ai), Aj(Aj), Ak(Ak)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const FlagGrid &flags,
+ Grid<Real> &dst,
+ const Grid<Real> &src,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak) const
+ {
+ if (!flags.isFluid(idx)) {
+ dst[idx] = src[idx];
+ return;
+ }
+
+ dst[idx] = src[idx] * A0[idx] + src[idx - X] * Ai[idx - X] + src[idx + X] * Ai[idx] +
+ src[idx - Y] * Aj[idx - Y] + src[idx + Y] * Aj[idx] + src[idx - Z] * Ak[idx - Z] +
+ src[idx + Z] * Ak[idx];
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return dst;
+ }
+ typedef Grid<Real> type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return src;
+ }
+ typedef Grid<Real> type2;
+ inline Grid<Real> &getArg3()
+ {
+ return A0;
+ }
+ typedef Grid<Real> type3;
+ inline Grid<Real> &getArg4()
+ {
+ return Ai;
+ }
+ typedef Grid<Real> type4;
+ inline Grid<Real> &getArg5()
+ {
+ return Aj;
+ }
+ typedef Grid<Real> type5;
+ inline Grid<Real> &getArg6()
+ {
+ return Ak;
+ }
+ typedef Grid<Real> type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel ApplyMatrix ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, flags, dst, src, A0, Ai, Aj, Ak);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &dst;
+ const Grid<Real> &src;
+ Grid<Real> &A0;
+ Grid<Real> &Ai;
+ Grid<Real> &Aj;
+ Grid<Real> &Ak;
+};
+
+//! Kernel: Apply symmetric stored Matrix. 2D version
+
+struct ApplyMatrix2D : public KernelBase {
+ ApplyMatrix2D(const FlagGrid &flags,
+ Grid<Real> &dst,
+ const Grid<Real> &src,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak)
+ : KernelBase(&flags, 0), flags(flags), dst(dst), src(src), A0(A0), Ai(Ai), Aj(Aj), Ak(Ak)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const FlagGrid &flags,
+ Grid<Real> &dst,
+ const Grid<Real> &src,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak) const
+ {
+ unusedParameter(Ak); // only there for parameter compatibility with ApplyMatrix
+
+ if (!flags.isFluid(idx)) {
+ dst[idx] = src[idx];
+ return;
+ }
+
+ dst[idx] = src[idx] * A0[idx] + src[idx - X] * Ai[idx - X] + src[idx + X] * Ai[idx] +
+ src[idx - Y] * Aj[idx - Y] + src[idx + Y] * Aj[idx];
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return dst;
+ }
+ typedef Grid<Real> type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return src;
+ }
+ typedef Grid<Real> type2;
+ inline Grid<Real> &getArg3()
+ {
+ return A0;
+ }
+ typedef Grid<Real> type3;
+ inline Grid<Real> &getArg4()
+ {
+ return Ai;
+ }
+ typedef Grid<Real> type4;
+ inline Grid<Real> &getArg5()
+ {
+ return Aj;
+ }
+ typedef Grid<Real> type5;
+ inline Grid<Real> &getArg6()
+ {
+ return Ak;
+ }
+ typedef Grid<Real> type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel ApplyMatrix2D ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, flags, dst, src, A0, Ai, Aj, Ak);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &dst;
+ const Grid<Real> &src;
+ Grid<Real> &A0;
+ Grid<Real> &Ai;
+ Grid<Real> &Aj;
+ Grid<Real> &Ak;
+};
+
+//! Kernel: Construct the matrix for the poisson equation
+
+struct MakeLaplaceMatrix : public KernelBase {
+ MakeLaplaceMatrix(const FlagGrid &flags,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak,
+ const MACGrid *fractions = 0)
+ : KernelBase(&flags, 1), flags(flags), A0(A0), Ai(Ai), Aj(Aj), Ak(Ak), fractions(fractions)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak,
+ const MACGrid *fractions = 0) const
+ {
+ if (!flags.isFluid(i, j, k))
+ return;
+
+ if (!fractions) {
+ // diagonal, A0
+ if (!flags.isObstacle(i - 1, j, k))
+ A0(i, j, k) += 1.;
+ if (!flags.isObstacle(i + 1, j, k))
+ A0(i, j, k) += 1.;
+ if (!flags.isObstacle(i, j - 1, k))
+ A0(i, j, k) += 1.;
+ if (!flags.isObstacle(i, j + 1, k))
+ A0(i, j, k) += 1.;
+ if (flags.is3D() && !flags.isObstacle(i, j, k - 1))
+ A0(i, j, k) += 1.;
+ if (flags.is3D() && !flags.isObstacle(i, j, k + 1))
+ A0(i, j, k) += 1.;
+
+ // off-diagonal entries
+ if (flags.isFluid(i + 1, j, k))
+ Ai(i, j, k) = -1.;
+ if (flags.isFluid(i, j + 1, k))
+ Aj(i, j, k) = -1.;
+ if (flags.is3D() && flags.isFluid(i, j, k + 1))
+ Ak(i, j, k) = -1.;
+ }
+ else {
+ // diagonal
+ A0(i, j, k) += fractions->get(i, j, k).x;
+ A0(i, j, k) += fractions->get(i + 1, j, k).x;
+ A0(i, j, k) += fractions->get(i, j, k).y;
+ A0(i, j, k) += fractions->get(i, j + 1, k).y;
+ if (flags.is3D())
+ A0(i, j, k) += fractions->get(i, j, k).z;
+ if (flags.is3D())
+ A0(i, j, k) += fractions->get(i, j, k + 1).z;
+
+ // off-diagonal entries
+ if (flags.isFluid(i + 1, j, k))
+ Ai(i, j, k) = -fractions->get(i + 1, j, k).x;
+ if (flags.isFluid(i, j + 1, k))
+ Aj(i, j, k) = -fractions->get(i, j + 1, k).y;
+ if (flags.is3D() && flags.isFluid(i, j, k + 1))
+ Ak(i, j, k) = -fractions->get(i, j, k + 1).z;
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return A0;
+ }
+ typedef Grid<Real> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return Ai;
+ }
+ typedef Grid<Real> type2;
+ inline Grid<Real> &getArg3()
+ {
+ return Aj;
+ }
+ typedef Grid<Real> type3;
+ inline Grid<Real> &getArg4()
+ {
+ return Ak;
+ }
+ typedef Grid<Real> type4;
+ inline const MACGrid *getArg5()
+ {
+ return fractions;
+ }
+ typedef MACGrid type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel MakeLaplaceMatrix ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, A0, Ai, Aj, Ak, fractions);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, A0, Ai, Aj, Ak, fractions);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &A0;
+ Grid<Real> &Ai;
+ Grid<Real> &Aj;
+ Grid<Real> &Ak;
+ const MACGrid *fractions;
+};
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/conjugategrad.h.reg.cpp b/extern/mantaflow/preprocessed/conjugategrad.h.reg.cpp
new file mode 100644
index 00000000000..d152fe8f113
--- /dev/null
+++ b/extern/mantaflow/preprocessed/conjugategrad.h.reg.cpp
@@ -0,0 +1,13 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "conjugategrad.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_3()
+{
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/edgecollapse.cpp b/extern/mantaflow/preprocessed/edgecollapse.cpp
new file mode 100644
index 00000000000..72c76ca9200
--- /dev/null
+++ b/extern/mantaflow/preprocessed/edgecollapse.cpp
@@ -0,0 +1,700 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Mesh edge collapse and subdivision
+ *
+ ******************************************************************************/
+
+/******************************************************************************/
+// Copyright note:
+//
+// These functions (C) Chris Wojtan
+// Long-term goal is to unify with his split&merge codebase
+//
+/******************************************************************************/
+
+#include "edgecollapse.h"
+#include <queue>
+
+using namespace std;
+
+namespace Manta {
+
+// 8-point butterfly subdivision scheme (as described by Brochu&Bridson 2009)
+Vec3 ButterflySubdivision(Mesh &m, const Corner &ca, const Corner &cb)
+{
+ Vec3 p = m.nodes(m.corners(ca.prev).node).pos + m.nodes(m.corners(ca.next).node).pos;
+ Vec3 q = m.nodes(ca.node).pos + m.nodes(cb.node).pos;
+ Vec3 r = m.nodes(m.corners(m.corners(ca.next).opposite).node).pos +
+ m.nodes(m.corners(m.corners(ca.prev).opposite).node).pos +
+ m.nodes(m.corners(m.corners(cb.next).opposite).node).pos +
+ m.nodes(m.corners(m.corners(cb.prev).opposite).node).pos;
+ return (8 * p + 2 * q - r) / 16.0;
+}
+
+// Modified Butterfly Subdivision Scheme from:
+// Interpolating Subdivision for Meshes with Arbitrary Topology
+// Denis Zorin, Peter Schroder, and Wim Sweldens
+// input the Corner that satisfies the following:
+// c.prev.node is the extraordinary vertex,
+// and c.next.node is the other vertex involved in the subdivision
+Vec3 OneSidedButterflySubdivision(Mesh &m, const int valence, const Corner &c)
+{
+ Vec3 out;
+ Vec3 p0 = m.nodes(m.corners(c.prev).node).pos;
+ Vec3 p1 = m.nodes(m.corners(c.next).node).pos;
+
+ if (valence == 3) {
+ Vec3 p2 = m.nodes(c.node).pos;
+ Vec3 p3 = m.nodes(m.corners(m.corners(c.next).opposite).node).pos;
+ out = (5.0 / 12.0) * p1 - (1.0 / 12.0) * (p2 + p3) + 0.75 * p0;
+ }
+ else if (valence == 4) {
+ Vec3 p2 = m.nodes(m.corners(m.corners(c.next).opposite).node).pos;
+ out = 0.375 * p1 - 0.125 * p2 + 0.75 * p0;
+ }
+ else {
+ // rotate around extraordinary vertex,
+ // calculate subdivision weights,
+ // and interpolate vertex position
+ double rv = 1.0 / (double)valence;
+ out = 0.0;
+ int current = c.prev;
+ for (int j = 0; j < valence; j++) {
+ double s = (0.25 + cos(2 * M_PI * j * rv) + 0.5 * cos(4 * M_PI * j * rv)) * rv;
+ Vec3 p = m.nodes(m.corners(m.corners(current).prev).node).pos;
+
+ out += s * p;
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ }
+ out += 0.75 * m.nodes(m.corners(c.prev).node).pos;
+ }
+ return out;
+}
+
+// Modified Butterfly Subdivision Scheme from:
+// Interpolating Subdivision for Meshes with Arbitrary Topology
+// Denis Zorin, Peter Schroder, and Wim Sweldens
+Vec3 ModifiedButterflySubdivision(Mesh &m,
+ const Corner &ca,
+ const Corner &cb,
+ const Vec3 &fallback)
+{
+ // calculate the valence of the two parent vertices
+ int start = ca.prev;
+ int current = start;
+ int valenceA = 0;
+ do {
+ valenceA++;
+ int op = m.corners(m.corners(current).next).opposite;
+ if (op < 0)
+ return fallback;
+ current = m.corners(op).next;
+ } while (current != start);
+ start = ca.next;
+ current = start;
+ int valenceB = 0;
+ do {
+ valenceB++;
+ int op = m.corners(m.corners(current).next).opposite;
+ if (op < 0)
+ return fallback;
+ current = m.corners(op).next;
+ } while (current != start);
+
+ // if both vertices have valence 6, use butterfly subdivision
+ if (valenceA == 6 && valenceB == 6) {
+ return ButterflySubdivision(m, ca, cb);
+ }
+ else if (valenceA == 6) // use a one-sided scheme
+ {
+ return OneSidedButterflySubdivision(m, valenceB, cb);
+ }
+ else if (valenceB == 6) // use a one-sided scheme
+ {
+ return OneSidedButterflySubdivision(m, valenceA, ca);
+ }
+ else // average the results from two one-sided schemes
+ {
+ return 0.5 * (OneSidedButterflySubdivision(m, valenceA, ca) +
+ OneSidedButterflySubdivision(m, valenceB, cb));
+ }
+}
+
+bool gAbort = false;
+
+// collapse an edge on triangle "trinum".
+// "which" is 0,1, or 2,
+// where which==0 is the triangle edge from p0 to p1,
+// which==1 is the triangle edge from p1 to p2,
+// and which==2 is the triangle edge from p2 to p0,
+void CollapseEdge(Mesh &m,
+ const int trinum,
+ const int which,
+ const Vec3 &edgevect,
+ const Vec3 &endpoint,
+ vector<int> &deletedNodes,
+ std::map<int, bool> &taintedTris,
+ int &numCollapses,
+ bool doTubeCutting)
+{
+ if (gAbort)
+ return;
+ // I wanted to draw a pretty picture of an edge collapse,
+ // but I don't know how to make wacky angled lines in ASCII.
+ // Instead, I will show the before case and tell you what needs to be done.
+
+ // BEFORE:
+ // *
+ // / \.
+ // /C0 \.
+ // / \.
+ // / \.
+ // / B \.
+ // / \.
+ // /C1 C2 \.
+ // P0 *---------------* P1
+ // \C2 C1 /
+ // \ /
+ // \ A /
+ // \ /
+ // \ /
+ // \C0 /
+ // \ /
+ // *
+ //
+ // We are going to collapse the edge between P0 and P1
+ // by deleting P1,
+ // and taking all references to P1,
+ // and rerouting them to P0 instead
+ //
+ // What we need to do:
+ // Move position of P0
+ // Preserve connectivity in both triangles:
+ // (C1.opposite).opposite = C2.o
+ // (C2.opposite).opposite = C1.o
+ // Delete references to Corners of deleted triangles in both P0 and P1's Corner list
+ // Reassign references to P1:
+ // loop through P1 triangles:
+ // rename P1 references to P0 in p lists.
+ // rename Corner.v references
+ // Copy P1's list of Corners over to P0's list of Corners
+ // Delete P1
+
+ Corner ca_old[3], cb_old[3];
+ ca_old[0] = m.corners(trinum, which);
+ ca_old[1] = m.corners(ca_old[0].next);
+ ca_old[2] = m.corners(ca_old[0].prev);
+ bool haveB = false;
+ if (ca_old[0].opposite >= 0) {
+ cb_old[0] = m.corners(ca_old[0].opposite);
+ cb_old[1] = m.corners(cb_old[0].next);
+ cb_old[2] = m.corners(cb_old[0].prev);
+ haveB = true;
+ }
+ if (!haveB) {
+ // for now, don't collapse
+ return;
+ }
+
+ int P0 = ca_old[2].node;
+ int P1 = ca_old[1].node;
+
+ ///////////////
+ // avoid creating nonmanifold edges
+ bool nonmanifold = false;
+ bool nonmanifold2 = false;
+
+ set<int> &ring0 = m.get1Ring(P0).nodes;
+ set<int> &ring1 = m.get1Ring(P1).nodes;
+
+ // check for intersections of the 1-rings of P0,P1
+ int cl = 0, commonVert = -1;
+ for (set<int>::iterator it = ring1.begin(); it != ring1.end(); ++it)
+ if (ring0.find(*it) != ring0.end()) {
+ cl++;
+ if (*it != ca_old[0].node && *it != cb_old[0].node)
+ commonVert = *it;
+ }
+
+ nonmanifold = cl > 2;
+ nonmanifold2 = cl > 3;
+
+ if (nonmanifold && ca_old[1].opposite >= 0 && cb_old[1].opposite >= 0 &&
+ ca_old[2].opposite >= 0 &&
+ cb_old[2].opposite >= 0) // collapsing this edge would create a non-manifold edge
+ {
+ if (nonmanifold2)
+ return;
+
+ bool topTet = false;
+ bool botTet = false;
+ // check if collapsing this edge will collapse a tet.
+ if (m.corners(ca_old[1].opposite).node == m.corners(ca_old[2].opposite).node)
+ botTet = true;
+
+ if (m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node)
+ topTet = true;
+
+ if (topTet ^ botTet) {
+
+ // safe pyramid case.
+ // collapse the whole tet!
+ // First collapse the top of the pyramid,
+ // then carry on collapsing the original verts.
+ Corner cc_old[3], cd_old[3];
+ if (botTet)
+ cc_old[0] = m.corners(ca_old[1].opposite);
+ else // topTet
+ cc_old[0] = cb_old[2];
+ cc_old[1] = m.corners(cc_old[0].next);
+ cc_old[2] = m.corners(cc_old[0].prev);
+ if (cc_old[0].opposite < 0)
+ return;
+ cd_old[0] = m.corners(cc_old[0].opposite);
+ cd_old[1] = m.corners(cd_old[0].next);
+ cd_old[2] = m.corners(cd_old[0].prev);
+ int P2 = cc_old[2].node;
+ int P3 = cc_old[1].node;
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ for (int i = 0; i < m.numTriChannels(); i++) {
+ }; // TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]);
+
+ m.mergeNode(P2, P3);
+
+ // Preserve connectivity in both triangles
+ if (cc_old[1].opposite >= 0)
+ m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite;
+ if (cc_old[2].opposite >= 0)
+ m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite;
+ if (cd_old[1].opposite >= 0)
+ m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite;
+ if (cd_old[2].opposite >= 0)
+ m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ int tmpTrinum = cc_old[0].tri;
+ int tmpOthertri = cd_old[0].tri;
+ m.removeTriFromLookup(tmpTrinum);
+ m.removeTriFromLookup(tmpOthertri);
+ taintedTris[tmpTrinum] = true;
+ taintedTris[tmpOthertri] = true;
+ deletedNodes.push_back(P3);
+
+ numCollapses++;
+
+ // recompute Corners for triangles A and B
+ if (botTet)
+ ca_old[0] = m.corners(ca_old[2].opposite);
+ else
+ ca_old[0] = m.corners(ca_old[1].prev);
+ ca_old[1] = m.corners(ca_old[0].next);
+ ca_old[2] = m.corners(ca_old[0].prev);
+ cb_old[0] = m.corners(ca_old[0].opposite);
+ cb_old[1] = m.corners(cb_old[0].next);
+ cb_old[2] = m.corners(cb_old[0].prev);
+
+ ///////////////
+ // avoid creating nonmanifold edges... again
+ ring0 = m.get1Ring(ca_old[2].node).nodes;
+ ring1 = m.get1Ring(ca_old[1].node).nodes;
+
+ // check for intersections of the 1-rings of P0,P1
+ cl = 0;
+ for (set<int>::iterator it = ring1.begin(); it != ring1.end(); ++it)
+ if (*it != ca_old[0].node && ring0.find(*it) != ring0.end())
+ cl++;
+
+ if (cl > 2) { // nonmanifold
+ // this can happen if collapsing the first tet leads to another similar collapse that
+ // requires the collapse of a tet. for now, just move on and pick this up later.
+
+ // if the original component was very small, this first collapse could have led to a tiny
+ // piece of nonmanifold geometry. in this case, just delete everything that remains.
+ if (m.corners(ca_old[0].opposite).tri == cb_old[0].tri &&
+ m.corners(ca_old[1].opposite).tri == cb_old[0].tri &&
+ m.corners(ca_old[2].opposite).tri == cb_old[0].tri) {
+ taintedTris[ca_old[0].tri] = true;
+ taintedTris[cb_old[0].tri] = true;
+ m.removeTriFromLookup(ca_old[0].tri);
+ m.removeTriFromLookup(cb_old[0].tri);
+ deletedNodes.push_back(ca_old[0].node);
+ deletedNodes.push_back(ca_old[1].node);
+ deletedNodes.push_back(ca_old[2].node);
+ }
+ return;
+ }
+ }
+ else if (topTet && botTet && ca_old[1].opposite >= 0 && ca_old[2].opposite >= 0 &&
+ cb_old[1].opposite >= 0 && cb_old[2].opposite >= 0) {
+ if (!(m.corners(ca_old[1].opposite).node == m.corners(ca_old[2].opposite).node &&
+ m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node &&
+ (m.corners(ca_old[1].opposite).node == m.corners(cb_old[1].opposite).node ||
+ (m.corners(ca_old[1].opposite).node == cb_old[0].node &&
+ m.corners(cb_old[1].opposite).node == ca_old[0].node)))) {
+ // just collapse one for now.
+
+ // collapse the whole tet!
+ // First collapse the top of the pyramid,
+ // then carry on collapsing the original verts.
+ Corner cc_old[3], cd_old[3];
+
+ // collapse top
+ {
+ cc_old[0] = m.corners(ca_old[1].opposite);
+ cc_old[1] = m.corners(cc_old[0].next);
+ cc_old[2] = m.corners(cc_old[0].prev);
+ if (cc_old[0].opposite < 0)
+ return;
+ cd_old[0] = m.corners(cc_old[0].opposite);
+ cd_old[1] = m.corners(cd_old[0].next);
+ cd_old[2] = m.corners(cd_old[0].prev);
+ int P2 = cc_old[2].node;
+ int P3 = cc_old[1].node;
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ // TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]);
+
+ m.mergeNode(P2, P3);
+
+ // Preserve connectivity in both triangles
+ if (cc_old[1].opposite >= 0)
+ m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite;
+ if (cc_old[2].opposite >= 0)
+ m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite;
+ if (cd_old[1].opposite >= 0)
+ m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite;
+ if (cd_old[2].opposite >= 0)
+ m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ int tmpTrinum = cc_old[0].tri;
+ int tmpOthertri = cd_old[0].tri;
+ taintedTris[tmpTrinum] = true;
+ taintedTris[tmpOthertri] = true;
+ m.removeTriFromLookup(tmpTrinum);
+ m.removeTriFromLookup(tmpOthertri);
+ deletedNodes.push_back(P3);
+
+ numCollapses++;
+ }
+ // then collapse bottom
+ {
+ // cc_old[0] = [ca_old[1].opposite;
+ cc_old[0] = cb_old[2];
+ cc_old[1] = m.corners(cc_old[0].next);
+ cc_old[2] = m.corners(cc_old[0].prev);
+ if (cc_old[0].opposite < 0)
+ return;
+ cd_old[0] = m.corners(cc_old[0].opposite);
+ cd_old[1] = m.corners(cd_old[0].next);
+ cd_old[2] = m.corners(cd_old[0].prev);
+ int P2 = cc_old[2].node;
+ int P3 = cc_old[1].node;
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ // TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]);
+
+ m.mergeNode(P2, P3);
+
+ // Preserve connectivity in both triangles
+ if (cc_old[1].opposite >= 0)
+ m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite;
+ if (cc_old[2].opposite >= 0)
+ m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite;
+ if (cd_old[1].opposite >= 0)
+ m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite;
+ if (cd_old[2].opposite >= 0)
+ m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ int tmpTrinum = cc_old[0].tri;
+ int tmpOthertri = cd_old[0].tri;
+ taintedTris[tmpTrinum] = true;
+ taintedTris[tmpOthertri] = true;
+ deletedNodes.push_back(P3);
+
+ numCollapses++;
+ }
+
+ // Though we've collapsed a lot of stuff, we still haven't collapsed the original edge.
+ // At this point we still haven't guaranteed that this original collapse weill be safe.
+ // quit for now, and we'll catch the remaining short edges the next time this function is
+ // called.
+ return;
+ }
+ }
+ else if (doTubeCutting) {
+ // tube case
+ // cout<<"CollapseEdge:tube case" << endl;
+
+ // find the edges that touch the common vert
+ int P2 = commonVert;
+ int P1P2 = -1, P2P1, P2P0 = -1, P0P2 = -1; // corners across from the cutting seam
+ int start = ca_old[0].next;
+ int end = cb_old[0].prev;
+ int current = start;
+ do {
+ // rotate around vertex P1 counter-clockwise
+ int op = m.corners(m.corners(current).next).opposite;
+ if (op < 0)
+ errMsg("tube cutting failed, no opposite");
+ current = m.corners(op).next;
+
+ if (m.corners(m.corners(current).prev).node == commonVert)
+ P1P2 = m.corners(current).next;
+ } while (current != end);
+
+ start = ca_old[0].prev;
+ end = cb_old[0].next;
+ current = start;
+ do {
+ // rotate around vertex P0 clockwise
+ int op = m.corners(m.corners(current).prev).opposite;
+ if (op < 0)
+ errMsg("tube cutting failed, no opposite");
+
+ current = m.corners(op).prev;
+ if (m.corners(m.corners(current).next).node == commonVert)
+ P2P0 = m.corners(current).prev;
+ } while (current != end);
+
+ if (P1P2 < 0 || P2P0 < 0)
+ errMsg("tube cutting failed, ill geometry");
+
+ P2P1 = m.corners(P1P2).opposite;
+ P0P2 = m.corners(P2P0).opposite;
+
+ // duplicate vertices on the top half of the cut,
+ // and use them to split the tube at this seam
+ int P0b = m.addNode(Node(m.nodes(P0).pos));
+ int P1b = m.addNode(Node(m.nodes(P1).pos));
+ int P2b = m.addNode(Node(m.nodes(P2).pos));
+ for (int i = 0; i < m.numNodeChannels(); i++) {
+ m.nodeChannel(i)->addInterpol(P0, P0, 0.5);
+ m.nodeChannel(i)->addInterpol(P1, P1, 0.5);
+ m.nodeChannel(i)->addInterpol(P2, P2, 0.5);
+ }
+
+ // offset the verts in the normal directions to avoid self intersections
+ Vec3 offsetVec = cross(m.nodes(P1).pos - m.nodes(P0).pos, m.nodes(P2).pos - m.nodes(P0).pos);
+ normalize(offsetVec);
+ offsetVec *= 0.01; // HACK:
+ m.nodes(P0).pos -= offsetVec;
+ m.nodes(P1).pos -= offsetVec;
+ m.nodes(P2).pos -= offsetVec;
+ m.nodes(P0b).pos += offsetVec;
+ m.nodes(P1b).pos += offsetVec;
+ m.nodes(P2b).pos += offsetVec;
+
+ // create a list of all triangles which touch P0, P1, and P2 from the top,
+ map<int, bool> topTris;
+ start = cb_old[0].next;
+ end = m.corners(P0P2).prev;
+ current = start;
+ topTris[start / 3] = true;
+ do {
+ // rotate around vertex P0 counter-clockwise
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ topTris[current / 3] = true;
+ } while (current != end);
+ start = m.corners(P0P2).next;
+ end = m.corners(P2P1).prev;
+ current = start;
+ topTris[start / 3] = true;
+ do {
+ // rotate around vertex P0 counter-clockwise
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ topTris[current / 3] = true;
+ } while (current != end);
+ start = m.corners(P2P1).next;
+ end = cb_old[0].prev;
+ current = start;
+ topTris[start / 3] = true;
+ do {
+ // rotate around vertex P0 counter-clockwise
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ topTris[current / 3] = true;
+ } while (current != end);
+
+ // create two new triangles,
+ int Ta = m.addTri(Triangle(P0, P1, P2));
+ int Tb = m.addTri(Triangle(P1b, P0b, P2b));
+ for (int i = 0; i < m.numTriChannels(); i++) {
+ m.triChannel(i)->addNew();
+ m.triChannel(i)->addNew();
+ }
+
+ // sew the tris to close the cut on each side
+ for (int c = 0; c < 3; c++)
+ m.addCorner(Corner(Ta, m.tris(Ta).c[c]));
+ for (int c = 0; c < 3; c++)
+ m.addCorner(Corner(Tb, m.tris(Tb).c[c]));
+ for (int c = 0; c < 3; c++) {
+ m.corners(Ta, c).next = 3 * Ta + ((c + 1) % 3);
+ m.corners(Ta, c).prev = 3 * Ta + ((c + 2) % 3);
+ m.corners(Tb, c).next = 3 * Tb + ((c + 1) % 3);
+ m.corners(Tb, c).prev = 3 * Tb + ((c + 2) % 3);
+ }
+ m.corners(Ta, 0).opposite = P1P2;
+ m.corners(Ta, 1).opposite = P2P0;
+ m.corners(Ta, 2).opposite = ca_old[1].prev;
+ m.corners(Tb, 0).opposite = P0P2;
+ m.corners(Tb, 1).opposite = P2P1;
+ m.corners(Tb, 2).opposite = cb_old[1].prev;
+ for (int c = 0; c < 3; c++) {
+ m.corners(m.corners(Ta, c).opposite).opposite = 3 * Ta + c;
+ m.corners(m.corners(Tb, c).opposite).opposite = 3 * Tb + c;
+ }
+ // replace P0,P1,P2 on the top with P0b,P1b,P2b.
+ for (map<int, bool>::iterator tti = topTris.begin(); tti != topTris.end(); tti++) {
+ // cout << "H " << tti->first << " : " << m.tris(tti->first).c[0] << " " <<
+ // m.tris(tti->first).c[1] << " " << m.tris(tti->first).c[2] << " " << endl;
+ for (int i = 0; i < 3; i++) {
+ int cn = m.tris(tti->first).c[i];
+ set<int> &ring = m.get1Ring(cn).nodes;
+
+ if (ring.find(P0) != ring.end() && cn != P0 && cn != P1 && cn != P2 && cn != P0b &&
+ cn != P1b && cn != P2b) {
+ ring.erase(P0);
+ ring.insert(P0b);
+ m.get1Ring(P0).nodes.erase(cn);
+ m.get1Ring(P0b).nodes.insert(cn);
+ }
+ if (ring.find(P1) != ring.end() && cn != P0 && cn != P1 && cn != P2 && cn != P0b &&
+ cn != P1b && cn != P2b) {
+ ring.erase(P1);
+ ring.insert(P1b);
+ m.get1Ring(P1).nodes.erase(cn);
+ m.get1Ring(P1b).nodes.insert(cn);
+ }
+ if (ring.find(P2) != ring.end() && cn != P0 && cn != P1 && cn != P2 && cn != P0b &&
+ cn != P1b && cn != P2b) {
+ ring.erase(P2);
+ ring.insert(P2b);
+ m.get1Ring(P2).nodes.erase(cn);
+ m.get1Ring(P2b).nodes.insert(cn);
+ }
+ if (cn == P0) {
+ m.tris(tti->first).c[i] = P0b;
+ m.corners(tti->first, i).node = P0b;
+ m.get1Ring(P0).tris.erase(tti->first);
+ m.get1Ring(P0b).tris.insert(tti->first);
+ }
+ else if (cn == P1) {
+ m.tris(tti->first).c[i] = P1b;
+ m.corners(tti->first, i).node = P1b;
+ m.get1Ring(P1).tris.erase(tti->first);
+ m.get1Ring(P1b).tris.insert(tti->first);
+ }
+ else if (cn == P2) {
+ m.tris(tti->first).c[i] = P2b;
+ m.corners(tti->first, i).node = P2b;
+ m.get1Ring(P2).tris.erase(tti->first);
+ m.get1Ring(P2b).tris.insert(tti->first);
+ }
+ }
+ }
+
+ // m.sanityCheck(true, &deletedNodes, &taintedTris);
+
+ return;
+ }
+ return;
+ }
+ if (ca_old[1].opposite >= 0 && ca_old[2].opposite >= 0 && cb_old[1].opposite >= 0 &&
+ cb_old[2].opposite >= 0 && ca_old[0].opposite >= 0 && cb_old[0].opposite >= 0 &&
+ ((m.corners(ca_old[1].opposite).node ==
+ m.corners(ca_old[2].opposite).node && // two-pyramid tubey case (6 tris, 5 verts)
+ m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node &&
+ (m.corners(ca_old[1].opposite).node == m.corners(cb_old[1].opposite).node ||
+ (m.corners(ca_old[1].opposite).node == cb_old[0].node && // single tetrahedron case
+ m.corners(cb_old[1].opposite).node == ca_old[0].node))) ||
+ (m.corners(ca_old[0].opposite).tri == m.corners(cb_old[0].opposite).tri &&
+ m.corners(ca_old[1].opposite).tri == m.corners(cb_old[0].opposite).tri &&
+ m.corners(ca_old[2].opposite).tri ==
+ m.corners(cb_old[0].opposite).tri // nonmanifold: 2 tris, 3 verts
+ && m.corners(cb_old[0].opposite).tri == m.corners(ca_old[0].opposite).tri &&
+ m.corners(cb_old[1].opposite).tri == m.corners(ca_old[0].opposite).tri &&
+ m.corners(cb_old[2].opposite).tri == m.corners(ca_old[0].opposite).tri))) {
+ // both top and bottom are closed pyramid caps, or it is a single tet
+ // delete the whole component!
+ // flood fill to mark all triangles in the component
+ map<int, bool> markedTris;
+ queue<int> triQ;
+ triQ.push(trinum);
+ markedTris[trinum] = true;
+ int iters = 0;
+ while (!triQ.empty()) {
+ int trival = triQ.front();
+ triQ.pop();
+ for (int i = 0; i < 3; i++) {
+ int newtri = m.corners(m.corners(trival, i).opposite).tri;
+ if (markedTris.find(newtri) == markedTris.end()) {
+ triQ.push(newtri);
+ markedTris[newtri] = true;
+ }
+ }
+ iters++;
+ }
+ map<int, bool> markedverts;
+ for (map<int, bool>::iterator mit = markedTris.begin(); mit != markedTris.end(); mit++) {
+ taintedTris[mit->first] = true;
+ markedverts[m.tris(mit->first).c[0]] = true;
+ markedverts[m.tris(mit->first).c[1]] = true;
+ markedverts[m.tris(mit->first).c[2]] = true;
+ }
+ for (map<int, bool>::iterator mit = markedverts.begin(); mit != markedverts.end(); mit++)
+ deletedNodes.push_back(mit->first);
+ return;
+ }
+
+ //////////////////////////
+ // begin original edge collapse
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ // TODO: handleTriPropertyEdgeCollapse(trinum, P0,P1, ca_old[0], cb_old[0]);
+
+ m.mergeNode(P0, P1);
+
+ // Move position of P0
+ m.nodes(P0).pos = endpoint + 0.5 * edgevect;
+
+ // Preserve connectivity in both triangles
+ if (ca_old[1].opposite >= 0)
+ m.corners(ca_old[1].opposite).opposite = ca_old[2].opposite;
+ if (ca_old[2].opposite >= 0)
+ m.corners(ca_old[2].opposite).opposite = ca_old[1].opposite;
+ if (haveB && cb_old[1].opposite >= 0)
+ m.corners(cb_old[1].opposite).opposite = cb_old[2].opposite;
+ if (haveB && cb_old[2].opposite >= 0)
+ m.corners(cb_old[2].opposite).opposite = cb_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ taintedTris[ca_old[0].tri] = true;
+ m.removeTriFromLookup(ca_old[0].tri);
+ if (haveB) {
+ taintedTris[cb_old[0].tri] = true;
+ m.removeTriFromLookup(cb_old[0].tri);
+ }
+ deletedNodes.push_back(P1);
+ numCollapses++;
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/edgecollapse.h b/extern/mantaflow/preprocessed/edgecollapse.h
new file mode 100644
index 00000000000..c482255c6ce
--- /dev/null
+++ b/extern/mantaflow/preprocessed/edgecollapse.h
@@ -0,0 +1,51 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Mesh edge collapse and subdivision
+ *
+ ******************************************************************************/
+
+/******************************************************************************/
+// Copyright note:
+//
+// These functions (C) Chris Wojtan
+// Long-term goal is to unify with his split&merge codebase
+//
+/******************************************************************************/
+
+#ifndef _EDGECOLLAPSE_H
+#define _EDGECOLLAPSE_H
+
+#include "mesh.h"
+
+namespace Manta {
+
+void CollapseEdge(Mesh &mesh,
+ const int trinum,
+ const int which,
+ const Vec3 &edgevect,
+ const Vec3 &endpoint,
+ std::vector<int> &deletedNodes,
+ std::map<int, bool> &taintedTris,
+ int &numCollapses,
+ bool doTubeCutting);
+
+Vec3 ModifiedButterflySubdivision(Mesh &mesh,
+ const Corner &ca,
+ const Corner &cb,
+ const Vec3 &fallback);
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/edgecollapse.h.reg.cpp b/extern/mantaflow/preprocessed/edgecollapse.h.reg.cpp
new file mode 100644
index 00000000000..002756b3a9c
--- /dev/null
+++ b/extern/mantaflow/preprocessed/edgecollapse.h.reg.cpp
@@ -0,0 +1,13 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "edgecollapse.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_19()
+{
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/fastmarch.cpp b/extern/mantaflow/preprocessed/fastmarch.cpp
new file mode 100644
index 00000000000..7792ddafe6a
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fastmarch.cpp
@@ -0,0 +1,1200 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Fast marching and extrapolation
+ *
+ ******************************************************************************/
+
+#include "fastmarch.h"
+#include "levelset.h"
+#include "kernel.h"
+#include <algorithm>
+
+using namespace std;
+
+namespace Manta {
+
+template<class COMP, int TDIR>
+FastMarch<COMP, TDIR>::FastMarch(const FlagGrid &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &levelset,
+ Real maxTime,
+ MACGrid *velTransport)
+ : mLevelset(levelset), mFlags(flags), mFmFlags(fmFlags)
+{
+ if (velTransport)
+ mVelTransport.initMarching(velTransport, &flags);
+
+ mMaxTime = maxTime * TDIR;
+}
+
+// helper for individual components to calculateDistance
+template<class COMP, int TDIR>
+template<int C>
+Real FastMarch<COMP, TDIR>::calcWeights(int &okcnt, int &invcnt, Real *v, const Vec3i &idx)
+{
+ Real val = 0.;
+ Vec3i idxPlus(idx), idxMinus(idx);
+ idxPlus[C]++;
+ idxMinus[C]--;
+
+ mWeights[C * 2] = mWeights[C * 2 + 1] = 0.;
+ if (mFmFlags(idxPlus) == FlagInited) {
+ // somewhat arbitrary - choose +1 value over -1 ...
+ val = mLevelset(idxPlus);
+ v[okcnt] = val;
+ okcnt++;
+ mWeights[C * 2] = 1.;
+ }
+ else if (mFmFlags(idxMinus) == FlagInited) {
+ val = mLevelset(idxMinus);
+ v[okcnt] = val;
+ okcnt++;
+ mWeights[C * 2 + 1] = 1.;
+ }
+ else {
+ invcnt++;
+ }
+ return val;
+}
+
+template<class COMP, int TDIR>
+inline Real FastMarch<COMP, TDIR>::calculateDistance(const Vec3i &idx)
+{
+ // int invflag = 0;
+ int invcnt = 0;
+ Real v[3];
+ int okcnt = 0;
+
+ Real aVal = calcWeights<0>(okcnt, invcnt, v, idx);
+ Real bVal = calcWeights<1>(okcnt, invcnt, v, idx);
+ Real cVal = 0.;
+ if (mLevelset.is3D())
+ cVal = calcWeights<2>(okcnt, invcnt, v, idx);
+ else {
+ invcnt++;
+ mWeights[4] = mWeights[5] = 0.;
+ }
+
+ Real ret = InvalidTime();
+ switch (invcnt) {
+ case 0: {
+ // take all values
+ const Real ca = v[0], cb = v[1], cc = v[2];
+ const Real csqrt = max(0.,
+ -2. * (ca * ca + cb * cb - cb * cc + cc * cc - ca * (cb + cc)) + 3);
+ // clamp to make sure the sqrt is valid
+ ret = 0.333333 * (ca + cb + cc + TDIR * sqrt(csqrt));
+
+ // weights needed for transport (transpTouch)
+ mWeights[0] *= fabs(ret - ca);
+ mWeights[1] *= fabs(ret - ca);
+ mWeights[2] *= fabs(ret - cb);
+ mWeights[3] *= fabs(ret - cb);
+ mWeights[4] *= fabs(ret - cc);
+ mWeights[5] *= fabs(ret - cc);
+
+ Real norm = 0.0; // try to force normalization
+ for (int i = 0; i < 6; i++) {
+ norm += mWeights[i];
+ }
+ norm = 1.0 / norm;
+ for (int i = 0; i < 6; i++) {
+ mWeights[i] *= norm;
+ }
+
+ } break;
+ case 1: {
+ // take just the 2 ok values
+ // t=0.5*( a+b+ (2*g*g-(b-a)*(b-a))^0.5)
+ const Real csqrt = max(0., 2. - (v[1] - v[0]) * (v[1] - v[0]));
+ // clamp to make sure the sqrt is valid
+ ret = 0.5 * (v[0] + v[1] + TDIR * sqrt(csqrt));
+
+ // weights needed for transport (transpTouch)
+ mWeights[0] *= fabs(ret - aVal);
+ mWeights[1] *= fabs(ret - aVal);
+ mWeights[2] *= fabs(ret - bVal);
+ mWeights[3] *= fabs(ret - bVal);
+ mWeights[4] *= fabs(ret - cVal);
+ mWeights[5] *= fabs(ret - cVal);
+
+ Real norm = 0.0; // try to force normalization
+ for (int i = 0; i < 6; i++) {
+ norm += mWeights[i];
+ }
+ norm = 1.0 / norm;
+ for (int i = 0; i < 6; i++) {
+ mWeights[i] *= norm;
+ }
+ // */
+
+ } break;
+ case 2: {
+ // just use the one remaining value
+ ret = v[0] + (Real)(TDIR); // direction = +- 1
+ } break;
+ default:
+ errMsg("FastMarch :: Invalid invcnt");
+ break;
+ }
+ return ret;
+}
+
+template<class COMP, int TDIR>
+void FastMarch<COMP, TDIR>::addToList(const Vec3i &p, const Vec3i &src)
+{
+ if (!mLevelset.isInBounds(p, 1))
+ return;
+ const IndexInt idx = mLevelset.index(p);
+
+ // already known value, value alreay set to valid value? skip cell...
+ if (mFmFlags[idx] == FlagInited)
+ return;
+
+ // discard by source time now , TODO do instead before calling all addtolists?
+ Real srct = mLevelset(src);
+ if (COMP::compare(srct, mMaxTime))
+ return;
+
+ Real ttime = calculateDistance(p);
+
+ // remove old entry if larger
+ bool found = false;
+
+ Real oldt = mLevelset[idx];
+ if (mFmFlags[idx] == FlagIsOnHeap) {
+ found = true;
+ // is old time better?
+ if (COMP::compare(ttime, oldt))
+ return;
+ }
+
+ // update field
+ mFmFlags[idx] = FlagIsOnHeap;
+ mLevelset[idx] = ttime;
+ // debug info std::cout<<"set "<< idx <<","<< ttime <<"\n";
+
+ if (mVelTransport.isInitialized())
+ mVelTransport.transpTouch(p.x, p.y, p.z, mWeights, ttime);
+
+ // the following adds entries to the heap of active cells
+ // current: (!found) , previous: always add, might lead to duplicate
+ // entries, but the earlier will be handled earlier, the second one will skip to the
+ // FlagInited check above
+ if (!found) {
+ // add list entry with source value
+ COMP entry;
+ entry.p = p;
+ entry.time = mLevelset[idx];
+
+ mHeap.push(entry);
+ // debug info std::cout<<"push "<< entry.p <<","<< entry.time <<"\n";
+ }
+}
+
+//! Enforce delta_phi = 0 on boundaries
+
+struct SetLevelsetBoundaries : public KernelBase {
+ SetLevelsetBoundaries(Grid<Real> &phi) : KernelBase(&phi, 0), phi(phi)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Real> &phi)
+ {
+ if (i == 0)
+ phi(i, j, k) = phi(1, j, k);
+ if (i == maxX - 1)
+ phi(i, j, k) = phi(i - 1, j, k);
+
+ if (j == 0)
+ phi(i, j, k) = phi(i, 1, k);
+ if (j == maxY - 1)
+ phi(i, j, k) = phi(i, j - 1, k);
+
+ if (phi.is3D()) {
+ if (k == 0)
+ phi(i, j, k) = phi(i, j, 1);
+ if (k == maxZ - 1)
+ phi(i, j, k) = phi(i, j, k - 1);
+ }
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel SetLevelsetBoundaries ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void run()
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ for (int k = minZ; k < maxZ; k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, phi);
+ }
+ Grid<Real> &phi;
+};
+
+/*****************************************************************************/
+//! Walk...
+template<class COMP, int TDIR> void FastMarch<COMP, TDIR>::performMarching()
+{
+ mReheapVal = 0.0;
+ while (mHeap.size() > 0) {
+
+ const COMP &ce = mHeap.top();
+ Vec3i p = ce.p;
+ mFmFlags(p) = FlagInited;
+ mHeap.pop();
+ // debug info std::cout<<"pop "<< ce.p <<","<< ce.time <<"\n";
+
+ addToList(Vec3i(p.x - 1, p.y, p.z), p);
+ addToList(Vec3i(p.x + 1, p.y, p.z), p);
+ addToList(Vec3i(p.x, p.y - 1, p.z), p);
+ addToList(Vec3i(p.x, p.y + 1, p.z), p);
+ if (mLevelset.is3D()) {
+ addToList(Vec3i(p.x, p.y, p.z - 1), p);
+ addToList(Vec3i(p.x, p.y, p.z + 1), p);
+ }
+ }
+
+ // set boundary for plain array
+ SetLevelsetBoundaries setls(mLevelset);
+ setls.getArg0(); // get rid of compiler warning...
+}
+
+// explicit instantiation
+template class FastMarch<FmHeapEntryIn, -1>;
+template class FastMarch<FmHeapEntryOut, +1>;
+
+/*****************************************************************************/
+// simpler extrapolation functions (primarily for FLIP)
+
+struct knExtrapolateMACSimple : public KernelBase {
+ knExtrapolateMACSimple(MACGrid &vel, int distance, Grid<int> &tmp, const int d, const int c)
+ : KernelBase(&vel, 1), vel(vel), distance(distance), tmp(tmp), d(d), c(c)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ MACGrid &vel,
+ int distance,
+ Grid<int> &tmp,
+ const int d,
+ const int c) const
+ {
+ static const Vec3i nb[6] = {Vec3i(1, 0, 0),
+ Vec3i(-1, 0, 0),
+ Vec3i(0, 1, 0),
+ Vec3i(0, -1, 0),
+ Vec3i(0, 0, 1),
+ Vec3i(0, 0, -1)};
+ const int dim = (vel.is3D() ? 3 : 2);
+
+ if (tmp(i, j, k) != 0)
+ return;
+
+ // copy from initialized neighbors
+ Vec3i p(i, j, k);
+ int nbs = 0;
+ Real avgVel = 0.;
+ for (int n = 0; n < 2 * dim; ++n) {
+ if (tmp(p + nb[n]) == d) {
+ // vel(p)[c] = (c+1.)*0.1;
+ avgVel += vel(p + nb[n])[c];
+ nbs++;
+ }
+ }
+
+ if (nbs > 0) {
+ tmp(p) = d + 1;
+ vel(p)[c] = avgVel / nbs;
+ }
+ }
+ inline MACGrid &getArg0()
+ {
+ return vel;
+ }
+ typedef MACGrid type0;
+ inline int &getArg1()
+ {
+ return distance;
+ }
+ typedef int type1;
+ inline Grid<int> &getArg2()
+ {
+ return tmp;
+ }
+ typedef Grid<int> type2;
+ inline const int &getArg3()
+ {
+ return d;
+ }
+ typedef int type3;
+ inline const int &getArg4()
+ {
+ return c;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knExtrapolateMACSimple ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, distance, tmp, d, c);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, distance, tmp, d, c);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ MACGrid &vel;
+ int distance;
+ Grid<int> &tmp;
+ const int d;
+ const int c;
+};
+//! copy velocity into domain side, note - don't read & write same grid, hence velTmp copy
+
+struct knExtrapolateIntoBnd : public KernelBase {
+ knExtrapolateIntoBnd(FlagGrid &flags, MACGrid &vel, const MACGrid &velTmp)
+ : KernelBase(&flags, 0), flags(flags), vel(vel), velTmp(velTmp)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, FlagGrid &flags, MACGrid &vel, const MACGrid &velTmp) const
+ {
+ int c = 0;
+ Vec3 v(0, 0, 0);
+ const bool isObs = flags.isObstacle(i, j, k);
+ if (i == 0) {
+ v = velTmp(i + 1, j, k);
+ if (isObs && v[0] < 0.)
+ v[0] = 0.;
+ c++;
+ }
+ else if (i == (flags.getSizeX() - 1)) {
+ v = velTmp(i - 1, j, k);
+ if (isObs && v[0] > 0.)
+ v[0] = 0.;
+ c++;
+ }
+ if (j == 0) {
+ v = velTmp(i, j + 1, k);
+ if (isObs && v[1] < 0.)
+ v[1] = 0.;
+ c++;
+ }
+ else if (j == (flags.getSizeY() - 1)) {
+ v = velTmp(i, j - 1, k);
+ if (isObs && v[1] > 0.)
+ v[1] = 0.;
+ c++;
+ }
+ if (flags.is3D()) {
+ if (k == 0) {
+ v = velTmp(i, j, k + 1);
+ if (isObs && v[2] < 0.)
+ v[2] = 0.;
+ c++;
+ }
+ else if (k == (flags.getSizeZ() - 1)) {
+ v = velTmp(i, j, k - 1);
+ if (isObs && v[2] > 0.)
+ v[2] = 0.;
+ c++;
+ }
+ }
+ if (c > 0) {
+ vel(i, j, k) = v / (Real)c;
+ }
+ }
+ inline FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return velTmp;
+ }
+ typedef MACGrid type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knExtrapolateIntoBnd ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, vel, velTmp);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, vel, velTmp);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ FlagGrid &flags;
+ MACGrid &vel;
+ const MACGrid &velTmp;
+};
+
+// todo - use getGradient instead?
+inline Vec3 getNormal(const Grid<Real> &data, int i, int j, int k)
+{
+ if (i > data.getSizeX() - 2)
+ i = data.getSizeX() - 2;
+ if (i < 1)
+ i = 1;
+ if (j > data.getSizeY() - 2)
+ j = data.getSizeY() - 2;
+ if (j < 1)
+ j = 1;
+
+ int kd = 1;
+ if (data.is3D()) {
+ if (k > data.getSizeZ() - 2)
+ k = data.getSizeZ() - 2;
+ if (k < 1)
+ k = 1;
+ }
+ else {
+ kd = 0;
+ }
+
+ return Vec3(data(i + 1, j, k) - data(i - 1, j, k),
+ data(i, j + 1, k) - data(i, j - 1, k),
+ data(i, j, k + kd) - data(i, j, k - kd));
+}
+
+struct knUnprojectNormalComp : public KernelBase {
+ knUnprojectNormalComp(FlagGrid &flags, MACGrid &vel, Grid<Real> &phi, Real maxDist)
+ : KernelBase(&flags, 1), flags(flags), vel(vel), phi(phi), maxDist(maxDist)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, FlagGrid &flags, MACGrid &vel, Grid<Real> &phi, Real maxDist) const
+ {
+ // apply inside, within range near obstacle surface
+ if (phi(i, j, k) > 0. || phi(i, j, k) < -maxDist)
+ return;
+
+ Vec3 n = getNormal(phi, i, j, k);
+ Vec3 v = vel(i, j, k);
+ if (dot(n, v) < 0.) {
+ normalize(n);
+ Real l = dot(n, v);
+ vel(i, j, k) -= n * l;
+ }
+ }
+ inline FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline Grid<Real> &getArg2()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type2;
+ inline Real &getArg3()
+ {
+ return maxDist;
+ }
+ typedef Real type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knUnprojectNormalComp ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, phi, maxDist);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, phi, maxDist);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ FlagGrid &flags;
+ MACGrid &vel;
+ Grid<Real> &phi;
+ Real maxDist;
+};
+// a simple extrapolation step , used for cases where there's no levelset
+// (note, less accurate than fast marching extrapolation.)
+// into obstacle is a special mode for second order obstable boundaries (extrapolating
+// only fluid velocities, not those at obstacles)
+
+void extrapolateMACSimple(FlagGrid &flags,
+ MACGrid &vel,
+ int distance = 4,
+ LevelsetGrid *phiObs = NULL,
+ bool intoObs = false)
+{
+ Grid<int> tmp(flags.getParent());
+ int dim = (flags.is3D() ? 3 : 2);
+
+ for (int c = 0; c < dim; ++c) {
+ Vec3i dir = 0;
+ dir[c] = 1;
+ tmp.clear();
+
+ // remove all fluid cells (not touching obstacles)
+ FOR_IJK_BND(flags, 1)
+ {
+ Vec3i p(i, j, k);
+ bool mark = false;
+ if (!intoObs) {
+ if (flags.isFluid(p) || flags.isFluid(p - dir))
+ mark = true;
+ }
+ else {
+ if ((flags.isFluid(p) || flags.isFluid(p - dir)) && (!flags.isObstacle(p)) &&
+ (!flags.isObstacle(p - dir)))
+ mark = true;
+ }
+
+ if (mark)
+ tmp(p) = 1;
+ }
+
+ // extrapolate for distance
+ for (int d = 1; d < 1 + distance; ++d) {
+ knExtrapolateMACSimple(vel, distance, tmp, d, c);
+ } // d
+ }
+
+ if (phiObs) {
+ knUnprojectNormalComp(flags, vel, *phiObs, distance);
+ }
+
+ // copy tangential values into sides of domain
+ MACGrid velTmp(flags.getParent());
+ velTmp.copyFrom(vel);
+ knExtrapolateIntoBnd(flags, vel, velTmp);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "extrapolateMACSimple", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ int distance = _args.getOpt<int>("distance", 2, 4, &_lock);
+ LevelsetGrid *phiObs = _args.getPtrOpt<LevelsetGrid>("phiObs", 3, NULL, &_lock);
+ bool intoObs = _args.getOpt<bool>("intoObs", 4, false, &_lock);
+ _retval = getPyNone();
+ extrapolateMACSimple(flags, vel, distance, phiObs, intoObs);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "extrapolateMACSimple", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("extrapolateMACSimple", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_extrapolateMACSimple("", "extrapolateMACSimple", _W_0);
+extern "C" {
+void PbRegister_extrapolateMACSimple()
+{
+ KEEP_UNUSED(_RP_extrapolateMACSimple);
+}
+}
+
+struct knExtrapolateMACFromWeight : public KernelBase {
+ knExtrapolateMACFromWeight(
+ MACGrid &vel, Grid<Vec3> &weight, int distance, const int d, const int c)
+ : KernelBase(&vel, 1), vel(vel), weight(weight), distance(distance), d(d), c(c)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ MACGrid &vel,
+ Grid<Vec3> &weight,
+ int distance,
+ const int d,
+ const int c) const
+ {
+ static const Vec3i nb[6] = {Vec3i(1, 0, 0),
+ Vec3i(-1, 0, 0),
+ Vec3i(0, 1, 0),
+ Vec3i(0, -1, 0),
+ Vec3i(0, 0, 1),
+ Vec3i(0, 0, -1)};
+ const int dim = (vel.is3D() ? 3 : 2);
+
+ if (weight(i, j, k)[c] != 0)
+ return;
+
+ // copy from initialized neighbors
+ Vec3i p(i, j, k);
+ int nbs = 0;
+ Real avgVel = 0.;
+ for (int n = 0; n < 2 * dim; ++n) {
+ if (weight(p + nb[n])[c] == d) {
+ avgVel += vel(p + nb[n])[c];
+ nbs++;
+ }
+ }
+
+ if (nbs > 0) {
+ weight(p)[c] = d + 1;
+ vel(p)[c] = avgVel / nbs;
+ }
+ }
+ inline MACGrid &getArg0()
+ {
+ return vel;
+ }
+ typedef MACGrid type0;
+ inline Grid<Vec3> &getArg1()
+ {
+ return weight;
+ }
+ typedef Grid<Vec3> type1;
+ inline int &getArg2()
+ {
+ return distance;
+ }
+ typedef int type2;
+ inline const int &getArg3()
+ {
+ return d;
+ }
+ typedef int type3;
+ inline const int &getArg4()
+ {
+ return c;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knExtrapolateMACFromWeight ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, weight, distance, d, c);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, weight, distance, d, c);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ MACGrid &vel;
+ Grid<Vec3> &weight;
+ int distance;
+ const int d;
+ const int c;
+};
+
+// same as extrapolateMACSimple, but uses weight vec3 grid instead of flags to check
+// for valid values (to be used in combination with mapPartsToMAC)
+// note - the weight grid values are destroyed! the function is necessary due to discrepancies
+// between velocity mapping on surface-levelset / fluid-flag creation. With this
+// extrapolation we make sure the fluid region is covered by initial velocities
+
+void extrapolateMACFromWeight(MACGrid &vel, Grid<Vec3> &weight, int distance = 2)
+{
+ const int dim = (vel.is3D() ? 3 : 2);
+
+ for (int c = 0; c < dim; ++c) {
+ Vec3i dir = 0;
+ dir[c] = 1;
+
+ // reset weight values to 0 (uninitialized), and 1 (initialized inner values)
+ FOR_IJK_BND(vel, 1)
+ {
+ Vec3i p(i, j, k);
+ if (weight(p)[c] > 0.)
+ weight(p)[c] = 1.0;
+ }
+
+ // extrapolate for distance
+ for (int d = 1; d < 1 + distance; ++d) {
+ knExtrapolateMACFromWeight(vel, weight, distance, d, c);
+ } // d
+ }
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "extrapolateMACFromWeight", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ Grid<Vec3> &weight = *_args.getPtr<Grid<Vec3>>("weight", 1, &_lock);
+ int distance = _args.getOpt<int>("distance", 2, 2, &_lock);
+ _retval = getPyNone();
+ extrapolateMACFromWeight(vel, weight, distance);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "extrapolateMACFromWeight", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("extrapolateMACFromWeight", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_extrapolateMACFromWeight("", "extrapolateMACFromWeight", _W_1);
+extern "C" {
+void PbRegister_extrapolateMACFromWeight()
+{
+ KEEP_UNUSED(_RP_extrapolateMACFromWeight);
+}
+}
+
+// simple extrapolation functions for levelsets
+
+static const Vec3i nb[6] = {Vec3i(1, 0, 0),
+ Vec3i(-1, 0, 0),
+ Vec3i(0, 1, 0),
+ Vec3i(0, -1, 0),
+ Vec3i(0, 0, 1),
+ Vec3i(0, 0, -1)};
+
+template<class S> struct knExtrapolateLsSimple : public KernelBase {
+ knExtrapolateLsSimple(Grid<S> &val, int distance, Grid<int> &tmp, const int d, S direction)
+ : KernelBase(&val, 1), val(val), distance(distance), tmp(tmp), d(d), direction(direction)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<S> &val,
+ int distance,
+ Grid<int> &tmp,
+ const int d,
+ S direction) const
+ {
+ const int dim = (val.is3D() ? 3 : 2);
+ if (tmp(i, j, k) != 0)
+ return;
+
+ // copy from initialized neighbors
+ Vec3i p(i, j, k);
+ int nbs = 0;
+ S avg(0.);
+ for (int n = 0; n < 2 * dim; ++n) {
+ if (tmp(p + nb[n]) == d) {
+ avg += val(p + nb[n]);
+ nbs++;
+ }
+ }
+
+ if (nbs > 0) {
+ tmp(p) = d + 1;
+ val(p) = avg / nbs + direction;
+ }
+ }
+ inline Grid<S> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid<S> type0;
+ inline int &getArg1()
+ {
+ return distance;
+ }
+ typedef int type1;
+ inline Grid<int> &getArg2()
+ {
+ return tmp;
+ }
+ typedef Grid<int> type2;
+ inline const int &getArg3()
+ {
+ return d;
+ }
+ typedef int type3;
+ inline S &getArg4()
+ {
+ return direction;
+ }
+ typedef S type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knExtrapolateLsSimple ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, val, distance, tmp, d, direction);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, val, distance, tmp, d, direction);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<S> &val;
+ int distance;
+ Grid<int> &tmp;
+ const int d;
+ S direction;
+};
+
+template<class S> struct knSetRemaining : public KernelBase {
+ knSetRemaining(Grid<S> &phi, Grid<int> &tmp, S distance)
+ : KernelBase(&phi, 1), phi(phi), tmp(tmp), distance(distance)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<S> &phi, Grid<int> &tmp, S distance) const
+ {
+ if (tmp(i, j, k) != 0)
+ return;
+ phi(i, j, k) = distance;
+ }
+ inline Grid<S> &getArg0()
+ {
+ return phi;
+ }
+ typedef Grid<S> type0;
+ inline Grid<int> &getArg1()
+ {
+ return tmp;
+ }
+ typedef Grid<int> type1;
+ inline S &getArg2()
+ {
+ return distance;
+ }
+ typedef S type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetRemaining ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, phi, tmp, distance);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, phi, tmp, distance);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<S> &phi;
+ Grid<int> &tmp;
+ S distance;
+};
+
+void extrapolateLsSimple(Grid<Real> &phi, int distance = 4, bool inside = false)
+{
+ Grid<int> tmp(phi.getParent());
+ tmp.clear();
+ const int dim = (phi.is3D() ? 3 : 2);
+
+ // by default, march outside
+ Real direction = 1.;
+ if (!inside) {
+ // mark all inside
+ FOR_IJK_BND(phi, 1)
+ {
+ if (phi(i, j, k) < 0.) {
+ tmp(i, j, k) = 1;
+ }
+ }
+ }
+ else {
+ direction = -1.;
+ FOR_IJK_BND(phi, 1)
+ {
+ if (phi(i, j, k) > 0.) {
+ tmp(i, j, k) = 1;
+ }
+ }
+ }
+ // + first layer around
+ FOR_IJK_BND(phi, 1)
+ {
+ Vec3i p(i, j, k);
+ if (tmp(p))
+ continue;
+ for (int n = 0; n < 2 * dim; ++n) {
+ if (tmp(p + nb[n]) == 1) {
+ tmp(i, j, k) = 2;
+ n = 2 * dim;
+ }
+ }
+ }
+
+ // extrapolate for distance
+ for (int d = 2; d < 1 + distance; ++d) {
+ knExtrapolateLsSimple<Real>(phi, distance, tmp, d, direction);
+ }
+
+ // set all remaining cells to max
+ knSetRemaining<Real>(phi, tmp, Real(direction * (distance + 2)));
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "extrapolateLsSimple", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &phi = *_args.getPtr<Grid<Real>>("phi", 0, &_lock);
+ int distance = _args.getOpt<int>("distance", 1, 4, &_lock);
+ bool inside = _args.getOpt<bool>("inside", 2, false, &_lock);
+ _retval = getPyNone();
+ extrapolateLsSimple(phi, distance, inside);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "extrapolateLsSimple", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("extrapolateLsSimple", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_extrapolateLsSimple("", "extrapolateLsSimple", _W_2);
+extern "C" {
+void PbRegister_extrapolateLsSimple()
+{
+ KEEP_UNUSED(_RP_extrapolateLsSimple);
+}
+}
+
+// extrapolate centered vec3 values from marked fluid cells
+
+void extrapolateVec3Simple(Grid<Vec3> &vel, Grid<Real> &phi, int distance = 4, bool inside = false)
+{
+ Grid<int> tmp(vel.getParent());
+ tmp.clear();
+ const int dim = (vel.is3D() ? 3 : 2);
+
+ // mark initial cells, by default, march outside
+ if (!inside) {
+ // mark all inside
+ FOR_IJK_BND(phi, 1)
+ {
+ if (phi(i, j, k) < 0.) {
+ tmp(i, j, k) = 1;
+ }
+ }
+ }
+ else {
+ FOR_IJK_BND(phi, 1)
+ {
+ if (phi(i, j, k) > 0.) {
+ tmp(i, j, k) = 1;
+ }
+ }
+ }
+ // + first layer next to initial cells
+ FOR_IJK_BND(vel, 1)
+ {
+ Vec3i p(i, j, k);
+ if (tmp(p))
+ continue;
+ for (int n = 0; n < 2 * dim; ++n) {
+ if (tmp(p + nb[n]) == 1) {
+ tmp(i, j, k) = 2;
+ n = 2 * dim;
+ }
+ }
+ }
+
+ for (int d = 2; d < 1 + distance; ++d) {
+ knExtrapolateLsSimple<Vec3>(vel, distance, tmp, d, Vec3(0.));
+ }
+ knSetRemaining<Vec3>(vel, tmp, Vec3(0.));
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "extrapolateVec3Simple", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &vel = *_args.getPtr<Grid<Vec3>>("vel", 0, &_lock);
+ Grid<Real> &phi = *_args.getPtr<Grid<Real>>("phi", 1, &_lock);
+ int distance = _args.getOpt<int>("distance", 2, 4, &_lock);
+ bool inside = _args.getOpt<bool>("inside", 3, false, &_lock);
+ _retval = getPyNone();
+ extrapolateVec3Simple(vel, phi, distance, inside);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "extrapolateVec3Simple", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("extrapolateVec3Simple", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_extrapolateVec3Simple("", "extrapolateVec3Simple", _W_3);
+extern "C" {
+void PbRegister_extrapolateVec3Simple()
+{
+ KEEP_UNUSED(_RP_extrapolateVec3Simple);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/fastmarch.h b/extern/mantaflow/preprocessed/fastmarch.h
new file mode 100644
index 00000000000..8d0511cc06d
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fastmarch.h
@@ -0,0 +1,241 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Fast marching
+ *
+ ******************************************************************************/
+
+#ifndef _FASTMARCH_H
+#define _FASTMARCH_H
+
+#include <queue>
+#include "levelset.h"
+
+namespace Manta {
+
+//! Fast marching. Transport certain values
+// This class exists in two versions: for scalar, and for vector values - the only difference are
+// flag checks i transpTouch (for simplicity in separate classes)
+
+template<class GRID, class T>
+inline T fmInterpolateNeighbors(GRID *mpVal, int x, int y, int z, Real *weights)
+{
+ T val(0.);
+ if (weights[0] > 0.0)
+ val += mpVal->get(x + 1, y + 0, z + 0) * weights[0];
+ if (weights[1] > 0.0)
+ val += mpVal->get(x - 1, y + 0, z + 0) * weights[1];
+ if (weights[2] > 0.0)
+ val += mpVal->get(x + 0, y + 1, z + 0) * weights[2];
+ if (weights[3] > 0.0)
+ val += mpVal->get(x + 0, y - 1, z + 0) * weights[3];
+ if (mpVal->is3D()) {
+ if (weights[4] > 0.0)
+ val += mpVal->get(x + 0, y + 0, z + 1) * weights[4];
+ if (weights[5] > 0.0)
+ val += mpVal->get(x + 0, y + 0, z - 1) * weights[5];
+ }
+ return val;
+}
+
+template<class GRID, class T> class FmValueTransportScalar {
+ public:
+ FmValueTransportScalar() : mpVal(0), mpFlags(0){};
+ ~FmValueTransportScalar(){};
+ void initMarching(GRID *val, FlagGrid *flags)
+ {
+ mpVal = val;
+ mpFlags = flags;
+ }
+ inline bool isInitialized()
+ {
+ return mpVal != 0;
+ }
+
+ //! cell is touched by marching from source cell
+ inline void transpTouch(int x, int y, int z, Real *weights, Real time)
+ {
+ if (!mpVal || !mpFlags->isEmpty(x, y, z))
+ return;
+ T val = fmInterpolateNeighbors<GRID, T>(mpVal, x, y, z, weights);
+ (*mpVal)(x, y, z) = val;
+ };
+
+ protected:
+ GRID *mpVal;
+ FlagGrid *mpFlags;
+};
+
+template<class GRID, class T> class FmValueTransportVec3 {
+ public:
+ FmValueTransportVec3() : mpVal(0), mpFlags(0){};
+ ~FmValueTransportVec3(){};
+ inline bool isInitialized()
+ {
+ return mpVal != 0;
+ }
+ void initMarching(GRID *val, const FlagGrid *flags)
+ {
+ mpVal = val;
+ mpFlags = flags;
+ }
+
+ //! cell is touched by marching from source cell
+ inline void transpTouch(int x, int y, int z, Real *weights, Real time)
+ {
+ if (!mpVal || !mpFlags->isEmpty(x, y, z))
+ return;
+
+ T val = fmInterpolateNeighbors<GRID, T>(mpVal, x, y, z, weights);
+
+ // set velocity components if adjacent is empty
+ if (mpFlags->isEmpty(x - 1, y, z))
+ (*mpVal)(x, y, z).x = val.x;
+ if (mpFlags->isEmpty(x, y - 1, z))
+ (*mpVal)(x, y, z).y = val.y;
+ if (mpVal->is3D()) {
+ if (mpFlags->isEmpty(x, y, z - 1))
+ (*mpVal)(x, y, z).z = val.z;
+ }
+ };
+
+ protected:
+ GRID *mpVal;
+ const FlagGrid *mpFlags;
+};
+
+class FmHeapEntryOut {
+ public:
+ Vec3i p;
+ // quick time access for sorting
+ Real time;
+ static inline bool compare(const Real x, const Real y)
+ {
+ return x > y;
+ }
+
+ inline bool operator<(const FmHeapEntryOut &o) const
+ {
+ const Real d = fabs((time) - ((o.time)));
+ if (d > 0.)
+ return (time) > ((o.time));
+ if (p.z != o.p.z)
+ return p.z > o.p.z;
+ if (p.y != o.p.y)
+ return p.y > o.p.y;
+ return p.x > o.p.x;
+ };
+};
+
+class FmHeapEntryIn {
+ public:
+ Vec3i p;
+ // quick time access for sorting
+ Real time;
+ static inline bool compare(const Real x, const Real y)
+ {
+ return x < y;
+ }
+
+ inline bool operator<(const FmHeapEntryIn &o) const
+ {
+ const Real d = fabs((time) - ((o.time)));
+ if (d > 0.)
+ return (time) < ((o.time));
+ if (p.z != o.p.z)
+ return p.z < o.p.z;
+ if (p.y != o.p.y)
+ return p.y < o.p.y;
+ return p.x < o.p.x;
+ };
+};
+
+//! fast marching algorithm wrapper class
+template<class T, int TDIR> class FastMarch {
+
+ public:
+ // MSVC doesn't allow static const variables in template classes
+ static inline Real InvalidTime()
+ {
+ return -1000;
+ }
+ static inline Real InvtOffset()
+ {
+ return 500;
+ }
+
+ enum SpecialValues { FlagInited = 1, FlagIsOnHeap = 2 };
+
+ FastMarch(const FlagGrid &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &levelset,
+ Real maxTime,
+ MACGrid *velTransport = NULL);
+ ~FastMarch()
+ {
+ }
+
+ //! advect level set function with given velocity */
+ void performMarching();
+
+ //! test value for invalidity
+ inline bool isInvalid(Real v) const
+ {
+ return (v <= InvalidTime());
+ }
+
+ void addToList(const Vec3i &p, const Vec3i &src);
+
+ //! convert phi to time value
+ inline Real phi2time(Real phival)
+ {
+ return (phival - InvalidTime() + InvtOffset()) * -1.0;
+ }
+
+ //! ... and back
+ inline Real time2phi(Real tval)
+ {
+ return (InvalidTime() - InvtOffset() - tval);
+ }
+
+ inline Real _phi(int i, int j, int k)
+ {
+ return mLevelset(i, j, k);
+ }
+
+ protected:
+ Grid<Real> &mLevelset;
+ const FlagGrid &mFlags;
+ Grid<int> &mFmFlags;
+
+ //! velocity extrpolation
+ FmValueTransportVec3<MACGrid, Vec3> mVelTransport;
+
+ //! maximal time to march for
+ Real mMaxTime;
+
+ //! fast marching list
+ std::priority_queue<T, std::vector<T>, std::less<T>> mHeap;
+ Real mReheapVal;
+
+ //! weights for touching points
+ Real mWeights[6];
+
+ template<int C> inline Real calcWeights(int &okCnt, int &invcnt, Real *v, const Vec3i &idx);
+
+ inline Real calculateDistance(const Vec3i &pos);
+};
+
+} // namespace Manta
+#endif
diff --git a/extern/mantaflow/preprocessed/fastmarch.h.reg.cpp b/extern/mantaflow/preprocessed/fastmarch.h.reg.cpp
new file mode 100644
index 00000000000..903637af502
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fastmarch.h.reg.cpp
@@ -0,0 +1,13 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "fastmarch.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_5()
+{
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/fileio/iogrids.cpp b/extern/mantaflow/preprocessed/fileio/iogrids.cpp
new file mode 100644
index 00000000000..2f6cdaa6209
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fileio/iogrids.cpp
@@ -0,0 +1,1524 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstring>
+
+#if NO_ZLIB != 1
+extern "C" {
+# include <zlib.h>
+}
+#endif
+
+#if OPENVDB == 1
+# include "openvdb/openvdb.h"
+#endif
+
+#include "cnpy.h"
+#include "mantaio.h"
+#include "grid.h"
+#include "vector4d.h"
+#include "grid4d.h"
+
+using namespace std;
+
+namespace Manta {
+
+static const int STR_LEN_GRID = 252;
+
+//! uni file header, v4
+typedef struct {
+ int dimX, dimY, dimZ; // grid size
+ int gridType, elementType, bytesPerElement; // data type info
+ char info[STR_LEN_GRID]; // mantaflow build information
+ int dimT; // optionally store forth dimension for 4d grids
+ unsigned long long timestamp; // creation time
+} UniHeader;
+
+// note: header v4 only uses 4 bytes of the info string to store the fourth dimension, not needed
+// for pdata
+
+//*****************************************************************************
+// conversion functions for double precision
+// (note - uni files always store single prec. values)
+//*****************************************************************************
+
+#if NO_ZLIB != 1
+template<class GRIDT> void gridConvertWrite(gzFile &gzf, GRIDT &grid, void *ptr, UniHeader &head)
+{
+ errMsg("gridConvertWrite: unknown type, not yet supported");
+}
+
+template<> void gridConvertWrite(gzFile &gzf, Grid<int> &grid, void *ptr, UniHeader &head)
+{
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, &grid[0], sizeof(int) * head.dimX * head.dimY * head.dimZ);
+}
+template<> void gridConvertWrite(gzFile &gzf, Grid<double> &grid, void *ptr, UniHeader &head)
+{
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i, ++ptrf) {
+ *ptrf = (float)grid[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float) * head.dimX * head.dimY * head.dimZ);
+}
+template<>
+void gridConvertWrite(gzFile &gzf, Grid<Vector3D<double>> &grid, void *ptr, UniHeader &head)
+{
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i) {
+ for (int c = 0; c < 3; ++c) {
+ *ptrf = (float)grid[i][c];
+ ptrf++;
+ }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) * head.dimX * head.dimY * head.dimZ);
+}
+
+template<> void gridConvertWrite(gzFile &gzf, Grid4d<int> &grid, void *ptr, UniHeader &head)
+{
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, &grid[0], sizeof(int) * head.dimX * head.dimY * head.dimZ * head.dimT);
+}
+template<> void gridConvertWrite(gzFile &gzf, Grid4d<double> &grid, void *ptr, UniHeader &head)
+{
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float *ptrf = (float *)ptr;
+ IndexInt s = grid.getStrideT() * grid.getSizeT();
+ for (IndexInt i = 0; i < s; ++i, ++ptrf) {
+ *ptrf = (float)grid[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float) * s);
+}
+template<>
+void gridConvertWrite(gzFile &gzf, Grid4d<Vector3D<double>> &grid, void *ptr, UniHeader &head)
+{
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float *ptrf = (float *)ptr;
+ IndexInt s = grid.getStrideT() * grid.getSizeT();
+ for (IndexInt i = 0; i < s; ++i) {
+ for (int c = 0; c < 3; ++c) {
+ *ptrf = (float)grid[i][c];
+ ptrf++;
+ }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) * s);
+}
+template<>
+void gridConvertWrite(gzFile &gzf, Grid4d<Vector4D<double>> &grid, void *ptr, UniHeader &head)
+{
+ head.bytesPerElement = sizeof(Vector4D<float>);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float *ptrf = (float *)ptr;
+ IndexInt s = grid.getStrideT() * grid.getSizeT();
+ for (IndexInt i = 0; i < s; ++i) {
+ for (int c = 0; c < 4; ++c) {
+ *ptrf = (float)grid[i][c];
+ ptrf++;
+ }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector4D<float>) * s);
+}
+
+template<class T> void gridReadConvert(gzFile &gzf, Grid<T> &grid, void *ptr, int bytesPerElement)
+{
+ errMsg("gridReadConvert: unknown type, not yet supported");
+}
+
+template<> void gridReadConvert<int>(gzFile &gzf, Grid<int> &grid, void *ptr, int bytesPerElement)
+{
+ gzread(gzf, ptr, sizeof(int) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
+ assertMsg(bytesPerElement == sizeof(int),
+ "grid element size doesn't match " << bytesPerElement << " vs " << sizeof(int));
+ // easy, nothing to do for ints
+ memcpy(&(grid[0]), ptr, sizeof(int) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
+}
+
+template<>
+void gridReadConvert<double>(gzFile &gzf, Grid<double> &grid, void *ptr, int bytesPerElement)
+{
+ gzread(gzf, ptr, sizeof(float) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
+ assertMsg(bytesPerElement == sizeof(float),
+ "grid element size doesn't match " << bytesPerElement << " vs " << sizeof(float));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i, ++ptrf) {
+ grid[i] = (double)(*ptrf);
+ }
+}
+
+template<>
+void gridReadConvert<Vec3>(gzFile &gzf, Grid<Vec3> &grid, void *ptr, int bytesPerElement)
+{
+ gzread(gzf, ptr, sizeof(Vector3D<float>) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
+ assertMsg(bytesPerElement == sizeof(Vector3D<float>),
+ "grid element size doesn't match " << bytesPerElement << " vs "
+ << sizeof(Vector3D<float>));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i) {
+ Vec3 v;
+ for (int c = 0; c < 3; ++c) {
+ v[c] = double(*ptrf);
+ ptrf++;
+ }
+ grid[i] = v;
+ }
+}
+
+template<class T>
+void gridReadConvert4d(gzFile &gzf, Grid4d<T> &grid, void *ptr, int bytesPerElement, int t)
+{
+ errMsg("gridReadConvert4d: unknown type, not yet supported");
+}
+
+template<>
+void gridReadConvert4d<int>(gzFile &gzf, Grid4d<int> &grid, void *ptr, int bytesPerElement, int t)
+{
+ gzread(gzf, ptr, sizeof(int) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
+ assertMsg(bytesPerElement == sizeof(int),
+ "grid element size doesn't match " << bytesPerElement << " vs " << sizeof(int));
+ // nothing to do for ints
+ memcpy(&(grid[grid.getSizeX() * grid.getSizeY() * grid.getSizeZ() * t]),
+ ptr,
+ sizeof(int) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
+}
+
+template<>
+void gridReadConvert4d<double>(
+ gzFile &gzf, Grid4d<double> &grid, void *ptr, int bytesPerElement, int t)
+{
+ assertMsg(bytesPerElement == sizeof(float),
+ "grid element size doesn't match " << bytesPerElement << " vs " << sizeof(float));
+
+ float *ptrf = (float *)ptr;
+ gzread(gzf, ptr, sizeof(float) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
+ for (IndexInt i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i, ++ptrf) {
+ grid[grid.getSizeX() * grid.getSizeY() * grid.getSizeZ() * t + i] = (double)(*ptrf);
+ }
+}
+
+template<>
+void gridReadConvert4d<Vec3>(
+ gzFile &gzf, Grid4d<Vec3> &grid, void *ptr, int bytesPerElement, int t)
+{
+ assertMsg(bytesPerElement == sizeof(Vector3D<float>),
+ "grid element size doesn't match " << bytesPerElement << " vs " << sizeof(float));
+
+ gzread(gzf, ptr, sizeof(Vector3D<float>) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
+ float *ptrf = (float *)ptr;
+ for (IndexInt i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i) {
+ Vec3 v;
+ for (int c = 0; c < 3; ++c) {
+ v[c] = double(*ptrf);
+ ptrf++;
+ }
+ grid[grid.getSizeX() * grid.getSizeY() * grid.getSizeZ() * t + i] = v;
+ }
+}
+
+template<>
+void gridReadConvert4d<Vec4>(
+ gzFile &gzf, Grid4d<Vec4> &grid, void *ptr, int bytesPerElement, int t)
+{
+ assertMsg(bytesPerElement == sizeof(Vector4D<float>),
+ "grid element size doesn't match " << bytesPerElement << " vs " << sizeof(float));
+
+ gzread(gzf, ptr, sizeof(Vector4D<float>) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
+ float *ptrf = (float *)ptr;
+ for (IndexInt i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i) {
+ Vec4 v;
+ for (int c = 0; c < 4; ++c) {
+ v[c] = double(*ptrf);
+ ptrf++;
+ }
+ grid[grid.getSizeX() * grid.getSizeY() * grid.getSizeZ() * t + i] = v;
+ }
+}
+
+// make sure compatible grid types dont lead to errors...
+static int unifyGridType(int type)
+{
+ // real <> levelset
+ if (type & GridBase::TypeReal)
+ type |= GridBase::TypeLevelset;
+ if (type & GridBase::TypeLevelset)
+ type |= GridBase::TypeReal;
+ // vec3 <> mac
+ if (type & GridBase::TypeVec3)
+ type |= GridBase::TypeMAC;
+ if (type & GridBase::TypeMAC)
+ type |= GridBase::TypeVec3;
+ return type;
+}
+
+#endif // NO_ZLIB!=1
+
+//*****************************************************************************
+// grid data
+//*****************************************************************************
+
+template<class T> void writeGridTxt(const string &name, Grid<T> *grid)
+{
+ debMsg("writing grid " << grid->getName() << " to text file " << name, 1);
+
+ ofstream ofs(name.c_str());
+ if (!ofs.good())
+ errMsg("writeGridTxt: can't open file " << name);
+ FOR_IJK(*grid)
+ {
+ ofs << Vec3i(i, j, k) << " = " << (*grid)(i, j, k) << "\n";
+ }
+ ofs.close();
+}
+
+template<class T> void writeGridRaw(const string &name, Grid<T> *grid)
+{
+ debMsg("writing grid " << grid->getName() << " to raw file " << name, 1);
+
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf)
+ errMsg("writeGridRaw: can't open file " << name);
+ gzwrite(gzf, &((*grid)[0]), sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ());
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+}
+
+template<class T> void readGridRaw(const string &name, Grid<T> *grid)
+{
+ debMsg("reading grid " << grid->getName() << " from raw file " << name, 1);
+
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf)
+ errMsg("readGridRaw: can't open file " << name);
+
+ IndexInt bytes = sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ();
+ IndexInt readBytes = gzread(gzf, &((*grid)[0]), bytes);
+ assertMsg(bytes == readBytes,
+ "can't read raw file, stream length does not match, " << bytes << " vs " << readBytes);
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+}
+
+//! legacy headers for reading old files
+typedef struct {
+ int dimX, dimY, dimZ;
+ int frames, elements, elementType, bytesPerElement, bytesPerFrame;
+} UniLegacyHeader;
+
+typedef struct {
+ int dimX, dimY, dimZ;
+ int gridType, elementType, bytesPerElement;
+} UniLegacyHeader2;
+
+typedef struct {
+ int dimX, dimY, dimZ;
+ int gridType, elementType, bytesPerElement;
+ char info[256];
+ unsigned long long timestamp;
+} UniLegacyHeader3;
+
+//! for auto-init & check of results of test runs , optionally returns info string of header
+void getUniFileSize(const string &name, int &x, int &y, int &z, int *t, std::string *info)
+{
+ x = y = z = 0;
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (gzf) {
+ char ID[5] = {0, 0, 0, 0, 0};
+ gzread(gzf, ID, 4);
+
+ // v3
+ if ((!strcmp(ID, "MNT2")) || (!strcmp(ID, "M4T2"))) {
+ UniLegacyHeader3 head;
+ assertMsg(gzread(gzf, &head, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3),
+ "can't read file, no header present");
+ x = head.dimX;
+ y = head.dimY;
+ z = head.dimZ;
+
+ // optionally , read fourth dim
+ if ((!strcmp(ID, "M4T2")) && t) {
+ int dimT = 0;
+ gzread(gzf, &dimT, sizeof(int));
+ (*t) = dimT;
+ }
+ }
+
+ // v4
+ if ((!strcmp(ID, "MNT3")) || (!strcmp(ID, "M4T3"))) {
+ UniHeader head;
+ assertMsg(gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader),
+ "can't read file, no header present");
+ x = head.dimX;
+ y = head.dimY;
+ z = head.dimZ;
+ if (t)
+ (*t) = head.dimT;
+ }
+
+ gzclose(gzf);
+ }
+#endif
+ if (info) {
+ std::ostringstream out;
+ out << x << "," << y << "," << z;
+ if (t && (*t) > 0)
+ out << "," << (*t);
+ *info = out.str();
+ }
+}
+Vec3 getUniFileSize(const string &name)
+{
+ int x, y, z;
+ getUniFileSize(name, x, y, z);
+ return Vec3(Real(x), Real(y), Real(z));
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getUniFileSize", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const string &name = _args.get<string>("name", 0, &_lock);
+ _retval = toPy(getUniFileSize(name));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getUniFileSize", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getUniFileSize", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getUniFileSize("", "getUniFileSize", _W_0);
+extern "C" {
+void PbRegister_getUniFileSize()
+{
+ KEEP_UNUSED(_RP_getUniFileSize);
+}
+}
+
+//! for test run debugging
+void printUniFileInfoString(const string &name)
+{
+ std::string info("<file not found>");
+ int x = -1, y = -1, z = -1, t = -1;
+ // use getUniFileSize to parse the different headers
+ getUniFileSize(name, x, y, z, &t, &info);
+ debMsg("File '" << name << "' info: " << info, 1);
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "printUniFileInfoString", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const string &name = _args.get<string>("name", 0, &_lock);
+ _retval = getPyNone();
+ printUniFileInfoString(name);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "printUniFileInfoString", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("printUniFileInfoString", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_printUniFileInfoString("", "printUniFileInfoString", _W_1);
+extern "C" {
+void PbRegister_printUniFileInfoString()
+{
+ KEEP_UNUSED(_RP_printUniFileInfoString);
+}
+}
+
+// actual read/write functions
+
+template<class T> void writeGridUni(const string &name, Grid<T> *grid)
+{
+ debMsg("Writing grid " << grid->getName() << " to uni file " << name, 1);
+
+#if NO_ZLIB != 1
+ char ID[5] = "MNT3";
+ UniHeader head;
+ head.dimX = grid->getSizeX();
+ head.dimY = grid->getSizeY();
+ head.dimZ = grid->getSizeZ();
+ head.dimT = 0;
+ head.gridType = grid->getType();
+ head.bytesPerElement = sizeof(T);
+ snprintf(head.info, STR_LEN_GRID, "%s", buildInfoString().c_str());
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ if (grid->getType() & GridBase::TypeInt)
+ head.elementType = 0;
+ else if (grid->getType() & GridBase::TypeReal)
+ head.elementType = 1;
+ else if (grid->getType() & GridBase::TypeVec3)
+ head.elementType = 2;
+ else
+ errMsg("writeGridUni: unknown element type");
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf)
+ errMsg("writeGridUni: can't open file " << name);
+
+ gzwrite(gzf, ID, 4);
+# if FLOATINGPOINT_PRECISION != 1
+ // always write float values, even if compiled with double precision...
+ Grid<T> temp(grid->getParent());
+ // "misuse" temp grid as storage for floating point values (we have double, so it will always
+ // fit)
+ gridConvertWrite(gzf, *grid, &(temp[0]), head);
+# else
+ void *ptr = &((*grid)[0]);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, ptr, sizeof(T) * head.dimX * head.dimY * head.dimZ);
+# endif
+ gzclose(gzf);
+
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+};
+
+template<class T> void readGridUni(const string &name, Grid<T> *grid)
+{
+ debMsg("Reading grid " << grid->getName() << " from uni file " << name, 1);
+
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf)
+ errMsg("readGridUni: can't open file " << name);
+
+ char ID[5] = {0, 0, 0, 0, 0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "DDF2")) {
+ // legacy file format
+ UniLegacyHeader head;
+ assertMsg(gzread(gzf, &head, sizeof(UniLegacyHeader)) == sizeof(UniLegacyHeader),
+ "can't read file, no header present");
+ assertMsg(head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() &&
+ head.dimZ == grid->getSizeZ(),
+ "grid dim doesn't match");
+ assertMsg(head.bytesPerElement * head.elements == sizeof(T), "grid type doesn't match");
+ // skip flags
+ int numEl = head.dimX * head.dimY * head.dimZ;
+ gzseek(gzf, numEl, SEEK_CUR);
+ // actual grid read
+ gzread(gzf, &((*grid)[0]), sizeof(T) * numEl);
+ }
+ else if (!strcmp(ID, "MNT1")) {
+ // legacy file format 2
+ UniLegacyHeader2 head;
+ assertMsg(gzread(gzf, &head, sizeof(UniLegacyHeader2)) == sizeof(UniLegacyHeader2),
+ "can't read file, no header present");
+ assertMsg(head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() &&
+ head.dimZ == grid->getSizeZ(),
+ "grid dim doesn't match, " << Vec3(head.dimX, head.dimY, head.dimZ) << " vs "
+ << grid->getSize());
+ assertMsg(head.gridType == grid->getType(),
+ "grid type doesn't match " << head.gridType << " vs " << grid->getType());
+ assertMsg(head.bytesPerElement == sizeof(T),
+ "grid element size doesn't match " << head.bytesPerElement << " vs " << sizeof(T));
+ gzread(gzf, &((*grid)[0]), sizeof(T) * head.dimX * head.dimY * head.dimZ);
+ }
+ else if (!strcmp(ID, "MNT2")) {
+ // a bit ugly, almost identical to MNT3
+ UniLegacyHeader3 head;
+ assertMsg(gzread(gzf, &head, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3),
+ "can't read file, no header present");
+ assertMsg(head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() &&
+ head.dimZ == grid->getSizeZ(),
+ "grid dim doesn't match, " << Vec3(head.dimX, head.dimY, head.dimZ) << " vs "
+ << grid->getSize());
+ assertMsg(unifyGridType(head.gridType) == unifyGridType(grid->getType()),
+ "grid type doesn't match " << head.gridType << " vs " << grid->getType());
+# if FLOATINGPOINT_PRECISION != 1
+ Grid<T> temp(grid->getParent());
+ void *ptr = &(temp[0]);
+ gridReadConvert<T>(gzf, *grid, ptr, head.bytesPerElement);
+# else
+ assertMsg(head.bytesPerElement == sizeof(T),
+ "grid element size doesn't match " << head.bytesPerElement << " vs " << sizeof(T));
+ gzread(gzf, &((*grid)[0]), sizeof(T) * head.dimX * head.dimY * head.dimZ);
+# endif
+ }
+ else if (!strcmp(ID, "MNT3")) {
+ // current file format
+ UniHeader head;
+ assertMsg(gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader),
+ "can't read file, no header present");
+ assertMsg(head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() &&
+ head.dimZ == grid->getSizeZ(),
+ "grid dim doesn't match, " << Vec3(head.dimX, head.dimY, head.dimZ) << " vs "
+ << grid->getSize());
+ assertMsg(unifyGridType(head.gridType) == unifyGridType(grid->getType()),
+ "grid type doesn't match " << head.gridType << " vs " << grid->getType());
+# if FLOATINGPOINT_PRECISION != 1
+ // convert float to double
+ Grid<T> temp(grid->getParent());
+ void *ptr = &(temp[0]);
+ gridReadConvert<T>(gzf, *grid, ptr, head.bytesPerElement);
+# else
+ assertMsg(head.bytesPerElement == sizeof(T),
+ "grid element size doesn't match " << head.bytesPerElement << " vs " << sizeof(T));
+ gzread(gzf, &((*grid)[0]), sizeof(T) * head.dimX * head.dimY * head.dimZ);
+# endif
+ }
+ else {
+ errMsg("readGridUni: Unknown header '" << ID << "' ");
+ }
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+};
+
+template<class T> void writeGridVol(const string &name, Grid<T> *grid)
+{
+ debMsg("writing grid " << grid->getName() << " to vol file " << name, 1);
+ errMsg("writeGridVol: Type not yet supported!");
+}
+
+struct volHeader {
+ char ID[3];
+ char version;
+ int encoding;
+ int dimX, dimY, dimZ;
+ int channels;
+ Vec3 bboxMin, bboxMax;
+};
+
+template<> void writeGridVol<Real>(const string &name, Grid<Real> *grid)
+{
+ debMsg("writing real grid " << grid->getName() << " to vol file " << name, 1);
+
+ volHeader header;
+ header.ID[0] = 'V';
+ header.ID[1] = 'O';
+ header.ID[2] = 'L';
+ header.version = 3;
+ header.encoding = 1; // float32 precision
+ header.dimX = grid->getSizeX();
+ header.dimY = grid->getSizeY();
+ header.dimZ = grid->getSizeZ();
+ header.channels = 1; // only 1 channel
+ header.bboxMin = Vec3(-0.5);
+ header.bboxMax = Vec3(0.5);
+
+ FILE *fp = fopen(name.c_str(), "wb");
+ if (fp == NULL) {
+ errMsg("writeGridVol: Cannot open '" << name << "'");
+ return;
+ }
+
+ fwrite(&header, sizeof(volHeader), 1, fp);
+
+#if FLOATINGPOINT_PRECISION == 1
+ // for float, write one big chunk
+ fwrite(&(*grid)[0], sizeof(float), grid->getSizeX() * grid->getSizeY() * grid->getSizeZ(), fp);
+#else
+ // explicitly convert each entry to float - we might have double precision in mantaflow
+ FOR_IDX(*grid)
+ {
+ float value = (*grid)[idx];
+ fwrite(&value, sizeof(float), 1, fp);
+ }
+#endif
+
+ fclose(fp);
+};
+
+template<class T> void readGridVol(const string &name, Grid<T> *grid)
+{
+ debMsg("writing grid " << grid->getName() << " to vol file " << name, 1);
+ errMsg("readGridVol: Type not yet supported!");
+}
+
+template<> void readGridVol<Real>(const string &name, Grid<Real> *grid)
+{
+ debMsg("reading real grid " << grid->getName() << " from vol file " << name, 1);
+
+ volHeader header;
+ FILE *fp = fopen(name.c_str(), "rb");
+ if (fp == NULL) {
+ errMsg("readGridVol: Cannot open '" << name << "'");
+ return;
+ }
+
+ // note, only very basic file format checks here!
+ assertMsg(fread(&header, 1, sizeof(volHeader), fp) == sizeof(volHeader),
+ "can't read file, no header present");
+ if (header.dimX != grid->getSizeX() || header.dimY != grid->getSizeY() ||
+ header.dimZ != grid->getSizeZ())
+ errMsg("grid dim doesn't match, " << Vec3(header.dimX, header.dimY, header.dimZ) << " vs "
+ << grid->getSize());
+#if FLOATINGPOINT_PRECISION != 1
+ errMsg("readGridVol: Double precision not yet supported");
+#else
+ const unsigned int s = sizeof(float) * header.dimX * header.dimY * header.dimZ;
+ assertMsg(fread(&((*grid)[0]), 1, s, fp) == s, "can't read file, no / not enough data");
+#endif
+
+ fclose(fp);
+};
+
+// 4d grids IO
+
+template<class T> void writeGrid4dUni(const string &name, Grid4d<T> *grid)
+{
+ debMsg("writing grid4d " << grid->getName() << " to uni file " << name, 1);
+
+#if NO_ZLIB != 1
+ char ID[5] = "M4T3";
+ UniHeader head;
+ head.dimX = grid->getSizeX();
+ head.dimY = grid->getSizeY();
+ head.dimZ = grid->getSizeZ();
+ head.dimT = grid->getSizeT();
+ head.gridType = grid->getType();
+ head.bytesPerElement = sizeof(T);
+ snprintf(head.info, STR_LEN_GRID, "%s", buildInfoString().c_str());
+ MuTime stamp;
+ stamp.get();
+ head.timestamp = stamp.time;
+
+ if (grid->getType() & Grid4dBase::TypeInt)
+ head.elementType = 0;
+ else if (grid->getType() & Grid4dBase::TypeReal)
+ head.elementType = 1;
+ else if (grid->getType() & Grid4dBase::TypeVec3)
+ head.elementType = 2;
+ else if (grid->getType() & Grid4dBase::TypeVec4)
+ head.elementType = 2;
+ else
+ errMsg("writeGrid4dUni: unknown element type");
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf)
+ errMsg("writeGrid4dUni: can't open file " << name);
+
+ gzwrite(gzf, ID, 4);
+# if FLOATINGPOINT_PRECISION != 1
+ Grid4d<T> temp(grid->getParent());
+ gridConvertWrite<Grid4d<T>>(gzf, *grid, &(temp[0]), head);
+# else
+ gzwrite(gzf, &head, sizeof(UniHeader));
+
+ // can be too large - write in chunks
+ for (int t = 0; t < head.dimT; ++t) {
+ void *ptr = &((*grid)[head.dimX * head.dimY * head.dimZ * t]);
+ gzwrite(gzf, ptr, sizeof(T) * head.dimX * head.dimY * head.dimZ * 1);
+ }
+# endif
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+};
+
+//! note, reading 4d uni grids is slightly more complicated than 3d ones
+//! as it optionally supports sliced reading
+template<class T>
+void readGrid4dUni(
+ const string &name, Grid4d<T> *grid, int readTslice, Grid4d<T> *slice, void **fileHandle)
+{
+ if (grid)
+ debMsg("reading grid " << grid->getName() << " from uni file " << name, 1);
+ if (slice)
+ debMsg("reading slice " << slice->getName() << ",t=" << readTslice << " from uni file "
+ << name,
+ 1);
+
+#if NO_ZLIB != 1
+ gzFile gzf = NULL;
+ char ID[5] = {0, 0, 0, 0, 0};
+
+ // optionally - reuse file handle, if valid one is passed in fileHandle pointer...
+ if ((!fileHandle) || (fileHandle && (*fileHandle == NULL))) {
+ gzf = gzopen(name.c_str(), "rb");
+ if (!gzf)
+ errMsg("readGrid4dUni: can't open file " << name);
+
+ gzread(gzf, ID, 4);
+ if (fileHandle) {
+ *fileHandle = gzf;
+ }
+ }
+ else {
+ // optimized read - reduced sanity checks
+ gzf = (gzFile)(*fileHandle);
+ void *ptr = &((*slice)[0]);
+ gzread(gzf, ptr, sizeof(T) * slice->getStrideT() * 1); // quick and dirty...
+ return;
+ }
+
+ if ((!strcmp(ID, "M4T2")) || (!strcmp(ID, "M4T3"))) {
+ int headerSize = -1;
+
+ // current file format
+ UniHeader head;
+ if (!strcmp(ID, "M4T3")) {
+ headerSize = sizeof(UniHeader);
+ assertMsg(gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader),
+ "can't read file, no 4d header present");
+ if (FLOATINGPOINT_PRECISION == 1)
+ assertMsg(head.bytesPerElement == sizeof(T),
+ "4d grid element size doesn't match " << head.bytesPerElement << " vs "
+ << sizeof(T));
+ }
+ // old header
+ if (!strcmp(ID, "M4T2")) {
+ UniLegacyHeader3 lhead;
+ headerSize = sizeof(UniLegacyHeader3) + sizeof(int);
+ assertMsg(gzread(gzf, &lhead, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3),
+ "can't read file, no 4dl header present");
+ if (FLOATINGPOINT_PRECISION == 1)
+ assertMsg(lhead.bytesPerElement == sizeof(T),
+ "4d grid element size doesn't match " << lhead.bytesPerElement << " vs "
+ << sizeof(T));
+
+ int fourthDim = 0;
+ gzread(gzf, &fourthDim, sizeof(fourthDim));
+
+ head.dimX = lhead.dimX;
+ head.dimY = lhead.dimY;
+ head.dimZ = lhead.dimZ;
+ head.dimT = fourthDim;
+ head.gridType = lhead.gridType;
+ }
+
+ if (readTslice < 0) {
+ assertMsg(head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() &&
+ head.dimZ == grid->getSizeZ(),
+ "grid dim doesn't match, " << Vec3(head.dimX, head.dimY, head.dimZ) << " vs "
+ << grid->getSize());
+ assertMsg(unifyGridType(head.gridType) == unifyGridType(grid->getType()),
+ "grid type doesn't match " << head.gridType << " vs " << grid->getType());
+
+ // read full 4d grid
+ assertMsg(head.dimT == grid->getSizeT(),
+ "grid dim4 doesn't match, " << head.dimT << " vs " << grid->getSize());
+
+ // can be too large - read in chunks
+# if FLOATINGPOINT_PRECISION != 1
+ Grid4d<T> temp(grid->getParent());
+ void *ptr = &(temp[0]);
+ for (int t = 0; t < head.dimT; ++t) {
+ gridReadConvert4d<T>(gzf, *grid, ptr, head.bytesPerElement, t);
+ }
+# else
+ for (int t = 0; t < head.dimT; ++t) {
+ void *ptr = &((*grid)[head.dimX * head.dimY * head.dimZ * t]);
+ gzread(gzf, ptr, sizeof(T) * head.dimX * head.dimY * head.dimZ * 1);
+ }
+# endif
+ }
+ else {
+ // read chosen slice only
+ assertMsg(head.dimX == slice->getSizeX() && head.dimY == slice->getSizeY() &&
+ head.dimZ == slice->getSizeZ(),
+ "grid dim doesn't match, " << Vec3(head.dimX, head.dimY, head.dimZ) << " vs "
+ << slice->getSize());
+ assertMsg(unifyGridType(head.gridType) == unifyGridType(slice->getType()),
+ "grid type doesn't match " << head.gridType << " vs " << slice->getType());
+
+# if FLOATINGPOINT_PRECISION != 1
+ errMsg("readGrid4dUni: NYI (2)"); // slice read not yet supported for double
+# else
+ assertMsg(slice, "No 3d slice grid data given");
+ assertMsg(readTslice < head.dimT,
+ "grid dim4 slice too large " << readTslice << " vs " << head.dimT);
+ void *ptr = &((*slice)[0]);
+ gzseek(gzf,
+ sizeof(T) * head.dimX * head.dimY * head.dimZ * readTslice + headerSize + 4,
+ SEEK_SET);
+ gzread(gzf, ptr, sizeof(T) * head.dimX * head.dimY * head.dimZ * 1);
+# endif
+ }
+ }
+ else {
+ debMsg("Unknown header!", 1);
+ }
+
+ if (!fileHandle) {
+ gzclose(gzf);
+ }
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+};
+void readGrid4dUniCleanup(void **fileHandle)
+{
+ gzFile gzf = NULL;
+ if (fileHandle) {
+ gzf = (gzFile)(*fileHandle);
+ gzclose(gzf);
+ *fileHandle = NULL;
+ }
+}
+
+template<class T> void writeGrid4dRaw(const string &name, Grid4d<T> *grid)
+{
+ debMsg("writing grid4d " << grid->getName() << " to raw file " << name, 1);
+
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf)
+ errMsg("writeGrid4dRaw: can't open file " << name);
+ gzwrite(gzf,
+ &((*grid)[0]),
+ sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ() * grid->getSizeT());
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+}
+
+template<class T> void readGrid4dRaw(const string &name, Grid4d<T> *grid)
+{
+ debMsg("reading grid4d " << grid->getName() << " from raw file " << name, 1);
+
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf)
+ errMsg("readGrid4dRaw: can't open file " << name);
+
+ IndexInt bytes = sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ() *
+ grid->getSizeT();
+ IndexInt readBytes = gzread(gzf, &((*grid)[0]), bytes);
+ assertMsg(bytes == readBytes,
+ "can't read raw file, stream length does not match, " << bytes << " vs " << readBytes);
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+}
+
+//*****************************************************************************
+// optional openvdb export
+
+#if OPENVDB == 1
+
+template<class T> void writeGridVDB(const string &name, Grid<T> *grid)
+{
+ debMsg("Writing grid " << grid->getName() << " to vdb file " << name << " not yet supported!",
+ 1);
+}
+
+template<class T> void readGridVDB(const string &name, Grid<T> *grid)
+{
+ debMsg("Reading grid " << grid->getName() << " from vdb file " << name << " not yet supported!",
+ 1);
+}
+
+template<> void writeGridVDB(const string &name, Grid<Real> *grid)
+{
+ debMsg("Writing real grid " << grid->getName() << " to vdb file " << name, 1);
+
+ // Create an empty floating-point grid with background value 0.
+ openvdb::initialize();
+ openvdb::FloatGrid::Ptr gridVDB = openvdb::FloatGrid::create();
+ gridVDB->setTransform(
+ openvdb::math::Transform::createLinearTransform(1. / grid->getSizeX())); // voxel size
+
+ // Get an accessor for coordinate-based access to voxels.
+ openvdb::FloatGrid::Accessor accessor = gridVDB->getAccessor();
+
+ // Identify the grid as a level set.
+ gridVDB->setGridClass(openvdb::GRID_FOG_VOLUME);
+
+ // Name the grid "density".
+ gridVDB->setName(grid->getName());
+
+ openvdb::io::File file(name);
+
+ FOR_IJK(*grid)
+ {
+ openvdb::Coord xyz(i, j, k);
+ accessor.setValue(xyz, (*grid)(i, j, k));
+ }
+
+ // Add the grid pointer to a container.
+ openvdb::GridPtrVec gridsVDB;
+ gridsVDB.push_back(gridVDB);
+
+ // Write out the contents of the container.
+ file.write(gridsVDB);
+ file.close();
+};
+
+template<> void readGridVDB(const string &name, Grid<Real> *grid)
+{
+ debMsg("Reading real grid " << grid->getName() << " from vdb file " << name, 1);
+
+ openvdb::initialize();
+ openvdb::io::File file(name);
+ file.open();
+
+ openvdb::GridBase::Ptr baseGrid;
+ for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName();
+ ++nameIter) {
+# ifndef BLENDER
+ // Read in only the grid we are interested in.
+ if (nameIter.gridName() == grid->getName()) {
+ baseGrid = file.readGrid(nameIter.gridName());
+ }
+ else {
+ debMsg("skipping grid " << nameIter.gridName(), 1);
+ }
+# else
+ // For Blender, skip name check and pick first grid from loop
+ baseGrid = file.readGrid(nameIter.gridName());
+ break;
+# endif
+ }
+ file.close();
+ openvdb::FloatGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::FloatGrid>(baseGrid);
+
+ openvdb::FloatGrid::Accessor accessor = gridVDB->getAccessor();
+
+ FOR_IJK(*grid)
+ {
+ openvdb::Coord xyz(i, j, k);
+ float v = accessor.getValue(xyz);
+ (*grid)(i, j, k) = v;
+ }
+};
+
+template<> void writeGridVDB(const string &name, Grid<Vec3> *grid)
+{
+ debMsg("Writing vec3 grid " << grid->getName() << " to vdb file " << name, 1);
+
+ openvdb::initialize();
+ openvdb::Vec3SGrid::Ptr gridVDB = openvdb::Vec3SGrid::create();
+ // note , warning - velocity content currently not scaled...
+ gridVDB->setTransform(
+ openvdb::math::Transform::createLinearTransform(1. / grid->getSizeX())); // voxel size
+ openvdb::Vec3SGrid::Accessor accessor = gridVDB->getAccessor();
+
+ // MAC or regular vec grid?
+ if (grid->getType() & GridBase::TypeMAC)
+ gridVDB->setGridClass(openvdb::GRID_STAGGERED);
+ else
+ gridVDB->setGridClass(openvdb::GRID_UNKNOWN);
+
+ gridVDB->setName(grid->getName());
+
+ openvdb::io::File file(name);
+ FOR_IJK(*grid)
+ {
+ openvdb::Coord xyz(i, j, k);
+ Vec3 v = (*grid)(i, j, k);
+ openvdb::Vec3f vo((float)v[0], (float)v[1], (float)v[2]);
+ accessor.setValue(xyz, vo);
+ }
+
+ openvdb::GridPtrVec gridsVDB;
+ gridsVDB.push_back(gridVDB);
+
+ file.write(gridsVDB);
+ file.close();
+};
+
+template<> void readGridVDB(const string &name, Grid<Vec3> *grid)
+{
+ debMsg("Reading vec3 grid " << grid->getName() << " from vdb file " << name, 1);
+
+ openvdb::initialize();
+ openvdb::io::File file(name);
+ file.open();
+
+ openvdb::GridBase::Ptr baseGrid;
+ for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName();
+ ++nameIter) {
+# ifndef BLENDER
+ // Read in only the grid we are interested in.
+ if (nameIter.gridName() == grid->getName()) {
+ baseGrid = file.readGrid(nameIter.gridName());
+ }
+ else {
+ debMsg("skipping grid " << nameIter.gridName(), 1);
+ }
+# else
+ // For Blender, skip name check and pick first grid from loop
+ baseGrid = file.readGrid(nameIter.gridName());
+ break;
+# endif
+ }
+ file.close();
+ openvdb::Vec3SGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::Vec3SGrid>(baseGrid);
+
+ openvdb::Vec3SGrid::Accessor accessor = gridVDB->getAccessor();
+
+ FOR_IJK(*grid)
+ {
+ openvdb::Coord xyz(i, j, k);
+ openvdb::Vec3f v = accessor.getValue(xyz);
+ (*grid)(i, j, k).x = (float)v[0];
+ (*grid)(i, j, k).y = (float)v[1];
+ (*grid)(i, j, k).z = (float)v[2];
+ }
+};
+
+#endif // OPENVDB==1
+
+//*****************************************************************************
+// npz file support (warning - read works, but write generates uncompressed npz; i.e. not
+// recommended for large volumes)
+
+template<class T> void writeGridNumpy(const string &name, Grid<T> *grid)
+{
+#if NO_ZLIB == 1
+ debMsg("file format not supported without zlib", 1);
+ return;
+#endif
+#if FLOATINGPOINT_PRECISION != 1
+ errMsg("writeGridNumpy: Double precision not yet supported");
+#endif
+
+ // find suffix to differentiate between npy <-> npz , TODO: check for actual "npy" string
+ std::string::size_type idx;
+ bool bUseNpz = false;
+ idx = name.rfind('.');
+ if (idx != std::string::npos) {
+ bUseNpz = name.substr(idx + 1) == "npz";
+ debMsg("Writing grid " << grid->getName() << " to npz file " << name, 1);
+ }
+ else {
+ debMsg("Writing grid " << grid->getName() << " to npy file " << name, 1);
+ }
+
+ // storage code
+ size_t uDim = 1;
+ if (grid->getType() & GridBase::TypeInt || grid->getType() & GridBase::TypeReal ||
+ grid->getType() & GridBase::TypeLevelset)
+ uDim = 1;
+ else if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC)
+ uDim = 3;
+ else
+ errMsg("writeGridNumpy: unknown element type");
+
+ const std::vector<size_t> shape = {static_cast<size_t>(grid->getSizeZ()),
+ static_cast<size_t>(grid->getSizeY()),
+ static_cast<size_t>(grid->getSizeX()),
+ uDim};
+
+ if (bUseNpz) {
+ // note, the following generates a zip file without compression
+ if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC) {
+ // cast to float* for export!
+ float *ptr = (float *)&((*grid)[0]);
+ cnpy::npz_save(name, "arr_0", ptr, shape, "w");
+ }
+ else {
+ T *ptr = &((*grid)[0]);
+ cnpy::npz_save(name, "arr_0", ptr, shape, "w");
+ }
+ }
+ else {
+ cnpy::npy_save(name, &grid[0], shape, "w");
+ }
+};
+
+template<class T> void readGridNumpy(const string &name, Grid<T> *grid)
+{
+#if NO_ZLIB == 1
+ debMsg("file format not supported without zlib", 1);
+ return;
+#endif
+#if FLOATINGPOINT_PRECISION != 1
+ errMsg("readGridNumpy: Double precision not yet supported");
+#endif
+
+ // find suffix to differentiate between npy <-> npz
+ std::string::size_type idx;
+ bool bUseNpz = false;
+ idx = name.rfind('.');
+ if (idx != std::string::npos) {
+ bUseNpz = name.substr(idx + 1) == "npz";
+ debMsg("Reading grid " << grid->getName() << " as npz file " << name, 1);
+ }
+ else {
+ debMsg("Reading grid " << grid->getName() << " as npy file " << name, 1);
+ }
+
+ cnpy::NpyArray gridArr;
+ if (bUseNpz) {
+ cnpy::npz_t fNpz = cnpy::npz_load(name);
+ gridArr = fNpz["arr_0"];
+ }
+ else {
+ gridArr = cnpy::npy_load(name);
+ }
+
+ // Check the file meta information
+ assertMsg(gridArr.shape[2] == grid->getSizeX() && gridArr.shape[1] == grid->getSizeY() &&
+ gridArr.shape[0] == grid->getSizeZ(),
+ "grid dim doesn't match, "
+ << Vec3(gridArr.shape[2], gridArr.shape[1], gridArr.shape[0]) << " vs "
+ << grid->getSize());
+ size_t uDim = 1;
+ if (grid->getType() & GridBase::TypeInt || grid->getType() & GridBase::TypeReal ||
+ grid->getType() & GridBase::TypeLevelset)
+ uDim = 1;
+ else if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC)
+ uDim = 3;
+ else
+ errMsg("readGridNumpy: unknown element type");
+ assertMsg(gridArr.shape[3] == uDim,
+ "grid data dim doesn't match, " << gridArr.shape[3] << " vs " << uDim);
+
+ if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC) {
+ // treated as float* for export , thus consider 3 elements
+ assertMsg(3 * gridArr.word_size == sizeof(T),
+ "vec3 grid data size doesn't match, " << 3 * gridArr.word_size << " vs "
+ << sizeof(T));
+ }
+ else {
+ assertMsg(gridArr.word_size == sizeof(T),
+ "grid data size doesn't match, " << gridArr.word_size << " vs " << sizeof(T));
+ }
+
+ // copy back, TODO: beautify...
+ memcpy(&((*grid)[0]),
+ gridArr.data<T>(),
+ sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ());
+};
+
+// adopted from getUniFileSize
+void getNpzFileSize(
+ const string &name, int &x, int &y, int &z, int *t = NULL, std::string *info = NULL)
+{
+ x = y = z = 0;
+#if NO_ZLIB != 1
+ debMsg("file format not supported without zlib", 1);
+ return;
+#endif
+#if FLOATINGPOINT_PRECISION != 1
+ errMsg("getNpzFileSize: Double precision not yet supported");
+#endif
+ // find suffix to differentiate between npy <-> npz
+ cnpy::NpyArray gridArr;
+ cnpy::npz_t fNpz = cnpy::npz_load(name);
+ gridArr = fNpz["arr_0"];
+
+ z = gridArr.shape[0];
+ y = gridArr.shape[1];
+ x = gridArr.shape[2];
+ if (t)
+ (*t) = 0; // unused for now
+}
+Vec3 getNpzFileSize(const string &name)
+{
+ int x, y, z;
+ getNpzFileSize(name, x, y, z);
+ return Vec3(Real(x), Real(y), Real(z));
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getNpzFileSize", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const string &name = _args.get<string>("name", 0, &_lock);
+ _retval = toPy(getNpzFileSize(name));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getNpzFileSize", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getNpzFileSize", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getNpzFileSize("", "getNpzFileSize", _W_2);
+extern "C" {
+void PbRegister_getNpzFileSize()
+{
+ KEEP_UNUSED(_RP_getNpzFileSize);
+}
+}
+
+//*****************************************************************************
+// helper functions
+
+void quantizeReal(Real &v, const Real step)
+{
+ int q = int(v / step + step * 0.5);
+ double qd = q * (double)step;
+ v = (Real)qd;
+}
+struct knQuantize : public KernelBase {
+ knQuantize(Grid<Real> &grid, Real step) : KernelBase(&grid, 0), grid(grid), step(step)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<Real> &grid, Real step) const
+ {
+ quantizeReal(grid(idx), step);
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<Real> type0;
+ inline Real &getArg1()
+ {
+ return step;
+ }
+ typedef Real type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knQuantize ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, grid, step);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Real> &grid;
+ Real step;
+};
+void quantizeGrid(Grid<Real> &grid, Real step)
+{
+ knQuantize(grid, step);
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "quantizeGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &grid = *_args.getPtr<Grid<Real>>("grid", 0, &_lock);
+ Real step = _args.get<Real>("step", 1, &_lock);
+ _retval = getPyNone();
+ quantizeGrid(grid, step);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "quantizeGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("quantizeGrid", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_quantizeGrid("", "quantizeGrid", _W_3);
+extern "C" {
+void PbRegister_quantizeGrid()
+{
+ KEEP_UNUSED(_RP_quantizeGrid);
+}
+}
+
+struct knQuantizeVec3 : public KernelBase {
+ knQuantizeVec3(Grid<Vec3> &grid, Real step) : KernelBase(&grid, 0), grid(grid), step(step)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<Vec3> &grid, Real step) const
+ {
+ for (int c = 0; c < 3; ++c)
+ quantizeReal(grid(idx)[c], step);
+ }
+ inline Grid<Vec3> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<Vec3> type0;
+ inline Real &getArg1()
+ {
+ return step;
+ }
+ typedef Real type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knQuantizeVec3 ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, grid, step);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Vec3> &grid;
+ Real step;
+};
+void quantizeGridVec3(Grid<Vec3> &grid, Real step)
+{
+ knQuantizeVec3(grid, step);
+}
+static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "quantizeGridVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &grid = *_args.getPtr<Grid<Vec3>>("grid", 0, &_lock);
+ Real step = _args.get<Real>("step", 1, &_lock);
+ _retval = getPyNone();
+ quantizeGridVec3(grid, step);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "quantizeGridVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("quantizeGridVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_quantizeGridVec3("", "quantizeGridVec3", _W_4);
+extern "C" {
+void PbRegister_quantizeGridVec3()
+{
+ KEEP_UNUSED(_RP_quantizeGridVec3);
+}
+}
+
+// explicit instantiation
+template void writeGridRaw<int>(const string &name, Grid<int> *grid);
+template void writeGridRaw<Real>(const string &name, Grid<Real> *grid);
+template void writeGridRaw<Vec3>(const string &name, Grid<Vec3> *grid);
+template void writeGridUni<int>(const string &name, Grid<int> *grid);
+template void writeGridUni<Real>(const string &name, Grid<Real> *grid);
+template void writeGridUni<Vec3>(const string &name, Grid<Vec3> *grid);
+template void writeGridVol<int>(const string &name, Grid<int> *grid);
+template void writeGridVol<Vec3>(const string &name, Grid<Vec3> *grid);
+template void writeGridTxt<int>(const string &name, Grid<int> *grid);
+template void writeGridTxt<Real>(const string &name, Grid<Real> *grid);
+template void writeGridTxt<Vec3>(const string &name, Grid<Vec3> *grid);
+
+template void readGridRaw<int>(const string &name, Grid<int> *grid);
+template void readGridRaw<Real>(const string &name, Grid<Real> *grid);
+template void readGridRaw<Vec3>(const string &name, Grid<Vec3> *grid);
+template void readGridUni<int>(const string &name, Grid<int> *grid);
+template void readGridUni<Real>(const string &name, Grid<Real> *grid);
+template void readGridUni<Vec3>(const string &name, Grid<Vec3> *grid);
+template void readGridVol<int>(const string &name, Grid<int> *grid);
+template void readGridVol<Vec3>(const string &name, Grid<Vec3> *grid);
+
+template void readGrid4dUni<int>(
+ const string &name, Grid4d<int> *grid, int readTslice, Grid4d<int> *slice, void **fileHandle);
+template void readGrid4dUni<Real>(const string &name,
+ Grid4d<Real> *grid,
+ int readTslice,
+ Grid4d<Real> *slice,
+ void **fileHandle);
+template void readGrid4dUni<Vec3>(const string &name,
+ Grid4d<Vec3> *grid,
+ int readTslice,
+ Grid4d<Vec3> *slice,
+ void **fileHandle);
+template void readGrid4dUni<Vec4>(const string &name,
+ Grid4d<Vec4> *grid,
+ int readTslice,
+ Grid4d<Vec4> *slice,
+ void **fileHandle);
+template void writeGrid4dUni<int>(const string &name, Grid4d<int> *grid);
+template void writeGrid4dUni<Real>(const string &name, Grid4d<Real> *grid);
+template void writeGrid4dUni<Vec3>(const string &name, Grid4d<Vec3> *grid);
+template void writeGrid4dUni<Vec4>(const string &name, Grid4d<Vec4> *grid);
+
+template void readGrid4dRaw<int>(const string &name, Grid4d<int> *grid);
+template void readGrid4dRaw<Real>(const string &name, Grid4d<Real> *grid);
+template void readGrid4dRaw<Vec3>(const string &name, Grid4d<Vec3> *grid);
+template void readGrid4dRaw<Vec4>(const string &name, Grid4d<Vec4> *grid);
+template void writeGrid4dRaw<int>(const string &name, Grid4d<int> *grid);
+template void writeGrid4dRaw<Real>(const string &name, Grid4d<Real> *grid);
+template void writeGrid4dRaw<Vec3>(const string &name, Grid4d<Vec3> *grid);
+template void writeGrid4dRaw<Vec4>(const string &name, Grid4d<Vec4> *grid);
+
+template void writeGridNumpy<int>(const string &name, Grid<int> *grid);
+template void writeGridNumpy<Real>(const string &name, Grid<Real> *grid);
+template void writeGridNumpy<Vec3>(const string &name, Grid<Vec3> *grid);
+template void readGridNumpy<int>(const string &name, Grid<int> *grid);
+template void readGridNumpy<Real>(const string &name, Grid<Real> *grid);
+template void readGridNumpy<Vec3>(const string &name, Grid<Vec3> *grid);
+
+#if OPENVDB == 1
+template void writeGridVDB<int>(const string &name, Grid<int> *grid);
+template void writeGridVDB<Vec3>(const string &name, Grid<Vec3> *grid);
+template void writeGridVDB<Real>(const string &name, Grid<Real> *grid);
+
+template void readGridVDB<int>(const string &name, Grid<int> *grid);
+template void readGridVDB<Vec3>(const string &name, Grid<Vec3> *grid);
+template void readGridVDB<Real>(const string &name, Grid<Real> *grid);
+#endif // OPENVDB==1
+
+} // namespace Manta
+
+namespace Manta {
+
+}
diff --git a/extern/mantaflow/preprocessed/fileio/iomeshes.cpp b/extern/mantaflow/preprocessed/fileio/iomeshes.cpp
new file mode 100644
index 00000000000..fc57e2a8c2b
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fileio/iomeshes.cpp
@@ -0,0 +1,490 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#if NO_ZLIB != 1
+extern "C" {
+# include <zlib.h>
+}
+#endif
+
+#include "mantaio.h"
+#include "grid.h"
+#include "mesh.h"
+#include "vortexsheet.h"
+#include <cstring>
+
+using namespace std;
+
+namespace Manta {
+
+static const int STR_LEN_PDATA = 256;
+
+//! mdata uni header, v3 (similar to grid header and mdata header)
+typedef struct {
+ int dim; // number of vertices
+ int dimX, dimY, dimZ; // underlying solver resolution (all data in local coordinates!)
+ int elementType, bytesPerElement; // type id and byte size
+ char info[STR_LEN_PDATA]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+} UniMeshHeader;
+
+//*****************************************************************************
+// conversion functions for double precision
+// (note - uni files always store single prec. values)
+//*****************************************************************************
+
+#if NO_ZLIB != 1
+
+template<class T>
+void mdataConvertWrite(gzFile &gzf, MeshDataImpl<T> &mdata, void *ptr, UniMeshHeader &head)
+{
+ errMsg("mdataConvertWrite: unknown type, not yet supported");
+}
+
+template<>
+void mdataConvertWrite(gzFile &gzf, MeshDataImpl<int> &mdata, void *ptr, UniMeshHeader &head)
+{
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ gzwrite(gzf, &mdata[0], sizeof(int) * head.dim);
+}
+template<>
+void mdataConvertWrite(gzFile &gzf, MeshDataImpl<double> &mdata, void *ptr, UniMeshHeader &head)
+{
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < mdata.size(); ++i, ++ptrf) {
+ *ptrf = (float)mdata[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float) * head.dim);
+}
+template<>
+void mdataConvertWrite(gzFile &gzf, MeshDataImpl<Vec3> &mdata, void *ptr, UniMeshHeader &head)
+{
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < mdata.size(); ++i) {
+ for (int c = 0; c < 3; ++c) {
+ *ptrf = (float)mdata[i][c];
+ ptrf++;
+ }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) * head.dim);
+}
+
+template<class T>
+void mdataReadConvert(gzFile &gzf, MeshDataImpl<T> &grid, void *ptr, int bytesPerElement)
+{
+ errMsg("mdataReadConvert: unknown mdata type, not yet supported");
+}
+
+template<>
+void mdataReadConvert<int>(gzFile &gzf, MeshDataImpl<int> &mdata, void *ptr, int bytesPerElement)
+{
+ gzread(gzf, ptr, sizeof(int) * mdata.size());
+ assertMsg(bytesPerElement == sizeof(int),
+ "mdata element size doesn't match " << bytesPerElement << " vs " << sizeof(int));
+ // int dont change in double precision mode - copy over
+ memcpy(&(mdata[0]), ptr, sizeof(int) * mdata.size());
+}
+
+template<>
+void mdataReadConvert<double>(gzFile &gzf,
+ MeshDataImpl<double> &mdata,
+ void *ptr,
+ int bytesPerElement)
+{
+ gzread(gzf, ptr, sizeof(float) * mdata.size());
+ assertMsg(bytesPerElement == sizeof(float),
+ "mdata element size doesn't match " << bytesPerElement << " vs " << sizeof(float));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < mdata.size(); ++i, ++ptrf) {
+ mdata[i] = double(*ptrf);
+ }
+}
+
+template<>
+void mdataReadConvert<Vec3>(gzFile &gzf, MeshDataImpl<Vec3> &mdata, void *ptr, int bytesPerElement)
+{
+ gzread(gzf, ptr, sizeof(Vector3D<float>) * mdata.size());
+ assertMsg(bytesPerElement == sizeof(Vector3D<float>),
+ "mdata element size doesn't match " << bytesPerElement << " vs "
+ << sizeof(Vector3D<float>));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < mdata.size(); ++i) {
+ Vec3 v;
+ for (int c = 0; c < 3; ++c) {
+ v[c] = double(*ptrf);
+ ptrf++;
+ }
+ mdata[i] = v;
+ }
+}
+
+#endif // NO_ZLIB!=1
+
+//*****************************************************************************
+// mesh data
+//*****************************************************************************
+
+void readBobjFile(const string &name, Mesh *mesh, bool append)
+{
+ debMsg("reading mesh file " << name, 1);
+ if (!append)
+ mesh->clear();
+ else
+ errMsg("readBobj: append not yet implemented!");
+
+#if NO_ZLIB != 1
+ const Real dx = mesh->getParent()->getDx();
+ const Vec3 gs = toVec3(mesh->getParent()->getGridSize());
+
+ gzFile gzf = gzopen(name.c_str(), "rb1"); // do some compression
+ if (!gzf)
+ errMsg("readBobj: unable to open file");
+
+ // read vertices
+ int num = 0;
+ gzread(gzf, &num, sizeof(int));
+ mesh->resizeNodes(num);
+ debMsg("read mesh , verts " << num, 1);
+ for (int i = 0; i < num; i++) {
+ Vector3D<float> pos;
+ gzread(gzf, &pos.value[0], sizeof(float) * 3);
+ mesh->nodes(i).pos = toVec3(pos);
+
+ // convert to grid space
+ mesh->nodes(i).pos /= dx;
+ mesh->nodes(i).pos += gs * 0.5;
+ }
+
+ // normals
+ num = 0;
+ gzread(gzf, &num, sizeof(int));
+ for (int i = 0; i < num; i++) {
+ Vector3D<float> pos;
+ gzread(gzf, &pos.value[0], sizeof(float) * 3);
+ mesh->nodes(i).normal = toVec3(pos);
+ }
+
+ // read tris
+ num = 0;
+ gzread(gzf, &num, sizeof(int));
+ mesh->resizeTris(num);
+ for (int t = 0; t < num; t++) {
+ for (int j = 0; j < 3; j++) {
+ int trip = 0;
+ gzread(gzf, &trip, sizeof(int));
+ mesh->tris(t).c[j] = trip;
+ }
+ }
+ // note - vortex sheet info ignored for now... (see writeBobj)
+ gzclose(gzf);
+ debMsg("read mesh , triangles " << mesh->numTris() << ", vertices " << mesh->numNodes() << " ",
+ 1);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+}
+
+void writeBobjFile(const string &name, Mesh *mesh)
+{
+ debMsg("writing mesh file " << name, 1);
+#if NO_ZLIB != 1
+ const Real dx = mesh->getParent()->getDx();
+ const Vec3i gs = mesh->getParent()->getGridSize();
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf)
+ errMsg("writeBobj: unable to open file");
+
+ // write vertices
+ int numVerts = mesh->numNodes();
+ gzwrite(gzf, &numVerts, sizeof(int));
+ for (int i = 0; i < numVerts; i++) {
+ Vector3D<float> pos = toVec3f(mesh->nodes(i).pos);
+ // normalize to unit cube around 0
+ pos -= toVec3f(gs) * 0.5;
+ pos *= dx;
+ gzwrite(gzf, &pos.value[0], sizeof(float) * 3);
+ }
+
+ // normals
+ mesh->computeVertexNormals();
+ gzwrite(gzf, &numVerts, sizeof(int));
+ for (int i = 0; i < numVerts; i++) {
+ Vector3D<float> pos = toVec3f(mesh->nodes(i).normal);
+ gzwrite(gzf, &pos.value[0], sizeof(float) * 3);
+ }
+
+ // write tris
+ int numTris = mesh->numTris();
+ gzwrite(gzf, &numTris, sizeof(int));
+ for (int t = 0; t < numTris; t++) {
+ for (int j = 0; j < 3; j++) {
+ int trip = mesh->tris(t).c[j];
+ gzwrite(gzf, &trip, sizeof(int));
+ }
+ }
+
+ // per vertex smoke densities
+ if (mesh->getType() == Mesh::TypeVortexSheet) {
+ VortexSheetMesh *vmesh = (VortexSheetMesh *)mesh;
+ int densId[4] = {0, 'v', 'd', 'e'};
+ gzwrite(gzf, &densId[0], sizeof(int) * 4);
+
+ // compute densities
+ vector<float> triDensity(numTris);
+ for (int tri = 0; tri < numTris; tri++) {
+ Real area = vmesh->getFaceArea(tri);
+ if (area > 0)
+ triDensity[tri] = vmesh->sheet(tri).smokeAmount;
+ }
+
+ // project triangle data to vertex
+ vector<int> triPerVertex(numVerts);
+ vector<float> density(numVerts);
+ for (int tri = 0; tri < numTris; tri++) {
+ for (int c = 0; c < 3; c++) {
+ int vertex = mesh->tris(tri).c[c];
+ density[vertex] += triDensity[tri];
+ triPerVertex[vertex]++;
+ }
+ }
+
+ // averaged smoke densities
+ for (int point = 0; point < numVerts; point++) {
+ float dens = 0;
+ if (triPerVertex[point] > 0)
+ dens = density[point] / triPerVertex[point];
+ gzwrite(gzf, &dens, sizeof(float));
+ }
+ }
+
+ // vertex flags
+ if (mesh->getType() == Mesh::TypeVortexSheet) {
+ int Id[4] = {0, 'v', 'x', 'f'};
+ gzwrite(gzf, &Id[0], sizeof(int) * 4);
+
+ // averaged smoke densities
+ for (int point = 0; point < numVerts; point++) {
+ float alpha = (mesh->nodes(point).flags & Mesh::NfMarked) ? 1 : 0;
+ gzwrite(gzf, &alpha, sizeof(float));
+ }
+ }
+
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+}
+
+void readObjFile(const std::string &name, Mesh *mesh, bool append)
+{
+ ifstream ifs(name.c_str());
+
+ if (!ifs.good())
+ errMsg("can't open file '" + name + "'");
+
+ if (!append)
+ mesh->clear();
+ int nodebase = mesh->numNodes();
+ int cnt = nodebase;
+ while (ifs.good() && !ifs.eof()) {
+ string id;
+ ifs >> id;
+
+ if (id[0] == '#') {
+ // comment
+ getline(ifs, id);
+ continue;
+ }
+ if (id == "vt") {
+ // tex coord, ignore
+ }
+ else if (id == "vn") {
+ // normals
+ if (!mesh->numNodes())
+ errMsg("invalid amount of nodes");
+ Node n = mesh->nodes(cnt);
+ ifs >> n.normal.x >> n.normal.y >> n.normal.z;
+ cnt++;
+ }
+ else if (id == "v") {
+ // vertex
+ Node n;
+ ifs >> n.pos.x >> n.pos.y >> n.pos.z;
+ mesh->addNode(n);
+ }
+ else if (id == "g") {
+ // group
+ string group;
+ ifs >> group;
+ }
+ else if (id == "f") {
+ // face
+ string face;
+ Triangle t;
+ for (int i = 0; i < 3; i++) {
+ ifs >> face;
+ if (face.find('/') != string::npos)
+ face = face.substr(0, face.find('/')); // ignore other indices
+ int idx = atoi(face.c_str()) - 1;
+ if (idx < 0)
+ errMsg("invalid face encountered");
+ idx += nodebase;
+ t.c[i] = idx;
+ }
+ mesh->addTri(t);
+ }
+ else {
+ // whatever, ignore
+ }
+ // kill rest of line
+ getline(ifs, id);
+ }
+ ifs.close();
+}
+
+// write regular .obj file, in line with bobj.gz output (but only verts & tris for now)
+void writeObjFile(const string &name, Mesh *mesh)
+{
+ const Real dx = mesh->getParent()->getDx();
+ const Vec3i gs = mesh->getParent()->getGridSize();
+
+ ofstream ofs(name.c_str());
+ if (!ofs.good())
+ errMsg("writeObjFile: can't open file " << name);
+
+ ofs << "o MantaMesh\n";
+
+ // write vertices
+ int numVerts = mesh->numNodes();
+ for (int i = 0; i < numVerts; i++) {
+ Vector3D<float> pos = toVec3f(mesh->nodes(i).pos);
+ // normalize to unit cube around 0
+ pos -= toVec3f(gs) * 0.5;
+ pos *= dx;
+ ofs << "v " << pos.value[0] << " " << pos.value[1] << " " << pos.value[2] << " "
+ << "\n";
+ }
+
+ // write normals
+ for (int i = 0; i < numVerts; i++) {
+ Vector3D<float> n = toVec3f(mesh->nodes(i).normal);
+ // normalize to unit cube around 0
+ ofs << "vn " << n.value[0] << " " << n.value[1] << " " << n.value[2] << " "
+ << "\n";
+ }
+
+ // write tris
+ int numTris = mesh->numTris();
+ for (int t = 0; t < numTris; t++) {
+ ofs << "f " << (mesh->tris(t).c[0] + 1) << " " << (mesh->tris(t).c[1] + 1) << " "
+ << (mesh->tris(t).c[2] + 1) << " "
+ << "\n";
+ }
+
+ ofs.close();
+}
+
+template<class T> void readMdataUni(const std::string &name, MeshDataImpl<T> *mdata)
+{
+ debMsg("reading mesh data " << mdata->getName() << " from uni file " << name, 1);
+
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf)
+ errMsg("can't open file " << name);
+
+ char ID[5] = {0, 0, 0, 0, 0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "MD01")) {
+ UniMeshHeader head;
+ assertMsg(gzread(gzf, &head, sizeof(UniMeshHeader)) == sizeof(UniMeshHeader),
+ "can't read file, no header present");
+ assertMsg(head.dim == mdata->size(), "mdata size doesn't match");
+# if FLOATINGPOINT_PRECISION != 1
+ MeshDataImpl<T> temp(mdata->getParent());
+ temp.resize(mdata->size());
+ mdataReadConvert<T>(gzf, *mdata, &(temp[0]), head.bytesPerElement);
+# else
+ assertMsg(((head.bytesPerElement == sizeof(T)) && (head.elementType == 1)),
+ "mdata type doesn't match");
+ IndexInt bytes = sizeof(T) * head.dim;
+ IndexInt readBytes = gzread(gzf, &(mdata->get(0)), sizeof(T) * head.dim);
+ assertMsg(bytes == readBytes,
+ "can't read uni file, stream length does not match, " << bytes << " vs "
+ << readBytes);
+# endif
+ }
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+}
+
+template<class T> void writeMdataUni(const std::string &name, MeshDataImpl<T> *mdata)
+{
+ debMsg("writing mesh data " << mdata->getName() << " to uni file " << name, 1);
+
+#if NO_ZLIB != 1
+ char ID[5] = "MD01";
+ UniMeshHeader head;
+ head.dim = mdata->size();
+ head.bytesPerElement = sizeof(T);
+ head.elementType = 1; // 1 for mesh data, todo - add sub types?
+ snprintf(head.info, STR_LEN_PDATA, "%s", buildInfoString().c_str());
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf)
+ errMsg("can't open file " << name);
+ gzwrite(gzf, ID, 4);
+
+# if FLOATINGPOINT_PRECISION != 1
+ // always write float values, even if compiled with double precision (as for grids)
+ MeshDataImpl<T> temp(mdata->getParent());
+ temp.resize(mdata->size());
+ mdataConvertWrite(gzf, *mdata, &(temp[0]), head);
+# else
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ gzwrite(gzf, &(mdata->get(0)), sizeof(T) * head.dim);
+# endif
+ gzclose(gzf);
+
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+};
+
+// explicit instantiation
+template void writeMdataUni<int>(const std::string &name, MeshDataImpl<int> *mdata);
+template void writeMdataUni<Real>(const std::string &name, MeshDataImpl<Real> *mdata);
+template void writeMdataUni<Vec3>(const std::string &name, MeshDataImpl<Vec3> *mdata);
+template void readMdataUni<int>(const std::string &name, MeshDataImpl<int> *mdata);
+template void readMdataUni<Real>(const std::string &name, MeshDataImpl<Real> *mdata);
+template void readMdataUni<Vec3>(const std::string &name, MeshDataImpl<Vec3> *mdata);
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/fileio/ioparticles.cpp b/extern/mantaflow/preprocessed/fileio/ioparticles.cpp
new file mode 100644
index 00000000000..432cbc9f100
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fileio/ioparticles.cpp
@@ -0,0 +1,342 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstring>
+#if NO_ZLIB != 1
+extern "C" {
+# include <zlib.h>
+}
+#endif
+
+#include "mantaio.h"
+#include "grid.h"
+#include "particle.h"
+#include "vector4d.h"
+#include "grid4d.h"
+
+using namespace std;
+
+namespace Manta {
+
+static const int STR_LEN_PDATA = 256;
+
+//! pdata uni header, v3 (similar to grid header)
+typedef struct {
+ int dim; // number of partilces
+ int dimX, dimY, dimZ; // underlying solver resolution (all data in local coordinates!)
+ int elementType, bytesPerElement; // type id and byte size
+ char info[STR_LEN_PDATA]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+} UniPartHeader;
+
+//*****************************************************************************
+// conversion functions for double precision
+// (note - uni files always store single prec. values)
+//*****************************************************************************
+
+#if NO_ZLIB != 1
+
+template<class T>
+void pdataConvertWrite(gzFile &gzf, ParticleDataImpl<T> &pdata, void *ptr, UniPartHeader &head)
+{
+ errMsg("pdataConvertWrite: unknown type, not yet supported");
+}
+
+template<>
+void pdataConvertWrite(gzFile &gzf, ParticleDataImpl<int> &pdata, void *ptr, UniPartHeader &head)
+{
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &pdata[0], sizeof(int) * head.dim);
+}
+template<>
+void pdataConvertWrite(gzFile &gzf,
+ ParticleDataImpl<double> &pdata,
+ void *ptr,
+ UniPartHeader &head)
+{
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < pdata.size(); ++i, ++ptrf) {
+ *ptrf = (float)pdata[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float) * head.dim);
+}
+template<>
+void pdataConvertWrite(gzFile &gzf, ParticleDataImpl<Vec3> &pdata, void *ptr, UniPartHeader &head)
+{
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < pdata.size(); ++i) {
+ for (int c = 0; c < 3; ++c) {
+ *ptrf = (float)pdata[i][c];
+ ptrf++;
+ }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) * head.dim);
+}
+
+template<class T>
+void pdataReadConvert(gzFile &gzf, ParticleDataImpl<T> &grid, void *ptr, int bytesPerElement)
+{
+ errMsg("pdataReadConvert: unknown pdata type, not yet supported");
+}
+
+template<>
+void pdataReadConvert<int>(gzFile &gzf,
+ ParticleDataImpl<int> &pdata,
+ void *ptr,
+ int bytesPerElement)
+{
+ gzread(gzf, ptr, sizeof(int) * pdata.size());
+ assertMsg(bytesPerElement == sizeof(int),
+ "pdata element size doesn't match " << bytesPerElement << " vs " << sizeof(int));
+ // int dont change in double precision mode - copy over
+ memcpy(&(pdata[0]), ptr, sizeof(int) * pdata.size());
+}
+
+template<>
+void pdataReadConvert<double>(gzFile &gzf,
+ ParticleDataImpl<double> &pdata,
+ void *ptr,
+ int bytesPerElement)
+{
+ gzread(gzf, ptr, sizeof(float) * pdata.size());
+ assertMsg(bytesPerElement == sizeof(float),
+ "pdata element size doesn't match " << bytesPerElement << " vs " << sizeof(float));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < pdata.size(); ++i, ++ptrf) {
+ pdata[i] = double(*ptrf);
+ }
+}
+
+template<>
+void pdataReadConvert<Vec3>(gzFile &gzf,
+ ParticleDataImpl<Vec3> &pdata,
+ void *ptr,
+ int bytesPerElement)
+{
+ gzread(gzf, ptr, sizeof(Vector3D<float>) * pdata.size());
+ assertMsg(bytesPerElement == sizeof(Vector3D<float>),
+ "pdata element size doesn't match " << bytesPerElement << " vs "
+ << sizeof(Vector3D<float>));
+ float *ptrf = (float *)ptr;
+ for (int i = 0; i < pdata.size(); ++i) {
+ Vec3 v;
+ for (int c = 0; c < 3; ++c) {
+ v[c] = double(*ptrf);
+ ptrf++;
+ }
+ pdata[i] = v;
+ }
+}
+
+#endif // NO_ZLIB!=1
+
+//*****************************************************************************
+// particles and particle data
+//*****************************************************************************
+
+static const int PartSysSize = sizeof(Vector3D<float>) + sizeof(int);
+
+void writeParticlesUni(const std::string &name, const BasicParticleSystem *parts)
+{
+ debMsg("writing particles " << parts->getName() << " to uni file " << name, 1);
+
+#if NO_ZLIB != 1
+ char ID[5] = "PB02";
+ UniPartHeader head;
+ head.dim = parts->size();
+ Vec3i gridSize = parts->getParent()->getGridSize();
+ head.dimX = gridSize.x;
+ head.dimY = gridSize.y;
+ head.dimZ = gridSize.z;
+ head.bytesPerElement = PartSysSize;
+ head.elementType = 0; // 0 for base data
+ snprintf(head.info, STR_LEN_PDATA, "%s", buildInfoString().c_str());
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf)
+ errMsg("can't open file " << name);
+
+ gzwrite(gzf, ID, 4);
+# if FLOATINGPOINT_PRECISION != 1
+ // warning - hard coded conversion of byte size here...
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ for (int i = 0; i < parts->size(); ++i) {
+ Vector3D<float> pos = toVec3f((*parts)[i].pos);
+ int flag = (*parts)[i].flag;
+ gzwrite(gzf, &pos, sizeof(Vector3D<float>));
+ gzwrite(gzf, &flag, sizeof(int));
+ }
+# else
+ assertMsg(sizeof(BasicParticleData) == PartSysSize, "particle data size doesn't match");
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &((*parts)[0]), PartSysSize * head.dim);
+# endif
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+};
+
+void readParticlesUni(const std::string &name, BasicParticleSystem *parts)
+{
+ debMsg("reading particles " << parts->getName() << " from uni file " << name, 1);
+
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf)
+ errMsg("can't open file " << name);
+
+ char ID[5] = {0, 0, 0, 0, 0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "PB01")) {
+ errMsg("particle uni file format v01 not supported anymore");
+ }
+ else if (!strcmp(ID, "PB02")) {
+ // current file format
+ UniPartHeader head;
+ assertMsg(gzread(gzf, &head, sizeof(UniPartHeader)) == sizeof(UniPartHeader),
+ "can't read file, no header present");
+ assertMsg(((head.bytesPerElement == PartSysSize) && (head.elementType == 0)),
+ "particle type doesn't match");
+
+ // re-allocate all data
+ parts->resizeAll(head.dim);
+
+ assertMsg(head.dim == parts->size(), "particle size doesn't match");
+# if FLOATINGPOINT_PRECISION != 1
+ for (int i = 0; i < parts->size(); ++i) {
+ Vector3D<float> pos;
+ int flag;
+ gzread(gzf, &pos, sizeof(Vector3D<float>));
+ gzread(gzf, &flag, sizeof(int));
+ (*parts)[i].pos = toVec3d(pos);
+ (*parts)[i].flag = flag;
+ }
+# else
+ assertMsg(sizeof(BasicParticleData) == PartSysSize, "particle data size doesn't match");
+ IndexInt bytes = PartSysSize * head.dim;
+ IndexInt readBytes = gzread(gzf, &(parts->getData()[0]), bytes);
+ assertMsg(bytes == readBytes,
+ "can't read uni file, stream length does not match, " << bytes << " vs "
+ << readBytes);
+# endif
+
+ parts->transformPositions(Vec3i(head.dimX, head.dimY, head.dimZ),
+ parts->getParent()->getGridSize());
+ }
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+};
+
+template<class T> void writePdataUni(const std::string &name, ParticleDataImpl<T> *pdata)
+{
+ debMsg("writing particle data " << pdata->getName() << " to uni file " << name, 1);
+
+#if NO_ZLIB != 1
+ char ID[5] = "PD01";
+ UniPartHeader head;
+ head.dim = pdata->size();
+ Vec3i gridSize = pdata->getParent()->getGridSize();
+ head.dimX = gridSize.x;
+ head.dimY = gridSize.y;
+ head.dimZ = gridSize.z;
+ head.bytesPerElement = sizeof(T);
+ head.elementType = 1; // 1 for particle data, todo - add sub types?
+ snprintf(head.info, STR_LEN_PDATA, "%s", buildInfoString().c_str());
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf)
+ errMsg("can't open file " << name);
+ gzwrite(gzf, ID, 4);
+
+# if FLOATINGPOINT_PRECISION != 1
+ // always write float values, even if compiled with double precision (as for grids)
+ ParticleDataImpl<T> temp(pdata->getParent());
+ temp.resize(pdata->size());
+ pdataConvertWrite(gzf, *pdata, &(temp[0]), head);
+# else
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &(pdata->get(0)), sizeof(T) * head.dim);
+# endif
+ gzclose(gzf);
+
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+};
+
+template<class T> void readPdataUni(const std::string &name, ParticleDataImpl<T> *pdata)
+{
+ debMsg("reading particle data " << pdata->getName() << " from uni file " << name, 1);
+
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf)
+ errMsg("can't open file " << name);
+
+ char ID[5] = {0, 0, 0, 0, 0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "PD01")) {
+ UniPartHeader head;
+ assertMsg(gzread(gzf, &head, sizeof(UniPartHeader)) == sizeof(UniPartHeader),
+ "can't read file, no header present");
+ assertMsg(head.dim == pdata->size(), "pdata size doesn't match");
+# if FLOATINGPOINT_PRECISION != 1
+ ParticleDataImpl<T> temp(pdata->getParent());
+ temp.resize(pdata->size());
+ pdataReadConvert<T>(gzf, *pdata, &(temp[0]), head.bytesPerElement);
+# else
+ assertMsg(((head.bytesPerElement == sizeof(T)) && (head.elementType == 1)),
+ "pdata type doesn't match");
+ IndexInt bytes = sizeof(T) * head.dim;
+ IndexInt readBytes = gzread(gzf, &(pdata->get(0)), sizeof(T) * head.dim);
+ assertMsg(bytes == readBytes,
+ "can't read uni file, stream length does not match, " << bytes << " vs "
+ << readBytes);
+# endif
+ }
+ gzclose(gzf);
+#else
+ debMsg("file format not supported without zlib", 1);
+#endif
+}
+
+// explicit instantiation
+template void writePdataUni<int>(const std::string &name, ParticleDataImpl<int> *pdata);
+template void writePdataUni<Real>(const std::string &name, ParticleDataImpl<Real> *pdata);
+template void writePdataUni<Vec3>(const std::string &name, ParticleDataImpl<Vec3> *pdata);
+template void readPdataUni<int>(const std::string &name, ParticleDataImpl<int> *pdata);
+template void readPdataUni<Real>(const std::string &name, ParticleDataImpl<Real> *pdata);
+template void readPdataUni<Vec3>(const std::string &name, ParticleDataImpl<Vec3> *pdata);
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/fileio/mantaio.h b/extern/mantaflow/preprocessed/fileio/mantaio.h
new file mode 100644
index 00000000000..8bb0a5af6a4
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fileio/mantaio.h
@@ -0,0 +1,81 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#ifndef _FILEIO_H
+#define _FILEIO_H
+
+#include <string>
+
+namespace Manta {
+
+// forward decl.
+class Mesh;
+class FlagGrid;
+template<class T> class Grid;
+template<class T> class Grid4d;
+class BasicParticleSystem;
+template<class T> class ParticleDataImpl;
+template<class T> class MeshDataImpl;
+
+void writeObjFile(const std::string &name, Mesh *mesh);
+void writeBobjFile(const std::string &name, Mesh *mesh);
+void readObjFile(const std::string &name, Mesh *mesh, bool append);
+void readBobjFile(const std::string &name, Mesh *mesh, bool append);
+
+template<class T> void writeGridRaw(const std::string &name, Grid<T> *grid);
+template<class T> void writeGridUni(const std::string &name, Grid<T> *grid);
+template<class T> void writeGridVol(const std::string &name, Grid<T> *grid);
+template<class T> void writeGridTxt(const std::string &name, Grid<T> *grid);
+
+#if OPENVDB == 1
+template<class T> void writeGridVDB(const std::string &name, Grid<T> *grid);
+template<class T> void readGridVDB(const std::string &name, Grid<T> *grid);
+#endif // OPENVDB==1
+template<class T> void writeGridNumpy(const std::string &name, Grid<T> *grid);
+template<class T> void readGridNumpy(const std::string &name, Grid<T> *grid);
+
+template<class T> void readGridUni(const std::string &name, Grid<T> *grid);
+template<class T> void readGridRaw(const std::string &name, Grid<T> *grid);
+template<class T> void readGridVol(const std::string &name, Grid<T> *grid);
+
+template<class T> void writeGrid4dUni(const std::string &name, Grid4d<T> *grid);
+template<class T>
+void readGrid4dUni(const std::string &name,
+ Grid4d<T> *grid,
+ int readTslice = -1,
+ Grid4d<T> *slice = NULL,
+ void **fileHandle = NULL);
+void readGrid4dUniCleanup(void **fileHandle);
+template<class T> void writeGrid4dRaw(const std::string &name, Grid4d<T> *grid);
+template<class T> void readGrid4dRaw(const std::string &name, Grid4d<T> *grid);
+
+void writeParticlesUni(const std::string &name, const BasicParticleSystem *parts);
+void readParticlesUni(const std::string &name, BasicParticleSystem *parts);
+
+template<class T> void writePdataUni(const std::string &name, ParticleDataImpl<T> *pdata);
+template<class T> void readPdataUni(const std::string &name, ParticleDataImpl<T> *pdata);
+
+template<class T> void writeMdataUni(const std::string &name, MeshDataImpl<T> *mdata);
+template<class T> void readMdataUni(const std::string &name, MeshDataImpl<T> *mdata);
+
+void getUniFileSize(
+ const std::string &name, int &x, int &y, int &z, int *t = NULL, std::string *info = NULL);
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/fileio/mantaio.h.reg.cpp b/extern/mantaflow/preprocessed/fileio/mantaio.h.reg.cpp
new file mode 100644
index 00000000000..6520786181e
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fileio/mantaio.h.reg.cpp
@@ -0,0 +1,13 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "fileio/mantaio.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_18()
+{
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/fluidsolver.cpp b/extern/mantaflow/preprocessed/fluidsolver.cpp
new file mode 100644
index 00000000000..814d5444b15
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fluidsolver.cpp
@@ -0,0 +1,397 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Main class for the fluid solver
+ *
+ ******************************************************************************/
+
+#include "fluidsolver.h"
+#include "grid.h"
+#include <sstream>
+#include <fstream>
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// Gridstorage-related members
+
+template<class T> void FluidSolver::GridStorage<T>::free()
+{
+ if (used != 0)
+ errMsg("can't clean grid cache, some grids are still in use");
+ for (size_t i = 0; i < grids.size(); i++)
+ delete[] grids[i];
+ grids.clear();
+}
+template<class T> T *FluidSolver::GridStorage<T>::get(Vec3i size)
+{
+ if ((int)grids.size() <= used) {
+ debMsg("FluidSolver::GridStorage::get Allocating new " << size.x << "," << size.y << ","
+ << size.z << " ",
+ 3);
+ grids.push_back(new T[(long long)(size.x) * size.y * size.z]);
+ }
+ if (used > 200)
+ errMsg("too many temp grids used -- are they released properly ?");
+ return grids[used++];
+}
+template<class T> void FluidSolver::GridStorage<T>::release(T *ptr)
+{
+ // rewrite pointer, as it may have changed due to swap operations
+ used--;
+ if (used < 0)
+ errMsg("temp grid inconsistency");
+ grids[used] = ptr;
+}
+
+template<> int *FluidSolver::getGridPointer<int>()
+{
+ return mGridsInt.get(mGridSize);
+}
+template<> Real *FluidSolver::getGridPointer<Real>()
+{
+ return mGridsReal.get(mGridSize);
+}
+template<> Vec3 *FluidSolver::getGridPointer<Vec3>()
+{
+ return mGridsVec.get(mGridSize);
+}
+template<> Vec4 *FluidSolver::getGridPointer<Vec4>()
+{
+ return mGridsVec4.get(mGridSize);
+}
+template<> void FluidSolver::freeGridPointer<int>(int *ptr)
+{
+ mGridsInt.release(ptr);
+}
+template<> void FluidSolver::freeGridPointer<Real>(Real *ptr)
+{
+ mGridsReal.release(ptr);
+}
+template<> void FluidSolver::freeGridPointer<Vec3>(Vec3 *ptr)
+{
+ mGridsVec.release(ptr);
+}
+template<> void FluidSolver::freeGridPointer<Vec4>(Vec4 *ptr)
+{
+ mGridsVec4.release(ptr);
+}
+
+// 4d data (work around for now, convert to 1d length)
+
+template<> int *FluidSolver::getGrid4dPointer<int>()
+{
+ return mGrids4dInt.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim));
+}
+template<> Real *FluidSolver::getGrid4dPointer<Real>()
+{
+ return mGrids4dReal.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim));
+}
+template<> Vec3 *FluidSolver::getGrid4dPointer<Vec3>()
+{
+ return mGrids4dVec.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim));
+}
+template<> Vec4 *FluidSolver::getGrid4dPointer<Vec4>()
+{
+ return mGrids4dVec4.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim));
+}
+template<> void FluidSolver::freeGrid4dPointer<int>(int *ptr)
+{
+ mGrids4dInt.release(ptr);
+}
+template<> void FluidSolver::freeGrid4dPointer<Real>(Real *ptr)
+{
+ mGrids4dReal.release(ptr);
+}
+template<> void FluidSolver::freeGrid4dPointer<Vec3>(Vec3 *ptr)
+{
+ mGrids4dVec.release(ptr);
+}
+template<> void FluidSolver::freeGrid4dPointer<Vec4>(Vec4 *ptr)
+{
+ mGrids4dVec4.release(ptr);
+}
+
+//******************************************************************************
+// FluidSolver members
+
+FluidSolver::FluidSolver(Vec3i gridsize, int dim, int fourthDim)
+ : PbClass(this),
+ mDt(1.0),
+ mTimeTotal(0.),
+ mFrame(0),
+ mCflCond(1000),
+ mDtMin(1.),
+ mDtMax(1.),
+ mFrameLength(1.),
+ mGridSize(gridsize),
+ mDim(dim),
+ mTimePerFrame(0.),
+ mLockDt(false),
+ mFourthDim(fourthDim)
+{
+ if (dim == 4 && mFourthDim > 0)
+ errMsg("Don't create 4D solvers, use 3D with fourth-dim parameter >0 instead.");
+ assertMsg(dim == 2 || dim == 3, "Only 2D and 3D solvers allowed.");
+ assertMsg(dim != 2 || gridsize.z == 1, "Trying to create 2D solver with size.z != 1");
+}
+
+FluidSolver::~FluidSolver()
+{
+ mGridsInt.free();
+ mGridsReal.free();
+ mGridsVec.free();
+ mGridsVec4.free();
+
+ mGrids4dInt.free();
+ mGrids4dReal.free();
+ mGrids4dVec.free();
+ mGrids4dVec4.free();
+}
+
+PbClass *FluidSolver::create(PbType t, PbTypeVec T, const string &name)
+{
+#if NOPYTHON != 1
+ _args.add("nocheck", true);
+ if (t.str() == "")
+ errMsg(
+ "Need to specify object type. Use e.g. Solver.create(FlagGrid, ...) or "
+ "Solver.create(type=FlagGrid, ...)");
+
+ PbClass *ret = PbClass::createPyObject(t.str() + T.str(), name, _args, this);
+#else
+ PbClass *ret = NULL;
+#endif
+ return ret;
+}
+
+void FluidSolver::step()
+{
+ // update simulation time with adaptive time stepping
+ // (use eps value to prevent roundoff errors)
+ mTimePerFrame += mDt;
+ mTimeTotal += mDt;
+
+ if ((mTimePerFrame + VECTOR_EPSILON) > mFrameLength) {
+ mFrame++;
+
+ // re-calc total time, prevent drift...
+ mTimeTotal = (double)mFrame * mFrameLength;
+ mTimePerFrame = 0.;
+ mLockDt = false;
+ }
+
+ updateQtGui(true, mFrame, mTimeTotal, "FluidSolver::step");
+}
+
+void FluidSolver::printMemInfo()
+{
+ std::ostringstream msg;
+ msg << "Allocated grids: int " << mGridsInt.used << "/" << mGridsInt.grids.size() << ", ";
+ msg << " real " << mGridsReal.used << "/" << mGridsReal.grids.size() << ", ";
+ msg << " vec3 " << mGridsVec.used << "/" << mGridsVec.grids.size() << ". ";
+ msg << " vec4 " << mGridsVec4.used << "/" << mGridsVec4.grids.size() << ". ";
+ if (supports4D()) {
+ msg << "Allocated 4d grids: int " << mGrids4dInt.used << "/" << mGrids4dInt.grids.size()
+ << ", ";
+ msg << " real " << mGrids4dReal.used << "/" << mGrids4dReal.grids.size()
+ << ", ";
+ msg << " vec3 " << mGrids4dVec.used << "/" << mGrids4dVec.grids.size()
+ << ". ";
+ msg << " vec4 " << mGrids4dVec4.used << "/" << mGrids4dVec4.grids.size()
+ << ". ";
+ }
+ printf("%s\n", msg.str().c_str());
+}
+
+//! warning, uses 10^-4 epsilon values, thus only use around "regular" FPS time scales, e.g. 30
+//! frames per time unit pass max magnitude of current velocity as maxvel, not yet scaled by dt!
+void FluidSolver::adaptTimestep(Real maxVel)
+{
+ const Real mvt = maxVel * mDt;
+ if (!mLockDt) {
+ // calculate current timestep from maxvel, clamp range
+ mDt = std::max(std::min(mDt * (Real)(mCflCond / (mvt + 1e-05)), mDtMax), mDtMin);
+ if ((mTimePerFrame + mDt * 1.05) > mFrameLength) {
+ // within 5% of full step? add epsilon to prevent roundoff errors...
+ mDt = (mFrameLength - mTimePerFrame) + 1e-04;
+ }
+ else if ((mTimePerFrame + mDt + mDtMin) > mFrameLength ||
+ (mTimePerFrame + (mDt * 1.25)) > mFrameLength) {
+ // avoid tiny timesteps and strongly varying ones, do 2 medium size ones if necessary...
+ mDt = (mFrameLength - mTimePerFrame + 1e-04) * 0.5;
+ mLockDt = true;
+ }
+ }
+ debMsg("Frame " << mFrame << ", max vel per step: " << mvt << " , dt: " << mDt << ", frame time "
+ << mTimePerFrame << "/" << mFrameLength << "; lock:" << mLockDt,
+ 2);
+
+ // sanity check
+ assertMsg((mDt > (mDtMin / 2.)), "Invalid dt encountered! Shouldnt happen...");
+}
+
+//******************************************************************************
+// Generic helpers (no PYTHON funcs in general.cpp, thus they're here...)
+
+//! helper to unify printing from python scripts and printing internal messages (optionally pass
+//! debug level to control amount of output)
+void mantaMsg(const std::string &out, int level = 1)
+{
+ debMsg(out, level);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "mantaMsg", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const std::string &out = _args.get<std::string>("out", 0, &_lock);
+ int level = _args.getOpt<int>("level", 1, 1, &_lock);
+ _retval = getPyNone();
+ mantaMsg(out, level);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mantaMsg", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mantaMsg", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mantaMsg("", "mantaMsg", _W_0);
+extern "C" {
+void PbRegister_mantaMsg()
+{
+ KEEP_UNUSED(_RP_mantaMsg);
+}
+}
+
+std::string printBuildInfo()
+{
+ string infoString = buildInfoString();
+ debMsg("Build info: " << infoString.c_str() << " ", 1);
+ return infoString;
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "printBuildInfo", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ _retval = toPy(printBuildInfo());
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "printBuildInfo", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("printBuildInfo", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_printBuildInfo("", "printBuildInfo", _W_1);
+extern "C" {
+void PbRegister_printBuildInfo()
+{
+ KEEP_UNUSED(_RP_printBuildInfo);
+}
+}
+
+//! set debug level for messages (0 off, 1 regular, higher = more, up to 10)
+void setDebugLevel(int level = 1)
+{
+ gDebugLevel = level;
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setDebugLevel", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int level = _args.getOpt<int>("level", 0, 1, &_lock);
+ _retval = getPyNone();
+ setDebugLevel(level);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setDebugLevel", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setDebugLevel", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setDebugLevel("", "setDebugLevel", _W_2);
+extern "C" {
+void PbRegister_setDebugLevel()
+{
+ KEEP_UNUSED(_RP_setDebugLevel);
+}
+}
+
+//! helper function to check for numpy compilation
+void assertNumpy()
+{
+#if NUMPY == 1
+ // all good, nothing to do...
+#else
+ errMsg("This scene requires numpy support. Enable compilation in cmake with \"-DNUMPY=1\" ");
+#endif
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "assertNumpy", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ _retval = getPyNone();
+ assertNumpy();
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "assertNumpy", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("assertNumpy", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_assertNumpy("", "assertNumpy", _W_3);
+extern "C" {
+void PbRegister_assertNumpy()
+{
+ KEEP_UNUSED(_RP_assertNumpy);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/fluidsolver.h b/extern/mantaflow/preprocessed/fluidsolver.h
new file mode 100644
index 00000000000..d01f87082b6
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fluidsolver.h
@@ -0,0 +1,395 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Main class for the fluid solver
+ *
+ ******************************************************************************/
+
+#ifndef _FLUIDSOLVER_H
+#define _FLUIDSOLVER_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "vector4d.h"
+#include <vector>
+#include <map>
+
+namespace Manta {
+
+//! Encodes grid size, timstep etc.
+
+class FluidSolver : public PbClass {
+ public:
+ FluidSolver(Vec3i gridSize, int dim = 3, int fourthDim = -1);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "FluidSolver::FluidSolver", !noTiming);
+ {
+ ArgLocker _lock;
+ Vec3i gridSize = _args.get<Vec3i>("gridSize", 0, &_lock);
+ int dim = _args.getOpt<int>("dim", 1, 3, &_lock);
+ int fourthDim = _args.getOpt<int>("fourthDim", 2, -1, &_lock);
+ obj = new FluidSolver(gridSize, dim, fourthDim);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "FluidSolver::FluidSolver", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("FluidSolver::FluidSolver", e.what());
+ return -1;
+ }
+ }
+
+ virtual ~FluidSolver();
+
+ // accessors
+ Vec3i getGridSize()
+ {
+ return mGridSize;
+ }
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "FluidSolver::getGridSize", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getGridSize());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "FluidSolver::getGridSize", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("FluidSolver::getGridSize", e.what());
+ return 0;
+ }
+ }
+
+ inline Real getDt() const
+ {
+ return mDt;
+ }
+ inline Real getDx() const
+ {
+ return 1.0 / mGridSize.max();
+ }
+ inline Real getTime() const
+ {
+ return mTimeTotal;
+ }
+
+ //! Check dimensionality
+ inline bool is2D() const
+ {
+ return mDim == 2;
+ }
+ //! Check dimensionality (3d or above)
+ inline bool is3D() const
+ {
+ return mDim == 3;
+ }
+
+ void printMemInfo();
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "FluidSolver::printMemInfo", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->printMemInfo();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "FluidSolver::printMemInfo", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("FluidSolver::printMemInfo", e.what());
+ return 0;
+ }
+ }
+
+ //! Advance the solver one timestep, update GUI if present
+ void step();
+ static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "FluidSolver::step", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->step();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "FluidSolver::step", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("FluidSolver::step", e.what());
+ return 0;
+ }
+ }
+
+ //! Update the timestep size based on given maximal velocity magnitude
+ void adaptTimestep(Real maxVel);
+ static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "FluidSolver::adaptTimestep", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real maxVel = _args.get<Real>("maxVel", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->adaptTimestep(maxVel);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "FluidSolver::adaptTimestep", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("FluidSolver::adaptTimestep", e.what());
+ return 0;
+ }
+ }
+
+ //! create a object with the solver as its parent
+ PbClass *create(PbType type, PbTypeVec T = PbTypeVec(), const std::string &name = "");
+ static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "FluidSolver::create", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ PbType type = _args.get<PbType>("type", 0, &_lock);
+ PbTypeVec T = _args.getOpt<PbTypeVec>("T", 1, PbTypeVec(), &_lock);
+ const std::string &name = _args.getOpt<std::string>("name", 2, "", &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->create(type, T, name));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "FluidSolver::create", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("FluidSolver::create", e.what());
+ return 0;
+ }
+ }
+
+ // temp grid and plugin functions: you shouldn't call this manually
+ template<class T> T *getGridPointer();
+ template<class T> void freeGridPointer(T *ptr);
+
+ //! expose animation time to python
+ Real mDt;
+ static PyObject *_GET_mDt(PyObject *self, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ return toPy(pbo->mDt);
+ }
+ static int _SET_mDt(PyObject *self, PyObject *val, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ pbo->mDt = fromPy<Real>(val);
+ return 0;
+ }
+
+ Real mTimeTotal;
+ static PyObject *_GET_mTimeTotal(PyObject *self, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ return toPy(pbo->mTimeTotal);
+ }
+ static int _SET_mTimeTotal(PyObject *self, PyObject *val, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ pbo->mTimeTotal = fromPy<Real>(val);
+ return 0;
+ }
+
+ int mFrame;
+ static PyObject *_GET_mFrame(PyObject *self, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ return toPy(pbo->mFrame);
+ }
+ static int _SET_mFrame(PyObject *self, PyObject *val, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ pbo->mFrame = fromPy<int>(val);
+ return 0;
+ }
+
+ //! parameters for adaptive time stepping
+ Real mCflCond;
+ static PyObject *_GET_mCflCond(PyObject *self, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ return toPy(pbo->mCflCond);
+ }
+ static int _SET_mCflCond(PyObject *self, PyObject *val, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ pbo->mCflCond = fromPy<Real>(val);
+ return 0;
+ }
+
+ Real mDtMin;
+ static PyObject *_GET_mDtMin(PyObject *self, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ return toPy(pbo->mDtMin);
+ }
+ static int _SET_mDtMin(PyObject *self, PyObject *val, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ pbo->mDtMin = fromPy<Real>(val);
+ return 0;
+ }
+
+ Real mDtMax;
+ static PyObject *_GET_mDtMax(PyObject *self, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ return toPy(pbo->mDtMax);
+ }
+ static int _SET_mDtMax(PyObject *self, PyObject *val, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ pbo->mDtMax = fromPy<Real>(val);
+ return 0;
+ }
+
+ Real mFrameLength;
+ static PyObject *_GET_mFrameLength(PyObject *self, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ return toPy(pbo->mFrameLength);
+ }
+ static int _SET_mFrameLength(PyObject *self, PyObject *val, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ pbo->mFrameLength = fromPy<Real>(val);
+ return 0;
+ }
+
+ //! Per frame duration. Blender needs access in order to restore value in new solver object
+ Real mTimePerFrame;
+ static PyObject *_GET_mTimePerFrame(PyObject *self, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ return toPy(pbo->mTimePerFrame);
+ }
+ static int _SET_mTimePerFrame(PyObject *self, PyObject *val, void *cl)
+ {
+ FluidSolver *pbo = dynamic_cast<FluidSolver *>(Pb::objFromPy(self));
+ pbo->mTimePerFrame = fromPy<Real>(val);
+ return 0;
+ }
+
+ protected:
+ Vec3i mGridSize;
+ const int mDim;
+ bool mLockDt;
+
+ //! subclass for managing grid memory
+ //! stored as a stack to allow fast allocation
+ template<class T> struct GridStorage {
+ GridStorage() : used(0)
+ {
+ }
+ T *get(Vec3i size);
+ void free();
+ void release(T *ptr);
+
+ std::vector<T *> grids;
+ int used;
+ };
+
+ //! memory for regular (3d) grids
+ GridStorage<int> mGridsInt;
+ GridStorage<Real> mGridsReal;
+ GridStorage<Vec3> mGridsVec;
+
+ //! 4d data section, only required for simulations working with space-time data
+
+ public:
+ //! 4D enabled? note, there's intentionally no "is4D" function, there are only 3D solvers that
+ //! also support 4D of a certain size
+ inline bool supports4D() const
+ {
+ return mFourthDim > 0;
+ }
+ //! fourth dimension size
+ inline int getFourthDim() const
+ {
+ return mFourthDim;
+ }
+ //! 4d data allocation
+ template<class T> T *getGrid4dPointer();
+ template<class T> void freeGrid4dPointer(T *ptr);
+
+ protected:
+ //! 4d size. Note - 4d is not treated like going from 2d to 3d! 4D grids are a separate data
+ //! type. Normally all grids are forced to have the same size. In contrast, a solver can create
+ //! and work with 3D as well as 4D grids, when fourth-dim is >0.
+ int mFourthDim;
+
+ //! 4d grid storage
+ GridStorage<Vec4> mGridsVec4;
+ GridStorage<int> mGrids4dInt;
+ GridStorage<Real> mGrids4dReal;
+ GridStorage<Vec3> mGrids4dVec;
+ GridStorage<Vec4> mGrids4dVec4;
+ public:
+ PbArgs _args;
+}
+#define _C_FluidSolver
+;
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/fluidsolver.h.reg.cpp b/extern/mantaflow/preprocessed/fluidsolver.h.reg.cpp
new file mode 100644
index 00000000000..764c7c59021
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fluidsolver.h.reg.cpp
@@ -0,0 +1,70 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "fluidsolver.h"
+namespace Manta {
+#ifdef _C_FluidSolver
+static const Pb::Register _R_6("FluidSolver", "Solver", "PbClass");
+template<> const char *Namify<FluidSolver>::S = "FluidSolver";
+static const Pb::Register _R_7("FluidSolver", "FluidSolver", FluidSolver::_W_0);
+static const Pb::Register _R_8("FluidSolver", "getGridSize", FluidSolver::_W_1);
+static const Pb::Register _R_9("FluidSolver", "printMemInfo", FluidSolver::_W_2);
+static const Pb::Register _R_10("FluidSolver", "step", FluidSolver::_W_3);
+static const Pb::Register _R_11("FluidSolver", "adaptTimestep", FluidSolver::_W_4);
+static const Pb::Register _R_12("FluidSolver", "create", FluidSolver::_W_5);
+static const Pb::Register _R_13("FluidSolver",
+ "timestep",
+ FluidSolver::_GET_mDt,
+ FluidSolver::_SET_mDt);
+static const Pb::Register _R_14("FluidSolver",
+ "timeTotal",
+ FluidSolver::_GET_mTimeTotal,
+ FluidSolver::_SET_mTimeTotal);
+static const Pb::Register _R_15("FluidSolver",
+ "frame",
+ FluidSolver::_GET_mFrame,
+ FluidSolver::_SET_mFrame);
+static const Pb::Register _R_16("FluidSolver",
+ "cfl",
+ FluidSolver::_GET_mCflCond,
+ FluidSolver::_SET_mCflCond);
+static const Pb::Register _R_17("FluidSolver",
+ "timestepMin",
+ FluidSolver::_GET_mDtMin,
+ FluidSolver::_SET_mDtMin);
+static const Pb::Register _R_18("FluidSolver",
+ "timestepMax",
+ FluidSolver::_GET_mDtMax,
+ FluidSolver::_SET_mDtMax);
+static const Pb::Register _R_19("FluidSolver",
+ "frameLength",
+ FluidSolver::_GET_mFrameLength,
+ FluidSolver::_SET_mFrameLength);
+static const Pb::Register _R_20("FluidSolver",
+ "timePerFrame",
+ FluidSolver::_GET_mTimePerFrame,
+ FluidSolver::_SET_mTimePerFrame);
+#endif
+extern "C" {
+void PbRegister_file_6()
+{
+ KEEP_UNUSED(_R_6);
+ KEEP_UNUSED(_R_7);
+ KEEP_UNUSED(_R_8);
+ KEEP_UNUSED(_R_9);
+ KEEP_UNUSED(_R_10);
+ KEEP_UNUSED(_R_11);
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/general.cpp b/extern/mantaflow/preprocessed/general.cpp
new file mode 100644
index 00000000000..266e6c8719d
--- /dev/null
+++ b/extern/mantaflow/preprocessed/general.cpp
@@ -0,0 +1,167 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Globally used macros and functions (e.g. time measurements),
+ * and doxygen documentation collection.
+ *
+ ******************************************************************************/
+
+/*! \mainpage Welcome to mantaflow!
+ *
+ * Here you can find the auto-generated documentation of the mantaflow framework.
+ *
+ * One of the most useful parts is probably the list of python functions, classes and the C++
+ * kernels. Those can be found found in the ''Modules'' section. For python functions the
+ * parameters (e.g. Grids, Real or int values) are automatically transferred to and from python.
+ * Thus, this list is a good reference how to call the functions used in the example scenes.
+ *
+ */
+
+// Define plugin documentation group
+// all kernels, plugin functions and classes will automatically be added to this group
+//! @defgroup Plugins Functions callable from Python
+//! @defgroup PyClasses Classes exposed to Python
+//! @defgroup Kernels Computation Kernels
+
+#include "general.h"
+#if defined(WIN32) || defined(_WIN32)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+# undef NOMINMAX
+#else
+# include <sys/time.h>
+# include "gitinfo.h"
+#endif
+
+using namespace std;
+
+namespace Manta {
+
+int gDebugLevel = 1;
+
+void MuTime::get()
+{
+#if defined(WIN32) || defined(_WIN32)
+ LARGE_INTEGER liTimerFrequency;
+ QueryPerformanceFrequency(&liTimerFrequency);
+ LARGE_INTEGER liLastTime;
+ QueryPerformanceCounter(&liLastTime);
+ time = (INT)(((double)liLastTime.QuadPart / liTimerFrequency.QuadPart) * 1000);
+#else
+ struct timeval tv;
+ struct timezone tz;
+ tz.tz_minuteswest = 0;
+ tz.tz_dsttime = 0;
+ gettimeofday(&tv, &tz);
+ time = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+#endif
+}
+
+MuTime MuTime::update()
+{
+ MuTime o = *this;
+ get();
+ return *this - o;
+}
+
+string MuTime::toString()
+{
+ stringstream ss;
+ ss << *this;
+ return ss.str();
+}
+
+ostream &operator<<(ostream &os, const MuTime &t)
+{
+ unsigned long ms = (unsigned long)((double)t.time / (60.0 * 1000.0));
+ unsigned long ss = (unsigned long)(((double)t.time / 1000.0) - ((double)ms * 60.0));
+ int ps = (int)(((double)t.time - (double)ss * 1000.0) / 1.0);
+
+ if (ms > 0) {
+ os << ms << "m" << ss << "s";
+ }
+ else {
+ if (ps > 0) {
+ os << ss << ".";
+ if (ps < 10) {
+ os << "0";
+ }
+ if (ps < 100) {
+ os << "0";
+ }
+ os << ps << "s";
+ }
+ else {
+ os << ss << "s";
+ }
+ }
+ return os;
+}
+
+//! print info about this mantaflow build, used eg by printBuildInfo in fluidsolver.cpp
+std::string buildInfoString()
+{
+ std::ostringstream infoStr;
+#ifndef MANTAVERSION
+# define MANTAVERSION "<unknown-version>"
+#endif
+ infoStr << "mantaflow " << MANTAVERSION;
+
+ // os
+#if defined(WIN32) || defined(_WIN32)
+ infoStr << " win";
+#endif
+#ifdef __APPLE__
+ infoStr << " mac";
+#endif
+#ifdef LINUX
+ infoStr << " linux";
+#endif
+
+ // 32/64 bit
+ if (sizeof(size_t) == 8)
+ infoStr << " 64bit";
+ else
+ infoStr << " 32bit";
+
+ // fp precision
+#if FLOATINGPOINT_PRECISION == 2
+ infoStr << " fp2";
+#else
+ infoStr << " fp1";
+#endif
+
+ // other compile switches
+#ifdef DEBUG
+ infoStr << " debug";
+#endif
+#ifdef OPENMP
+ infoStr << " omp";
+#endif
+
+ // repository info (git commit id)
+#ifndef MANTA_GIT_VERSION
+# define MANTA_GIT_VERSION "<unknown-commit>"
+#endif
+ infoStr << " " << MANTA_GIT_VERSION;
+
+ infoStr << " from " << __DATE__ << ", " << __TIME__;
+ return infoStr.str();
+}
+
+//! note - generic PYTHON helpers in fluidsolver.cpp , no python bindings here
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/general.h b/extern/mantaflow/preprocessed/general.h
new file mode 100644
index 00000000000..7a840517cef
--- /dev/null
+++ b/extern/mantaflow/preprocessed/general.h
@@ -0,0 +1,247 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Globally used macros and functions
+ *
+ ******************************************************************************/
+
+#ifndef _GENERAL_H
+#define _GENERAL_H
+
+#include <iostream>
+#include <sstream>
+#include <cmath>
+#include <algorithm>
+
+namespace Manta {
+
+// ui data exchange
+#ifdef GUI
+// defined in qtmain.cpp
+extern void updateQtGui(bool full, int frame, float time, const std::string &curPlugin);
+#else
+// dummy function if GUI is not enabled
+inline void updateQtGui(bool full, int frame, float time, const std::string &curPlugin)
+{
+}
+#endif
+
+// activate debug mode if _DEBUG is defined (eg for windows)
+#ifndef DEBUG
+# ifdef _DEBUG
+# define DEBUG 1
+# endif // _DEBUG
+#endif // DEBUG
+
+// Standard exception
+class Error : public std::exception {
+ public:
+ Error(const std::string &s) : mS(s)
+ {
+#ifdef DEBUG
+ // print error
+ std::cerr << "Aborting: " << s << " \n";
+ // then force immedieate crash in debug mode
+ *(volatile int *)(0) = 1;
+#endif
+ }
+ virtual ~Error() throw()
+ {
+ }
+ virtual const char *what() const throw()
+ {
+ return mS.c_str();
+ }
+
+ private:
+ std::string mS;
+};
+
+// mark unused parameter variables
+#define unusedParameter(x) ((void)x)
+
+// Debug output functions and macros
+extern int gDebugLevel;
+
+#define MSGSTREAM \
+ std::ostringstream msg; \
+ msg.precision(7); \
+ msg.width(9);
+#define debMsg(mStr, level) \
+ if (_chklevel(level)) { \
+ MSGSTREAM; \
+ msg << mStr; \
+ std::cout << msg.str() << std::endl; \
+ }
+inline bool _chklevel(int level = 0)
+{
+ return gDebugLevel >= level;
+}
+
+// error and assertation macros
+#ifdef DEBUG
+# define DEBUG_ONLY(a) a
+#else
+# define DEBUG_ONLY(a)
+#endif
+#define throwError(msg) \
+ { \
+ std::ostringstream __s; \
+ __s << msg << std::endl << "Error raised in " << __FILE__ << ":" << __LINE__; \
+ throw Manta::Error(__s.str()); \
+ }
+#define errMsg(msg) throwError(msg);
+#define assertMsg(cond, msg) \
+ if (!(cond)) \
+ throwError(msg)
+#define assertDeb(cond, msg) DEBUG_ONLY(assertMsg(cond, msg))
+
+// for compatibility with blender, blender only defines WITH_FLUID, make sure we have "BLENDER"
+#ifndef BLENDER
+# ifdef WITH_FLUID
+# define BLENDER 1
+# endif
+#endif
+
+// common type for indexing large grids
+typedef long long IndexInt;
+
+// template tricks
+template<typename T> struct remove_pointers {
+ typedef T type;
+};
+
+template<typename T> struct remove_pointers<T *> {
+ typedef T type;
+};
+
+template<typename T> struct remove_pointers<T &> {
+ typedef T type;
+};
+
+// Commonly used enums and types
+//! Timing class for preformance measuring
+struct MuTime {
+ MuTime()
+ {
+ get();
+ }
+ MuTime operator-(const MuTime &a)
+ {
+ MuTime b;
+ b.time = time - a.time;
+ return b;
+ };
+ MuTime operator+(const MuTime &a)
+ {
+ MuTime b;
+ b.time = time + a.time;
+ return b;
+ };
+ MuTime operator/(unsigned long a)
+ {
+ MuTime b;
+ b.time = time / a;
+ return b;
+ };
+ MuTime &operator+=(const MuTime &a)
+ {
+ time += a.time;
+ return *this;
+ }
+ MuTime &operator-=(const MuTime &a)
+ {
+ time -= a.time;
+ return *this;
+ }
+ MuTime &operator/=(unsigned long a)
+ {
+ time /= a;
+ return *this;
+ }
+ std::string toString();
+
+ void clear()
+ {
+ time = 0;
+ }
+ void get();
+ MuTime update();
+
+ unsigned long time;
+};
+std::ostream &operator<<(std::ostream &os, const MuTime &t);
+
+//! generate a string with infos about the current mantaflow build
+std::string buildInfoString();
+
+// Some commonly used math helpers
+template<class T> inline T square(T a)
+{
+ return a * a;
+}
+template<class T> inline T cubed(T a)
+{
+ return a * a * a;
+}
+
+template<class T> inline T clamp(const T &val, const T &vmin, const T &vmax)
+{
+ if (val < vmin)
+ return vmin;
+ if (val > vmax)
+ return vmax;
+ return val;
+}
+
+template<class T> inline T nmod(const T &a, const T &b);
+template<> inline int nmod(const int &a, const int &b)
+{
+ int c = a % b;
+ return (c < 0) ? (c + b) : c;
+}
+template<> inline float nmod(const float &a, const float &b)
+{
+ float c = std::fmod(a, b);
+ return (c < 0) ? (c + b) : c;
+}
+template<> inline double nmod(const double &a, const double &b)
+{
+ double c = std::fmod(a, b);
+ return (c < 0) ? (c + b) : c;
+}
+
+template<class T> inline T safeDivide(const T &a, const T &b);
+template<> inline int safeDivide<int>(const int &a, const int &b)
+{
+ return (b) ? (a / b) : a;
+}
+template<> inline float safeDivide<float>(const float &a, const float &b)
+{
+ return (b) ? (a / b) : a;
+}
+template<> inline double safeDivide<double>(const double &a, const double &b)
+{
+ return (b) ? (a / b) : a;
+}
+
+inline bool c_isnan(float c)
+{
+ volatile float d = c;
+ return d != d;
+}
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/general.h.reg.cpp b/extern/mantaflow/preprocessed/general.h.reg.cpp
new file mode 100644
index 00000000000..cab2c4782b0
--- /dev/null
+++ b/extern/mantaflow/preprocessed/general.h.reg.cpp
@@ -0,0 +1,13 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "general.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_1()
+{
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h
new file mode 100644
index 00000000000..154f928dc2f
--- /dev/null
+++ b/extern/mantaflow/preprocessed/gitinfo.h
@@ -0,0 +1,3 @@
+
+
+#define MANTA_GIT_VERSION "commit 761849c592daaea320f9026768b5a0750528009c"
diff --git a/extern/mantaflow/preprocessed/grid.cpp b/extern/mantaflow/preprocessed/grid.cpp
new file mode 100644
index 00000000000..c21d56d8879
--- /dev/null
+++ b/extern/mantaflow/preprocessed/grid.cpp
@@ -0,0 +1,2939 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#include "grid.h"
+#include "levelset.h"
+#include "kernel.h"
+#include "mantaio.h"
+#include <limits>
+#include <sstream>
+#include <cstring>
+
+#include "commonkernels.h"
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// GridBase members
+
+GridBase::GridBase(FluidSolver *parent) : PbClass(parent), mType(TypeNone)
+{
+ checkParent();
+ m3D = getParent()->is3D();
+}
+
+//******************************************************************************
+// Grid<T> members
+
+// helpers to set type
+template<class T> inline GridBase::GridType typeList()
+{
+ return GridBase::TypeNone;
+}
+template<> inline GridBase::GridType typeList<Real>()
+{
+ return GridBase::TypeReal;
+}
+template<> inline GridBase::GridType typeList<int>()
+{
+ return GridBase::TypeInt;
+}
+template<> inline GridBase::GridType typeList<Vec3>()
+{
+ return GridBase::TypeVec3;
+}
+
+template<class T>
+Grid<T>::Grid(FluidSolver *parent, bool show) : GridBase(parent), externalData(false)
+{
+ mType = typeList<T>();
+ mSize = parent->getGridSize();
+ mData = parent->getGridPointer<T>();
+
+ mStrideZ = parent->is2D() ? 0 : (mSize.x * mSize.y);
+ mDx = 1.0 / mSize.max();
+ clear();
+ setHidden(!show);
+}
+
+template<class T>
+Grid<T>::Grid(FluidSolver *parent, T *data, bool show)
+ : GridBase(parent), mData(data), externalData(true)
+{
+ mType = typeList<T>();
+ mSize = parent->getGridSize();
+
+ mStrideZ = parent->is2D() ? 0 : (mSize.x * mSize.y);
+ mDx = 1.0 / mSize.max();
+
+ setHidden(!show);
+}
+
+template<class T> Grid<T>::Grid(const Grid<T> &a) : GridBase(a.getParent()), externalData(false)
+{
+ mSize = a.mSize;
+ mType = a.mType;
+ mStrideZ = a.mStrideZ;
+ mDx = a.mDx;
+ FluidSolver *gp = a.getParent();
+ mData = gp->getGridPointer<T>();
+ memcpy(mData, a.mData, sizeof(T) * a.mSize.x * a.mSize.y * a.mSize.z);
+}
+
+template<class T> Grid<T>::~Grid()
+{
+ if (!externalData) {
+ mParent->freeGridPointer<T>(mData);
+ }
+}
+
+template<class T> void Grid<T>::clear()
+{
+ memset(mData, 0, sizeof(T) * mSize.x * mSize.y * mSize.z);
+}
+
+template<class T> void Grid<T>::swap(Grid<T> &other)
+{
+ if (other.getSizeX() != getSizeX() || other.getSizeY() != getSizeY() ||
+ other.getSizeZ() != getSizeZ())
+ errMsg("Grid::swap(): Grid dimensions mismatch.");
+
+ if (externalData || other.externalData)
+ errMsg("Grid::swap(): Cannot swap if one grid stores externalData.");
+
+ T *dswap = other.mData;
+ other.mData = mData;
+ mData = dswap;
+}
+
+template<class T> void Grid<T>::load(string name)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".raw")
+ readGridRaw(name, this);
+ else if (ext == ".uni")
+ readGridUni(name, this);
+ else if (ext == ".vol")
+ readGridVol(name, this);
+ else if (ext == ".npz")
+ readGridNumpy(name, this);
+#if OPENVDB == 1
+ else if (ext == ".vdb")
+ readGridVDB(name, this);
+#endif // OPENVDB==1
+ else
+ errMsg("file '" + name + "' filetype not supported");
+}
+
+template<class T> void Grid<T>::save(string name)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".raw")
+ writeGridRaw(name, this);
+ else if (ext == ".uni")
+ writeGridUni(name, this);
+ else if (ext == ".vol")
+ writeGridVol(name, this);
+#if OPENVDB == 1
+ else if (ext == ".vdb")
+ writeGridVDB(name, this);
+#endif // OPENVDB==1
+ else if (ext == ".npz")
+ writeGridNumpy(name, this);
+ else if (ext == ".txt")
+ writeGridTxt(name, this);
+ else
+ errMsg("file '" + name + "' filetype not supported");
+}
+
+//******************************************************************************
+// Grid<T> operators
+
+//! Kernel: Compute min value of Real grid
+
+struct CompMinReal : public KernelBase {
+ CompMinReal(const Grid<Real> &val)
+ : KernelBase(&val, 0), val(val), minVal(std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Real> &val, Real &minVal)
+ {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+ }
+ inline operator Real()
+ {
+ return minVal;
+ }
+ inline Real &getRet()
+ {
+ return minVal;
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid<Real> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompMinReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, minVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompMinReal(CompMinReal &o, tbb::split)
+ : KernelBase(o), val(o.val), minVal(std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompMinReal &o)
+ {
+ minVal = min(minVal, o.minVal);
+ }
+ const Grid<Real> &val;
+ Real minVal;
+};
+
+//! Kernel: Compute max value of Real grid
+
+struct CompMaxReal : public KernelBase {
+ CompMaxReal(const Grid<Real> &val)
+ : KernelBase(&val, 0), val(val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Real> &val, Real &maxVal)
+ {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+ }
+ inline operator Real()
+ {
+ return maxVal;
+ }
+ inline Real &getRet()
+ {
+ return maxVal;
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid<Real> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompMaxReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, maxVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompMaxReal(CompMaxReal &o, tbb::split)
+ : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompMaxReal &o)
+ {
+ maxVal = max(maxVal, o.maxVal);
+ }
+ const Grid<Real> &val;
+ Real maxVal;
+};
+
+//! Kernel: Compute min value of int grid
+
+struct CompMinInt : public KernelBase {
+ CompMinInt(const Grid<int> &val)
+ : KernelBase(&val, 0), val(val), minVal(std::numeric_limits<int>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<int> &val, int &minVal)
+ {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+ }
+ inline operator int()
+ {
+ return minVal;
+ }
+ inline int &getRet()
+ {
+ return minVal;
+ }
+ inline const Grid<int> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid<int> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompMinInt ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, minVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompMinInt(CompMinInt &o, tbb::split)
+ : KernelBase(o), val(o.val), minVal(std::numeric_limits<int>::max())
+ {
+ }
+ void join(const CompMinInt &o)
+ {
+ minVal = min(minVal, o.minVal);
+ }
+ const Grid<int> &val;
+ int minVal;
+};
+
+//! Kernel: Compute max value of int grid
+
+struct CompMaxInt : public KernelBase {
+ CompMaxInt(const Grid<int> &val)
+ : KernelBase(&val, 0), val(val), maxVal(-std::numeric_limits<int>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<int> &val, int &maxVal)
+ {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+ }
+ inline operator int()
+ {
+ return maxVal;
+ }
+ inline int &getRet()
+ {
+ return maxVal;
+ }
+ inline const Grid<int> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid<int> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompMaxInt ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, maxVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompMaxInt(CompMaxInt &o, tbb::split)
+ : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<int>::max())
+ {
+ }
+ void join(const CompMaxInt &o)
+ {
+ maxVal = max(maxVal, o.maxVal);
+ }
+ const Grid<int> &val;
+ int maxVal;
+};
+
+//! Kernel: Compute min norm of vec grid
+
+struct CompMinVec : public KernelBase {
+ CompMinVec(const Grid<Vec3> &val)
+ : KernelBase(&val, 0), val(val), minVal(std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Vec3> &val, Real &minVal)
+ {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+ }
+ inline operator Real()
+ {
+ return minVal;
+ }
+ inline Real &getRet()
+ {
+ return minVal;
+ }
+ inline const Grid<Vec3> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid<Vec3> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompMinVec ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, minVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompMinVec(CompMinVec &o, tbb::split)
+ : KernelBase(o), val(o.val), minVal(std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompMinVec &o)
+ {
+ minVal = min(minVal, o.minVal);
+ }
+ const Grid<Vec3> &val;
+ Real minVal;
+};
+
+//! Kernel: Compute max norm of vec grid
+
+struct CompMaxVec : public KernelBase {
+ CompMaxVec(const Grid<Vec3> &val)
+ : KernelBase(&val, 0), val(val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Vec3> &val, Real &maxVal)
+ {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+ }
+ inline operator Real()
+ {
+ return maxVal;
+ }
+ inline Real &getRet()
+ {
+ return maxVal;
+ }
+ inline const Grid<Vec3> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid<Vec3> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompMaxVec ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, maxVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompMaxVec(CompMaxVec &o, tbb::split)
+ : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompMaxVec &o)
+ {
+ maxVal = max(maxVal, o.maxVal);
+ }
+ const Grid<Vec3> &val;
+ Real maxVal;
+};
+
+template<class T> Grid<T> &Grid<T>::copyFrom(const Grid<T> &a, bool copyType)
+{
+ assertMsg(a.mSize.x == mSize.x && a.mSize.y == mSize.y && a.mSize.z == mSize.z,
+ "different grid resolutions " << a.mSize << " vs " << this->mSize);
+ memcpy(mData, a.mData, sizeof(T) * mSize.x * mSize.y * mSize.z);
+ if (copyType)
+ mType = a.mType; // copy type marker
+ return *this;
+}
+/*template<class T> Grid<T>& Grid<T>::operator= (const Grid<T>& a) {
+ note: do not use , use copyFrom instead
+}*/
+
+template<class T> struct knGridSetConstReal : public KernelBase {
+ knGridSetConstReal(Grid<T> &me, T val) : KernelBase(&me, 0), me(me), val(val)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, T val) const
+ {
+ me[idx] = val;
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline T &getArg1()
+ {
+ return val;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knGridSetConstReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, val);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ T val;
+};
+template<class T> struct knGridAddConstReal : public KernelBase {
+ knGridAddConstReal(Grid<T> &me, T val) : KernelBase(&me, 0), me(me), val(val)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, T val) const
+ {
+ me[idx] += val;
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline T &getArg1()
+ {
+ return val;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knGridAddConstReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, val);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ T val;
+};
+template<class T> struct knGridMultConst : public KernelBase {
+ knGridMultConst(Grid<T> &me, T val) : KernelBase(&me, 0), me(me), val(val)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, T val) const
+ {
+ me[idx] *= val;
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline T &getArg1()
+ {
+ return val;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knGridMultConst ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, val);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ T val;
+};
+
+template<class T> struct knGridSafeDiv : public KernelBase {
+ knGridSafeDiv(Grid<T> &me, const Grid<T> &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, const Grid<T> &other) const
+ {
+ me[idx] = safeDivide(me[idx], other[idx]);
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const Grid<T> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid<T> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knGridSafeDiv ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const Grid<T> &other;
+};
+// KERNEL(idx) template<class T> void gridSafeDiv (Grid<T>& me, const Grid<T>& other) { me[idx] =
+// safeDivide(me[idx], other[idx]); }
+
+template<class T> struct knGridClamp : public KernelBase {
+ knGridClamp(Grid<T> &me, const T &min, const T &max)
+ : KernelBase(&me, 0), me(me), min(min), max(max)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, const T &min, const T &max) const
+ {
+ me[idx] = clamp(me[idx], min, max);
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const T &getArg1()
+ {
+ return min;
+ }
+ typedef T type1;
+ inline const T &getArg2()
+ {
+ return max;
+ }
+ typedef T type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knGridClamp ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, min, max);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const T &min;
+ const T &max;
+};
+
+template<typename T> inline void stomp(T &v, const T &th)
+{
+ if (v < th)
+ v = 0;
+}
+template<> inline void stomp<Vec3>(Vec3 &v, const Vec3 &th)
+{
+ if (v[0] < th[0])
+ v[0] = 0;
+ if (v[1] < th[1])
+ v[1] = 0;
+ if (v[2] < th[2])
+ v[2] = 0;
+}
+template<class T> struct knGridStomp : public KernelBase {
+ knGridStomp(Grid<T> &me, const T &threshold) : KernelBase(&me, 0), me(me), threshold(threshold)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, const T &threshold) const
+ {
+ stomp(me[idx], threshold);
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const T &getArg1()
+ {
+ return threshold;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knGridStomp ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, threshold);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const T &threshold;
+};
+
+template<class T> struct knPermuteAxes : public KernelBase {
+ knPermuteAxes(Grid<T> &self, Grid<T> &target, int axis0, int axis1, int axis2)
+ : KernelBase(&self, 0), self(self), target(target), axis0(axis0), axis1(axis1), axis2(axis2)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, Grid<T> &self, Grid<T> &target, int axis0, int axis1, int axis2) const
+ {
+ int i0 = axis0 == 0 ? i : (axis0 == 1 ? j : k);
+ int i1 = axis1 == 0 ? i : (axis1 == 1 ? j : k);
+ int i2 = axis2 == 0 ? i : (axis2 == 1 ? j : k);
+ target(i0, i1, i2) = self(i, j, k);
+ }
+ inline Grid<T> &getArg0()
+ {
+ return self;
+ }
+ typedef Grid<T> type0;
+ inline Grid<T> &getArg1()
+ {
+ return target;
+ }
+ typedef Grid<T> type1;
+ inline int &getArg2()
+ {
+ return axis0;
+ }
+ typedef int type2;
+ inline int &getArg3()
+ {
+ return axis1;
+ }
+ typedef int type3;
+ inline int &getArg4()
+ {
+ return axis2;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPermuteAxes ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, self, target, axis0, axis1, axis2);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, self, target, axis0, axis1, axis2);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<T> &self;
+ Grid<T> &target;
+ int axis0;
+ int axis1;
+ int axis2;
+};
+
+template<class T> Grid<T> &Grid<T>::safeDivide(const Grid<T> &a)
+{
+ knGridSafeDiv<T>(*this, a);
+ return *this;
+}
+
+template<class T> int Grid<T>::getGridType()
+{
+ return static_cast<int>(mType);
+}
+
+template<class T> void Grid<T>::add(const Grid<T> &a)
+{
+ gridAdd<T, T>(*this, a);
+}
+template<class T> void Grid<T>::sub(const Grid<T> &a)
+{
+ gridSub<T, T>(*this, a);
+}
+template<class T> void Grid<T>::addScaled(const Grid<T> &a, const T &factor)
+{
+ gridScaledAdd<T, T>(*this, a, factor);
+}
+template<class T> void Grid<T>::setConst(T a)
+{
+ knGridSetConstReal<T>(*this, T(a));
+}
+template<class T> void Grid<T>::addConst(T a)
+{
+ knGridAddConstReal<T>(*this, T(a));
+}
+template<class T> void Grid<T>::multConst(T a)
+{
+ knGridMultConst<T>(*this, a);
+}
+
+template<class T> void Grid<T>::mult(const Grid<T> &a)
+{
+ gridMult<T, T>(*this, a);
+}
+
+template<class T> void Grid<T>::clamp(Real min, Real max)
+{
+ knGridClamp<T>(*this, T(min), T(max));
+}
+template<class T> void Grid<T>::stomp(const T &threshold)
+{
+ knGridStomp<T>(*this, threshold);
+}
+template<class T> void Grid<T>::permuteAxes(int axis0, int axis1, int axis2)
+{
+ if (axis0 == axis1 || axis0 == axis2 || axis1 == axis2 || axis0 > 2 || axis1 > 2 || axis2 > 2 ||
+ axis0 < 0 || axis1 < 0 || axis2 < 0)
+ return;
+ Vec3i size = mParent->getGridSize();
+ assertMsg(mParent->is2D() ? size.x == size.y : size.x == size.y && size.y == size.z,
+ "Grid must be cubic!");
+ Grid<T> tmp(mParent);
+ knPermuteAxes<T>(*this, tmp, axis0, axis1, axis2);
+ this->swap(tmp);
+}
+template<class T>
+void Grid<T>::permuteAxesCopyToGrid(int axis0, int axis1, int axis2, Grid<T> &out)
+{
+ if (axis0 == axis1 || axis0 == axis2 || axis1 == axis2 || axis0 > 2 || axis1 > 2 || axis2 > 2 ||
+ axis0 < 0 || axis1 < 0 || axis2 < 0)
+ return;
+ assertMsg(this->getGridType() == out.getGridType(), "Grids must have same data type!");
+ Vec3i size = mParent->getGridSize();
+ Vec3i sizeTarget = out.getParent()->getGridSize();
+ assertMsg(sizeTarget[axis0] == size[0] && sizeTarget[axis1] == size[1] &&
+ sizeTarget[axis2] == size[2],
+ "Permuted grids must have the same dimensions!");
+ knPermuteAxes<T>(*this, out, axis0, axis1, axis2);
+}
+
+template<> Real Grid<Real>::getMax() const
+{
+ return CompMaxReal(*this);
+}
+template<> Real Grid<Real>::getMin() const
+{
+ return CompMinReal(*this);
+}
+template<> Real Grid<Real>::getMaxAbs() const
+{
+ Real amin = CompMinReal(*this);
+ Real amax = CompMaxReal(*this);
+ return max(fabs(amin), fabs(amax));
+}
+template<> Real Grid<Vec3>::getMax() const
+{
+ return sqrt(CompMaxVec(*this));
+}
+template<> Real Grid<Vec3>::getMin() const
+{
+ return sqrt(CompMinVec(*this));
+}
+template<> Real Grid<Vec3>::getMaxAbs() const
+{
+ return sqrt(CompMaxVec(*this));
+}
+template<> Real Grid<int>::getMax() const
+{
+ return (Real)CompMaxInt(*this);
+}
+template<> Real Grid<int>::getMin() const
+{
+ return (Real)CompMinInt(*this);
+}
+template<> Real Grid<int>::getMaxAbs() const
+{
+ int amin = CompMinInt(*this);
+ int amax = CompMaxInt(*this);
+ return max(fabs((Real)amin), fabs((Real)amax));
+}
+template<class T> std::string Grid<T>::getDataPointer()
+{
+ std::ostringstream out;
+ out << mData;
+ return out.str();
+}
+
+// L1 / L2 functions
+
+//! calculate L1 norm for whole grid with non-parallelized loop
+template<class GRID> Real loop_calcL1Grid(const GRID &grid, int bnd)
+{
+ double accu = 0.;
+ FOR_IJKT_BND(grid, bnd)
+ {
+ accu += norm(grid(i, j, k, t));
+ }
+ return (Real)accu;
+}
+
+//! calculate L2 norm for whole grid with non-parallelized loop
+// note - kernels "could" be used here, but they can't be templated at the moment (also, that would
+// mean the bnd parameter is fixed)
+template<class GRID> Real loop_calcL2Grid(const GRID &grid, int bnd)
+{
+ double accu = 0.;
+ FOR_IJKT_BND(grid, bnd)
+ {
+ accu += normSquare(grid(i, j, k, t)); // supported for real and vec3,4 types
+ }
+ return (Real)sqrt(accu);
+}
+
+//! compute L1 norm of whole grid content (note, not parallel at the moment)
+template<class T> Real Grid<T>::getL1(int bnd)
+{
+ return loop_calcL1Grid<Grid<T>>(*this, bnd);
+}
+//! compute L2 norm of whole grid content (note, not parallel at the moment)
+template<class T> Real Grid<T>::getL2(int bnd)
+{
+ return loop_calcL2Grid<Grid<T>>(*this, bnd);
+}
+
+struct knCountCells : public KernelBase {
+ knCountCells(const FlagGrid &flags, int flag, int bnd, Grid<Real> *mask)
+ : KernelBase(&flags, 0), flags(flags), flag(flag), bnd(bnd), mask(mask), cnt(0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, const FlagGrid &flags, int flag, int bnd, Grid<Real> *mask, int &cnt)
+ {
+ if (mask)
+ (*mask)(i, j, k) = 0.;
+ if (bnd > 0 && (!flags.isInBounds(Vec3i(i, j, k), bnd)))
+ return;
+ if (flags(i, j, k) & flag) {
+ cnt++;
+ if (mask)
+ (*mask)(i, j, k) = 1.;
+ }
+ }
+ inline operator int()
+ {
+ return cnt;
+ }
+ inline int &getRet()
+ {
+ return cnt;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline int &getArg1()
+ {
+ return flag;
+ }
+ typedef int type1;
+ inline int &getArg2()
+ {
+ return bnd;
+ }
+ typedef int type2;
+ inline Grid<Real> *getArg3()
+ {
+ return mask;
+ }
+ typedef Grid<Real> type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCountCells ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, flag, bnd, mask, cnt);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, flag, bnd, mask, cnt);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ knCountCells(knCountCells &o, tbb::split)
+ : KernelBase(o), flags(o.flags), flag(o.flag), bnd(o.bnd), mask(o.mask), cnt(0)
+ {
+ }
+ void join(const knCountCells &o)
+ {
+ cnt += o.cnt;
+ }
+ const FlagGrid &flags;
+ int flag;
+ int bnd;
+ Grid<Real> *mask;
+ int cnt;
+};
+
+//! count number of cells of a certain type flag (can contain multiple bits, checks if any one of
+//! them is set - not all!)
+int FlagGrid::countCells(int flag, int bnd, Grid<Real> *mask)
+{
+ return knCountCells(*this, flag, bnd, mask);
+}
+
+// compute maximal diference of two cells in the grid
+// used for testing system
+
+Real gridMaxDiff(Grid<Real> &g1, Grid<Real> &g2)
+{
+ double maxVal = 0.;
+ FOR_IJK(g1)
+ {
+ maxVal = std::max(maxVal, (double)fabs(g1(i, j, k) - g2(i, j, k)));
+ }
+ return maxVal;
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "gridMaxDiff", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &g1 = *_args.getPtr<Grid<Real>>("g1", 0, &_lock);
+ Grid<Real> &g2 = *_args.getPtr<Grid<Real>>("g2", 1, &_lock);
+ _retval = toPy(gridMaxDiff(g1, g2));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "gridMaxDiff", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("gridMaxDiff", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_gridMaxDiff("", "gridMaxDiff", _W_0);
+extern "C" {
+void PbRegister_gridMaxDiff()
+{
+ KEEP_UNUSED(_RP_gridMaxDiff);
+}
+}
+
+Real gridMaxDiffInt(Grid<int> &g1, Grid<int> &g2)
+{
+ double maxVal = 0.;
+ FOR_IJK(g1)
+ {
+ maxVal = std::max(maxVal, (double)fabs((double)g1(i, j, k) - g2(i, j, k)));
+ }
+ return maxVal;
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "gridMaxDiffInt", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<int> &g1 = *_args.getPtr<Grid<int>>("g1", 0, &_lock);
+ Grid<int> &g2 = *_args.getPtr<Grid<int>>("g2", 1, &_lock);
+ _retval = toPy(gridMaxDiffInt(g1, g2));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "gridMaxDiffInt", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("gridMaxDiffInt", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_gridMaxDiffInt("", "gridMaxDiffInt", _W_1);
+extern "C" {
+void PbRegister_gridMaxDiffInt()
+{
+ KEEP_UNUSED(_RP_gridMaxDiffInt);
+}
+}
+
+Real gridMaxDiffVec3(Grid<Vec3> &g1, Grid<Vec3> &g2)
+{
+ double maxVal = 0.;
+ FOR_IJK(g1)
+ {
+ // accumulate differences with double precision
+ // note - don't use norm here! should be as precise as possible...
+ double d = 0.;
+ for (int c = 0; c < 3; ++c) {
+ d += fabs((double)g1(i, j, k)[c] - (double)g2(i, j, k)[c]);
+ }
+ maxVal = std::max(maxVal, d);
+ // maxVal = std::max(maxVal, (double)fabs( norm(g1(i,j,k)-g2(i,j,k)) ));
+ }
+ return maxVal;
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "gridMaxDiffVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &g1 = *_args.getPtr<Grid<Vec3>>("g1", 0, &_lock);
+ Grid<Vec3> &g2 = *_args.getPtr<Grid<Vec3>>("g2", 1, &_lock);
+ _retval = toPy(gridMaxDiffVec3(g1, g2));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "gridMaxDiffVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("gridMaxDiffVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_gridMaxDiffVec3("", "gridMaxDiffVec3", _W_2);
+extern "C" {
+void PbRegister_gridMaxDiffVec3()
+{
+ KEEP_UNUSED(_RP_gridMaxDiffVec3);
+}
+}
+
+// simple helper functions to copy (convert) mac to vec3 , and levelset to real grids
+// (are assumed to be the same for running the test cases - in general they're not!)
+
+void copyMacToVec3(MACGrid &source, Grid<Vec3> &target)
+{
+ FOR_IJK(target)
+ {
+ target(i, j, k) = source(i, j, k);
+ }
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "copyMacToVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &source = *_args.getPtr<MACGrid>("source", 0, &_lock);
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock);
+ _retval = getPyNone();
+ copyMacToVec3(source, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "copyMacToVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("copyMacToVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_copyMacToVec3("", "copyMacToVec3", _W_3);
+extern "C" {
+void PbRegister_copyMacToVec3()
+{
+ KEEP_UNUSED(_RP_copyMacToVec3);
+}
+}
+
+void convertMacToVec3(MACGrid &source, Grid<Vec3> &target)
+{
+ debMsg("Deprecated - do not use convertMacToVec3... use copyMacToVec3 instead", 1);
+ copyMacToVec3(source, target);
+}
+static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "convertMacToVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &source = *_args.getPtr<MACGrid>("source", 0, &_lock);
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock);
+ _retval = getPyNone();
+ convertMacToVec3(source, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "convertMacToVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("convertMacToVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_convertMacToVec3("", "convertMacToVec3", _W_4);
+extern "C" {
+void PbRegister_convertMacToVec3()
+{
+ KEEP_UNUSED(_RP_convertMacToVec3);
+}
+}
+
+//! vec3->mac grid conversion , but with full resampling
+void resampleVec3ToMac(Grid<Vec3> &source, MACGrid &target)
+{
+ FOR_IJK_BND(target, 1)
+ {
+ target(i, j, k)[0] = 0.5 * (source(i - 1, j, k)[0] + source(i, j, k))[0];
+ target(i, j, k)[1] = 0.5 * (source(i, j - 1, k)[1] + source(i, j, k))[1];
+ if (target.is3D()) {
+ target(i, j, k)[2] = 0.5 * (source(i, j, k - 1)[2] + source(i, j, k))[2];
+ }
+ }
+}
+static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "resampleVec3ToMac", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &source = *_args.getPtr<Grid<Vec3>>("source", 0, &_lock);
+ MACGrid &target = *_args.getPtr<MACGrid>("target", 1, &_lock);
+ _retval = getPyNone();
+ resampleVec3ToMac(source, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "resampleVec3ToMac", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("resampleVec3ToMac", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_resampleVec3ToMac("", "resampleVec3ToMac", _W_5);
+extern "C" {
+void PbRegister_resampleVec3ToMac()
+{
+ KEEP_UNUSED(_RP_resampleVec3ToMac);
+}
+}
+
+//! mac->vec3 grid conversion , with full resampling
+void resampleMacToVec3(MACGrid &source, Grid<Vec3> &target)
+{
+ FOR_IJK_BND(target, 1)
+ {
+ target(i, j, k) = source.getCentered(i, j, k);
+ }
+}
+static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "resampleMacToVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &source = *_args.getPtr<MACGrid>("source", 0, &_lock);
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock);
+ _retval = getPyNone();
+ resampleMacToVec3(source, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "resampleMacToVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("resampleMacToVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_resampleMacToVec3("", "resampleMacToVec3", _W_6);
+extern "C" {
+void PbRegister_resampleMacToVec3()
+{
+ KEEP_UNUSED(_RP_resampleMacToVec3);
+}
+}
+
+void copyLevelsetToReal(LevelsetGrid &source, Grid<Real> &target)
+{
+ FOR_IJK(target)
+ {
+ target(i, j, k) = source(i, j, k);
+ }
+}
+static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "copyLevelsetToReal", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ LevelsetGrid &source = *_args.getPtr<LevelsetGrid>("source", 0, &_lock);
+ Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 1, &_lock);
+ _retval = getPyNone();
+ copyLevelsetToReal(source, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "copyLevelsetToReal", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("copyLevelsetToReal", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_copyLevelsetToReal("", "copyLevelsetToReal", _W_7);
+extern "C" {
+void PbRegister_copyLevelsetToReal()
+{
+ KEEP_UNUSED(_RP_copyLevelsetToReal);
+}
+}
+
+void copyVec3ToReal(Grid<Vec3> &source,
+ Grid<Real> &targetX,
+ Grid<Real> &targetY,
+ Grid<Real> &targetZ)
+{
+ FOR_IJK(source)
+ {
+ targetX(i, j, k) = source(i, j, k).x;
+ targetY(i, j, k) = source(i, j, k).y;
+ targetZ(i, j, k) = source(i, j, k).z;
+ }
+}
+static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "copyVec3ToReal", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &source = *_args.getPtr<Grid<Vec3>>("source", 0, &_lock);
+ Grid<Real> &targetX = *_args.getPtr<Grid<Real>>("targetX", 1, &_lock);
+ Grid<Real> &targetY = *_args.getPtr<Grid<Real>>("targetY", 2, &_lock);
+ Grid<Real> &targetZ = *_args.getPtr<Grid<Real>>("targetZ", 3, &_lock);
+ _retval = getPyNone();
+ copyVec3ToReal(source, targetX, targetY, targetZ);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "copyVec3ToReal", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("copyVec3ToReal", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_copyVec3ToReal("", "copyVec3ToReal", _W_8);
+extern "C" {
+void PbRegister_copyVec3ToReal()
+{
+ KEEP_UNUSED(_RP_copyVec3ToReal);
+}
+}
+
+void copyRealToVec3(Grid<Real> &sourceX,
+ Grid<Real> &sourceY,
+ Grid<Real> &sourceZ,
+ Grid<Vec3> &target)
+{
+ FOR_IJK(target)
+ {
+ target(i, j, k).x = sourceX(i, j, k);
+ target(i, j, k).y = sourceY(i, j, k);
+ target(i, j, k).z = sourceZ(i, j, k);
+ }
+}
+static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "copyRealToVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &sourceX = *_args.getPtr<Grid<Real>>("sourceX", 0, &_lock);
+ Grid<Real> &sourceY = *_args.getPtr<Grid<Real>>("sourceY", 1, &_lock);
+ Grid<Real> &sourceZ = *_args.getPtr<Grid<Real>>("sourceZ", 2, &_lock);
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 3, &_lock);
+ _retval = getPyNone();
+ copyRealToVec3(sourceX, sourceY, sourceZ, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "copyRealToVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("copyRealToVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_copyRealToVec3("", "copyRealToVec3", _W_9);
+extern "C" {
+void PbRegister_copyRealToVec3()
+{
+ KEEP_UNUSED(_RP_copyRealToVec3);
+}
+}
+
+void convertLevelsetToReal(LevelsetGrid &source, Grid<Real> &target)
+{
+ debMsg("Deprecated - do not use convertLevelsetToReal... use copyLevelsetToReal instead", 1);
+ copyLevelsetToReal(source, target);
+}
+static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "convertLevelsetToReal", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ LevelsetGrid &source = *_args.getPtr<LevelsetGrid>("source", 0, &_lock);
+ Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 1, &_lock);
+ _retval = getPyNone();
+ convertLevelsetToReal(source, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "convertLevelsetToReal", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("convertLevelsetToReal", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_convertLevelsetToReal("", "convertLevelsetToReal", _W_10);
+extern "C" {
+void PbRegister_convertLevelsetToReal()
+{
+ KEEP_UNUSED(_RP_convertLevelsetToReal);
+}
+}
+
+template<class T> void Grid<T>::printGrid(int zSlice, bool printIndex, int bnd)
+{
+ std::ostringstream out;
+ out << std::endl;
+ FOR_IJK_BND(*this, bnd)
+ {
+ IndexInt idx = (*this).index(i, j, k);
+ if ((zSlice >= 0 && k == zSlice) || (zSlice < 0)) {
+ out << " ";
+ if (printIndex && this->is3D())
+ out << " " << i << "," << j << "," << k << ":";
+ if (printIndex && !this->is3D())
+ out << " " << i << "," << j << ":";
+ out << (*this)[idx];
+ if (i == (*this).getSizeX() - 1 - bnd)
+ out << std::endl;
+ }
+ }
+ out << endl;
+ debMsg("Printing " << this->getName() << out.str().c_str(), 1);
+}
+
+//! helper to swap components of a grid (eg for data import)
+void swapComponents(Grid<Vec3> &vel, int c1 = 0, int c2 = 1, int c3 = 2)
+{
+ FOR_IJK(vel)
+ {
+ Vec3 v = vel(i, j, k);
+ vel(i, j, k)[0] = v[c1];
+ vel(i, j, k)[1] = v[c2];
+ vel(i, j, k)[2] = v[c3];
+ }
+}
+static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "swapComponents", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &vel = *_args.getPtr<Grid<Vec3>>("vel", 0, &_lock);
+ int c1 = _args.getOpt<int>("c1", 1, 0, &_lock);
+ int c2 = _args.getOpt<int>("c2", 2, 1, &_lock);
+ int c3 = _args.getOpt<int>("c3", 3, 2, &_lock);
+ _retval = getPyNone();
+ swapComponents(vel, c1, c2, c3);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "swapComponents", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("swapComponents", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_swapComponents("", "swapComponents", _W_11);
+extern "C" {
+void PbRegister_swapComponents()
+{
+ KEEP_UNUSED(_RP_swapComponents);
+}
+}
+
+// helper functions for UV grid data (stored grid coordinates as Vec3 values, and uv weight in
+// entry zero)
+
+// make uv weight accesible in python
+Real getUvWeight(Grid<Vec3> &uv)
+{
+ return uv[0][0];
+}
+static PyObject *_W_12(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getUvWeight", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &uv = *_args.getPtr<Grid<Vec3>>("uv", 0, &_lock);
+ _retval = toPy(getUvWeight(uv));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getUvWeight", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getUvWeight", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getUvWeight("", "getUvWeight", _W_12);
+extern "C" {
+void PbRegister_getUvWeight()
+{
+ KEEP_UNUSED(_RP_getUvWeight);
+}
+}
+
+// note - right now the UV grids have 0 values at the border after advection... could be fixed with
+// an extrapolation step...
+
+// compute normalized modulo interval
+static inline Real computeUvGridTime(Real t, Real resetTime)
+{
+ return fmod((t / resetTime), (Real)1.);
+}
+// create ramp function in 0..1 range with half frequency
+static inline Real computeUvRamp(Real t)
+{
+ Real uvWeight = 2. * t;
+ if (uvWeight > 1.)
+ uvWeight = 2. - uvWeight;
+ return uvWeight;
+}
+
+struct knResetUvGrid : public KernelBase {
+ knResetUvGrid(Grid<Vec3> &target, const Vec3 *offset)
+ : KernelBase(&target, 0), target(target), offset(offset)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Vec3> &target, const Vec3 *offset) const
+ {
+ Vec3 coord = Vec3((Real)i, (Real)j, (Real)k);
+ if (offset)
+ coord += (*offset);
+ target(i, j, k) = coord;
+ }
+ inline Grid<Vec3> &getArg0()
+ {
+ return target;
+ }
+ typedef Grid<Vec3> type0;
+ inline const Vec3 *getArg1()
+ {
+ return offset;
+ }
+ typedef Vec3 type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knResetUvGrid ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, target, offset);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, target, offset);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<Vec3> &target;
+ const Vec3 *offset;
+};
+
+void resetUvGrid(Grid<Vec3> &target, const Vec3 *offset = NULL)
+{
+ knResetUvGrid reset(target,
+ offset); // note, llvm complains about anonymous declaration here... ?
+}
+static PyObject *_W_13(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "resetUvGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 0, &_lock);
+ const Vec3 *offset = _args.getPtrOpt<Vec3>("offset", 1, NULL, &_lock);
+ _retval = getPyNone();
+ resetUvGrid(target, offset);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "resetUvGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("resetUvGrid", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_resetUvGrid("", "resetUvGrid", _W_13);
+extern "C" {
+void PbRegister_resetUvGrid()
+{
+ KEEP_UNUSED(_RP_resetUvGrid);
+}
+}
+
+void updateUvWeight(
+ Real resetTime, int index, int numUvs, Grid<Vec3> &uv, const Vec3 *offset = NULL)
+{
+ const Real t = uv.getParent()->getTime();
+ Real timeOff = resetTime / (Real)numUvs;
+
+ Real lastt = computeUvGridTime(t + (Real)index * timeOff - uv.getParent()->getDt(), resetTime);
+ Real currt = computeUvGridTime(t + (Real)index * timeOff, resetTime);
+ Real uvWeight = computeUvRamp(currt);
+
+ // normalize the uvw weights , note: this is a bit wasteful...
+ Real uvWTotal = 0.;
+ for (int i = 0; i < numUvs; ++i) {
+ uvWTotal += computeUvRamp(computeUvGridTime(t + (Real)i * timeOff, resetTime));
+ }
+ if (uvWTotal <= VECTOR_EPSILON) {
+ uvWeight = uvWTotal = 1.;
+ }
+ else
+ uvWeight /= uvWTotal;
+
+ // check for reset
+ if (currt < lastt)
+ knResetUvGrid reset(uv, offset);
+
+ // write new weight value to grid
+ uv[0] = Vec3(uvWeight, 0., 0.);
+
+ // print info about uv weights?
+ debMsg("Uv grid " << index << "/" << numUvs << " t=" << currt << " w=" << uvWeight
+ << ", reset:" << (int)(currt < lastt),
+ 2);
+}
+static PyObject *_W_14(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "updateUvWeight", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real resetTime = _args.get<Real>("resetTime", 0, &_lock);
+ int index = _args.get<int>("index", 1, &_lock);
+ int numUvs = _args.get<int>("numUvs", 2, &_lock);
+ Grid<Vec3> &uv = *_args.getPtr<Grid<Vec3>>("uv", 3, &_lock);
+ const Vec3 *offset = _args.getPtrOpt<Vec3>("offset", 4, NULL, &_lock);
+ _retval = getPyNone();
+ updateUvWeight(resetTime, index, numUvs, uv, offset);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "updateUvWeight", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("updateUvWeight", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_updateUvWeight("", "updateUvWeight", _W_14);
+extern "C" {
+void PbRegister_updateUvWeight()
+{
+ KEEP_UNUSED(_RP_updateUvWeight);
+}
+}
+
+template<class T> struct knSetBoundary : public KernelBase {
+ knSetBoundary(Grid<T> &grid, T value, int w)
+ : KernelBase(&grid, 0), grid(grid), value(value), w(w)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<T> &grid, T value, int w) const
+ {
+ bool bnd = (i <= w || i >= grid.getSizeX() - 1 - w || j <= w || j >= grid.getSizeY() - 1 - w ||
+ (grid.is3D() && (k <= w || k >= grid.getSizeZ() - 1 - w)));
+ if (bnd)
+ grid(i, j, k) = value;
+ }
+ inline Grid<T> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<T> type0;
+ inline T &getArg1()
+ {
+ return value;
+ }
+ typedef T type1;
+ inline int &getArg2()
+ {
+ return w;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetBoundary ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, value, w);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, value, w);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<T> &grid;
+ T value;
+ int w;
+};
+
+template<class T> void Grid<T>::setBound(T value, int boundaryWidth)
+{
+ knSetBoundary<T>(*this, value, boundaryWidth);
+}
+
+template<class T> struct knSetBoundaryNeumann : public KernelBase {
+ knSetBoundaryNeumann(Grid<T> &grid, int w) : KernelBase(&grid, 0), grid(grid), w(w)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<T> &grid, int w) const
+ {
+ bool set = false;
+ int si = i, sj = j, sk = k;
+ if (i <= w) {
+ si = w + 1;
+ set = true;
+ }
+ if (i >= grid.getSizeX() - 1 - w) {
+ si = grid.getSizeX() - 1 - w - 1;
+ set = true;
+ }
+ if (j <= w) {
+ sj = w + 1;
+ set = true;
+ }
+ if (j >= grid.getSizeY() - 1 - w) {
+ sj = grid.getSizeY() - 1 - w - 1;
+ set = true;
+ }
+ if (grid.is3D()) {
+ if (k <= w) {
+ sk = w + 1;
+ set = true;
+ }
+ if (k >= grid.getSizeZ() - 1 - w) {
+ sk = grid.getSizeZ() - 1 - w - 1;
+ set = true;
+ }
+ }
+ if (set)
+ grid(i, j, k) = grid(si, sj, sk);
+ }
+ inline Grid<T> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<T> type0;
+ inline int &getArg1()
+ {
+ return w;
+ }
+ typedef int type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetBoundaryNeumann ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, w);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, w);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<T> &grid;
+ int w;
+};
+
+template<class T> void Grid<T>::setBoundNeumann(int boundaryWidth)
+{
+ knSetBoundaryNeumann<T>(*this, boundaryWidth);
+}
+
+//! kernel to set velocity components of mac grid to value for a boundary of w cells
+struct knSetBoundaryMAC : public KernelBase {
+ knSetBoundaryMAC(Grid<Vec3> &grid, Vec3 value, int w)
+ : KernelBase(&grid, 0), grid(grid), value(value), w(w)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Vec3> &grid, Vec3 value, int w) const
+ {
+ if (i <= w || i >= grid.getSizeX() - w || j <= w - 1 || j >= grid.getSizeY() - 1 - w ||
+ (grid.is3D() && (k <= w - 1 || k >= grid.getSizeZ() - 1 - w)))
+ grid(i, j, k).x = value.x;
+ if (i <= w - 1 || i >= grid.getSizeX() - 1 - w || j <= w || j >= grid.getSizeY() - w ||
+ (grid.is3D() && (k <= w - 1 || k >= grid.getSizeZ() - 1 - w)))
+ grid(i, j, k).y = value.y;
+ if (i <= w - 1 || i >= grid.getSizeX() - 1 - w || j <= w - 1 || j >= grid.getSizeY() - 1 - w ||
+ (grid.is3D() && (k <= w || k >= grid.getSizeZ() - w)))
+ grid(i, j, k).z = value.z;
+ }
+ inline Grid<Vec3> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<Vec3> type0;
+ inline Vec3 &getArg1()
+ {
+ return value;
+ }
+ typedef Vec3 type1;
+ inline int &getArg2()
+ {
+ return w;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetBoundaryMAC ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, value, w);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, value, w);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<Vec3> &grid;
+ Vec3 value;
+ int w;
+};
+
+//! only set normal velocity components of mac grid to value for a boundary of w cells
+struct knSetBoundaryMACNorm : public KernelBase {
+ knSetBoundaryMACNorm(Grid<Vec3> &grid, Vec3 value, int w)
+ : KernelBase(&grid, 0), grid(grid), value(value), w(w)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Vec3> &grid, Vec3 value, int w) const
+ {
+ if (i <= w || i >= grid.getSizeX() - w)
+ grid(i, j, k).x = value.x;
+ if (j <= w || j >= grid.getSizeY() - w)
+ grid(i, j, k).y = value.y;
+ if ((grid.is3D() && (k <= w || k >= grid.getSizeZ() - w)))
+ grid(i, j, k).z = value.z;
+ }
+ inline Grid<Vec3> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<Vec3> type0;
+ inline Vec3 &getArg1()
+ {
+ return value;
+ }
+ typedef Vec3 type1;
+ inline int &getArg2()
+ {
+ return w;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetBoundaryMACNorm ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, value, w);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, value, w);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<Vec3> &grid;
+ Vec3 value;
+ int w;
+};
+
+//! set velocity components of mac grid to value for a boundary of w cells (optionally only normal
+//! values)
+void MACGrid::setBoundMAC(Vec3 value, int boundaryWidth, bool normalOnly)
+{
+ if (!normalOnly)
+ knSetBoundaryMAC(*this, value, boundaryWidth);
+ else
+ knSetBoundaryMACNorm(*this, value, boundaryWidth);
+}
+
+//! helper kernels for getGridAvg
+
+struct knGridTotalSum : public KernelBase {
+ knGridTotalSum(const Grid<Real> &a, FlagGrid *flags)
+ : KernelBase(&a, 0), a(a), flags(flags), result(0.0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Real> &a, FlagGrid *flags, double &result)
+ {
+ if (flags) {
+ if (flags->isFluid(idx))
+ result += a[idx];
+ }
+ else {
+ result += a[idx];
+ }
+ }
+ inline operator double()
+ {
+ return result;
+ }
+ inline double &getRet()
+ {
+ return result;
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return a;
+ }
+ typedef Grid<Real> type0;
+ inline FlagGrid *getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knGridTotalSum ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, a, flags, result);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ knGridTotalSum(knGridTotalSum &o, tbb::split)
+ : KernelBase(o), a(o.a), flags(o.flags), result(0.0)
+ {
+ }
+ void join(const knGridTotalSum &o)
+ {
+ result += o.result;
+ }
+ const Grid<Real> &a;
+ FlagGrid *flags;
+ double result;
+};
+
+struct knCountFluidCells : public KernelBase {
+ knCountFluidCells(FlagGrid &flags) : KernelBase(&flags, 0), flags(flags), numEmpty(0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, FlagGrid &flags, int &numEmpty)
+ {
+ if (flags.isFluid(idx))
+ numEmpty++;
+ }
+ inline operator int()
+ {
+ return numEmpty;
+ }
+ inline int &getRet()
+ {
+ return numEmpty;
+ }
+ inline FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCountFluidCells ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, flags, numEmpty);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ knCountFluidCells(knCountFluidCells &o, tbb::split) : KernelBase(o), flags(o.flags), numEmpty(0)
+ {
+ }
+ void join(const knCountFluidCells &o)
+ {
+ numEmpty += o.numEmpty;
+ }
+ FlagGrid &flags;
+ int numEmpty;
+};
+
+//! averaged value for all cells (if flags are given, only for fluid cells)
+
+Real getGridAvg(Grid<Real> &source, FlagGrid *flags = NULL)
+{
+ double sum = knGridTotalSum(source, flags);
+
+ double cells;
+ if (flags) {
+ cells = knCountFluidCells(*flags);
+ }
+ else {
+ cells = source.getSizeX() * source.getSizeY() * source.getSizeZ();
+ }
+
+ if (cells > 0.)
+ sum *= 1. / cells;
+ else
+ sum = -1.;
+ return sum;
+}
+static PyObject *_W_15(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getGridAvg", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &source = *_args.getPtr<Grid<Real>>("source", 0, &_lock);
+ FlagGrid *flags = _args.getPtrOpt<FlagGrid>("flags", 1, NULL, &_lock);
+ _retval = toPy(getGridAvg(source, flags));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getGridAvg", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getGridAvg", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getGridAvg("", "getGridAvg", _W_15);
+extern "C" {
+void PbRegister_getGridAvg()
+{
+ KEEP_UNUSED(_RP_getGridAvg);
+}
+}
+
+//! transfer data between real and vec3 grids
+
+struct knGetComponent : public KernelBase {
+ knGetComponent(const Grid<Vec3> &source, Grid<Real> &target, int component)
+ : KernelBase(&source, 0), source(source), target(target), component(component)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Vec3> &source, Grid<Real> &target, int component) const
+ {
+ target[idx] = source[idx][component];
+ }
+ inline const Grid<Vec3> &getArg0()
+ {
+ return source;
+ }
+ typedef Grid<Vec3> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return target;
+ }
+ typedef Grid<Real> type1;
+ inline int &getArg2()
+ {
+ return component;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knGetComponent ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, source, target, component);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const Grid<Vec3> &source;
+ Grid<Real> &target;
+ int component;
+};
+void getComponent(const Grid<Vec3> &source, Grid<Real> &target, int component)
+{
+ knGetComponent(source, target, component);
+}
+static PyObject *_W_16(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getComponent", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Vec3> &source = *_args.getPtr<Grid<Vec3>>("source", 0, &_lock);
+ Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 1, &_lock);
+ int component = _args.get<int>("component", 2, &_lock);
+ _retval = getPyNone();
+ getComponent(source, target, component);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getComponent", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getComponent", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getComponent("", "getComponent", _W_16);
+extern "C" {
+void PbRegister_getComponent()
+{
+ KEEP_UNUSED(_RP_getComponent);
+}
+}
+
+struct knSetComponent : public KernelBase {
+ knSetComponent(const Grid<Real> &source, Grid<Vec3> &target, int component)
+ : KernelBase(&source, 0), source(source), target(target), component(component)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Real> &source, Grid<Vec3> &target, int component) const
+ {
+ target[idx][component] = source[idx];
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return source;
+ }
+ typedef Grid<Real> type0;
+ inline Grid<Vec3> &getArg1()
+ {
+ return target;
+ }
+ typedef Grid<Vec3> type1;
+ inline int &getArg2()
+ {
+ return component;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetComponent ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, source, target, component);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const Grid<Real> &source;
+ Grid<Vec3> &target;
+ int component;
+};
+void setComponent(const Grid<Real> &source, Grid<Vec3> &target, int component)
+{
+ knSetComponent(source, target, component);
+}
+static PyObject *_W_17(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setComponent", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Real> &source = *_args.getPtr<Grid<Real>>("source", 0, &_lock);
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock);
+ int component = _args.get<int>("component", 2, &_lock);
+ _retval = getPyNone();
+ setComponent(source, target, component);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setComponent", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setComponent", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setComponent("", "setComponent", _W_17);
+extern "C" {
+void PbRegister_setComponent()
+{
+ KEEP_UNUSED(_RP_setComponent);
+}
+}
+
+//******************************************************************************
+// Specialization classes
+
+void FlagGrid::InitMinXWall(const int &boundaryWidth, Grid<Real> &phiWalls)
+{
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls)
+ {
+ phiWalls(i, j, k) = std::min(i - w - .5, (double)phiWalls(i, j, k));
+ }
+}
+
+void FlagGrid::InitMaxXWall(const int &boundaryWidth, Grid<Real> &phiWalls)
+{
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls)
+ {
+ phiWalls(i, j, k) = std::min(mSize.x - i - 1.5 - w, (double)phiWalls(i, j, k));
+ }
+}
+
+void FlagGrid::InitMinYWall(const int &boundaryWidth, Grid<Real> &phiWalls)
+{
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls)
+ {
+ phiWalls(i, j, k) = std::min(j - w - .5, (double)phiWalls(i, j, k));
+ }
+}
+
+void FlagGrid::InitMaxYWall(const int &boundaryWidth, Grid<Real> &phiWalls)
+{
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls)
+ {
+ phiWalls(i, j, k) = std::min(mSize.y - j - 1.5 - w, (double)phiWalls(i, j, k));
+ }
+}
+
+void FlagGrid::InitMinZWall(const int &boundaryWidth, Grid<Real> &phiWalls)
+{
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls)
+ {
+ phiWalls(i, j, k) = std::min(k - w - .5, (double)phiWalls(i, j, k));
+ }
+}
+
+void FlagGrid::InitMaxZWall(const int &boundaryWidth, Grid<Real> &phiWalls)
+{
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls)
+ {
+ phiWalls(i, j, k) = std::min(mSize.z - k - 1.5 - w, (double)phiWalls(i, j, k));
+ }
+}
+
+void FlagGrid::initDomain(const int &boundaryWidth,
+ const string &wallIn,
+ const string &openIn,
+ const string &inflowIn,
+ const string &outflowIn,
+ Grid<Real> *phiWalls)
+{
+
+ int types[6] = {0};
+ bool set[6] = {false};
+ // make sure we have at least 6 entries
+ string wall = wallIn;
+ wall.append(" ");
+ string open = openIn;
+ open.append(" ");
+ string inflow = inflowIn;
+ inflow.append(" ");
+ string outflow = outflowIn;
+ outflow.append(" ");
+
+ if (phiWalls)
+ phiWalls->setConst(1000000000);
+
+ for (int i = 0; i < 6; ++i) {
+ // min x-direction
+ if (!set[0]) {
+ if (open[i] == 'x') {
+ types[0] = TypeOpen;
+ set[0] = true;
+ }
+ else if (inflow[i] == 'x') {
+ types[0] = TypeInflow;
+ set[0] = true;
+ }
+ else if (outflow[i] == 'x') {
+ types[0] = TypeOutflow;
+ set[0] = true;
+ }
+ else if (wall[i] == 'x') {
+ types[0] = TypeObstacle;
+ if (phiWalls)
+ InitMinXWall(boundaryWidth, *phiWalls);
+ set[0] = true;
+ }
+ }
+ // max x-direction
+ if (!set[1]) {
+ if (open[i] == 'X') {
+ types[1] = TypeOpen;
+ set[1] = true;
+ }
+ else if (inflow[i] == 'X') {
+ types[1] = TypeInflow;
+ set[1] = true;
+ }
+ else if (outflow[i] == 'X') {
+ types[1] = TypeOutflow;
+ set[1] = true;
+ }
+ else if (wall[i] == 'X') {
+ types[1] = TypeObstacle;
+ if (phiWalls)
+ InitMaxXWall(boundaryWidth, *phiWalls);
+ set[1] = true;
+ }
+ }
+ // min y-direction
+ if (!set[2]) {
+ if (open[i] == 'y') {
+ types[2] = TypeOpen;
+ set[2] = true;
+ }
+ else if (inflow[i] == 'y') {
+ types[2] = TypeInflow;
+ set[2] = true;
+ }
+ else if (outflow[i] == 'y') {
+ types[2] = TypeOutflow;
+ set[2] = true;
+ }
+ else if (wall[i] == 'y') {
+ types[2] = TypeObstacle;
+ if (phiWalls)
+ InitMinYWall(boundaryWidth, *phiWalls);
+ set[2] = true;
+ }
+ }
+ // max y-direction
+ if (!set[3]) {
+ if (open[i] == 'Y') {
+ types[3] = TypeOpen;
+ set[3] = true;
+ }
+ else if (inflow[i] == 'Y') {
+ types[3] = TypeInflow;
+ set[3] = true;
+ }
+ else if (outflow[i] == 'Y') {
+ types[3] = TypeOutflow;
+ set[3] = true;
+ }
+ else if (wall[i] == 'Y') {
+ types[3] = TypeObstacle;
+ if (phiWalls)
+ InitMaxYWall(boundaryWidth, *phiWalls);
+ set[3] = true;
+ }
+ }
+ if (this->is3D()) {
+ // min z-direction
+ if (!set[4]) {
+ if (open[i] == 'z') {
+ types[4] = TypeOpen;
+ set[4] = true;
+ }
+ else if (inflow[i] == 'z') {
+ types[4] = TypeInflow;
+ set[4] = true;
+ }
+ else if (outflow[i] == 'z') {
+ types[4] = TypeOutflow;
+ set[4] = true;
+ }
+ else if (wall[i] == 'z') {
+ types[4] = TypeObstacle;
+ if (phiWalls)
+ InitMinZWall(boundaryWidth, *phiWalls);
+ set[4] = true;
+ }
+ }
+ // max z-direction
+ if (!set[5]) {
+ if (open[i] == 'Z') {
+ types[5] = TypeOpen;
+ set[5] = true;
+ }
+ else if (inflow[i] == 'Z') {
+ types[5] = TypeInflow;
+ set[5] = true;
+ }
+ else if (outflow[i] == 'Z') {
+ types[5] = TypeOutflow;
+ set[5] = true;
+ }
+ else if (wall[i] == 'Z') {
+ types[5] = TypeObstacle;
+ if (phiWalls)
+ InitMaxZWall(boundaryWidth, *phiWalls);
+ set[5] = true;
+ }
+ }
+ }
+ }
+
+ setConst(TypeEmpty);
+ initBoundaries(boundaryWidth, types);
+}
+
+void FlagGrid::initBoundaries(const int &boundaryWidth, const int *types)
+{
+ const int w = boundaryWidth;
+ FOR_IJK(*this)
+ {
+ bool bnd = (i <= w);
+ if (bnd)
+ mData[index(i, j, k)] = types[0];
+ bnd = (i >= mSize.x - 1 - w);
+ if (bnd)
+ mData[index(i, j, k)] = types[1];
+ bnd = (j <= w);
+ if (bnd)
+ mData[index(i, j, k)] = types[2];
+ bnd = (j >= mSize.y - 1 - w);
+ if (bnd)
+ mData[index(i, j, k)] = types[3];
+ if (is3D()) {
+ bnd = (k <= w);
+ if (bnd)
+ mData[index(i, j, k)] = types[4];
+ bnd = (k >= mSize.z - 1 - w);
+ if (bnd)
+ mData[index(i, j, k)] = types[5];
+ }
+ }
+}
+
+void FlagGrid::updateFromLevelset(LevelsetGrid &levelset)
+{
+ FOR_IDX(*this)
+ {
+ if (!isObstacle(idx) && !isOutflow(idx)) {
+ const Real phi = levelset[idx];
+ if (phi <= levelset.invalidTimeValue())
+ continue;
+
+ mData[idx] &= ~(TypeEmpty | TypeFluid); // clear empty/fluid flags
+ mData[idx] |= (phi <= 0) ? TypeFluid : TypeEmpty; // set resepctive flag
+ }
+ }
+}
+
+void FlagGrid::fillGrid(int type)
+{
+ FOR_IDX(*this)
+ {
+ if ((mData[idx] & TypeObstacle) == 0 && (mData[idx] & TypeInflow) == 0 &&
+ (mData[idx] & TypeOutflow) == 0 && (mData[idx] & TypeOpen) == 0)
+ mData[idx] = (mData[idx] & ~(TypeEmpty | TypeFluid)) | type;
+ }
+}
+
+// flag grid helper
+
+bool isIsolatedFluidCell(const IndexInt idx, const FlagGrid &flags)
+{
+ if (!flags.isFluid(idx))
+ return false;
+ if (flags.isFluid(idx - flags.getStrideX()))
+ return false;
+ if (flags.isFluid(idx + flags.getStrideX()))
+ return false;
+ if (flags.isFluid(idx - flags.getStrideY()))
+ return false;
+ if (flags.isFluid(idx + flags.getStrideY()))
+ return false;
+ if (!flags.is3D())
+ return true;
+ if (flags.isFluid(idx - flags.getStrideZ()))
+ return false;
+ if (flags.isFluid(idx + flags.getStrideZ()))
+ return false;
+ return true;
+}
+
+struct knMarkIsolatedFluidCell : public KernelBase {
+ knMarkIsolatedFluidCell(FlagGrid &flags, const int mark)
+ : KernelBase(&flags, 0), flags(flags), mark(mark)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, FlagGrid &flags, const int mark) const
+ {
+ if (isIsolatedFluidCell(idx, flags))
+ flags[idx] = mark;
+ }
+ inline FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const int &getArg1()
+ {
+ return mark;
+ }
+ typedef int type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMarkIsolatedFluidCell ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, flags, mark);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ FlagGrid &flags;
+ const int mark;
+};
+
+void markIsolatedFluidCell(FlagGrid &flags, const int mark)
+{
+ knMarkIsolatedFluidCell(flags, mark);
+}
+static PyObject *_W_18(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "markIsolatedFluidCell", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const int mark = _args.get<int>("mark", 1, &_lock);
+ _retval = getPyNone();
+ markIsolatedFluidCell(flags, mark);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "markIsolatedFluidCell", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("markIsolatedFluidCell", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_markIsolatedFluidCell("", "markIsolatedFluidCell", _W_18);
+extern "C" {
+void PbRegister_markIsolatedFluidCell()
+{
+ KEEP_UNUSED(_RP_markIsolatedFluidCell);
+}
+}
+
+void copyMACData(
+ const MACGrid &source, MACGrid &target, const FlagGrid &flags, const int flag, const int bnd)
+{
+ assertMsg(source.getSize().x == target.getSize().x && source.getSize().y == target.getSize().y &&
+ source.getSize().z == target.getSize().z,
+ "different grid resolutions " << source.getSize() << " vs " << target.getSize());
+
+ // Grid<Real> divGrid(target.getParent());
+ // DivergenceOpMAC(divGrid, target);
+ // Real fDivOrig = GridSumSqr(divGrid);
+
+ FOR_IJK_BND(target, bnd)
+ {
+ if (flags.get(i, j, k) & flag) {
+ target(i, j, k) = source(i, j, k);
+ }
+ }
+
+ // DivergenceOpMAC(divGrid, target);
+ // Real fDivTransfer = GridSumSqr(divGrid);
+ // std::cout << "Divergence: " << fDivOrig << " -> " << fDivTransfer << std::endl;
+}
+static PyObject *_W_19(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "copyMACData", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MACGrid &source = *_args.getPtr<MACGrid>("source", 0, &_lock);
+ MACGrid &target = *_args.getPtr<MACGrid>("target", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ const int flag = _args.get<int>("flag", 3, &_lock);
+ const int bnd = _args.get<int>("bnd", 4, &_lock);
+ _retval = getPyNone();
+ copyMACData(source, target, flags, flag, bnd);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "copyMACData", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("copyMACData", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_copyMACData("", "copyMACData", _W_19);
+extern "C" {
+void PbRegister_copyMACData()
+{
+ KEEP_UNUSED(_RP_copyMACData);
+}
+}
+
+// explicit instantiation
+template class Grid<int>;
+template class Grid<Real>;
+template class Grid<Vec3>;
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/grid.h b/extern/mantaflow/preprocessed/grid.h
new file mode 100644
index 00000000000..bd4e0f99f85
--- /dev/null
+++ b/extern/mantaflow/preprocessed/grid.h
@@ -0,0 +1,2260 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#ifndef _GRID_H
+#define _GRID_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "interpol.h"
+#include "interpolHigh.h"
+#include "kernel.h"
+
+namespace Manta {
+class LevelsetGrid;
+
+//! Base class for all grids
+class GridBase : public PbClass {
+ public:
+ enum GridType {
+ TypeNone = 0,
+ TypeReal = 1,
+ TypeInt = 2,
+ TypeVec3 = 4,
+ TypeMAC = 8,
+ TypeLevelset = 16,
+ TypeFlags = 32
+ };
+
+ GridBase(FluidSolver *parent);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "GridBase::GridBase", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new GridBase(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "GridBase::GridBase", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("GridBase::GridBase", e.what());
+ return -1;
+ }
+ }
+
+ //! Get the grids X dimension
+ inline int getSizeX() const
+ {
+ return mSize.x;
+ }
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ GridBase *pbo = dynamic_cast<GridBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "GridBase::getSizeX", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getSizeX());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "GridBase::getSizeX", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("GridBase::getSizeX", e.what());
+ return 0;
+ }
+ }
+
+ //! Get the grids Y dimension
+ inline int getSizeY() const
+ {
+ return mSize.y;
+ }
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ GridBase *pbo = dynamic_cast<GridBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "GridBase::getSizeY", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getSizeY());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "GridBase::getSizeY", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("GridBase::getSizeY", e.what());
+ return 0;
+ }
+ }
+
+ //! Get the grids Z dimension
+ inline int getSizeZ() const
+ {
+ return mSize.z;
+ }
+ static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ GridBase *pbo = dynamic_cast<GridBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "GridBase::getSizeZ", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getSizeZ());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "GridBase::getSizeZ", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("GridBase::getSizeZ", e.what());
+ return 0;
+ }
+ }
+
+ //! Get the grids dimensions
+ inline Vec3i getSize() const
+ {
+ return mSize;
+ }
+ static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ GridBase *pbo = dynamic_cast<GridBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "GridBase::getSize", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getSize());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "GridBase::getSize", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("GridBase::getSize", e.what());
+ return 0;
+ }
+ }
+
+ //! Get Stride in X dimension
+ inline IndexInt getStrideX() const
+ {
+ return 1;
+ }
+ //! Get Stride in Y dimension
+ inline IndexInt getStrideY() const
+ {
+ return mSize.x;
+ }
+ //! Get Stride in Z dimension
+ inline IndexInt getStrideZ() const
+ {
+ return mStrideZ;
+ }
+
+ inline Real getDx() const
+ {
+ return mDx;
+ }
+
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(int i, int j, int k) const;
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(IndexInt idx) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec3i &p, int bnd) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec3i &p) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec3 &p, int bnd = 0) const
+ {
+ return isInBounds(toVec3i(p), bnd);
+ }
+ //! Check if linear index is in the range of the array
+ inline bool isInBounds(IndexInt idx) const;
+
+ //! Get the type of grid
+ inline GridType getType() const
+ {
+ return mType;
+ }
+ //! Check dimensionality
+ inline bool is3D() const
+ {
+ return m3D;
+ }
+ static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ GridBase *pbo = dynamic_cast<GridBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "GridBase::is3D", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->is3D());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "GridBase::is3D", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("GridBase::is3D", e.what());
+ return 0;
+ }
+ }
+
+ //! Get index into the data
+ inline IndexInt index(int i, int j, int k) const
+ {
+ DEBUG_ONLY(checkIndex(i, j, k));
+ return (IndexInt)i + (IndexInt)mSize.x * j + (IndexInt)mStrideZ * k;
+ }
+ //! Get index into the data
+ inline IndexInt index(const Vec3i &pos) const
+ {
+ DEBUG_ONLY(checkIndex(pos.x, pos.y, pos.z));
+ return (IndexInt)pos.x + (IndexInt)mSize.x * pos.y + (IndexInt)mStrideZ * pos.z;
+ }
+
+ //! grid4d compatibility functions
+ inline bool is4D() const
+ {
+ return false;
+ }
+ static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ GridBase *pbo = dynamic_cast<GridBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "GridBase::is4D", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->is4D());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "GridBase::is4D", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("GridBase::is4D", e.what());
+ return 0;
+ }
+ }
+
+ inline int getSizeT() const
+ {
+ return 1;
+ }
+ static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ GridBase *pbo = dynamic_cast<GridBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "GridBase::getSizeT", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getSizeT());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "GridBase::getSizeT", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("GridBase::getSizeT", e.what());
+ return 0;
+ }
+ }
+
+ inline int getStrideT() const
+ {
+ return 0;
+ }
+ static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ GridBase *pbo = dynamic_cast<GridBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "GridBase::getStrideT", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getStrideT());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "GridBase::getStrideT", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("GridBase::getStrideT", e.what());
+ return 0;
+ }
+ }
+
+ inline int index(int i, int j, int k, int unused) const
+ {
+ return index(i, j, k);
+ }
+ inline bool isInBounds(int i, int j, int k, int t, int bnd) const
+ {
+ if (t != 0)
+ return false;
+ return isInBounds(Vec3i(i, j, k), bnd);
+ }
+
+ protected:
+ GridType mType;
+ Vec3i mSize;
+ Real mDx;
+ bool m3D; // precomputed Z shift: to ensure 2D compatibility, always use this instead of sx*sy !
+ IndexInt mStrideZ;
+ public:
+ PbArgs _args;
+}
+#define _C_GridBase
+;
+
+//! Grid class
+
+template<class T> class Grid : public GridBase {
+ public:
+ //! init new grid, values are set to zero
+ Grid(FluidSolver *parent, bool show = true);
+ static int _W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "Grid::Grid", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ bool show = _args.getOpt<bool>("show", 1, true, &_lock);
+ obj = new Grid(parent, show);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "Grid::Grid", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::Grid", e.what());
+ return -1;
+ }
+ }
+
+ //! init new grid with an existing array
+ Grid(FluidSolver *parent, T *data, bool show = true);
+ //! create new & copy content from another grid
+ Grid(const Grid<T> &a);
+ //! return memory to solver
+ virtual ~Grid();
+
+ typedef T BASETYPE;
+ typedef GridBase BASETYPE_GRID;
+
+ void save(std::string name);
+ static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::save", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->save(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::save", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::save", e.what());
+ return 0;
+ }
+ }
+
+ void load(std::string name);
+ static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::load", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->load(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::load", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::load", e.what());
+ return 0;
+ }
+ }
+
+ //! set all cells to zero
+ void clear();
+ static PyObject *_W_12(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::clear", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clear();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::clear", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::clear", e.what());
+ return 0;
+ }
+ }
+
+ //! all kinds of access functions, use grid(), grid[] or grid.get()
+ //! access data
+ inline T get(int i, int j, int k) const
+ {
+ return mData[index(i, j, k)];
+ }
+ //! access data
+ inline T &get(int i, int j, int k)
+ {
+ return mData[index(i, j, k)];
+ }
+ //! access data
+ inline T get(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkIndex(idx));
+ return mData[idx];
+ }
+ //! access data
+ inline T get(const Vec3i &pos) const
+ {
+ return mData[index(pos)];
+ }
+ //! access data
+ inline T &operator()(int i, int j, int k)
+ {
+ return mData[index(i, j, k)];
+ }
+ //! access data
+ inline T operator()(int i, int j, int k) const
+ {
+ return mData[index(i, j, k)];
+ }
+ //! access data
+ inline T &operator()(IndexInt idx)
+ {
+ DEBUG_ONLY(checkIndex(idx));
+ return mData[idx];
+ }
+ //! access data
+ inline T operator()(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkIndex(idx));
+ return mData[idx];
+ }
+ //! access data
+ inline T &operator()(const Vec3i &pos)
+ {
+ return mData[index(pos)];
+ }
+ //! access data
+ inline T operator()(const Vec3i &pos) const
+ {
+ return mData[index(pos)];
+ }
+ //! access data
+ inline T &operator[](IndexInt idx)
+ {
+ DEBUG_ONLY(checkIndex(idx));
+ return mData[idx];
+ }
+ //! access data
+ inline const T operator[](IndexInt idx) const
+ {
+ DEBUG_ONLY(checkIndex(idx));
+ return mData[idx];
+ }
+
+ // interpolated access
+ inline T getInterpolated(const Vec3 &pos) const
+ {
+ return interpol<T>(mData, mSize, mStrideZ, pos);
+ }
+ inline void setInterpolated(const Vec3 &pos, const T &val, Grid<Real> &sumBuffer) const
+ {
+ setInterpol<T>(mData, mSize, mStrideZ, pos, val, &sumBuffer[0]);
+ }
+ // higher order interpolation (1=linear, 2=cubic)
+ inline T getInterpolatedHi(const Vec3 &pos, int order) const
+ {
+ switch (order) {
+ case 1:
+ return interpol<T>(mData, mSize, mStrideZ, pos);
+ case 2:
+ return interpolCubic<T>(mData, mSize, mStrideZ, pos);
+ default:
+ assertMsg(false, "Unknown interpolation order " << order);
+ }
+ return T(0.); // should never be reached, just to prevent compiler warnings
+ }
+
+ // assignment / copy
+
+ //! warning - do not use "=" for grids in python, this copies the reference! not the grid
+ //! content...
+ // Grid<T>& operator=(const Grid<T>& a);
+ //! copy content from other grid (use this one instead of operator= !)
+ Grid<T> &copyFrom(const Grid<T> &a, bool copyType = true);
+ static PyObject *_W_13(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::copyFrom", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<T> &a = *_args.getPtr<Grid<T>>("a", 0, &_lock);
+ bool copyType = _args.getOpt<bool>("copyType", 1, true, &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->copyFrom(a, copyType));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::copyFrom", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::copyFrom", e.what());
+ return 0;
+ }
+ }
+ // old: { *this = a; }
+
+ // helper functions to work with grids in scene files
+
+ //! get grid type
+ int getGridType();
+ static PyObject *_W_14(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::getGridType", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getGridType());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::getGridType", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::getGridType", e.what());
+ return 0;
+ }
+ }
+
+ //! add/subtract other grid
+ void add(const Grid<T> &a);
+ static PyObject *_W_15(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::add", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<T> &a = *_args.getPtr<Grid<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->add(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::add", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::add", e.what());
+ return 0;
+ }
+ }
+
+ void sub(const Grid<T> &a);
+ static PyObject *_W_16(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::sub", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<T> &a = *_args.getPtr<Grid<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->sub(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::sub", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::sub", e.what());
+ return 0;
+ }
+ }
+
+ //! set all cells to constant value
+ void setConst(T s);
+ static PyObject *_W_17(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::setConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::setConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::setConst", e.what());
+ return 0;
+ }
+ }
+
+ //! add constant to all grid cells
+ void addConst(T s);
+ static PyObject *_W_18(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::addConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->addConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::addConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::addConst", e.what());
+ return 0;
+ }
+ }
+
+ //! add scaled other grid to current one (note, only "Real" factor, "T" type not supported here!)
+ void addScaled(const Grid<T> &a, const T &factor);
+ static PyObject *_W_19(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::addScaled", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<T> &a = *_args.getPtr<Grid<T>>("a", 0, &_lock);
+ const T &factor = *_args.getPtr<T>("factor", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->addScaled(a, factor);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::addScaled", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::addScaled", e.what());
+ return 0;
+ }
+ }
+
+ //! multiply contents of grid
+ void mult(const Grid<T> &a);
+ static PyObject *_W_20(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::mult", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<T> &a = *_args.getPtr<Grid<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->mult(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::mult", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::mult", e.what());
+ return 0;
+ }
+ }
+
+ //! multiply each cell by a constant scalar value
+ void multConst(T s);
+ static PyObject *_W_21(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::multConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->multConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::multConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::multConst", e.what());
+ return 0;
+ }
+ }
+
+ //! clamp content to range (for vec3, clamps each component separately)
+ void clamp(Real min, Real max);
+ static PyObject *_W_22(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::clamp", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real min = _args.get<Real>("min", 0, &_lock);
+ Real max = _args.get<Real>("max", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clamp(min, max);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::clamp", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::clamp", e.what());
+ return 0;
+ }
+ }
+
+ //! reduce small values to zero
+ void stomp(const T &threshold);
+ static PyObject *_W_23(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::stomp", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const T &threshold = *_args.getPtr<T>("threshold", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->stomp(threshold);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::stomp", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::stomp", e.what());
+ return 0;
+ }
+ }
+
+ //! permute grid axes, e.g. switch y with z (0,2,1)
+ void permuteAxes(int axis0, int axis1, int axis2);
+ static PyObject *_W_24(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::permuteAxes", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int axis0 = _args.get<int>("axis0", 0, &_lock);
+ int axis1 = _args.get<int>("axis1", 1, &_lock);
+ int axis2 = _args.get<int>("axis2", 2, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->permuteAxes(axis0, axis1, axis2);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::permuteAxes", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::permuteAxes", e.what());
+ return 0;
+ }
+ }
+
+ //! permute grid axes, e.g. switch y with z (0,2,1)
+ void permuteAxesCopyToGrid(int axis0, int axis1, int axis2, Grid<T> &out);
+ static PyObject *_W_25(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::permuteAxesCopyToGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int axis0 = _args.get<int>("axis0", 0, &_lock);
+ int axis1 = _args.get<int>("axis1", 1, &_lock);
+ int axis2 = _args.get<int>("axis2", 2, &_lock);
+ Grid<T> &out = *_args.getPtr<Grid<T>>("out", 3, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->permuteAxesCopyToGrid(axis0, axis1, axis2, out);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::permuteAxesCopyToGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::permuteAxesCopyToGrid", e.what());
+ return 0;
+ }
+ }
+
+ // common compound operators
+ //! get absolute max value in grid
+ Real getMaxAbs() const;
+ static PyObject *_W_26(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::getMaxAbs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMaxAbs());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::getMaxAbs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::getMaxAbs", e.what());
+ return 0;
+ }
+ }
+
+ //! get max value in grid
+ Real getMax() const;
+ static PyObject *_W_27(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::getMax", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMax());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::getMax", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::getMax", e.what());
+ return 0;
+ }
+ }
+
+ //! get min value in grid
+ Real getMin() const;
+ static PyObject *_W_28(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::getMin", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMin());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::getMin", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::getMin", e.what());
+ return 0;
+ }
+ }
+
+ //! calculate L1 norm of grid content
+ Real getL1(int bnd = 0);
+ static PyObject *_W_29(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::getL1", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int bnd = _args.getOpt<int>("bnd", 0, 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getL1(bnd));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::getL1", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::getL1", e.what());
+ return 0;
+ }
+ }
+
+ //! calculate L2 norm of grid content
+ Real getL2(int bnd = 0);
+ static PyObject *_W_30(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::getL2", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int bnd = _args.getOpt<int>("bnd", 0, 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getL2(bnd));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::getL2", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::getL2", e.what());
+ return 0;
+ }
+ }
+
+ //! set all boundary cells to constant value (Dirichlet)
+ void setBound(T value, int boundaryWidth = 1);
+ static PyObject *_W_31(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::setBound", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T value = _args.get<T>("value", 0, &_lock);
+ int boundaryWidth = _args.getOpt<int>("boundaryWidth", 1, 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setBound(value, boundaryWidth);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::setBound", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::setBound", e.what());
+ return 0;
+ }
+ }
+
+ //! set all boundary cells to last inner value (Neumann)
+ void setBoundNeumann(int boundaryWidth = 1);
+ static PyObject *_W_32(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::setBoundNeumann", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int boundaryWidth = _args.getOpt<int>("boundaryWidth", 0, 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setBoundNeumann(boundaryWidth);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::setBoundNeumann", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::setBoundNeumann", e.what());
+ return 0;
+ }
+ }
+
+ //! get data pointer of grid
+ std::string getDataPointer();
+ static PyObject *_W_33(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::getDataPointer", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getDataPointer());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::getDataPointer", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::getDataPointer", e.what());
+ return 0;
+ }
+ }
+
+ //! debugging helper, print grid from python. skip boundary of width bnd
+ void printGrid(int zSlice = -1, bool printIndex = false, int bnd = 1);
+ static PyObject *_W_34(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid *pbo = dynamic_cast<Grid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid::printGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int zSlice = _args.getOpt<int>("zSlice", 0, -1, &_lock);
+ bool printIndex = _args.getOpt<bool>("printIndex", 1, false, &_lock);
+ int bnd = _args.getOpt<int>("bnd", 2, 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->printGrid(zSlice, printIndex, bnd);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid::printGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid::printGrid", e.what());
+ return 0;
+ }
+ }
+
+ // c++ only operators
+ template<class S> Grid<T> &operator+=(const Grid<S> &a);
+ template<class S> Grid<T> &operator+=(const S &a);
+ template<class S> Grid<T> &operator-=(const Grid<S> &a);
+ template<class S> Grid<T> &operator-=(const S &a);
+ template<class S> Grid<T> &operator*=(const Grid<S> &a);
+ template<class S> Grid<T> &operator*=(const S &a);
+ template<class S> Grid<T> &operator/=(const Grid<S> &a);
+ template<class S> Grid<T> &operator/=(const S &a);
+ Grid<T> &safeDivide(const Grid<T> &a);
+
+ //! Swap data with another grid (no actual data is moved)
+ void swap(Grid<T> &other);
+
+ //! grid4d compatibility functions
+ inline T &operator()(int i, int j, int k, int unused)
+ {
+ return mData[index(i, j, k)];
+ }
+ inline T operator()(int i, int j, int k, int unused) const
+ {
+ return mData[index(i, j, k)];
+ }
+
+ protected:
+ T *mData;
+ bool externalData; // True if mData is managed outside of the Fluidsolver
+ public:
+ PbArgs _args;
+}
+#define _C_Grid
+;
+
+// Python doesn't know about templates: explicit aliases needed
+
+//! Special function for staggered grids
+class MACGrid : public Grid<Vec3> {
+ public:
+ MACGrid(FluidSolver *parent, bool show = true) : Grid<Vec3>(parent, show)
+ {
+ mType = (GridType)(TypeMAC | TypeVec3);
+ }
+ static int _W_35(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "MACGrid::MACGrid", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ bool show = _args.getOpt<bool>("show", 1, true, &_lock);
+ obj = new MACGrid(parent, show);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "MACGrid::MACGrid", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("MACGrid::MACGrid", e.what());
+ return -1;
+ }
+ }
+
+ MACGrid(FluidSolver *parent, Vec3 *data, bool show = true) : Grid<Vec3>(parent, data, show)
+ {
+ mType = (GridType)(TypeMAC | TypeVec3);
+ }
+
+ // specialized functions for interpolating MAC information
+ inline Vec3 getCentered(int i, int j, int k) const;
+ inline Vec3 getCentered(const Vec3i &pos) const
+ {
+ return getCentered(pos.x, pos.y, pos.z);
+ }
+ inline Vec3 getAtMACX(int i, int j, int k) const;
+ inline Vec3 getAtMACY(int i, int j, int k) const;
+ inline Vec3 getAtMACZ(int i, int j, int k) const;
+ // interpolation
+ inline Vec3 getInterpolated(const Vec3 &pos) const
+ {
+ return interpolMAC(mData, mSize, mStrideZ, pos);
+ }
+ inline void setInterpolated(const Vec3 &pos, const Vec3 &val, Vec3 *tmp) const
+ {
+ return setInterpolMAC(mData, mSize, mStrideZ, pos, val, tmp);
+ }
+ inline Vec3 getInterpolatedHi(const Vec3 &pos, int order) const
+ {
+ switch (order) {
+ case 1:
+ return interpolMAC(mData, mSize, mStrideZ, pos);
+ case 2:
+ return interpolCubicMAC(mData, mSize, mStrideZ, pos);
+ default:
+ assertMsg(false, "Unknown interpolation order " << order);
+ }
+ return Vec3(0.); // should never be reached, just to prevent compiler warnings
+ }
+ // specials for mac grid:
+ template<int comp> inline Real getInterpolatedComponent(Vec3 pos) const
+ {
+ return interpolComponent<comp>(mData, mSize, mStrideZ, pos);
+ }
+ template<int comp> inline Real getInterpolatedComponentHi(const Vec3 &pos, int order) const
+ {
+ switch (order) {
+ case 1:
+ return interpolComponent<comp>(mData, mSize, mStrideZ, pos);
+ case 2:
+ return interpolCubicMAC(mData, mSize, mStrideZ, pos)[comp]; // warning - not yet optimized
+ default:
+ assertMsg(false, "Unknown interpolation order " << order);
+ }
+ return 0.; // should never be reached, just to prevent compiler warnings
+ }
+
+ //! set all boundary cells of a MAC grid to certain value (Dirchlet). Respects staggered grid
+ //! locations optionally, only set normal components
+ void setBoundMAC(Vec3 value, int boundaryWidth, bool normalOnly = false);
+ static PyObject *_W_36(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MACGrid *pbo = dynamic_cast<MACGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MACGrid::setBoundMAC", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Vec3 value = _args.get<Vec3>("value", 0, &_lock);
+ int boundaryWidth = _args.get<int>("boundaryWidth", 1, &_lock);
+ bool normalOnly = _args.getOpt<bool>("normalOnly", 2, false, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setBoundMAC(value, boundaryWidth, normalOnly);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MACGrid::setBoundMAC", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MACGrid::setBoundMAC", e.what());
+ return 0;
+ }
+ }
+
+ protected:
+ public:
+ PbArgs _args;
+}
+#define _C_MACGrid
+;
+
+//! Special functions for FlagGrid
+class FlagGrid : public Grid<int> {
+ public:
+ FlagGrid(FluidSolver *parent, int dim = 3, bool show = true) : Grid<int>(parent, show)
+ {
+ mType = (GridType)(TypeFlags | TypeInt);
+ }
+ static int _W_37(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "FlagGrid::FlagGrid", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ int dim = _args.getOpt<int>("dim", 1, 3, &_lock);
+ bool show = _args.getOpt<bool>("show", 2, true, &_lock);
+ obj = new FlagGrid(parent, dim, show);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "FlagGrid::FlagGrid", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("FlagGrid::FlagGrid", e.what());
+ return -1;
+ }
+ }
+
+ FlagGrid(FluidSolver *parent, int *data, int dim = 3, bool show = true)
+ : Grid<int>(parent, data, show)
+ {
+ mType = (GridType)(TypeFlags | TypeInt);
+ }
+
+ //! types of cells, in/outflow can be combined, e.g., TypeFluid|TypeInflow
+ enum CellType {
+ TypeNone = 0,
+ TypeFluid = 1,
+ TypeObstacle = 2,
+ TypeEmpty = 4,
+ TypeInflow = 8,
+ TypeOutflow = 16,
+ TypeOpen = 32,
+ TypeStick = 64,
+ TypeReserved = 256
+ };
+
+ //! access for particles
+ inline int getAt(const Vec3 &pos) const
+ {
+ return mData[index((int)pos.x, (int)pos.y, (int)pos.z)];
+ }
+
+ //! check for different flag types
+ inline bool isObstacle(IndexInt idx) const
+ {
+ return get(idx) & TypeObstacle;
+ }
+ inline bool isObstacle(int i, int j, int k) const
+ {
+ return get(i, j, k) & TypeObstacle;
+ }
+ inline bool isObstacle(const Vec3i &pos) const
+ {
+ return get(pos) & TypeObstacle;
+ }
+ inline bool isObstacle(const Vec3 &pos) const
+ {
+ return getAt(pos) & TypeObstacle;
+ }
+ inline bool isFluid(IndexInt idx) const
+ {
+ return get(idx) & TypeFluid;
+ }
+ inline bool isFluid(int i, int j, int k) const
+ {
+ return get(i, j, k) & TypeFluid;
+ }
+ inline bool isFluid(const Vec3i &pos) const
+ {
+ return get(pos) & TypeFluid;
+ }
+ inline bool isFluid(const Vec3 &pos) const
+ {
+ return getAt(pos) & TypeFluid;
+ }
+ inline bool isInflow(IndexInt idx) const
+ {
+ return get(idx) & TypeInflow;
+ }
+ inline bool isInflow(int i, int j, int k) const
+ {
+ return get(i, j, k) & TypeInflow;
+ }
+ inline bool isInflow(const Vec3i &pos) const
+ {
+ return get(pos) & TypeInflow;
+ }
+ inline bool isInflow(const Vec3 &pos) const
+ {
+ return getAt(pos) & TypeInflow;
+ }
+ inline bool isEmpty(IndexInt idx) const
+ {
+ return get(idx) & TypeEmpty;
+ }
+ inline bool isEmpty(int i, int j, int k) const
+ {
+ return get(i, j, k) & TypeEmpty;
+ }
+ inline bool isEmpty(const Vec3i &pos) const
+ {
+ return get(pos) & TypeEmpty;
+ }
+ inline bool isEmpty(const Vec3 &pos) const
+ {
+ return getAt(pos) & TypeEmpty;
+ }
+ inline bool isOutflow(IndexInt idx) const
+ {
+ return get(idx) & TypeOutflow;
+ }
+ inline bool isOutflow(int i, int j, int k) const
+ {
+ return get(i, j, k) & TypeOutflow;
+ }
+ inline bool isOutflow(const Vec3i &pos) const
+ {
+ return get(pos) & TypeOutflow;
+ }
+ inline bool isOutflow(const Vec3 &pos) const
+ {
+ return getAt(pos) & TypeOutflow;
+ }
+ inline bool isOpen(IndexInt idx) const
+ {
+ return get(idx) & TypeOpen;
+ }
+ inline bool isOpen(int i, int j, int k) const
+ {
+ return get(i, j, k) & TypeOpen;
+ }
+ inline bool isOpen(const Vec3i &pos) const
+ {
+ return get(pos) & TypeOpen;
+ }
+ inline bool isOpen(const Vec3 &pos) const
+ {
+ return getAt(pos) & TypeOpen;
+ }
+ inline bool isStick(IndexInt idx) const
+ {
+ return get(idx) & TypeStick;
+ }
+ inline bool isStick(int i, int j, int k) const
+ {
+ return get(i, j, k) & TypeStick;
+ }
+ inline bool isStick(const Vec3i &pos) const
+ {
+ return get(pos) & TypeStick;
+ }
+ inline bool isStick(const Vec3 &pos) const
+ {
+ return getAt(pos) & TypeStick;
+ }
+
+ void InitMinXWall(const int &boundaryWidth, Grid<Real> &phiWalls);
+ void InitMaxXWall(const int &boundaryWidth, Grid<Real> &phiWalls);
+ void InitMinYWall(const int &boundaryWidth, Grid<Real> &phiWalls);
+ void InitMaxYWall(const int &boundaryWidth, Grid<Real> &phiWalls);
+ void InitMinZWall(const int &boundaryWidth, Grid<Real> &phiWalls);
+ void InitMaxZWall(const int &boundaryWidth, Grid<Real> &phiWalls);
+ // Python callables
+
+ void initDomain(const int &boundaryWidth = 0,
+ const std::string &wall = "xXyYzZ",
+ const std::string &open = " ",
+ const std::string &inflow = " ",
+ const std::string &outflow = " ",
+ Grid<Real> *phiWalls = 0x00);
+ static PyObject *_W_38(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FlagGrid *pbo = dynamic_cast<FlagGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "FlagGrid::initDomain", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const int &boundaryWidth = _args.getOpt<int>("boundaryWidth", 0, 0, &_lock);
+ const std::string &wall = _args.getOpt<std::string>("wall", 1, "xXyYzZ", &_lock);
+ const std::string &open = _args.getOpt<std::string>("open", 2, " ", &_lock);
+ const std::string &inflow = _args.getOpt<std::string>("inflow", 3, " ", &_lock);
+ const std::string &outflow = _args.getOpt<std::string>("outflow", 4, " ", &_lock);
+ Grid<Real> *phiWalls = _args.getPtrOpt<Grid<Real>>("phiWalls", 5, 0x00, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->initDomain(boundaryWidth, wall, open, inflow, outflow, phiWalls);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "FlagGrid::initDomain", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("FlagGrid::initDomain", e.what());
+ return 0;
+ }
+ }
+
+ void initBoundaries(const int &boundaryWidth, const int *types);
+
+ //! set fluid flags inside levelset (liquids)
+ void updateFromLevelset(LevelsetGrid &levelset);
+ static PyObject *_W_39(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FlagGrid *pbo = dynamic_cast<FlagGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "FlagGrid::updateFromLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ LevelsetGrid &levelset = *_args.getPtr<LevelsetGrid>("levelset", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->updateFromLevelset(levelset);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "FlagGrid::updateFromLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("FlagGrid::updateFromLevelset", e.what());
+ return 0;
+ }
+ }
+
+ //! set all cells (except obs/in/outflow) to type (fluid by default)
+ void fillGrid(int type = TypeFluid);
+ static PyObject *_W_40(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FlagGrid *pbo = dynamic_cast<FlagGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "FlagGrid::fillGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int type = _args.getOpt<int>("type", 0, TypeFluid, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->fillGrid(type);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "FlagGrid::fillGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("FlagGrid::fillGrid", e.what());
+ return 0;
+ }
+ }
+
+ //! count no. of cells matching flags via "AND"
+ //! warning for large grids! only regular int returned (due to python interface)
+ //! optionally creates mask in RealGrid (1 where flag matches, 0 otherwise)
+ int countCells(int flag, int bnd = 0, Grid<Real> *mask = NULL);
+ static PyObject *_W_41(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FlagGrid *pbo = dynamic_cast<FlagGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "FlagGrid::countCells", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int flag = _args.get<int>("flag", 0, &_lock);
+ int bnd = _args.getOpt<int>("bnd", 1, 0, &_lock);
+ Grid<Real> *mask = _args.getPtrOpt<Grid<Real>>("mask", 2, NULL, &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->countCells(flag, bnd, mask));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "FlagGrid::countCells", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("FlagGrid::countCells", e.what());
+ return 0;
+ }
+ }
+
+ public:
+ PbArgs _args;
+}
+#define _C_FlagGrid
+;
+
+//! helper to compute grid conversion factor between local coordinates of two grids
+inline Vec3 calcGridSizeFactor(Vec3i s1, Vec3i s2)
+{
+ return Vec3(Real(s1[0]) / s2[0], Real(s1[1]) / s2[1], Real(s1[2]) / s2[2]);
+}
+
+// prototypes for grid plugins
+void copyMacToVec3(MACGrid &source, Grid<Vec3> &target);
+void convertMacToVec3(MACGrid &source, Grid<Vec3> &target);
+void resampleVec3ToMac(Grid<Vec3> &source, MACGrid &target);
+void resampleMacToVec3(MACGrid &source, Grid<Vec3> &target);
+
+void getComponent(const Grid<Vec3> &source, Grid<Real> &target, int component);
+void setComponent(const Grid<Real> &source, Grid<Vec3> &target, int component);
+
+//******************************************************************************
+// Implementation of inline functions
+
+inline void GridBase::checkIndex(int i, int j, int k) const
+{
+ if (i < 0 || j < 0 || k < 0 || i >= mSize.x || j >= mSize.y || k >= mSize.z) {
+ std::ostringstream s;
+ s << "Grid " << mName << " dim " << mSize << " : index " << i << "," << j << "," << k
+ << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+inline void GridBase::checkIndex(IndexInt idx) const
+{
+ if (idx < 0 || idx >= mSize.x * mSize.y * mSize.z) {
+ std::ostringstream s;
+ s << "Grid " << mName << " dim " << mSize << " : index " << idx << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+bool GridBase::isInBounds(const Vec3i &p) const
+{
+ return (p.x >= 0 && p.y >= 0 && p.z >= 0 && p.x < mSize.x && p.y < mSize.y && p.z < mSize.z);
+}
+
+bool GridBase::isInBounds(const Vec3i &p, int bnd) const
+{
+ bool ret = (p.x >= bnd && p.y >= bnd && p.x < mSize.x - bnd && p.y < mSize.y - bnd);
+ if (this->is3D()) {
+ ret &= (p.z >= bnd && p.z < mSize.z - bnd);
+ }
+ else {
+ ret &= (p.z == 0);
+ }
+ return ret;
+}
+//! Check if linear index is in the range of the array
+bool GridBase::isInBounds(IndexInt idx) const
+{
+ if (idx < 0 || idx >= mSize.x * mSize.y * mSize.z) {
+ return false;
+ }
+ return true;
+}
+
+inline Vec3 MACGrid::getCentered(int i, int j, int k) const
+{
+ DEBUG_ONLY(checkIndex(i + 1, j + 1, k));
+ const IndexInt idx = index(i, j, k);
+ Vec3 v = Vec3(
+ 0.5 * (mData[idx].x + mData[idx + 1].x), 0.5 * (mData[idx].y + mData[idx + mSize.x].y), 0.);
+ if (this->is3D()) {
+ DEBUG_ONLY(checkIndex(idx + mStrideZ));
+ v[2] = 0.5 * (mData[idx].z + mData[idx + mStrideZ].z);
+ }
+ return v;
+}
+
+inline Vec3 MACGrid::getAtMACX(int i, int j, int k) const
+{
+ DEBUG_ONLY(checkIndex(i - 1, j + 1, k));
+ const IndexInt idx = index(i, j, k);
+ Vec3 v = Vec3((mData[idx].x),
+ 0.25 * (mData[idx].y + mData[idx - 1].y + mData[idx + mSize.x].y +
+ mData[idx + mSize.x - 1].y),
+ 0.);
+ if (this->is3D()) {
+ DEBUG_ONLY(checkIndex(idx + mStrideZ - 1));
+ v[2] = 0.25 * (mData[idx].z + mData[idx - 1].z + mData[idx + mStrideZ].z +
+ mData[idx + mStrideZ - 1].z);
+ }
+ return v;
+}
+
+inline Vec3 MACGrid::getAtMACY(int i, int j, int k) const
+{
+ DEBUG_ONLY(checkIndex(i + 1, j - 1, k));
+ const IndexInt idx = index(i, j, k);
+ Vec3 v = Vec3(0.25 * (mData[idx].x + mData[idx - mSize.x].x + mData[idx + 1].x +
+ mData[idx + 1 - mSize.x].x),
+ (mData[idx].y),
+ 0.);
+ if (this->is3D()) {
+ DEBUG_ONLY(checkIndex(idx + mStrideZ - mSize.x));
+ v[2] = 0.25 * (mData[idx].z + mData[idx - mSize.x].z + mData[idx + mStrideZ].z +
+ mData[idx + mStrideZ - mSize.x].z);
+ }
+ return v;
+}
+
+inline Vec3 MACGrid::getAtMACZ(int i, int j, int k) const
+{
+ const IndexInt idx = index(i, j, k);
+ DEBUG_ONLY(checkIndex(idx - mStrideZ));
+ DEBUG_ONLY(checkIndex(idx + mSize.x - mStrideZ));
+ Vec3 v = Vec3(0.25 * (mData[idx].x + mData[idx - mStrideZ].x + mData[idx + 1].x +
+ mData[idx + 1 - mStrideZ].x),
+ 0.25 * (mData[idx].y + mData[idx - mStrideZ].y + mData[idx + mSize.x].y +
+ mData[idx + mSize.x - mStrideZ].y),
+ (mData[idx].z));
+ return v;
+}
+
+template<class T, class S> struct gridAdd : public KernelBase {
+ gridAdd(Grid<T> &me, const Grid<S> &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, const Grid<S> &other) const
+ {
+ me[idx] += other[idx];
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const Grid<S> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel gridAdd ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const Grid<S> &other;
+};
+template<class T, class S> struct gridSub : public KernelBase {
+ gridSub(Grid<T> &me, const Grid<S> &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, const Grid<S> &other) const
+ {
+ me[idx] -= other[idx];
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const Grid<S> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel gridSub ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const Grid<S> &other;
+};
+template<class T, class S> struct gridMult : public KernelBase {
+ gridMult(Grid<T> &me, const Grid<S> &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, const Grid<S> &other) const
+ {
+ me[idx] *= other[idx];
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const Grid<S> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel gridMult ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const Grid<S> &other;
+};
+template<class T, class S> struct gridDiv : public KernelBase {
+ gridDiv(Grid<T> &me, const Grid<S> &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, const Grid<S> &other) const
+ {
+ me[idx] /= other[idx];
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const Grid<S> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel gridDiv ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const Grid<S> &other;
+};
+template<class T, class S> struct gridAddScalar : public KernelBase {
+ gridAddScalar(Grid<T> &me, const S &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, const S &other) const
+ {
+ me[idx] += other;
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel gridAddScalar ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const S &other;
+};
+template<class T, class S> struct gridMultScalar : public KernelBase {
+ gridMultScalar(Grid<T> &me, const S &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, const S &other) const
+ {
+ me[idx] *= other;
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel gridMultScalar ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const S &other;
+};
+template<class T, class S> struct gridScaledAdd : public KernelBase {
+ gridScaledAdd(Grid<T> &me, const Grid<T> &other, const S &factor)
+ : KernelBase(&me, 0), me(me), other(other), factor(factor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &me, const Grid<T> &other, const S &factor) const
+ {
+ me[idx] += factor * other[idx];
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const Grid<T> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid<T> type1;
+ inline const S &getArg2()
+ {
+ return factor;
+ }
+ typedef S type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel gridScaledAdd ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other, factor);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const Grid<T> &other;
+ const S &factor;
+};
+
+template<class T> struct gridSetConst : public KernelBase {
+ gridSetConst(Grid<T> &grid, T value) : KernelBase(&grid, 0), grid(grid), value(value)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<T> &grid, T value) const
+ {
+ grid[idx] = value;
+ }
+ inline Grid<T> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<T> type0;
+ inline T &getArg1()
+ {
+ return value;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel gridSetConst ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, grid, value);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &grid;
+ T value;
+};
+
+template<class T> template<class S> Grid<T> &Grid<T>::operator+=(const Grid<S> &a)
+{
+ gridAdd<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T> &Grid<T>::operator+=(const S &a)
+{
+ gridAddScalar<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T> &Grid<T>::operator-=(const Grid<S> &a)
+{
+ gridSub<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T> &Grid<T>::operator-=(const S &a)
+{
+ gridAddScalar<T, S>(*this, -a);
+ return *this;
+}
+template<class T> template<class S> Grid<T> &Grid<T>::operator*=(const Grid<S> &a)
+{
+ gridMult<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T> &Grid<T>::operator*=(const S &a)
+{
+ gridMultScalar<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T> &Grid<T>::operator/=(const Grid<S> &a)
+{
+ gridDiv<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T> &Grid<T>::operator/=(const S &a)
+{
+ S rez((S)1.0 / a);
+ gridMultScalar<T, S>(*this, rez);
+ return *this;
+}
+
+//******************************************************************************
+// Other helper functions
+
+// compute gradient of a scalar grid
+inline Vec3 getGradient(const Grid<Real> &data, int i, int j, int k)
+{
+ Vec3 v;
+
+ if (i > data.getSizeX() - 2)
+ i = data.getSizeX() - 2;
+ if (j > data.getSizeY() - 2)
+ j = data.getSizeY() - 2;
+ if (i < 1)
+ i = 1;
+ if (j < 1)
+ j = 1;
+ v = Vec3(data(i + 1, j, k) - data(i - 1, j, k), data(i, j + 1, k) - data(i, j - 1, k), 0.);
+
+ if (data.is3D()) {
+ if (k > data.getSizeZ() - 2)
+ k = data.getSizeZ() - 2;
+ if (k < 1)
+ k = 1;
+ v[2] = data(i, j, k + 1) - data(i, j, k - 1);
+ }
+
+ return v;
+}
+
+// interpolate grid from one size to another size
+
+template<class S> struct knInterpolateGridTempl : public KernelBase {
+ knInterpolateGridTempl(Grid<S> &target,
+ const Grid<S> &source,
+ const Vec3 &sourceFactor,
+ Vec3 offset,
+ int orderSpace = 1)
+ : KernelBase(&target, 0),
+ target(target),
+ source(source),
+ sourceFactor(sourceFactor),
+ offset(offset),
+ orderSpace(orderSpace)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<S> &target,
+ const Grid<S> &source,
+ const Vec3 &sourceFactor,
+ Vec3 offset,
+ int orderSpace = 1) const
+ {
+ Vec3 pos = Vec3(i, j, k) * sourceFactor + offset;
+ if (!source.is3D())
+ pos[2] = 0; // allow 2d -> 3d
+ target(i, j, k) = source.getInterpolatedHi(pos, orderSpace);
+ }
+ inline Grid<S> &getArg0()
+ {
+ return target;
+ }
+ typedef Grid<S> type0;
+ inline const Grid<S> &getArg1()
+ {
+ return source;
+ }
+ typedef Grid<S> type1;
+ inline const Vec3 &getArg2()
+ {
+ return sourceFactor;
+ }
+ typedef Vec3 type2;
+ inline Vec3 &getArg3()
+ {
+ return offset;
+ }
+ typedef Vec3 type3;
+ inline int &getArg4()
+ {
+ return orderSpace;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knInterpolateGridTempl ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, target, source, sourceFactor, offset, orderSpace);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, target, source, sourceFactor, offset, orderSpace);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<S> &target;
+ const Grid<S> &source;
+ const Vec3 &sourceFactor;
+ Vec3 offset;
+ int orderSpace;
+};
+// template glue code - choose interpolation based on template arguments
+template<class GRID> void interpolGridTempl(GRID &target, GRID &source)
+{
+ errMsg("interpolGridTempl - Only valid for specific instantiations");
+}
+
+} // namespace Manta
+#endif
diff --git a/extern/mantaflow/preprocessed/grid.h.reg.cpp b/extern/mantaflow/preprocessed/grid.h.reg.cpp
new file mode 100644
index 00000000000..d7f87604edf
--- /dev/null
+++ b/extern/mantaflow/preprocessed/grid.h.reg.cpp
@@ -0,0 +1,246 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "grid.h"
+namespace Manta {
+#ifdef _C_FlagGrid
+static const Pb::Register _R_26("FlagGrid", "FlagGrid", "Grid<int>");
+template<> const char *Namify<FlagGrid>::S = "FlagGrid";
+static const Pb::Register _R_27("FlagGrid", "FlagGrid", FlagGrid::_W_37);
+static const Pb::Register _R_28("FlagGrid", "initDomain", FlagGrid::_W_38);
+static const Pb::Register _R_29("FlagGrid", "updateFromLevelset", FlagGrid::_W_39);
+static const Pb::Register _R_30("FlagGrid", "fillGrid", FlagGrid::_W_40);
+static const Pb::Register _R_31("FlagGrid", "countCells", FlagGrid::_W_41);
+#endif
+#ifdef _C_Grid
+static const Pb::Register _R_32("Grid<int>", "Grid<int>", "GridBase");
+template<> const char *Namify<Grid<int>>::S = "Grid<int>";
+static const Pb::Register _R_33("Grid<int>", "Grid", Grid<int>::_W_9);
+static const Pb::Register _R_34("Grid<int>", "save", Grid<int>::_W_10);
+static const Pb::Register _R_35("Grid<int>", "load", Grid<int>::_W_11);
+static const Pb::Register _R_36("Grid<int>", "clear", Grid<int>::_W_12);
+static const Pb::Register _R_37("Grid<int>", "copyFrom", Grid<int>::_W_13);
+static const Pb::Register _R_38("Grid<int>", "getGridType", Grid<int>::_W_14);
+static const Pb::Register _R_39("Grid<int>", "add", Grid<int>::_W_15);
+static const Pb::Register _R_40("Grid<int>", "sub", Grid<int>::_W_16);
+static const Pb::Register _R_41("Grid<int>", "setConst", Grid<int>::_W_17);
+static const Pb::Register _R_42("Grid<int>", "addConst", Grid<int>::_W_18);
+static const Pb::Register _R_43("Grid<int>", "addScaled", Grid<int>::_W_19);
+static const Pb::Register _R_44("Grid<int>", "mult", Grid<int>::_W_20);
+static const Pb::Register _R_45("Grid<int>", "multConst", Grid<int>::_W_21);
+static const Pb::Register _R_46("Grid<int>", "clamp", Grid<int>::_W_22);
+static const Pb::Register _R_47("Grid<int>", "stomp", Grid<int>::_W_23);
+static const Pb::Register _R_48("Grid<int>", "permuteAxes", Grid<int>::_W_24);
+static const Pb::Register _R_49("Grid<int>", "permuteAxesCopyToGrid", Grid<int>::_W_25);
+static const Pb::Register _R_50("Grid<int>", "getMaxAbs", Grid<int>::_W_26);
+static const Pb::Register _R_51("Grid<int>", "getMax", Grid<int>::_W_27);
+static const Pb::Register _R_52("Grid<int>", "getMin", Grid<int>::_W_28);
+static const Pb::Register _R_53("Grid<int>", "getL1", Grid<int>::_W_29);
+static const Pb::Register _R_54("Grid<int>", "getL2", Grid<int>::_W_30);
+static const Pb::Register _R_55("Grid<int>", "setBound", Grid<int>::_W_31);
+static const Pb::Register _R_56("Grid<int>", "setBoundNeumann", Grid<int>::_W_32);
+static const Pb::Register _R_57("Grid<int>", "getDataPointer", Grid<int>::_W_33);
+static const Pb::Register _R_58("Grid<int>", "printGrid", Grid<int>::_W_34);
+static const Pb::Register _R_59("Grid<Real>", "Grid<Real>", "GridBase");
+template<> const char *Namify<Grid<Real>>::S = "Grid<Real>";
+static const Pb::Register _R_60("Grid<Real>", "Grid", Grid<Real>::_W_9);
+static const Pb::Register _R_61("Grid<Real>", "save", Grid<Real>::_W_10);
+static const Pb::Register _R_62("Grid<Real>", "load", Grid<Real>::_W_11);
+static const Pb::Register _R_63("Grid<Real>", "clear", Grid<Real>::_W_12);
+static const Pb::Register _R_64("Grid<Real>", "copyFrom", Grid<Real>::_W_13);
+static const Pb::Register _R_65("Grid<Real>", "getGridType", Grid<Real>::_W_14);
+static const Pb::Register _R_66("Grid<Real>", "add", Grid<Real>::_W_15);
+static const Pb::Register _R_67("Grid<Real>", "sub", Grid<Real>::_W_16);
+static const Pb::Register _R_68("Grid<Real>", "setConst", Grid<Real>::_W_17);
+static const Pb::Register _R_69("Grid<Real>", "addConst", Grid<Real>::_W_18);
+static const Pb::Register _R_70("Grid<Real>", "addScaled", Grid<Real>::_W_19);
+static const Pb::Register _R_71("Grid<Real>", "mult", Grid<Real>::_W_20);
+static const Pb::Register _R_72("Grid<Real>", "multConst", Grid<Real>::_W_21);
+static const Pb::Register _R_73("Grid<Real>", "clamp", Grid<Real>::_W_22);
+static const Pb::Register _R_74("Grid<Real>", "stomp", Grid<Real>::_W_23);
+static const Pb::Register _R_75("Grid<Real>", "permuteAxes", Grid<Real>::_W_24);
+static const Pb::Register _R_76("Grid<Real>", "permuteAxesCopyToGrid", Grid<Real>::_W_25);
+static const Pb::Register _R_77("Grid<Real>", "getMaxAbs", Grid<Real>::_W_26);
+static const Pb::Register _R_78("Grid<Real>", "getMax", Grid<Real>::_W_27);
+static const Pb::Register _R_79("Grid<Real>", "getMin", Grid<Real>::_W_28);
+static const Pb::Register _R_80("Grid<Real>", "getL1", Grid<Real>::_W_29);
+static const Pb::Register _R_81("Grid<Real>", "getL2", Grid<Real>::_W_30);
+static const Pb::Register _R_82("Grid<Real>", "setBound", Grid<Real>::_W_31);
+static const Pb::Register _R_83("Grid<Real>", "setBoundNeumann", Grid<Real>::_W_32);
+static const Pb::Register _R_84("Grid<Real>", "getDataPointer", Grid<Real>::_W_33);
+static const Pb::Register _R_85("Grid<Real>", "printGrid", Grid<Real>::_W_34);
+static const Pb::Register _R_86("Grid<Vec3>", "Grid<Vec3>", "GridBase");
+template<> const char *Namify<Grid<Vec3>>::S = "Grid<Vec3>";
+static const Pb::Register _R_87("Grid<Vec3>", "Grid", Grid<Vec3>::_W_9);
+static const Pb::Register _R_88("Grid<Vec3>", "save", Grid<Vec3>::_W_10);
+static const Pb::Register _R_89("Grid<Vec3>", "load", Grid<Vec3>::_W_11);
+static const Pb::Register _R_90("Grid<Vec3>", "clear", Grid<Vec3>::_W_12);
+static const Pb::Register _R_91("Grid<Vec3>", "copyFrom", Grid<Vec3>::_W_13);
+static const Pb::Register _R_92("Grid<Vec3>", "getGridType", Grid<Vec3>::_W_14);
+static const Pb::Register _R_93("Grid<Vec3>", "add", Grid<Vec3>::_W_15);
+static const Pb::Register _R_94("Grid<Vec3>", "sub", Grid<Vec3>::_W_16);
+static const Pb::Register _R_95("Grid<Vec3>", "setConst", Grid<Vec3>::_W_17);
+static const Pb::Register _R_96("Grid<Vec3>", "addConst", Grid<Vec3>::_W_18);
+static const Pb::Register _R_97("Grid<Vec3>", "addScaled", Grid<Vec3>::_W_19);
+static const Pb::Register _R_98("Grid<Vec3>", "mult", Grid<Vec3>::_W_20);
+static const Pb::Register _R_99("Grid<Vec3>", "multConst", Grid<Vec3>::_W_21);
+static const Pb::Register _R_100("Grid<Vec3>", "clamp", Grid<Vec3>::_W_22);
+static const Pb::Register _R_101("Grid<Vec3>", "stomp", Grid<Vec3>::_W_23);
+static const Pb::Register _R_102("Grid<Vec3>", "permuteAxes", Grid<Vec3>::_W_24);
+static const Pb::Register _R_103("Grid<Vec3>", "permuteAxesCopyToGrid", Grid<Vec3>::_W_25);
+static const Pb::Register _R_104("Grid<Vec3>", "getMaxAbs", Grid<Vec3>::_W_26);
+static const Pb::Register _R_105("Grid<Vec3>", "getMax", Grid<Vec3>::_W_27);
+static const Pb::Register _R_106("Grid<Vec3>", "getMin", Grid<Vec3>::_W_28);
+static const Pb::Register _R_107("Grid<Vec3>", "getL1", Grid<Vec3>::_W_29);
+static const Pb::Register _R_108("Grid<Vec3>", "getL2", Grid<Vec3>::_W_30);
+static const Pb::Register _R_109("Grid<Vec3>", "setBound", Grid<Vec3>::_W_31);
+static const Pb::Register _R_110("Grid<Vec3>", "setBoundNeumann", Grid<Vec3>::_W_32);
+static const Pb::Register _R_111("Grid<Vec3>", "getDataPointer", Grid<Vec3>::_W_33);
+static const Pb::Register _R_112("Grid<Vec3>", "printGrid", Grid<Vec3>::_W_34);
+#endif
+#ifdef _C_GridBase
+static const Pb::Register _R_113("GridBase", "GridBase", "PbClass");
+template<> const char *Namify<GridBase>::S = "GridBase";
+static const Pb::Register _R_114("GridBase", "GridBase", GridBase::_W_0);
+static const Pb::Register _R_115("GridBase", "getSizeX", GridBase::_W_1);
+static const Pb::Register _R_116("GridBase", "getSizeY", GridBase::_W_2);
+static const Pb::Register _R_117("GridBase", "getSizeZ", GridBase::_W_3);
+static const Pb::Register _R_118("GridBase", "getSize", GridBase::_W_4);
+static const Pb::Register _R_119("GridBase", "is3D", GridBase::_W_5);
+static const Pb::Register _R_120("GridBase", "is4D", GridBase::_W_6);
+static const Pb::Register _R_121("GridBase", "getSizeT", GridBase::_W_7);
+static const Pb::Register _R_122("GridBase", "getStrideT", GridBase::_W_8);
+#endif
+#ifdef _C_MACGrid
+static const Pb::Register _R_123("MACGrid", "MACGrid", "Grid<Vec3>");
+template<> const char *Namify<MACGrid>::S = "MACGrid";
+static const Pb::Register _R_124("MACGrid", "MACGrid", MACGrid::_W_35);
+static const Pb::Register _R_125("MACGrid", "setBoundMAC", MACGrid::_W_36);
+#endif
+static const Pb::Register _R_7("GridType_TypeNone", 0);
+static const Pb::Register _R_8("GridType_TypeReal", 1);
+static const Pb::Register _R_9("GridType_TypeInt", 2);
+static const Pb::Register _R_10("GridType_TypeVec3", 4);
+static const Pb::Register _R_11("GridType_TypeMAC", 8);
+static const Pb::Register _R_12("GridType_TypeLevelset", 16);
+static const Pb::Register _R_13("GridType_TypeFlags", 32);
+static const Pb::Register _R_14("Grid<int>", "IntGrid", "");
+static const Pb::Register _R_15("Grid<Real>", "RealGrid", "");
+static const Pb::Register _R_16("Grid<Vec3>", "VecGrid", "");
+static const Pb::Register _R_17("CellType_TypeNone", 0);
+static const Pb::Register _R_18("CellType_TypeFluid", 1);
+static const Pb::Register _R_19("CellType_TypeObstacle", 2);
+static const Pb::Register _R_20("CellType_TypeEmpty", 4);
+static const Pb::Register _R_21("CellType_TypeInflow", 8);
+static const Pb::Register _R_22("CellType_TypeOutflow", 16);
+static const Pb::Register _R_23("CellType_TypeOpen", 32);
+static const Pb::Register _R_24("CellType_TypeStick", 64);
+static const Pb::Register _R_25("CellType_TypeReserved", 256);
+extern "C" {
+void PbRegister_file_7()
+{
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+ KEEP_UNUSED(_R_101);
+ KEEP_UNUSED(_R_102);
+ KEEP_UNUSED(_R_103);
+ KEEP_UNUSED(_R_104);
+ KEEP_UNUSED(_R_105);
+ KEEP_UNUSED(_R_106);
+ KEEP_UNUSED(_R_107);
+ KEEP_UNUSED(_R_108);
+ KEEP_UNUSED(_R_109);
+ KEEP_UNUSED(_R_110);
+ KEEP_UNUSED(_R_111);
+ KEEP_UNUSED(_R_112);
+ KEEP_UNUSED(_R_113);
+ KEEP_UNUSED(_R_114);
+ KEEP_UNUSED(_R_115);
+ KEEP_UNUSED(_R_116);
+ KEEP_UNUSED(_R_117);
+ KEEP_UNUSED(_R_118);
+ KEEP_UNUSED(_R_119);
+ KEEP_UNUSED(_R_120);
+ KEEP_UNUSED(_R_121);
+ KEEP_UNUSED(_R_122);
+ KEEP_UNUSED(_R_123);
+ KEEP_UNUSED(_R_124);
+ KEEP_UNUSED(_R_125);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/grid4d.cpp b/extern/mantaflow/preprocessed/grid4d.cpp
new file mode 100644
index 00000000000..41d69b2d33a
--- /dev/null
+++ b/extern/mantaflow/preprocessed/grid4d.cpp
@@ -0,0 +1,1798 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#include <limits>
+#include <sstream>
+#include <cstring>
+
+#include "grid4d.h"
+#include "levelset.h"
+#include "kernel.h"
+#include "mantaio.h"
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// GridBase members
+
+Grid4dBase::Grid4dBase(FluidSolver *parent) : PbClass(parent), mType(TypeNone)
+{
+ checkParent();
+}
+
+//******************************************************************************
+// Grid4d<T> members
+
+// helpers to set type
+template<class T> inline Grid4dBase::Grid4dType typeList()
+{
+ return Grid4dBase::TypeNone;
+}
+template<> inline Grid4dBase::Grid4dType typeList<Real>()
+{
+ return Grid4dBase::TypeReal;
+}
+template<> inline Grid4dBase::Grid4dType typeList<int>()
+{
+ return Grid4dBase::TypeInt;
+}
+template<> inline Grid4dBase::Grid4dType typeList<Vec3>()
+{
+ return Grid4dBase::TypeVec3;
+}
+template<> inline Grid4dBase::Grid4dType typeList<Vec4>()
+{
+ return Grid4dBase::TypeVec4;
+}
+
+template<class T> Grid4d<T>::Grid4d(FluidSolver *parent, bool show) : Grid4dBase(parent)
+{
+ assertMsg(parent->is3D() && parent->supports4D(),
+ "To use 4d grids create a 3d solver with fourthDim>0");
+
+ mType = typeList<T>();
+ Vec3i s = parent->getGridSize();
+ mSize = Vec4i(s.x, s.y, s.z, parent->getFourthDim());
+ mData = parent->getGrid4dPointer<T>();
+ assertMsg(mData, "Couldnt allocate data pointer!");
+
+ mStrideZ = (mSize.x * mSize.y);
+ mStrideT = (mStrideZ * mSize.z);
+
+ Real sizemax = (Real)mSize[0];
+ for (int c = 1; c < 3; ++c)
+ if (mSize[c] > sizemax)
+ sizemax = mSize[c];
+ // note - the 4d component is ignored for dx! keep same scaling as for 3d...
+ mDx = 1.0 / sizemax;
+
+ clear();
+ setHidden(!show);
+}
+
+template<class T> Grid4d<T>::Grid4d(const Grid4d<T> &a) : Grid4dBase(a.getParent())
+{
+ mSize = a.mSize;
+ mType = a.mType;
+ mStrideZ = a.mStrideZ;
+ mStrideT = a.mStrideT;
+ mDx = a.mDx;
+ FluidSolver *gp = a.getParent();
+ mData = gp->getGrid4dPointer<T>();
+ assertMsg(mData, "Couldnt allocate data pointer!");
+
+ memcpy(mData, a.mData, sizeof(T) * a.mSize.x * a.mSize.y * a.mSize.z * a.mSize.t);
+}
+
+template<class T> Grid4d<T>::~Grid4d()
+{
+ mParent->freeGrid4dPointer<T>(mData);
+}
+
+template<class T> void Grid4d<T>::clear()
+{
+ memset(mData, 0, sizeof(T) * mSize.x * mSize.y * mSize.z * mSize.t);
+}
+
+template<class T> void Grid4d<T>::swap(Grid4d<T> &other)
+{
+ if (other.getSizeX() != getSizeX() || other.getSizeY() != getSizeY() ||
+ other.getSizeZ() != getSizeZ() || other.getSizeT() != getSizeT())
+ errMsg("Grid4d::swap(): Grid4d dimensions mismatch.");
+
+ T *dswap = other.mData;
+ other.mData = mData;
+ mData = dswap;
+}
+
+template<class T> void Grid4d<T>::load(string name)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ readGrid4dUni(name, this);
+ else if (ext == ".raw")
+ readGrid4dRaw(name, this);
+ else
+ errMsg("file '" + name + "' filetype not supported");
+}
+
+template<class T> void Grid4d<T>::save(string name)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ writeGrid4dUni(name, this);
+ else if (ext == ".raw")
+ writeGrid4dRaw(name, this);
+ else
+ errMsg("file '" + name + "' filetype not supported");
+}
+
+//******************************************************************************
+// Grid4d<T> operators
+
+//! Kernel: Compute min value of Real Grid4d
+
+struct kn4dMinReal : public KernelBase {
+ kn4dMinReal(Grid4d<Real> &val)
+ : KernelBase(&val, 0), val(val), minVal(std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<Real> &val, Real &minVal)
+ {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+ }
+ inline operator Real()
+ {
+ return minVal;
+ }
+ inline Real &getRet()
+ {
+ return minVal;
+ }
+ inline Grid4d<Real> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid4d<Real> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn4dMinReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, minVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ kn4dMinReal(kn4dMinReal &o, tbb::split)
+ : KernelBase(o), val(o.val), minVal(std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const kn4dMinReal &o)
+ {
+ minVal = min(minVal, o.minVal);
+ }
+ Grid4d<Real> &val;
+ Real minVal;
+};
+
+//! Kernel: Compute max value of Real Grid4d
+
+struct kn4dMaxReal : public KernelBase {
+ kn4dMaxReal(Grid4d<Real> &val)
+ : KernelBase(&val, 0), val(val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<Real> &val, Real &maxVal)
+ {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+ }
+ inline operator Real()
+ {
+ return maxVal;
+ }
+ inline Real &getRet()
+ {
+ return maxVal;
+ }
+ inline Grid4d<Real> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid4d<Real> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn4dMaxReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, maxVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ kn4dMaxReal(kn4dMaxReal &o, tbb::split)
+ : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const kn4dMaxReal &o)
+ {
+ maxVal = max(maxVal, o.maxVal);
+ }
+ Grid4d<Real> &val;
+ Real maxVal;
+};
+
+//! Kernel: Compute min value of int Grid4d
+
+struct kn4dMinInt : public KernelBase {
+ kn4dMinInt(Grid4d<int> &val)
+ : KernelBase(&val, 0), val(val), minVal(std::numeric_limits<int>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<int> &val, int &minVal)
+ {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+ }
+ inline operator int()
+ {
+ return minVal;
+ }
+ inline int &getRet()
+ {
+ return minVal;
+ }
+ inline Grid4d<int> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid4d<int> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn4dMinInt ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, minVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ kn4dMinInt(kn4dMinInt &o, tbb::split)
+ : KernelBase(o), val(o.val), minVal(std::numeric_limits<int>::max())
+ {
+ }
+ void join(const kn4dMinInt &o)
+ {
+ minVal = min(minVal, o.minVal);
+ }
+ Grid4d<int> &val;
+ int minVal;
+};
+
+//! Kernel: Compute max value of int Grid4d
+
+struct kn4dMaxInt : public KernelBase {
+ kn4dMaxInt(Grid4d<int> &val)
+ : KernelBase(&val, 0), val(val), maxVal(std::numeric_limits<int>::min())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<int> &val, int &maxVal)
+ {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+ }
+ inline operator int()
+ {
+ return maxVal;
+ }
+ inline int &getRet()
+ {
+ return maxVal;
+ }
+ inline Grid4d<int> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid4d<int> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn4dMaxInt ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, maxVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ kn4dMaxInt(kn4dMaxInt &o, tbb::split)
+ : KernelBase(o), val(o.val), maxVal(std::numeric_limits<int>::min())
+ {
+ }
+ void join(const kn4dMaxInt &o)
+ {
+ maxVal = max(maxVal, o.maxVal);
+ }
+ Grid4d<int> &val;
+ int maxVal;
+};
+
+//! Kernel: Compute min norm of vec Grid4d
+
+template<class VEC> struct kn4dMinVec : public KernelBase {
+ kn4dMinVec(Grid4d<VEC> &val)
+ : KernelBase(&val, 0), val(val), minVal(std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<VEC> &val, Real &minVal)
+ {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+ }
+ inline operator Real()
+ {
+ return minVal;
+ }
+ inline Real &getRet()
+ {
+ return minVal;
+ }
+ inline Grid4d<VEC> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid4d<VEC> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn4dMinVec ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, minVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ kn4dMinVec(kn4dMinVec &o, tbb::split)
+ : KernelBase(o), val(o.val), minVal(std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const kn4dMinVec &o)
+ {
+ minVal = min(minVal, o.minVal);
+ }
+ Grid4d<VEC> &val;
+ Real minVal;
+};
+
+//! Kernel: Compute max norm of vec Grid4d
+
+template<class VEC> struct kn4dMaxVec : public KernelBase {
+ kn4dMaxVec(Grid4d<VEC> &val)
+ : KernelBase(&val, 0), val(val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<VEC> &val, Real &maxVal)
+ {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+ }
+ inline operator Real()
+ {
+ return maxVal;
+ }
+ inline Real &getRet()
+ {
+ return maxVal;
+ }
+ inline Grid4d<VEC> &getArg0()
+ {
+ return val;
+ }
+ typedef Grid4d<VEC> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn4dMaxVec ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, maxVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ kn4dMaxVec(kn4dMaxVec &o, tbb::split)
+ : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const kn4dMaxVec &o)
+ {
+ maxVal = max(maxVal, o.maxVal);
+ }
+ Grid4d<VEC> &val;
+ Real maxVal;
+};
+
+template<class T> Grid4d<T> &Grid4d<T>::safeDivide(const Grid4d<T> &a)
+{
+ Grid4dSafeDiv<T>(*this, a);
+ return *this;
+}
+template<class T> Grid4d<T> &Grid4d<T>::copyFrom(const Grid4d<T> &a, bool copyType)
+{
+ assertMsg(a.mSize.x == mSize.x && a.mSize.y == mSize.y && a.mSize.z == mSize.z &&
+ a.mSize.t == mSize.t,
+ "different Grid4d resolutions " << a.mSize << " vs " << this->mSize);
+ memcpy(mData, a.mData, sizeof(T) * mSize.x * mSize.y * mSize.z * mSize.t);
+ if (copyType)
+ mType = a.mType; // copy type marker
+ return *this;
+}
+/*template<class T> Grid4d<T>& Grid4d<T>::operator= (const Grid4d<T>& a) {
+ note: do not use , use copyFrom instead
+}*/
+
+template<class T> struct kn4dSetConstReal : public KernelBase {
+ kn4dSetConstReal(Grid4d<T> &me, T val) : KernelBase(&me, 0), me(me), val(val)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, T val) const
+ {
+ me[idx] = val;
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline T &getArg1()
+ {
+ return val;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn4dSetConstReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, val);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ T val;
+};
+template<class T> struct kn4dAddConstReal : public KernelBase {
+ kn4dAddConstReal(Grid4d<T> &me, T val) : KernelBase(&me, 0), me(me), val(val)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, T val) const
+ {
+ me[idx] += val;
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline T &getArg1()
+ {
+ return val;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn4dAddConstReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, val);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ T val;
+};
+template<class T> struct kn4dMultConst : public KernelBase {
+ kn4dMultConst(Grid4d<T> &me, T val) : KernelBase(&me, 0), me(me), val(val)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, T val) const
+ {
+ me[idx] *= val;
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline T &getArg1()
+ {
+ return val;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn4dMultConst ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, val);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ T val;
+};
+template<class T> struct kn4dClamp : public KernelBase {
+ kn4dClamp(Grid4d<T> &me, T min, T max) : KernelBase(&me, 0), me(me), min(min), max(max)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, T min, T max) const
+ {
+ me[idx] = clamp(me[idx], min, max);
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline T &getArg1()
+ {
+ return min;
+ }
+ typedef T type1;
+ inline T &getArg2()
+ {
+ return max;
+ }
+ typedef T type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel kn4dClamp ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, min, max);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ T min;
+ T max;
+};
+
+template<class T> void Grid4d<T>::add(const Grid4d<T> &a)
+{
+ Grid4dAdd<T, T>(*this, a);
+}
+template<class T> void Grid4d<T>::sub(const Grid4d<T> &a)
+{
+ Grid4dSub<T, T>(*this, a);
+}
+template<class T> void Grid4d<T>::addScaled(const Grid4d<T> &a, const T &factor)
+{
+ Grid4dScaledAdd<T, T>(*this, a, factor);
+}
+template<class T> void Grid4d<T>::setConst(T a)
+{
+ kn4dSetConstReal<T>(*this, T(a));
+}
+template<class T> void Grid4d<T>::addConst(T a)
+{
+ kn4dAddConstReal<T>(*this, T(a));
+}
+template<class T> void Grid4d<T>::multConst(T a)
+{
+ kn4dMultConst<T>(*this, a);
+}
+
+template<class T> void Grid4d<T>::mult(const Grid4d<T> &a)
+{
+ Grid4dMult<T, T>(*this, a);
+}
+
+template<class T> void Grid4d<T>::clamp(Real min, Real max)
+{
+ kn4dClamp<T>(*this, T(min), T(max));
+}
+
+template<> Real Grid4d<Real>::getMax()
+{
+ return kn4dMaxReal(*this);
+}
+template<> Real Grid4d<Real>::getMin()
+{
+ return kn4dMinReal(*this);
+}
+template<> Real Grid4d<Real>::getMaxAbs()
+{
+ Real amin = kn4dMinReal(*this);
+ Real amax = kn4dMaxReal(*this);
+ return max(fabs(amin), fabs(amax));
+}
+template<> Real Grid4d<Vec4>::getMax()
+{
+ return sqrt(kn4dMaxVec<Vec4>(*this));
+}
+template<> Real Grid4d<Vec4>::getMin()
+{
+ return sqrt(kn4dMinVec<Vec4>(*this));
+}
+template<> Real Grid4d<Vec4>::getMaxAbs()
+{
+ return sqrt(kn4dMaxVec<Vec4>(*this));
+}
+template<> Real Grid4d<int>::getMax()
+{
+ return (Real)kn4dMaxInt(*this);
+}
+template<> Real Grid4d<int>::getMin()
+{
+ return (Real)kn4dMinInt(*this);
+}
+template<> Real Grid4d<int>::getMaxAbs()
+{
+ int amin = kn4dMinInt(*this);
+ int amax = kn4dMaxInt(*this);
+ return max(fabs((Real)amin), fabs((Real)amax));
+}
+template<> Real Grid4d<Vec3>::getMax()
+{
+ return sqrt(kn4dMaxVec<Vec3>(*this));
+}
+template<> Real Grid4d<Vec3>::getMin()
+{
+ return sqrt(kn4dMinVec<Vec3>(*this));
+}
+template<> Real Grid4d<Vec3>::getMaxAbs()
+{
+ return sqrt(kn4dMaxVec<Vec3>(*this));
+}
+
+template<class T> void Grid4d<T>::printGrid(int zSlice, int tSlice, bool printIndex, int bnd)
+{
+ std::ostringstream out;
+ out << std::endl;
+ FOR_IJKT_BND(*this, bnd)
+ {
+ IndexInt idx = (*this).index(i, j, k, t);
+ if (((zSlice >= 0 && k == zSlice) || (zSlice < 0)) &&
+ ((tSlice >= 0 && t == tSlice) || (tSlice < 0))) {
+ out << " ";
+ if (printIndex)
+ out << " " << i << "," << j << "," << k << "," << t << ":";
+ out << (*this)[idx];
+ if (i == (*this).getSizeX() - 1 - bnd) {
+ out << std::endl;
+ if (j == (*this).getSizeY() - 1 - bnd) {
+ out << std::endl;
+ if (k == (*this).getSizeZ() - 1 - bnd) {
+ out << std::endl;
+ }
+ }
+ }
+ }
+ }
+ out << endl;
+ debMsg("Printing '" << this->getName() << "' " << out.str().c_str() << " ", 1);
+}
+
+// helper to set/get components of vec4 Grids
+struct knGetComp4d : public KernelBase {
+ knGetComp4d(const Grid4d<Vec4> &src, Grid4d<Real> &dst, int c)
+ : KernelBase(&src, 0), src(src), dst(dst), c(c)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid4d<Vec4> &src, Grid4d<Real> &dst, int c) const
+ {
+ dst[idx] = src[idx][c];
+ }
+ inline const Grid4d<Vec4> &getArg0()
+ {
+ return src;
+ }
+ typedef Grid4d<Vec4> type0;
+ inline Grid4d<Real> &getArg1()
+ {
+ return dst;
+ }
+ typedef Grid4d<Real> type1;
+ inline int &getArg2()
+ {
+ return c;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knGetComp4d ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, src, dst, c);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const Grid4d<Vec4> &src;
+ Grid4d<Real> &dst;
+ int c;
+};
+;
+struct knSetComp4d : public KernelBase {
+ knSetComp4d(const Grid4d<Real> &src, Grid4d<Vec4> &dst, int c)
+ : KernelBase(&src, 0), src(src), dst(dst), c(c)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid4d<Real> &src, Grid4d<Vec4> &dst, int c) const
+ {
+ dst[idx][c] = src[idx];
+ }
+ inline const Grid4d<Real> &getArg0()
+ {
+ return src;
+ }
+ typedef Grid4d<Real> type0;
+ inline Grid4d<Vec4> &getArg1()
+ {
+ return dst;
+ }
+ typedef Grid4d<Vec4> type1;
+ inline int &getArg2()
+ {
+ return c;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetComp4d ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, src, dst, c);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const Grid4d<Real> &src;
+ Grid4d<Vec4> &dst;
+ int c;
+};
+;
+void getComp4d(const Grid4d<Vec4> &src, Grid4d<Real> &dst, int c)
+{
+ knGetComp4d(src, dst, c);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getComp4d", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid4d<Vec4> &src = *_args.getPtr<Grid4d<Vec4>>("src", 0, &_lock);
+ Grid4d<Real> &dst = *_args.getPtr<Grid4d<Real>>("dst", 1, &_lock);
+ int c = _args.get<int>("c", 2, &_lock);
+ _retval = getPyNone();
+ getComp4d(src, dst, c);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getComp4d", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getComp4d", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getComp4d("", "getComp4d", _W_0);
+extern "C" {
+void PbRegister_getComp4d()
+{
+ KEEP_UNUSED(_RP_getComp4d);
+}
+}
+
+;
+void setComp4d(const Grid4d<Real> &src, Grid4d<Vec4> &dst, int c)
+{
+ knSetComp4d(src, dst, c);
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setComp4d", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid4d<Real> &src = *_args.getPtr<Grid4d<Real>>("src", 0, &_lock);
+ Grid4d<Vec4> &dst = *_args.getPtr<Grid4d<Vec4>>("dst", 1, &_lock);
+ int c = _args.get<int>("c", 2, &_lock);
+ _retval = getPyNone();
+ setComp4d(src, dst, c);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setComp4d", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setComp4d", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setComp4d("", "setComp4d", _W_1);
+extern "C" {
+void PbRegister_setComp4d()
+{
+ KEEP_UNUSED(_RP_setComp4d);
+}
+}
+
+;
+
+template<class T> struct knSetBnd4d : public KernelBase {
+ knSetBnd4d(Grid4d<T> &grid, T value, int w)
+ : KernelBase(&grid, 0), grid(grid), value(value), w(w)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, int t, Grid4d<T> &grid, T value, int w) const
+ {
+ bool bnd = (i <= w || i >= grid.getSizeX() - 1 - w || j <= w || j >= grid.getSizeY() - 1 - w ||
+ k <= w || k >= grid.getSizeZ() - 1 - w || t <= w || t >= grid.getSizeT() - 1 - w);
+ if (bnd)
+ grid(i, j, k, t) = value;
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid4d<T> type0;
+ inline T &getArg1()
+ {
+ return value;
+ }
+ typedef T type1;
+ inline int &getArg2()
+ {
+ return w;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetBnd4d ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ
+ << " "
+ " t "
+ << minT << " - " << maxT,
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ if (maxT > 1) {
+ for (int t = __r.begin(); t != (int)__r.end(); t++)
+ for (int k = 0; k < maxZ; k++)
+ for (int j = 0; j < maxY; j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, grid, value, w);
+ }
+ else if (maxZ > 1) {
+ const int t = 0;
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < maxY; j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, grid, value, w);
+ }
+ else {
+ const int t = 0;
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, grid, value, w);
+ }
+ }
+ void run()
+ {
+ if (maxT > 1) {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minT, maxT), *this);
+ }
+ else if (maxZ > 1) {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ }
+ else {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ }
+ Grid4d<T> &grid;
+ T value;
+ int w;
+};
+
+template<class T> void Grid4d<T>::setBound(T value, int boundaryWidth)
+{
+ knSetBnd4d<T>(*this, value, boundaryWidth);
+}
+
+template<class T> struct knSetBnd4dNeumann : public KernelBase {
+ knSetBnd4dNeumann(Grid4d<T> &grid, int w) : KernelBase(&grid, 0), grid(grid), w(w)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, int t, Grid4d<T> &grid, int w) const
+ {
+ bool set = false;
+ int si = i, sj = j, sk = k, st = t;
+ if (i <= w) {
+ si = w + 1;
+ set = true;
+ }
+ if (i >= grid.getSizeX() - 1 - w) {
+ si = grid.getSizeX() - 1 - w - 1;
+ set = true;
+ }
+ if (j <= w) {
+ sj = w + 1;
+ set = true;
+ }
+ if (j >= grid.getSizeY() - 1 - w) {
+ sj = grid.getSizeY() - 1 - w - 1;
+ set = true;
+ }
+ if (k <= w) {
+ sk = w + 1;
+ set = true;
+ }
+ if (k >= grid.getSizeZ() - 1 - w) {
+ sk = grid.getSizeZ() - 1 - w - 1;
+ set = true;
+ }
+ if (t <= w) {
+ st = w + 1;
+ set = true;
+ }
+ if (t >= grid.getSizeT() - 1 - w) {
+ st = grid.getSizeT() - 1 - w - 1;
+ set = true;
+ }
+ if (set)
+ grid(i, j, k, t) = grid(si, sj, sk, st);
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return grid;
+ }
+ typedef Grid4d<T> type0;
+ inline int &getArg1()
+ {
+ return w;
+ }
+ typedef int type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetBnd4dNeumann ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ
+ << " "
+ " t "
+ << minT << " - " << maxT,
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ if (maxT > 1) {
+ for (int t = __r.begin(); t != (int)__r.end(); t++)
+ for (int k = 0; k < maxZ; k++)
+ for (int j = 0; j < maxY; j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, grid, w);
+ }
+ else if (maxZ > 1) {
+ const int t = 0;
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < maxY; j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, grid, w);
+ }
+ else {
+ const int t = 0;
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, grid, w);
+ }
+ }
+ void run()
+ {
+ if (maxT > 1) {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minT, maxT), *this);
+ }
+ else if (maxZ > 1) {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ }
+ else {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ }
+ Grid4d<T> &grid;
+ int w;
+};
+
+template<class T> void Grid4d<T>::setBoundNeumann(int boundaryWidth)
+{
+ knSetBnd4dNeumann<T>(*this, boundaryWidth);
+}
+
+//******************************************************************************
+// testing helpers
+
+//! compute maximal diference of two cells in the grid, needed for testing system
+
+Real grid4dMaxDiff(Grid4d<Real> &g1, Grid4d<Real> &g2)
+{
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1, 0)
+ {
+ maxVal = std::max(maxVal, (double)fabs(g1(i, j, k, t) - g2(i, j, k, t)));
+ }
+ return maxVal;
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "grid4dMaxDiff", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid4d<Real> &g1 = *_args.getPtr<Grid4d<Real>>("g1", 0, &_lock);
+ Grid4d<Real> &g2 = *_args.getPtr<Grid4d<Real>>("g2", 1, &_lock);
+ _retval = toPy(grid4dMaxDiff(g1, g2));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "grid4dMaxDiff", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("grid4dMaxDiff", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_grid4dMaxDiff("", "grid4dMaxDiff", _W_2);
+extern "C" {
+void PbRegister_grid4dMaxDiff()
+{
+ KEEP_UNUSED(_RP_grid4dMaxDiff);
+}
+}
+
+Real grid4dMaxDiffInt(Grid4d<int> &g1, Grid4d<int> &g2)
+{
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1, 0)
+ {
+ maxVal = std::max(maxVal, (double)fabs((double)g1(i, j, k, t) - g2(i, j, k, t)));
+ }
+ return maxVal;
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "grid4dMaxDiffInt", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid4d<int> &g1 = *_args.getPtr<Grid4d<int>>("g1", 0, &_lock);
+ Grid4d<int> &g2 = *_args.getPtr<Grid4d<int>>("g2", 1, &_lock);
+ _retval = toPy(grid4dMaxDiffInt(g1, g2));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "grid4dMaxDiffInt", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("grid4dMaxDiffInt", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_grid4dMaxDiffInt("", "grid4dMaxDiffInt", _W_3);
+extern "C" {
+void PbRegister_grid4dMaxDiffInt()
+{
+ KEEP_UNUSED(_RP_grid4dMaxDiffInt);
+}
+}
+
+Real grid4dMaxDiffVec3(Grid4d<Vec3> &g1, Grid4d<Vec3> &g2)
+{
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1, 0)
+ {
+ double d = 0.;
+ for (int c = 0; c < 3; ++c) {
+ d += fabs((double)g1(i, j, k, t)[c] - (double)g2(i, j, k, t)[c]);
+ }
+ maxVal = std::max(maxVal, d);
+ }
+ return maxVal;
+}
+static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "grid4dMaxDiffVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid4d<Vec3> &g1 = *_args.getPtr<Grid4d<Vec3>>("g1", 0, &_lock);
+ Grid4d<Vec3> &g2 = *_args.getPtr<Grid4d<Vec3>>("g2", 1, &_lock);
+ _retval = toPy(grid4dMaxDiffVec3(g1, g2));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "grid4dMaxDiffVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("grid4dMaxDiffVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_grid4dMaxDiffVec3("", "grid4dMaxDiffVec3", _W_4);
+extern "C" {
+void PbRegister_grid4dMaxDiffVec3()
+{
+ KEEP_UNUSED(_RP_grid4dMaxDiffVec3);
+}
+}
+
+Real grid4dMaxDiffVec4(Grid4d<Vec4> &g1, Grid4d<Vec4> &g2)
+{
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1, 0)
+ {
+ double d = 0.;
+ for (int c = 0; c < 4; ++c) {
+ d += fabs((double)g1(i, j, k, t)[c] - (double)g2(i, j, k, t)[c]);
+ }
+ maxVal = std::max(maxVal, d);
+ }
+ return maxVal;
+}
+static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "grid4dMaxDiffVec4", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid4d<Vec4> &g1 = *_args.getPtr<Grid4d<Vec4>>("g1", 0, &_lock);
+ Grid4d<Vec4> &g2 = *_args.getPtr<Grid4d<Vec4>>("g2", 1, &_lock);
+ _retval = toPy(grid4dMaxDiffVec4(g1, g2));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "grid4dMaxDiffVec4", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("grid4dMaxDiffVec4", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_grid4dMaxDiffVec4("", "grid4dMaxDiffVec4", _W_5);
+extern "C" {
+void PbRegister_grid4dMaxDiffVec4()
+{
+ KEEP_UNUSED(_RP_grid4dMaxDiffVec4);
+}
+}
+
+// set a region to some value
+
+template<class S> struct knSetRegion4d : public KernelBase {
+ knSetRegion4d(Grid4d<S> &dst, Vec4 start, Vec4 end, S value)
+ : KernelBase(&dst, 0), dst(dst), start(start), end(end), value(value)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, int t, Grid4d<S> &dst, Vec4 start, Vec4 end, S value) const
+ {
+ Vec4 p(i, j, k, t);
+ for (int c = 0; c < 4; ++c)
+ if (p[c] < start[c] || p[c] > end[c])
+ return;
+ dst(i, j, k, t) = value;
+ }
+ inline Grid4d<S> &getArg0()
+ {
+ return dst;
+ }
+ typedef Grid4d<S> type0;
+ inline Vec4 &getArg1()
+ {
+ return start;
+ }
+ typedef Vec4 type1;
+ inline Vec4 &getArg2()
+ {
+ return end;
+ }
+ typedef Vec4 type2;
+ inline S &getArg3()
+ {
+ return value;
+ }
+ typedef S type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetRegion4d ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ
+ << " "
+ " t "
+ << minT << " - " << maxT,
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ if (maxT > 1) {
+ for (int t = __r.begin(); t != (int)__r.end(); t++)
+ for (int k = 0; k < maxZ; k++)
+ for (int j = 0; j < maxY; j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, dst, start, end, value);
+ }
+ else if (maxZ > 1) {
+ const int t = 0;
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < maxY; j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, dst, start, end, value);
+ }
+ else {
+ const int t = 0;
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, dst, start, end, value);
+ }
+ }
+ void run()
+ {
+ if (maxT > 1) {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minT, maxT), *this);
+ }
+ else if (maxZ > 1) {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ }
+ else {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ }
+ Grid4d<S> &dst;
+ Vec4 start;
+ Vec4 end;
+ S value;
+};
+//! simple init functions in 4d
+void setRegion4d(Grid4d<Real> &dst, Vec4 start, Vec4 end, Real value)
+{
+ knSetRegion4d<Real>(dst, start, end, value);
+}
+static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setRegion4d", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid4d<Real> &dst = *_args.getPtr<Grid4d<Real>>("dst", 0, &_lock);
+ Vec4 start = _args.get<Vec4>("start", 1, &_lock);
+ Vec4 end = _args.get<Vec4>("end", 2, &_lock);
+ Real value = _args.get<Real>("value", 3, &_lock);
+ _retval = getPyNone();
+ setRegion4d(dst, start, end, value);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setRegion4d", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setRegion4d", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setRegion4d("", "setRegion4d", _W_6);
+extern "C" {
+void PbRegister_setRegion4d()
+{
+ KEEP_UNUSED(_RP_setRegion4d);
+}
+}
+
+//! simple init functions in 4d, vec4
+void setRegion4dVec4(Grid4d<Vec4> &dst, Vec4 start, Vec4 end, Vec4 value)
+{
+ knSetRegion4d<Vec4>(dst, start, end, value);
+}
+static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setRegion4dVec4", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid4d<Vec4> &dst = *_args.getPtr<Grid4d<Vec4>>("dst", 0, &_lock);
+ Vec4 start = _args.get<Vec4>("start", 1, &_lock);
+ Vec4 end = _args.get<Vec4>("end", 2, &_lock);
+ Vec4 value = _args.get<Vec4>("value", 3, &_lock);
+ _retval = getPyNone();
+ setRegion4dVec4(dst, start, end, value);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setRegion4dVec4", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setRegion4dVec4", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setRegion4dVec4("", "setRegion4dVec4", _W_7);
+extern "C" {
+void PbRegister_setRegion4dVec4()
+{
+ KEEP_UNUSED(_RP_setRegion4dVec4);
+}
+}
+
+//! slow helper to visualize tests, get a 3d slice of a 4d grid
+void getSliceFrom4d(Grid4d<Real> &src, int srct, Grid<Real> &dst)
+{
+ const int bnd = 0;
+ if (!src.isInBounds(Vec4i(bnd, bnd, bnd, srct)))
+ return;
+
+ for (int k = bnd; k < src.getSizeZ() - bnd; k++)
+ for (int j = bnd; j < src.getSizeY() - bnd; j++)
+ for (int i = bnd; i < src.getSizeX() - bnd; i++) {
+ if (!dst.isInBounds(Vec3i(i, j, k)))
+ continue;
+ dst(i, j, k) = src(i, j, k, srct);
+ }
+}
+static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getSliceFrom4d", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid4d<Real> &src = *_args.getPtr<Grid4d<Real>>("src", 0, &_lock);
+ int srct = _args.get<int>("srct", 1, &_lock);
+ Grid<Real> &dst = *_args.getPtr<Grid<Real>>("dst", 2, &_lock);
+ _retval = getPyNone();
+ getSliceFrom4d(src, srct, dst);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getSliceFrom4d", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getSliceFrom4d", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getSliceFrom4d("", "getSliceFrom4d", _W_8);
+extern "C" {
+void PbRegister_getSliceFrom4d()
+{
+ KEEP_UNUSED(_RP_getSliceFrom4d);
+}
+}
+
+//! slow helper to visualize tests, get a 3d slice of a 4d vec4 grid
+void getSliceFrom4dVec(Grid4d<Vec4> &src, int srct, Grid<Vec3> &dst, Grid<Real> *dstt = NULL)
+{
+ const int bnd = 0;
+ if (!src.isInBounds(Vec4i(bnd, bnd, bnd, srct)))
+ return;
+
+ for (int k = bnd; k < src.getSizeZ() - bnd; k++)
+ for (int j = bnd; j < src.getSizeY() - bnd; j++)
+ for (int i = bnd; i < src.getSizeX() - bnd; i++) {
+ if (!dst.isInBounds(Vec3i(i, j, k)))
+ continue;
+ for (int c = 0; c < 3; ++c)
+ dst(i, j, k)[c] = src(i, j, k, srct)[c];
+ if (dstt)
+ (*dstt)(i, j, k) = src(i, j, k, srct)[3];
+ }
+}
+static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getSliceFrom4dVec", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid4d<Vec4> &src = *_args.getPtr<Grid4d<Vec4>>("src", 0, &_lock);
+ int srct = _args.get<int>("srct", 1, &_lock);
+ Grid<Vec3> &dst = *_args.getPtr<Grid<Vec3>>("dst", 2, &_lock);
+ Grid<Real> *dstt = _args.getPtrOpt<Grid<Real>>("dstt", 3, NULL, &_lock);
+ _retval = getPyNone();
+ getSliceFrom4dVec(src, srct, dst, dstt);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getSliceFrom4dVec", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getSliceFrom4dVec", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getSliceFrom4dVec("", "getSliceFrom4dVec", _W_9);
+extern "C" {
+void PbRegister_getSliceFrom4dVec()
+{
+ KEEP_UNUSED(_RP_getSliceFrom4dVec);
+}
+}
+
+//******************************************************************************
+// interpolation
+
+//! same as in grid.h , but takes an additional optional "desired" size
+static inline void gridFactor4d(
+ Vec4 s1, Vec4 s2, Vec4 optSize, Vec4 scale, Vec4 &srcFac, Vec4 &retOff)
+{
+ for (int c = 0; c < 4; c++) {
+ if (optSize[c] > 0.) {
+ s2[c] = optSize[c];
+ }
+ }
+ srcFac = calcGridSizeFactor4d(s1, s2) / scale;
+ retOff = -retOff * srcFac + srcFac * 0.5;
+}
+
+//! interpolate 4d grid from one size to another size
+// real valued offsets & scale
+
+template<class S> struct knInterpol4d : public KernelBase {
+ knInterpol4d(Grid4d<S> &target, Grid4d<S> &source, const Vec4 &srcFac, const Vec4 &offset)
+ : KernelBase(&target, 0), target(target), source(source), srcFac(srcFac), offset(offset)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ int t,
+ Grid4d<S> &target,
+ Grid4d<S> &source,
+ const Vec4 &srcFac,
+ const Vec4 &offset) const
+ {
+ Vec4 pos = Vec4(i, j, k, t) * srcFac + offset;
+ target(i, j, k, t) = source.getInterpolated(pos);
+ }
+ inline Grid4d<S> &getArg0()
+ {
+ return target;
+ }
+ typedef Grid4d<S> type0;
+ inline Grid4d<S> &getArg1()
+ {
+ return source;
+ }
+ typedef Grid4d<S> type1;
+ inline const Vec4 &getArg2()
+ {
+ return srcFac;
+ }
+ typedef Vec4 type2;
+ inline const Vec4 &getArg3()
+ {
+ return offset;
+ }
+ typedef Vec4 type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knInterpol4d ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ
+ << " "
+ " t "
+ << minT << " - " << maxT,
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ if (maxT > 1) {
+ for (int t = __r.begin(); t != (int)__r.end(); t++)
+ for (int k = 0; k < maxZ; k++)
+ for (int j = 0; j < maxY; j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, target, source, srcFac, offset);
+ }
+ else if (maxZ > 1) {
+ const int t = 0;
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < maxY; j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, target, source, srcFac, offset);
+ }
+ else {
+ const int t = 0;
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, target, source, srcFac, offset);
+ }
+ }
+ void run()
+ {
+ if (maxT > 1) {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minT, maxT), *this);
+ }
+ else if (maxZ > 1) {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ }
+ else {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ }
+ Grid4d<S> &target;
+ Grid4d<S> &source;
+ const Vec4 &srcFac;
+ const Vec4 &offset;
+};
+//! linearly interpolate data of a 4d grid
+
+void interpolateGrid4d(Grid4d<Real> &target,
+ Grid4d<Real> &source,
+ Vec4 offset = Vec4(0.),
+ Vec4 scale = Vec4(1.),
+ Vec4 size = Vec4(-1.))
+{
+ Vec4 srcFac(1.), off2 = offset;
+ gridFactor4d(toVec4(source.getSize()), toVec4(target.getSize()), size, scale, srcFac, off2);
+ knInterpol4d<Real>(target, source, srcFac, off2);
+}
+static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "interpolateGrid4d", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid4d<Real> &target = *_args.getPtr<Grid4d<Real>>("target", 0, &_lock);
+ Grid4d<Real> &source = *_args.getPtr<Grid4d<Real>>("source", 1, &_lock);
+ Vec4 offset = _args.getOpt<Vec4>("offset", 2, Vec4(0.), &_lock);
+ Vec4 scale = _args.getOpt<Vec4>("scale", 3, Vec4(1.), &_lock);
+ Vec4 size = _args.getOpt<Vec4>("size", 4, Vec4(-1.), &_lock);
+ _retval = getPyNone();
+ interpolateGrid4d(target, source, offset, scale, size);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "interpolateGrid4d", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("interpolateGrid4d", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_interpolateGrid4d("", "interpolateGrid4d", _W_10);
+extern "C" {
+void PbRegister_interpolateGrid4d()
+{
+ KEEP_UNUSED(_RP_interpolateGrid4d);
+}
+}
+
+//! linearly interpolate vec4 data of a 4d grid
+
+void interpolateGrid4dVec(Grid4d<Vec4> &target,
+ Grid4d<Vec4> &source,
+ Vec4 offset = Vec4(0.),
+ Vec4 scale = Vec4(1.),
+ Vec4 size = Vec4(-1.))
+{
+ Vec4 srcFac(1.), off2 = offset;
+ gridFactor4d(toVec4(source.getSize()), toVec4(target.getSize()), size, scale, srcFac, off2);
+ knInterpol4d<Vec4>(target, source, srcFac, off2);
+}
+static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "interpolateGrid4dVec", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid4d<Vec4> &target = *_args.getPtr<Grid4d<Vec4>>("target", 0, &_lock);
+ Grid4d<Vec4> &source = *_args.getPtr<Grid4d<Vec4>>("source", 1, &_lock);
+ Vec4 offset = _args.getOpt<Vec4>("offset", 2, Vec4(0.), &_lock);
+ Vec4 scale = _args.getOpt<Vec4>("scale", 3, Vec4(1.), &_lock);
+ Vec4 size = _args.getOpt<Vec4>("size", 4, Vec4(-1.), &_lock);
+ _retval = getPyNone();
+ interpolateGrid4dVec(target, source, offset, scale, size);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "interpolateGrid4dVec", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("interpolateGrid4dVec", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_interpolateGrid4dVec("", "interpolateGrid4dVec", _W_11);
+extern "C" {
+void PbRegister_interpolateGrid4dVec()
+{
+ KEEP_UNUSED(_RP_interpolateGrid4dVec);
+}
+}
+
+// explicit instantiation
+template class Grid4d<int>;
+template class Grid4d<Real>;
+template class Grid4d<Vec3>;
+template class Grid4d<Vec4>;
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/grid4d.h b/extern/mantaflow/preprocessed/grid4d.h
new file mode 100644
index 00000000000..c3a98788da3
--- /dev/null
+++ b/extern/mantaflow/preprocessed/grid4d.h
@@ -0,0 +1,1558 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#ifndef _GRID4D_H
+#define _GRID4D_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "vector4d.h"
+#include "kernel.h"
+
+namespace Manta {
+
+//! Base class for all grids
+class Grid4dBase : public PbClass {
+ public:
+ enum Grid4dType { TypeNone = 0, TypeReal = 1, TypeInt = 2, TypeVec3 = 4, TypeVec4 = 8 };
+
+ Grid4dBase(FluidSolver *parent);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "Grid4dBase::Grid4dBase", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new Grid4dBase(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "Grid4dBase::Grid4dBase", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4dBase::Grid4dBase", e.what());
+ return -1;
+ }
+ }
+
+ //! Get the grids X dimension
+ inline int getSizeX() const
+ {
+ return mSize.x;
+ }
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4dBase *pbo = dynamic_cast<Grid4dBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeX", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getSizeX());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4dBase::getSizeX", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4dBase::getSizeX", e.what());
+ return 0;
+ }
+ }
+
+ //! Get the grids Y dimension
+ inline int getSizeY() const
+ {
+ return mSize.y;
+ }
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4dBase *pbo = dynamic_cast<Grid4dBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeY", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getSizeY());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4dBase::getSizeY", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4dBase::getSizeY", e.what());
+ return 0;
+ }
+ }
+
+ //! Get the grids Z dimension
+ inline int getSizeZ() const
+ {
+ return mSize.z;
+ }
+ static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4dBase *pbo = dynamic_cast<Grid4dBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeZ", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getSizeZ());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4dBase::getSizeZ", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4dBase::getSizeZ", e.what());
+ return 0;
+ }
+ }
+
+ //! Get the grids T dimension
+ inline int getSizeT() const
+ {
+ return mSize.t;
+ }
+ static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4dBase *pbo = dynamic_cast<Grid4dBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeT", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getSizeT());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4dBase::getSizeT", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4dBase::getSizeT", e.what());
+ return 0;
+ }
+ }
+
+ //! Get the grids dimensions
+ inline Vec4i getSize() const
+ {
+ return mSize;
+ }
+ static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4dBase *pbo = dynamic_cast<Grid4dBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSize", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getSize());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4dBase::getSize", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4dBase::getSize", e.what());
+ return 0;
+ }
+ }
+
+ //! Get Stride in X dimension
+ inline IndexInt getStrideX() const
+ {
+ return 1;
+ }
+ //! Get Stride in Y dimension
+ inline IndexInt getStrideY() const
+ {
+ return mSize.x;
+ }
+ //! Get Stride in Z dimension
+ inline IndexInt getStrideZ() const
+ {
+ return mStrideZ;
+ }
+ //! Get Stride in T dimension
+ inline IndexInt getStrideT() const
+ {
+ return mStrideT;
+ }
+
+ inline Real getDx()
+ {
+ return mDx;
+ }
+
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(int i, int j, int k, int t) const;
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(IndexInt idx) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec4i &p, int bnd) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec4i &p) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec4 &p, int bnd = 0) const
+ {
+ return isInBounds(toVec4i(p), bnd);
+ }
+ //! Check if linear index is in the range of the array
+ inline bool isInBounds(IndexInt idx) const;
+
+ //! Get the type of grid
+ inline Grid4dType getType() const
+ {
+ return mType;
+ }
+ //! Check dimensionality
+ inline bool is3D() const
+ {
+ return true;
+ }
+ static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4dBase *pbo = dynamic_cast<Grid4dBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4dBase::is3D", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->is3D());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4dBase::is3D", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4dBase::is3D", e.what());
+ return 0;
+ }
+ }
+
+ inline bool is4D() const
+ {
+ return true;
+ }
+ static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4dBase *pbo = dynamic_cast<Grid4dBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4dBase::is4D", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->is4D());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4dBase::is4D", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4dBase::is4D", e.what());
+ return 0;
+ }
+ }
+
+ //! 3d compatibility
+ inline bool isInBounds(int i, int j, int k, int t, int bnd) const
+ {
+ return isInBounds(Vec4i(i, j, k, t), bnd);
+ }
+
+ //! Get index into the data
+ inline IndexInt index(int i, int j, int k, int t) const
+ {
+ DEBUG_ONLY(checkIndex(i, j, k, t));
+ return (IndexInt)i + (IndexInt)mSize.x * j + (IndexInt)mStrideZ * k + (IndexInt)mStrideT * t;
+ }
+ //! Get index into the data
+ inline IndexInt index(const Vec4i &pos) const
+ {
+ DEBUG_ONLY(checkIndex(pos.x, pos.y, pos.z, pos.t));
+ return (IndexInt)pos.x + (IndexInt)mSize.x * pos.y + (IndexInt)mStrideZ * pos.z +
+ (IndexInt)mStrideT * pos.t;
+ }
+
+ protected:
+ Grid4dType mType;
+ Vec4i mSize;
+ Real mDx;
+ // precomputed Z,T shift: to ensure 2D compatibility, always use this instead of sx*sy !
+ IndexInt mStrideZ;
+ IndexInt mStrideT;
+ public:
+ PbArgs _args;
+}
+#define _C_Grid4dBase
+;
+
+//! Grid class
+
+template<class T> class Grid4d : public Grid4dBase {
+ public:
+ //! init new grid, values are set to zero
+ Grid4d(FluidSolver *parent, bool show = true);
+ static int _W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "Grid4d::Grid4d", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ bool show = _args.getOpt<bool>("show", 1, true, &_lock);
+ obj = new Grid4d(parent, show);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "Grid4d::Grid4d", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::Grid4d", e.what());
+ return -1;
+ }
+ }
+
+ //! create new & copy content from another grid
+ Grid4d(const Grid4d<T> &a);
+ //! return memory to solver
+ virtual ~Grid4d();
+
+ typedef T BASETYPE;
+ typedef Grid4dBase BASETYPE_GRID;
+
+ void save(std::string name);
+ static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::save", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->save(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::save", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::save", e.what());
+ return 0;
+ }
+ }
+
+ void load(std::string name);
+ static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::load", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->load(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::load", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::load", e.what());
+ return 0;
+ }
+ }
+
+ //! set all cells to zero
+ void clear();
+ static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::clear", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clear();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::clear", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::clear", e.what());
+ return 0;
+ }
+ }
+
+ //! all kinds of access functions, use grid(), grid[] or grid.get()
+ //! access data
+ inline T get(int i, int j, int k, int t) const
+ {
+ return mData[index(i, j, k, t)];
+ }
+ //! access data
+ inline T &get(int i, int j, int k, int t)
+ {
+ return mData[index(i, j, k, t)];
+ }
+ //! access data
+ inline T get(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkIndex(idx));
+ return mData[idx];
+ }
+ //! access data
+ inline T get(const Vec4i &pos) const
+ {
+ return mData[index(pos)];
+ }
+ //! access data
+ inline T &operator()(int i, int j, int k, int t)
+ {
+ return mData[index(i, j, k, t)];
+ }
+ //! access data
+ inline T operator()(int i, int j, int k, int t) const
+ {
+ return mData[index(i, j, k, t)];
+ }
+ //! access data
+ inline T &operator()(IndexInt idx)
+ {
+ DEBUG_ONLY(checkIndex(idx));
+ return mData[idx];
+ }
+ //! access data
+ inline T operator()(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkIndex(idx));
+ return mData[idx];
+ }
+ //! access data
+ inline T &operator()(const Vec4i &pos)
+ {
+ return mData[index(pos)];
+ }
+ //! access data
+ inline T operator()(const Vec4i &pos) const
+ {
+ return mData[index(pos)];
+ }
+ //! access data
+ inline T &operator[](IndexInt idx)
+ {
+ DEBUG_ONLY(checkIndex(idx));
+ return mData[idx];
+ }
+ //! access data
+ inline const T operator[](IndexInt idx) const
+ {
+ DEBUG_ONLY(checkIndex(idx));
+ return mData[idx];
+ }
+
+ // interpolated access
+ inline T getInterpolated(const Vec4 &pos) const
+ {
+ return interpol4d<T>(mData, mSize, mStrideZ, mStrideT, pos);
+ }
+
+ // assignment / copy
+
+ //! warning - do not use "=" for grids in python, this copies the reference! not the grid
+ //! content...
+ // Grid4d<T>& operator=(const Grid4d<T>& a);
+ //! copy content from other grid (use this one instead of operator= !)
+ Grid4d<T> &copyFrom(const Grid4d<T> &a, bool copyType = true);
+ static PyObject *_W_12(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::copyFrom", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid4d<T> &a = *_args.getPtr<Grid4d<T>>("a", 0, &_lock);
+ bool copyType = _args.getOpt<bool>("copyType", 1, true, &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->copyFrom(a, copyType));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::copyFrom", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::copyFrom", e.what());
+ return 0;
+ }
+ }
+ // old: { *this = a; }
+
+ // helper functions to work with grids in scene files
+
+ //! add/subtract other grid
+ void add(const Grid4d<T> &a);
+ static PyObject *_W_13(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::add", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid4d<T> &a = *_args.getPtr<Grid4d<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->add(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::add", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::add", e.what());
+ return 0;
+ }
+ }
+
+ void sub(const Grid4d<T> &a);
+ static PyObject *_W_14(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::sub", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid4d<T> &a = *_args.getPtr<Grid4d<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->sub(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::sub", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::sub", e.what());
+ return 0;
+ }
+ }
+
+ //! set all cells to constant value
+ void setConst(T s);
+ static PyObject *_W_15(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::setConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::setConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::setConst", e.what());
+ return 0;
+ }
+ }
+
+ //! add constant to all grid cells
+ void addConst(T s);
+ static PyObject *_W_16(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::addConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->addConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::addConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::addConst", e.what());
+ return 0;
+ }
+ }
+
+ //! add scaled other grid to current one (note, only "Real" factor, "T" type not supported here!)
+ void addScaled(const Grid4d<T> &a, const T &factor);
+ static PyObject *_W_17(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::addScaled", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid4d<T> &a = *_args.getPtr<Grid4d<T>>("a", 0, &_lock);
+ const T &factor = *_args.getPtr<T>("factor", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->addScaled(a, factor);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::addScaled", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::addScaled", e.what());
+ return 0;
+ }
+ }
+
+ //! multiply contents of grid
+ void mult(const Grid4d<T> &a);
+ static PyObject *_W_18(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::mult", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid4d<T> &a = *_args.getPtr<Grid4d<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->mult(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::mult", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::mult", e.what());
+ return 0;
+ }
+ }
+
+ //! multiply each cell by a constant scalar value
+ void multConst(T s);
+ static PyObject *_W_19(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::multConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->multConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::multConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::multConst", e.what());
+ return 0;
+ }
+ }
+
+ //! clamp content to range (for vec3, clamps each component separately)
+ void clamp(Real min, Real max);
+ static PyObject *_W_20(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::clamp", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real min = _args.get<Real>("min", 0, &_lock);
+ Real max = _args.get<Real>("max", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clamp(min, max);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::clamp", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::clamp", e.what());
+ return 0;
+ }
+ }
+
+ // common compound operators
+ //! get absolute max value in grid
+ Real getMaxAbs();
+ static PyObject *_W_21(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::getMaxAbs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMaxAbs());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::getMaxAbs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::getMaxAbs", e.what());
+ return 0;
+ }
+ }
+
+ //! get max value in grid
+ Real getMax();
+ static PyObject *_W_22(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::getMax", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMax());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::getMax", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::getMax", e.what());
+ return 0;
+ }
+ }
+
+ //! get min value in grid
+ Real getMin();
+ static PyObject *_W_23(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::getMin", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMin());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::getMin", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::getMin", e.what());
+ return 0;
+ }
+ }
+
+ //! set all boundary cells to constant value (Dirichlet)
+ void setBound(T value, int boundaryWidth = 1);
+ static PyObject *_W_24(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::setBound", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T value = _args.get<T>("value", 0, &_lock);
+ int boundaryWidth = _args.getOpt<int>("boundaryWidth", 1, 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setBound(value, boundaryWidth);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::setBound", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::setBound", e.what());
+ return 0;
+ }
+ }
+
+ //! set all boundary cells to last inner value (Neumann)
+ void setBoundNeumann(int boundaryWidth = 1);
+ static PyObject *_W_25(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::setBoundNeumann", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int boundaryWidth = _args.getOpt<int>("boundaryWidth", 0, 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setBoundNeumann(boundaryWidth);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::setBoundNeumann", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::setBoundNeumann", e.what());
+ return 0;
+ }
+ }
+
+ //! debugging helper, print grid from Python
+ void printGrid(int zSlice = -1, int tSlice = -1, bool printIndex = false, int bnd = 0);
+ static PyObject *_W_26(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Grid4d *pbo = dynamic_cast<Grid4d *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Grid4d::printGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int zSlice = _args.getOpt<int>("zSlice", 0, -1, &_lock);
+ int tSlice = _args.getOpt<int>("tSlice", 1, -1, &_lock);
+ bool printIndex = _args.getOpt<bool>("printIndex", 2, false, &_lock);
+ int bnd = _args.getOpt<int>("bnd", 3, 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->printGrid(zSlice, tSlice, printIndex, bnd);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Grid4d::printGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Grid4d::printGrid", e.what());
+ return 0;
+ }
+ }
+
+ // c++ only operators
+ template<class S> Grid4d<T> &operator+=(const Grid4d<S> &a);
+ template<class S> Grid4d<T> &operator+=(const S &a);
+ template<class S> Grid4d<T> &operator-=(const Grid4d<S> &a);
+ template<class S> Grid4d<T> &operator-=(const S &a);
+ template<class S> Grid4d<T> &operator*=(const Grid4d<S> &a);
+ template<class S> Grid4d<T> &operator*=(const S &a);
+ template<class S> Grid4d<T> &operator/=(const Grid4d<S> &a);
+ template<class S> Grid4d<T> &operator/=(const S &a);
+ Grid4d<T> &safeDivide(const Grid4d<T> &a);
+
+ //! Swap data with another grid (no actual data is moved)
+ void swap(Grid4d<T> &other);
+
+ protected:
+ T *mData;
+ public:
+ PbArgs _args;
+}
+#define _C_Grid4d
+;
+
+// Python doesn't know about templates: explicit aliases needed
+
+//! helper to compute grid conversion factor between local coordinates of two grids
+inline Vec4 calcGridSizeFactor4d(Vec4i s1, Vec4i s2)
+{
+ return Vec4(Real(s1[0]) / s2[0], Real(s1[1]) / s2[1], Real(s1[2]) / s2[2], Real(s1[3]) / s2[3]);
+}
+inline Vec4 calcGridSizeFactor4d(Vec4 s1, Vec4 s2)
+{
+ return Vec4(s1[0] / s2[0], s1[1] / s2[1], s1[2] / s2[2], s1[3] / s2[3]);
+}
+
+// prototypes for grid plugins
+void getComponent4d(const Grid4d<Vec4> &src, Grid4d<Real> &dst, int c);
+void setComponent4d(const Grid4d<Real> &src, Grid4d<Vec4> &dst, int c);
+
+//******************************************************************************
+// Implementation of inline functions
+
+inline void Grid4dBase::checkIndex(int i, int j, int k, int t) const
+{
+ if (i < 0 || j < 0 || i >= mSize.x || j >= mSize.y || k < 0 || k >= mSize.z || t < 0 ||
+ t >= mSize.t) {
+ std::ostringstream s;
+ s << "Grid4d " << mName << " dim " << mSize << " : index " << i << "," << j << "," << k << ","
+ << t << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+inline void Grid4dBase::checkIndex(IndexInt idx) const
+{
+ if (idx < 0 || idx >= mSize.x * mSize.y * mSize.z * mSize.t) {
+ std::ostringstream s;
+ s << "Grid4d " << mName << " dim " << mSize << " : index " << idx << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+bool Grid4dBase::isInBounds(const Vec4i &p) const
+{
+ return (p.x >= 0 && p.y >= 0 && p.z >= 0 && p.t >= 0 && p.x < mSize.x && p.y < mSize.y &&
+ p.z < mSize.z && p.t < mSize.t);
+}
+
+bool Grid4dBase::isInBounds(const Vec4i &p, int bnd) const
+{
+ bool ret = (p.x >= bnd && p.y >= bnd && p.x < mSize.x - bnd && p.y < mSize.y - bnd);
+ ret &= (p.z >= bnd && p.z < mSize.z - bnd);
+ ret &= (p.t >= bnd && p.t < mSize.t - bnd);
+ return ret;
+}
+//! Check if linear index is in the range of the array
+bool Grid4dBase::isInBounds(IndexInt idx) const
+{
+ if (idx < 0 || idx >= mSize.x * mSize.y * mSize.z * mSize.t) {
+ return false;
+ }
+ return true;
+}
+
+// note - ugly, mostly copied from normal GRID!
+
+template<class T, class S> struct Grid4dAdd : public KernelBase {
+ Grid4dAdd(Grid4d<T> &me, const Grid4d<S> &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, const Grid4d<S> &other) const
+ {
+ me[idx] += other[idx];
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline const Grid4d<S> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid4d<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel Grid4dAdd ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ const Grid4d<S> &other;
+};
+template<class T, class S> struct Grid4dSub : public KernelBase {
+ Grid4dSub(Grid4d<T> &me, const Grid4d<S> &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, const Grid4d<S> &other) const
+ {
+ me[idx] -= other[idx];
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline const Grid4d<S> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid4d<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel Grid4dSub ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ const Grid4d<S> &other;
+};
+template<class T, class S> struct Grid4dMult : public KernelBase {
+ Grid4dMult(Grid4d<T> &me, const Grid4d<S> &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, const Grid4d<S> &other) const
+ {
+ me[idx] *= other[idx];
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline const Grid4d<S> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid4d<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel Grid4dMult ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ const Grid4d<S> &other;
+};
+template<class T, class S> struct Grid4dDiv : public KernelBase {
+ Grid4dDiv(Grid4d<T> &me, const Grid4d<S> &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, const Grid4d<S> &other) const
+ {
+ me[idx] /= other[idx];
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline const Grid4d<S> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid4d<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel Grid4dDiv ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ const Grid4d<S> &other;
+};
+template<class T, class S> struct Grid4dAddScalar : public KernelBase {
+ Grid4dAddScalar(Grid4d<T> &me, const S &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, const S &other) const
+ {
+ me[idx] += other;
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel Grid4dAddScalar ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ const S &other;
+};
+template<class T, class S> struct Grid4dMultScalar : public KernelBase {
+ Grid4dMultScalar(Grid4d<T> &me, const S &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, const S &other) const
+ {
+ me[idx] *= other;
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel Grid4dMultScalar ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ const S &other;
+};
+template<class T, class S> struct Grid4dScaledAdd : public KernelBase {
+ Grid4dScaledAdd(Grid4d<T> &me, const Grid4d<T> &other, const S &factor)
+ : KernelBase(&me, 0), me(me), other(other), factor(factor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, const Grid4d<T> &other, const S &factor) const
+ {
+ me[idx] += factor * other[idx];
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline const Grid4d<T> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid4d<T> type1;
+ inline const S &getArg2()
+ {
+ return factor;
+ }
+ typedef S type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel Grid4dScaledAdd ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other, factor);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ const Grid4d<T> &other;
+ const S &factor;
+};
+
+template<class T> struct Grid4dSafeDiv : public KernelBase {
+ Grid4dSafeDiv(Grid4d<T> &me, const Grid4d<T> &other) : KernelBase(&me, 0), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, const Grid4d<T> &other) const
+ {
+ me[idx] = safeDivide(me[idx], other[idx]);
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline const Grid4d<T> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid4d<T> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel Grid4dSafeDiv ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ const Grid4d<T> &other;
+};
+template<class T> struct Grid4dSetConst : public KernelBase {
+ Grid4dSetConst(Grid4d<T> &me, T value) : KernelBase(&me, 0), me(me), value(value)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid4d<T> &me, T value) const
+ {
+ me[idx] = value;
+ }
+ inline Grid4d<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid4d<T> type0;
+ inline T &getArg1()
+ {
+ return value;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel Grid4dSetConst ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, value);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid4d<T> &me;
+ T value;
+};
+
+template<class T> template<class S> Grid4d<T> &Grid4d<T>::operator+=(const Grid4d<S> &a)
+{
+ Grid4dAdd<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T> &Grid4d<T>::operator+=(const S &a)
+{
+ Grid4dAddScalar<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T> &Grid4d<T>::operator-=(const Grid4d<S> &a)
+{
+ Grid4dSub<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T> &Grid4d<T>::operator-=(const S &a)
+{
+ Grid4dAddScalar<T, S>(*this, -a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T> &Grid4d<T>::operator*=(const Grid4d<S> &a)
+{
+ Grid4dMult<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T> &Grid4d<T>::operator*=(const S &a)
+{
+ Grid4dMultScalar<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T> &Grid4d<T>::operator/=(const Grid4d<S> &a)
+{
+ Grid4dDiv<T, S>(*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T> &Grid4d<T>::operator/=(const S &a)
+{
+ S rez((S)1.0 / a);
+ Grid4dMultScalar<T, S>(*this, rez);
+ return *this;
+}
+
+//******************************************************************************
+// Other helper functions
+
+inline Vec4 getGradient4d(const Grid4d<Real> &data, int i, int j, int k, int t)
+{
+ Vec4 v;
+ if (i > data.getSizeX() - 2)
+ i = data.getSizeX() - 2;
+ if (j > data.getSizeY() - 2)
+ j = data.getSizeY() - 2;
+ if (k > data.getSizeZ() - 2)
+ k = data.getSizeZ() - 2;
+ if (t > data.getSizeT() - 2)
+ t = data.getSizeT() - 2;
+ if (i < 1)
+ i = 1;
+ if (j < 1)
+ j = 1;
+ if (k < 1)
+ k = 1;
+ if (t < 1)
+ t = 1;
+ v = Vec4(data(i + 1, j, k, t) - data(i - 1, j, k, t),
+ data(i, j + 1, k, t) - data(i, j - 1, k, t),
+ data(i, j, k + 1, t) - data(i, j, k - 1, t),
+ data(i, j, k, t + 1) - data(i, j, k, t - 1));
+ return v;
+}
+
+template<class S> struct KnInterpolateGrid4dTempl : public KernelBase {
+ KnInterpolateGrid4dTempl(Grid4d<S> &target,
+ Grid4d<S> &source,
+ const Vec4 &sourceFactor,
+ Vec4 offset)
+ : KernelBase(&target, 0),
+ target(target),
+ source(source),
+ sourceFactor(sourceFactor),
+ offset(offset)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ int t,
+ Grid4d<S> &target,
+ Grid4d<S> &source,
+ const Vec4 &sourceFactor,
+ Vec4 offset) const
+ {
+ Vec4 pos = Vec4(i, j, k, t) * sourceFactor + offset;
+ if (!source.is3D())
+ pos[2] = 0.; // allow 2d -> 3d
+ if (!source.is4D())
+ pos[3] = 0.; // allow 3d -> 4d
+ target(i, j, k, t) = source.getInterpolated(pos);
+ }
+ inline Grid4d<S> &getArg0()
+ {
+ return target;
+ }
+ typedef Grid4d<S> type0;
+ inline Grid4d<S> &getArg1()
+ {
+ return source;
+ }
+ typedef Grid4d<S> type1;
+ inline const Vec4 &getArg2()
+ {
+ return sourceFactor;
+ }
+ typedef Vec4 type2;
+ inline Vec4 &getArg3()
+ {
+ return offset;
+ }
+ typedef Vec4 type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnInterpolateGrid4dTempl ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ
+ << " "
+ " t "
+ << minT << " - " << maxT,
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ if (maxT > 1) {
+ for (int t = __r.begin(); t != (int)__r.end(); t++)
+ for (int k = 0; k < maxZ; k++)
+ for (int j = 0; j < maxY; j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, target, source, sourceFactor, offset);
+ }
+ else if (maxZ > 1) {
+ const int t = 0;
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < maxY; j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, target, source, sourceFactor, offset);
+ }
+ else {
+ const int t = 0;
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < maxX; i++)
+ op(i, j, k, t, target, source, sourceFactor, offset);
+ }
+ }
+ void run()
+ {
+ if (maxT > 1) {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minT, maxT), *this);
+ }
+ else if (maxZ > 1) {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ }
+ else {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ }
+ Grid4d<S> &target;
+ Grid4d<S> &source;
+ const Vec4 &sourceFactor;
+ Vec4 offset;
+};
+
+} // namespace Manta
+#endif
diff --git a/extern/mantaflow/preprocessed/grid4d.h.reg.cpp b/extern/mantaflow/preprocessed/grid4d.h.reg.cpp
new file mode 100644
index 00000000000..7e490221ee6
--- /dev/null
+++ b/extern/mantaflow/preprocessed/grid4d.h.reg.cpp
@@ -0,0 +1,204 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "grid4d.h"
+namespace Manta {
+#ifdef _C_Grid4d
+static const Pb::Register _R_12("Grid4d<int>", "Grid4d<int>", "Grid4dBase");
+template<> const char *Namify<Grid4d<int>>::S = "Grid4d<int>";
+static const Pb::Register _R_13("Grid4d<int>", "Grid4d", Grid4d<int>::_W_8);
+static const Pb::Register _R_14("Grid4d<int>", "save", Grid4d<int>::_W_9);
+static const Pb::Register _R_15("Grid4d<int>", "load", Grid4d<int>::_W_10);
+static const Pb::Register _R_16("Grid4d<int>", "clear", Grid4d<int>::_W_11);
+static const Pb::Register _R_17("Grid4d<int>", "copyFrom", Grid4d<int>::_W_12);
+static const Pb::Register _R_18("Grid4d<int>", "add", Grid4d<int>::_W_13);
+static const Pb::Register _R_19("Grid4d<int>", "sub", Grid4d<int>::_W_14);
+static const Pb::Register _R_20("Grid4d<int>", "setConst", Grid4d<int>::_W_15);
+static const Pb::Register _R_21("Grid4d<int>", "addConst", Grid4d<int>::_W_16);
+static const Pb::Register _R_22("Grid4d<int>", "addScaled", Grid4d<int>::_W_17);
+static const Pb::Register _R_23("Grid4d<int>", "mult", Grid4d<int>::_W_18);
+static const Pb::Register _R_24("Grid4d<int>", "multConst", Grid4d<int>::_W_19);
+static const Pb::Register _R_25("Grid4d<int>", "clamp", Grid4d<int>::_W_20);
+static const Pb::Register _R_26("Grid4d<int>", "getMaxAbs", Grid4d<int>::_W_21);
+static const Pb::Register _R_27("Grid4d<int>", "getMax", Grid4d<int>::_W_22);
+static const Pb::Register _R_28("Grid4d<int>", "getMin", Grid4d<int>::_W_23);
+static const Pb::Register _R_29("Grid4d<int>", "setBound", Grid4d<int>::_W_24);
+static const Pb::Register _R_30("Grid4d<int>", "setBoundNeumann", Grid4d<int>::_W_25);
+static const Pb::Register _R_31("Grid4d<int>", "printGrid", Grid4d<int>::_W_26);
+static const Pb::Register _R_32("Grid4d<Real>", "Grid4d<Real>", "Grid4dBase");
+template<> const char *Namify<Grid4d<Real>>::S = "Grid4d<Real>";
+static const Pb::Register _R_33("Grid4d<Real>", "Grid4d", Grid4d<Real>::_W_8);
+static const Pb::Register _R_34("Grid4d<Real>", "save", Grid4d<Real>::_W_9);
+static const Pb::Register _R_35("Grid4d<Real>", "load", Grid4d<Real>::_W_10);
+static const Pb::Register _R_36("Grid4d<Real>", "clear", Grid4d<Real>::_W_11);
+static const Pb::Register _R_37("Grid4d<Real>", "copyFrom", Grid4d<Real>::_W_12);
+static const Pb::Register _R_38("Grid4d<Real>", "add", Grid4d<Real>::_W_13);
+static const Pb::Register _R_39("Grid4d<Real>", "sub", Grid4d<Real>::_W_14);
+static const Pb::Register _R_40("Grid4d<Real>", "setConst", Grid4d<Real>::_W_15);
+static const Pb::Register _R_41("Grid4d<Real>", "addConst", Grid4d<Real>::_W_16);
+static const Pb::Register _R_42("Grid4d<Real>", "addScaled", Grid4d<Real>::_W_17);
+static const Pb::Register _R_43("Grid4d<Real>", "mult", Grid4d<Real>::_W_18);
+static const Pb::Register _R_44("Grid4d<Real>", "multConst", Grid4d<Real>::_W_19);
+static const Pb::Register _R_45("Grid4d<Real>", "clamp", Grid4d<Real>::_W_20);
+static const Pb::Register _R_46("Grid4d<Real>", "getMaxAbs", Grid4d<Real>::_W_21);
+static const Pb::Register _R_47("Grid4d<Real>", "getMax", Grid4d<Real>::_W_22);
+static const Pb::Register _R_48("Grid4d<Real>", "getMin", Grid4d<Real>::_W_23);
+static const Pb::Register _R_49("Grid4d<Real>", "setBound", Grid4d<Real>::_W_24);
+static const Pb::Register _R_50("Grid4d<Real>", "setBoundNeumann", Grid4d<Real>::_W_25);
+static const Pb::Register _R_51("Grid4d<Real>", "printGrid", Grid4d<Real>::_W_26);
+static const Pb::Register _R_52("Grid4d<Vec3>", "Grid4d<Vec3>", "Grid4dBase");
+template<> const char *Namify<Grid4d<Vec3>>::S = "Grid4d<Vec3>";
+static const Pb::Register _R_53("Grid4d<Vec3>", "Grid4d", Grid4d<Vec3>::_W_8);
+static const Pb::Register _R_54("Grid4d<Vec3>", "save", Grid4d<Vec3>::_W_9);
+static const Pb::Register _R_55("Grid4d<Vec3>", "load", Grid4d<Vec3>::_W_10);
+static const Pb::Register _R_56("Grid4d<Vec3>", "clear", Grid4d<Vec3>::_W_11);
+static const Pb::Register _R_57("Grid4d<Vec3>", "copyFrom", Grid4d<Vec3>::_W_12);
+static const Pb::Register _R_58("Grid4d<Vec3>", "add", Grid4d<Vec3>::_W_13);
+static const Pb::Register _R_59("Grid4d<Vec3>", "sub", Grid4d<Vec3>::_W_14);
+static const Pb::Register _R_60("Grid4d<Vec3>", "setConst", Grid4d<Vec3>::_W_15);
+static const Pb::Register _R_61("Grid4d<Vec3>", "addConst", Grid4d<Vec3>::_W_16);
+static const Pb::Register _R_62("Grid4d<Vec3>", "addScaled", Grid4d<Vec3>::_W_17);
+static const Pb::Register _R_63("Grid4d<Vec3>", "mult", Grid4d<Vec3>::_W_18);
+static const Pb::Register _R_64("Grid4d<Vec3>", "multConst", Grid4d<Vec3>::_W_19);
+static const Pb::Register _R_65("Grid4d<Vec3>", "clamp", Grid4d<Vec3>::_W_20);
+static const Pb::Register _R_66("Grid4d<Vec3>", "getMaxAbs", Grid4d<Vec3>::_W_21);
+static const Pb::Register _R_67("Grid4d<Vec3>", "getMax", Grid4d<Vec3>::_W_22);
+static const Pb::Register _R_68("Grid4d<Vec3>", "getMin", Grid4d<Vec3>::_W_23);
+static const Pb::Register _R_69("Grid4d<Vec3>", "setBound", Grid4d<Vec3>::_W_24);
+static const Pb::Register _R_70("Grid4d<Vec3>", "setBoundNeumann", Grid4d<Vec3>::_W_25);
+static const Pb::Register _R_71("Grid4d<Vec3>", "printGrid", Grid4d<Vec3>::_W_26);
+static const Pb::Register _R_72("Grid4d<Vec4>", "Grid4d<Vec4>", "Grid4dBase");
+template<> const char *Namify<Grid4d<Vec4>>::S = "Grid4d<Vec4>";
+static const Pb::Register _R_73("Grid4d<Vec4>", "Grid4d", Grid4d<Vec4>::_W_8);
+static const Pb::Register _R_74("Grid4d<Vec4>", "save", Grid4d<Vec4>::_W_9);
+static const Pb::Register _R_75("Grid4d<Vec4>", "load", Grid4d<Vec4>::_W_10);
+static const Pb::Register _R_76("Grid4d<Vec4>", "clear", Grid4d<Vec4>::_W_11);
+static const Pb::Register _R_77("Grid4d<Vec4>", "copyFrom", Grid4d<Vec4>::_W_12);
+static const Pb::Register _R_78("Grid4d<Vec4>", "add", Grid4d<Vec4>::_W_13);
+static const Pb::Register _R_79("Grid4d<Vec4>", "sub", Grid4d<Vec4>::_W_14);
+static const Pb::Register _R_80("Grid4d<Vec4>", "setConst", Grid4d<Vec4>::_W_15);
+static const Pb::Register _R_81("Grid4d<Vec4>", "addConst", Grid4d<Vec4>::_W_16);
+static const Pb::Register _R_82("Grid4d<Vec4>", "addScaled", Grid4d<Vec4>::_W_17);
+static const Pb::Register _R_83("Grid4d<Vec4>", "mult", Grid4d<Vec4>::_W_18);
+static const Pb::Register _R_84("Grid4d<Vec4>", "multConst", Grid4d<Vec4>::_W_19);
+static const Pb::Register _R_85("Grid4d<Vec4>", "clamp", Grid4d<Vec4>::_W_20);
+static const Pb::Register _R_86("Grid4d<Vec4>", "getMaxAbs", Grid4d<Vec4>::_W_21);
+static const Pb::Register _R_87("Grid4d<Vec4>", "getMax", Grid4d<Vec4>::_W_22);
+static const Pb::Register _R_88("Grid4d<Vec4>", "getMin", Grid4d<Vec4>::_W_23);
+static const Pb::Register _R_89("Grid4d<Vec4>", "setBound", Grid4d<Vec4>::_W_24);
+static const Pb::Register _R_90("Grid4d<Vec4>", "setBoundNeumann", Grid4d<Vec4>::_W_25);
+static const Pb::Register _R_91("Grid4d<Vec4>", "printGrid", Grid4d<Vec4>::_W_26);
+#endif
+#ifdef _C_Grid4dBase
+static const Pb::Register _R_92("Grid4dBase", "Grid4dBase", "PbClass");
+template<> const char *Namify<Grid4dBase>::S = "Grid4dBase";
+static const Pb::Register _R_93("Grid4dBase", "Grid4dBase", Grid4dBase::_W_0);
+static const Pb::Register _R_94("Grid4dBase", "getSizeX", Grid4dBase::_W_1);
+static const Pb::Register _R_95("Grid4dBase", "getSizeY", Grid4dBase::_W_2);
+static const Pb::Register _R_96("Grid4dBase", "getSizeZ", Grid4dBase::_W_3);
+static const Pb::Register _R_97("Grid4dBase", "getSizeT", Grid4dBase::_W_4);
+static const Pb::Register _R_98("Grid4dBase", "getSize", Grid4dBase::_W_5);
+static const Pb::Register _R_99("Grid4dBase", "is3D", Grid4dBase::_W_6);
+static const Pb::Register _R_100("Grid4dBase", "is4D", Grid4dBase::_W_7);
+#endif
+static const Pb::Register _R_8("Grid4d<int>", "Grid4Int", "");
+static const Pb::Register _R_9("Grid4d<Real>", "Grid4Real", "");
+static const Pb::Register _R_10("Grid4d<Vec3>", "Grid4Vec3", "");
+static const Pb::Register _R_11("Grid4d<Vec4>", "Grid4Vec4", "");
+extern "C" {
+void PbRegister_file_8()
+{
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/kernel.cpp b/extern/mantaflow/preprocessed/kernel.cpp
new file mode 100644
index 00000000000..72a5efff795
--- /dev/null
+++ b/extern/mantaflow/preprocessed/kernel.cpp
@@ -0,0 +1,61 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Function and macros for defining compution kernels over grids
+ *
+ ******************************************************************************/
+
+#include "kernel.h"
+#include "grid.h"
+#include "grid4d.h"
+#include "particle.h"
+
+namespace Manta {
+
+KernelBase::KernelBase(const GridBase *base, int bnd)
+ : maxX(base->getSizeX() - bnd),
+ maxY(base->getSizeY() - bnd),
+ maxZ(base->is3D() ? (base->getSizeZ() - bnd) : 1),
+ minZ(base->is3D() ? bnd : 0),
+ maxT(1),
+ minT(0),
+ X(base->getStrideX()),
+ Y(base->getStrideY()),
+ Z(base->getStrideZ()),
+ dimT(0),
+ size(base->getSizeX() * base->getSizeY() * (IndexInt)base->getSizeZ())
+{
+}
+
+KernelBase::KernelBase(IndexInt num)
+ : maxX(0), maxY(0), maxZ(0), minZ(0), maxT(0), X(0), Y(0), Z(0), dimT(0), size(num)
+{
+}
+
+KernelBase::KernelBase(const Grid4dBase *base, int bnd)
+ : maxX(base->getSizeX() - bnd),
+ maxY(base->getSizeY() - bnd),
+ maxZ(base->getSizeZ() - bnd),
+ minZ(bnd),
+ maxT(base->getSizeT() - bnd),
+ minT(bnd),
+ X(base->getStrideX()),
+ Y(base->getStrideY()),
+ Z(base->getStrideZ()),
+ dimT(base->getStrideT()),
+ size(base->getSizeX() * base->getSizeY() * base->getSizeZ() * (IndexInt)base->getSizeT())
+{
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/kernel.h b/extern/mantaflow/preprocessed/kernel.h
new file mode 100644
index 00000000000..90e30cd21e1
--- /dev/null
+++ b/extern/mantaflow/preprocessed/kernel.h
@@ -0,0 +1,99 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Function and macros for defining compution kernels over grids
+ *
+ ******************************************************************************/
+
+#ifndef _KERNEL_H
+#define _KERNEL_H
+
+#if TBB == 1
+# include <tbb/blocked_range3d.h>
+# include <tbb/blocked_range.h>
+# include <tbb/parallel_for.h>
+# include <tbb/parallel_reduce.h>
+#endif
+
+#if OPENMP == 1
+# include <omp.h>
+#endif
+
+#include "general.h"
+
+namespace Manta {
+
+// fwd decl
+class GridBase;
+class Grid4dBase;
+class ParticleBase;
+
+// simple iteration
+#define FOR_IJK_BND(grid, bnd) \
+ for (int k = ((grid).is3D() ? bnd : 0), \
+ __kmax = ((grid).is3D() ? ((grid).getSizeZ() - bnd) : 1); \
+ k < __kmax; \
+ k++) \
+ for (int j = bnd; j < (grid).getSizeY() - bnd; j++) \
+ for (int i = bnd; i < (grid).getSizeX() - bnd; i++)
+
+#define FOR_IJK_REVERSE(grid) \
+ for (int k = (grid).getSizeZ() - 1; k >= 0; k--) \
+ for (int j = (grid).getSizeY() - 1; j >= 0; j--) \
+ for (int i = (grid).getSizeX() - 1; i >= 0; i--)
+
+#define FOR_IDX(grid) \
+ for (IndexInt idx = 0, total = (grid).getSizeX() * (grid).getSizeY() * (grid).getSizeZ(); \
+ idx < total; \
+ idx++)
+
+#define FOR_IJK(grid) FOR_IJK_BND(grid, 0)
+
+#define FOR_PARTS(parts) for (IndexInt idx = 0, total = (parts).size(); idx < total; idx++)
+
+// simple loop over 4d grids
+#define FOR_IJKT_BND(grid, bnd) \
+ for (int t = ((grid).is4D() ? bnd : 0); t < ((grid).is4D() ? ((grid).getSizeT() - bnd) : 1); \
+ ++t) \
+ for (int k = ((grid).is3D() ? bnd : 0); k < ((grid).is3D() ? ((grid).getSizeZ() - bnd) : 1); \
+ ++k) \
+ for (int j = bnd; j < (grid).getSizeY() - bnd; ++j) \
+ for (int i = bnd; i < (grid).getSizeX() - bnd; ++i)
+
+//! Basic data structure for kernel data, initialized based on kernel type (e.g. single, idx, etc).
+struct KernelBase {
+ int maxX, maxY, maxZ, minZ, maxT, minT;
+ int X, Y, Z, dimT;
+ IndexInt size;
+
+ KernelBase(IndexInt num);
+ KernelBase(const GridBase *base, int bnd);
+ KernelBase(const Grid4dBase *base, int bnd);
+
+ // specify in your derived classes:
+
+ // kernel operators
+ // ijk mode: void operator() (int i, int j, int k)
+ // idx mode: void operator() (IndexInt idx)
+
+ // reduce mode:
+ // void join(classname& other)
+ // void setup()
+};
+
+} // namespace Manta
+
+// all kernels will automatically be added to the "Kernels" group in doxygen
+
+#endif
diff --git a/extern/mantaflow/preprocessed/kernel.h.reg.cpp b/extern/mantaflow/preprocessed/kernel.h.reg.cpp
new file mode 100644
index 00000000000..002396024ea
--- /dev/null
+++ b/extern/mantaflow/preprocessed/kernel.h.reg.cpp
@@ -0,0 +1,13 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "kernel.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_15()
+{
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/levelset.cpp b/extern/mantaflow/preprocessed/levelset.cpp
new file mode 100644
index 00000000000..dcc10718d71
--- /dev/null
+++ b/extern/mantaflow/preprocessed/levelset.cpp
@@ -0,0 +1,876 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Levelset
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "fastmarch.h"
+#include "kernel.h"
+#include "mcubes.h"
+#include "mesh.h"
+#include <stack>
+
+using namespace std;
+namespace Manta {
+
+//************************************************************************
+// Helper functions and kernels for marching
+
+static const int FlagInited = FastMarch<FmHeapEntryOut, +1>::FlagInited;
+
+// neighbor lookup vectors
+static const Vec3i neighbors[6] = {Vec3i(-1, 0, 0),
+ Vec3i(1, 0, 0),
+ Vec3i(0, -1, 0),
+ Vec3i(0, 1, 0),
+ Vec3i(0, 0, -1),
+ Vec3i(0, 0, 1)};
+
+struct InitFmIn : public KernelBase {
+ InitFmIn(const FlagGrid &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ bool ignoreWalls,
+ int obstacleType)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ fmFlags(fmFlags),
+ phi(phi),
+ ignoreWalls(ignoreWalls),
+ obstacleType(obstacleType)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ bool ignoreWalls,
+ int obstacleType) const
+ {
+ const IndexInt idx = flags.index(i, j, k);
+ const Real v = phi[idx];
+ if (ignoreWalls) {
+ if (v >= 0. && ((flags[idx] & obstacleType) == 0))
+ fmFlags[idx] = FlagInited;
+ else
+ fmFlags[idx] = 0;
+ }
+ else {
+ if (v >= 0)
+ fmFlags[idx] = FlagInited;
+ else
+ fmFlags[idx] = 0;
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<int> &getArg1()
+ {
+ return fmFlags;
+ }
+ typedef Grid<int> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type2;
+ inline bool &getArg3()
+ {
+ return ignoreWalls;
+ }
+ typedef bool type3;
+ inline int &getArg4()
+ {
+ return obstacleType;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel InitFmIn ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, ignoreWalls, obstacleType);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, ignoreWalls, obstacleType);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<int> &fmFlags;
+ Grid<Real> &phi;
+ bool ignoreWalls;
+ int obstacleType;
+};
+
+struct InitFmOut : public KernelBase {
+ InitFmOut(const FlagGrid &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ bool ignoreWalls,
+ int obstacleType)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ fmFlags(fmFlags),
+ phi(phi),
+ ignoreWalls(ignoreWalls),
+ obstacleType(obstacleType)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ bool ignoreWalls,
+ int obstacleType) const
+ {
+ const IndexInt idx = flags.index(i, j, k);
+ const Real v = phi[idx];
+ if (ignoreWalls) {
+ fmFlags[idx] = (v < 0) ? FlagInited : 0;
+ if ((flags[idx] & obstacleType) != 0) {
+ fmFlags[idx] = 0;
+ phi[idx] = 0;
+ }
+ }
+ else {
+ fmFlags[idx] = (v < 0) ? FlagInited : 0;
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<int> &getArg1()
+ {
+ return fmFlags;
+ }
+ typedef Grid<int> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type2;
+ inline bool &getArg3()
+ {
+ return ignoreWalls;
+ }
+ typedef bool type3;
+ inline int &getArg4()
+ {
+ return obstacleType;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel InitFmOut ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, ignoreWalls, obstacleType);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, ignoreWalls, obstacleType);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<int> &fmFlags;
+ Grid<Real> &phi;
+ bool ignoreWalls;
+ int obstacleType;
+};
+
+struct SetUninitialized : public KernelBase {
+ SetUninitialized(const Grid<int> &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ const Real val,
+ int ignoreWalls,
+ int obstacleType)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ fmFlags(fmFlags),
+ phi(phi),
+ val(val),
+ ignoreWalls(ignoreWalls),
+ obstacleType(obstacleType)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const Grid<int> &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ const Real val,
+ int ignoreWalls,
+ int obstacleType) const
+ {
+ if (ignoreWalls) {
+ if ((fmFlags(i, j, k) != FlagInited) && ((flags(i, j, k) & obstacleType) == 0)) {
+ phi(i, j, k) = val;
+ }
+ }
+ else {
+ if ((fmFlags(i, j, k) != FlagInited))
+ phi(i, j, k) = val;
+ }
+ }
+ inline const Grid<int> &getArg0()
+ {
+ return flags;
+ }
+ typedef Grid<int> type0;
+ inline Grid<int> &getArg1()
+ {
+ return fmFlags;
+ }
+ typedef Grid<int> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type2;
+ inline const Real &getArg3()
+ {
+ return val;
+ }
+ typedef Real type3;
+ inline int &getArg4()
+ {
+ return ignoreWalls;
+ }
+ typedef int type4;
+ inline int &getArg5()
+ {
+ return obstacleType;
+ }
+ typedef int type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel SetUninitialized ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, val, ignoreWalls, obstacleType);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, val, ignoreWalls, obstacleType);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const Grid<int> &flags;
+ Grid<int> &fmFlags;
+ Grid<Real> &phi;
+ const Real val;
+ int ignoreWalls;
+ int obstacleType;
+};
+
+template<bool inward>
+inline bool isAtInterface(const Grid<int> &fmFlags, Grid<Real> &phi, const Vec3i &p)
+{
+ // check for interface
+ int max = phi.is3D() ? 6 : 4;
+ for (int nb = 0; nb < max; nb++) {
+ const Vec3i pn(p + neighbors[nb]);
+ if (!fmFlags.isInBounds(pn))
+ continue;
+
+ if (fmFlags(pn) != FlagInited)
+ continue;
+ if ((inward && phi(pn) >= 0.) || (!inward && phi(pn) < 0.))
+ return true;
+ }
+ return false;
+}
+
+//************************************************************************
+// Levelset class def
+
+LevelsetGrid::LevelsetGrid(FluidSolver *parent, bool show) : Grid<Real>(parent, show)
+{
+ mType = (GridType)(TypeLevelset | TypeReal);
+}
+
+LevelsetGrid::LevelsetGrid(FluidSolver *parent, Real *data, bool show)
+ : Grid<Real>(parent, data, show)
+{
+ mType = (GridType)(TypeLevelset | TypeReal);
+}
+
+Real LevelsetGrid::invalidTimeValue()
+{
+ return FastMarch<FmHeapEntryOut, 1>::InvalidTime();
+}
+
+//! Kernel: perform levelset union
+struct KnJoin : public KernelBase {
+ KnJoin(Grid<Real> &a, const Grid<Real> &b) : KernelBase(&a, 0), a(a), b(b)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<Real> &a, const Grid<Real> &b) const
+ {
+ a[idx] = min(a[idx], b[idx]);
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return a;
+ }
+ typedef Grid<Real> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return b;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnJoin ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, a, b);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Real> &a;
+ const Grid<Real> &b;
+};
+void LevelsetGrid::join(const LevelsetGrid &o)
+{
+ KnJoin(*this, o);
+}
+
+//! subtract b, note does not preserve SDF!
+struct KnSubtract : public KernelBase {
+ KnSubtract(Grid<Real> &a, const Grid<Real> &b, const FlagGrid *flags, int subtractType)
+ : KernelBase(&a, 0), a(a), b(b), flags(flags), subtractType(subtractType)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ Grid<Real> &a,
+ const Grid<Real> &b,
+ const FlagGrid *flags,
+ int subtractType) const
+ {
+ if (flags && ((*flags)(idx)&subtractType) == 0)
+ return;
+ if (b[idx] < 0.)
+ a[idx] = b[idx] * -1.;
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return a;
+ }
+ typedef Grid<Real> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return b;
+ }
+ typedef Grid<Real> type1;
+ inline const FlagGrid *getArg2()
+ {
+ return flags;
+ }
+ typedef FlagGrid type2;
+ inline int &getArg3()
+ {
+ return subtractType;
+ }
+ typedef int type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnSubtract ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, a, b, flags, subtractType);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Real> &a;
+ const Grid<Real> &b;
+ const FlagGrid *flags;
+ int subtractType;
+};
+void LevelsetGrid::subtract(const LevelsetGrid &o, const FlagGrid *flags, const int subtractType)
+{
+ KnSubtract(*this, o, flags, subtractType);
+}
+
+//! re-init levelset and extrapolate velocities (in & out)
+// note - uses flags to identify border (could also be done based on ls values)
+static void doReinitMarch(Grid<Real> &phi,
+ const FlagGrid &flags,
+ Real maxTime,
+ MACGrid *velTransport,
+ bool ignoreWalls,
+ bool correctOuterLayer,
+ int obstacleType)
+{
+ const int dim = (phi.is3D() ? 3 : 2);
+ Grid<int> fmFlags(phi.getParent());
+
+ FastMarch<FmHeapEntryIn, -1> marchIn(flags, fmFlags, phi, maxTime, NULL);
+
+ // march inside
+ InitFmIn(flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FOR_IJK_BND(flags, 1)
+ {
+ if (fmFlags(i, j, k) == FlagInited)
+ continue;
+ if (ignoreWalls && ((flags(i, j, k) & obstacleType) != 0))
+ continue;
+ const Vec3i p(i, j, k);
+
+ if (isAtInterface<true>(fmFlags, phi, p)) {
+ // set value
+ fmFlags(p) = FlagInited;
+
+ // add neighbors that are not at the interface
+ for (int nb = 0; nb < 2 * dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+ if (ignoreWalls && ((flags.get(pn) & obstacleType) != 0))
+ continue;
+
+ // check neighbors of neighbor
+ if (phi(pn) < 0. && !isAtInterface<true>(fmFlags, phi, pn)) {
+ marchIn.addToList(pn, p);
+ }
+ }
+ }
+ }
+ marchIn.performMarching();
+ // done with inwards marching
+
+ // now march out...
+
+ // set un initialized regions
+ SetUninitialized(flags, fmFlags, phi, -maxTime - 1., ignoreWalls, obstacleType);
+
+ InitFmOut(flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FastMarch<FmHeapEntryOut, +1> marchOut(flags, fmFlags, phi, maxTime, velTransport);
+
+ // by default, correctOuterLayer is on
+ if (correctOuterLayer) {
+ // normal version, inwards march is done, now add all outside values (0..2] to list
+ // note, this might move the interface a bit! but keeps a nice signed distance field...
+ FOR_IJK_BND(flags, 1)
+ {
+ if (ignoreWalls && ((flags(i, j, k) & obstacleType) != 0))
+ continue;
+ const Vec3i p(i, j, k);
+
+ // check nbs
+ for (int nb = 0; nb < 2 * dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+
+ if (fmFlags(pn) != FlagInited)
+ continue;
+ if (ignoreWalls && ((flags.get(pn) & obstacleType)) != 0)
+ continue;
+
+ const Real nbPhi = phi(pn);
+
+ // only add nodes near interface, not e.g. outer boundary vs. invalid region
+ if (nbPhi < 0 && nbPhi >= -2)
+ marchOut.addToList(p, pn);
+ }
+ }
+ }
+ else {
+ // alternative version, keep interface, do not distort outer cells
+ // add all ouside values, but not those at the IF layer
+ FOR_IJK_BND(flags, 1)
+ {
+ if (ignoreWalls && ((flags(i, j, k) & obstacleType) != 0))
+ continue;
+
+ // only look at ouside values
+ const Vec3i p(i, j, k);
+ if (phi(p) < 0)
+ continue;
+
+ if (isAtInterface<false>(fmFlags, phi, p)) {
+ // now add all non, interface neighbors
+ fmFlags(p) = FlagInited;
+
+ // add neighbors that are not at the interface
+ for (int nb = 0; nb < 2 * dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+ if (ignoreWalls && ((flags.get(pn) & obstacleType) != 0))
+ continue;
+
+ // check neighbors of neighbor
+ if (phi(pn) > 0. && !isAtInterface<false>(fmFlags, phi, pn)) {
+ marchOut.addToList(pn, p);
+ }
+ }
+ }
+ }
+ }
+ marchOut.performMarching();
+
+ // set un initialized regions
+ SetUninitialized(flags, fmFlags, phi, +maxTime + 1., ignoreWalls, obstacleType);
+}
+
+//! call for levelset grids & external real grids
+
+void LevelsetGrid::reinitMarching(const FlagGrid &flags,
+ Real maxTime,
+ MACGrid *velTransport,
+ bool ignoreWalls,
+ bool correctOuterLayer,
+ int obstacleType)
+{
+ doReinitMarch(*this, flags, maxTime, velTransport, ignoreWalls, correctOuterLayer, obstacleType);
+}
+
+void LevelsetGrid::initFromFlags(const FlagGrid &flags, bool ignoreWalls)
+{
+ FOR_IDX(*this)
+ {
+ if (flags.isFluid(idx) || (ignoreWalls && flags.isObstacle(idx)))
+ mData[idx] = -0.5;
+ else
+ mData[idx] = 0.5;
+ }
+}
+
+void LevelsetGrid::fillHoles(int maxDepth, int boundaryWidth)
+{
+ Real curVal, i1, i2, j1, j2, k1, k2;
+ Vec3i c, cTmp;
+ std::stack<Vec3i> undoPos;
+ std::stack<Real> undoVal;
+ std::stack<Vec3i> todoPos;
+
+ FOR_IJK_BND(*this, boundaryWidth)
+ {
+
+ curVal = mData[index(i, j, k)];
+ i1 = mData[index(i - 1, j, k)];
+ i2 = mData[index(i + 1, j, k)];
+ j1 = mData[index(i, j - 1, k)];
+ j2 = mData[index(i, j + 1, k)];
+ k1 = mData[index(i, j, k - 1)];
+ k2 = mData[index(i, j, k + 1)];
+
+ /* Skip cells inside and cells outside with no inside neighbours early */
+ if (curVal < 0.)
+ continue;
+ if (curVal > 0. && i1 > 0. && i2 > 0. && j1 > 0. && j2 > 0. && k1 > 0. && k2 > 0.)
+ continue;
+
+ /* Cell at c is positive (outside) and has at least one negative (inside) neighbour cell */
+ c = Vec3i(i, j, k);
+
+ /* Current cell is outside and has inside neighbour(s) */
+ undoPos.push(c);
+ undoVal.push(curVal);
+ todoPos.push(c);
+
+ /* Enforce negative cell - if search depth gets exceeded this will be reverted to the original
+ * value */
+ mData[index(c.x, c.y, c.z)] = -0.5;
+
+ while (!todoPos.empty()) {
+ todoPos.pop();
+
+ /* Add neighbouring positive (inside) cells to stacks and set negavtive cell value */
+ if (c.x > 0 && mData[index(c.x - 1, c.y, c.z)] > 0.) {
+ cTmp = Vec3i(c.x - 1, c.y, c.z);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+ if (c.y > 0 && mData[index(c.x, c.y - 1, c.z)] > 0.) {
+ cTmp = Vec3i(c.x, c.y - 1, c.z);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+ if (c.z > 0 && mData[index(c.x, c.y, c.z - 1)] > 0.) {
+ cTmp = Vec3i(c.x, c.y, c.z - 1);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+ if (c.x < (*this).getSizeX() - 1 && mData[index(c.x + 1, c.y, c.z)] > 0.) {
+ cTmp = Vec3i(c.x + 1, c.y, c.z);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+ if (c.y < (*this).getSizeY() - 1 && mData[index(c.x, c.y + 1, c.z)] > 0.) {
+ cTmp = Vec3i(c.x, c.y + 1, c.z);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+ if (c.z < (*this).getSizeZ() - 1 && mData[index(c.x, c.y, c.z + 1)] > 0.) {
+ cTmp = Vec3i(c.x, c.y, c.z + 1);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+
+ /* Restore original value in cells if undo needed ie once cell undo count exceeds given limit
+ */
+ if (undoPos.size() > maxDepth) {
+ /* Clear todo stack */
+ while (!todoPos.empty()) {
+ todoPos.pop();
+ }
+ /* Clear undo stack and revert value */
+ while (!undoPos.empty()) {
+ c = undoPos.top();
+ curVal = undoVal.top();
+ undoPos.pop();
+ undoVal.pop();
+ mData[index(c.x, c.y, c.z)] = curVal;
+ }
+ break;
+ }
+
+ /* Ensure that undo stack is cleared at the end if no more items in todo stack left */
+ if (todoPos.empty()) {
+ while (!undoPos.empty()) {
+ undoPos.pop();
+ }
+ while (!undoVal.empty()) {
+ undoVal.pop();
+ }
+ }
+ /* Pop value for next while iteration */
+ else {
+ c = todoPos.top();
+ }
+ }
+ }
+}
+
+//! run marching cubes to create a mesh for the 0-levelset
+void LevelsetGrid::createMesh(Mesh &mesh)
+{
+ assertMsg(is3D(), "Only 3D grids supported so far");
+
+ mesh.clear();
+
+ const Real invalidTime = invalidTimeValue();
+ const Real isoValue = 1e-4;
+
+ // create some temp grids
+ Grid<int> edgeVX(mParent);
+ Grid<int> edgeVY(mParent);
+ Grid<int> edgeVZ(mParent);
+
+ for (int i = 0; i < mSize.x - 1; i++)
+ for (int j = 0; j < mSize.y - 1; j++)
+ for (int k = 0; k < mSize.z - 1; k++) {
+ Real value[8] = {get(i, j, k),
+ get(i + 1, j, k),
+ get(i + 1, j + 1, k),
+ get(i, j + 1, k),
+ get(i, j, k + 1),
+ get(i + 1, j, k + 1),
+ get(i + 1, j + 1, k + 1),
+ get(i, j + 1, k + 1)};
+
+ // build lookup index, check for invalid times
+ bool skip = false;
+ int cubeIdx = 0;
+ for (int l = 0; l < 8; l++) {
+ value[l] *= -1;
+ if (-value[l] <= invalidTime)
+ skip = true;
+ if (value[l] < isoValue)
+ cubeIdx |= 1 << l;
+ }
+ if (skip || (mcEdgeTable[cubeIdx] == 0))
+ continue;
+
+ // where to look up if this point already exists
+ int triIndices[12];
+ int *eVert[12] = {&edgeVX(i, j, k),
+ &edgeVY(i + 1, j, k),
+ &edgeVX(i, j + 1, k),
+ &edgeVY(i, j, k),
+ &edgeVX(i, j, k + 1),
+ &edgeVY(i + 1, j, k + 1),
+ &edgeVX(i, j + 1, k + 1),
+ &edgeVY(i, j, k + 1),
+ &edgeVZ(i, j, k),
+ &edgeVZ(i + 1, j, k),
+ &edgeVZ(i + 1, j + 1, k),
+ &edgeVZ(i, j + 1, k)};
+
+ const Vec3 pos[9] = {Vec3(i, j, k),
+ Vec3(i + 1, j, k),
+ Vec3(i + 1, j + 1, k),
+ Vec3(i, j + 1, k),
+ Vec3(i, j, k + 1),
+ Vec3(i + 1, j, k + 1),
+ Vec3(i + 1, j + 1, k + 1),
+ Vec3(i, j + 1, k + 1)};
+
+ for (int e = 0; e < 12; e++) {
+ if (mcEdgeTable[cubeIdx] & (1 << e)) {
+ // vertex already calculated ?
+ if (*eVert[e] == 0) {
+ // interpolate edge
+ const int e1 = mcEdges[e * 2];
+ const int e2 = mcEdges[e * 2 + 1];
+ const Vec3 p1 = pos[e1]; // scalar field pos 1
+ const Vec3 p2 = pos[e2]; // scalar field pos 2
+ const float valp1 = value[e1]; // scalar field val 1
+ const float valp2 = value[e2]; // scalar field val 2
+ const float mu = (isoValue - valp1) / (valp2 - valp1);
+
+ // init isolevel vertex
+ Node vertex;
+ vertex.pos = p1 + (p2 - p1) * mu + Vec3(Real(0.5));
+ vertex.normal = getNormalized(
+ getGradient(
+ *this, i + cubieOffsetX[e1], j + cubieOffsetY[e1], k + cubieOffsetZ[e1]) *
+ (1.0 - mu) +
+ getGradient(
+ *this, i + cubieOffsetX[e2], j + cubieOffsetY[e2], k + cubieOffsetZ[e2]) *
+ (mu));
+
+ triIndices[e] = mesh.addNode(vertex) + 1;
+
+ // store vertex
+ *eVert[e] = triIndices[e];
+ }
+ else {
+ // retrieve from vert array
+ triIndices[e] = *eVert[e];
+ }
+ }
+ }
+
+ // Create the triangles...
+ for (int e = 0; mcTriTable[cubeIdx][e] != -1; e += 3) {
+ mesh.addTri(Triangle(triIndices[mcTriTable[cubeIdx][e + 0]] - 1,
+ triIndices[mcTriTable[cubeIdx][e + 1]] - 1,
+ triIndices[mcTriTable[cubeIdx][e + 2]] - 1));
+ }
+ }
+
+ // mesh.rebuildCorners();
+ // mesh.rebuildLookup();
+
+ // Update mdata fields
+ mesh.updateDataFields();
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/levelset.h b/extern/mantaflow/preprocessed/levelset.h
new file mode 100644
index 00000000000..ab36ac24903
--- /dev/null
+++ b/extern/mantaflow/preprocessed/levelset.h
@@ -0,0 +1,245 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Levelset
+ *
+ ******************************************************************************/
+
+#ifndef _LEVELSET_H_
+#define _LEVELSET_H_
+
+#include "grid.h"
+
+namespace Manta {
+class Mesh;
+
+//! Special function for levelsets
+class LevelsetGrid : public Grid<Real> {
+ public:
+ LevelsetGrid(FluidSolver *parent, bool show = true);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "LevelsetGrid::LevelsetGrid", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ bool show = _args.getOpt<bool>("show", 1, true, &_lock);
+ obj = new LevelsetGrid(parent, show);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "LevelsetGrid::LevelsetGrid", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("LevelsetGrid::LevelsetGrid", e.what());
+ return -1;
+ }
+ }
+
+ LevelsetGrid(FluidSolver *parent, Real *data, bool show = true);
+
+ //! reconstruct the levelset using fast marching
+
+ void reinitMarching(const FlagGrid &flags,
+ Real maxTime = 4.0,
+ MACGrid *velTransport = NULL,
+ bool ignoreWalls = false,
+ bool correctOuterLayer = true,
+ int obstacleType = FlagGrid::TypeObstacle);
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ LevelsetGrid *pbo = dynamic_cast<LevelsetGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "LevelsetGrid::reinitMarching", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Real maxTime = _args.getOpt<Real>("maxTime", 1, 4.0, &_lock);
+ MACGrid *velTransport = _args.getPtrOpt<MACGrid>("velTransport", 2, NULL, &_lock);
+ bool ignoreWalls = _args.getOpt<bool>("ignoreWalls", 3, false, &_lock);
+ bool correctOuterLayer = _args.getOpt<bool>("correctOuterLayer", 4, true, &_lock);
+ int obstacleType = _args.getOpt<int>("obstacleType", 5, FlagGrid::TypeObstacle, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->reinitMarching(
+ flags, maxTime, velTransport, ignoreWalls, correctOuterLayer, obstacleType);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "LevelsetGrid::reinitMarching", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("LevelsetGrid::reinitMarching", e.what());
+ return 0;
+ }
+ }
+
+ //! create a triangle mesh from the levelset isosurface
+ void createMesh(Mesh &mesh);
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ LevelsetGrid *pbo = dynamic_cast<LevelsetGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "LevelsetGrid::createMesh", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->createMesh(mesh);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "LevelsetGrid::createMesh", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("LevelsetGrid::createMesh", e.what());
+ return 0;
+ }
+ }
+
+ //! union with another levelset
+ void join(const LevelsetGrid &o);
+ static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ LevelsetGrid *pbo = dynamic_cast<LevelsetGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "LevelsetGrid::join", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const LevelsetGrid &o = *_args.getPtr<LevelsetGrid>("o", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->join(o);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "LevelsetGrid::join", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("LevelsetGrid::join", e.what());
+ return 0;
+ }
+ }
+
+ void subtract(const LevelsetGrid &o, const FlagGrid *flags = NULL, const int subtractType = 0);
+ static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ LevelsetGrid *pbo = dynamic_cast<LevelsetGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "LevelsetGrid::subtract", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const LevelsetGrid &o = *_args.getPtr<LevelsetGrid>("o", 0, &_lock);
+ const FlagGrid *flags = _args.getPtrOpt<FlagGrid>("flags", 1, NULL, &_lock);
+ const int subtractType = _args.getOpt<int>("subtractType", 2, 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->subtract(o, flags, subtractType);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "LevelsetGrid::subtract", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("LevelsetGrid::subtract", e.what());
+ return 0;
+ }
+ }
+
+ //! initialize levelset from flags (+/- 0.5 heaviside)
+ void initFromFlags(const FlagGrid &flags, bool ignoreWalls = false);
+ static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ LevelsetGrid *pbo = dynamic_cast<LevelsetGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "LevelsetGrid::initFromFlags", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ bool ignoreWalls = _args.getOpt<bool>("ignoreWalls", 1, false, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->initFromFlags(flags, ignoreWalls);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "LevelsetGrid::initFromFlags", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("LevelsetGrid::initFromFlags", e.what());
+ return 0;
+ }
+ }
+
+ //! fill holes (pos cells enclosed by neg ones) up to given size with -0.5 (ie not preserving
+ //! sdf)
+ void fillHoles(int maxDepth = 10, int boundaryWidth = 1);
+ static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ LevelsetGrid *pbo = dynamic_cast<LevelsetGrid *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "LevelsetGrid::fillHoles", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int maxDepth = _args.getOpt<int>("maxDepth", 0, 10, &_lock);
+ int boundaryWidth = _args.getOpt<int>("boundaryWidth", 1, 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->fillHoles(maxDepth, boundaryWidth);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "LevelsetGrid::fillHoles", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("LevelsetGrid::fillHoles", e.what());
+ return 0;
+ }
+ }
+
+ static Real invalidTimeValue();
+ public:
+ PbArgs _args;
+}
+#define _C_LevelsetGrid
+;
+
+} // namespace Manta
+#endif
diff --git a/extern/mantaflow/preprocessed/levelset.h.reg.cpp b/extern/mantaflow/preprocessed/levelset.h.reg.cpp
new file mode 100644
index 00000000000..dc6669b5da3
--- /dev/null
+++ b/extern/mantaflow/preprocessed/levelset.h.reg.cpp
@@ -0,0 +1,32 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "levelset.h"
+namespace Manta {
+#ifdef _C_LevelsetGrid
+static const Pb::Register _R_11("LevelsetGrid", "LevelsetGrid", "Grid<Real>");
+template<> const char *Namify<LevelsetGrid>::S = "LevelsetGrid";
+static const Pb::Register _R_12("LevelsetGrid", "LevelsetGrid", LevelsetGrid::_W_0);
+static const Pb::Register _R_13("LevelsetGrid", "reinitMarching", LevelsetGrid::_W_1);
+static const Pb::Register _R_14("LevelsetGrid", "createMesh", LevelsetGrid::_W_2);
+static const Pb::Register _R_15("LevelsetGrid", "join", LevelsetGrid::_W_3);
+static const Pb::Register _R_16("LevelsetGrid", "subtract", LevelsetGrid::_W_4);
+static const Pb::Register _R_17("LevelsetGrid", "initFromFlags", LevelsetGrid::_W_5);
+static const Pb::Register _R_18("LevelsetGrid", "fillHoles", LevelsetGrid::_W_6);
+#endif
+extern "C" {
+void PbRegister_file_11()
+{
+ KEEP_UNUSED(_R_11);
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/mesh.cpp b/extern/mantaflow/preprocessed/mesh.cpp
new file mode 100644
index 00000000000..d93c2ac04c0
--- /dev/null
+++ b/extern/mantaflow/preprocessed/mesh.cpp
@@ -0,0 +1,2733 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Meshes
+ *
+ * note: this is only a temporary solution, details are bound to change
+ * long term goal is integration with Split&Merge code by Wojtan et al.
+ *
+ ******************************************************************************/
+
+#include "mesh.h"
+#include "integrator.h"
+#include "mantaio.h"
+#include "kernel.h"
+#include "shapes.h"
+#include "noisefield.h"
+//#include "grid.h"
+#include <stack>
+#include <cstring>
+
+using namespace std;
+namespace Manta {
+
+Mesh::Mesh(FluidSolver *parent) : PbClass(parent)
+{
+}
+
+Mesh::~Mesh()
+{
+ for (IndexInt i = 0; i < (IndexInt)mMeshData.size(); ++i)
+ mMeshData[i]->setMesh(NULL);
+
+ if (mFreeMdata) {
+ for (IndexInt i = 0; i < (IndexInt)mMeshData.size(); ++i)
+ delete mMeshData[i];
+ }
+}
+
+Mesh *Mesh::clone()
+{
+ Mesh *nm = new Mesh(mParent);
+ *nm = *this;
+ nm->setName(getName());
+ return nm;
+}
+
+void Mesh::deregister(MeshDataBase *mdata)
+{
+ bool done = false;
+ // remove pointer from mesh data list
+ for (IndexInt i = 0; i < (IndexInt)mMeshData.size(); ++i) {
+ if (mMeshData[i] == mdata) {
+ if (i < (IndexInt)mMeshData.size() - 1)
+ mMeshData[i] = mMeshData[mMeshData.size() - 1];
+ mMeshData.pop_back();
+ done = true;
+ }
+ }
+ if (!done)
+ errMsg("Invalid pointer given, not registered!");
+}
+
+// create and attach a new mdata field to this mesh
+PbClass *Mesh::create(PbType t, PbTypeVec T, const string &name)
+{
+#if NOPYTHON != 1
+ _args.add("nocheck", true);
+ if (t.str() == "")
+ errMsg("Specify mesh data type to create");
+ // debMsg( "Mdata creating '"<< t.str <<" with size "<< this->getSizeSlow(), 5 );
+
+ PbClass *pyObj = PbClass::createPyObject(t.str() + T.str(), name, _args, this->getParent());
+
+ MeshDataBase *mdata = dynamic_cast<MeshDataBase *>(pyObj);
+ if (!mdata) {
+ errMsg(
+ "Unable to get mesh data pointer from newly created object. Only create MeshData type "
+ "with a Mesh.creat() call, eg, MdataReal, MdataVec3 etc.");
+ delete pyObj;
+ return NULL;
+ }
+ else {
+ this->registerMdata(mdata);
+ }
+
+ // directly init size of new mdata field:
+ mdata->resize(this->getSizeSlow());
+#else
+ PbClass *pyObj = NULL;
+#endif
+ return pyObj;
+}
+
+void Mesh::registerMdata(MeshDataBase *mdata)
+{
+ mdata->setMesh(this);
+ mMeshData.push_back(mdata);
+
+ if (mdata->getType() == MeshDataBase::TypeReal) {
+ MeshDataImpl<Real> *pd = dynamic_cast<MeshDataImpl<Real> *>(mdata);
+ if (!pd)
+ errMsg("Invalid mdata object posing as real!");
+ this->registerMdataReal(pd);
+ }
+ else if (mdata->getType() == MeshDataBase::TypeInt) {
+ MeshDataImpl<int> *pd = dynamic_cast<MeshDataImpl<int> *>(mdata);
+ if (!pd)
+ errMsg("Invalid mdata object posing as int!");
+ this->registerMdataInt(pd);
+ }
+ else if (mdata->getType() == MeshDataBase::TypeVec3) {
+ MeshDataImpl<Vec3> *pd = dynamic_cast<MeshDataImpl<Vec3> *>(mdata);
+ if (!pd)
+ errMsg("Invalid mdata object posing as vec3!");
+ this->registerMdataVec3(pd);
+ }
+}
+void Mesh::registerMdataReal(MeshDataImpl<Real> *pd)
+{
+ mMdataReal.push_back(pd);
+}
+void Mesh::registerMdataVec3(MeshDataImpl<Vec3> *pd)
+{
+ mMdataVec3.push_back(pd);
+}
+void Mesh::registerMdataInt(MeshDataImpl<int> *pd)
+{
+ mMdataInt.push_back(pd);
+}
+
+void Mesh::addAllMdata()
+{
+ for (IndexInt i = 0; i < (IndexInt)mMeshData.size(); ++i) {
+ mMeshData[i]->addEntry();
+ }
+}
+
+Real Mesh::computeCenterOfMass(Vec3 &cm) const
+{
+
+ // use double precision for summation, otherwise too much error accumulation
+ double vol = 0;
+ Vector3D<double> cmd(0.0);
+ for (size_t tri = 0; tri < mTris.size(); tri++) {
+ Vector3D<double> p1(toVec3d(getNode(tri, 0)));
+ Vector3D<double> p2(toVec3d(getNode(tri, 1)));
+ Vector3D<double> p3(toVec3d(getNode(tri, 2)));
+
+ double cvol = dot(cross(p1, p2), p3) / 6.0;
+ cmd += (p1 + p2 + p3) * (cvol / 4.0);
+ vol += cvol;
+ }
+ if (vol != 0.0)
+ cmd /= vol;
+
+ cm = toVec3(cmd);
+ return (Real)vol;
+}
+
+void Mesh::clear()
+{
+ mNodes.clear();
+ mTris.clear();
+ mCorners.clear();
+ m1RingLookup.clear();
+ for (size_t i = 0; i < mNodeChannels.size(); i++)
+ mNodeChannels[i]->resize(0);
+ for (size_t i = 0; i < mTriChannels.size(); i++)
+ mTriChannels[i]->resize(0);
+
+ // clear mdata fields as well
+ for (size_t i = 0; i < mMdataReal.size(); i++)
+ mMdataReal[i]->resize(0);
+ for (size_t i = 0; i < mMdataVec3.size(); i++)
+ mMdataVec3[i]->resize(0);
+ for (size_t i = 0; i < mMdataInt.size(); i++)
+ mMdataInt[i]->resize(0);
+}
+
+Mesh &Mesh::operator=(const Mesh &o)
+{
+ // wipe current data
+ clear();
+ if (mNodeChannels.size() != o.mNodeChannels.size() ||
+ mTriChannels.size() != o.mTriChannels.size())
+ errMsg("can't copy mesh, channels not identical");
+ mNodeChannels.clear();
+ mTriChannels.clear();
+
+ // copy corner, nodes, tris
+ mCorners = o.mCorners;
+ mNodes = o.mNodes;
+ mTris = o.mTris;
+ m1RingLookup = o.m1RingLookup;
+
+ // copy channels
+ for (size_t i = 0; i < mNodeChannels.size(); i++)
+ mNodeChannels[i] = o.mNodeChannels[i];
+ for (size_t i = 0; i < o.mTriChannels.size(); i++)
+ mTriChannels[i] = o.mTriChannels[i];
+
+ return *this;
+}
+
+void Mesh::load(string name, bool append)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".gz") // assume bobj gz
+ readBobjFile(name, this, append);
+ else if (ext == ".obj")
+ readObjFile(name, this, append);
+ else
+ errMsg("file '" + name + "' filetype not supported");
+
+ // dont always rebuild...
+ // rebuildCorners();
+ // rebuildLookup();
+}
+
+void Mesh::save(string name)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".obj")
+ writeObjFile(name, this);
+ else if (ext == ".gz")
+ writeBobjFile(name, this);
+ else
+ errMsg("file '" + name + "' filetype not supported");
+}
+
+void Mesh::fromShape(Shape &shape, bool append)
+{
+ if (!append)
+ clear();
+ shape.generateMesh(this);
+}
+
+void Mesh::resizeTris(int numTris)
+{
+ mTris.resize(numTris);
+ rebuildChannels();
+}
+void Mesh::resizeNodes(int numNodes)
+{
+ mNodes.resize(numNodes);
+ rebuildChannels();
+}
+
+//! do a quick check whether a rebuild is necessary, and if yes do rebuild
+void Mesh::rebuildQuickCheck()
+{
+ if (mCorners.size() != 3 * mTris.size())
+ rebuildCorners();
+ if (m1RingLookup.size() != mNodes.size())
+ rebuildLookup();
+}
+
+void Mesh::rebuildCorners(int from, int to)
+{
+ mCorners.resize(3 * mTris.size());
+ if (to < 0)
+ to = mTris.size();
+
+ // fill in basic info
+ for (int tri = from; tri < to; tri++) {
+ for (int c = 0; c < 3; c++) {
+ const int idx = tri * 3 + c;
+ mCorners[idx].tri = tri;
+ mCorners[idx].node = mTris[tri].c[c];
+ mCorners[idx].next = 3 * tri + ((c + 1) % 3);
+ mCorners[idx].prev = 3 * tri + ((c + 2) % 3);
+ mCorners[idx].opposite = -1;
+ }
+ }
+
+ // set opposite info
+ int maxc = to * 3;
+ for (int c = from * 3; c < maxc; c++) {
+ int next = mCorners[mCorners[c].next].node;
+ int prev = mCorners[mCorners[c].prev].node;
+
+ // find corner with same next/prev nodes
+ for (int c2 = c + 1; c2 < maxc; c2++) {
+ int next2 = mCorners[mCorners[c2].next].node;
+ if (next2 != next && next2 != prev)
+ continue;
+ int prev2 = mCorners[mCorners[c2].prev].node;
+ if (prev2 != next && prev2 != prev)
+ continue;
+
+ // found
+ mCorners[c].opposite = c2;
+ mCorners[c2].opposite = c;
+ break;
+ }
+ if (mCorners[c].opposite < 0) {
+ // didn't find opposite
+ errMsg("can't rebuild corners, index without an opposite");
+ }
+ }
+
+ rebuildChannels();
+}
+
+void Mesh::rebuildLookup(int from, int to)
+{
+ if (from == 0 && to < 0)
+ m1RingLookup.clear();
+ m1RingLookup.resize(mNodes.size());
+ if (to < 0)
+ to = mTris.size();
+ from *= 3;
+ to *= 3;
+ for (int i = from; i < to; i++) {
+ const int node = mCorners[i].node;
+ m1RingLookup[node].nodes.insert(mCorners[mCorners[i].next].node);
+ m1RingLookup[node].nodes.insert(mCorners[mCorners[i].prev].node);
+ m1RingLookup[node].tris.insert(mCorners[i].tri);
+ }
+}
+
+void Mesh::rebuildChannels()
+{
+ for (size_t i = 0; i < mTriChannels.size(); i++)
+ mTriChannels[i]->resize(mTris.size());
+ for (size_t i = 0; i < mNodeChannels.size(); i++)
+ mNodeChannels[i]->resize(mNodes.size());
+}
+
+struct _KnAdvectMeshInGrid : public KernelBase {
+ _KnAdvectMeshInGrid(const KernelBase &base,
+ vector<Node> &nodes,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ const Real dt,
+ vector<Vec3> &u)
+ : KernelBase(base), nodes(nodes), flags(flags), vel(vel), dt(dt), u(u)
+ {
+ }
+ inline void op(IndexInt idx,
+ vector<Node> &nodes,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ const Real dt,
+ vector<Vec3> &u) const
+ {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = 0.0;
+ else if (!flags.isInBounds(nodes[idx].pos, 1))
+ u[idx] = 0.0;
+ else
+ u[idx] = vel.getInterpolated(nodes[idx].pos) * dt;
+ }
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, nodes, flags, vel, dt, u);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ vector<Node> &nodes;
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ const Real dt;
+ vector<Vec3> &u;
+};
+struct KnAdvectMeshInGrid : public KernelBase {
+ KnAdvectMeshInGrid(vector<Node> &nodes, const FlagGrid &flags, const MACGrid &vel, const Real dt)
+ : KernelBase(nodes.size()),
+ _inner(KernelBase(nodes.size()), nodes, flags, vel, dt, u),
+ nodes(nodes),
+ flags(flags),
+ vel(vel),
+ dt(dt),
+ u((size))
+ {
+ runMessage();
+ run();
+ }
+ void run()
+ {
+ _inner.run();
+ }
+ inline operator vector<Vec3>()
+ {
+ return u;
+ }
+ inline vector<Vec3> &getRet()
+ {
+ return u;
+ }
+ inline vector<Node> &getArg0()
+ {
+ return nodes;
+ }
+ typedef vector<Node> type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return vel;
+ }
+ typedef MACGrid type2;
+ inline const Real &getArg3()
+ {
+ return dt;
+ }
+ typedef Real type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnAdvectMeshInGrid ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ _KnAdvectMeshInGrid _inner;
+ vector<Node> &nodes;
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ const Real dt;
+ vector<Vec3> u;
+};
+
+// advection plugin
+void Mesh::advectInGrid(FlagGrid &flags, MACGrid &vel, int integrationMode)
+{
+ KnAdvectMeshInGrid kernel(mNodes, flags, vel, getParent()->getDt());
+ integratePointSet(kernel, integrationMode);
+}
+
+void Mesh::scale(Vec3 s)
+{
+ for (size_t i = 0; i < mNodes.size(); i++)
+ mNodes[i].pos *= s;
+}
+
+void Mesh::offset(Vec3 o)
+{
+ for (size_t i = 0; i < mNodes.size(); i++)
+ mNodes[i].pos += o;
+}
+
+void Mesh::rotate(Vec3 thetas)
+{
+ // rotation thetas are in radians (e.g. pi is equal to 180 degrees)
+ auto rotate = [&](Real theta, unsigned int first_axis, unsigned int second_axis) {
+ if (theta == 0.0f)
+ return;
+
+ Real sin_t = sin(theta);
+ Real cos_t = cos(theta);
+
+ Real sin_sign = first_axis == 0u && second_axis == 2u ? -1.0f : 1.0f;
+ sin_t *= sin_sign;
+
+ size_t length = mNodes.size();
+ for (size_t n = 0; n < length; ++n) {
+ Vec3 &node = mNodes[n].pos;
+ Real first_axis_val = node[first_axis];
+ Real second_axis_val = node[second_axis];
+ node[first_axis] = first_axis_val * cos_t - second_axis_val * sin_t;
+ node[second_axis] = second_axis_val * cos_t + first_axis_val * sin_t;
+ }
+ };
+
+ // rotate x
+ rotate(thetas[0], 1u, 2u);
+ // rotate y
+ rotate(thetas[1], 0u, 2u);
+ // rotate z
+ rotate(thetas[2], 0u, 1u);
+}
+
+void Mesh::computeVelocity(Mesh &oldMesh, MACGrid &vel)
+{
+ // Early return if sizes do not match
+ if (oldMesh.mNodes.size() != mNodes.size())
+ return;
+
+ // temp grid
+ Grid<Vec3> veloMeanCounter(getParent());
+ veloMeanCounter.setConst(0.0f);
+
+ bool bIs2D = getParent()->is2D();
+
+ // calculate velocities from previous to current frame (per vertex)
+ for (size_t i = 0; i < mNodes.size(); ++i) {
+ // skip vertices that are not needed for 2D
+ if (bIs2D && (mNodes[i].pos.z < -0.5f || mNodes[i].pos.z > 0.5f))
+ continue;
+
+ Vec3 velo = mNodes[i].pos - oldMesh.mNodes[i].pos;
+ vel.setInterpolated(mNodes[i].pos, velo, &(veloMeanCounter[0]));
+ }
+
+ // discretize the vertex velocities by averaging them on the grid
+ vel.safeDivide(veloMeanCounter);
+}
+
+void Mesh::removeTri(int tri)
+{
+ // delete triangles by overwriting them with elements from the end of the array.
+ if (tri != (int)mTris.size() - 1) {
+ // if this is the last element, and it is marked for deletion,
+ // don't waste cycles transfering data to itself,
+ // and DEFINITELY don't transfer .opposite data to other, untainted triangles.
+
+ // old corners hold indices on the end of the corners array
+ // new corners holds indices in the new spot in the middle of the array
+ Corner *oldcorners[3];
+ Corner *newcorners[3];
+ int oldtri = mTris.size() - 1;
+ for (int c = 0; c < 3; c++) {
+ oldcorners[c] = &corners(oldtri, c);
+ newcorners[c] = &corners(tri, c);
+ }
+
+ // move the position of the triangle
+ mTris[tri] = mTris[oldtri];
+
+ // 1) update c.node, c.opposite (c.next and c.prev should be fine as they are)
+ for (int c = 0; c < 3; c++) {
+ newcorners[c]->node = mTris[tri].c[c];
+ newcorners[c]->opposite = oldcorners[c]->opposite;
+ }
+
+ // 2) c.opposite.opposite = c
+ for (int c = 0; c < 3; c++) {
+ if (newcorners[c]->opposite >= 0)
+ mCorners[newcorners[c]->opposite].opposite = 3 * tri + c;
+ }
+
+ // update tri lookup
+ for (int c = 0; c < 3; c++) {
+ int node = mTris[tri].c[c];
+ m1RingLookup[node].tris.erase(oldtri);
+ m1RingLookup[node].tris.insert(tri);
+ }
+ }
+
+ // transfer tri props
+ for (size_t p = 0; p < mTriChannels.size(); p++)
+ mTriChannels[p]->remove(tri);
+
+ // pop the triangle and corners out of the vector
+ mTris.pop_back();
+ mCorners.resize(mTris.size() * 3);
+}
+
+void Mesh::removeNodes(const vector<int> &deletedNodes)
+{
+ // After we delete the nodes that are marked for removal,
+ // the size of mNodes will be the current size - the size of the deleted array.
+ // We are going to move the elements at the end of the array
+ // (everything with an index >= newsize)
+ // to the deleted spots.
+ // We have to map all references to the last few nodes to their new locations.
+ int newsize = (int)(mNodes.size() - deletedNodes.size());
+
+ vector<int> new_index(deletedNodes.size());
+ int di, ni;
+ for (ni = 0; ni < (int)new_index.size(); ni++)
+ new_index[ni] = 0;
+ for (di = 0; di < (int)deletedNodes.size(); di++) {
+ if (deletedNodes[di] >= newsize)
+ new_index[deletedNodes[di] - newsize] = -1; // tag this node as invalid
+ }
+ for (di = 0, ni = 0; ni < (int)new_index.size(); ni++, di++) {
+ // we need to find a valid node to move
+ // we marked invalid nodes in the earlier loop with a (-1),
+ // so pick anything but those
+ while (ni < (int)new_index.size() && new_index[ni] == -1)
+ ni++;
+
+ if (ni >= (int)new_index.size())
+ break;
+
+ // next we need to find a valid spot to move the node to.
+ // we iterate through deleted[] until we find a valid spot
+ while (di < (int)new_index.size() && deletedNodes[di] >= newsize)
+ di++;
+
+ // now we assign the valid node to the valid spot
+ new_index[ni] = deletedNodes[di];
+ }
+
+ // Now we have a map of valid indices.
+ // we move node[newsize+i] to location new_index[i].
+ // We ignore the nodes with a -1 index, because they should not be moved.
+ for (int i = 0; i < (int)new_index.size(); i++) {
+ if (new_index[i] != -1)
+ mNodes[new_index[i]] = mNodes[newsize + i];
+ }
+ mNodes.resize(newsize);
+
+ // handle vertex properties
+ for (size_t i = 0; i < mNodeChannels.size(); i++)
+ mNodeChannels[i]->renumber(new_index, newsize);
+
+ // finally, we reconnect everything that used to point to this vertex.
+ for (size_t tri = 0, n = 0; tri < mTris.size(); tri++) {
+ for (int c = 0; c < 3; c++, n++) {
+ if (mCorners[n].node >= newsize) {
+ int newindex = new_index[mCorners[n].node - newsize];
+ mCorners[n].node = newindex;
+ mTris[mCorners[n].tri].c[c] = newindex;
+ }
+ }
+ }
+
+ // renumber 1-ring
+ for (int i = 0; i < (int)new_index.size(); i++) {
+ if (new_index[i] != -1) {
+ m1RingLookup[new_index[i]].nodes.swap(m1RingLookup[newsize + i].nodes);
+ m1RingLookup[new_index[i]].tris.swap(m1RingLookup[newsize + i].tris);
+ }
+ }
+ m1RingLookup.resize(newsize);
+ vector<int> reStack(new_index.size());
+ for (int i = 0; i < newsize; i++) {
+ set<int> &cs = m1RingLookup[i].nodes;
+ int reNum = 0;
+ // find all nodes > newsize
+ set<int>::reverse_iterator itend = cs.rend();
+ for (set<int>::reverse_iterator it = cs.rbegin(); it != itend; ++it) {
+ if (*it < newsize)
+ break;
+ reStack[reNum++] = *it;
+ }
+ // kill them and insert shifted values
+ if (reNum > 0) {
+ cs.erase(cs.find(reStack[reNum - 1]), cs.end());
+ for (int j = 0; j < reNum; j++) {
+ cs.insert(new_index[reStack[j] - newsize]);
+#ifdef DEBUG
+ if (new_index[reStack[j] - newsize] == -1)
+ errMsg("invalid node present in 1-ring set");
+#endif
+ }
+ }
+ }
+}
+
+void Mesh::mergeNode(int node, int delnode)
+{
+ set<int> &ring = m1RingLookup[delnode].nodes;
+ for (set<int>::iterator it = ring.begin(); it != ring.end(); ++it) {
+ m1RingLookup[*it].nodes.erase(delnode);
+ if (*it != node) {
+ m1RingLookup[*it].nodes.insert(node);
+ m1RingLookup[node].nodes.insert(*it);
+ }
+ }
+ set<int> &ringt = m1RingLookup[delnode].tris;
+ for (set<int>::iterator it = ringt.begin(); it != ringt.end(); ++it) {
+ const int t = *it;
+ for (int c = 0; c < 3; c++) {
+ if (mCorners[3 * t + c].node == delnode) {
+ mCorners[3 * t + c].node = node;
+ mTris[t].c[c] = node;
+ }
+ }
+ m1RingLookup[node].tris.insert(t);
+ }
+ for (size_t i = 0; i < mNodeChannels.size(); i++) {
+ // weight is fixed to 1/2 for now
+ mNodeChannels[i]->mergeWith(node, delnode, 0.5);
+ }
+}
+
+void Mesh::removeTriFromLookup(int tri)
+{
+ for (int c = 0; c < 3; c++) {
+ int node = mTris[tri].c[c];
+ m1RingLookup[node].tris.erase(tri);
+ }
+}
+
+void Mesh::addCorner(Corner a)
+{
+ mCorners.push_back(a);
+}
+
+int Mesh::addTri(Triangle a)
+{
+ mTris.push_back(a);
+ for (int c = 0; c < 3; c++) {
+ int node = a.c[c];
+ int nextnode = a.c[(c + 1) % 3];
+ if ((int)m1RingLookup.size() <= node)
+ m1RingLookup.resize(node + 1);
+ if ((int)m1RingLookup.size() <= nextnode)
+ m1RingLookup.resize(nextnode + 1);
+ m1RingLookup[node].nodes.insert(nextnode);
+ m1RingLookup[nextnode].nodes.insert(node);
+ m1RingLookup[node].tris.insert(mTris.size() - 1);
+ }
+ return mTris.size() - 1;
+}
+
+int Mesh::addNode(Node a)
+{
+ mNodes.push_back(a);
+ if (m1RingLookup.size() < mNodes.size())
+ m1RingLookup.resize(mNodes.size());
+
+ // if mdata exists, add zero init for every node
+ addAllMdata();
+
+ return mNodes.size() - 1;
+}
+
+void Mesh::computeVertexNormals()
+{
+ for (size_t i = 0; i < mNodes.size(); i++) {
+ mNodes[i].normal = 0.0;
+ }
+ for (size_t t = 0; t < mTris.size(); t++) {
+ Vec3 p0 = getNode(t, 0), p1 = getNode(t, 1), p2 = getNode(t, 2);
+ Vec3 n0 = p0 - p1, n1 = p1 - p2, n2 = p2 - p0;
+ Real l0 = normSquare(n0), l1 = normSquare(n1), l2 = normSquare(n2);
+
+ Vec3 nm = cross(n0, n1);
+
+ mNodes[mTris[t].c[0]].normal += nm * (1.0 / (l0 * l2));
+ mNodes[mTris[t].c[1]].normal += nm * (1.0 / (l0 * l1));
+ mNodes[mTris[t].c[2]].normal += nm * (1.0 / (l1 * l2));
+ }
+ for (size_t i = 0; i < mNodes.size(); i++) {
+ normalize(mNodes[i].normal);
+ }
+}
+
+void Mesh::fastNodeLookupRebuild(int corner)
+{
+ int node = mCorners[corner].node;
+ m1RingLookup[node].nodes.clear();
+ m1RingLookup[node].tris.clear();
+ int start = mCorners[corner].prev;
+ int current = start;
+ do {
+ m1RingLookup[node].nodes.insert(mCorners[current].node);
+ m1RingLookup[node].tris.insert(mCorners[current].tri);
+ current = mCorners[mCorners[current].opposite].next;
+ if (current < 0)
+ errMsg("Can't use fastNodeLookupRebuild on incomplete surfaces");
+ } while (current != start);
+}
+
+void Mesh::sanityCheck(bool strict, vector<int> *deletedNodes, map<int, bool> *taintedTris)
+{
+ const int nodes = numNodes(), tris = numTris(), corners = 3 * tris;
+ for (size_t i = 0; i < mNodeChannels.size(); i++) {
+ if (mNodeChannels[i]->size() != nodes)
+ errMsg("Node channel size mismatch");
+ }
+ for (size_t i = 0; i < mTriChannels.size(); i++) {
+ if (mTriChannels[i]->size() != tris)
+ errMsg("Tri channel size mismatch");
+ }
+ if ((int)m1RingLookup.size() != nodes)
+ errMsg("1Ring size wrong");
+ for (size_t t = 0; t < mTris.size(); t++) {
+ if (taintedTris && taintedTris->find(t) != taintedTris->end())
+ continue;
+ for (int c = 0; c < 3; c++) {
+ int corner = t * 3 + c;
+ int node = mTris[t].c[c];
+ int next = mTris[t].c[(c + 1) % 3];
+ int prev = mTris[t].c[(c + 2) % 3];
+ int rnext = mCorners[corner].next;
+ int rprev = mCorners[corner].prev;
+ int ro = mCorners[corner].opposite;
+ if (node < 0 || node >= nodes || next < 0 || next >= nodes || prev < 0 || prev >= nodes)
+ errMsg("invalid node entry");
+ if (mCorners[corner].node != node || mCorners[corner].tri != (int)t)
+ errMsg("invalid basic corner entry");
+ if (rnext < 0 || rnext >= corners || rprev < 0 || rprev >= corners || ro >= corners)
+ errMsg("invalid corner links");
+ if (mCorners[rnext].node != next || mCorners[rprev].node != prev)
+ errMsg("invalid corner next/prev");
+ if (strict && ro < 0)
+ errMsg("opposite missing");
+ if (mCorners[ro].opposite != corner)
+ errMsg("invalid opposite ref");
+ set<int> &rnodes = m1RingLookup[node].nodes;
+ set<int> &rtris = m1RingLookup[node].tris;
+ if (rnodes.find(next) == rnodes.end() || rnodes.find(prev) == rnodes.end()) {
+ debMsg("Tri " << t << " " << node << " " << next << " " << prev, 1);
+ for (set<int>::iterator it = rnodes.begin(); it != rnodes.end(); ++it)
+ debMsg(*it, 1);
+ errMsg("node missing in 1ring");
+ }
+ if (rtris.find(t) == rtris.end()) {
+ debMsg("Tri " << t << " " << node, 1);
+ errMsg("tri missing in 1ring");
+ }
+ }
+ }
+ for (int n = 0; n < nodes; n++) {
+ bool docheck = true;
+ if (deletedNodes)
+ for (size_t e = 0; e < deletedNodes->size(); e++)
+ if ((*deletedNodes)[e] == n)
+ docheck = false;
+ ;
+
+ if (docheck) {
+ set<int> &sn = m1RingLookup[n].nodes;
+ set<int> &st = m1RingLookup[n].tris;
+ set<int> sn2;
+
+ for (set<int>::iterator it = st.begin(); it != st.end(); ++it) {
+ bool found = false;
+ for (int c = 0; c < 3; c++) {
+ if (mTris[*it].c[c] == n)
+ found = true;
+ else
+ sn2.insert(mTris[*it].c[c]);
+ }
+ if (!found) {
+ cout << *it << " " << n << endl;
+ for (int c = 0; c < 3; c++)
+ cout << mTris[*it].c[c] << endl;
+ errMsg("invalid triangle in 1ring");
+ }
+ if (taintedTris && taintedTris->find(*it) != taintedTris->end()) {
+ cout << *it << endl;
+ errMsg("tainted tri still is use");
+ }
+ }
+ if (sn.size() != sn2.size())
+ errMsg("invalid nodes in 1ring");
+ for (set<int>::iterator it = sn.begin(), it2 = sn2.begin(); it != sn.end(); ++it, ++it2) {
+ if (*it != *it2) {
+ cout << "Node " << n << ": " << *it << " vs " << *it2 << endl;
+ errMsg("node ring mismatch");
+ }
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+// rasterization
+
+void meshSDF(Mesh &mesh, LevelsetGrid &levelset, Real sigma, Real cutoff = 0.);
+
+//! helper vec3 array container
+struct CVec3Ptr {
+ Real *x, *y, *z;
+ inline Vec3 get(int i) const
+ {
+ return Vec3(x[i], y[i], z[i]);
+ };
+ inline void set(int i, const Vec3 &v)
+ {
+ x[i] = v.x;
+ y[i] = v.y;
+ z[i] = v.z;
+ };
+};
+//! helper vec3 array, for CUDA compatibility, remove at some point
+struct CVec3Array {
+ CVec3Array(int sz)
+ {
+ x.resize(sz);
+ y.resize(sz);
+ z.resize(sz);
+ }
+ CVec3Array(const std::vector<Vec3> &v)
+ {
+ x.resize(v.size());
+ y.resize(v.size());
+ z.resize(v.size());
+ for (size_t i = 0; i < v.size(); i++) {
+ x[i] = v[i].x;
+ y[i] = v[i].y;
+ z[i] = v[i].z;
+ }
+ }
+ CVec3Ptr data()
+ {
+ CVec3Ptr a = {x.data(), y.data(), z.data()};
+ return a;
+ }
+ inline const Vec3 operator[](int idx) const
+ {
+ return Vec3((Real)x[idx], (Real)y[idx], (Real)z[idx]);
+ }
+ inline void set(int idx, const Vec3 &v)
+ {
+ x[idx] = v.x;
+ y[idx] = v.y;
+ z[idx] = v.z;
+ }
+ inline int size()
+ {
+ return x.size();
+ }
+ std::vector<Real> x, y, z;
+};
+
+// void SDFKernel(const int* partStart, const int* partLen, CVec3Ptr pos, CVec3Ptr normal, Real*
+// sdf, Vec3i gridRes, int intRadius, Real safeRadius2, Real cutoff2, Real isigma2);
+//! helper for rasterization
+static void SDFKernel(Grid<int> &partStart,
+ Grid<int> &partLen,
+ CVec3Ptr pos,
+ CVec3Ptr normal,
+ LevelsetGrid &sdf,
+ Vec3i gridRes,
+ int intRadius,
+ Real safeRadius2,
+ Real cutoff2,
+ Real isigma2)
+{
+ for (int cnt_x(0); cnt_x < gridRes[0]; ++cnt_x) {
+ for (int cnt_y(0); cnt_y < gridRes[1]; ++cnt_y) {
+ for (int cnt_z(0); cnt_z < gridRes[2]; ++cnt_z) {
+ // cell index, center
+ Vec3i cell = Vec3i(cnt_x, cnt_y, cnt_z);
+ if (cell.x >= gridRes.x || cell.y >= gridRes.y || cell.z >= gridRes.z)
+ return;
+ Vec3 cpos = Vec3(cell.x + 0.5f, cell.y + 0.5f, cell.z + 0.5f);
+ Real sum = 0.0f;
+ Real dist = 0.0f;
+
+ // query cells within block radius
+ Vec3i minBlock = Vec3i(
+ max(cell.x - intRadius, 0), max(cell.y - intRadius, 0), max(cell.z - intRadius, 0));
+ Vec3i maxBlock = Vec3i(min(cell.x + intRadius, gridRes.x - 1),
+ min(cell.y + intRadius, gridRes.y - 1),
+ min(cell.z + intRadius, gridRes.z - 1));
+ for (int i = minBlock.x; i <= maxBlock.x; i++)
+ for (int j = minBlock.y; j <= maxBlock.y; j++)
+ for (int k = minBlock.z; k <= maxBlock.z; k++) {
+ // test if block is within radius
+ Vec3 d = Vec3(cell.x - i, cell.y - j, cell.z - k);
+ Real normSqr = d[0] * d[0] + d[1] * d[1] + d[2] * d[2];
+ if (normSqr > safeRadius2)
+ continue;
+
+ // find source cell, and divide it into thread blocks
+ int block = i + gridRes.x * (j + gridRes.y * k);
+ int slen = partLen[block];
+ if (slen == 0)
+ continue;
+ int start = partStart[block];
+
+ // process sources
+ for (int s = 0; s < slen; s++) {
+
+ // actual sdf kernel
+ Vec3 r = cpos - pos.get(start + s);
+ Real normSqr = r[0] * r[0] + r[1] * r[1] + r[2] * r[2];
+ Real r2 = normSqr;
+ if (r2 < cutoff2) {
+ Real w = expf(-r2 * isigma2);
+ sum += w;
+ dist += dot(normal.get(start + s), r) * w;
+ }
+ }
+ }
+ // writeback
+ if (sum > 0.0f) {
+ // sdf[cell.x + gridRes.x * (cell.y + gridRes.y * cell.z)] = dist / sum;
+ sdf(cell.x, cell.y, cell.z) = dist / sum;
+ }
+ }
+ }
+ }
+}
+
+static inline IndexInt _cIndex(const Vec3 &pos, const Vec3i &s)
+{
+ Vec3i p = toVec3i(pos);
+ if (p.x < 0 || p.y < 0 || p.z < 0 || p.x >= s.x || p.y >= s.y || p.z >= s.z)
+ return -1;
+ return p.x + s.x * (p.y + s.y * p.z);
+}
+
+//! Kernel: Apply a shape to a grid, setting value inside
+
+template<class T> struct ApplyMeshToGrid : public KernelBase {
+ ApplyMeshToGrid(Grid<T> *grid, Grid<Real> &sdf, T value, FlagGrid *respectFlags)
+ : KernelBase(grid, 0), grid(grid), sdf(sdf), value(value), respectFlags(respectFlags)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, Grid<T> *grid, Grid<Real> &sdf, T value, FlagGrid *respectFlags) const
+ {
+ if (respectFlags && respectFlags->isObstacle(i, j, k))
+ return;
+ if (sdf(i, j, k) < 0) {
+ (*grid)(i, j, k) = value;
+ }
+ }
+ inline Grid<T> *getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<T> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return sdf;
+ }
+ typedef Grid<Real> type1;
+ inline T &getArg2()
+ {
+ return value;
+ }
+ typedef T type2;
+ inline FlagGrid *getArg3()
+ {
+ return respectFlags;
+ }
+ typedef FlagGrid type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel ApplyMeshToGrid ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, sdf, value, respectFlags);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, sdf, value, respectFlags);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<T> *grid;
+ Grid<Real> &sdf;
+ T value;
+ FlagGrid *respectFlags;
+};
+
+void Mesh::applyMeshToGrid(GridBase *grid, FlagGrid *respectFlags, Real cutoff, Real meshSigma)
+{
+ FluidSolver dummy(grid->getSize());
+ LevelsetGrid mesh_sdf(&dummy, false);
+ meshSDF(*this, mesh_sdf, meshSigma, cutoff); // meshSigma=2 fixed here
+
+#if NOPYTHON != 1
+ if (grid->getType() & GridBase::TypeInt)
+ ApplyMeshToGrid<int>((Grid<int> *)grid, mesh_sdf, _args.get<int>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeReal)
+ ApplyMeshToGrid<Real>((Grid<Real> *)grid, mesh_sdf, _args.get<Real>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeVec3)
+ ApplyMeshToGrid<Vec3>((Grid<Vec3> *)grid, mesh_sdf, _args.get<Vec3>("value"), respectFlags);
+ else
+ errMsg("Shape::applyToGrid(): unknown grid type");
+#else
+ errMsg("Not yet supported...");
+#endif
+}
+
+void Mesh::computeLevelset(LevelsetGrid &levelset, Real sigma, Real cutoff)
+{
+ meshSDF(*this, levelset, sigma, cutoff);
+}
+
+LevelsetGrid Mesh::getLevelset(Real sigma, Real cutoff)
+{
+ LevelsetGrid phi(getParent());
+ meshSDF(*this, phi, sigma, cutoff);
+ return phi;
+}
+
+void meshSDF(Mesh &mesh, LevelsetGrid &levelset, Real sigma, Real cutoff)
+{
+ if (cutoff < 0)
+ cutoff = 2 * sigma;
+ Real maxEdgeLength = 0.75;
+ Real numSamplesPerCell = 0.75;
+
+ Vec3i gridRes = levelset.getSize();
+ Vec3 mult = toVec3(gridRes) / toVec3(mesh.getParent()->getGridSize());
+
+ // prepare center values
+ std::vector<Vec3> center;
+ std::vector<Vec3> normals;
+ short bigEdges(0);
+ std::vector<Vec3> samplePoints;
+ for (int i = 0; i < mesh.numTris(); i++) {
+ center.push_back(Vec3(mesh.getFaceCenter(i) * mult));
+ normals.push_back(mesh.getFaceNormal(i));
+ // count big, stretched edges
+ bigEdges = 0;
+ for (short edge(0); edge < 3; ++edge) {
+ if (norm(mesh.getEdge(i, edge)) > maxEdgeLength) {
+ bigEdges += 1 << edge;
+ }
+ }
+ if (bigEdges > 0) {
+ samplePoints.clear();
+ short iterA, pointA, iterB, pointB;
+ int numSamples0 = norm(mesh.getEdge(i, 1)) * numSamplesPerCell;
+ int numSamples1 = norm(mesh.getEdge(i, 2)) * numSamplesPerCell;
+ int numSamples2 = norm(mesh.getEdge(i, 0)) * numSamplesPerCell;
+ if (!(bigEdges & (1 << 0))) {
+ // loop through 0,1
+ iterA = numSamples1;
+ pointA = 0;
+ iterB = numSamples2;
+ pointB = 1;
+ }
+ else if (!(bigEdges & (1 << 1))) {
+ // loop through 1,2
+ iterA = numSamples2;
+ pointA = 1;
+ iterB = numSamples0;
+ pointB = 2;
+ }
+ else {
+ // loop through 2,0
+ iterA = numSamples0;
+ pointA = 2;
+ iterB = numSamples1;
+ pointB = 0;
+ }
+
+ Real u(0.), v(0.), w(0.); // barycentric uvw coords
+ Vec3 samplePoint, normal;
+ for (int sample0(0); sample0 < iterA; ++sample0) {
+ u = Real(1. * sample0 / iterA);
+ for (int sample1(0); sample1 < iterB; ++sample1) {
+ v = Real(1. * sample1 / iterB);
+ w = 1 - u - v;
+ if (w < 0.)
+ continue;
+ samplePoint = mesh.getNode(i, pointA) * mult * u + mesh.getNode(i, pointB) * mult * v +
+ mesh.getNode(i, (3 - pointA - pointB)) * mult * w;
+ samplePoints.push_back(samplePoint);
+ normal = mesh.getFaceNormal(i);
+ normals.push_back(normal);
+ }
+ }
+ center.insert(center.end(), samplePoints.begin(), samplePoints.end());
+ }
+ }
+
+ // prepare grid
+ levelset.setConst(-cutoff);
+
+ // 1. count sources per cell
+ Grid<int> srcPerCell(levelset.getParent());
+ for (size_t i = 0; i < center.size(); i++) {
+ IndexInt idx = _cIndex(center[i], gridRes);
+ if (idx >= 0)
+ srcPerCell[idx]++;
+ }
+
+ // 2. create start index lookup
+ Grid<int> srcCellStart(levelset.getParent());
+ int cnt = 0;
+ FOR_IJK(srcCellStart)
+ {
+ IndexInt idx = srcCellStart.index(i, j, k);
+ srcCellStart[idx] = cnt;
+ cnt += srcPerCell[idx];
+ }
+
+ // 3. reorder nodes
+ CVec3Array reorderPos(center.size());
+ CVec3Array reorderNormal(center.size());
+ {
+ Grid<int> curSrcCell(levelset.getParent());
+ for (int i = 0; i < (int)center.size(); i++) {
+ IndexInt idx = _cIndex(center[i], gridRes);
+ if (idx < 0)
+ continue;
+ IndexInt idx2 = srcCellStart[idx] + curSrcCell[idx];
+ reorderPos.set(idx2, center[i]);
+ reorderNormal.set(idx2, normals[i]);
+ curSrcCell[idx]++;
+ }
+ }
+
+ // construct parameters
+ Real safeRadius = cutoff + sqrt(3.0) * 0.5;
+ Real safeRadius2 = safeRadius * safeRadius;
+ Real cutoff2 = cutoff * cutoff;
+ Real isigma2 = 1.0 / (sigma * sigma);
+ int intRadius = (int)(cutoff + 0.5);
+
+ SDFKernel(srcCellStart,
+ srcPerCell,
+ reorderPos.data(),
+ reorderNormal.data(),
+ levelset,
+ gridRes,
+ intRadius,
+ safeRadius2,
+ cutoff2,
+ isigma2);
+
+ // floodfill outside
+ std::stack<Vec3i> outside;
+ FOR_IJK(levelset)
+ {
+ if (levelset(i, j, k) >= cutoff - 1.0f)
+ outside.push(Vec3i(i, j, k));
+ }
+ while (!outside.empty()) {
+ Vec3i c = outside.top();
+ outside.pop();
+ levelset(c) = cutoff;
+ if (c.x > 0 && levelset(c.x - 1, c.y, c.z) < 0)
+ outside.push(Vec3i(c.x - 1, c.y, c.z));
+ if (c.y > 0 && levelset(c.x, c.y - 1, c.z) < 0)
+ outside.push(Vec3i(c.x, c.y - 1, c.z));
+ if (c.z > 0 && levelset(c.x, c.y, c.z - 1) < 0)
+ outside.push(Vec3i(c.x, c.y, c.z - 1));
+ if (c.x < levelset.getSizeX() - 1 && levelset(c.x + 1, c.y, c.z) < 0)
+ outside.push(Vec3i(c.x + 1, c.y, c.z));
+ if (c.y < levelset.getSizeY() - 1 && levelset(c.x, c.y + 1, c.z) < 0)
+ outside.push(Vec3i(c.x, c.y + 1, c.z));
+ if (c.z < levelset.getSizeZ() - 1 && levelset(c.x, c.y, c.z + 1) < 0)
+ outside.push(Vec3i(c.x, c.y, c.z + 1));
+ };
+}
+
+// Blender data pointer accessors
+std::string Mesh::getNodesDataPointer()
+{
+ std::ostringstream out;
+ out << &mNodes;
+ return out.str();
+}
+std::string Mesh::getTrisDataPointer()
+{
+ std::ostringstream out;
+ out << &mTris;
+ return out.str();
+}
+
+// mesh data
+
+MeshDataBase::MeshDataBase(FluidSolver *parent) : PbClass(parent), mMesh(NULL)
+{
+}
+
+MeshDataBase::~MeshDataBase()
+{
+ // notify parent of deletion
+ if (mMesh)
+ mMesh->deregister(this);
+}
+
+// actual data implementation
+
+template<class T>
+MeshDataImpl<T>::MeshDataImpl(FluidSolver *parent)
+ : MeshDataBase(parent), mpGridSource(NULL), mGridSourceMAC(false)
+{
+}
+
+template<class T>
+MeshDataImpl<T>::MeshDataImpl(FluidSolver *parent, MeshDataImpl<T> *other)
+ : MeshDataBase(parent), mpGridSource(NULL), mGridSourceMAC(false)
+{
+ this->mData = other->mData;
+ setName(other->getName());
+}
+
+template<class T> MeshDataImpl<T>::~MeshDataImpl()
+{
+}
+
+template<class T> IndexInt MeshDataImpl<T>::getSizeSlow() const
+{
+ return mData.size();
+}
+template<class T> void MeshDataImpl<T>::addEntry()
+{
+ // add zero'ed entry
+ T tmp = T(0.);
+ // for debugging, force init:
+ // tmp = T(0.02 * mData.size()); // increasing
+ // tmp = T(1.); // constant 1
+ return mData.push_back(tmp);
+}
+template<class T> void MeshDataImpl<T>::resize(IndexInt s)
+{
+ mData.resize(s);
+}
+template<class T> void MeshDataImpl<T>::copyValueSlow(IndexInt from, IndexInt to)
+{
+ this->copyValue(from, to);
+}
+template<class T> MeshDataBase *MeshDataImpl<T>::clone()
+{
+ MeshDataImpl<T> *npd = new MeshDataImpl<T>(getParent(), this);
+ return npd;
+}
+
+template<class T> void MeshDataImpl<T>::setSource(Grid<T> *grid, bool isMAC)
+{
+ mpGridSource = grid;
+ mGridSourceMAC = isMAC;
+ if (isMAC)
+ assertMsg(dynamic_cast<MACGrid *>(grid) != NULL, "Given grid is not a valid MAC grid");
+}
+
+template<class T> void MeshDataImpl<T>::initNewValue(IndexInt idx, Vec3 pos)
+{
+ if (!mpGridSource)
+ mData[idx] = 0;
+ else {
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ }
+}
+
+// special handling needed for velocities
+template<> void MeshDataImpl<Vec3>::initNewValue(IndexInt idx, Vec3 pos)
+{
+ if (!mpGridSource)
+ mData[idx] = 0;
+ else {
+ if (!mGridSourceMAC)
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ else
+ mData[idx] = ((MACGrid *)mpGridSource)->getInterpolated(pos);
+ }
+}
+
+//! update additional mesh data
+void Mesh::updateDataFields()
+{
+ for (size_t i = 0; i < mNodes.size(); ++i) {
+ Vec3 pos = mNodes[i].pos;
+ for (IndexInt md = 0; md < (IndexInt)mMdataReal.size(); ++md)
+ mMdataReal[md]->initNewValue(i, mNodes[i].pos);
+ for (IndexInt md = 0; md < (IndexInt)mMdataVec3.size(); ++md)
+ mMdataVec3[md]->initNewValue(i, mNodes[i].pos);
+ for (IndexInt md = 0; md < (IndexInt)mMdataInt.size(); ++md)
+ mMdataInt[md]->initNewValue(i, mNodes[i].pos);
+ }
+}
+
+template<typename T> void MeshDataImpl<T>::load(string name)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ readMdataUni<T>(name, this);
+ else if (ext == ".raw") // raw = uni for now
+ readMdataUni<T>(name, this);
+ else
+ errMsg("mesh data '" + name + "' filetype not supported for loading");
+}
+
+template<typename T> void MeshDataImpl<T>::save(string name)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ writeMdataUni<T>(name, this);
+ else if (ext == ".raw") // raw = uni for now
+ writeMdataUni<T>(name, this);
+ else
+ errMsg("mesh data '" + name + "' filetype not supported for saving");
+}
+
+// specializations
+
+template<> MeshDataBase::MdataType MeshDataImpl<Real>::getType() const
+{
+ return MeshDataBase::TypeReal;
+}
+template<> MeshDataBase::MdataType MeshDataImpl<int>::getType() const
+{
+ return MeshDataBase::TypeInt;
+}
+template<> MeshDataBase::MdataType MeshDataImpl<Vec3>::getType() const
+{
+ return MeshDataBase::TypeVec3;
+}
+
+template<class T> struct knSetMdataConst : public KernelBase {
+ knSetMdataConst(MeshDataImpl<T> &mdata, T value)
+ : KernelBase(mdata.size()), mdata(mdata), value(value)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &mdata, T value) const
+ {
+ mdata[idx] = value;
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return mdata;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline T &getArg1()
+ {
+ return value;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetMdataConst ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, mdata, value);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &mdata;
+ T value;
+};
+
+template<class T, class S> struct knMdataSet : public KernelBase {
+ knMdataSet(MeshDataImpl<T> &me, const MeshDataImpl<S> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const MeshDataImpl<S> &other) const
+ {
+ me[idx] += other[idx];
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const MeshDataImpl<S> &getArg1()
+ {
+ return other;
+ }
+ typedef MeshDataImpl<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataSet ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const MeshDataImpl<S> &other;
+};
+template<class T, class S> struct knMdataAdd : public KernelBase {
+ knMdataAdd(MeshDataImpl<T> &me, const MeshDataImpl<S> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const MeshDataImpl<S> &other) const
+ {
+ me[idx] += other[idx];
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const MeshDataImpl<S> &getArg1()
+ {
+ return other;
+ }
+ typedef MeshDataImpl<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataAdd ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const MeshDataImpl<S> &other;
+};
+template<class T, class S> struct knMdataSub : public KernelBase {
+ knMdataSub(MeshDataImpl<T> &me, const MeshDataImpl<S> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const MeshDataImpl<S> &other) const
+ {
+ me[idx] -= other[idx];
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const MeshDataImpl<S> &getArg1()
+ {
+ return other;
+ }
+ typedef MeshDataImpl<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataSub ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const MeshDataImpl<S> &other;
+};
+template<class T, class S> struct knMdataMult : public KernelBase {
+ knMdataMult(MeshDataImpl<T> &me, const MeshDataImpl<S> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const MeshDataImpl<S> &other) const
+ {
+ me[idx] *= other[idx];
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const MeshDataImpl<S> &getArg1()
+ {
+ return other;
+ }
+ typedef MeshDataImpl<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataMult ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const MeshDataImpl<S> &other;
+};
+template<class T, class S> struct knMdataDiv : public KernelBase {
+ knMdataDiv(MeshDataImpl<T> &me, const MeshDataImpl<S> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const MeshDataImpl<S> &other) const
+ {
+ me[idx] /= other[idx];
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const MeshDataImpl<S> &getArg1()
+ {
+ return other;
+ }
+ typedef MeshDataImpl<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataDiv ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const MeshDataImpl<S> &other;
+};
+
+template<class T, class S> struct knMdataSetScalar : public KernelBase {
+ knMdataSetScalar(MeshDataImpl<T> &me, const S &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const S &other) const
+ {
+ me[idx] = other;
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataSetScalar ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const S &other;
+};
+template<class T, class S> struct knMdataAddScalar : public KernelBase {
+ knMdataAddScalar(MeshDataImpl<T> &me, const S &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const S &other) const
+ {
+ me[idx] += other;
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataAddScalar ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const S &other;
+};
+template<class T, class S> struct knMdataMultScalar : public KernelBase {
+ knMdataMultScalar(MeshDataImpl<T> &me, const S &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const S &other) const
+ {
+ me[idx] *= other;
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataMultScalar ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const S &other;
+};
+template<class T, class S> struct knMdataScaledAdd : public KernelBase {
+ knMdataScaledAdd(MeshDataImpl<T> &me, const MeshDataImpl<T> &other, const S &factor)
+ : KernelBase(me.size()), me(me), other(other), factor(factor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ MeshDataImpl<T> &me,
+ const MeshDataImpl<T> &other,
+ const S &factor) const
+ {
+ me[idx] += factor * other[idx];
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const MeshDataImpl<T> &getArg1()
+ {
+ return other;
+ }
+ typedef MeshDataImpl<T> type1;
+ inline const S &getArg2()
+ {
+ return factor;
+ }
+ typedef S type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataScaledAdd ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other, factor);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const MeshDataImpl<T> &other;
+ const S &factor;
+};
+
+template<class T> struct knMdataSafeDiv : public KernelBase {
+ knMdataSafeDiv(MeshDataImpl<T> &me, const MeshDataImpl<T> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const MeshDataImpl<T> &other) const
+ {
+ me[idx] = safeDivide(me[idx], other[idx]);
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const MeshDataImpl<T> &getArg1()
+ {
+ return other;
+ }
+ typedef MeshDataImpl<T> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataSafeDiv ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const MeshDataImpl<T> &other;
+};
+template<class T> struct knMdataSetConst : public KernelBase {
+ knMdataSetConst(MeshDataImpl<T> &mdata, T value)
+ : KernelBase(mdata.size()), mdata(mdata), value(value)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &mdata, T value) const
+ {
+ mdata[idx] = value;
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return mdata;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline T &getArg1()
+ {
+ return value;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataSetConst ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, mdata, value);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &mdata;
+ T value;
+};
+
+template<class T> struct knMdataClamp : public KernelBase {
+ knMdataClamp(MeshDataImpl<T> &me, T min, T max)
+ : KernelBase(me.size()), me(me), min(min), max(max)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, T min, T max) const
+ {
+ me[idx] = clamp(me[idx], min, max);
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline T &getArg1()
+ {
+ return min;
+ }
+ typedef T type1;
+ inline T &getArg2()
+ {
+ return max;
+ }
+ typedef T type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataClamp ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, min, max);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ T min;
+ T max;
+};
+template<class T> struct knMdataClampMin : public KernelBase {
+ knMdataClampMin(MeshDataImpl<T> &me, const T vmin) : KernelBase(me.size()), me(me), vmin(vmin)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const T vmin) const
+ {
+ me[idx] = std::max(vmin, me[idx]);
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const T &getArg1()
+ {
+ return vmin;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataClampMin ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, vmin);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const T vmin;
+};
+template<class T> struct knMdataClampMax : public KernelBase {
+ knMdataClampMax(MeshDataImpl<T> &me, const T vmax) : KernelBase(me.size()), me(me), vmax(vmax)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<T> &me, const T vmax) const
+ {
+ me[idx] = std::min(vmax, me[idx]);
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const T &getArg1()
+ {
+ return vmax;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataClampMax ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, vmax);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const T vmax;
+};
+struct knMdataClampMinVec3 : public KernelBase {
+ knMdataClampMinVec3(MeshDataImpl<Vec3> &me, const Real vmin)
+ : KernelBase(me.size()), me(me), vmin(vmin)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<Vec3> &me, const Real vmin) const
+ {
+ me[idx].x = std::max(vmin, me[idx].x);
+ me[idx].y = std::max(vmin, me[idx].y);
+ me[idx].z = std::max(vmin, me[idx].z);
+ }
+ inline MeshDataImpl<Vec3> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<Vec3> type0;
+ inline const Real &getArg1()
+ {
+ return vmin;
+ }
+ typedef Real type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataClampMinVec3 ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, vmin);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<Vec3> &me;
+ const Real vmin;
+};
+struct knMdataClampMaxVec3 : public KernelBase {
+ knMdataClampMaxVec3(MeshDataImpl<Vec3> &me, const Real vmax)
+ : KernelBase(me.size()), me(me), vmax(vmax)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, MeshDataImpl<Vec3> &me, const Real vmax) const
+ {
+ me[idx].x = std::min(vmax, me[idx].x);
+ me[idx].y = std::min(vmax, me[idx].y);
+ me[idx].z = std::min(vmax, me[idx].z);
+ }
+ inline MeshDataImpl<Vec3> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<Vec3> type0;
+ inline const Real &getArg1()
+ {
+ return vmax;
+ }
+ typedef Real type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataClampMaxVec3 ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, vmax);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<Vec3> &me;
+ const Real vmax;
+};
+
+// python operators
+
+template<typename T> MeshDataImpl<T> &MeshDataImpl<T>::copyFrom(const MeshDataImpl<T> &a)
+{
+ assertMsg(a.mData.size() == mData.size(),
+ "different mdata size " << a.mData.size() << " vs " << this->mData.size());
+ memcpy(&mData[0], &a.mData[0], sizeof(T) * mData.size());
+ return *this;
+}
+
+template<typename T> void MeshDataImpl<T>::setConst(T s)
+{
+ knMdataSetScalar<T, T> op(*this, s);
+}
+
+template<typename T> void MeshDataImpl<T>::setConstRange(T s, const int begin, const int end)
+{
+ for (int i = begin; i < end; ++i)
+ (*this)[i] = s;
+}
+
+// special set by flag
+template<class T, class S> struct knMdataSetScalarIntFlag : public KernelBase {
+ knMdataSetScalarIntFlag(MeshDataImpl<T> &me,
+ const S &other,
+ const MeshDataImpl<int> &t,
+ const int itype)
+ : KernelBase(me.size()), me(me), other(other), t(t), itype(itype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ MeshDataImpl<T> &me,
+ const S &other,
+ const MeshDataImpl<int> &t,
+ const int itype) const
+ {
+ if (t[idx] & itype)
+ me[idx] = other;
+ }
+ inline MeshDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ inline const MeshDataImpl<int> &getArg2()
+ {
+ return t;
+ }
+ typedef MeshDataImpl<int> type2;
+ inline const int &getArg3()
+ {
+ return itype;
+ }
+ typedef int type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMdataSetScalarIntFlag ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other, t, itype);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MeshDataImpl<T> &me;
+ const S &other;
+ const MeshDataImpl<int> &t;
+ const int itype;
+};
+template<typename T>
+void MeshDataImpl<T>::setConstIntFlag(T s, const MeshDataImpl<int> &t, const int itype)
+{
+ knMdataSetScalarIntFlag<T, T> op(*this, s, t, itype);
+}
+
+template<typename T> void MeshDataImpl<T>::add(const MeshDataImpl<T> &a)
+{
+ knMdataAdd<T, T> op(*this, a);
+}
+template<typename T> void MeshDataImpl<T>::sub(const MeshDataImpl<T> &a)
+{
+ knMdataSub<T, T> op(*this, a);
+}
+
+template<typename T> void MeshDataImpl<T>::addConst(T s)
+{
+ knMdataAddScalar<T, T> op(*this, s);
+}
+
+template<typename T> void MeshDataImpl<T>::addScaled(const MeshDataImpl<T> &a, const T &factor)
+{
+ knMdataScaledAdd<T, T> op(*this, a, factor);
+}
+
+template<typename T> void MeshDataImpl<T>::mult(const MeshDataImpl<T> &a)
+{
+ knMdataMult<T, T> op(*this, a);
+}
+
+template<typename T> void MeshDataImpl<T>::safeDiv(const MeshDataImpl<T> &a)
+{
+ knMdataSafeDiv<T> op(*this, a);
+}
+
+template<typename T> void MeshDataImpl<T>::multConst(T s)
+{
+ knMdataMultScalar<T, T> op(*this, s);
+}
+
+template<typename T> void MeshDataImpl<T>::clamp(Real vmin, Real vmax)
+{
+ knMdataClamp<T> op(*this, vmin, vmax);
+}
+
+template<typename T> void MeshDataImpl<T>::clampMin(Real vmin)
+{
+ knMdataClampMin<T> op(*this, vmin);
+}
+template<typename T> void MeshDataImpl<T>::clampMax(Real vmax)
+{
+ knMdataClampMax<T> op(*this, vmax);
+}
+
+template<> void MeshDataImpl<Vec3>::clampMin(Real vmin)
+{
+ knMdataClampMinVec3 op(*this, vmin);
+}
+template<> void MeshDataImpl<Vec3>::clampMax(Real vmax)
+{
+ knMdataClampMaxVec3 op(*this, vmax);
+}
+
+template<typename T> struct KnPtsSum : public KernelBase {
+ KnPtsSum(const MeshDataImpl<T> &val, const MeshDataImpl<int> *t, const int itype)
+ : KernelBase(val.size()), val(val), t(t), itype(itype), result(T(0.))
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const MeshDataImpl<T> &val,
+ const MeshDataImpl<int> *t,
+ const int itype,
+ T &result)
+ {
+ if (t && !((*t)[idx] & itype))
+ return;
+ result += val[idx];
+ }
+ inline operator T()
+ {
+ return result;
+ }
+ inline T &getRet()
+ {
+ return result;
+ }
+ inline const MeshDataImpl<T> &getArg0()
+ {
+ return val;
+ }
+ typedef MeshDataImpl<T> type0;
+ inline const MeshDataImpl<int> *getArg1()
+ {
+ return t;
+ }
+ typedef MeshDataImpl<int> type1;
+ inline const int &getArg2()
+ {
+ return itype;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnPtsSum ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, t, itype, result);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ KnPtsSum(KnPtsSum &o, tbb::split)
+ : KernelBase(o), val(o.val), t(o.t), itype(o.itype), result(T(0.))
+ {
+ }
+ void join(const KnPtsSum &o)
+ {
+ result += o.result;
+ }
+ const MeshDataImpl<T> &val;
+ const MeshDataImpl<int> *t;
+ const int itype;
+ T result;
+};
+template<typename T> struct KnPtsSumSquare : public KernelBase {
+ KnPtsSumSquare(const MeshDataImpl<T> &val) : KernelBase(val.size()), val(val), result(0.)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const MeshDataImpl<T> &val, Real &result)
+ {
+ result += normSquare(val[idx]);
+ }
+ inline operator Real()
+ {
+ return result;
+ }
+ inline Real &getRet()
+ {
+ return result;
+ }
+ inline const MeshDataImpl<T> &getArg0()
+ {
+ return val;
+ }
+ typedef MeshDataImpl<T> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnPtsSumSquare ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, result);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ KnPtsSumSquare(KnPtsSumSquare &o, tbb::split) : KernelBase(o), val(o.val), result(0.)
+ {
+ }
+ void join(const KnPtsSumSquare &o)
+ {
+ result += o.result;
+ }
+ const MeshDataImpl<T> &val;
+ Real result;
+};
+template<typename T> struct KnPtsSumMagnitude : public KernelBase {
+ KnPtsSumMagnitude(const MeshDataImpl<T> &val) : KernelBase(val.size()), val(val), result(0.)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const MeshDataImpl<T> &val, Real &result)
+ {
+ result += norm(val[idx]);
+ }
+ inline operator Real()
+ {
+ return result;
+ }
+ inline Real &getRet()
+ {
+ return result;
+ }
+ inline const MeshDataImpl<T> &getArg0()
+ {
+ return val;
+ }
+ typedef MeshDataImpl<T> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnPtsSumMagnitude ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, result);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ KnPtsSumMagnitude(KnPtsSumMagnitude &o, tbb::split) : KernelBase(o), val(o.val), result(0.)
+ {
+ }
+ void join(const KnPtsSumMagnitude &o)
+ {
+ result += o.result;
+ }
+ const MeshDataImpl<T> &val;
+ Real result;
+};
+
+template<typename T> T MeshDataImpl<T>::sum(const MeshDataImpl<int> *t, const int itype) const
+{
+ return KnPtsSum<T>(*this, t, itype);
+}
+template<typename T> Real MeshDataImpl<T>::sumSquare() const
+{
+ return KnPtsSumSquare<T>(*this);
+}
+template<typename T> Real MeshDataImpl<T>::sumMagnitude() const
+{
+ return KnPtsSumMagnitude<T>(*this);
+}
+
+template<typename T>
+
+struct CompMdata_Min : public KernelBase {
+ CompMdata_Min(const MeshDataImpl<T> &val)
+ : KernelBase(val.size()), val(val), minVal(std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const MeshDataImpl<T> &val, Real &minVal)
+ {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+ }
+ inline operator Real()
+ {
+ return minVal;
+ }
+ inline Real &getRet()
+ {
+ return minVal;
+ }
+ inline const MeshDataImpl<T> &getArg0()
+ {
+ return val;
+ }
+ typedef MeshDataImpl<T> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompMdata_Min ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, minVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompMdata_Min(CompMdata_Min &o, tbb::split)
+ : KernelBase(o), val(o.val), minVal(std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompMdata_Min &o)
+ {
+ minVal = min(minVal, o.minVal);
+ }
+ const MeshDataImpl<T> &val;
+ Real minVal;
+};
+
+template<typename T>
+
+struct CompMdata_Max : public KernelBase {
+ CompMdata_Max(const MeshDataImpl<T> &val)
+ : KernelBase(val.size()), val(val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const MeshDataImpl<T> &val, Real &maxVal)
+ {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+ }
+ inline operator Real()
+ {
+ return maxVal;
+ }
+ inline Real &getRet()
+ {
+ return maxVal;
+ }
+ inline const MeshDataImpl<T> &getArg0()
+ {
+ return val;
+ }
+ typedef MeshDataImpl<T> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompMdata_Max ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, maxVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompMdata_Max(CompMdata_Max &o, tbb::split)
+ : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompMdata_Max &o)
+ {
+ maxVal = max(maxVal, o.maxVal);
+ }
+ const MeshDataImpl<T> &val;
+ Real maxVal;
+};
+
+template<typename T> Real MeshDataImpl<T>::getMin()
+{
+ return CompMdata_Min<T>(*this);
+}
+
+template<typename T> Real MeshDataImpl<T>::getMaxAbs()
+{
+ Real amin = CompMdata_Min<T>(*this);
+ Real amax = CompMdata_Max<T>(*this);
+ return max(fabs(amin), fabs(amax));
+}
+
+template<typename T> Real MeshDataImpl<T>::getMax()
+{
+ return CompMdata_Max<T>(*this);
+}
+
+template<typename T>
+void MeshDataImpl<T>::printMdata(IndexInt start, IndexInt stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ IndexInt s = (start > 0 ? start : 0);
+ IndexInt e = (stop > 0 ? stop : (IndexInt)mData.size());
+ s = Manta::clamp(s, (IndexInt)0, (IndexInt)mData.size());
+ e = Manta::clamp(e, (IndexInt)0, (IndexInt)mData.size());
+
+ for (IndexInt i = s; i < e; ++i) {
+ if (printIndex)
+ sstr << i << ": ";
+ sstr << mData[i] << " "
+ << "\n";
+ }
+ debMsg(sstr.str(), 1);
+}
+template<class T> std::string MeshDataImpl<T>::getDataPointer()
+{
+ std::ostringstream out;
+ out << &mData;
+ return out.str();
+}
+
+// specials for vec3
+// work on length values, ie, always positive (in contrast to scalar versions above)
+
+struct CompMdata_MinVec3 : public KernelBase {
+ CompMdata_MinVec3(const MeshDataImpl<Vec3> &val)
+ : KernelBase(val.size()), val(val), minVal(-std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const MeshDataImpl<Vec3> &val, Real &minVal)
+ {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+ }
+ inline operator Real()
+ {
+ return minVal;
+ }
+ inline Real &getRet()
+ {
+ return minVal;
+ }
+ inline const MeshDataImpl<Vec3> &getArg0()
+ {
+ return val;
+ }
+ typedef MeshDataImpl<Vec3> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompMdata_MinVec3 ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, minVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompMdata_MinVec3(CompMdata_MinVec3 &o, tbb::split)
+ : KernelBase(o), val(o.val), minVal(-std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompMdata_MinVec3 &o)
+ {
+ minVal = min(minVal, o.minVal);
+ }
+ const MeshDataImpl<Vec3> &val;
+ Real minVal;
+};
+
+struct CompMdata_MaxVec3 : public KernelBase {
+ CompMdata_MaxVec3(const MeshDataImpl<Vec3> &val)
+ : KernelBase(val.size()), val(val), maxVal(-std::numeric_limits<Real>::min())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const MeshDataImpl<Vec3> &val, Real &maxVal)
+ {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+ }
+ inline operator Real()
+ {
+ return maxVal;
+ }
+ inline Real &getRet()
+ {
+ return maxVal;
+ }
+ inline const MeshDataImpl<Vec3> &getArg0()
+ {
+ return val;
+ }
+ typedef MeshDataImpl<Vec3> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompMdata_MaxVec3 ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, maxVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompMdata_MaxVec3(CompMdata_MaxVec3 &o, tbb::split)
+ : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<Real>::min())
+ {
+ }
+ void join(const CompMdata_MaxVec3 &o)
+ {
+ maxVal = max(maxVal, o.maxVal);
+ }
+ const MeshDataImpl<Vec3> &val;
+ Real maxVal;
+};
+
+template<> Real MeshDataImpl<Vec3>::getMin()
+{
+ return sqrt(CompMdata_MinVec3(*this));
+}
+
+template<> Real MeshDataImpl<Vec3>::getMaxAbs()
+{
+ return sqrt(CompMdata_MaxVec3(*this)); // no minimum necessary here
+}
+
+template<> Real MeshDataImpl<Vec3>::getMax()
+{
+ return sqrt(CompMdata_MaxVec3(*this));
+}
+
+// explicit instantiation
+template class MeshDataImpl<int>;
+template class MeshDataImpl<Real>;
+template class MeshDataImpl<Vec3>;
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/mesh.h b/extern/mantaflow/preprocessed/mesh.h
new file mode 100644
index 00000000000..f49619515ce
--- /dev/null
+++ b/extern/mantaflow/preprocessed/mesh.h
@@ -0,0 +1,1690 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Meshes
+ *
+ * note: this is only a temporary solution, details are bound to change
+ * long term goal is integration with Split&Merge code by Wojtan et al.
+ *
+ ******************************************************************************/
+
+#ifndef _MESH_H
+#define _MESH_H
+
+#include <vector>
+#include "manta.h"
+#include "vectorbase.h"
+#include <set>
+#include "levelset.h"
+
+namespace Manta {
+
+// fwd decl
+class GridBase;
+// class LevelsetGrid;
+class FlagGrid;
+class MACGrid;
+class Shape;
+class MeshDataBase;
+template<class T> class MeshDataImpl;
+
+//! Node position and flags
+struct Node {
+ Node() : flags(0), pos(Vec3::Zero), normal(Vec3::Zero)
+ {
+ }
+ Node(const Vec3 &p) : flags(0), pos(p)
+ {
+ }
+ int flags;
+ Vec3 pos, normal;
+};
+
+//! Carries indices of its nodes
+struct Triangle {
+ Triangle() : flags(0)
+ {
+ c[0] = c[1] = c[2] = 0;
+ }
+ Triangle(int n0, int n1, int n2) : flags(0)
+ {
+ c[0] = n0;
+ c[1] = n1;
+ c[2] = n2;
+ }
+
+ int c[3];
+ int flags;
+};
+
+//! For fast access to nodes and neighboring triangles
+struct Corner {
+ Corner() : tri(-1), node(-1), opposite(-1), next(-1), prev(-1){};
+ Corner(int t, int n) : tri(t), node(n), opposite(-1), next(-1), prev(-1)
+ {
+ }
+
+ int tri;
+ int node;
+ int opposite;
+ int next;
+ int prev;
+};
+
+//! Base class for mesh data channels (texture coords, vorticity, ...)
+struct NodeChannel {
+ virtual ~NodeChannel(){};
+ virtual void resize(int num) = 0;
+ virtual int size() = 0;
+ virtual NodeChannel *clone() = 0;
+
+ virtual void addInterpol(int a, int b, Real alpha) = 0;
+ virtual void mergeWith(int node, int delnode, Real alpha) = 0;
+ virtual void renumber(const std::vector<int> &newIndex, int newsize) = 0;
+};
+
+//! Node channel using only a vector
+template<class T> struct SimpleNodeChannel : public NodeChannel {
+ SimpleNodeChannel(){};
+ SimpleNodeChannel(const SimpleNodeChannel<T> &a) : data(a.data)
+ {
+ }
+ void resize(int num)
+ {
+ data.resize(num);
+ }
+ virtual int size()
+ {
+ return data.size();
+ }
+ virtual void renumber(const std::vector<int> &newIndex, int newsize);
+
+ // virtual void addSplit(int from, Real alpha) { data.push_back(data[from]); }
+
+ std::vector<T> data;
+};
+
+//! Base class for mesh data channels (texture coords, vorticity, ...)
+struct TriChannel {
+ virtual ~TriChannel(){};
+ virtual void resize(int num) = 0;
+ virtual TriChannel *clone() = 0;
+ virtual int size() = 0;
+
+ virtual void addNew() = 0;
+ virtual void addSplit(int from, Real alpha) = 0;
+ virtual void remove(int tri) = 0;
+};
+
+//! Tri channel using only a vector
+template<class T> struct SimpleTriChannel : public TriChannel {
+ SimpleTriChannel(){};
+ SimpleTriChannel(const SimpleTriChannel<T> &a) : data(a.data)
+ {
+ }
+ void resize(int num)
+ {
+ data.resize(num);
+ }
+ void remove(int tri)
+ {
+ if (tri != (int)data.size() - 1)
+ data[tri] = *data.rbegin();
+ data.pop_back();
+ }
+ virtual int size()
+ {
+ return data.size();
+ }
+
+ virtual void addSplit(int from, Real alpha)
+ {
+ data.push_back(data[from]);
+ }
+ virtual void addNew()
+ {
+ data.push_back(T());
+ }
+
+ std::vector<T> data;
+};
+
+struct OneRing {
+ OneRing()
+ {
+ }
+ std::set<int> nodes;
+ std::set<int> tris;
+};
+
+//! Triangle mesh class
+/*! note: this is only a temporary solution, details are bound to change
+ long term goal is integration with Split&Merge code by Wojtan et al.*/
+class Mesh : public PbClass {
+ public:
+ Mesh(FluidSolver *parent);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "Mesh::Mesh", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new Mesh(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "Mesh::Mesh", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::Mesh", e.what());
+ return -1;
+ }
+ }
+
+ virtual ~Mesh();
+ virtual Mesh *clone();
+
+ enum NodeFlags { NfNone = 0, NfFixed = 1, NfMarked = 2, NfKillme = 4, NfCollide = 8 };
+ enum FaceFlags { FfNone = 0, FfDoubled = 1, FfMarked = 2 };
+ enum MeshType { TypeNormal = 0, TypeVortexSheet };
+
+ virtual MeshType getType()
+ {
+ return TypeNormal;
+ }
+
+ Real computeCenterOfMass(Vec3 &cm) const;
+ void computeVertexNormals();
+
+ // plugins
+ void clear();
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::clear", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clear();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::clear", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::clear", e.what());
+ return 0;
+ }
+ }
+
+ void load(std::string name, bool append = false);
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::load", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ std::string name = _args.get<std::string>("name", 0, &_lock);
+ bool append = _args.getOpt<bool>("append", 1, false, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->load(name, append);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::load", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::load", e.what());
+ return 0;
+ }
+ }
+
+ void fromShape(Shape &shape, bool append = false);
+ static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::fromShape", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Shape &shape = *_args.getPtr<Shape>("shape", 0, &_lock);
+ bool append = _args.getOpt<bool>("append", 1, false, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->fromShape(shape, append);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::fromShape", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::fromShape", e.what());
+ return 0;
+ }
+ }
+
+ void save(std::string name);
+ static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::save", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->save(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::save", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::save", e.what());
+ return 0;
+ }
+ }
+
+ void advectInGrid(FlagGrid &flags, MACGrid &vel, int integrationMode);
+ static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::advectInGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ int integrationMode = _args.get<int>("integrationMode", 2, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->advectInGrid(flags, vel, integrationMode);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::advectInGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::advectInGrid", e.what());
+ return 0;
+ }
+ }
+
+ void scale(Vec3 s);
+ static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::scale", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Vec3 s = _args.get<Vec3>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->scale(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::scale", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::scale", e.what());
+ return 0;
+ }
+ }
+
+ void offset(Vec3 o);
+ static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::offset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Vec3 o = _args.get<Vec3>("o", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->offset(o);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::offset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::offset", e.what());
+ return 0;
+ }
+ }
+
+ void rotate(Vec3 thetas);
+ static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::rotate", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Vec3 thetas = _args.get<Vec3>("thetas", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->rotate(thetas);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::rotate", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::rotate", e.what());
+ return 0;
+ }
+ }
+
+ void computeVelocity(Mesh &oldMesh, MACGrid &vel);
+ static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::computeVelocity", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Mesh &oldMesh = *_args.getPtr<Mesh>("oldMesh", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->computeVelocity(oldMesh, vel);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::computeVelocity", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::computeVelocity", e.what());
+ return 0;
+ }
+ }
+
+ void computeLevelset(LevelsetGrid &levelset, Real sigma, Real cutoff = -1.);
+ static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::computeLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ LevelsetGrid &levelset = *_args.getPtr<LevelsetGrid>("levelset", 0, &_lock);
+ Real sigma = _args.get<Real>("sigma", 1, &_lock);
+ Real cutoff = _args.getOpt<Real>("cutoff", 2, -1., &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->computeLevelset(levelset, sigma, cutoff);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::computeLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::computeLevelset", e.what());
+ return 0;
+ }
+ }
+
+ LevelsetGrid getLevelset(Real sigma, Real cutoff = -1.);
+ static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::getLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real sigma = _args.get<Real>("sigma", 0, &_lock);
+ Real cutoff = _args.getOpt<Real>("cutoff", 1, -1., &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getLevelset(sigma, cutoff));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::getLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::getLevelset", e.what());
+ return 0;
+ }
+ }
+
+ //! map mesh to grid with sdf
+ void applyMeshToGrid(GridBase *grid,
+ FlagGrid *respectFlags = 0,
+ Real cutoff = -1.,
+ Real meshSigma = 2.);
+ static PyObject *_W_12(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::applyMeshToGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ GridBase *grid = _args.getPtr<GridBase>("grid", 0, &_lock);
+ FlagGrid *respectFlags = _args.getPtrOpt<FlagGrid>("respectFlags", 1, 0, &_lock);
+ Real cutoff = _args.getOpt<Real>("cutoff", 2, -1., &_lock);
+ Real meshSigma = _args.getOpt<Real>("meshSigma", 3, 2., &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->applyMeshToGrid(grid, respectFlags, cutoff, meshSigma);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::applyMeshToGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::applyMeshToGrid", e.what());
+ return 0;
+ }
+ }
+
+ //! get data pointer of nodes
+ std::string getNodesDataPointer();
+ static PyObject *_W_13(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::getNodesDataPointer", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getNodesDataPointer());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::getNodesDataPointer", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::getNodesDataPointer", e.what());
+ return 0;
+ }
+ }
+
+ //! get data pointer of tris
+ std::string getTrisDataPointer();
+ static PyObject *_W_14(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::getTrisDataPointer", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getTrisDataPointer());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::getTrisDataPointer", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::getTrisDataPointer", e.what());
+ return 0;
+ }
+ }
+
+ // ops
+ Mesh &operator=(const Mesh &o);
+
+ // accessors
+ inline int numTris() const
+ {
+ return mTris.size();
+ }
+ inline int numNodes() const
+ {
+ return mNodes.size();
+ }
+ inline int numTriChannels() const
+ {
+ return mTriChannels.size();
+ }
+ inline int numNodeChannels() const
+ {
+ return mNodeChannels.size();
+ }
+
+ //! return size of container
+ //! note , python binding disabled for now! cannot yet deal with long-long types
+ inline IndexInt size() const
+ {
+ return mNodes.size();
+ }
+ //! slow virtual function of base class, also returns size
+ virtual IndexInt getSizeSlow() const
+ {
+ return size();
+ }
+
+ inline Triangle &tris(int i)
+ {
+ return mTris[i];
+ }
+ inline Node &nodes(int i)
+ {
+ return mNodes[i];
+ }
+ inline Corner &corners(int tri, int c)
+ {
+ return mCorners[tri * 3 + c];
+ }
+ inline Corner &corners(int c)
+ {
+ return mCorners[c];
+ }
+ inline NodeChannel *nodeChannel(int i)
+ {
+ return mNodeChannels[i];
+ }
+ inline TriChannel *triChannel(int i)
+ {
+ return mTriChannels[i];
+ }
+
+ // allocate memory (eg upon load)
+ void resizeTris(int numTris);
+ void resizeNodes(int numNodes);
+
+ inline bool isNodeFixed(int n)
+ {
+ return mNodes[n].flags & NfFixed;
+ }
+ inline bool isTriangleFixed(int t)
+ {
+ return (mNodes[mTris[t].c[0]].flags & NfFixed) || (mNodes[mTris[t].c[1]].flags & NfFixed) ||
+ (mNodes[mTris[t].c[2]].flags & NfFixed);
+ }
+
+ inline const Vec3 getNode(int tri, int c) const
+ {
+ return mNodes[mTris[tri].c[c]].pos;
+ }
+ inline Vec3 &getNode(int tri, int c)
+ {
+ return mNodes[mTris[tri].c[c]].pos;
+ }
+ inline const Vec3 getEdge(int tri, int e) const
+ {
+ return getNode(tri, (e + 1) % 3) - getNode(tri, e);
+ }
+ inline OneRing &get1Ring(int node)
+ {
+ return m1RingLookup[node];
+ }
+ inline Real getFaceArea(int t) const
+ {
+ Vec3 c0 = mNodes[mTris[t].c[0]].pos;
+ return 0.5 * norm(cross(mNodes[mTris[t].c[1]].pos - c0, mNodes[mTris[t].c[2]].pos - c0));
+ }
+ inline Vec3 getFaceNormal(int t)
+ {
+ Vec3 c0 = mNodes[mTris[t].c[0]].pos;
+ return getNormalized(cross(mNodes[mTris[t].c[1]].pos - c0, mNodes[mTris[t].c[2]].pos - c0));
+ }
+ inline Vec3 getFaceCenter(int t) const
+ {
+ return (mNodes[mTris[t].c[0]].pos + mNodes[mTris[t].c[1]].pos + mNodes[mTris[t].c[2]].pos) /
+ 3.0;
+ }
+ inline std::vector<Node> &getNodeData()
+ {
+ return mNodes;
+ }
+
+ void mergeNode(int node, int delnode);
+ int addNode(Node a);
+ int addTri(Triangle a);
+ void addCorner(Corner a);
+ void removeTri(int tri);
+ void removeTriFromLookup(int tri);
+ void removeNodes(const std::vector<int> &deletedNodes);
+ void rebuildCorners(int from = 0, int to = -1);
+ void rebuildLookup(int from = 0, int to = -1);
+ void rebuildQuickCheck();
+ void fastNodeLookupRebuild(int corner);
+ void sanityCheck(bool strict = true,
+ std::vector<int> *deletedNodes = 0,
+ std::map<int, bool> *taintedTris = 0);
+
+ void addTriChannel(TriChannel *c)
+ {
+ mTriChannels.push_back(c);
+ rebuildChannels();
+ }
+ void addNodeChannel(NodeChannel *c)
+ {
+ mNodeChannels.push_back(c);
+ rebuildChannels();
+ }
+
+ //! mesh data functions
+
+ //! create a mesh data object
+ PbClass *create(PbType type, PbTypeVec T = PbTypeVec(), const std::string &name = "");
+ static PyObject *_W_15(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Mesh *pbo = dynamic_cast<Mesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Mesh::create", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ PbType type = _args.get<PbType>("type", 0, &_lock);
+ PbTypeVec T = _args.getOpt<PbTypeVec>("T", 1, PbTypeVec(), &_lock);
+ const std::string &name = _args.getOpt<std::string>("name", 2, "", &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->create(type, T, name));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Mesh::create", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Mesh::create", e.what());
+ return 0;
+ }
+ }
+
+ //! add a mesh data field, set its parent mesh pointer
+ void registerMdata(MeshDataBase *mdata);
+ void registerMdataReal(MeshDataImpl<Real> *mdata);
+ void registerMdataVec3(MeshDataImpl<Vec3> *mdata);
+ void registerMdataInt(MeshDataImpl<int> *mdata);
+ //! remove a mesh data entry
+ void deregister(MeshDataBase *mdata);
+ //! add one zero entry to all data fields
+ void addAllMdata();
+ // note - deletion of mdata is handled in compress function
+
+ //! how many are there?
+ IndexInt getNumMdata() const
+ {
+ return mMeshData.size();
+ }
+ //! access one of the fields
+ MeshDataBase *getMdata(int i)
+ {
+ return mMeshData[i];
+ }
+
+ //! update data fields
+ void updateDataFields();
+
+ protected:
+ void rebuildChannels();
+
+ std::vector<Node> mNodes;
+ std::vector<Triangle> mTris;
+ std::vector<Corner> mCorners;
+ std::vector<NodeChannel *> mNodeChannels;
+ std::vector<TriChannel *> mTriChannels;
+ std::vector<OneRing> m1RingLookup;
+
+ //! store mesh data , each pointer has its own storage vector of a certain type (int, real, vec3)
+ std::vector<MeshDataBase *> mMeshData;
+ //! lists of different types, for fast operations w/o virtual function calls
+ std::vector<MeshDataImpl<Real> *> mMdataReal;
+ std::vector<MeshDataImpl<Vec3> *> mMdataVec3;
+ std::vector<MeshDataImpl<int> *>
+ mMdataInt; //! indicate that mdata of this mesh is copied, and needs to be freed
+ bool mFreeMdata;
+ public:
+ PbArgs _args;
+}
+#define _C_Mesh
+;
+
+//******************************************************************************
+
+//! abstract interface for mesh data
+class MeshDataBase : public PbClass {
+ public:
+ MeshDataBase(FluidSolver *parent);
+ static int _W_16(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "MeshDataBase::MeshDataBase", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new MeshDataBase(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "MeshDataBase::MeshDataBase", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataBase::MeshDataBase", e.what());
+ return -1;
+ }
+ }
+
+ virtual ~MeshDataBase();
+
+ //! data type IDs, in line with those for grids
+ enum MdataType { TypeNone = 0, TypeReal = 1, TypeInt = 2, TypeVec3 = 4 };
+
+ //! interface functions, using assert instead of pure virtual for python compatibility
+ virtual IndexInt getSizeSlow() const
+ {
+ assertMsg(false, "Dont use, override...");
+ return 0;
+ }
+ virtual void addEntry()
+ {
+ assertMsg(false, "Dont use, override...");
+ return;
+ }
+ virtual MeshDataBase *clone()
+ {
+ assertMsg(false, "Dont use, override...");
+ return NULL;
+ }
+ virtual MdataType getType() const
+ {
+ assertMsg(false, "Dont use, override...");
+ return TypeNone;
+ }
+ virtual void resize(IndexInt size)
+ {
+ assertMsg(false, "Dont use, override...");
+ return;
+ }
+ virtual void copyValueSlow(IndexInt from, IndexInt to)
+ {
+ assertMsg(false, "Dont use, override...");
+ return;
+ }
+
+ //! set base pointer
+ void setMesh(Mesh *set)
+ {
+ mMesh = set;
+ }
+
+ //! debugging
+ inline void checkNodeIndex(IndexInt idx) const;
+
+ protected:
+ Mesh *mMesh;
+ public:
+ PbArgs _args;
+}
+#define _C_MeshDataBase
+;
+
+//! abstract interface for mesh data
+
+template<class T> class MeshDataImpl : public MeshDataBase {
+ public:
+ MeshDataImpl(FluidSolver *parent);
+ static int _W_17(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "MeshDataImpl::MeshDataImpl", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new MeshDataImpl(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "MeshDataImpl::MeshDataImpl", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::MeshDataImpl", e.what());
+ return -1;
+ }
+ }
+
+ MeshDataImpl(FluidSolver *parent, MeshDataImpl<T> *other);
+ virtual ~MeshDataImpl();
+
+ //! access data
+ inline T &get(IndexInt idx)
+ {
+ DEBUG_ONLY(checkNodeIndex(idx));
+ return mData[idx];
+ }
+ inline const T &get(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkNodeIndex(idx));
+ return mData[idx];
+ }
+ inline T &operator[](IndexInt idx)
+ {
+ DEBUG_ONLY(checkNodeIndex(idx));
+ return mData[idx];
+ }
+ inline const T &operator[](IndexInt idx) const
+ {
+ DEBUG_ONLY(checkNodeIndex(idx));
+ return mData[idx];
+ }
+
+ //! set all values to 0, note - different from meshSystem::clear! doesnt modify size of array
+ //! (has to stay in sync with parent system)
+ void clear();
+ static PyObject *_W_18(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clear", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clear();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::clear", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::clear", e.what());
+ return 0;
+ }
+ }
+
+ //! set grid from which to get data...
+ void setSource(Grid<T> *grid, bool isMAC = false);
+ static PyObject *_W_19(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setSource", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<T> *grid = _args.getPtr<Grid<T>>("grid", 0, &_lock);
+ bool isMAC = _args.getOpt<bool>("isMAC", 1, false, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setSource(grid, isMAC);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::setSource", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::setSource", e.what());
+ return 0;
+ }
+ }
+
+ //! mesh data base interface
+ virtual IndexInt getSizeSlow() const;
+ virtual void addEntry();
+ virtual MeshDataBase *clone();
+ virtual MdataType getType() const;
+ virtual void resize(IndexInt s);
+ virtual void copyValueSlow(IndexInt from, IndexInt to);
+
+ IndexInt size() const
+ {
+ return mData.size();
+ }
+
+ //! fast inlined functions for per mesh operations
+ inline void copyValue(IndexInt from, IndexInt to)
+ {
+ get(to) = get(from);
+ }
+ void initNewValue(IndexInt idx, Vec3 pos);
+
+ //! python interface (similar to grid data)
+ void setConst(T s);
+ static PyObject *_W_20(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::setConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::setConst", e.what());
+ return 0;
+ }
+ }
+
+ void setConstRange(T s, const int begin, const int end);
+ static PyObject *_W_21(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setConstRange", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ const int begin = _args.get<int>("begin", 1, &_lock);
+ const int end = _args.get<int>("end", 2, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setConstRange(s, begin, end);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::setConstRange", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::setConstRange", e.what());
+ return 0;
+ }
+ }
+
+ MeshDataImpl<T> &copyFrom(const MeshDataImpl<T> &a);
+ static PyObject *_W_22(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::copyFrom", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MeshDataImpl<T> &a = *_args.getPtr<MeshDataImpl<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->copyFrom(a));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::copyFrom", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::copyFrom", e.what());
+ return 0;
+ }
+ }
+
+ void add(const MeshDataImpl<T> &a);
+ static PyObject *_W_23(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::add", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MeshDataImpl<T> &a = *_args.getPtr<MeshDataImpl<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->add(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::add", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::add", e.what());
+ return 0;
+ }
+ }
+
+ void sub(const MeshDataImpl<T> &a);
+ static PyObject *_W_24(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sub", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MeshDataImpl<T> &a = *_args.getPtr<MeshDataImpl<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->sub(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::sub", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::sub", e.what());
+ return 0;
+ }
+ }
+
+ void addConst(T s);
+ static PyObject *_W_25(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::addConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->addConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::addConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::addConst", e.what());
+ return 0;
+ }
+ }
+
+ void addScaled(const MeshDataImpl<T> &a, const T &factor);
+ static PyObject *_W_26(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::addScaled", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MeshDataImpl<T> &a = *_args.getPtr<MeshDataImpl<T>>("a", 0, &_lock);
+ const T &factor = *_args.getPtr<T>("factor", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->addScaled(a, factor);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::addScaled", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::addScaled", e.what());
+ return 0;
+ }
+ }
+
+ void mult(const MeshDataImpl<T> &a);
+ static PyObject *_W_27(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::mult", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MeshDataImpl<T> &a = *_args.getPtr<MeshDataImpl<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->mult(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::mult", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::mult", e.what());
+ return 0;
+ }
+ }
+
+ void multConst(T s);
+ static PyObject *_W_28(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::multConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->multConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::multConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::multConst", e.what());
+ return 0;
+ }
+ }
+
+ void safeDiv(const MeshDataImpl<T> &a);
+ static PyObject *_W_29(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::safeDiv", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MeshDataImpl<T> &a = *_args.getPtr<MeshDataImpl<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->safeDiv(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::safeDiv", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::safeDiv", e.what());
+ return 0;
+ }
+ }
+
+ void clamp(Real min, Real max);
+ static PyObject *_W_30(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clamp", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real min = _args.get<Real>("min", 0, &_lock);
+ Real max = _args.get<Real>("max", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clamp(min, max);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::clamp", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::clamp", e.what());
+ return 0;
+ }
+ }
+
+ void clampMin(Real vmin);
+ static PyObject *_W_31(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clampMin", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real vmin = _args.get<Real>("vmin", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clampMin(vmin);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::clampMin", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::clampMin", e.what());
+ return 0;
+ }
+ }
+
+ void clampMax(Real vmax);
+ static PyObject *_W_32(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clampMax", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real vmax = _args.get<Real>("vmax", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clampMax(vmax);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::clampMax", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::clampMax", e.what());
+ return 0;
+ }
+ }
+
+ Real getMaxAbs();
+ static PyObject *_W_33(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getMaxAbs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMaxAbs());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::getMaxAbs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::getMaxAbs", e.what());
+ return 0;
+ }
+ }
+
+ Real getMax();
+ static PyObject *_W_34(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getMax", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMax());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::getMax", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::getMax", e.what());
+ return 0;
+ }
+ }
+
+ Real getMin();
+ static PyObject *_W_35(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getMin", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMin());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::getMin", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::getMin", e.what());
+ return 0;
+ }
+ }
+
+ T sum(const MeshDataImpl<int> *t = NULL, const int itype = 0) const;
+ static PyObject *_W_36(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sum", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MeshDataImpl<int> *t = _args.getPtrOpt<MeshDataImpl<int>>("t", 0, NULL, &_lock);
+ const int itype = _args.getOpt<int>("itype", 1, 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->sum(t, itype));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::sum", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::sum", e.what());
+ return 0;
+ }
+ }
+
+ Real sumSquare() const;
+ static PyObject *_W_37(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sumSquare", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->sumSquare());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::sumSquare", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::sumSquare", e.what());
+ return 0;
+ }
+ }
+
+ Real sumMagnitude() const;
+ static PyObject *_W_38(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sumMagnitude", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->sumMagnitude());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::sumMagnitude", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::sumMagnitude", e.what());
+ return 0;
+ }
+ }
+
+ //! special, set if int flag in t has "flag"
+ void setConstIntFlag(T s, const MeshDataImpl<int> &t, const int flag);
+ static PyObject *_W_39(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setConstIntFlag", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ T s = _args.get<T>("s", 0, &_lock);
+ const MeshDataImpl<int> &t = *_args.getPtr<MeshDataImpl<int>>("t", 1, &_lock);
+ const int flag = _args.get<int>("flag", 2, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setConstIntFlag(s, t, flag);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::setConstIntFlag", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::setConstIntFlag", e.what());
+ return 0;
+ }
+ }
+
+ void printMdata(IndexInt start = -1, IndexInt stop = -1, bool printIndex = false);
+ static PyObject *_W_40(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::printMdata", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ IndexInt start = _args.getOpt<IndexInt>("start", 0, -1, &_lock);
+ IndexInt stop = _args.getOpt<IndexInt>("stop", 1, -1, &_lock);
+ bool printIndex = _args.getOpt<bool>("printIndex", 2, false, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->printMdata(start, stop, printIndex);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::printMdata", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::printMdata", e.what());
+ return 0;
+ }
+ }
+
+ //! file io
+ void save(const std::string name);
+ static PyObject *_W_41(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::save", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->save(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::save", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::save", e.what());
+ return 0;
+ }
+ }
+
+ void load(const std::string name);
+ static PyObject *_W_42(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::load", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->load(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::load", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::load", e.what());
+ return 0;
+ }
+ }
+
+ //! get data pointer of mesh data
+ std::string getDataPointer();
+ static PyObject *_W_43(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MeshDataImpl *pbo = dynamic_cast<MeshDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getDataPointer", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getDataPointer());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MeshDataImpl::getDataPointer", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MeshDataImpl::getDataPointer", e.what());
+ return 0;
+ }
+ }
+
+ protected:
+ //! data storage
+ std::vector<T> mData;
+
+ //! optionally , we might have an associated grid from which to grab new data
+ Grid<T> *mpGridSource; //! unfortunately , we need to distinguish mac vs regular vec3
+ bool mGridSourceMAC;
+ public:
+ PbArgs _args;
+}
+#define _C_MeshDataImpl
+;
+
+// ***************************************************************************************************************
+// Implementation
+
+template<class T>
+void SimpleNodeChannel<T>::renumber(const std::vector<int> &newIndex, int newsize)
+{
+ for (size_t i = 0; i < newIndex.size(); i++) {
+ if (newIndex[i] != -1)
+ data[newIndex[i]] = data[newsize + i];
+ }
+ data.resize(newsize);
+}
+
+inline void MeshDataBase::checkNodeIndex(IndexInt idx) const
+{
+ IndexInt mySize = this->getSizeSlow();
+ if (idx < 0 || idx > mySize) {
+ errMsg("MeshData "
+ << " size " << mySize << " : index " << idx << " out of bound ");
+ }
+ if (mMesh && mMesh->getSizeSlow() != mySize) {
+ errMsg("MeshData "
+ << " size " << mySize << " does not match parent! (" << mMesh->getSizeSlow() << ") ");
+ }
+}
+
+template<class T> void MeshDataImpl<T>::clear()
+{
+ for (IndexInt i = 0; i < (IndexInt)mData.size(); ++i)
+ mData[i] = 0.;
+}
+
+} // namespace Manta
+#endif
diff --git a/extern/mantaflow/preprocessed/mesh.h.reg.cpp b/extern/mantaflow/preprocessed/mesh.h.reg.cpp
new file mode 100644
index 00000000000..b2ba3e22032
--- /dev/null
+++ b/extern/mantaflow/preprocessed/mesh.h.reg.cpp
@@ -0,0 +1,239 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "mesh.h"
+namespace Manta {
+#ifdef _C_Mesh
+static const Pb::Register _R_12("Mesh", "Mesh", "PbClass");
+template<> const char *Namify<Mesh>::S = "Mesh";
+static const Pb::Register _R_13("Mesh", "Mesh", Mesh::_W_0);
+static const Pb::Register _R_14("Mesh", "clear", Mesh::_W_1);
+static const Pb::Register _R_15("Mesh", "load", Mesh::_W_2);
+static const Pb::Register _R_16("Mesh", "fromShape", Mesh::_W_3);
+static const Pb::Register _R_17("Mesh", "save", Mesh::_W_4);
+static const Pb::Register _R_18("Mesh", "advectInGrid", Mesh::_W_5);
+static const Pb::Register _R_19("Mesh", "scale", Mesh::_W_6);
+static const Pb::Register _R_20("Mesh", "offset", Mesh::_W_7);
+static const Pb::Register _R_21("Mesh", "rotate", Mesh::_W_8);
+static const Pb::Register _R_22("Mesh", "computeVelocity", Mesh::_W_9);
+static const Pb::Register _R_23("Mesh", "computeLevelset", Mesh::_W_10);
+static const Pb::Register _R_24("Mesh", "getLevelset", Mesh::_W_11);
+static const Pb::Register _R_25("Mesh", "applyMeshToGrid", Mesh::_W_12);
+static const Pb::Register _R_26("Mesh", "getNodesDataPointer", Mesh::_W_13);
+static const Pb::Register _R_27("Mesh", "getTrisDataPointer", Mesh::_W_14);
+static const Pb::Register _R_28("Mesh", "create", Mesh::_W_15);
+#endif
+#ifdef _C_MeshDataBase
+static const Pb::Register _R_29("MeshDataBase", "MeshDataBase", "PbClass");
+template<> const char *Namify<MeshDataBase>::S = "MeshDataBase";
+static const Pb::Register _R_30("MeshDataBase", "MeshDataBase", MeshDataBase::_W_16);
+#endif
+#ifdef _C_MeshDataImpl
+static const Pb::Register _R_31("MeshDataImpl<int>", "MeshDataImpl<int>", "MeshDataBase");
+template<> const char *Namify<MeshDataImpl<int>>::S = "MeshDataImpl<int>";
+static const Pb::Register _R_32("MeshDataImpl<int>", "MeshDataImpl", MeshDataImpl<int>::_W_17);
+static const Pb::Register _R_33("MeshDataImpl<int>", "clear", MeshDataImpl<int>::_W_18);
+static const Pb::Register _R_34("MeshDataImpl<int>", "setSource", MeshDataImpl<int>::_W_19);
+static const Pb::Register _R_35("MeshDataImpl<int>", "setConst", MeshDataImpl<int>::_W_20);
+static const Pb::Register _R_36("MeshDataImpl<int>", "setConstRange", MeshDataImpl<int>::_W_21);
+static const Pb::Register _R_37("MeshDataImpl<int>", "copyFrom", MeshDataImpl<int>::_W_22);
+static const Pb::Register _R_38("MeshDataImpl<int>", "add", MeshDataImpl<int>::_W_23);
+static const Pb::Register _R_39("MeshDataImpl<int>", "sub", MeshDataImpl<int>::_W_24);
+static const Pb::Register _R_40("MeshDataImpl<int>", "addConst", MeshDataImpl<int>::_W_25);
+static const Pb::Register _R_41("MeshDataImpl<int>", "addScaled", MeshDataImpl<int>::_W_26);
+static const Pb::Register _R_42("MeshDataImpl<int>", "mult", MeshDataImpl<int>::_W_27);
+static const Pb::Register _R_43("MeshDataImpl<int>", "multConst", MeshDataImpl<int>::_W_28);
+static const Pb::Register _R_44("MeshDataImpl<int>", "safeDiv", MeshDataImpl<int>::_W_29);
+static const Pb::Register _R_45("MeshDataImpl<int>", "clamp", MeshDataImpl<int>::_W_30);
+static const Pb::Register _R_46("MeshDataImpl<int>", "clampMin", MeshDataImpl<int>::_W_31);
+static const Pb::Register _R_47("MeshDataImpl<int>", "clampMax", MeshDataImpl<int>::_W_32);
+static const Pb::Register _R_48("MeshDataImpl<int>", "getMaxAbs", MeshDataImpl<int>::_W_33);
+static const Pb::Register _R_49("MeshDataImpl<int>", "getMax", MeshDataImpl<int>::_W_34);
+static const Pb::Register _R_50("MeshDataImpl<int>", "getMin", MeshDataImpl<int>::_W_35);
+static const Pb::Register _R_51("MeshDataImpl<int>", "sum", MeshDataImpl<int>::_W_36);
+static const Pb::Register _R_52("MeshDataImpl<int>", "sumSquare", MeshDataImpl<int>::_W_37);
+static const Pb::Register _R_53("MeshDataImpl<int>", "sumMagnitude", MeshDataImpl<int>::_W_38);
+static const Pb::Register _R_54("MeshDataImpl<int>", "setConstIntFlag", MeshDataImpl<int>::_W_39);
+static const Pb::Register _R_55("MeshDataImpl<int>", "printMdata", MeshDataImpl<int>::_W_40);
+static const Pb::Register _R_56("MeshDataImpl<int>", "save", MeshDataImpl<int>::_W_41);
+static const Pb::Register _R_57("MeshDataImpl<int>", "load", MeshDataImpl<int>::_W_42);
+static const Pb::Register _R_58("MeshDataImpl<int>", "getDataPointer", MeshDataImpl<int>::_W_43);
+static const Pb::Register _R_59("MeshDataImpl<Real>", "MeshDataImpl<Real>", "MeshDataBase");
+template<> const char *Namify<MeshDataImpl<Real>>::S = "MeshDataImpl<Real>";
+static const Pb::Register _R_60("MeshDataImpl<Real>", "MeshDataImpl", MeshDataImpl<Real>::_W_17);
+static const Pb::Register _R_61("MeshDataImpl<Real>", "clear", MeshDataImpl<Real>::_W_18);
+static const Pb::Register _R_62("MeshDataImpl<Real>", "setSource", MeshDataImpl<Real>::_W_19);
+static const Pb::Register _R_63("MeshDataImpl<Real>", "setConst", MeshDataImpl<Real>::_W_20);
+static const Pb::Register _R_64("MeshDataImpl<Real>", "setConstRange", MeshDataImpl<Real>::_W_21);
+static const Pb::Register _R_65("MeshDataImpl<Real>", "copyFrom", MeshDataImpl<Real>::_W_22);
+static const Pb::Register _R_66("MeshDataImpl<Real>", "add", MeshDataImpl<Real>::_W_23);
+static const Pb::Register _R_67("MeshDataImpl<Real>", "sub", MeshDataImpl<Real>::_W_24);
+static const Pb::Register _R_68("MeshDataImpl<Real>", "addConst", MeshDataImpl<Real>::_W_25);
+static const Pb::Register _R_69("MeshDataImpl<Real>", "addScaled", MeshDataImpl<Real>::_W_26);
+static const Pb::Register _R_70("MeshDataImpl<Real>", "mult", MeshDataImpl<Real>::_W_27);
+static const Pb::Register _R_71("MeshDataImpl<Real>", "multConst", MeshDataImpl<Real>::_W_28);
+static const Pb::Register _R_72("MeshDataImpl<Real>", "safeDiv", MeshDataImpl<Real>::_W_29);
+static const Pb::Register _R_73("MeshDataImpl<Real>", "clamp", MeshDataImpl<Real>::_W_30);
+static const Pb::Register _R_74("MeshDataImpl<Real>", "clampMin", MeshDataImpl<Real>::_W_31);
+static const Pb::Register _R_75("MeshDataImpl<Real>", "clampMax", MeshDataImpl<Real>::_W_32);
+static const Pb::Register _R_76("MeshDataImpl<Real>", "getMaxAbs", MeshDataImpl<Real>::_W_33);
+static const Pb::Register _R_77("MeshDataImpl<Real>", "getMax", MeshDataImpl<Real>::_W_34);
+static const Pb::Register _R_78("MeshDataImpl<Real>", "getMin", MeshDataImpl<Real>::_W_35);
+static const Pb::Register _R_79("MeshDataImpl<Real>", "sum", MeshDataImpl<Real>::_W_36);
+static const Pb::Register _R_80("MeshDataImpl<Real>", "sumSquare", MeshDataImpl<Real>::_W_37);
+static const Pb::Register _R_81("MeshDataImpl<Real>", "sumMagnitude", MeshDataImpl<Real>::_W_38);
+static const Pb::Register _R_82("MeshDataImpl<Real>",
+ "setConstIntFlag",
+ MeshDataImpl<Real>::_W_39);
+static const Pb::Register _R_83("MeshDataImpl<Real>", "printMdata", MeshDataImpl<Real>::_W_40);
+static const Pb::Register _R_84("MeshDataImpl<Real>", "save", MeshDataImpl<Real>::_W_41);
+static const Pb::Register _R_85("MeshDataImpl<Real>", "load", MeshDataImpl<Real>::_W_42);
+static const Pb::Register _R_86("MeshDataImpl<Real>", "getDataPointer", MeshDataImpl<Real>::_W_43);
+static const Pb::Register _R_87("MeshDataImpl<Vec3>", "MeshDataImpl<Vec3>", "MeshDataBase");
+template<> const char *Namify<MeshDataImpl<Vec3>>::S = "MeshDataImpl<Vec3>";
+static const Pb::Register _R_88("MeshDataImpl<Vec3>", "MeshDataImpl", MeshDataImpl<Vec3>::_W_17);
+static const Pb::Register _R_89("MeshDataImpl<Vec3>", "clear", MeshDataImpl<Vec3>::_W_18);
+static const Pb::Register _R_90("MeshDataImpl<Vec3>", "setSource", MeshDataImpl<Vec3>::_W_19);
+static const Pb::Register _R_91("MeshDataImpl<Vec3>", "setConst", MeshDataImpl<Vec3>::_W_20);
+static const Pb::Register _R_92("MeshDataImpl<Vec3>", "setConstRange", MeshDataImpl<Vec3>::_W_21);
+static const Pb::Register _R_93("MeshDataImpl<Vec3>", "copyFrom", MeshDataImpl<Vec3>::_W_22);
+static const Pb::Register _R_94("MeshDataImpl<Vec3>", "add", MeshDataImpl<Vec3>::_W_23);
+static const Pb::Register _R_95("MeshDataImpl<Vec3>", "sub", MeshDataImpl<Vec3>::_W_24);
+static const Pb::Register _R_96("MeshDataImpl<Vec3>", "addConst", MeshDataImpl<Vec3>::_W_25);
+static const Pb::Register _R_97("MeshDataImpl<Vec3>", "addScaled", MeshDataImpl<Vec3>::_W_26);
+static const Pb::Register _R_98("MeshDataImpl<Vec3>", "mult", MeshDataImpl<Vec3>::_W_27);
+static const Pb::Register _R_99("MeshDataImpl<Vec3>", "multConst", MeshDataImpl<Vec3>::_W_28);
+static const Pb::Register _R_100("MeshDataImpl<Vec3>", "safeDiv", MeshDataImpl<Vec3>::_W_29);
+static const Pb::Register _R_101("MeshDataImpl<Vec3>", "clamp", MeshDataImpl<Vec3>::_W_30);
+static const Pb::Register _R_102("MeshDataImpl<Vec3>", "clampMin", MeshDataImpl<Vec3>::_W_31);
+static const Pb::Register _R_103("MeshDataImpl<Vec3>", "clampMax", MeshDataImpl<Vec3>::_W_32);
+static const Pb::Register _R_104("MeshDataImpl<Vec3>", "getMaxAbs", MeshDataImpl<Vec3>::_W_33);
+static const Pb::Register _R_105("MeshDataImpl<Vec3>", "getMax", MeshDataImpl<Vec3>::_W_34);
+static const Pb::Register _R_106("MeshDataImpl<Vec3>", "getMin", MeshDataImpl<Vec3>::_W_35);
+static const Pb::Register _R_107("MeshDataImpl<Vec3>", "sum", MeshDataImpl<Vec3>::_W_36);
+static const Pb::Register _R_108("MeshDataImpl<Vec3>", "sumSquare", MeshDataImpl<Vec3>::_W_37);
+static const Pb::Register _R_109("MeshDataImpl<Vec3>", "sumMagnitude", MeshDataImpl<Vec3>::_W_38);
+static const Pb::Register _R_110("MeshDataImpl<Vec3>",
+ "setConstIntFlag",
+ MeshDataImpl<Vec3>::_W_39);
+static const Pb::Register _R_111("MeshDataImpl<Vec3>", "printMdata", MeshDataImpl<Vec3>::_W_40);
+static const Pb::Register _R_112("MeshDataImpl<Vec3>", "save", MeshDataImpl<Vec3>::_W_41);
+static const Pb::Register _R_113("MeshDataImpl<Vec3>", "load", MeshDataImpl<Vec3>::_W_42);
+static const Pb::Register _R_114("MeshDataImpl<Vec3>",
+ "getDataPointer",
+ MeshDataImpl<Vec3>::_W_43);
+#endif
+static const Pb::Register _R_9("MeshDataImpl<int>", "MdataInt", "");
+static const Pb::Register _R_10("MeshDataImpl<Real>", "MdataReal", "");
+static const Pb::Register _R_11("MeshDataImpl<Vec3>", "MdataVec3", "");
+extern "C" {
+void PbRegister_file_9()
+{
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+ KEEP_UNUSED(_R_101);
+ KEEP_UNUSED(_R_102);
+ KEEP_UNUSED(_R_103);
+ KEEP_UNUSED(_R_104);
+ KEEP_UNUSED(_R_105);
+ KEEP_UNUSED(_R_106);
+ KEEP_UNUSED(_R_107);
+ KEEP_UNUSED(_R_108);
+ KEEP_UNUSED(_R_109);
+ KEEP_UNUSED(_R_110);
+ KEEP_UNUSED(_R_111);
+ KEEP_UNUSED(_R_112);
+ KEEP_UNUSED(_R_113);
+ KEEP_UNUSED(_R_114);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/movingobs.cpp b/extern/mantaflow/preprocessed/movingobs.cpp
new file mode 100644
index 00000000000..a6ff01fd1e0
--- /dev/null
+++ b/extern/mantaflow/preprocessed/movingobs.cpp
@@ -0,0 +1,112 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Moving obstacles
+ *
+ ******************************************************************************/
+
+#include "movingobs.h"
+#include "commonkernels.h"
+#include "randomstream.h"
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// MovingObs class members
+
+int MovingObstacle::sIDcnt = 10;
+
+MovingObstacle::MovingObstacle(FluidSolver *parent, int emptyType)
+ : PbClass(parent), mEmptyType(emptyType)
+{
+ mID = 1 << sIDcnt;
+ sIDcnt++;
+ if (sIDcnt > 15)
+ errMsg(
+ "currently only 5 separate moving obstacles supported (are you generating them in a "
+ "loop?)");
+}
+
+void MovingObstacle::add(Shape *shape)
+{
+ mShapes.push_back(shape);
+}
+
+void MovingObstacle::projectOutside(FlagGrid &flags, BasicParticleSystem &parts)
+{
+ LevelsetGrid levelset(mParent, false);
+ Grid<Vec3> gradient(mParent);
+
+ // rebuild obstacle levelset
+ FOR_IDX(levelset)
+ {
+ levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5;
+ }
+ levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved);
+
+ // build levelset gradient
+ GradientOp(gradient, levelset);
+
+ parts.projectOutside(gradient);
+}
+
+void MovingObstacle::moveLinear(
+ Real t, Real t0, Real t1, Vec3 p0, Vec3 p1, FlagGrid &flags, MACGrid &vel, bool smooth)
+{
+ Real alpha = (t - t0) / (t1 - t0);
+ if (alpha >= 0 && alpha <= 1) {
+ Vec3 v = (p1 - p0) / ((t1 - t0) * getParent()->getDt());
+
+ // ease in and out
+ if (smooth) {
+ v *= 6.0f * (alpha - square(alpha));
+ alpha = square(alpha) * (3.0f - 2.0f * alpha);
+ }
+
+ Vec3 pos = alpha * p1 + (1.0f - alpha) * p0;
+ for (size_t i = 0; i < mShapes.size(); i++)
+ mShapes[i]->setCenter(pos);
+
+ // reset flags
+ FOR_IDX(flags)
+ {
+ if ((flags[idx] & mID) != 0)
+ flags[idx] = mEmptyType;
+ }
+ // apply new flags
+ for (size_t i = 0; i < mShapes.size(); i++) {
+#if NOPYTHON != 1
+ mShapes[i]->_args.clear();
+ mShapes[i]->_args.add("value", FlagGrid::TypeObstacle | mID);
+ mShapes[i]->applyToGrid(&flags, 0);
+#else
+ errMsg("Not yet supported...");
+#endif
+ }
+ // apply velocities
+ FOR_IJK_BND(flags, 1)
+ {
+ bool cur = (flags(i, j, k) & mID) != 0;
+ if (cur || (flags(i - 1, j, k) & mID) != 0)
+ vel(i, j, k).x = v.x;
+ if (cur || (flags(i, j - 1, k) & mID) != 0)
+ vel(i, j, k).y = v.y;
+ if (cur || (flags(i, j, k - 1) & mID) != 0)
+ vel(i, j, k).z = v.z;
+ }
+ }
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/movingobs.h b/extern/mantaflow/preprocessed/movingobs.h
new file mode 100644
index 00000000000..71cc441f1d0
--- /dev/null
+++ b/extern/mantaflow/preprocessed/movingobs.h
@@ -0,0 +1,164 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * moving obstacles
+ *
+ ******************************************************************************/
+
+#ifndef _MOVINGOBS_H
+#define _MOVINGOBS_H
+
+#include "shapes.h"
+#include "particle.h"
+
+namespace Manta {
+
+//! Moving obstacle composed of basic shapes
+class MovingObstacle : public PbClass {
+ public:
+ MovingObstacle(FluidSolver *parent, int emptyType = FlagGrid::TypeEmpty);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "MovingObstacle::MovingObstacle", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ int emptyType = _args.getOpt<int>("emptyType", 1, FlagGrid::TypeEmpty, &_lock);
+ obj = new MovingObstacle(parent, emptyType);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "MovingObstacle::MovingObstacle", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("MovingObstacle::MovingObstacle", e.what());
+ return -1;
+ }
+ }
+
+ void add(Shape *shape);
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MovingObstacle *pbo = dynamic_cast<MovingObstacle *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MovingObstacle::add", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Shape *shape = _args.getPtr<Shape>("shape", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->add(shape);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MovingObstacle::add", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MovingObstacle::add", e.what());
+ return 0;
+ }
+ }
+
+ //! If t in [t0,t1], apply linear motion path from p0 to p1
+ void moveLinear(Real t,
+ Real t0,
+ Real t1,
+ Vec3 p0,
+ Vec3 p1,
+ FlagGrid &flags,
+ MACGrid &vel,
+ bool smooth = true);
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MovingObstacle *pbo = dynamic_cast<MovingObstacle *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MovingObstacle::moveLinear", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real t = _args.get<Real>("t", 0, &_lock);
+ Real t0 = _args.get<Real>("t0", 1, &_lock);
+ Real t1 = _args.get<Real>("t1", 2, &_lock);
+ Vec3 p0 = _args.get<Vec3>("p0", 3, &_lock);
+ Vec3 p1 = _args.get<Vec3>("p1", 4, &_lock);
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 5, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 6, &_lock);
+ bool smooth = _args.getOpt<bool>("smooth", 7, true, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->moveLinear(t, t0, t1, p0, p1, flags, vel, smooth);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MovingObstacle::moveLinear", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MovingObstacle::moveLinear", e.what());
+ return 0;
+ }
+ }
+
+ //! Compute levelset, and project FLIP particles outside obstacles
+ void projectOutside(FlagGrid &flags, BasicParticleSystem &flip);
+ static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ MovingObstacle *pbo = dynamic_cast<MovingObstacle *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "MovingObstacle::projectOutside", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ BasicParticleSystem &flip = *_args.getPtr<BasicParticleSystem>("flip", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->projectOutside(flags, flip);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "MovingObstacle::projectOutside", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("MovingObstacle::projectOutside", e.what());
+ return 0;
+ }
+ }
+
+ protected:
+ std::vector<Shape *> mShapes;
+ int mEmptyType;
+ int mID;
+ static int sIDcnt;
+ public:
+ PbArgs _args;
+}
+#define _C_MovingObstacle
+;
+
+} // namespace Manta
+#endif
diff --git a/extern/mantaflow/preprocessed/movingobs.h.reg.cpp b/extern/mantaflow/preprocessed/movingobs.h.reg.cpp
new file mode 100644
index 00000000000..b5a01a83c3b
--- /dev/null
+++ b/extern/mantaflow/preprocessed/movingobs.h.reg.cpp
@@ -0,0 +1,26 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "movingobs.h"
+namespace Manta {
+#ifdef _C_MovingObstacle
+static const Pb::Register _R_17("MovingObstacle", "MovingObstacle", "PbClass");
+template<> const char *Namify<MovingObstacle>::S = "MovingObstacle";
+static const Pb::Register _R_18("MovingObstacle", "MovingObstacle", MovingObstacle::_W_0);
+static const Pb::Register _R_19("MovingObstacle", "add", MovingObstacle::_W_1);
+static const Pb::Register _R_20("MovingObstacle", "moveLinear", MovingObstacle::_W_2);
+static const Pb::Register _R_21("MovingObstacle", "projectOutside", MovingObstacle::_W_3);
+#endif
+extern "C" {
+void PbRegister_file_17()
+{
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/multigrid.cpp b/extern/mantaflow/preprocessed/multigrid.cpp
new file mode 100644
index 00000000000..9e35c6f9368
--- /dev/null
+++ b/extern/mantaflow/preprocessed/multigrid.cpp
@@ -0,0 +1,1857 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Multigrid solver
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Copyright 2016, by Florian Ferstl (florian.ferstl.ff@gmail.com)
+ *
+ * This is an implementation of the solver developed by Dick et al. [1]
+ * without topology awareness (= vertex duplication on coarser levels). This
+ * simplification allows us to use regular grids for all levels of the multigrid
+ * hierarchy and works well for moderately complex domains.
+ *
+ * [1] Solving the Fluid Pressure Poisson Equation Using Multigrid-Evaluation
+ * and Improvements, C. Dick, M. Rogowsky, R. Westermann, IEEE TVCG 2015
+ *
+ ******************************************************************************/
+
+#include "multigrid.h"
+
+#define FOR_LVL(IDX, LVL) for (int IDX = 0; IDX < mb[LVL].size(); IDX++)
+
+#define FOR_VEC_MINMAX(VEC, MIN, MAX) \
+ Vec3i VEC; \
+ const Vec3i VEC##__min = (MIN), VEC##__max = (MAX); \
+ for (VEC.z = VEC##__min.z; VEC.z <= VEC##__max.z; VEC.z++) \
+ for (VEC.y = VEC##__min.y; VEC.y <= VEC##__max.y; VEC.y++) \
+ for (VEC.x = VEC##__min.x; VEC.x <= VEC##__max.x; VEC.x++)
+
+#define FOR_VECLIN_MINMAX(VEC, LIN, MIN, MAX) \
+ Vec3i VEC; \
+ int LIN = 0; \
+ const Vec3i VEC##__min = (MIN), VEC##__max = (MAX); \
+ for (VEC.z = VEC##__min.z; VEC.z <= VEC##__max.z; VEC.z++) \
+ for (VEC.y = VEC##__min.y; VEC.y <= VEC##__max.y; VEC.y++) \
+ for (VEC.x = VEC##__min.x; VEC.x <= VEC##__max.x; VEC.x++, LIN++)
+
+#define MG_TIMINGS(X)
+//#define MG_TIMINGS(X) X
+
+using namespace std;
+namespace Manta {
+
+// Helper class for calling mantaflow kernels with a specific number of threads
+class ThreadSize {
+ IndexInt s;
+
+ public:
+ ThreadSize(IndexInt _s)
+ {
+ s = _s;
+ }
+ IndexInt size()
+ {
+ return s;
+ }
+};
+
+// ----------------------------------------------------------------------------
+// Efficient min heap for <ID, key> pairs with 0<=ID<N and 0<=key<K
+// (elements are stored in K buckets, where each bucket is a doubly linked list).
+// - if K<<N, all ops are O(1) on avg (worst case O(K)).
+// - memory usage O(K+N): (K+N) * 3 * sizeof(int).
+class NKMinHeap {
+ private:
+ struct Entry {
+ int key, prev, next;
+ Entry() : key(-1), prev(-1), next(-1)
+ {
+ }
+ };
+
+ int mN, mK, mSize, mMinKey;
+
+ // Double linked lists of IDs, one for each bucket/key.
+ // The first K entries are the buckets' head pointers,
+ // and the last N entries correspond to the IDs.
+ std::vector<Entry> mEntries;
+
+ public:
+ NKMinHeap(int N, int K) : mN(N), mK(K), mSize(0), mMinKey(-1), mEntries(N + K)
+ {
+ }
+
+ int size()
+ {
+ return mSize;
+ }
+ int getKey(int ID)
+ {
+ return mEntries[mK + ID].key;
+ }
+
+ // Insert, decrease or increase key (or delete by setting key to -1)
+ void setKey(int ID, int key);
+
+ // peek min key (returns ID/key pair)
+ std::pair<int, int> peekMin();
+
+ // pop min key (returns ID/key pair)
+ std::pair<int, int> popMin();
+
+ void print(); // for debugging
+};
+
+void NKMinHeap::setKey(int ID, int key)
+{
+ assertMsg(0 <= ID && ID < mN, "NKMinHeap::setKey: ID out of range");
+ assertMsg(-1 <= key && key < mK, "NKMinHeap::setKey: key out of range");
+
+ const int kid = mK + ID;
+
+ if (mEntries[kid].key == key)
+ return; // nothing changes
+
+ // remove from old key-list if ID existed previously
+ if (mEntries[kid].key != -1) {
+ int pred = mEntries[kid].prev;
+ int succ = mEntries[kid].next; // can be -1
+
+ mEntries[pred].next = succ;
+ if (succ != -1)
+ mEntries[succ].prev = pred;
+
+ // if removed key was minimum key, mMinKey may need to be updated
+ int removedKey = mEntries[kid].key;
+ if (removedKey == mMinKey) {
+ if (mSize == 1) {
+ mMinKey = -1;
+ }
+ else {
+ for (; mMinKey < mK; mMinKey++) {
+ if (mEntries[mMinKey].next != -1)
+ break;
+ }
+ }
+ }
+
+ mSize--;
+ }
+
+ // set new key of ID
+ mEntries[kid].key = key;
+
+ if (key == -1) {
+ // finished if key was set to -1
+ mEntries[kid].next = mEntries[kid].prev = -1;
+ return;
+ }
+
+ // add key
+ mSize++;
+ if (mMinKey == -1)
+ mMinKey = key;
+ else
+ mMinKey = std::min(mMinKey, key);
+
+ // insert into new key-list (headed by mEntries[key])
+ int tmp = mEntries[key].next;
+
+ mEntries[key].next = kid;
+ mEntries[kid].prev = key;
+
+ mEntries[kid].next = tmp;
+ if (tmp != -1)
+ mEntries[tmp].prev = kid;
+}
+
+std::pair<int, int> NKMinHeap::peekMin()
+{
+ if (mSize == 0)
+ return std::pair<int, int>(-1, -1); // error
+
+ const int ID = mEntries[mMinKey].next - mK;
+ return std::pair<int, int>(ID, mMinKey);
+}
+
+std::pair<int, int> NKMinHeap::popMin()
+{
+ if (mSize == 0)
+ return std::pair<int, int>(-1, -1); // error
+
+ const int kid = mEntries[mMinKey].next;
+ const int ID = kid - mK;
+ const int key = mMinKey;
+
+ // remove from key-list
+ int pred = mEntries[kid].prev;
+ int succ = mEntries[kid].next; // can be -1
+
+ mEntries[pred].next = succ;
+ if (succ != -1)
+ mEntries[succ].prev = pred;
+
+ // remove entry
+ mEntries[kid] = Entry();
+ mSize--;
+
+ // update mMinKey
+ if (mSize == 0) {
+ mMinKey = -1;
+ }
+ else {
+ for (; mMinKey < mK; mMinKey++) {
+ if (mEntries[mMinKey].next != -1)
+ break;
+ }
+ }
+
+ // return result
+ return std::pair<int, int>(ID, key);
+}
+
+void NKMinHeap::print()
+{
+ std::cout << "Size: " << mSize << ", MinKey: " << mMinKey << std::endl;
+ for (int key = 0; key < mK; key++) {
+ if (mEntries[key].next != -1) {
+ std::cout << "Key " << key << ": ";
+ int kid = mEntries[key].next;
+ while (kid != -1) {
+ std::cout << kid - mK << " ";
+ kid = mEntries[kid].next;
+ }
+ std::cout << std::endl;
+ }
+ }
+ std::cout << std::endl;
+}
+
+// ----------------------------------------------------------------------------
+// GridMg methods
+//
+// Illustration of 27-point stencil indices
+// y | z = -1 z = 0 z = 1
+// ^ | 6 7 8, 15 16 17, 24 25 26
+// | | 3 4 5, 12 13 14, 21 22 23
+// o-> x | 0 1 2, 9 10 11, 18 19 20
+//
+// Symmetric storage with only 14 entries per vertex
+// y | z = -1 z = 0 z = 1
+// ^ | - - -, 2 3 4, 11 12 13
+// | | - - -, - 0 1, 8 9 10
+// o-> x | - - -, - - -, 5 6 7
+
+GridMg::GridMg(const Vec3i &gridSize)
+ : mNumPreSmooth(1),
+ mNumPostSmooth(1),
+ mCoarsestLevelAccuracy(Real(1E-8)),
+ mTrivialEquationScale(Real(1E-6)),
+ mIsASet(false),
+ mIsRhsSet(false)
+{
+ MG_TIMINGS(MuTime time;)
+
+ // 2D or 3D mode
+ mIs3D = (gridSize.z > 1);
+ mDim = mIs3D ? 3 : 2;
+ mStencilSize = mIs3D ? 14 : 5; // A has a full 27-point stencil on levels > 0
+ mStencilSize0 = mIs3D ? 4 : 3; // A has a 7-point stencil on level 0
+ mStencilMin = Vec3i(-1, -1, mIs3D ? -1 : 0);
+ mStencilMax = Vec3i(1, 1, mIs3D ? 1 : 0);
+
+ // Create level 0 (=original grid)
+ mSize.push_back(gridSize);
+ mPitch.push_back(Vec3i(1, mSize.back().x, mSize.back().x * mSize.back().y));
+ int n = mSize.back().x * mSize.back().y * mSize.back().z;
+
+ mA.push_back(std::vector<Real>(n * mStencilSize0));
+ mx.push_back(std::vector<Real>(n));
+ mb.push_back(std::vector<Real>(n));
+ mr.push_back(std::vector<Real>(n));
+ mType.push_back(std::vector<VertexType>(n));
+ mCGtmp1.push_back(std::vector<double>());
+ mCGtmp2.push_back(std::vector<double>());
+ mCGtmp3.push_back(std::vector<double>());
+ mCGtmp4.push_back(std::vector<double>());
+
+ debMsg("GridMg::GridMg level 0: " << mSize[0].x << " x " << mSize[0].y << " x " << mSize[0].z
+ << " x ",
+ 2);
+
+ // Create coarse levels >0
+ for (int l = 1; l <= 100; l++) {
+ if (mSize[l - 1].x <= 5 && mSize[l - 1].y <= 5 && mSize[l - 1].z <= 5)
+ break;
+ if (n <= 1000)
+ break;
+
+ mSize.push_back((mSize[l - 1] + 2) / 2);
+ mPitch.push_back(Vec3i(1, mSize.back().x, mSize.back().x * mSize.back().y));
+ n = mSize.back().x * mSize.back().y * mSize.back().z;
+
+ mA.push_back(std::vector<Real>(n * mStencilSize));
+ mx.push_back(std::vector<Real>(n));
+ mb.push_back(std::vector<Real>(n));
+ mr.push_back(std::vector<Real>(n));
+ mType.push_back(std::vector<VertexType>(n));
+ mCGtmp1.push_back(std::vector<double>());
+ mCGtmp2.push_back(std::vector<double>());
+ mCGtmp3.push_back(std::vector<double>());
+ mCGtmp4.push_back(std::vector<double>());
+
+ debMsg("GridMg::GridMg level " << l << ": " << mSize[l].x << " x " << mSize[l].y << " x "
+ << mSize[l].z << " x ",
+ 2);
+ }
+
+ // Additional memory for CG on coarsest level
+ mCGtmp1.back() = std::vector<double>(n);
+ mCGtmp2.back() = std::vector<double>(n);
+ mCGtmp3.back() = std::vector<double>(n);
+ mCGtmp4.back() = std::vector<double>(n);
+
+ MG_TIMINGS(debMsg("GridMg: Allocation done in " << time.update(), 1);)
+
+ // Precalculate coarsening paths:
+ // (V) <--restriction-- (U) <--A_{l-1}-- (W) <--interpolation-- (N)
+ Vec3i p7stencil[7] = {Vec3i(0, 0, 0),
+ Vec3i(-1, 0, 0),
+ Vec3i(1, 0, 0),
+ Vec3i(0, -1, 0),
+ Vec3i(0, 1, 0),
+ Vec3i(0, 0, -1),
+ Vec3i(0, 0, 1)};
+ Vec3i V(1, 1, 1); // reference coarse grid vertex at (1,1,1)
+ FOR_VEC_MINMAX(U, V * 2 + mStencilMin, V * 2 + mStencilMax)
+ {
+ for (int i = 0; i < 1 + 2 * mDim; i++) {
+ Vec3i W = U + p7stencil[i];
+ FOR_VEC_MINMAX(N, W / 2, (W + 1) / 2)
+ {
+ int s = dot(N, Vec3i(1, 3, 9));
+
+ if (s >= 13) {
+ CoarseningPath path;
+ path.N = N - 1; // offset of N on coarse grid
+ path.U = U - V * 2; // offset of U on fine grid
+ path.W = W - V * 2; // offset of W on fine grid
+ path.sc = s - 13; // stencil index corresponding to V<-N on coarse grid
+ path.sf = (i + 1) / 2; // stencil index corresponding to U<-W on coarse grid
+ path.inUStencil = (i % 2 == 0); // fine grid stencil entry stored at U or W?
+ path.rw = Real(1) /
+ Real(1 << ((U.x % 2) + (U.y % 2) + (U.z % 2))); // restriction weight V<-U
+ path.iw = Real(1) /
+ Real(1 << ((W.x % 2) + (W.y % 2) + (W.z % 2))); // interpolation weight W<-N
+ mCoarseningPaths0.push_back(path);
+ }
+ }
+ }
+ }
+
+ auto pathLess = [](const GridMg::CoarseningPath &p1, const GridMg::CoarseningPath &p2) {
+ if (p1.sc == p2.sc)
+ return dot(p1.U + 1, Vec3i(1, 3, 9)) < dot(p2.U + 1, Vec3i(1, 3, 9));
+ return p1.sc < p2.sc;
+ };
+ std::sort(mCoarseningPaths0.begin(), mCoarseningPaths0.end(), pathLess);
+}
+
+void GridMg::analyzeStencil(int v,
+ bool is3D,
+ bool &isStencilSumNonZero,
+ bool &isEquationTrivial) const
+{
+ Vec3i V = vecIdx(v, 0);
+
+ // collect stencil entries
+ Real A[7];
+ A[0] = mA[0][v * mStencilSize0 + 0];
+ A[1] = mA[0][v * mStencilSize0 + 1];
+ A[2] = mA[0][v * mStencilSize0 + 2];
+ A[3] = is3D ? mA[0][v * mStencilSize0 + 3] : Real(0);
+ A[4] = V.x != 0 ? mA[0][(v - mPitch[0].x) * mStencilSize0 + 1] : Real(0);
+ A[5] = V.y != 0 ? mA[0][(v - mPitch[0].y) * mStencilSize0 + 2] : Real(0);
+ A[6] = V.z != 0 && is3D ? mA[0][(v - mPitch[0].z) * mStencilSize0 + 3] : Real(0);
+
+ // compute sum of stencil entries
+ Real stencilMax = Real(0), stencilSum = Real(0);
+ for (int i = 0; i < 7; i++) {
+ stencilSum += A[i];
+ stencilMax = max(stencilMax, std::abs(A[i]));
+ }
+
+ // check if sum is numerically zero
+ isStencilSumNonZero = std::abs(stencilSum / stencilMax) > Real(1E-6);
+
+ // check for trivial equation (exact comparisons)
+ isEquationTrivial = A[0] == Real(1) && A[1] == Real(0) && A[2] == Real(0) && A[3] == Real(0) &&
+ A[4] == Real(0) && A[5] == Real(0) && A[6] == Real(0);
+}
+
+struct knCopyA : public KernelBase {
+ knCopyA(std::vector<Real> &sizeRef,
+ std::vector<Real> &A0,
+ int stencilSize0,
+ bool is3D,
+ const Grid<Real> *pA0,
+ const Grid<Real> *pAi,
+ const Grid<Real> *pAj,
+ const Grid<Real> *pAk)
+ : KernelBase(sizeRef.size()),
+ sizeRef(sizeRef),
+ A0(A0),
+ stencilSize0(stencilSize0),
+ is3D(is3D),
+ pA0(pA0),
+ pAi(pAi),
+ pAj(pAj),
+ pAk(pAk)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ std::vector<Real> &sizeRef,
+ std::vector<Real> &A0,
+ int stencilSize0,
+ bool is3D,
+ const Grid<Real> *pA0,
+ const Grid<Real> *pAi,
+ const Grid<Real> *pAj,
+ const Grid<Real> *pAk) const
+ {
+ A0[idx * stencilSize0 + 0] = (*pA0)[idx];
+ A0[idx * stencilSize0 + 1] = (*pAi)[idx];
+ A0[idx * stencilSize0 + 2] = (*pAj)[idx];
+ if (is3D)
+ A0[idx * stencilSize0 + 3] = (*pAk)[idx];
+ }
+ inline std::vector<Real> &getArg0()
+ {
+ return sizeRef;
+ }
+ typedef std::vector<Real> type0;
+ inline std::vector<Real> &getArg1()
+ {
+ return A0;
+ }
+ typedef std::vector<Real> type1;
+ inline int &getArg2()
+ {
+ return stencilSize0;
+ }
+ typedef int type2;
+ inline bool &getArg3()
+ {
+ return is3D;
+ }
+ typedef bool type3;
+ inline const Grid<Real> *getArg4()
+ {
+ return pA0;
+ }
+ typedef Grid<Real> type4;
+ inline const Grid<Real> *getArg5()
+ {
+ return pAi;
+ }
+ typedef Grid<Real> type5;
+ inline const Grid<Real> *getArg6()
+ {
+ return pAj;
+ }
+ typedef Grid<Real> type6;
+ inline const Grid<Real> *getArg7()
+ {
+ return pAk;
+ }
+ typedef Grid<Real> type7;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCopyA ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, sizeRef, A0, stencilSize0, is3D, pA0, pAi, pAj, pAk);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<Real> &sizeRef;
+ std::vector<Real> &A0;
+ int stencilSize0;
+ bool is3D;
+ const Grid<Real> *pA0;
+ const Grid<Real> *pAi;
+ const Grid<Real> *pAj;
+ const Grid<Real> *pAk;
+};
+
+struct knActivateVertices : public KernelBase {
+ knActivateVertices(std::vector<GridMg::VertexType> &type_0,
+ std::vector<Real> &A0,
+ bool &nonZeroStencilSumFound,
+ bool &trivialEquationsFound,
+ const GridMg &mg)
+ : KernelBase(type_0.size()),
+ type_0(type_0),
+ A0(A0),
+ nonZeroStencilSumFound(nonZeroStencilSumFound),
+ trivialEquationsFound(trivialEquationsFound),
+ mg(mg)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ std::vector<GridMg::VertexType> &type_0,
+ std::vector<Real> &A0,
+ bool &nonZeroStencilSumFound,
+ bool &trivialEquationsFound,
+ const GridMg &mg) const
+ {
+ // active vertices on level 0 are vertices with non-zero diagonal entry in A
+ type_0[idx] = GridMg::vtInactive;
+
+ if (mg.mA[0][idx * mg.mStencilSize0 + 0] != Real(0)) {
+ type_0[idx] = GridMg::vtActive;
+
+ bool isStencilSumNonZero = false, isEquationTrivial = false;
+ mg.analyzeStencil(int(idx), mg.mIs3D, isStencilSumNonZero, isEquationTrivial);
+
+ // Note: nonZeroStencilSumFound and trivialEquationsFound are only
+ // changed from false to true, and hence there are no race conditions.
+ if (isStencilSumNonZero)
+ nonZeroStencilSumFound = true;
+
+ // scale down trivial equations
+ if (isEquationTrivial) {
+ type_0[idx] = GridMg::vtActiveTrivial;
+ A0[idx * mg.mStencilSize0 + 0] *= mg.mTrivialEquationScale;
+ trivialEquationsFound = true;
+ };
+ }
+ }
+ inline std::vector<GridMg::VertexType> &getArg0()
+ {
+ return type_0;
+ }
+ typedef std::vector<GridMg::VertexType> type0;
+ inline std::vector<Real> &getArg1()
+ {
+ return A0;
+ }
+ typedef std::vector<Real> type1;
+ inline bool &getArg2()
+ {
+ return nonZeroStencilSumFound;
+ }
+ typedef bool type2;
+ inline bool &getArg3()
+ {
+ return trivialEquationsFound;
+ }
+ typedef bool type3;
+ inline const GridMg &getArg4()
+ {
+ return mg;
+ }
+ typedef GridMg type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knActivateVertices ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, type_0, A0, nonZeroStencilSumFound, trivialEquationsFound, mg);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<GridMg::VertexType> &type_0;
+ std::vector<Real> &A0;
+ bool &nonZeroStencilSumFound;
+ bool &trivialEquationsFound;
+ const GridMg &mg;
+};
+
+void GridMg::setA(const Grid<Real> *pA0,
+ const Grid<Real> *pAi,
+ const Grid<Real> *pAj,
+ const Grid<Real> *pAk)
+{
+ MG_TIMINGS(MuTime time;)
+
+ // Copy level 0
+ knCopyA(mx[0], mA[0], mStencilSize0, mIs3D, pA0, pAi, pAj, pAk);
+
+ // Determine active vertices and scale trivial equations
+ bool nonZeroStencilSumFound = false;
+ bool trivialEquationsFound = false;
+
+ knActivateVertices(mType[0], mA[0], nonZeroStencilSumFound, trivialEquationsFound, *this);
+
+ if (trivialEquationsFound)
+ debMsg("GridMg::setA: Found at least one trivial equation", 2);
+
+ // Sanity check: if all rows of A sum up to 0 --> A doesn't have full rank (opposite direction
+ // isn't necessarily true)
+ if (!nonZeroStencilSumFound)
+ debMsg(
+ "GridMg::setA: Found constant mode: A*1=0! A does not have full rank and multigrid may "
+ "not converge. (forgot to fix a pressure value?)",
+ 1);
+
+ // Create coarse grids and operators on levels >0
+ for (int l = 1; l < mA.size(); l++) {
+ MG_TIMINGS(time.get();)
+ genCoarseGrid(l);
+ MG_TIMINGS(debMsg("GridMg: Generated level " << l << " in " << time.update(), 1);)
+ genCoraseGridOperator(l);
+ MG_TIMINGS(debMsg("GridMg: Generated operator " << l << " in " << time.update(), 1);)
+ }
+
+ mIsASet = true;
+ mIsRhsSet = false; // invalidate rhs
+}
+
+struct knSetRhs : public KernelBase {
+ knSetRhs(std::vector<Real> &b, const Grid<Real> &rhs, const GridMg &mg)
+ : KernelBase(b.size()), b(b), rhs(rhs), mg(mg)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, std::vector<Real> &b, const Grid<Real> &rhs, const GridMg &mg) const
+ {
+ b[idx] = rhs[idx];
+
+ // scale down trivial equations
+ if (mg.mType[0][idx] == GridMg::vtActiveTrivial) {
+ b[idx] *= mg.mTrivialEquationScale;
+ };
+ }
+ inline std::vector<Real> &getArg0()
+ {
+ return b;
+ }
+ typedef std::vector<Real> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return rhs;
+ }
+ typedef Grid<Real> type1;
+ inline const GridMg &getArg2()
+ {
+ return mg;
+ }
+ typedef GridMg type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetRhs ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, b, rhs, mg);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<Real> &b;
+ const Grid<Real> &rhs;
+ const GridMg &mg;
+};
+
+void GridMg::setRhs(const Grid<Real> &rhs)
+{
+ assertMsg(mIsASet, "GridMg::setRhs Error: A has not been set.");
+
+ knSetRhs(mb[0], rhs, *this);
+
+ mIsRhsSet = true;
+}
+
+template<class T> struct knSet : public KernelBase {
+ knSet(std::vector<T> &data, T value) : KernelBase(data.size()), data(data), value(value)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, std::vector<T> &data, T value) const
+ {
+ data[idx] = value;
+ }
+ inline std::vector<T> &getArg0()
+ {
+ return data;
+ }
+ typedef std::vector<T> type0;
+ inline T &getArg1()
+ {
+ return value;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSet ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, data, value);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<T> &data;
+ T value;
+};
+
+template<class T> struct knCopyToVector : public KernelBase {
+ knCopyToVector(std::vector<T> &dst, const Grid<T> &src)
+ : KernelBase(dst.size()), dst(dst), src(src)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, std::vector<T> &dst, const Grid<T> &src) const
+ {
+ dst[idx] = src[idx];
+ }
+ inline std::vector<T> &getArg0()
+ {
+ return dst;
+ }
+ typedef std::vector<T> type0;
+ inline const Grid<T> &getArg1()
+ {
+ return src;
+ }
+ typedef Grid<T> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCopyToVector ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, dst, src);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<T> &dst;
+ const Grid<T> &src;
+};
+
+template<class T> struct knCopyToGrid : public KernelBase {
+ knCopyToGrid(const std::vector<T> &src, Grid<T> &dst)
+ : KernelBase(src.size()), src(src), dst(dst)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const std::vector<T> &src, Grid<T> &dst) const
+ {
+ dst[idx] = src[idx];
+ }
+ inline const std::vector<T> &getArg0()
+ {
+ return src;
+ }
+ typedef std::vector<T> type0;
+ inline Grid<T> &getArg1()
+ {
+ return dst;
+ }
+ typedef Grid<T> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCopyToGrid ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, src, dst);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const std::vector<T> &src;
+ Grid<T> &dst;
+};
+
+template<class T> struct knAddAssign : public KernelBase {
+ knAddAssign(std::vector<T> &dst, const std::vector<T> &src)
+ : KernelBase(dst.size()), dst(dst), src(src)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, std::vector<T> &dst, const std::vector<T> &src) const
+ {
+ dst[idx] += src[idx];
+ }
+ inline std::vector<T> &getArg0()
+ {
+ return dst;
+ }
+ typedef std::vector<T> type0;
+ inline const std::vector<T> &getArg1()
+ {
+ return src;
+ }
+ typedef std::vector<T> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knAddAssign ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, dst, src);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<T> &dst;
+ const std::vector<T> &src;
+};
+
+Real GridMg::doVCycle(Grid<Real> &dst, const Grid<Real> *src)
+{
+ MG_TIMINGS(MuTime timeSmooth; MuTime timeCG; MuTime timeI; MuTime timeR; MuTime timeTotal;
+ MuTime time;)
+ MG_TIMINGS(timeSmooth.clear(); timeCG.clear(); timeI.clear(); timeR.clear();)
+
+ assertMsg(mIsASet && mIsRhsSet, "GridMg::doVCycle Error: A and/or rhs have not been set.");
+
+ const int maxLevel = int(mA.size()) - 1;
+
+ if (src) {
+ knCopyToVector<Real>(mx[0], *src);
+ }
+ else {
+ knSet<Real>(mx[0], Real(0));
+ }
+
+ for (int l = 0; l < maxLevel; l++) {
+ MG_TIMINGS(time.update();)
+ for (int i = 0; i < mNumPreSmooth; i++) {
+ smoothGS(l, false);
+ }
+
+ MG_TIMINGS(timeSmooth += time.update();)
+
+ calcResidual(l);
+ restrict(l + 1, mr[l], mb[l + 1]);
+
+ knSet<Real>(mx[l + 1], Real(0));
+
+ MG_TIMINGS(timeR += time.update();)
+ }
+
+ MG_TIMINGS(time.update();)
+ solveCG(maxLevel);
+ MG_TIMINGS(timeCG += time.update();)
+
+ for (int l = maxLevel - 1; l >= 0; l--) {
+ MG_TIMINGS(time.update();)
+ interpolate(l, mx[l + 1], mr[l]);
+
+ knAddAssign<Real>(mx[l], mr[l]);
+
+ MG_TIMINGS(timeI += time.update();)
+
+ for (int i = 0; i < mNumPostSmooth; i++) {
+ smoothGS(l, true);
+ }
+ MG_TIMINGS(timeSmooth += time.update();)
+ }
+
+ calcResidual(0);
+ Real res = calcResidualNorm(0);
+
+ knCopyToGrid<Real>(mx[0], dst);
+
+ MG_TIMINGS(debMsg("GridMg: Finished VCycle in "
+ << timeTotal.update() << " (smoothing: " << timeSmooth
+ << ", CG: " << timeCG << ", R: " << timeR << ", I: " << timeI << ")",
+ 1);)
+
+ return res;
+}
+
+struct knActivateCoarseVertices : public KernelBase {
+ knActivateCoarseVertices(std::vector<GridMg::VertexType> &type, int unused)
+ : KernelBase(type.size()), type(type), unused(unused)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, std::vector<GridMg::VertexType> &type, int unused) const
+ {
+ // set all remaining 'free' vertices to 'removed',
+ if (type[idx] == GridMg::vtFree)
+ type[idx] = GridMg::vtRemoved;
+
+ // then convert 'zero' vertices to 'active' and 'removed' vertices to 'inactive'
+ if (type[idx] == GridMg::vtZero)
+ type[idx] = GridMg::vtActive;
+ if (type[idx] == GridMg::vtRemoved)
+ type[idx] = GridMg::vtInactive;
+ }
+ inline std::vector<GridMg::VertexType> &getArg0()
+ {
+ return type;
+ }
+ typedef std::vector<GridMg::VertexType> type0;
+ inline int &getArg1()
+ {
+ return unused;
+ }
+ typedef int type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knActivateCoarseVertices ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, type, unused);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<GridMg::VertexType> &type;
+ int unused;
+};
+
+// Determine active cells on coarse level l from active cells on fine level l-1
+// while ensuring a full-rank interpolation operator (see Section 3.3 in [1]).
+void GridMg::genCoarseGrid(int l)
+{
+ // AF_Free: unused/untouched vertices
+ // AF_Zero: vertices selected for coarser level
+ // AF_Removed: vertices removed from coarser level
+ enum activeFlags : char { AF_Removed = 0, AF_Zero = 1, AF_Free = 2 };
+
+ // initialize all coarse vertices with 'free'
+ knSet<VertexType>(mType[l], vtFree);
+
+ // initialize min heap of (ID: fine grid vertex, key: #free interpolation vertices) pairs
+ NKMinHeap heap(int(mb[l - 1].size()),
+ mIs3D ? 9 : 5); // max 8 (or 4 in 2D) free interpolation vertices
+
+ FOR_LVL(v, l - 1)
+ {
+ if (mType[l - 1][v] != vtInactive) {
+ Vec3i V = vecIdx(v, l - 1);
+ int fiv = 1 << ((V.x % 2) + (V.y % 2) + (V.z % 2));
+ heap.setKey(v, fiv);
+ }
+ }
+
+ // process fine vertices in heap consecutively, always choosing the vertex with
+ // the currently smallest number of free interpolation vertices
+ while (heap.size() > 0) {
+ int v = heap.popMin().first;
+ Vec3i V = vecIdx(v, l - 1);
+
+ // loop over associated interpolation vertices of V on coarse level l:
+ // the first encountered 'free' vertex is set to 'zero',
+ // all remaining 'free' vertices are set to 'removed'.
+ bool vdone = false;
+
+ FOR_VEC_MINMAX(I, V / 2, (V + 1) / 2)
+ {
+ int i = linIdx(I, l);
+
+ if (mType[l][i] == vtFree) {
+ if (vdone) {
+ mType[l][i] = vtRemoved;
+ }
+ else {
+ mType[l][i] = vtZero;
+ vdone = true;
+ }
+
+ // update #free interpolation vertices in heap:
+ // loop over all associated restriction vertices of I on fine level l-1
+ FOR_VEC_MINMAX(R, vmax(0, I * 2 - 1), vmin(mSize[l - 1] - 1, I * 2 + 1))
+ {
+ int r = linIdx(R, l - 1);
+ int key = heap.getKey(r);
+
+ if (key > 1) {
+ heap.setKey(r, key - 1);
+ } // decrease key of r
+ else if (key > -1) {
+ heap.setKey(r, -1);
+ } // removes r from heap
+ }
+ }
+ }
+ }
+
+ knActivateCoarseVertices(mType[l], 0);
+}
+
+struct knGenCoarseGridOperator : public KernelBase {
+ knGenCoarseGridOperator(std::vector<Real> &sizeRef,
+ std::vector<Real> &A,
+ int l,
+ const GridMg &mg)
+ : KernelBase(sizeRef.size()), sizeRef(sizeRef), A(A), l(l), mg(mg)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ std::vector<Real> &sizeRef,
+ std::vector<Real> &A,
+ int l,
+ const GridMg &mg) const
+ {
+ if (mg.mType[l][idx] == GridMg::vtInactive)
+ return;
+
+ for (int i = 0; i < mg.mStencilSize; i++) {
+ A[idx * mg.mStencilSize + i] = Real(0);
+ } // clear stencil
+
+ Vec3i V = mg.vecIdx(int(idx), l);
+
+ // Calculate the stencil of A_l at V by considering all vertex paths of the form:
+ // (V) <--restriction-- (U) <--A_{l-1}-- (W) <--interpolation-- (N)
+ // V and N are vertices on the coarse grid level l,
+ // U and W are vertices on the fine grid level l-1.
+
+ if (l == 1) {
+ // loop over precomputed paths
+ for (auto it = mg.mCoarseningPaths0.begin(); it != mg.mCoarseningPaths0.end(); it++) {
+ Vec3i N = V + it->N;
+ int n = mg.linIdx(N, l);
+ if (!mg.inGrid(N, l) || mg.mType[l][n] == GridMg::vtInactive)
+ continue;
+
+ Vec3i U = V * 2 + it->U;
+ int u = mg.linIdx(U, l - 1);
+ if (!mg.inGrid(U, l - 1) || mg.mType[l - 1][u] == GridMg::vtInactive)
+ continue;
+
+ Vec3i W = V * 2 + it->W;
+ int w = mg.linIdx(W, l - 1);
+ if (!mg.inGrid(W, l - 1) || mg.mType[l - 1][w] == GridMg::vtInactive)
+ continue;
+
+ if (it->inUStencil) {
+ A[idx * mg.mStencilSize + it->sc] += it->rw *
+ mg.mA[l - 1][u * mg.mStencilSize0 + it->sf] *
+ it->iw;
+ }
+ else {
+ A[idx * mg.mStencilSize + it->sc] += it->rw *
+ mg.mA[l - 1][w * mg.mStencilSize0 + it->sf] *
+ it->iw;
+ }
+ }
+ }
+ else {
+ // l > 1:
+ // loop over restriction vertices U on level l-1 associated with V
+ FOR_VEC_MINMAX(U, vmax(0, V * 2 - 1), vmin(mg.mSize[l - 1] - 1, V * 2 + 1))
+ {
+ int u = mg.linIdx(U, l - 1);
+ if (mg.mType[l - 1][u] == GridMg::vtInactive)
+ continue;
+
+ // restriction weight
+ Real rw = Real(1) / Real(1 << ((U.x % 2) + (U.y % 2) + (U.z % 2)));
+
+ // loop over all stencil neighbors N of V on level l that can be reached via restriction to
+ // U
+ FOR_VEC_MINMAX(N, (U - 1) / 2, vmin(mg.mSize[l] - 1, (U + 2) / 2))
+ {
+ int n = mg.linIdx(N, l);
+ if (mg.mType[l][n] == GridMg::vtInactive)
+ continue;
+
+ // stencil entry at V associated to N (coarse grid level l)
+ Vec3i SC = N - V + mg.mStencilMax;
+ int sc = SC.x + 3 * SC.y + 9 * SC.z;
+ if (sc < mg.mStencilSize - 1)
+ continue;
+
+ // loop over all vertices W which are in the stencil of A_{l-1} at U
+ // and which interpolate from N
+ FOR_VEC_MINMAX(W,
+ vmax(0, vmax(U - 1, N * 2 - 1)),
+ vmin(mg.mSize[l - 1] - 1, vmin(U + 1, N * 2 + 1)))
+ {
+ int w = mg.linIdx(W, l - 1);
+ if (mg.mType[l - 1][w] == GridMg::vtInactive)
+ continue;
+
+ // stencil entry at U associated to W (fine grid level l-1)
+ Vec3i SF = W - U + mg.mStencilMax;
+ int sf = SF.x + 3 * SF.y + 9 * SF.z;
+
+ Real iw = Real(1) /
+ Real(1 << ((W.x % 2) + (W.y % 2) + (W.z % 2))); // interpolation weight
+
+ if (sf < mg.mStencilSize) {
+ A[idx * mg.mStencilSize + sc - mg.mStencilSize + 1] +=
+ rw * mg.mA[l - 1][w * mg.mStencilSize + mg.mStencilSize - 1 - sf] * iw;
+ }
+ else {
+ A[idx * mg.mStencilSize + sc - mg.mStencilSize + 1] +=
+ rw * mg.mA[l - 1][u * mg.mStencilSize + sf - mg.mStencilSize + 1] * iw;
+ }
+ }
+ }
+ }
+ }
+ }
+ inline std::vector<Real> &getArg0()
+ {
+ return sizeRef;
+ }
+ typedef std::vector<Real> type0;
+ inline std::vector<Real> &getArg1()
+ {
+ return A;
+ }
+ typedef std::vector<Real> type1;
+ inline int &getArg2()
+ {
+ return l;
+ }
+ typedef int type2;
+ inline const GridMg &getArg3()
+ {
+ return mg;
+ }
+ typedef GridMg type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knGenCoarseGridOperator ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, sizeRef, A, l, mg);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<Real> &sizeRef;
+ std::vector<Real> &A;
+ int l;
+ const GridMg &mg;
+};
+
+// Calculate A_l on coarse level l from A_{l-1} on fine level l-1 using
+// Galerkin-based coarsening, i.e., compute A_l = R * A_{l-1} * I.
+void GridMg::genCoraseGridOperator(int l)
+{
+ // for each coarse grid vertex V
+ knGenCoarseGridOperator(mx[l], mA[l], l, *this);
+}
+
+struct knSmoothColor : public KernelBase {
+ knSmoothColor(ThreadSize &numBlocks,
+ std::vector<Real> &x,
+ const Vec3i &blockSize,
+ const std::vector<Vec3i> &colorOffs,
+ int l,
+ const GridMg &mg)
+ : KernelBase(numBlocks.size()),
+ numBlocks(numBlocks),
+ x(x),
+ blockSize(blockSize),
+ colorOffs(colorOffs),
+ l(l),
+ mg(mg)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ ThreadSize &numBlocks,
+ std::vector<Real> &x,
+ const Vec3i &blockSize,
+ const std::vector<Vec3i> &colorOffs,
+ int l,
+ const GridMg &mg) const
+ {
+ Vec3i blockOff(int(idx) % blockSize.x,
+ (int(idx) % (blockSize.x * blockSize.y)) / blockSize.x,
+ int(idx) / (blockSize.x * blockSize.y));
+
+ for (int off = 0; off < colorOffs.size(); off++) {
+
+ Vec3i V = blockOff * 2 + colorOffs[off];
+ if (!mg.inGrid(V, l))
+ continue;
+
+ const int v = mg.linIdx(V, l);
+ if (mg.mType[l][v] == GridMg::vtInactive)
+ continue;
+
+ Real sum = mg.mb[l][v];
+
+ if (l == 0) {
+ int n;
+ for (int d = 0; d < mg.mDim; d++) {
+ if (V[d] > 0) {
+ n = v - mg.mPitch[0][d];
+ sum -= mg.mA[0][n * mg.mStencilSize0 + d + 1] * mg.mx[0][n];
+ }
+ if (V[d] < mg.mSize[0][d] - 1) {
+ n = v + mg.mPitch[0][d];
+ sum -= mg.mA[0][v * mg.mStencilSize0 + d + 1] * mg.mx[0][n];
+ }
+ }
+
+ x[v] = sum / mg.mA[0][v * mg.mStencilSize0 + 0];
+ }
+ else {
+ FOR_VECLIN_MINMAX(S, s, mg.mStencilMin, mg.mStencilMax)
+ {
+ if (s == mg.mStencilSize - 1)
+ continue;
+
+ Vec3i N = V + S;
+ int n = mg.linIdx(N, l);
+
+ if (mg.inGrid(N, l) && mg.mType[l][n] != GridMg::vtInactive) {
+ if (s < mg.mStencilSize) {
+ sum -= mg.mA[l][n * mg.mStencilSize + mg.mStencilSize - 1 - s] * mg.mx[l][n];
+ }
+ else {
+ sum -= mg.mA[l][v * mg.mStencilSize + s - mg.mStencilSize + 1] * mg.mx[l][n];
+ }
+ }
+ }
+
+ x[v] = sum / mg.mA[l][v * mg.mStencilSize + 0];
+ }
+ }
+ }
+ inline ThreadSize &getArg0()
+ {
+ return numBlocks;
+ }
+ typedef ThreadSize type0;
+ inline std::vector<Real> &getArg1()
+ {
+ return x;
+ }
+ typedef std::vector<Real> type1;
+ inline const Vec3i &getArg2()
+ {
+ return blockSize;
+ }
+ typedef Vec3i type2;
+ inline const std::vector<Vec3i> &getArg3()
+ {
+ return colorOffs;
+ }
+ typedef std::vector<Vec3i> type3;
+ inline int &getArg4()
+ {
+ return l;
+ }
+ typedef int type4;
+ inline const GridMg &getArg5()
+ {
+ return mg;
+ }
+ typedef GridMg type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSmoothColor ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, numBlocks, x, blockSize, colorOffs, l, mg);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ThreadSize &numBlocks;
+ std::vector<Real> &x;
+ const Vec3i &blockSize;
+ const std::vector<Vec3i> &colorOffs;
+ int l;
+ const GridMg &mg;
+};
+
+void GridMg::smoothGS(int l, bool reversedOrder)
+{
+ // Multicolor Gauss-Seidel with two colors for the 5/7-point stencil on level 0
+ // and with four/eight colors for the 9/27-point stencil on levels > 0
+ std::vector<std::vector<Vec3i>> colorOffs;
+ const Vec3i a[8] = {Vec3i(0, 0, 0),
+ Vec3i(1, 0, 0),
+ Vec3i(0, 1, 0),
+ Vec3i(1, 1, 0),
+ Vec3i(0, 0, 1),
+ Vec3i(1, 0, 1),
+ Vec3i(0, 1, 1),
+ Vec3i(1, 1, 1)};
+ if (mIs3D) {
+ if (l == 0)
+ colorOffs = {{a[0], a[3], a[5], a[6]}, {a[1], a[2], a[4], a[7]}};
+ else
+ colorOffs = {{a[0]}, {a[1]}, {a[2]}, {a[3]}, {a[4]}, {a[5]}, {a[6]}, {a[7]}};
+ }
+ else {
+ if (l == 0)
+ colorOffs = {{a[0], a[3]}, {a[1], a[2]}};
+ else
+ colorOffs = {{a[0]}, {a[1]}, {a[2]}, {a[3]}};
+ }
+
+ // Divide grid into 2x2 blocks for parallelization
+ Vec3i blockSize = (mSize[l] + 1) / 2;
+ ThreadSize numBlocks(blockSize.x * blockSize.y * blockSize.z);
+
+ for (int c = 0; c < colorOffs.size(); c++) {
+ int color = reversedOrder ? int(colorOffs.size()) - 1 - c : c;
+
+ knSmoothColor(numBlocks, mx[l], blockSize, colorOffs[color], l, *this);
+ }
+}
+
+struct knCalcResidual : public KernelBase {
+ knCalcResidual(std::vector<Real> &r, int l, const GridMg &mg)
+ : KernelBase(r.size()), r(r), l(l), mg(mg)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, std::vector<Real> &r, int l, const GridMg &mg) const
+ {
+ if (mg.mType[l][idx] == GridMg::vtInactive)
+ return;
+
+ Vec3i V = mg.vecIdx(int(idx), l);
+
+ Real sum = mg.mb[l][idx];
+
+ if (l == 0) {
+ int n;
+ for (int d = 0; d < mg.mDim; d++) {
+ if (V[d] > 0) {
+ n = int(idx) - mg.mPitch[0][d];
+ sum -= mg.mA[0][n * mg.mStencilSize0 + d + 1] * mg.mx[0][n];
+ }
+ if (V[d] < mg.mSize[0][d] - 1) {
+ n = int(idx) + mg.mPitch[0][d];
+ sum -= mg.mA[0][idx * mg.mStencilSize0 + d + 1] * mg.mx[0][n];
+ }
+ }
+ sum -= mg.mA[0][idx * mg.mStencilSize0 + 0] * mg.mx[0][idx];
+ }
+ else {
+ FOR_VECLIN_MINMAX(S, s, mg.mStencilMin, mg.mStencilMax)
+ {
+ Vec3i N = V + S;
+ int n = mg.linIdx(N, l);
+
+ if (mg.inGrid(N, l) && mg.mType[l][n] != GridMg::vtInactive) {
+ if (s < mg.mStencilSize) {
+ sum -= mg.mA[l][n * mg.mStencilSize + mg.mStencilSize - 1 - s] * mg.mx[l][n];
+ }
+ else {
+ sum -= mg.mA[l][idx * mg.mStencilSize + s - mg.mStencilSize + 1] * mg.mx[l][n];
+ }
+ }
+ }
+ }
+
+ r[idx] = sum;
+ }
+ inline std::vector<Real> &getArg0()
+ {
+ return r;
+ }
+ typedef std::vector<Real> type0;
+ inline int &getArg1()
+ {
+ return l;
+ }
+ typedef int type1;
+ inline const GridMg &getArg2()
+ {
+ return mg;
+ }
+ typedef GridMg type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCalcResidual ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, r, l, mg);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<Real> &r;
+ int l;
+ const GridMg &mg;
+};
+
+void GridMg::calcResidual(int l)
+{
+ knCalcResidual(mr[l], l, *this);
+}
+
+struct knResidualNormSumSqr : public KernelBase {
+ knResidualNormSumSqr(const vector<Real> &r, int l, const GridMg &mg)
+ : KernelBase(r.size()), r(r), l(l), mg(mg), result(Real(0))
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const vector<Real> &r, int l, const GridMg &mg, Real &result)
+ {
+ if (mg.mType[l][idx] == GridMg::vtInactive)
+ return;
+
+ result += r[idx] * r[idx];
+ }
+ inline operator Real()
+ {
+ return result;
+ }
+ inline Real &getRet()
+ {
+ return result;
+ }
+ inline const vector<Real> &getArg0()
+ {
+ return r;
+ }
+ typedef vector<Real> type0;
+ inline int &getArg1()
+ {
+ return l;
+ }
+ typedef int type1;
+ inline const GridMg &getArg2()
+ {
+ return mg;
+ }
+ typedef GridMg type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knResidualNormSumSqr ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, r, l, mg, result);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ knResidualNormSumSqr(knResidualNormSumSqr &o, tbb::split)
+ : KernelBase(o), r(o.r), l(o.l), mg(o.mg), result(Real(0))
+ {
+ }
+ void join(const knResidualNormSumSqr &o)
+ {
+ result += o.result;
+ }
+ const vector<Real> &r;
+ int l;
+ const GridMg &mg;
+ Real result;
+};
+;
+
+Real GridMg::calcResidualNorm(int l)
+{
+ Real res = knResidualNormSumSqr(mr[l], l, *this);
+
+ return std::sqrt(res);
+}
+
+// Standard conjugate gradients with Jacobi preconditioner
+// Notes: Always run at double precision. Not parallelized since
+// coarsest level is assumed to be small.
+void GridMg::solveCG(int l)
+{
+ auto applyAStencil = [this](int v, int l, const std::vector<double> &vec) -> double {
+ Vec3i V = vecIdx(v, l);
+
+ double sum = 0;
+
+ if (l == 0) {
+ int n;
+ for (int d = 0; d < mDim; d++) {
+ if (V[d] > 0) {
+ n = v - mPitch[0][d];
+ sum += mA[0][n * mStencilSize0 + d + 1] * vec[n];
+ }
+ if (V[d] < mSize[0][d] - 1) {
+ n = v + mPitch[0][d];
+ sum += mA[0][v * mStencilSize0 + d + 1] * vec[n];
+ }
+ }
+ sum += mA[0][v * mStencilSize0 + 0] * vec[v];
+ }
+ else {
+ FOR_VECLIN_MINMAX(S, s, mStencilMin, mStencilMax)
+ {
+ Vec3i N = V + S;
+ int n = linIdx(N, l);
+
+ if (inGrid(N, l) && mType[l][n] != vtInactive) {
+ if (s < mStencilSize) {
+ sum += mA[l][n * mStencilSize + mStencilSize - 1 - s] * vec[n];
+ }
+ else {
+ sum += mA[l][v * mStencilSize + s - mStencilSize + 1] * vec[n];
+ }
+ }
+ }
+ }
+
+ return sum;
+ };
+
+ std::vector<double> &z = mCGtmp1[l];
+ std::vector<double> &p = mCGtmp2[l];
+ std::vector<double> &x = mCGtmp3[l];
+ std::vector<double> &r = mCGtmp4[l];
+
+ // Initialization:
+ double alphaTop = 0;
+ double initialResidual = 0;
+
+ FOR_LVL(v, l)
+ {
+ x[v] = mx[l][v];
+ }
+
+ FOR_LVL(v, l)
+ {
+ if (mType[l][v] == vtInactive)
+ continue;
+
+ r[v] = mb[l][v] - applyAStencil(v, l, x);
+ if (l == 0) {
+ z[v] = r[v] / mA[0][v * mStencilSize0 + 0];
+ }
+ else {
+ z[v] = r[v] / mA[l][v * mStencilSize + 0];
+ }
+
+ initialResidual += r[v] * r[v];
+ p[v] = z[v];
+ alphaTop += r[v] * z[v];
+ }
+
+ initialResidual = std::sqrt(initialResidual);
+
+ int iter = 0;
+ const int maxIter = 10000;
+ double residual = -1;
+
+ // CG iterations
+ for (; iter < maxIter && initialResidual > 1E-12; iter++) {
+ double alphaBot = 0;
+
+ FOR_LVL(v, l)
+ {
+ if (mType[l][v] == vtInactive)
+ continue;
+
+ z[v] = applyAStencil(v, l, p);
+ alphaBot += p[v] * z[v];
+ }
+
+ double alpha = alphaTop / alphaBot;
+
+ double alphaTopNew = 0;
+ residual = 0;
+
+ FOR_LVL(v, l)
+ {
+ if (mType[l][v] == vtInactive)
+ continue;
+
+ x[v] += alpha * p[v];
+ r[v] -= alpha * z[v];
+ residual += r[v] * r[v];
+ if (l == 0)
+ z[v] = r[v] / mA[0][v * mStencilSize0 + 0];
+ else
+ z[v] = r[v] / mA[l][v * mStencilSize + 0];
+ alphaTopNew += r[v] * z[v];
+ }
+
+ residual = std::sqrt(residual);
+
+ if (residual / initialResidual < mCoarsestLevelAccuracy)
+ break;
+
+ double beta = alphaTopNew / alphaTop;
+ alphaTop = alphaTopNew;
+
+ FOR_LVL(v, l)
+ {
+ p[v] = z[v] + beta * p[v];
+ }
+ debMsg("GridMg::solveCG i=" << iter << " rel-residual=" << (residual / initialResidual), 5);
+ }
+
+ FOR_LVL(v, l)
+ {
+ mx[l][v] = Real(x[v]);
+ }
+
+ if (iter == maxIter) {
+ debMsg("GridMg::solveCG Warning: Reached maximum number of CG iterations", 1);
+ }
+ else {
+ debMsg("GridMg::solveCG Info: Reached residual " << residual << " in " << iter
+ << " iterations",
+ 2);
+ }
+}
+
+struct knRestrict : public KernelBase {
+ knRestrict(std::vector<Real> &dst, const std::vector<Real> &src, int l_dst, const GridMg &mg)
+ : KernelBase(dst.size()), dst(dst), src(src), l_dst(l_dst), mg(mg)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ std::vector<Real> &dst,
+ const std::vector<Real> &src,
+ int l_dst,
+ const GridMg &mg) const
+ {
+ if (mg.mType[l_dst][idx] == GridMg::vtInactive)
+ return;
+
+ const int l_src = l_dst - 1;
+
+ // Coarse grid vertex
+ Vec3i V = mg.vecIdx(int(idx), l_dst);
+
+ Real sum = Real(0);
+
+ FOR_VEC_MINMAX(R, vmax(0, V * 2 - 1), vmin(mg.mSize[l_src] - 1, V * 2 + 1))
+ {
+ int r = mg.linIdx(R, l_src);
+ if (mg.mType[l_src][r] == GridMg::vtInactive)
+ continue;
+
+ // restriction weight
+ Real rw = Real(1) / Real(1 << ((R.x % 2) + (R.y % 2) + (R.z % 2)));
+
+ sum += rw * src[r];
+ }
+
+ dst[idx] = sum;
+ }
+ inline std::vector<Real> &getArg0()
+ {
+ return dst;
+ }
+ typedef std::vector<Real> type0;
+ inline const std::vector<Real> &getArg1()
+ {
+ return src;
+ }
+ typedef std::vector<Real> type1;
+ inline int &getArg2()
+ {
+ return l_dst;
+ }
+ typedef int type2;
+ inline const GridMg &getArg3()
+ {
+ return mg;
+ }
+ typedef GridMg type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knRestrict ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, dst, src, l_dst, mg);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<Real> &dst;
+ const std::vector<Real> &src;
+ int l_dst;
+ const GridMg &mg;
+};
+
+void GridMg::restrict(int l_dst, const std::vector<Real> &src, std::vector<Real> &dst) const
+{
+ knRestrict(dst, src, l_dst, *this);
+}
+
+struct knInterpolate : public KernelBase {
+ knInterpolate(std::vector<Real> &dst, const std::vector<Real> &src, int l_dst, const GridMg &mg)
+ : KernelBase(dst.size()), dst(dst), src(src), l_dst(l_dst), mg(mg)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ std::vector<Real> &dst,
+ const std::vector<Real> &src,
+ int l_dst,
+ const GridMg &mg) const
+ {
+ if (mg.mType[l_dst][idx] == GridMg::vtInactive)
+ return;
+
+ const int l_src = l_dst + 1;
+
+ Vec3i V = mg.vecIdx(int(idx), l_dst);
+
+ Real sum = Real(0);
+
+ FOR_VEC_MINMAX(I, V / 2, (V + 1) / 2)
+ {
+ int i = mg.linIdx(I, l_src);
+ if (mg.mType[l_src][i] != GridMg::vtInactive)
+ sum += src[i];
+ }
+
+ // interpolation weight
+ Real iw = Real(1) / Real(1 << ((V.x % 2) + (V.y % 2) + (V.z % 2)));
+
+ dst[idx] = iw * sum;
+ }
+ inline std::vector<Real> &getArg0()
+ {
+ return dst;
+ }
+ typedef std::vector<Real> type0;
+ inline const std::vector<Real> &getArg1()
+ {
+ return src;
+ }
+ typedef std::vector<Real> type1;
+ inline int &getArg2()
+ {
+ return l_dst;
+ }
+ typedef int type2;
+ inline const GridMg &getArg3()
+ {
+ return mg;
+ }
+ typedef GridMg type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knInterpolate ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, dst, src, l_dst, mg);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<Real> &dst;
+ const std::vector<Real> &src;
+ int l_dst;
+ const GridMg &mg;
+};
+
+void GridMg::interpolate(int l_dst, const std::vector<Real> &src, std::vector<Real> &dst) const
+{
+ knInterpolate(dst, src, l_dst, *this);
+}
+
+}; // namespace Manta
diff --git a/extern/mantaflow/preprocessed/multigrid.h b/extern/mantaflow/preprocessed/multigrid.h
new file mode 100644
index 00000000000..12cc4d9abce
--- /dev/null
+++ b/extern/mantaflow/preprocessed/multigrid.h
@@ -0,0 +1,186 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Multigrid solver by Florian Ferstl (florian.ferstl.ff@gmail.com)
+ *
+ * This is an implementation of the solver developed by Dick et al. [1]
+ * without topology awareness (= vertex duplication on coarser levels). This
+ * simplification allows us to use regular grids for all levels of the multigrid
+ * hierarchy and works well for moderately complex domains.
+ *
+ * [1] Solving the Fluid Pressure Poisson Equation Using Multigrid-Evaluation
+ * and Improvements, C. Dick, M. Rogowsky, R. Westermann, IEEE TVCG 2015
+ *
+ ******************************************************************************/
+
+#ifndef _MULTIGRID_H
+#define _MULTIGRID_H
+
+#include "vectorbase.h"
+#include "grid.h"
+
+namespace Manta {
+
+//! Multigrid solver
+class GridMg {
+ public:
+ //! constructor: preallocates most of required memory for multigrid hierarchy
+ GridMg(const Vec3i &gridSize);
+ ~GridMg(){};
+
+ //! update system matrix A from symmetric 7-point stencil
+ void setA(const Grid<Real> *pA0,
+ const Grid<Real> *pAi,
+ const Grid<Real> *pAj,
+ const Grid<Real> *pAk);
+
+ //! set right-hand side after setting A
+ void setRhs(const Grid<Real> &rhs);
+
+ bool isASet() const
+ {
+ return mIsASet;
+ }
+ bool isRhsSet() const
+ {
+ return mIsRhsSet;
+ }
+
+ //! perform VCycle iteration
+ // - if src is null, then a zero vector is used instead
+ // - returns norm of residual after VCylcle
+ Real doVCycle(Grid<Real> &dst, const Grid<Real> *src = nullptr);
+
+ // access
+ void setCoarsestLevelAccuracy(Real accuracy)
+ {
+ mCoarsestLevelAccuracy = accuracy;
+ }
+ Real getCoarsestLevelAccuracy() const
+ {
+ return mCoarsestLevelAccuracy;
+ }
+ void setSmoothing(int numPreSmooth, int numPostSmooth)
+ {
+ mNumPreSmooth = numPreSmooth;
+ mNumPostSmooth = numPostSmooth;
+ }
+ int getNumPreSmooth() const
+ {
+ return mNumPreSmooth;
+ }
+ int getNumPostSmooth() const
+ {
+ return mNumPostSmooth;
+ }
+
+ //! Set factor for automated downscaling of trivial equations:
+ // 1*x_i = b_i ---> trivialEquationScale*x_i = trivialEquationScale*b_i
+ // Factor should be significantly smaller than the scale of the entries in A.
+ // Info: Trivial equations of the form x_i = b_i can have a negative
+ // effect on the coarse grid operators of the multigrid hierarchy (due
+ // to scaling mismatches), which can lead to slow multigrid convergence.
+ // To avoid this, the solver checks for such equations when updating A
+ // (and rhs) and scales these equations by a fixed factor < 1.
+ void setTrivialEquationScale(Real scale)
+ {
+ mTrivialEquationScale = scale;
+ }
+
+ private:
+ Vec3i vecIdx(int v, int l) const
+ {
+ return Vec3i(v % mSize[l].x,
+ (v % (mSize[l].x * mSize[l].y)) / mSize[l].x,
+ v / (mSize[l].x * mSize[l].y));
+ }
+ int linIdx(Vec3i V, int l) const
+ {
+ return V.x + V.y * mPitch[l].y + V.z * mPitch[l].z;
+ }
+ bool inGrid(Vec3i V, int l) const
+ {
+ return V.x >= 0 && V.y >= 0 && V.z >= 0 && V.x < mSize[l].x && V.y < mSize[l].y &&
+ V.z < mSize[l].z;
+ }
+
+ void analyzeStencil(int v, bool is3D, bool &isStencilSumNonZero, bool &isEquationTrivial) const;
+
+ void genCoarseGrid(int l);
+ void genCoraseGridOperator(int l);
+
+ void smoothGS(int l, bool reversedOrder);
+ void calcResidual(int l);
+ Real calcResidualNorm(int l);
+ void solveCG(int l);
+
+ void restrict(int l_dst, const std::vector<Real> &src, std::vector<Real> &dst) const;
+ void interpolate(int l_dst, const std::vector<Real> &src, std::vector<Real> &dst) const;
+
+ private:
+ enum VertexType : char {
+ vtInactive = 0,
+ vtActive = 1,
+ vtActiveTrivial = 2, // only on finest level 0
+ vtRemoved = 3, //-+
+ vtZero = 4, // +-- only during coarse grid generation
+ vtFree = 5 //-+
+ };
+
+ struct CoarseningPath {
+ Vec3i U, W, N;
+ int sc, sf;
+ Real rw, iw;
+ bool inUStencil;
+ };
+
+ int mNumPreSmooth;
+ int mNumPostSmooth;
+ Real mCoarsestLevelAccuracy;
+ Real mTrivialEquationScale;
+
+ std::vector<std::vector<Real>> mA;
+ std::vector<std::vector<Real>> mx;
+ std::vector<std::vector<Real>> mb;
+ std::vector<std::vector<Real>> mr;
+ std::vector<std::vector<VertexType>> mType;
+ std::vector<std::vector<double>> mCGtmp1, mCGtmp2, mCGtmp3, mCGtmp4;
+ std::vector<Vec3i> mSize, mPitch;
+ std::vector<CoarseningPath> mCoarseningPaths0;
+
+ bool mIs3D;
+ int mDim;
+ int mStencilSize;
+ int mStencilSize0;
+ Vec3i mStencilMin;
+ Vec3i mStencilMax;
+
+ bool mIsASet;
+ bool mIsRhsSet;
+
+ // provide kernels with access
+ friend struct knActivateVertices;
+ friend struct knActivateCoarseVertices;
+ friend struct knSetRhs;
+ friend struct knGenCoarseGridOperator;
+ friend struct knSmoothColor;
+ friend struct knCalcResidual;
+ friend struct knResidualNormSumSqr;
+ friend struct knRestrict;
+ friend struct knInterpolate;
+}; // GridMg
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/multigrid.h.reg.cpp b/extern/mantaflow/preprocessed/multigrid.h.reg.cpp
new file mode 100644
index 00000000000..8f91e6ecf2e
--- /dev/null
+++ b/extern/mantaflow/preprocessed/multigrid.h.reg.cpp
@@ -0,0 +1,13 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "multigrid.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_4()
+{
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/noisefield.cpp b/extern/mantaflow/preprocessed/noisefield.cpp
new file mode 100644
index 00000000000..98a92309b05
--- /dev/null
+++ b/extern/mantaflow/preprocessed/noisefield.cpp
@@ -0,0 +1,325 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Noise field
+ *
+ ******************************************************************************/
+
+#include "noisefield.h"
+#include "randomstream.h"
+#include "grid.h"
+
+using namespace std;
+
+//*****************************************************************************
+// Wavelet noise
+
+#if FLOATINGPOINT_PRECISION == 1
+# define TILENAME "waveletNoiseTile.bin"
+#else
+# define TILENAME "waveletNoiseTileD.bin"
+#endif
+
+namespace Manta {
+
+int WaveletNoiseField::randomSeed = 13322223;
+Real *WaveletNoiseField::mNoiseTile = NULL;
+std::atomic<int> WaveletNoiseField::mNoiseReferenceCount(0);
+
+static Real _aCoeffs[32] = {
+ 0.000334, -0.001528, 0.000410, 0.003545, -0.000938, -0.008233, 0.002172, 0.019120,
+ -0.005040, -0.044412, 0.011655, 0.103311, -0.025936, -0.243780, 0.033979, 0.655340,
+ 0.655340, 0.033979, -0.243780, -0.025936, 0.103311, 0.011655, -0.044412, -0.005040,
+ 0.019120, 0.002172, -0.008233, -0.000938, 0.003546, 0.000410, -0.001528, 0.000334};
+
+void WaveletNoiseField::downsample(Real *from, Real *to, int n, int stride)
+{
+ const Real *a = &_aCoeffs[16];
+ for (int i = 0; i < n / 2; i++) {
+ to[i * stride] = 0;
+ for (int k = 2 * i - 16; k < 2 * i + 16; k++) {
+ to[i * stride] += a[k - 2 * i] * from[modFast128(k) * stride];
+ }
+ }
+}
+
+static Real _pCoeffs[4] = {0.25, 0.75, 0.75, 0.25};
+
+void WaveletNoiseField::upsample(Real *from, Real *to, int n, int stride)
+{
+ const Real *pp = &_pCoeffs[1];
+
+ for (int i = 0; i < n; i++) {
+ to[i * stride] = 0;
+ for (int k = i / 2 - 1; k < i / 2 + 3; k++) {
+ to[i * stride] += 0.5 * pp[k - i / 2] * from[modSlow(k, n / 2) * stride];
+ } // new */
+ }
+}
+
+WaveletNoiseField::WaveletNoiseField(FluidSolver *parent, int fixedSeed, int loadFromFile)
+ : PbClass(parent),
+ mPosOffset(0.),
+ mPosScale(1.),
+ mValOffset(0.),
+ mValScale(1.),
+ mClamp(false),
+ mClampNeg(0),
+ mClampPos(1),
+ mTimeAnim(0),
+ mGsInvX(0),
+ mGsInvY(0),
+ mGsInvZ(0)
+{
+ Real scale = 1.0 / parent->getGridSize().max();
+ mGsInvX = scale;
+ mGsInvY = scale;
+ mGsInvZ = parent->is3D() ? scale : 1;
+
+ // use global random seed with offset if none is given
+ if (fixedSeed == -1) {
+ fixedSeed = randomSeed + 123;
+ }
+ RandomStream randStreamPos(fixedSeed);
+ mSeedOffset = Vec3(randStreamPos.getVec3Norm());
+
+ generateTile(loadFromFile);
+};
+
+string WaveletNoiseField::toString()
+{
+ std::ostringstream out;
+ out << "NoiseField: name '" << mName << "' "
+ << " pos off=" << mPosOffset << " scale=" << mPosScale << " val off=" << mValOffset
+ << " scale=" << mValScale << " clamp =" << mClamp << " val=" << mClampNeg << " to "
+ << mClampPos << " timeAni =" << mTimeAnim
+ << " gridInv =" << Vec3(mGsInvX, mGsInvY, mGsInvZ);
+ return out.str();
+}
+
+void WaveletNoiseField::generateTile(int loadFromFile)
+{
+ // generate tile
+ const int n = NOISE_TILE_SIZE;
+ const int n3 = n * n * n, n3d = n3 * 3;
+
+ if (mNoiseTile) {
+ mNoiseReferenceCount++;
+ return;
+ }
+ Real *noise3 = new Real[n3d];
+ if (loadFromFile) {
+ FILE *fp = fopen(TILENAME, "rb");
+ if (fp) {
+ assertMsg(fread(noise3, sizeof(Real), n3d, fp) == n3d,
+ "Failed to read wavelet noise tile, file invalid/corrupt? (" << TILENAME << ") ");
+ fclose(fp);
+ debMsg("Noise tile loaded from file " TILENAME, 1);
+ mNoiseTile = noise3;
+ mNoiseReferenceCount++;
+ return;
+ }
+ }
+
+ debMsg("Generating 3x " << n << "^3 noise tile ", 1);
+ Real *temp13 = new Real[n3d];
+ Real *temp23 = new Real[n3d];
+
+ // initialize
+ for (int i = 0; i < n3d; i++) {
+ temp13[i] = temp23[i] = noise3[i] = 0.;
+ }
+
+ // Step 1. Fill the tile with random numbers in the range -1 to 1.
+ RandomStream randStreamTile(randomSeed);
+ for (int i = 0; i < n3d; i++) {
+ // noise3[i] = (randStream.getReal() + randStream2.getReal()) -1.; // produces repeated
+ // values??
+ noise3[i] = randStreamTile.getRandNorm(0, 1);
+ }
+
+ // Steps 2 and 3. Downsample and upsample the tile
+ for (int tile = 0; tile < 3; tile++) {
+ for (int iy = 0; iy < n; iy++)
+ for (int iz = 0; iz < n; iz++) {
+ const int i = iy * n + iz * n * n + tile * n3;
+ downsample(&noise3[i], &temp13[i], n, 1);
+ upsample(&temp13[i], &temp23[i], n, 1);
+ }
+ for (int ix = 0; ix < n; ix++)
+ for (int iz = 0; iz < n; iz++) {
+ const int i = ix + iz * n * n + tile * n3;
+ downsample(&temp23[i], &temp13[i], n, n);
+ upsample(&temp13[i], &temp23[i], n, n);
+ }
+ for (int ix = 0; ix < n; ix++)
+ for (int iy = 0; iy < n; iy++) {
+ const int i = ix + iy * n + tile * n3;
+ downsample(&temp23[i], &temp13[i], n, n * n);
+ upsample(&temp13[i], &temp23[i], n, n * n);
+ }
+ }
+
+ // Step 4. Subtract out the coarse-scale contribution
+ for (int i = 0; i < n3d; i++) {
+ noise3[i] -= temp23[i];
+ }
+
+ // Avoid even/odd variance difference by adding odd-offset version of noise to itself.
+ int offset = n / 2;
+ if (offset % 2 == 0)
+ offset++;
+
+ if (n != 128)
+ errMsg("WaveletNoise::Fast 128 mod used, change for non-128 resolution");
+
+ int icnt = 0;
+ for (int tile = 0; tile < 3; tile++)
+ for (int ix = 0; ix < n; ix++)
+ for (int iy = 0; iy < n; iy++)
+ for (int iz = 0; iz < n; iz++) {
+ temp13[icnt] = noise3[modFast128(ix + offset) + modFast128(iy + offset) * n +
+ modFast128(iz + offset) * n * n + tile * n3];
+ icnt++;
+ }
+
+ for (int i = 0; i < n3d; i++) {
+ noise3[i] += temp13[i];
+ }
+
+ mNoiseTile = noise3;
+ mNoiseReferenceCount++;
+ delete[] temp13;
+ delete[] temp23;
+
+ if (loadFromFile) {
+ FILE *fp = fopen(TILENAME, "wb");
+ if (fp) {
+ fwrite(noise3, sizeof(Real), n3d, fp);
+ fclose(fp);
+ debMsg("Noise field saved to file ", 1);
+ }
+ }
+}
+
+void WaveletNoiseField::downsampleNeumann(const Real *from, Real *to, int n, int stride)
+{
+ // if these values are not local incorrect results are generated
+ static const Real *const aCoCenter = &_aCoeffs[16];
+ for (int i = 0; i < n / 2; i++) {
+ to[i * stride] = 0;
+ for (int k = 2 * i - 16; k < 2 * i + 16; k++) {
+ // handle boundary
+ Real fromval;
+ if (k < 0) {
+ fromval = from[0];
+ }
+ else if (k > n - 1) {
+ fromval = from[(n - 1) * stride];
+ }
+ else {
+ fromval = from[k * stride];
+ }
+ to[i * stride] += aCoCenter[k - 2 * i] * fromval;
+ }
+ }
+}
+
+void WaveletNoiseField::upsampleNeumann(const Real *from, Real *to, int n, int stride)
+{
+ static const Real *const pp = &_pCoeffs[1];
+ for (int i = 0; i < n; i++) {
+ to[i * stride] = 0;
+ for (int k = i / 2 - 1; k < i / 2 + 3; k++) {
+ Real fromval;
+ if (k > n / 2 - 1) {
+ fromval = from[(n / 2 - 1) * stride];
+ }
+ else if (k < 0) {
+ fromval = from[0];
+ }
+ else {
+ fromval = from[k * stride];
+ }
+ to[i * stride] += 0.5 * pp[k - i / 2] * fromval;
+ }
+ }
+}
+
+void WaveletNoiseField::computeCoefficients(Grid<Real> &input,
+ Grid<Real> &tempIn1,
+ Grid<Real> &tempIn2)
+{
+ // generate tile
+ const int sx = input.getSizeX();
+ const int sy = input.getSizeY();
+ const int sz = input.getSizeZ();
+ const int n3 = sx * sy * sz;
+ // just for compatibility with wavelet turb code
+ Real *temp13 = &tempIn1(0, 0, 0);
+ Real *temp23 = &tempIn2(0, 0, 0);
+ Real *noise3 = &input(0, 0, 0);
+
+ // clear grids
+ for (int i = 0; i < n3; i++) {
+ temp13[i] = temp23[i] = 0.f;
+ }
+
+ // Steps 2 and 3. Downsample and upsample the tile
+ for (int iz = 0; iz < sz; iz++)
+ for (int iy = 0; iy < sy; iy++) {
+ const int i = iz * sx * sy + iy * sx;
+ downsampleNeumann(&noise3[i], &temp13[i], sx, 1);
+ upsampleNeumann(&temp13[i], &temp23[i], sx, 1);
+ }
+
+ for (int iz = 0; iz < sz; iz++)
+ for (int ix = 0; ix < sx; ix++) {
+ const int i = iz * sx * sy + ix;
+ downsampleNeumann(&temp23[i], &temp13[i], sy, sx);
+ upsampleNeumann(&temp13[i], &temp23[i], sy, sx);
+ }
+
+ if (input.is3D()) {
+ for (int iy = 0; iy < sy; iy++)
+ for (int ix = 0; ix < sx; ix++) {
+ const int i = iy * sx + ix;
+ downsampleNeumann(&temp23[i], &temp13[i], sz, sy * sx);
+ upsampleNeumann(&temp13[i], &temp23[i], sz, sy * sx);
+ }
+ }
+
+ // Step 4. Subtract out the coarse-scale contribution
+ for (int i = 0; i < n3; i++) {
+ Real residual = noise3[i] - temp23[i];
+ temp13[i] = sqrtf(fabs(residual));
+ }
+
+ // copy back, and compute actual weight for wavelet turbulence...
+ Real smoothingFactor = 1. / 6.;
+ if (!input.is3D())
+ smoothingFactor = 1. / 4.;
+ FOR_IJK_BND(input, 1)
+ {
+ // apply some brute force smoothing
+ Real res = temp13[k * sx * sy + j * sx + i - 1] + temp13[k * sx * sy + j * sx + i + 1];
+ res += temp13[k * sx * sy + j * sx + i - sx] + temp13[k * sx * sy + j * sx + i + sx];
+ if (input.is3D())
+ res += temp13[k * sx * sy + j * sx + i - sx * sy] +
+ temp13[k * sx * sy + j * sx + i + sx * sy];
+ input(i, j, k) = res * smoothingFactor;
+ }
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/noisefield.h b/extern/mantaflow/preprocessed/noisefield.h
new file mode 100644
index 00000000000..ddf47573dd9
--- /dev/null
+++ b/extern/mantaflow/preprocessed/noisefield.h
@@ -0,0 +1,635 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Wavelet noise field
+ *
+ ******************************************************************************/
+
+#ifndef _NOISEFIELD_H_
+#define _NOISEFIELD_H_
+
+#include "vectorbase.h"
+#include "manta.h"
+#include "grid.h"
+#include <atomic>
+
+namespace Manta {
+
+#define NOISE_TILE_SIZE 128
+
+// wrapper for a parametrized field of wavelet noise
+
+class WaveletNoiseField : public PbClass {
+ public:
+ WaveletNoiseField(FluidSolver *parent, int fixedSeed = -1, int loadFromFile = false);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "WaveletNoiseField::WaveletNoiseField", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ int fixedSeed = _args.getOpt<int>("fixedSeed", 1, -1, &_lock);
+ int loadFromFile = _args.getOpt<int>("loadFromFile", 2, false, &_lock);
+ obj = new WaveletNoiseField(parent, fixedSeed, loadFromFile);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "WaveletNoiseField::WaveletNoiseField", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("WaveletNoiseField::WaveletNoiseField", e.what());
+ return -1;
+ }
+ }
+
+ ~WaveletNoiseField()
+ {
+ if (mNoiseTile && !mNoiseReferenceCount) {
+ delete mNoiseTile;
+ mNoiseTile = NULL;
+ }
+ };
+
+ //! evaluate noise
+ inline Real evaluate(Vec3 pos, int tile = 0) const;
+ //! evaluate noise as a vector
+ inline Vec3 evaluateVec(Vec3 pos, int tile = 0) const;
+ //! evaluate curl noise
+ inline Vec3 evaluateCurl(Vec3 pos) const;
+
+ //! direct data access
+ Real *data()
+ {
+ return mNoiseTile;
+ }
+
+ //! compute wavelet decomposition of an input grid (stores residual coefficients)
+ static void computeCoefficients(Grid<Real> &input, Grid<Real> &tempIn1, Grid<Real> &tempIn2);
+
+ // helper
+ std::string toString();
+
+ // texcoord position and scale
+ Vec3 mPosOffset;
+ static PyObject *_GET_mPosOffset(PyObject *self, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ return toPy(pbo->mPosOffset);
+ }
+ static int _SET_mPosOffset(PyObject *self, PyObject *val, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ pbo->mPosOffset = fromPy<Vec3>(val);
+ return 0;
+ }
+
+ Vec3 mPosScale;
+ static PyObject *_GET_mPosScale(PyObject *self, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ return toPy(pbo->mPosScale);
+ }
+ static int _SET_mPosScale(PyObject *self, PyObject *val, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ pbo->mPosScale = fromPy<Vec3>(val);
+ return 0;
+ }
+
+ // value offset & scale
+ Real mValOffset;
+ static PyObject *_GET_mValOffset(PyObject *self, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ return toPy(pbo->mValOffset);
+ }
+ static int _SET_mValOffset(PyObject *self, PyObject *val, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ pbo->mValOffset = fromPy<Real>(val);
+ return 0;
+ }
+
+ Real mValScale;
+ static PyObject *_GET_mValScale(PyObject *self, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ return toPy(pbo->mValScale);
+ }
+ static int _SET_mValScale(PyObject *self, PyObject *val, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ pbo->mValScale = fromPy<Real>(val);
+ return 0;
+ }
+
+ // clamp? (default 0-1)
+ bool mClamp;
+ static PyObject *_GET_mClamp(PyObject *self, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ return toPy(pbo->mClamp);
+ }
+ static int _SET_mClamp(PyObject *self, PyObject *val, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ pbo->mClamp = fromPy<bool>(val);
+ return 0;
+ }
+
+ Real mClampNeg;
+ static PyObject *_GET_mClampNeg(PyObject *self, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ return toPy(pbo->mClampNeg);
+ }
+ static int _SET_mClampNeg(PyObject *self, PyObject *val, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ pbo->mClampNeg = fromPy<Real>(val);
+ return 0;
+ }
+
+ Real mClampPos;
+ static PyObject *_GET_mClampPos(PyObject *self, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ return toPy(pbo->mClampPos);
+ }
+ static int _SET_mClampPos(PyObject *self, PyObject *val, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ pbo->mClampPos = fromPy<Real>(val);
+ return 0;
+ }
+
+ // animated over time
+ Real mTimeAnim;
+ static PyObject *_GET_mTimeAnim(PyObject *self, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ return toPy(pbo->mTimeAnim);
+ }
+ static int _SET_mTimeAnim(PyObject *self, PyObject *val, void *cl)
+ {
+ WaveletNoiseField *pbo = dynamic_cast<WaveletNoiseField *>(Pb::objFromPy(self));
+ pbo->mTimeAnim = fromPy<Real>(val);
+ return 0;
+ }
+
+ protected:
+ // noise evaluation functions
+ static inline Real WNoiseDx(const Vec3 &p, Real *data);
+ static inline Vec3 WNoiseVec(const Vec3 &p, Real *data);
+ static inline Real WNoise(const Vec3 &p, Real *data);
+
+ // helpers for tile generation , for periodic 128 grids only
+ static void downsample(Real *from, Real *to, int n, int stride);
+ static void upsample(Real *from, Real *to, int n, int stride);
+
+ // for grids with arbitrary sizes, and neumann boundary conditions
+ static void downsampleNeumann(const Real *from, Real *to, int n, int stride);
+ static void upsampleNeumann(const Real *from, Real *to, int n, int stride);
+
+ static inline int modSlow(int x, int n)
+ {
+ int m = x % n;
+ return (m < 0) ? m + n : m;
+ }
+// warning - noiseTileSize has to be 128^3!
+#define modFast128(x) ((x)&127)
+
+ inline Real getTime() const
+ {
+ return mParent->getTime() * mParent->getDx() * mTimeAnim;
+ }
+
+ // pre-compute tile data for wavelet noise
+ void generateTile(int loadFromFile);
+
+ // animation over time
+ // grid size normalization (inverse size)
+ Real mGsInvX, mGsInvY, mGsInvZ;
+ // random offset into tile to simulate different random seeds
+ Vec3 mSeedOffset;
+
+ static Real *mNoiseTile;
+ // global random seed storage
+ static int randomSeed;
+ // global reference count for noise tile
+ static std::atomic<int> mNoiseReferenceCount;
+ public:
+ PbArgs _args;
+}
+#define _C_WaveletNoiseField
+;
+
+// **************************************************************************
+// Implementation
+
+#define ADD_WEIGHTED(x, y, z) \
+ weight = 1.0f; \
+ xC = modFast128(midX + (x)); \
+ weight *= w[0][(x) + 1]; \
+ yC = modFast128(midY + (y)); \
+ weight *= w[1][(y) + 1]; \
+ zC = modFast128(midZ + (z)); \
+ weight *= w[2][(z) + 1]; \
+ result += weight * data[(zC * NOISE_TILE_SIZE + yC) * NOISE_TILE_SIZE + xC];
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// derivatives of 3D noise - unrolled for performance
+//////////////////////////////////////////////////////////////////////////////////////////
+inline Real WaveletNoiseField::WNoiseDx(const Vec3 &p, Real *data)
+{
+ Real w[3][3], t, result = 0;
+
+ // Evaluate quadratic B-spline basis functions
+ int midX = (int)ceil(p[0] - 0.5f);
+ t = midX - (p[0] - 0.5f);
+ w[0][0] = -t;
+ w[0][2] = (1.f - t);
+ w[0][1] = 2.0f * t - 1.0f;
+
+ int midY = (int)ceil(p[1] - 0.5f);
+ t = midY - (p[1] - 0.5f);
+ w[1][0] = t * t * 0.5f;
+ w[1][2] = (1.f - t) * (1.f - t) * 0.5f;
+ w[1][1] = 1.f - w[1][0] - w[1][2];
+
+ int midZ = (int)ceil(p[2] - 0.5f);
+ t = midZ - (p[2] - 0.5f);
+ w[2][0] = t * t * 0.5f;
+ w[2][2] = (1.f - t) * (1.f - t) * 0.5f;
+ w[2][1] = 1.f - w[2][0] - w[2][2];
+
+ // Evaluate noise by weighting noise coefficients by basis function values
+ int xC, yC, zC;
+ Real weight = 1;
+
+ ADD_WEIGHTED(-1, -1, -1);
+ ADD_WEIGHTED(0, -1, -1);
+ ADD_WEIGHTED(1, -1, -1);
+ ADD_WEIGHTED(-1, 0, -1);
+ ADD_WEIGHTED(0, 0, -1);
+ ADD_WEIGHTED(1, 0, -1);
+ ADD_WEIGHTED(-1, 1, -1);
+ ADD_WEIGHTED(0, 1, -1);
+ ADD_WEIGHTED(1, 1, -1);
+
+ ADD_WEIGHTED(-1, -1, 0);
+ ADD_WEIGHTED(0, -1, 0);
+ ADD_WEIGHTED(1, -1, 0);
+ ADD_WEIGHTED(-1, 0, 0);
+ ADD_WEIGHTED(0, 0, 0);
+ ADD_WEIGHTED(1, 0, 0);
+ ADD_WEIGHTED(-1, 1, 0);
+ ADD_WEIGHTED(0, 1, 0);
+ ADD_WEIGHTED(1, 1, 0);
+
+ ADD_WEIGHTED(-1, -1, 1);
+ ADD_WEIGHTED(0, -1, 1);
+ ADD_WEIGHTED(1, -1, 1);
+ ADD_WEIGHTED(-1, 0, 1);
+ ADD_WEIGHTED(0, 0, 1);
+ ADD_WEIGHTED(1, 0, 1);
+ ADD_WEIGHTED(-1, 1, 1);
+ ADD_WEIGHTED(0, 1, 1);
+ ADD_WEIGHTED(1, 1, 1);
+
+ return result;
+}
+
+inline Real WaveletNoiseField::WNoise(const Vec3 &p, Real *data)
+{
+ Real w[3][3], t, result = 0;
+
+ // Evaluate quadratic B-spline basis functions
+ int midX = (int)ceilf(p[0] - 0.5f);
+ t = midX - (p[0] - 0.5f);
+ w[0][0] = t * t * 0.5f;
+ w[0][2] = (1.f - t) * (1.f - t) * 0.5f;
+ w[0][1] = 1.f - w[0][0] - w[0][2];
+
+ int midY = (int)ceilf(p[1] - 0.5f);
+ t = midY - (p[1] - 0.5f);
+ w[1][0] = t * t * 0.5f;
+ w[1][2] = (1.f - t) * (1.f - t) * 0.5f;
+ w[1][1] = 1.f - w[1][0] - w[1][2];
+
+ int midZ = (int)ceilf(p[2] - 0.5f);
+ t = midZ - (p[2] - 0.5f);
+ w[2][0] = t * t * 0.5f;
+ w[2][2] = (1.f - t) * (1.f - t) * 0.5f;
+ w[2][1] = 1.f - w[2][0] - w[2][2];
+
+ // Evaluate noise by weighting noise coefficients by basis function values
+ int xC, yC, zC;
+ Real weight = 1;
+
+ ADD_WEIGHTED(-1, -1, -1);
+ ADD_WEIGHTED(0, -1, -1);
+ ADD_WEIGHTED(1, -1, -1);
+ ADD_WEIGHTED(-1, 0, -1);
+ ADD_WEIGHTED(0, 0, -1);
+ ADD_WEIGHTED(1, 0, -1);
+ ADD_WEIGHTED(-1, 1, -1);
+ ADD_WEIGHTED(0, 1, -1);
+ ADD_WEIGHTED(1, 1, -1);
+
+ ADD_WEIGHTED(-1, -1, 0);
+ ADD_WEIGHTED(0, -1, 0);
+ ADD_WEIGHTED(1, -1, 0);
+ ADD_WEIGHTED(-1, 0, 0);
+ ADD_WEIGHTED(0, 0, 0);
+ ADD_WEIGHTED(1, 0, 0);
+ ADD_WEIGHTED(-1, 1, 0);
+ ADD_WEIGHTED(0, 1, 0);
+ ADD_WEIGHTED(1, 1, 0);
+
+ ADD_WEIGHTED(-1, -1, 1);
+ ADD_WEIGHTED(0, -1, 1);
+ ADD_WEIGHTED(1, -1, 1);
+ ADD_WEIGHTED(-1, 0, 1);
+ ADD_WEIGHTED(0, 0, 1);
+ ADD_WEIGHTED(1, 0, 1);
+ ADD_WEIGHTED(-1, 1, 1);
+ ADD_WEIGHTED(0, 1, 1);
+ ADD_WEIGHTED(1, 1, 1);
+
+ return result;
+}
+
+#define ADD_WEIGHTEDX(x, y, z) \
+ weight = dw[0][(x) + 1] * w[1][(y) + 1] * w[2][(z) + 1]; \
+ result += weight * neighbors[x + 1][y + 1][z + 1];
+
+#define ADD_WEIGHTEDY(x, y, z) \
+ weight = w[0][(x) + 1] * dw[1][(y) + 1] * w[2][(z) + 1]; \
+ result += weight * neighbors[x + 1][y + 1][z + 1];
+
+#define ADD_WEIGHTEDZ(x, y, z) \
+ weight = w[0][(x) + 1] * w[1][(y) + 1] * dw[2][(z) + 1]; \
+ result += weight * neighbors[x + 1][y + 1][z + 1];
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// compute all derivatives in at once
+//////////////////////////////////////////////////////////////////////////////////////////
+inline Vec3 WaveletNoiseField::WNoiseVec(const Vec3 &p, Real *data)
+{
+ Vec3 final(0.);
+ Real w[3][3];
+ Real dw[3][3];
+ Real result = 0;
+ int xC, yC, zC;
+ Real weight;
+
+ int midX = (int)ceil(p[0] - 0.5f);
+ int midY = (int)ceil(p[1] - 0.5f);
+ int midZ = (int)ceil(p[2] - 0.5f);
+
+ Real t0 = midX - (p[0] - 0.5f);
+ Real t1 = midY - (p[1] - 0.5f);
+ Real t2 = midZ - (p[2] - 0.5f);
+
+ // precache all the neighbors for fast access
+ Real neighbors[3][3][3];
+ for (int z = -1; z <= 1; z++)
+ for (int y = -1; y <= 1; y++)
+ for (int x = -1; x <= 1; x++) {
+ xC = modFast128(midX + (x));
+ yC = modFast128(midY + (y));
+ zC = modFast128(midZ + (z));
+ neighbors[x + 1][y + 1][z + 1] =
+ data[zC * NOISE_TILE_SIZE * NOISE_TILE_SIZE + yC * NOISE_TILE_SIZE + xC];
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // evaluate splines
+ ///////////////////////////////////////////////////////////////////////////////////////
+ dw[0][0] = -t0;
+ dw[0][2] = (1.f - t0);
+ dw[0][1] = 2.0f * t0 - 1.0f;
+
+ dw[1][0] = -t1;
+ dw[1][2] = (1.0f - t1);
+ dw[1][1] = 2.0f * t1 - 1.0f;
+
+ dw[2][0] = -t2;
+ dw[2][2] = (1.0f - t2);
+ dw[2][1] = 2.0f * t2 - 1.0f;
+
+ w[0][0] = t0 * t0 * 0.5f;
+ w[0][2] = (1.f - t0) * (1.f - t0) * 0.5f;
+ w[0][1] = 1.f - w[0][0] - w[0][2];
+
+ w[1][0] = t1 * t1 * 0.5f;
+ w[1][2] = (1.f - t1) * (1.f - t1) * 0.5f;
+ w[1][1] = 1.f - w[1][0] - w[1][2];
+
+ w[2][0] = t2 * t2 * 0.5f;
+ w[2][2] = (1.f - t2) * (1.f - t2) * 0.5f;
+ w[2][1] = 1.f - w[2][0] - w[2][2];
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // x derivative
+ ///////////////////////////////////////////////////////////////////////////////////////
+ result = 0.0f;
+ ADD_WEIGHTEDX(-1, -1, -1);
+ ADD_WEIGHTEDX(0, -1, -1);
+ ADD_WEIGHTEDX(1, -1, -1);
+ ADD_WEIGHTEDX(-1, 0, -1);
+ ADD_WEIGHTEDX(0, 0, -1);
+ ADD_WEIGHTEDX(1, 0, -1);
+ ADD_WEIGHTEDX(-1, 1, -1);
+ ADD_WEIGHTEDX(0, 1, -1);
+ ADD_WEIGHTEDX(1, 1, -1);
+
+ ADD_WEIGHTEDX(-1, -1, 0);
+ ADD_WEIGHTEDX(0, -1, 0);
+ ADD_WEIGHTEDX(1, -1, 0);
+ ADD_WEIGHTEDX(-1, 0, 0);
+ ADD_WEIGHTEDX(0, 0, 0);
+ ADD_WEIGHTEDX(1, 0, 0);
+ ADD_WEIGHTEDX(-1, 1, 0);
+ ADD_WEIGHTEDX(0, 1, 0);
+ ADD_WEIGHTEDX(1, 1, 0);
+
+ ADD_WEIGHTEDX(-1, -1, 1);
+ ADD_WEIGHTEDX(0, -1, 1);
+ ADD_WEIGHTEDX(1, -1, 1);
+ ADD_WEIGHTEDX(-1, 0, 1);
+ ADD_WEIGHTEDX(0, 0, 1);
+ ADD_WEIGHTEDX(1, 0, 1);
+ ADD_WEIGHTEDX(-1, 1, 1);
+ ADD_WEIGHTEDX(0, 1, 1);
+ ADD_WEIGHTEDX(1, 1, 1);
+ final[0] = result;
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // y derivative
+ ///////////////////////////////////////////////////////////////////////////////////////
+ result = 0.0f;
+ ADD_WEIGHTEDY(-1, -1, -1);
+ ADD_WEIGHTEDY(0, -1, -1);
+ ADD_WEIGHTEDY(1, -1, -1);
+ ADD_WEIGHTEDY(-1, 0, -1);
+ ADD_WEIGHTEDY(0, 0, -1);
+ ADD_WEIGHTEDY(1, 0, -1);
+ ADD_WEIGHTEDY(-1, 1, -1);
+ ADD_WEIGHTEDY(0, 1, -1);
+ ADD_WEIGHTEDY(1, 1, -1);
+
+ ADD_WEIGHTEDY(-1, -1, 0);
+ ADD_WEIGHTEDY(0, -1, 0);
+ ADD_WEIGHTEDY(1, -1, 0);
+ ADD_WEIGHTEDY(-1, 0, 0);
+ ADD_WEIGHTEDY(0, 0, 0);
+ ADD_WEIGHTEDY(1, 0, 0);
+ ADD_WEIGHTEDY(-1, 1, 0);
+ ADD_WEIGHTEDY(0, 1, 0);
+ ADD_WEIGHTEDY(1, 1, 0);
+
+ ADD_WEIGHTEDY(-1, -1, 1);
+ ADD_WEIGHTEDY(0, -1, 1);
+ ADD_WEIGHTEDY(1, -1, 1);
+ ADD_WEIGHTEDY(-1, 0, 1);
+ ADD_WEIGHTEDY(0, 0, 1);
+ ADD_WEIGHTEDY(1, 0, 1);
+ ADD_WEIGHTEDY(-1, 1, 1);
+ ADD_WEIGHTEDY(0, 1, 1);
+ ADD_WEIGHTEDY(1, 1, 1);
+ final[1] = result;
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // z derivative
+ ///////////////////////////////////////////////////////////////////////////////////////
+ result = 0.0f;
+ ADD_WEIGHTEDZ(-1, -1, -1);
+ ADD_WEIGHTEDZ(0, -1, -1);
+ ADD_WEIGHTEDZ(1, -1, -1);
+ ADD_WEIGHTEDZ(-1, 0, -1);
+ ADD_WEIGHTEDZ(0, 0, -1);
+ ADD_WEIGHTEDZ(1, 0, -1);
+ ADD_WEIGHTEDZ(-1, 1, -1);
+ ADD_WEIGHTEDZ(0, 1, -1);
+ ADD_WEIGHTEDZ(1, 1, -1);
+
+ ADD_WEIGHTEDZ(-1, -1, 0);
+ ADD_WEIGHTEDZ(0, -1, 0);
+ ADD_WEIGHTEDZ(1, -1, 0);
+ ADD_WEIGHTEDZ(-1, 0, 0);
+ ADD_WEIGHTEDZ(0, 0, 0);
+ ADD_WEIGHTEDZ(1, 0, 0);
+ ADD_WEIGHTEDZ(-1, 1, 0);
+ ADD_WEIGHTEDZ(0, 1, 0);
+ ADD_WEIGHTEDZ(1, 1, 0);
+
+ ADD_WEIGHTEDZ(-1, -1, 1);
+ ADD_WEIGHTEDZ(0, -1, 1);
+ ADD_WEIGHTEDZ(1, -1, 1);
+ ADD_WEIGHTEDZ(-1, 0, 1);
+ ADD_WEIGHTEDZ(0, 0, 1);
+ ADD_WEIGHTEDZ(1, 0, 1);
+ ADD_WEIGHTEDZ(-1, 1, 1);
+ ADD_WEIGHTEDZ(0, 1, 1);
+ ADD_WEIGHTEDZ(1, 1, 1);
+ final[2] = result;
+
+ // debMsg("FINAL","at "<<p<<" = "<<final); // DEBUG
+ return final;
+}
+#undef ADD_WEIGHTEDX
+#undef ADD_WEIGHTEDY
+#undef ADD_WEIGHTEDZ
+
+inline Real WaveletNoiseField::evaluate(Vec3 pos, int tile) const
+{
+ pos[0] *= mGsInvX;
+ pos[1] *= mGsInvY;
+ pos[2] *= mGsInvZ;
+ pos += mSeedOffset;
+
+ // time anim
+ pos += Vec3(getTime());
+
+ pos[0] *= mPosScale[0];
+ pos[1] *= mPosScale[1];
+ pos[2] *= mPosScale[2];
+ pos += mPosOffset;
+
+ const int n3 = square(NOISE_TILE_SIZE) * NOISE_TILE_SIZE;
+ Real v = WNoise(pos, &mNoiseTile[tile * n3]);
+
+ v += mValOffset;
+ v *= mValScale;
+ if (mClamp) {
+ if (v < mClampNeg)
+ v = mClampNeg;
+ if (v > mClampPos)
+ v = mClampPos;
+ }
+ return v;
+}
+
+inline Vec3 WaveletNoiseField::evaluateVec(Vec3 pos, int tile) const
+{
+ pos[0] *= mGsInvX;
+ pos[1] *= mGsInvY;
+ pos[2] *= mGsInvZ;
+ pos += mSeedOffset;
+
+ // time anim
+ pos += Vec3(getTime());
+
+ pos[0] *= mPosScale[0];
+ pos[1] *= mPosScale[1];
+ pos[2] *= mPosScale[2];
+ pos += mPosOffset;
+
+ const int n3 = square(NOISE_TILE_SIZE) * NOISE_TILE_SIZE;
+ Vec3 v = WNoiseVec(pos, &mNoiseTile[tile * n3]);
+
+ v += Vec3(mValOffset);
+ v *= mValScale;
+
+ if (mClamp) {
+ for (int i = 0; i < 3; i++) {
+ if (v[i] < mClampNeg)
+ v[i] = mClampNeg;
+ if (v[i] > mClampPos)
+ v[i] = mClampPos;
+ }
+ }
+ return v;
+}
+
+inline Vec3 WaveletNoiseField::evaluateCurl(Vec3 pos) const
+{
+ // gradients of w0-w2
+ Vec3 d0 = evaluateVec(pos, 0), d1 = evaluateVec(pos, 1), d2 = evaluateVec(pos, 2);
+
+ return Vec3(d0.y - d1.z, d2.z - d0.x, d1.x - d2.y);
+}
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/noisefield.h.reg.cpp b/extern/mantaflow/preprocessed/noisefield.h.reg.cpp
new file mode 100644
index 00000000000..f4967abcb43
--- /dev/null
+++ b/extern/mantaflow/preprocessed/noisefield.h.reg.cpp
@@ -0,0 +1,60 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "noisefield.h"
+namespace Manta {
+#ifdef _C_WaveletNoiseField
+static const Pb::Register _R_13("WaveletNoiseField", "NoiseField", "PbClass");
+template<> const char *Namify<WaveletNoiseField>::S = "WaveletNoiseField";
+static const Pb::Register _R_14("WaveletNoiseField", "WaveletNoiseField", WaveletNoiseField::_W_0);
+static const Pb::Register _R_15("WaveletNoiseField",
+ "posOffset",
+ WaveletNoiseField::_GET_mPosOffset,
+ WaveletNoiseField::_SET_mPosOffset);
+static const Pb::Register _R_16("WaveletNoiseField",
+ "posScale",
+ WaveletNoiseField::_GET_mPosScale,
+ WaveletNoiseField::_SET_mPosScale);
+static const Pb::Register _R_17("WaveletNoiseField",
+ "valOffset",
+ WaveletNoiseField::_GET_mValOffset,
+ WaveletNoiseField::_SET_mValOffset);
+static const Pb::Register _R_18("WaveletNoiseField",
+ "valScale",
+ WaveletNoiseField::_GET_mValScale,
+ WaveletNoiseField::_SET_mValScale);
+static const Pb::Register _R_19("WaveletNoiseField",
+ "clamp",
+ WaveletNoiseField::_GET_mClamp,
+ WaveletNoiseField::_SET_mClamp);
+static const Pb::Register _R_20("WaveletNoiseField",
+ "clampNeg",
+ WaveletNoiseField::_GET_mClampNeg,
+ WaveletNoiseField::_SET_mClampNeg);
+static const Pb::Register _R_21("WaveletNoiseField",
+ "clampPos",
+ WaveletNoiseField::_GET_mClampPos,
+ WaveletNoiseField::_SET_mClampPos);
+static const Pb::Register _R_22("WaveletNoiseField",
+ "timeAnim",
+ WaveletNoiseField::_GET_mTimeAnim,
+ WaveletNoiseField::_SET_mTimeAnim);
+#endif
+extern "C" {
+void PbRegister_file_13()
+{
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/particle.cpp b/extern/mantaflow/preprocessed/particle.cpp
new file mode 100644
index 00000000000..478f1417109
--- /dev/null
+++ b/extern/mantaflow/preprocessed/particle.cpp
@@ -0,0 +1,1620 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2013 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Particle data functionality
+ *
+ ******************************************************************************/
+
+#include <fstream>
+#include <cstring>
+#if NO_ZLIB != 1
+# include <zlib.h>
+#endif
+#include "particle.h"
+#include "levelset.h"
+#include "mantaio.h"
+
+using namespace std;
+namespace Manta {
+
+ParticleBase::ParticleBase(FluidSolver *parent)
+ : PbClass(parent), mAllowCompress(true), mFreePdata(false)
+{
+}
+
+ParticleBase::~ParticleBase()
+{
+ // make sure data fields now parent system is deleted
+ for (IndexInt i = 0; i < (IndexInt)mPartData.size(); ++i)
+ mPartData[i]->setParticleSys(NULL);
+
+ if (mFreePdata) {
+ for (IndexInt i = 0; i < (IndexInt)mPartData.size(); ++i)
+ delete mPartData[i];
+ }
+}
+
+std::string ParticleBase::infoString() const
+{
+ return "ParticleSystem " + mName + " <no info>";
+}
+
+void ParticleBase::cloneParticleData(ParticleBase *nm)
+{
+ // clone additional data , and make sure the copied particle system deletes it
+ nm->mFreePdata = true;
+ for (IndexInt i = 0; i < (IndexInt)mPartData.size(); ++i) {
+ ParticleDataBase *pdata = mPartData[i]->clone();
+ nm->registerPdata(pdata);
+ }
+}
+
+void ParticleBase::deregister(ParticleDataBase *pdata)
+{
+ bool done = false;
+ // remove pointer from particle data list
+ for (IndexInt i = 0; i < (IndexInt)mPartData.size(); ++i) {
+ if (mPartData[i] == pdata) {
+ if (i < (IndexInt)mPartData.size() - 1)
+ mPartData[i] = mPartData[mPartData.size() - 1];
+ mPartData.pop_back();
+ done = true;
+ }
+ }
+ if (!done)
+ errMsg("Invalid pointer given, not registered!");
+}
+
+// create and attach a new pdata field to this particle system
+PbClass *ParticleBase::create(PbType t, PbTypeVec T, const string &name)
+{
+#if NOPYTHON != 1
+ _args.add("nocheck", true);
+ if (t.str() == "")
+ errMsg("Specify particle data type to create");
+ // debMsg( "Pdata creating '"<< t.str <<" with size "<< this->getSizeSlow(), 5 );
+
+ PbClass *pyObj = PbClass::createPyObject(t.str() + T.str(), name, _args, this->getParent());
+
+ ParticleDataBase *pdata = dynamic_cast<ParticleDataBase *>(pyObj);
+ if (!pdata) {
+ errMsg(
+ "Unable to get particle data pointer from newly created object. Only create ParticleData "
+ "type with a ParticleSys.creat() call, eg, PdataReal, PdataVec3 etc.");
+ delete pyObj;
+ return NULL;
+ }
+ else {
+ this->registerPdata(pdata);
+ }
+
+ // directly init size of new pdata field:
+ pdata->resize(this->getSizeSlow());
+#else
+ PbClass *pyObj = NULL;
+#endif
+ return pyObj;
+}
+
+void ParticleBase::registerPdata(ParticleDataBase *pdata)
+{
+ pdata->setParticleSys(this);
+ mPartData.push_back(pdata);
+
+ if (pdata->getType() == ParticleDataBase::TypeReal) {
+ ParticleDataImpl<Real> *pd = dynamic_cast<ParticleDataImpl<Real> *>(pdata);
+ if (!pd)
+ errMsg("Invalid pdata object posing as real!");
+ this->registerPdataReal(pd);
+ }
+ else if (pdata->getType() == ParticleDataBase::TypeInt) {
+ ParticleDataImpl<int> *pd = dynamic_cast<ParticleDataImpl<int> *>(pdata);
+ if (!pd)
+ errMsg("Invalid pdata object posing as int!");
+ this->registerPdataInt(pd);
+ }
+ else if (pdata->getType() == ParticleDataBase::TypeVec3) {
+ ParticleDataImpl<Vec3> *pd = dynamic_cast<ParticleDataImpl<Vec3> *>(pdata);
+ if (!pd)
+ errMsg("Invalid pdata object posing as vec3!");
+ this->registerPdataVec3(pd);
+ }
+}
+void ParticleBase::registerPdataReal(ParticleDataImpl<Real> *pd)
+{
+ mPdataReal.push_back(pd);
+}
+void ParticleBase::registerPdataVec3(ParticleDataImpl<Vec3> *pd)
+{
+ mPdataVec3.push_back(pd);
+}
+void ParticleBase::registerPdataInt(ParticleDataImpl<int> *pd)
+{
+ mPdataInt.push_back(pd);
+}
+
+void ParticleBase::addAllPdata()
+{
+ for (IndexInt i = 0; i < (IndexInt)mPartData.size(); ++i) {
+ mPartData[i]->addEntry();
+ }
+}
+
+BasicParticleSystem::BasicParticleSystem(FluidSolver *parent)
+ : ParticleSystem<BasicParticleData>(parent)
+{
+ this->mAllowCompress = false;
+}
+
+// file io
+
+void BasicParticleSystem::writeParticlesText(const string name) const
+{
+ ofstream ofs(name.c_str());
+ if (!ofs.good())
+ errMsg("can't open file!");
+ ofs << this->size() << ", pdata: " << mPartData.size() << " (" << mPdataInt.size() << ","
+ << mPdataReal.size() << "," << mPdataVec3.size() << ") \n";
+ for (IndexInt i = 0; i < this->size(); ++i) {
+ ofs << i << ": " << this->getPos(i) << " , " << this->getStatus(i) << ". ";
+ for (IndexInt pd = 0; pd < (IndexInt)mPdataInt.size(); ++pd)
+ ofs << mPdataInt[pd]->get(i) << " ";
+ for (IndexInt pd = 0; pd < (IndexInt)mPdataReal.size(); ++pd)
+ ofs << mPdataReal[pd]->get(i) << " ";
+ for (IndexInt pd = 0; pd < (IndexInt)mPdataVec3.size(); ++pd)
+ ofs << mPdataVec3[pd]->get(i) << " ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+void BasicParticleSystem::writeParticlesRawPositionsGz(const string name) const
+{
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "wb1");
+ if (!gzf)
+ errMsg("can't open file " << name);
+ for (IndexInt i = 0; i < this->size(); ++i) {
+ Vector3D<float> p = toVec3f(this->getPos(i));
+ gzwrite(gzf, &p, sizeof(float) * 3);
+ }
+ gzclose(gzf);
+#else
+ cout << "file format not supported without zlib" << endl;
+#endif
+}
+
+void BasicParticleSystem::writeParticlesRawVelocityGz(const string name) const
+{
+#if NO_ZLIB != 1
+ gzFile gzf = gzopen(name.c_str(), "wb1");
+ if (!gzf)
+ errMsg("can't open file " << name);
+ if (mPdataVec3.size() < 1)
+ errMsg("no vec3 particle data channel found!");
+ // note , assuming particle data vec3 0 is velocity! make optional...
+ for (IndexInt i = 0; i < this->size(); ++i) {
+ Vector3D<float> p = toVec3f(mPdataVec3[0]->get(i));
+ gzwrite(gzf, &p, sizeof(float) * 3);
+ }
+ gzclose(gzf);
+#else
+ cout << "file format not supported without zlib" << endl;
+#endif
+}
+
+void BasicParticleSystem::load(const string name)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ readParticlesUni(name, this);
+ else if (ext == ".raw") // raw = uni for now
+ readParticlesUni(name, this);
+ else
+ errMsg("particle '" + name + "' filetype not supported for loading");
+}
+
+void BasicParticleSystem::save(const string name) const
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".txt")
+ this->writeParticlesText(name);
+ else if (ext == ".uni")
+ writeParticlesUni(name, this);
+ else if (ext == ".raw") // raw = uni for now
+ writeParticlesUni(name, this);
+ // raw data formats, very basic for simple data transfer to other programs
+ else if (ext == ".posgz")
+ this->writeParticlesRawPositionsGz(name);
+ else if (ext == ".velgz")
+ this->writeParticlesRawVelocityGz(name);
+ else
+ errMsg("particle '" + name + "' filetype not supported for saving");
+}
+
+void BasicParticleSystem::printParts(IndexInt start, IndexInt stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ IndexInt s = (start > 0 ? start : 0);
+ IndexInt e = (stop > 0 ? stop : (IndexInt)mData.size());
+ s = Manta::clamp(s, (IndexInt)0, (IndexInt)mData.size());
+ e = Manta::clamp(e, (IndexInt)0, (IndexInt)mData.size());
+
+ for (IndexInt i = s; i < e; ++i) {
+ if (printIndex)
+ sstr << i << ": ";
+ sstr << mData[i].pos << " " << mData[i].flag << "\n";
+ }
+ debMsg(sstr.str(), 1);
+}
+
+std::string BasicParticleSystem::getDataPointer()
+{
+ std::ostringstream out;
+ out << &mData;
+ return out.str();
+}
+
+void BasicParticleSystem::readParticles(BasicParticleSystem *from)
+{
+ // re-allocate all data
+ this->resizeAll(from->size());
+ assertMsg(from->size() == this->size(), "particle size doesn't match");
+
+ for (int i = 0; i < this->size(); ++i) {
+ (*this)[i].pos = (*from)[i].pos;
+ (*this)[i].flag = (*from)[i].flag;
+ }
+ this->transformPositions(from->getParent()->getGridSize(), this->getParent()->getGridSize());
+}
+
+// particle data
+
+ParticleDataBase::ParticleDataBase(FluidSolver *parent) : PbClass(parent), mpParticleSys(NULL)
+{
+}
+
+ParticleDataBase::~ParticleDataBase()
+{
+ // notify parent of deletion
+ if (mpParticleSys)
+ mpParticleSys->deregister(this);
+}
+
+// actual data implementation
+
+template<class T>
+ParticleDataImpl<T>::ParticleDataImpl(FluidSolver *parent)
+ : ParticleDataBase(parent), mpGridSource(NULL), mGridSourceMAC(false)
+{
+}
+
+template<class T>
+ParticleDataImpl<T>::ParticleDataImpl(FluidSolver *parent, ParticleDataImpl<T> *other)
+ : ParticleDataBase(parent), mpGridSource(NULL), mGridSourceMAC(false)
+{
+ this->mData = other->mData;
+ setName(other->getName());
+}
+
+template<class T> ParticleDataImpl<T>::~ParticleDataImpl()
+{
+}
+
+template<class T> IndexInt ParticleDataImpl<T>::getSizeSlow() const
+{
+ return mData.size();
+}
+template<class T> void ParticleDataImpl<T>::addEntry()
+{
+ // add zero'ed entry
+ T tmp = T(0.);
+ // for debugging, force init:
+ // tmp = T(0.02 * mData.size()); // increasing
+ // tmp = T(1.); // constant 1
+ return mData.push_back(tmp);
+}
+template<class T> void ParticleDataImpl<T>::resize(IndexInt s)
+{
+ mData.resize(s);
+}
+template<class T> void ParticleDataImpl<T>::copyValueSlow(IndexInt from, IndexInt to)
+{
+ this->copyValue(from, to);
+}
+template<class T> ParticleDataBase *ParticleDataImpl<T>::clone()
+{
+ ParticleDataImpl<T> *npd = new ParticleDataImpl<T>(getParent(), this);
+ return npd;
+}
+
+template<class T> void ParticleDataImpl<T>::setSource(Grid<T> *grid, bool isMAC)
+{
+ mpGridSource = grid;
+ mGridSourceMAC = isMAC;
+ if (isMAC)
+ assertMsg(dynamic_cast<MACGrid *>(grid) != NULL, "Given grid is not a valid MAC grid");
+}
+
+template<class T> void ParticleDataImpl<T>::initNewValue(IndexInt idx, Vec3 pos)
+{
+ if (!mpGridSource)
+ mData[idx] = 0;
+ else {
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ }
+}
+// special handling needed for velocities
+template<> void ParticleDataImpl<Vec3>::initNewValue(IndexInt idx, Vec3 pos)
+{
+ if (!mpGridSource)
+ mData[idx] = 0;
+ else {
+ if (!mGridSourceMAC)
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ else
+ mData[idx] = ((MACGrid *)mpGridSource)->getInterpolated(pos);
+ }
+}
+
+template<typename T> void ParticleDataImpl<T>::load(string name)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ readPdataUni<T>(name, this);
+ else if (ext == ".raw") // raw = uni for now
+ readPdataUni<T>(name, this);
+ else
+ errMsg("particle data '" + name + "' filetype not supported for loading");
+}
+
+template<typename T> void ParticleDataImpl<T>::save(string name)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ writePdataUni<T>(name, this);
+ else if (ext == ".raw") // raw = uni for now
+ writePdataUni<T>(name, this);
+ else
+ errMsg("particle data '" + name + "' filetype not supported for saving");
+}
+
+// specializations
+
+template<> ParticleDataBase::PdataType ParticleDataImpl<Real>::getType() const
+{
+ return ParticleDataBase::TypeReal;
+}
+template<> ParticleDataBase::PdataType ParticleDataImpl<int>::getType() const
+{
+ return ParticleDataBase::TypeInt;
+}
+template<> ParticleDataBase::PdataType ParticleDataImpl<Vec3>::getType() const
+{
+ return ParticleDataBase::TypeVec3;
+}
+
+// note, we need a flag value for functions such as advection
+// ideally, this value should never be modified
+int ParticleIndexData::flag = 0;
+Vec3 ParticleIndexData::pos = Vec3(0., 0., 0.);
+
+template<class T, class S> struct knPdataAdd : public KernelBase {
+ knPdataAdd(ParticleDataImpl<T> &me, const ParticleDataImpl<S> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const ParticleDataImpl<S> &other) const
+ {
+ me[idx] += other[idx];
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const ParticleDataImpl<S> &getArg1()
+ {
+ return other;
+ }
+ typedef ParticleDataImpl<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataAdd ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const ParticleDataImpl<S> &other;
+};
+template<class T, class S> struct knPdataSub : public KernelBase {
+ knPdataSub(ParticleDataImpl<T> &me, const ParticleDataImpl<S> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const ParticleDataImpl<S> &other) const
+ {
+ me[idx] -= other[idx];
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const ParticleDataImpl<S> &getArg1()
+ {
+ return other;
+ }
+ typedef ParticleDataImpl<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataSub ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const ParticleDataImpl<S> &other;
+};
+template<class T, class S> struct knPdataMult : public KernelBase {
+ knPdataMult(ParticleDataImpl<T> &me, const ParticleDataImpl<S> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const ParticleDataImpl<S> &other) const
+ {
+ me[idx] *= other[idx];
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const ParticleDataImpl<S> &getArg1()
+ {
+ return other;
+ }
+ typedef ParticleDataImpl<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataMult ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const ParticleDataImpl<S> &other;
+};
+template<class T, class S> struct knPdataDiv : public KernelBase {
+ knPdataDiv(ParticleDataImpl<T> &me, const ParticleDataImpl<S> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const ParticleDataImpl<S> &other) const
+ {
+ me[idx] /= other[idx];
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const ParticleDataImpl<S> &getArg1()
+ {
+ return other;
+ }
+ typedef ParticleDataImpl<S> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataDiv ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const ParticleDataImpl<S> &other;
+};
+template<class T> struct knPdataSafeDiv : public KernelBase {
+ knPdataSafeDiv(ParticleDataImpl<T> &me, const ParticleDataImpl<T> &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const ParticleDataImpl<T> &other) const
+ {
+ me[idx] = safeDivide(me[idx], other[idx]);
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const ParticleDataImpl<T> &getArg1()
+ {
+ return other;
+ }
+ typedef ParticleDataImpl<T> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataSafeDiv ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const ParticleDataImpl<T> &other;
+};
+
+template<class T, class S> struct knPdataSetScalar : public KernelBase {
+ knPdataSetScalar(ParticleDataImpl<T> &me, const S &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const S &other) const
+ {
+ me[idx] = other;
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataSetScalar ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const S &other;
+};
+template<class T, class S> struct knPdataAddScalar : public KernelBase {
+ knPdataAddScalar(ParticleDataImpl<T> &me, const S &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const S &other) const
+ {
+ me[idx] += other;
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataAddScalar ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const S &other;
+};
+template<class T, class S> struct knPdataMultScalar : public KernelBase {
+ knPdataMultScalar(ParticleDataImpl<T> &me, const S &other)
+ : KernelBase(me.size()), me(me), other(other)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const S &other) const
+ {
+ me[idx] *= other;
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataMultScalar ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const S &other;
+};
+template<class T, class S> struct knPdataScaledAdd : public KernelBase {
+ knPdataScaledAdd(ParticleDataImpl<T> &me, const ParticleDataImpl<T> &other, const S &factor)
+ : KernelBase(me.size()), me(me), other(other), factor(factor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ ParticleDataImpl<T> &me,
+ const ParticleDataImpl<T> &other,
+ const S &factor) const
+ {
+ me[idx] += factor * other[idx];
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const ParticleDataImpl<T> &getArg1()
+ {
+ return other;
+ }
+ typedef ParticleDataImpl<T> type1;
+ inline const S &getArg2()
+ {
+ return factor;
+ }
+ typedef S type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataScaledAdd ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other, factor);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const ParticleDataImpl<T> &other;
+ const S &factor;
+};
+
+template<class T> struct knPdataClamp : public KernelBase {
+ knPdataClamp(ParticleDataImpl<T> &me, const T vmin, const T vmax)
+ : KernelBase(me.size()), me(me), vmin(vmin), vmax(vmax)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const T vmin, const T vmax) const
+ {
+ me[idx] = clamp(me[idx], vmin, vmax);
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const T &getArg1()
+ {
+ return vmin;
+ }
+ typedef T type1;
+ inline const T &getArg2()
+ {
+ return vmax;
+ }
+ typedef T type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataClamp ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, vmin, vmax);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const T vmin;
+ const T vmax;
+};
+template<class T> struct knPdataClampMin : public KernelBase {
+ knPdataClampMin(ParticleDataImpl<T> &me, const T vmin)
+ : KernelBase(me.size()), me(me), vmin(vmin)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const T vmin) const
+ {
+ me[idx] = std::max(vmin, me[idx]);
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const T &getArg1()
+ {
+ return vmin;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataClampMin ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, vmin);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const T vmin;
+};
+template<class T> struct knPdataClampMax : public KernelBase {
+ knPdataClampMax(ParticleDataImpl<T> &me, const T vmax)
+ : KernelBase(me.size()), me(me), vmax(vmax)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const T vmax) const
+ {
+ me[idx] = std::min(vmax, me[idx]);
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const T &getArg1()
+ {
+ return vmax;
+ }
+ typedef T type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataClampMax ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, vmax);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const T vmax;
+};
+
+struct knPdataClampMinVec3 : public KernelBase {
+ knPdataClampMinVec3(ParticleDataImpl<Vec3> &me, const Real vmin)
+ : KernelBase(me.size()), me(me), vmin(vmin)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<Vec3> &me, const Real vmin) const
+ {
+ me[idx].x = std::max(vmin, me[idx].x);
+ me[idx].y = std::max(vmin, me[idx].y);
+ me[idx].z = std::max(vmin, me[idx].z);
+ }
+ inline ParticleDataImpl<Vec3> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<Vec3> type0;
+ inline const Real &getArg1()
+ {
+ return vmin;
+ }
+ typedef Real type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataClampMinVec3 ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, vmin);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<Vec3> &me;
+ const Real vmin;
+};
+
+struct knPdataClampMaxVec3 : public KernelBase {
+ knPdataClampMaxVec3(ParticleDataImpl<Vec3> &me, const Real vmax)
+ : KernelBase(me.size()), me(me), vmax(vmax)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleDataImpl<Vec3> &me, const Real vmax) const
+ {
+ me[idx].x = std::min(vmax, me[idx].x);
+ me[idx].y = std::min(vmax, me[idx].y);
+ me[idx].z = std::min(vmax, me[idx].z);
+ }
+ inline ParticleDataImpl<Vec3> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<Vec3> type0;
+ inline const Real &getArg1()
+ {
+ return vmax;
+ }
+ typedef Real type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataClampMaxVec3 ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, vmax);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<Vec3> &me;
+ const Real vmax;
+};
+
+// python operators
+
+template<typename T>
+ParticleDataImpl<T> &ParticleDataImpl<T>::copyFrom(const ParticleDataImpl<T> &a)
+{
+ assertMsg(a.mData.size() == mData.size(),
+ "different pdata size " << a.mData.size() << " vs " << this->mData.size());
+ mData = a.mData;
+ return *this;
+}
+
+template<typename T> void ParticleDataImpl<T>::setConst(const T &s)
+{
+ knPdataSetScalar<T, T> op(*this, s);
+}
+
+template<typename T>
+void ParticleDataImpl<T>::setConstRange(const T &s, const int begin, const int end)
+{
+ for (int i = begin; i < end; ++i)
+ (*this)[i] = s;
+}
+
+// special set by flag
+
+template<class T, class S> struct knPdataSetScalarIntFlag : public KernelBase {
+ knPdataSetScalarIntFlag(ParticleDataImpl<T> &me,
+ const S &other,
+ const ParticleDataImpl<int> &t,
+ const int itype)
+ : KernelBase(me.size()), me(me), other(other), t(t), itype(itype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ ParticleDataImpl<T> &me,
+ const S &other,
+ const ParticleDataImpl<int> &t,
+ const int itype) const
+ {
+ if (t[idx] & itype)
+ me[idx] = other;
+ }
+ inline ParticleDataImpl<T> &getArg0()
+ {
+ return me;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const S &getArg1()
+ {
+ return other;
+ }
+ typedef S type1;
+ inline const ParticleDataImpl<int> &getArg2()
+ {
+ return t;
+ }
+ typedef ParticleDataImpl<int> type2;
+ inline const int &getArg3()
+ {
+ return itype;
+ }
+ typedef int type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPdataSetScalarIntFlag ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other, t, itype);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<T> &me;
+ const S &other;
+ const ParticleDataImpl<int> &t;
+ const int itype;
+};
+template<typename T>
+void ParticleDataImpl<T>::setConstIntFlag(const T &s,
+ const ParticleDataImpl<int> &t,
+ const int itype)
+{
+ knPdataSetScalarIntFlag<T, T> op(*this, s, t, itype);
+}
+
+template<typename T> void ParticleDataImpl<T>::add(const ParticleDataImpl<T> &a)
+{
+ knPdataAdd<T, T> op(*this, a);
+}
+template<typename T> void ParticleDataImpl<T>::sub(const ParticleDataImpl<T> &a)
+{
+ knPdataSub<T, T> op(*this, a);
+}
+
+template<typename T> void ParticleDataImpl<T>::addConst(const T &s)
+{
+ knPdataAddScalar<T, T> op(*this, s);
+}
+
+template<typename T>
+void ParticleDataImpl<T>::addScaled(const ParticleDataImpl<T> &a, const T &factor)
+{
+ knPdataScaledAdd<T, T> op(*this, a, factor);
+}
+
+template<typename T> void ParticleDataImpl<T>::mult(const ParticleDataImpl<T> &a)
+{
+ knPdataMult<T, T> op(*this, a);
+}
+
+template<typename T> void ParticleDataImpl<T>::safeDiv(const ParticleDataImpl<T> &a)
+{
+ knPdataSafeDiv<T> op(*this, a);
+}
+
+template<typename T> void ParticleDataImpl<T>::multConst(const T &s)
+{
+ knPdataMultScalar<T, T> op(*this, s);
+}
+
+template<typename T> void ParticleDataImpl<T>::clamp(const Real vmin, const Real vmax)
+{
+ knPdataClamp<T> op(*this, vmin, vmax);
+}
+
+template<typename T> void ParticleDataImpl<T>::clampMin(const Real vmin)
+{
+ knPdataClampMin<T> op(*this, vmin);
+}
+template<typename T> void ParticleDataImpl<T>::clampMax(const Real vmax)
+{
+ knPdataClampMax<T> op(*this, vmax);
+}
+
+template<> void ParticleDataImpl<Vec3>::clampMin(const Real vmin)
+{
+ knPdataClampMinVec3 op(*this, vmin);
+}
+template<> void ParticleDataImpl<Vec3>::clampMax(const Real vmax)
+{
+ knPdataClampMaxVec3 op(*this, vmax);
+}
+
+template<typename T> struct KnPtsSum : public KernelBase {
+ KnPtsSum(const ParticleDataImpl<T> &val, const ParticleDataImpl<int> *t, const int itype)
+ : KernelBase(val.size()), val(val), t(t), itype(itype), result(T(0.))
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const ParticleDataImpl<T> &val,
+ const ParticleDataImpl<int> *t,
+ const int itype,
+ T &result)
+ {
+ if (t && !((*t)[idx] & itype))
+ return;
+ result += val[idx];
+ }
+ inline operator T()
+ {
+ return result;
+ }
+ inline T &getRet()
+ {
+ return result;
+ }
+ inline const ParticleDataImpl<T> &getArg0()
+ {
+ return val;
+ }
+ typedef ParticleDataImpl<T> type0;
+ inline const ParticleDataImpl<int> *getArg1()
+ {
+ return t;
+ }
+ typedef ParticleDataImpl<int> type1;
+ inline const int &getArg2()
+ {
+ return itype;
+ }
+ typedef int type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnPtsSum ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, t, itype, result);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ KnPtsSum(KnPtsSum &o, tbb::split)
+ : KernelBase(o), val(o.val), t(o.t), itype(o.itype), result(T(0.))
+ {
+ }
+ void join(const KnPtsSum &o)
+ {
+ result += o.result;
+ }
+ const ParticleDataImpl<T> &val;
+ const ParticleDataImpl<int> *t;
+ const int itype;
+ T result;
+};
+template<typename T> struct KnPtsSumSquare : public KernelBase {
+ KnPtsSumSquare(const ParticleDataImpl<T> &val) : KernelBase(val.size()), val(val), result(0.)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const ParticleDataImpl<T> &val, Real &result)
+ {
+ result += normSquare(val[idx]);
+ }
+ inline operator Real()
+ {
+ return result;
+ }
+ inline Real &getRet()
+ {
+ return result;
+ }
+ inline const ParticleDataImpl<T> &getArg0()
+ {
+ return val;
+ }
+ typedef ParticleDataImpl<T> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnPtsSumSquare ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, result);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ KnPtsSumSquare(KnPtsSumSquare &o, tbb::split) : KernelBase(o), val(o.val), result(0.)
+ {
+ }
+ void join(const KnPtsSumSquare &o)
+ {
+ result += o.result;
+ }
+ const ParticleDataImpl<T> &val;
+ Real result;
+};
+template<typename T> struct KnPtsSumMagnitude : public KernelBase {
+ KnPtsSumMagnitude(const ParticleDataImpl<T> &val) : KernelBase(val.size()), val(val), result(0.)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const ParticleDataImpl<T> &val, Real &result)
+ {
+ result += norm(val[idx]);
+ }
+ inline operator Real()
+ {
+ return result;
+ }
+ inline Real &getRet()
+ {
+ return result;
+ }
+ inline const ParticleDataImpl<T> &getArg0()
+ {
+ return val;
+ }
+ typedef ParticleDataImpl<T> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnPtsSumMagnitude ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, result);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ KnPtsSumMagnitude(KnPtsSumMagnitude &o, tbb::split) : KernelBase(o), val(o.val), result(0.)
+ {
+ }
+ void join(const KnPtsSumMagnitude &o)
+ {
+ result += o.result;
+ }
+ const ParticleDataImpl<T> &val;
+ Real result;
+};
+
+template<typename T>
+T ParticleDataImpl<T>::sum(const ParticleDataImpl<int> *t, const int itype) const
+{
+ return KnPtsSum<T>(*this, t, itype);
+}
+template<typename T> Real ParticleDataImpl<T>::sumSquare() const
+{
+ return KnPtsSumSquare<T>(*this);
+}
+template<typename T> Real ParticleDataImpl<T>::sumMagnitude() const
+{
+ return KnPtsSumMagnitude<T>(*this);
+}
+
+template<typename T>
+
+struct CompPdata_Min : public KernelBase {
+ CompPdata_Min(const ParticleDataImpl<T> &val)
+ : KernelBase(val.size()), val(val), minVal(std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const ParticleDataImpl<T> &val, Real &minVal)
+ {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+ }
+ inline operator Real()
+ {
+ return minVal;
+ }
+ inline Real &getRet()
+ {
+ return minVal;
+ }
+ inline const ParticleDataImpl<T> &getArg0()
+ {
+ return val;
+ }
+ typedef ParticleDataImpl<T> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompPdata_Min ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, minVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompPdata_Min(CompPdata_Min &o, tbb::split)
+ : KernelBase(o), val(o.val), minVal(std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompPdata_Min &o)
+ {
+ minVal = min(minVal, o.minVal);
+ }
+ const ParticleDataImpl<T> &val;
+ Real minVal;
+};
+
+template<typename T>
+
+struct CompPdata_Max : public KernelBase {
+ CompPdata_Max(const ParticleDataImpl<T> &val)
+ : KernelBase(val.size()), val(val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const ParticleDataImpl<T> &val, Real &maxVal)
+ {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+ }
+ inline operator Real()
+ {
+ return maxVal;
+ }
+ inline Real &getRet()
+ {
+ return maxVal;
+ }
+ inline const ParticleDataImpl<T> &getArg0()
+ {
+ return val;
+ }
+ typedef ParticleDataImpl<T> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompPdata_Max ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, maxVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompPdata_Max(CompPdata_Max &o, tbb::split)
+ : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompPdata_Max &o)
+ {
+ maxVal = max(maxVal, o.maxVal);
+ }
+ const ParticleDataImpl<T> &val;
+ Real maxVal;
+};
+
+template<typename T> Real ParticleDataImpl<T>::getMin() const
+{
+ return CompPdata_Min<T>(*this);
+}
+
+template<typename T> Real ParticleDataImpl<T>::getMaxAbs() const
+{
+ Real amin = CompPdata_Min<T>(*this);
+ Real amax = CompPdata_Max<T>(*this);
+ return max(fabs(amin), fabs(amax));
+}
+
+template<typename T> Real ParticleDataImpl<T>::getMax() const
+{
+ return CompPdata_Max<T>(*this);
+}
+
+template<typename T>
+void ParticleDataImpl<T>::printPdata(IndexInt start, IndexInt stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ IndexInt s = (start > 0 ? start : 0);
+ IndexInt e = (stop > 0 ? stop : (IndexInt)mData.size());
+ s = Manta::clamp(s, (IndexInt)0, (IndexInt)mData.size());
+ e = Manta::clamp(e, (IndexInt)0, (IndexInt)mData.size());
+
+ for (IndexInt i = s; i < e; ++i) {
+ if (printIndex)
+ sstr << i << ": ";
+ sstr << mData[i] << " "
+ << "\n";
+ }
+ debMsg(sstr.str(), 1);
+}
+template<class T> std::string ParticleDataImpl<T>::getDataPointer()
+{
+ std::ostringstream out;
+ out << &mData;
+ return out.str();
+}
+
+// specials for vec3
+// work on length values, ie, always positive (in contrast to scalar versions above)
+
+struct CompPdata_MinVec3 : public KernelBase {
+ CompPdata_MinVec3(const ParticleDataImpl<Vec3> &val)
+ : KernelBase(val.size()), val(val), minVal(std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const ParticleDataImpl<Vec3> &val, Real &minVal)
+ {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+ }
+ inline operator Real()
+ {
+ return minVal;
+ }
+ inline Real &getRet()
+ {
+ return minVal;
+ }
+ inline const ParticleDataImpl<Vec3> &getArg0()
+ {
+ return val;
+ }
+ typedef ParticleDataImpl<Vec3> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompPdata_MinVec3 ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, minVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompPdata_MinVec3(CompPdata_MinVec3 &o, tbb::split)
+ : KernelBase(o), val(o.val), minVal(std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompPdata_MinVec3 &o)
+ {
+ minVal = min(minVal, o.minVal);
+ }
+ const ParticleDataImpl<Vec3> &val;
+ Real minVal;
+};
+
+struct CompPdata_MaxVec3 : public KernelBase {
+ CompPdata_MaxVec3(const ParticleDataImpl<Vec3> &val)
+ : KernelBase(val.size()), val(val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const ParticleDataImpl<Vec3> &val, Real &maxVal)
+ {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+ }
+ inline operator Real()
+ {
+ return maxVal;
+ }
+ inline Real &getRet()
+ {
+ return maxVal;
+ }
+ inline const ParticleDataImpl<Vec3> &getArg0()
+ {
+ return val;
+ }
+ typedef ParticleDataImpl<Vec3> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CompPdata_MaxVec3 ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, val, maxVal);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CompPdata_MaxVec3(CompPdata_MaxVec3 &o, tbb::split)
+ : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<Real>::max())
+ {
+ }
+ void join(const CompPdata_MaxVec3 &o)
+ {
+ maxVal = max(maxVal, o.maxVal);
+ }
+ const ParticleDataImpl<Vec3> &val;
+ Real maxVal;
+};
+
+template<> Real ParticleDataImpl<Vec3>::getMin() const
+{
+ return sqrt(CompPdata_MinVec3(*this));
+}
+
+template<> Real ParticleDataImpl<Vec3>::getMaxAbs() const
+{
+ return sqrt(CompPdata_MaxVec3(*this)); // no minimum necessary here
+}
+
+template<> Real ParticleDataImpl<Vec3>::getMax() const
+{
+ return sqrt(CompPdata_MaxVec3(*this));
+}
+
+// explicit instantiation
+template class ParticleDataImpl<int>;
+template class ParticleDataImpl<Real>;
+template class ParticleDataImpl<Vec3>;
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/particle.h b/extern/mantaflow/preprocessed/particle.h
new file mode 100644
index 00000000000..2d41397a961
--- /dev/null
+++ b/extern/mantaflow/preprocessed/particle.h
@@ -0,0 +1,2582 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Base class for particle systems
+ *
+ ******************************************************************************/
+
+#ifndef _PARTICLE_H
+#define _PARTICLE_H
+
+#include <vector>
+#include "grid.h"
+#include "vectorbase.h"
+#include "integrator.h"
+#include "randomstream.h"
+namespace Manta {
+
+// fwd decl
+template<class T> class Grid;
+class ParticleDataBase;
+template<class T> class ParticleDataImpl;
+
+//! Baseclass for particle systems. Does not implement any data
+class ParticleBase : public PbClass {
+ public:
+ enum SystemType { BASE = 0, PARTICLE, VORTEX, FILAMENT, FLIP, TURBULENCE, INDEX };
+
+ enum ParticleStatus {
+ PNONE = 0,
+ PNEW = (1 << 0), // particles newly created in this step
+ PSPRAY = (1 << 1), // secondary particle types
+ PBUBBLE = (1 << 2),
+ PFOAM = (1 << 3),
+ PTRACER = (1 << 4),
+ PDELETE = (1 << 10), // mark as deleted, will be deleted in next compress() step
+ PINVALID = (1 << 30), // unused
+ };
+
+ ParticleBase(FluidSolver *parent);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "ParticleBase::ParticleBase", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new ParticleBase(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "ParticleBase::ParticleBase", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleBase::ParticleBase", e.what());
+ return -1;
+ }
+ }
+
+ virtual ~ParticleBase();
+
+ //! copy all the particle data thats registered with the other particle system to this one
+ virtual void cloneParticleData(ParticleBase *nm);
+
+ virtual SystemType getType() const
+ {
+ return BASE;
+ }
+ virtual std::string infoString() const;
+ virtual ParticleBase *clone()
+ {
+ assertMsg(false, "Dont use, override...");
+ return NULL;
+ }
+
+ //! slow virtual function to query size, do not use in kernels! use size() instead
+ virtual IndexInt getSizeSlow() const
+ {
+ assertMsg(false, "Dont use, override...");
+ return 0;
+ }
+
+ //! add a position as potential candidate for new particle (todo, make usable from parallel
+ //! threads)
+ inline void addBuffered(const Vec3 &pos, int flag = 0);
+
+ //! particle data functions
+
+ //! create a particle data object
+ PbClass *create(PbType type, PbTypeVec T = PbTypeVec(), const std::string &name = "");
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleBase *pbo = dynamic_cast<ParticleBase *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleBase::create", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ PbType type = _args.get<PbType>("type", 0, &_lock);
+ PbTypeVec T = _args.getOpt<PbTypeVec>("T", 1, PbTypeVec(), &_lock);
+ const std::string &name = _args.getOpt<std::string>("name", 2, "", &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->create(type, T, name));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleBase::create", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleBase::create", e.what());
+ return 0;
+ }
+ }
+
+ //! add a particle data field, set its parent particle-system pointer
+ void registerPdata(ParticleDataBase *pdata);
+ void registerPdataReal(ParticleDataImpl<Real> *pdata);
+ void registerPdataVec3(ParticleDataImpl<Vec3> *pdata);
+ void registerPdataInt(ParticleDataImpl<int> *pdata);
+ //! remove a particle data entry
+ void deregister(ParticleDataBase *pdata);
+ //! add one zero entry to all data fields
+ void addAllPdata();
+ // note - deletion of pdata is handled in compress function
+
+ //! how many are there?
+ IndexInt getNumPdata() const
+ {
+ return mPartData.size();
+ }
+ //! access one of the fields
+ ParticleDataBase *getPdata(int i)
+ {
+ return mPartData[i];
+ }
+
+ protected:
+ //! new particle candidates
+ std::vector<Vec3> mNewBufferPos;
+ std::vector<int> mNewBufferFlag;
+
+ //! allow automatic compression / resize? disallowed for, eg, flip particle systems
+ bool mAllowCompress;
+
+ //! store particle data , each pointer has its own storage vector of a certain type (int, real,
+ //! vec3)
+ std::vector<ParticleDataBase *> mPartData;
+ //! lists of different types, for fast operations w/o virtual function calls (all calls necessary
+ //! per particle)
+ std::vector<ParticleDataImpl<Real> *> mPdataReal;
+ std::vector<ParticleDataImpl<Vec3> *> mPdataVec3;
+ std::vector<ParticleDataImpl<int> *>
+ mPdataInt; //! indicate that pdata of this particle system is copied, and needs to be freed
+ bool mFreePdata;
+ public:
+ PbArgs _args;
+}
+#define _C_ParticleBase
+;
+
+//! Main class for particle systems
+/*! Basetype S must at least contain flag, pos fields */
+template<class S> class ParticleSystem : public ParticleBase {
+ public:
+ ParticleSystem(FluidSolver *parent) : ParticleBase(parent), mDeletes(0), mDeleteChunk(0)
+ {
+ }
+ static int _W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "ParticleSystem::ParticleSystem", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new ParticleSystem(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "ParticleSystem::ParticleSystem", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleSystem::ParticleSystem", e.what());
+ return -1;
+ }
+ }
+
+ virtual ~ParticleSystem(){};
+
+ virtual SystemType getType() const
+ {
+ return S::getType();
+ };
+
+ //! accessors
+ inline S &operator[](IndexInt idx)
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return mData[idx];
+ }
+ inline const S &operator[](IndexInt idx) const
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return mData[idx];
+ }
+ //! return size of container
+ //! note , python binding disabled for now! cannot yet deal with long-long types
+ inline IndexInt size() const
+ {
+ return mData.size();
+ }
+ //! slow virtual function of base class, also returns size
+ virtual IndexInt getSizeSlow() const
+ {
+ return size();
+ }
+ //! note , special call for python, note - doesnt support more than 2b parts!
+ int pySize() const
+ {
+ return (int)mData.size();
+ }
+ static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleSystem *pbo = dynamic_cast<ParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleSystem::pySize", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->pySize());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleSystem::pySize", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleSystem::pySize", e.what());
+ return 0;
+ }
+ }
+
+ //! query status
+ inline int getStatus(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return mData[idx].flag;
+ }
+ inline bool isActive(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return (mData[idx].flag & PDELETE) == 0;
+ }
+ inline bool isSpray(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return (mData[idx].flag & PSPRAY);
+ }
+ inline bool isBubble(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return (mData[idx].flag & PBUBBLE);
+ }
+ inline bool isFoam(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return (mData[idx].flag & PFOAM);
+ }
+ inline bool isTracer(IndexInt idx) const
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return (mData[idx].flag & PTRACER);
+ }
+
+ //! update status
+ inline void setStatus(IndexInt idx, const int status)
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ mData[idx].flag = status;
+ }
+
+ //! safe accessor for python
+ void setPos(const IndexInt idx, const Vec3 &pos)
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ mData[idx].pos = pos;
+ }
+ static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleSystem *pbo = dynamic_cast<ParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleSystem::setPos", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const IndexInt idx = _args.get<IndexInt>("idx", 0, &_lock);
+ const Vec3 &pos = _args.get<Vec3>("pos", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setPos(idx, pos);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleSystem::setPos", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleSystem::setPos", e.what());
+ return 0;
+ }
+ }
+
+ const Vec3 &getPos(const IndexInt idx) const
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return mData[idx].pos;
+ }
+ static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleSystem *pbo = dynamic_cast<ParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleSystem::getPos", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const IndexInt idx = _args.get<IndexInt>("idx", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getPos(idx));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleSystem::getPos", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleSystem::getPos", e.what());
+ return 0;
+ }
+ }
+
+ //! copy all positions into pdata vec3 field
+ void getPosPdata(ParticleDataImpl<Vec3> &target) const;
+ static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleSystem *pbo = dynamic_cast<ParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleSystem::getPosPdata", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ ParticleDataImpl<Vec3> &target = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "target", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->getPosPdata(target);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleSystem::getPosPdata", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleSystem::getPosPdata", e.what());
+ return 0;
+ }
+ }
+
+ void setPosPdata(const ParticleDataImpl<Vec3> &source);
+ static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleSystem *pbo = dynamic_cast<ParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleSystem::setPosPdata", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const ParticleDataImpl<Vec3> &source = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "source", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setPosPdata(source);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleSystem::setPosPdata", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleSystem::setPosPdata", e.what());
+ return 0;
+ }
+ }
+
+ //! transform coordinate system from one grid size to another (usually upon load)
+ void transformPositions(Vec3i dimOld, Vec3i dimNew);
+
+ //! explicitly trigger compression from outside
+ void doCompress()
+ {
+ if (mDeletes > mDeleteChunk)
+ compress();
+ }
+ //! insert buffered positions as new particles, update additional particle data
+ void insertBufferedParticles();
+ //! resize data vector, and all pdata fields
+ void resizeAll(IndexInt newsize);
+
+ //! adding and deleting
+ inline void kill(IndexInt idx);
+ IndexInt add(const S &data);
+ //! remove all particles, init 0 length arrays (also pdata)
+ void clear();
+ static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleSystem *pbo = dynamic_cast<ParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleSystem::clear", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clear();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleSystem::clear", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleSystem::clear", e.what());
+ return 0;
+ }
+ }
+
+ //! Advect particle in grid velocity field
+ void advectInGrid(const FlagGrid &flags,
+ const MACGrid &vel,
+ const int integrationMode,
+ const bool deleteInObstacle = true,
+ const bool stopInObstacle = true,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0);
+ static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleSystem *pbo = dynamic_cast<ParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleSystem::advectInGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const int integrationMode = _args.get<int>("integrationMode", 2, &_lock);
+ const bool deleteInObstacle = _args.getOpt<bool>("deleteInObstacle", 3, true, &_lock);
+ const bool stopInObstacle = _args.getOpt<bool>("stopInObstacle", 4, true, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 5, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 6, 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->advectInGrid(
+ flags, vel, integrationMode, deleteInObstacle, stopInObstacle, ptype, exclude);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleSystem::advectInGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleSystem::advectInGrid", e.what());
+ return 0;
+ }
+ }
+
+ //! Project particles outside obstacles
+ void projectOutside(Grid<Vec3> &gradient);
+ static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleSystem *pbo = dynamic_cast<ParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleSystem::projectOutside", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &gradient = *_args.getPtr<Grid<Vec3>>("gradient", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->projectOutside(gradient);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleSystem::projectOutside", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleSystem::projectOutside", e.what());
+ return 0;
+ }
+ }
+
+ void projectOutOfBnd(const FlagGrid &flags,
+ const Real bnd,
+ const std::string &plane = "xXyYzZ",
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0);
+ static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleSystem *pbo = dynamic_cast<ParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleSystem::projectOutOfBnd", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const Real bnd = _args.get<Real>("bnd", 1, &_lock);
+ const std::string &plane = _args.getOpt<std::string>("plane", 2, "xXyYzZ", &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 3, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 4, 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->projectOutOfBnd(flags, bnd, plane, ptype, exclude);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleSystem::projectOutOfBnd", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleSystem::projectOutOfBnd", e.what());
+ return 0;
+ }
+ }
+
+ virtual ParticleBase *clone();
+ virtual std::string infoString() const;
+
+ //! debugging
+ inline void checkPartIndex(IndexInt idx) const;
+
+ protected:
+ //! deletion count , and interval for re-compressing
+ IndexInt mDeletes, mDeleteChunk;
+ //! the particle data
+ std::vector<S> mData;
+ //! reduce storage , called by doCompress
+ virtual void compress();
+ public:
+ PbArgs _args;
+}
+#define _C_ParticleSystem
+;
+
+//******************************************************************************
+
+//! Simplest data class for particle systems
+//! contains a position and an int flag; note that these are deprectated, and will at
+//! some point be replaced by the more flexible pdata fields. For now manually copy with
+//! getPosPdata / setPosPdata.
+struct BasicParticleData {
+ public:
+ BasicParticleData() : pos(0.), flag(0)
+ {
+ }
+ BasicParticleData(const Vec3 &p) : pos(p), flag(0)
+ {
+ }
+ static ParticleBase::SystemType getType()
+ {
+ return ParticleBase::PARTICLE;
+ }
+
+ //! data (note, this size is currently hard coded for uni i/o)
+ Vec3 pos;
+ int flag;
+};
+
+class BasicParticleSystem : public ParticleSystem<BasicParticleData> {
+ public:
+ BasicParticleSystem(FluidSolver *parent);
+ static int _W_12(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "BasicParticleSystem::BasicParticleSystem", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new BasicParticleSystem(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "BasicParticleSystem::BasicParticleSystem", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("BasicParticleSystem::BasicParticleSystem", e.what());
+ return -1;
+ }
+ }
+
+ //! file io
+ void save(const std::string name) const;
+ static PyObject *_W_13(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ BasicParticleSystem *pbo = dynamic_cast<BasicParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::save", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->save(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "BasicParticleSystem::save", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("BasicParticleSystem::save", e.what());
+ return 0;
+ }
+ }
+
+ void load(const std::string name);
+ static PyObject *_W_14(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ BasicParticleSystem *pbo = dynamic_cast<BasicParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::load", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->load(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "BasicParticleSystem::load", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("BasicParticleSystem::load", e.what());
+ return 0;
+ }
+ }
+
+ //! save to text file
+ void writeParticlesText(const std::string name) const;
+ //! other output formats
+ void writeParticlesRawPositionsGz(const std::string name) const;
+ void writeParticlesRawVelocityGz(const std::string name) const;
+
+ //! read from other particle system (with resize)
+ void readParticles(BasicParticleSystem *from);
+ static PyObject *_W_15(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ BasicParticleSystem *pbo = dynamic_cast<BasicParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::readParticles", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ BasicParticleSystem *from = _args.getPtr<BasicParticleSystem>("from", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->readParticles(from);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "BasicParticleSystem::readParticles", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("BasicParticleSystem::readParticles", e.what());
+ return 0;
+ }
+ }
+
+ //! add particles in python
+ void addParticle(Vec3 pos)
+ {
+ add(BasicParticleData(pos));
+ }
+ static PyObject *_W_16(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ BasicParticleSystem *pbo = dynamic_cast<BasicParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::addParticle", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Vec3 pos = _args.get<Vec3>("pos", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->addParticle(pos);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "BasicParticleSystem::addParticle", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("BasicParticleSystem::addParticle", e.what());
+ return 0;
+ }
+ }
+
+ //! dangerous, get low level access - avoid usage, only used in vortex filament advection for now
+ std::vector<BasicParticleData> &getData()
+ {
+ return mData;
+ }
+
+ void printParts(IndexInt start = -1, IndexInt stop = -1, bool printIndex = false);
+ static PyObject *_W_17(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ BasicParticleSystem *pbo = dynamic_cast<BasicParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::printParts", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ IndexInt start = _args.getOpt<IndexInt>("start", 0, -1, &_lock);
+ IndexInt stop = _args.getOpt<IndexInt>("stop", 1, -1, &_lock);
+ bool printIndex = _args.getOpt<bool>("printIndex", 2, false, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->printParts(start, stop, printIndex);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "BasicParticleSystem::printParts", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("BasicParticleSystem::printParts", e.what());
+ return 0;
+ }
+ }
+
+ //! get data pointer of particle data
+ std::string getDataPointer();
+ static PyObject *_W_18(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ BasicParticleSystem *pbo = dynamic_cast<BasicParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::getDataPointer", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getDataPointer());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "BasicParticleSystem::getDataPointer", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("BasicParticleSystem::getDataPointer", e.what());
+ return 0;
+ }
+ }
+
+ public:
+ PbArgs _args;
+}
+#define _C_BasicParticleSystem
+;
+
+//******************************************************************************
+
+//! Index into other particle system
+// used for grid based neighborhood searches on generic particle systems (stores
+// only active particles, and reduces copied data)
+// note - pos & flag are disabled here, do not use!
+struct ParticleIndexData {
+ public:
+ ParticleIndexData() : sourceIndex(0)
+ {
+ }
+ static ParticleBase::SystemType getType()
+ {
+ return ParticleBase::INDEX;
+ }
+
+ IndexInt sourceIndex; // index of this particle in the original particle system
+ //! note - the following two are needed for template instantiation, but not used
+ //! for the particle index system (use values from original one!)
+ static Vec3 pos; // do not use...
+ static int flag; // not needed usally
+ // Vec3 pos; // enable for debugging
+};
+
+class ParticleIndexSystem : public ParticleSystem<ParticleIndexData> {
+ public:
+ ParticleIndexSystem(FluidSolver *parent) : ParticleSystem<ParticleIndexData>(parent)
+ {
+ }
+ static int _W_19(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "ParticleIndexSystem::ParticleIndexSystem", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new ParticleIndexSystem(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "ParticleIndexSystem::ParticleIndexSystem", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleIndexSystem::ParticleIndexSystem", e.what());
+ return -1;
+ }
+ };
+ //! we only need a resize function...
+ void resize(IndexInt size)
+ {
+ mData.resize(size);
+ }
+ public:
+ PbArgs _args;
+}
+#define _C_ParticleIndexSystem
+;
+
+//******************************************************************************
+
+//! Particle set with connectivity
+
+template<class DATA, class CON> class ConnectedParticleSystem : public ParticleSystem<DATA> {
+ public:
+ ConnectedParticleSystem(FluidSolver *parent) : ParticleSystem<DATA>(parent)
+ {
+ }
+ static int _W_20(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "ConnectedParticleSystem::ConnectedParticleSystem", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new ConnectedParticleSystem(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(
+ obj->getParent(), "ConnectedParticleSystem::ConnectedParticleSystem", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("ConnectedParticleSystem::ConnectedParticleSystem", e.what());
+ return -1;
+ }
+ }
+
+ //! accessors
+ inline bool isSegActive(int i)
+ {
+ return (mSegments[i].flag & ParticleBase::PDELETE) == 0;
+ }
+ inline int segSize() const
+ {
+ return mSegments.size();
+ }
+ inline CON &seg(int i)
+ {
+ return mSegments[i];
+ }
+ inline const CON &seg(int i) const
+ {
+ return mSegments[i];
+ }
+
+ virtual ParticleBase *clone();
+
+ protected:
+ std::vector<CON> mSegments;
+ virtual void compress();
+ public:
+ PbArgs _args;
+}
+#define _C_ConnectedParticleSystem
+;
+
+//******************************************************************************
+
+//! abstract interface for particle data
+class ParticleDataBase : public PbClass {
+ public:
+ ParticleDataBase(FluidSolver *parent);
+ static int _W_21(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "ParticleDataBase::ParticleDataBase", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new ParticleDataBase(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "ParticleDataBase::ParticleDataBase", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataBase::ParticleDataBase", e.what());
+ return -1;
+ }
+ }
+
+ virtual ~ParticleDataBase();
+
+ //! data type IDs, in line with those for grids
+ enum PdataType { TypeNone = 0, TypeReal = 1, TypeInt = 2, TypeVec3 = 4 };
+
+ //! interface functions, using assert instead of pure virtual for python compatibility
+ virtual IndexInt getSizeSlow() const
+ {
+ assertMsg(false, "Dont use, override...");
+ return 0;
+ }
+ virtual void addEntry()
+ {
+ assertMsg(false, "Dont use, override...");
+ return;
+ }
+ virtual ParticleDataBase *clone()
+ {
+ assertMsg(false, "Dont use, override...");
+ return NULL;
+ }
+ virtual PdataType getType() const
+ {
+ assertMsg(false, "Dont use, override...");
+ return TypeNone;
+ }
+ virtual void resize(IndexInt size)
+ {
+ assertMsg(false, "Dont use, override...");
+ return;
+ }
+ virtual void copyValueSlow(IndexInt from, IndexInt to)
+ {
+ assertMsg(false, "Dont use, override...");
+ return;
+ }
+
+ //! set base pointer
+ void setParticleSys(ParticleBase *set)
+ {
+ mpParticleSys = set;
+ }
+
+ //! debugging
+ inline void checkPartIndex(IndexInt idx) const;
+
+ protected:
+ ParticleBase *mpParticleSys;
+ public:
+ PbArgs _args;
+}
+#define _C_ParticleDataBase
+;
+
+//! abstract interface for particle data
+
+template<class T> class ParticleDataImpl : public ParticleDataBase {
+ public:
+ ParticleDataImpl(FluidSolver *parent);
+ static int _W_22(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "ParticleDataImpl::ParticleDataImpl", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new ParticleDataImpl(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "ParticleDataImpl::ParticleDataImpl", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::ParticleDataImpl", e.what());
+ return -1;
+ }
+ }
+
+ ParticleDataImpl(FluidSolver *parent, ParticleDataImpl<T> *other);
+ virtual ~ParticleDataImpl();
+
+ //! access data
+ inline T &get(const IndexInt idx)
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return mData[idx];
+ }
+ inline const T &get(const IndexInt idx) const
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return mData[idx];
+ }
+ inline T &operator[](const IndexInt idx)
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return mData[idx];
+ }
+ inline const T &operator[](const IndexInt idx) const
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ return mData[idx];
+ }
+
+ //! set all values to 0, note - different from particleSystem::clear! doesnt modify size of array
+ //! (has to stay in sync with parent system)
+ void clear();
+ static PyObject *_W_23(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clear", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clear();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::clear", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::clear", e.what());
+ return 0;
+ }
+ }
+
+ //! set grid from which to get data...
+ void setSource(Grid<T> *grid, bool isMAC = false);
+ static PyObject *_W_24(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setSource", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<T> *grid = _args.getPtr<Grid<T>>("grid", 0, &_lock);
+ bool isMAC = _args.getOpt<bool>("isMAC", 1, false, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setSource(grid, isMAC);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::setSource", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::setSource", e.what());
+ return 0;
+ }
+ }
+
+ //! particle data base interface
+ virtual IndexInt getSizeSlow() const;
+ virtual void addEntry();
+ virtual ParticleDataBase *clone();
+ virtual PdataType getType() const;
+ virtual void resize(IndexInt s);
+ virtual void copyValueSlow(IndexInt from, IndexInt to);
+
+ IndexInt size() const
+ {
+ return mData.size();
+ }
+
+ //! fast inlined functions for per particle operations
+ inline void copyValue(IndexInt from, IndexInt to)
+ {
+ get(to) = get(from);
+ }
+ void initNewValue(IndexInt idx, Vec3 pos);
+
+ //! python interface (similar to grid data)
+ ParticleDataImpl<T> &copyFrom(const ParticleDataImpl<T> &a);
+ static PyObject *_W_25(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::copyFrom", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const ParticleDataImpl<T> &a = *_args.getPtr<ParticleDataImpl<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->copyFrom(a));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::copyFrom", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::copyFrom", e.what());
+ return 0;
+ }
+ }
+
+ void setConst(const T &s);
+ static PyObject *_W_26(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const T &s = *_args.getPtr<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::setConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::setConst", e.what());
+ return 0;
+ }
+ }
+
+ void setConstRange(const T &s, const int begin, const int end);
+ static PyObject *_W_27(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setConstRange", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const T &s = *_args.getPtr<T>("s", 0, &_lock);
+ const int begin = _args.get<int>("begin", 1, &_lock);
+ const int end = _args.get<int>("end", 2, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setConstRange(s, begin, end);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::setConstRange", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::setConstRange", e.what());
+ return 0;
+ }
+ }
+
+ void add(const ParticleDataImpl<T> &a);
+ static PyObject *_W_28(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::add", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const ParticleDataImpl<T> &a = *_args.getPtr<ParticleDataImpl<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->add(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::add", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::add", e.what());
+ return 0;
+ }
+ }
+
+ void sub(const ParticleDataImpl<T> &a);
+ static PyObject *_W_29(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sub", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const ParticleDataImpl<T> &a = *_args.getPtr<ParticleDataImpl<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->sub(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::sub", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::sub", e.what());
+ return 0;
+ }
+ }
+
+ void addConst(const T &s);
+ static PyObject *_W_30(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::addConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const T &s = *_args.getPtr<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->addConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::addConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::addConst", e.what());
+ return 0;
+ }
+ }
+
+ void addScaled(const ParticleDataImpl<T> &a, const T &factor);
+ static PyObject *_W_31(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::addScaled", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const ParticleDataImpl<T> &a = *_args.getPtr<ParticleDataImpl<T>>("a", 0, &_lock);
+ const T &factor = *_args.getPtr<T>("factor", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->addScaled(a, factor);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::addScaled", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::addScaled", e.what());
+ return 0;
+ }
+ }
+
+ void mult(const ParticleDataImpl<T> &a);
+ static PyObject *_W_32(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::mult", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const ParticleDataImpl<T> &a = *_args.getPtr<ParticleDataImpl<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->mult(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::mult", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::mult", e.what());
+ return 0;
+ }
+ }
+
+ void multConst(const T &s);
+ static PyObject *_W_33(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::multConst", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const T &s = *_args.getPtr<T>("s", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->multConst(s);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::multConst", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::multConst", e.what());
+ return 0;
+ }
+ }
+
+ void safeDiv(const ParticleDataImpl<T> &a);
+ static PyObject *_W_34(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::safeDiv", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const ParticleDataImpl<T> &a = *_args.getPtr<ParticleDataImpl<T>>("a", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->safeDiv(a);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::safeDiv", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::safeDiv", e.what());
+ return 0;
+ }
+ }
+
+ void clamp(const Real vmin, const Real vmax);
+ static PyObject *_W_35(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clamp", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Real vmin = _args.get<Real>("vmin", 0, &_lock);
+ const Real vmax = _args.get<Real>("vmax", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clamp(vmin, vmax);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::clamp", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::clamp", e.what());
+ return 0;
+ }
+ }
+
+ void clampMin(const Real vmin);
+ static PyObject *_W_36(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clampMin", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Real vmin = _args.get<Real>("vmin", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clampMin(vmin);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::clampMin", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::clampMin", e.what());
+ return 0;
+ }
+ }
+
+ void clampMax(const Real vmax);
+ static PyObject *_W_37(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clampMax", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Real vmax = _args.get<Real>("vmax", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->clampMax(vmax);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::clampMax", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::clampMax", e.what());
+ return 0;
+ }
+ }
+
+ Real getMaxAbs() const;
+ static PyObject *_W_38(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMaxAbs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMaxAbs());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::getMaxAbs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::getMaxAbs", e.what());
+ return 0;
+ }
+ }
+
+ Real getMax() const;
+ static PyObject *_W_39(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMax", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMax());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::getMax", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::getMax", e.what());
+ return 0;
+ }
+ }
+
+ Real getMin() const;
+ static PyObject *_W_40(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMin", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getMin());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::getMin", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::getMin", e.what());
+ return 0;
+ }
+ }
+
+ T sum(const ParticleDataImpl<int> *t = NULL, const int itype = 0) const;
+ static PyObject *_W_41(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sum", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const ParticleDataImpl<int> *t = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "t", 0, NULL, &_lock);
+ const int itype = _args.getOpt<int>("itype", 1, 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->sum(t, itype));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::sum", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::sum", e.what());
+ return 0;
+ }
+ }
+
+ Real sumSquare() const;
+ static PyObject *_W_42(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sumSquare", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->sumSquare());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::sumSquare", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::sumSquare", e.what());
+ return 0;
+ }
+ }
+
+ Real sumMagnitude() const;
+ static PyObject *_W_43(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sumMagnitude", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->sumMagnitude());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::sumMagnitude", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::sumMagnitude", e.what());
+ return 0;
+ }
+ }
+
+ //! special, set if int flag in t has "flag"
+ void setConstIntFlag(const T &s, const ParticleDataImpl<int> &t, const int flag);
+ static PyObject *_W_44(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setConstIntFlag", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const T &s = *_args.getPtr<T>("s", 0, &_lock);
+ const ParticleDataImpl<int> &t = *_args.getPtr<ParticleDataImpl<int>>("t", 1, &_lock);
+ const int flag = _args.get<int>("flag", 2, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setConstIntFlag(s, t, flag);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::setConstIntFlag", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::setConstIntFlag", e.what());
+ return 0;
+ }
+ }
+
+ void printPdata(IndexInt start = -1, IndexInt stop = -1, bool printIndex = false);
+ static PyObject *_W_45(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::printPdata", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ IndexInt start = _args.getOpt<IndexInt>("start", 0, -1, &_lock);
+ IndexInt stop = _args.getOpt<IndexInt>("stop", 1, -1, &_lock);
+ bool printIndex = _args.getOpt<bool>("printIndex", 2, false, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->printPdata(start, stop, printIndex);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::printPdata", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::printPdata", e.what());
+ return 0;
+ }
+ }
+
+ //! file io
+ void save(const std::string name);
+ static PyObject *_W_46(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::save", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->save(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::save", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::save", e.what());
+ return 0;
+ }
+ }
+
+ void load(const std::string name);
+ static PyObject *_W_47(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::load", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const std::string name = _args.get<std::string>("name", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->load(name);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::load", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::load", e.what());
+ return 0;
+ }
+ }
+
+ //! get data pointer of particle data
+ std::string getDataPointer();
+ static PyObject *_W_48(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ ParticleDataImpl *pbo = dynamic_cast<ParticleDataImpl *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getDataPointer", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getDataPointer());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::getDataPointer", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("ParticleDataImpl::getDataPointer", e.what());
+ return 0;
+ }
+ }
+
+ protected:
+ //! data storage
+ std::vector<T> mData;
+
+ //! optionally , we might have an associated grid from which to grab new data
+ Grid<T> *mpGridSource; //! unfortunately , we need to distinguish mac vs regular vec3
+ bool mGridSourceMAC;
+ public:
+ PbArgs _args;
+}
+#define _C_ParticleDataImpl
+;
+
+//******************************************************************************
+// Implementation
+//******************************************************************************
+
+const int DELETE_PART = 20; // chunk size for compression
+
+void ParticleBase::addBuffered(const Vec3 &pos, int flag)
+{
+ mNewBufferPos.push_back(pos);
+ mNewBufferFlag.push_back(flag);
+}
+
+template<class S> void ParticleSystem<S>::clear()
+{
+ mDeleteChunk = mDeletes = 0;
+ this->resizeAll(0); // instead of mData.clear
+}
+
+template<class S> IndexInt ParticleSystem<S>::add(const S &data)
+{
+ mData.push_back(data);
+ mDeleteChunk = mData.size() / DELETE_PART;
+ this->addAllPdata();
+ return mData.size() - 1;
+}
+
+template<class S> inline void ParticleSystem<S>::kill(IndexInt idx)
+{
+ assertMsg(idx >= 0 && idx < size(), "Index out of bounds");
+ mData[idx].flag |= PDELETE;
+ if ((++mDeletes > mDeleteChunk) && (mAllowCompress))
+ compress();
+}
+
+template<class S> void ParticleSystem<S>::getPosPdata(ParticleDataImpl<Vec3> &target) const
+{
+ for (IndexInt i = 0; i < (IndexInt)this->size(); ++i) {
+ target[i] = this->getPos(i);
+ }
+}
+template<class S> void ParticleSystem<S>::setPosPdata(const ParticleDataImpl<Vec3> &source)
+{
+ for (IndexInt i = 0; i < (IndexInt)this->size(); ++i) {
+ this->setPos(i, source[i]);
+ }
+}
+
+template<class S> void ParticleSystem<S>::transformPositions(Vec3i dimOld, Vec3i dimNew)
+{
+ const Vec3 factor = calcGridSizeFactor(dimNew, dimOld);
+ for (IndexInt i = 0; i < (IndexInt)this->size(); ++i) {
+ this->setPos(i, this->getPos(i) * factor);
+ }
+}
+
+// check for deletion/invalid position, otherwise return velocity
+
+template<class S> struct _GridAdvectKernel : public KernelBase {
+ _GridAdvectKernel(const KernelBase &base,
+ std::vector<S> &p,
+ const MACGrid &vel,
+ const FlagGrid &flags,
+ const Real dt,
+ const bool deleteInObstacle,
+ const bool stopInObstacle,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude,
+ std::vector<Vec3> &u)
+ : KernelBase(base),
+ p(p),
+ vel(vel),
+ flags(flags),
+ dt(dt),
+ deleteInObstacle(deleteInObstacle),
+ stopInObstacle(stopInObstacle),
+ ptype(ptype),
+ exclude(exclude),
+ u(u)
+ {
+ }
+ inline void op(IndexInt idx,
+ std::vector<S> &p,
+ const MACGrid &vel,
+ const FlagGrid &flags,
+ const Real dt,
+ const bool deleteInObstacle,
+ const bool stopInObstacle,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude,
+ std::vector<Vec3> &u) const
+ {
+ if ((p[idx].flag & ParticleBase::PDELETE) || (ptype && ((*ptype)[idx] & exclude))) {
+ u[idx] = 0.;
+ return;
+ }
+ // special handling
+ if (deleteInObstacle || stopInObstacle) {
+ if (!flags.isInBounds(p[idx].pos, 1) || flags.isObstacle(p[idx].pos)) {
+ if (stopInObstacle)
+ u[idx] = 0.;
+ // for simple tracer particles, its convenient to delete particles right away
+ // for other sim types, eg flip, we can try to fix positions later on
+ if (deleteInObstacle)
+ p[idx].flag |= ParticleBase::PDELETE;
+ return;
+ }
+ }
+ u[idx] = vel.getInterpolated(p[idx].pos) * dt;
+ }
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, vel, flags, dt, deleteInObstacle, stopInObstacle, ptype, exclude, u);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<S> &p;
+ const MACGrid &vel;
+ const FlagGrid &flags;
+ const Real dt;
+ const bool deleteInObstacle;
+ const bool stopInObstacle;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+ std::vector<Vec3> &u;
+};
+template<class S> struct GridAdvectKernel : public KernelBase {
+ GridAdvectKernel(std::vector<S> &p,
+ const MACGrid &vel,
+ const FlagGrid &flags,
+ const Real dt,
+ const bool deleteInObstacle,
+ const bool stopInObstacle,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(p.size()),
+ _inner(KernelBase(p.size()),
+ p,
+ vel,
+ flags,
+ dt,
+ deleteInObstacle,
+ stopInObstacle,
+ ptype,
+ exclude,
+ u),
+ p(p),
+ vel(vel),
+ flags(flags),
+ dt(dt),
+ deleteInObstacle(deleteInObstacle),
+ stopInObstacle(stopInObstacle),
+ ptype(ptype),
+ exclude(exclude),
+ u((size))
+ {
+ runMessage();
+ run();
+ }
+ void run()
+ {
+ _inner.run();
+ }
+ inline operator std::vector<Vec3>()
+ {
+ return u;
+ }
+ inline std::vector<Vec3> &getRet()
+ {
+ return u;
+ }
+ inline std::vector<S> &getArg0()
+ {
+ return p;
+ }
+ typedef std::vector<S> type0;
+ inline const MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline const FlagGrid &getArg2()
+ {
+ return flags;
+ }
+ typedef FlagGrid type2;
+ inline const Real &getArg3()
+ {
+ return dt;
+ }
+ typedef Real type3;
+ inline const bool &getArg4()
+ {
+ return deleteInObstacle;
+ }
+ typedef bool type4;
+ inline const bool &getArg5()
+ {
+ return stopInObstacle;
+ }
+ typedef bool type5;
+ inline const ParticleDataImpl<int> *getArg6()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type6;
+ inline const int &getArg7()
+ {
+ return exclude;
+ }
+ typedef int type7;
+ void runMessage()
+ {
+ debMsg("Executing kernel GridAdvectKernel ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ _GridAdvectKernel<S> _inner;
+ std::vector<S> &p;
+ const MACGrid &vel;
+ const FlagGrid &flags;
+ const Real dt;
+ const bool deleteInObstacle;
+ const bool stopInObstacle;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+ std::vector<Vec3> u;
+};
+;
+
+// final check after advection to make sure particles haven't escaped
+// (similar to particle advection kernel)
+
+template<class S> struct KnDeleteInObstacle : public KernelBase {
+ KnDeleteInObstacle(std::vector<S> &p, const FlagGrid &flags)
+ : KernelBase(p.size()), p(p), flags(flags)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, std::vector<S> &p, const FlagGrid &flags) const
+ {
+ if (p[idx].flag & ParticleBase::PDELETE)
+ return;
+ if (!flags.isInBounds(p[idx].pos, 1) || flags.isObstacle(p[idx].pos)) {
+ p[idx].flag |= ParticleBase::PDELETE;
+ }
+ }
+ inline std::vector<S> &getArg0()
+ {
+ return p;
+ }
+ typedef std::vector<S> type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnDeleteInObstacle ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, flags);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<S> &p;
+ const FlagGrid &flags;
+};
+
+// try to get closer to actual obstacle boundary
+static inline Vec3 bisectBacktracePos(const FlagGrid &flags, const Vec3 &oldp, const Vec3 &newp)
+{
+ Real s = 0.;
+ for (int i = 1; i < 5; ++i) {
+ Real ds = 1. / (Real)(1 << i);
+ if (!flags.isObstacle(oldp * (1. - (s + ds)) + newp * (s + ds))) {
+ s += ds;
+ }
+ }
+ return (oldp * (1. - (s)) + newp * (s));
+}
+
+// at least make sure all particles are inside domain
+
+template<class S> struct KnClampPositions : public KernelBase {
+ KnClampPositions(std::vector<S> &p,
+ const FlagGrid &flags,
+ ParticleDataImpl<Vec3> *posOld = NULL,
+ bool stopInObstacle = true,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+ : KernelBase(p.size()),
+ p(p),
+ flags(flags),
+ posOld(posOld),
+ stopInObstacle(stopInObstacle),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ std::vector<S> &p,
+ const FlagGrid &flags,
+ ParticleDataImpl<Vec3> *posOld = NULL,
+ bool stopInObstacle = true,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0) const
+ {
+ if (p[idx].flag & ParticleBase::PDELETE)
+ return;
+ if (ptype && ((*ptype)[idx] & exclude)) {
+ if (posOld)
+ p[idx].pos = (*posOld)[idx];
+ return;
+ }
+ if (!flags.isInBounds(p[idx].pos, 0)) {
+ p[idx].pos = clamp(p[idx].pos, Vec3(0.), toVec3(flags.getSize()) - Vec3(1.));
+ }
+ if (stopInObstacle && (flags.isObstacle(p[idx].pos))) {
+ p[idx].pos = bisectBacktracePos(flags, (*posOld)[idx], p[idx].pos);
+ }
+ }
+ inline std::vector<S> &getArg0()
+ {
+ return p;
+ }
+ typedef std::vector<S> type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline ParticleDataImpl<Vec3> *getArg2()
+ {
+ return posOld;
+ }
+ typedef ParticleDataImpl<Vec3> type2;
+ inline bool &getArg3()
+ {
+ return stopInObstacle;
+ }
+ typedef bool type3;
+ inline const ParticleDataImpl<int> *getArg4()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type4;
+ inline const int &getArg5()
+ {
+ return exclude;
+ }
+ typedef int type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnClampPositions ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, flags, posOld, stopInObstacle, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ std::vector<S> &p;
+ const FlagGrid &flags;
+ ParticleDataImpl<Vec3> *posOld;
+ bool stopInObstacle;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+// advection plugin
+template<class S>
+void ParticleSystem<S>::advectInGrid(const FlagGrid &flags,
+ const MACGrid &vel,
+ const int integrationMode,
+ const bool deleteInObstacle,
+ const bool stopInObstacle,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+{
+ // position clamp requires old positions, backup
+ ParticleDataImpl<Vec3> *posOld = NULL;
+ if (!deleteInObstacle) {
+ posOld = new ParticleDataImpl<Vec3>(this->getParent());
+ posOld->resize(mData.size());
+ for (IndexInt i = 0; i < (IndexInt)mData.size(); ++i)
+ (*posOld)[i] = mData[i].pos;
+ }
+
+ // update positions
+ GridAdvectKernel<S> kernel(
+ mData, vel, flags, getParent()->getDt(), deleteInObstacle, stopInObstacle, ptype, exclude);
+ integratePointSet(kernel, integrationMode);
+
+ if (!deleteInObstacle) {
+ KnClampPositions<S>(mData, flags, posOld, stopInObstacle, ptype, exclude);
+ delete posOld;
+ }
+ else {
+ KnDeleteInObstacle<S>(mData, flags);
+ }
+}
+
+template<class S> struct KnProjectParticles : public KernelBase {
+ KnProjectParticles(ParticleSystem<S> &part, Grid<Vec3> &gradient)
+ : KernelBase(part.size()), part(part), gradient(gradient)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, ParticleSystem<S> &part, Grid<Vec3> &gradient)
+ {
+ static RandomStream rand(3123984);
+ const double jlen = 0.1;
+
+ if (part.isActive(idx)) {
+ // project along levelset gradient
+ Vec3 p = part[idx].pos;
+ if (gradient.isInBounds(p)) {
+ Vec3 n = gradient.getInterpolated(p);
+ Real dist = normalize(n);
+ Vec3 dx = n * (-dist + jlen * (1 + rand.getReal()));
+ p += dx;
+ }
+ // clamp to outer boundaries (+jitter)
+ const double jlen = 0.1;
+ Vec3 jitter = jlen * rand.getVec3();
+ part[idx].pos = clamp(p, Vec3(1, 1, 1) + jitter, toVec3(gradient.getSize() - 1) - jitter);
+ }
+ }
+ inline ParticleSystem<S> &getArg0()
+ {
+ return part;
+ }
+ typedef ParticleSystem<S> type0;
+ inline Grid<Vec3> &getArg1()
+ {
+ return gradient;
+ }
+ typedef Grid<Vec3> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnProjectParticles ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void run()
+ {
+ const IndexInt _sz = size;
+ for (IndexInt i = 0; i < _sz; i++)
+ op(i, part, gradient);
+ }
+ ParticleSystem<S> &part;
+ Grid<Vec3> &gradient;
+};
+
+template<class S> void ParticleSystem<S>::projectOutside(Grid<Vec3> &gradient)
+{
+ KnProjectParticles<S>(*this, gradient);
+}
+
+template<class S> struct KnProjectOutOfBnd : public KernelBase {
+ KnProjectOutOfBnd(ParticleSystem<S> &part,
+ const FlagGrid &flags,
+ const Real bnd,
+ const bool *axis,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(part.size()),
+ part(part),
+ flags(flags),
+ bnd(bnd),
+ axis(axis),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ ParticleSystem<S> &part,
+ const FlagGrid &flags,
+ const Real bnd,
+ const bool *axis,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (!part.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+ if (axis[0])
+ part[idx].pos.x = std::max(part[idx].pos.x, bnd);
+ if (axis[1])
+ part[idx].pos.x = std::min(part[idx].pos.x, static_cast<Real>(flags.getSizeX()) - bnd);
+ if (axis[2])
+ part[idx].pos.y = std::max(part[idx].pos.y, bnd);
+ if (axis[3])
+ part[idx].pos.y = std::min(part[idx].pos.y, static_cast<Real>(flags.getSizeY()) - bnd);
+ if (flags.is3D()) {
+ if (axis[4])
+ part[idx].pos.z = std::max(part[idx].pos.z, bnd);
+ if (axis[5])
+ part[idx].pos.z = std::min(part[idx].pos.z, static_cast<Real>(flags.getSizeZ()) - bnd);
+ }
+ }
+ inline ParticleSystem<S> &getArg0()
+ {
+ return part;
+ }
+ typedef ParticleSystem<S> type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const Real &getArg2()
+ {
+ return bnd;
+ }
+ typedef Real type2;
+ inline const bool *getArg3()
+ {
+ return axis;
+ }
+ typedef bool type3;
+ inline const ParticleDataImpl<int> *getArg4()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type4;
+ inline const int &getArg5()
+ {
+ return exclude;
+ }
+ typedef int type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnProjectOutOfBnd ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, part, flags, bnd, axis, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleSystem<S> &part;
+ const FlagGrid &flags;
+ const Real bnd;
+ const bool *axis;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+template<class S>
+void ParticleSystem<S>::projectOutOfBnd(const FlagGrid &flags,
+ const Real bnd,
+ const std::string &plane,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+{
+ bool axis[6] = {false};
+ for (std::string::const_iterator it = plane.begin(); it != plane.end(); ++it) {
+ if (*it == 'x')
+ axis[0] = true;
+ if (*it == 'X')
+ axis[1] = true;
+ if (*it == 'y')
+ axis[2] = true;
+ if (*it == 'Y')
+ axis[3] = true;
+ if (*it == 'z')
+ axis[4] = true;
+ if (*it == 'Z')
+ axis[5] = true;
+ }
+ KnProjectOutOfBnd<S>(*this, flags, bnd, axis, ptype, exclude);
+}
+
+template<class S> void ParticleSystem<S>::resizeAll(IndexInt size)
+{
+ // resize all buffers to target size in 1 go
+ mData.resize(size);
+ for (IndexInt i = 0; i < (IndexInt)mPartData.size(); ++i)
+ mPartData[i]->resize(size);
+}
+
+template<class S> void ParticleSystem<S>::compress()
+{
+ IndexInt nextRead = mData.size();
+ for (IndexInt i = 0; i < (IndexInt)mData.size(); i++) {
+ while ((mData[i].flag & PDELETE) != 0) {
+ nextRead--;
+ mData[i] = mData[nextRead];
+ // ugly, but prevent virtual function calls here:
+ for (IndexInt pd = 0; pd < (IndexInt)mPdataReal.size(); ++pd)
+ mPdataReal[pd]->copyValue(nextRead, i);
+ for (IndexInt pd = 0; pd < (IndexInt)mPdataVec3.size(); ++pd)
+ mPdataVec3[pd]->copyValue(nextRead, i);
+ for (IndexInt pd = 0; pd < (IndexInt)mPdataInt.size(); ++pd)
+ mPdataInt[pd]->copyValue(nextRead, i);
+ mData[nextRead].flag = PINVALID;
+ }
+ }
+ if (nextRead < (IndexInt)mData.size())
+ debMsg("Deleted " << ((IndexInt)mData.size() - nextRead) << " particles", 1); // debug info
+
+ resizeAll(nextRead);
+ mDeletes = 0;
+ mDeleteChunk = mData.size() / DELETE_PART;
+}
+
+//! insert buffered positions as new particles, update additional particle data
+template<class S> void ParticleSystem<S>::insertBufferedParticles()
+{
+ if (mNewBufferPos.size() == 0)
+ return;
+ IndexInt newCnt = mData.size();
+ resizeAll(newCnt + mNewBufferPos.size());
+
+ // clear new flag everywhere
+ for (IndexInt i = 0; i < (IndexInt)mData.size(); ++i)
+ mData[i].flag &= ~PNEW;
+
+ for (IndexInt i = 0; i < (IndexInt)mNewBufferPos.size(); ++i) {
+ int flag = (mNewBufferFlag.size() > 0) ? mNewBufferFlag[i] : 0;
+ // note, other fields are not initialized here...
+ mData[newCnt].pos = mNewBufferPos[i];
+ mData[newCnt].flag = PNEW | flag;
+ // now init pdata fields from associated grids...
+ for (IndexInt pd = 0; pd < (IndexInt)mPdataReal.size(); ++pd)
+ mPdataReal[pd]->initNewValue(newCnt, mNewBufferPos[i]);
+ for (IndexInt pd = 0; pd < (IndexInt)mPdataVec3.size(); ++pd)
+ mPdataVec3[pd]->initNewValue(newCnt, mNewBufferPos[i]);
+ for (IndexInt pd = 0; pd < (IndexInt)mPdataInt.size(); ++pd)
+ mPdataInt[pd]->initNewValue(newCnt, mNewBufferPos[i]);
+ newCnt++;
+ }
+ if (mNewBufferPos.size() > 0)
+ debMsg("Added & initialized " << (IndexInt)mNewBufferPos.size() << " particles",
+ 2); // debug info
+ mNewBufferPos.clear();
+ mNewBufferFlag.clear();
+}
+
+template<class DATA, class CON> void ConnectedParticleSystem<DATA, CON>::compress()
+{
+ const IndexInt sz = ParticleSystem<DATA>::size();
+ IndexInt *renumber_back = new IndexInt[sz];
+ IndexInt *renumber = new IndexInt[sz];
+ for (IndexInt i = 0; i < sz; i++)
+ renumber[i] = renumber_back[i] = -1;
+
+ // reorder elements
+ std::vector<DATA> &data = ParticleSystem<DATA>::mData;
+ IndexInt nextRead = sz;
+ for (IndexInt i = 0; i < nextRead; i++) {
+ if ((data[i].flag & ParticleBase::PDELETE) != 0) {
+ nextRead--;
+ data[i] = data[nextRead];
+ data[nextRead].flag = 0;
+ renumber_back[i] = nextRead;
+ }
+ else
+ renumber_back[i] = i;
+ }
+
+ // acceleration structure
+ for (IndexInt i = 0; i < nextRead; i++)
+ renumber[renumber_back[i]] = i;
+
+ // rename indices in filaments
+ for (IndexInt i = 0; i < (IndexInt)mSegments.size(); i++)
+ mSegments[i].renumber(renumber);
+
+ ParticleSystem<DATA>::mData.resize(nextRead);
+ ParticleSystem<DATA>::mDeletes = 0;
+ ParticleSystem<DATA>::mDeleteChunk = ParticleSystem<DATA>::size() / DELETE_PART;
+
+ delete[] renumber;
+ delete[] renumber_back;
+}
+
+template<class S> ParticleBase *ParticleSystem<S>::clone()
+{
+ ParticleSystem<S> *nm = new ParticleSystem<S>(getParent());
+ if (this->mAllowCompress)
+ compress();
+
+ nm->mData = mData;
+ nm->setName(getName());
+ this->cloneParticleData(nm);
+ return nm;
+}
+
+template<class DATA, class CON> ParticleBase *ConnectedParticleSystem<DATA, CON>::clone()
+{
+ ConnectedParticleSystem<DATA, CON> *nm = new ConnectedParticleSystem<DATA, CON>(
+ this->getParent());
+ if (this->mAllowCompress)
+ compress();
+
+ nm->mData = this->mData;
+ nm->mSegments = mSegments;
+ nm->setName(this->getName());
+ this->cloneParticleData(nm);
+ return nm;
+}
+
+template<class S> std::string ParticleSystem<S>::infoString() const
+{
+ std::stringstream s;
+ s << "ParticleSys '" << getName() << "'\n-> ";
+ if (this->getNumPdata() > 0)
+ s << "pdata: " << this->getNumPdata();
+ s << "parts: " << size();
+ // for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i) { sstr << i<<":" << mPartData[i]->size()
+ // <<" "; }
+ return s.str();
+}
+
+template<class S> inline void ParticleSystem<S>::checkPartIndex(IndexInt idx) const
+{
+ IndexInt mySize = this->size();
+ if (idx < 0 || idx > mySize) {
+ errMsg("ParticleBase "
+ << " size " << mySize << " : index " << idx << " out of bound ");
+ }
+}
+
+inline void ParticleDataBase::checkPartIndex(IndexInt idx) const
+{
+ IndexInt mySize = this->getSizeSlow();
+ if (idx < 0 || idx > mySize) {
+ errMsg("ParticleData "
+ << " size " << mySize << " : index " << idx << " out of bound ");
+ }
+ if (mpParticleSys && mpParticleSys->getSizeSlow() != mySize) {
+ errMsg("ParticleData "
+ << " size " << mySize << " does not match parent! (" << mpParticleSys->getSizeSlow()
+ << ") ");
+ }
+}
+
+// set contents to zero, as for a grid
+template<class T> void ParticleDataImpl<T>::clear()
+{
+ for (IndexInt i = 0; i < (IndexInt)mData.size(); ++i)
+ mData[i] = 0.;
+}
+
+//! count by type flag
+int countParticles(const ParticleDataImpl<int> &t, const int flag);
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/particle.h.reg.cpp b/extern/mantaflow/preprocessed/particle.h.reg.cpp
new file mode 100644
index 00000000000..6e0466d0203
--- /dev/null
+++ b/extern/mantaflow/preprocessed/particle.h.reg.cpp
@@ -0,0 +1,437 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "particle.h"
+namespace Manta {
+#ifdef _C_BasicParticleSystem
+static const Pb::Register _R_13("BasicParticleSystem",
+ "BasicParticleSystem",
+ "ParticleSystem<BasicParticleData>");
+template<> const char *Namify<BasicParticleSystem>::S = "BasicParticleSystem";
+static const Pb::Register _R_14("BasicParticleSystem",
+ "BasicParticleSystem",
+ BasicParticleSystem::_W_12);
+static const Pb::Register _R_15("BasicParticleSystem", "save", BasicParticleSystem::_W_13);
+static const Pb::Register _R_16("BasicParticleSystem", "load", BasicParticleSystem::_W_14);
+static const Pb::Register _R_17("BasicParticleSystem",
+ "readParticles",
+ BasicParticleSystem::_W_15);
+static const Pb::Register _R_18("BasicParticleSystem", "addParticle", BasicParticleSystem::_W_16);
+static const Pb::Register _R_19("BasicParticleSystem", "printParts", BasicParticleSystem::_W_17);
+static const Pb::Register _R_20("BasicParticleSystem",
+ "getDataPointer",
+ BasicParticleSystem::_W_18);
+#endif
+#ifdef _C_ParticleBase
+static const Pb::Register _R_21("ParticleBase", "ParticleBase", "PbClass");
+template<> const char *Namify<ParticleBase>::S = "ParticleBase";
+static const Pb::Register _R_22("ParticleBase", "ParticleBase", ParticleBase::_W_0);
+static const Pb::Register _R_23("ParticleBase", "create", ParticleBase::_W_1);
+#endif
+#ifdef _C_ParticleDataBase
+static const Pb::Register _R_24("ParticleDataBase", "ParticleDataBase", "PbClass");
+template<> const char *Namify<ParticleDataBase>::S = "ParticleDataBase";
+static const Pb::Register _R_25("ParticleDataBase", "ParticleDataBase", ParticleDataBase::_W_21);
+#endif
+#ifdef _C_ParticleDataImpl
+static const Pb::Register _R_26("ParticleDataImpl<int>",
+ "ParticleDataImpl<int>",
+ "ParticleDataBase");
+template<> const char *Namify<ParticleDataImpl<int>>::S = "ParticleDataImpl<int>";
+static const Pb::Register _R_27("ParticleDataImpl<int>",
+ "ParticleDataImpl",
+ ParticleDataImpl<int>::_W_22);
+static const Pb::Register _R_28("ParticleDataImpl<int>", "clear", ParticleDataImpl<int>::_W_23);
+static const Pb::Register _R_29("ParticleDataImpl<int>",
+ "setSource",
+ ParticleDataImpl<int>::_W_24);
+static const Pb::Register _R_30("ParticleDataImpl<int>", "copyFrom", ParticleDataImpl<int>::_W_25);
+static const Pb::Register _R_31("ParticleDataImpl<int>", "setConst", ParticleDataImpl<int>::_W_26);
+static const Pb::Register _R_32("ParticleDataImpl<int>",
+ "setConstRange",
+ ParticleDataImpl<int>::_W_27);
+static const Pb::Register _R_33("ParticleDataImpl<int>", "add", ParticleDataImpl<int>::_W_28);
+static const Pb::Register _R_34("ParticleDataImpl<int>", "sub", ParticleDataImpl<int>::_W_29);
+static const Pb::Register _R_35("ParticleDataImpl<int>", "addConst", ParticleDataImpl<int>::_W_30);
+static const Pb::Register _R_36("ParticleDataImpl<int>",
+ "addScaled",
+ ParticleDataImpl<int>::_W_31);
+static const Pb::Register _R_37("ParticleDataImpl<int>", "mult", ParticleDataImpl<int>::_W_32);
+static const Pb::Register _R_38("ParticleDataImpl<int>",
+ "multConst",
+ ParticleDataImpl<int>::_W_33);
+static const Pb::Register _R_39("ParticleDataImpl<int>", "safeDiv", ParticleDataImpl<int>::_W_34);
+static const Pb::Register _R_40("ParticleDataImpl<int>", "clamp", ParticleDataImpl<int>::_W_35);
+static const Pb::Register _R_41("ParticleDataImpl<int>", "clampMin", ParticleDataImpl<int>::_W_36);
+static const Pb::Register _R_42("ParticleDataImpl<int>", "clampMax", ParticleDataImpl<int>::_W_37);
+static const Pb::Register _R_43("ParticleDataImpl<int>",
+ "getMaxAbs",
+ ParticleDataImpl<int>::_W_38);
+static const Pb::Register _R_44("ParticleDataImpl<int>", "getMax", ParticleDataImpl<int>::_W_39);
+static const Pb::Register _R_45("ParticleDataImpl<int>", "getMin", ParticleDataImpl<int>::_W_40);
+static const Pb::Register _R_46("ParticleDataImpl<int>", "sum", ParticleDataImpl<int>::_W_41);
+static const Pb::Register _R_47("ParticleDataImpl<int>",
+ "sumSquare",
+ ParticleDataImpl<int>::_W_42);
+static const Pb::Register _R_48("ParticleDataImpl<int>",
+ "sumMagnitude",
+ ParticleDataImpl<int>::_W_43);
+static const Pb::Register _R_49("ParticleDataImpl<int>",
+ "setConstIntFlag",
+ ParticleDataImpl<int>::_W_44);
+static const Pb::Register _R_50("ParticleDataImpl<int>",
+ "printPdata",
+ ParticleDataImpl<int>::_W_45);
+static const Pb::Register _R_51("ParticleDataImpl<int>", "save", ParticleDataImpl<int>::_W_46);
+static const Pb::Register _R_52("ParticleDataImpl<int>", "load", ParticleDataImpl<int>::_W_47);
+static const Pb::Register _R_53("ParticleDataImpl<int>",
+ "getDataPointer",
+ ParticleDataImpl<int>::_W_48);
+static const Pb::Register _R_54("ParticleDataImpl<Real>",
+ "ParticleDataImpl<Real>",
+ "ParticleDataBase");
+template<> const char *Namify<ParticleDataImpl<Real>>::S = "ParticleDataImpl<Real>";
+static const Pb::Register _R_55("ParticleDataImpl<Real>",
+ "ParticleDataImpl",
+ ParticleDataImpl<Real>::_W_22);
+static const Pb::Register _R_56("ParticleDataImpl<Real>", "clear", ParticleDataImpl<Real>::_W_23);
+static const Pb::Register _R_57("ParticleDataImpl<Real>",
+ "setSource",
+ ParticleDataImpl<Real>::_W_24);
+static const Pb::Register _R_58("ParticleDataImpl<Real>",
+ "copyFrom",
+ ParticleDataImpl<Real>::_W_25);
+static const Pb::Register _R_59("ParticleDataImpl<Real>",
+ "setConst",
+ ParticleDataImpl<Real>::_W_26);
+static const Pb::Register _R_60("ParticleDataImpl<Real>",
+ "setConstRange",
+ ParticleDataImpl<Real>::_W_27);
+static const Pb::Register _R_61("ParticleDataImpl<Real>", "add", ParticleDataImpl<Real>::_W_28);
+static const Pb::Register _R_62("ParticleDataImpl<Real>", "sub", ParticleDataImpl<Real>::_W_29);
+static const Pb::Register _R_63("ParticleDataImpl<Real>",
+ "addConst",
+ ParticleDataImpl<Real>::_W_30);
+static const Pb::Register _R_64("ParticleDataImpl<Real>",
+ "addScaled",
+ ParticleDataImpl<Real>::_W_31);
+static const Pb::Register _R_65("ParticleDataImpl<Real>", "mult", ParticleDataImpl<Real>::_W_32);
+static const Pb::Register _R_66("ParticleDataImpl<Real>",
+ "multConst",
+ ParticleDataImpl<Real>::_W_33);
+static const Pb::Register _R_67("ParticleDataImpl<Real>",
+ "safeDiv",
+ ParticleDataImpl<Real>::_W_34);
+static const Pb::Register _R_68("ParticleDataImpl<Real>", "clamp", ParticleDataImpl<Real>::_W_35);
+static const Pb::Register _R_69("ParticleDataImpl<Real>",
+ "clampMin",
+ ParticleDataImpl<Real>::_W_36);
+static const Pb::Register _R_70("ParticleDataImpl<Real>",
+ "clampMax",
+ ParticleDataImpl<Real>::_W_37);
+static const Pb::Register _R_71("ParticleDataImpl<Real>",
+ "getMaxAbs",
+ ParticleDataImpl<Real>::_W_38);
+static const Pb::Register _R_72("ParticleDataImpl<Real>", "getMax", ParticleDataImpl<Real>::_W_39);
+static const Pb::Register _R_73("ParticleDataImpl<Real>", "getMin", ParticleDataImpl<Real>::_W_40);
+static const Pb::Register _R_74("ParticleDataImpl<Real>", "sum", ParticleDataImpl<Real>::_W_41);
+static const Pb::Register _R_75("ParticleDataImpl<Real>",
+ "sumSquare",
+ ParticleDataImpl<Real>::_W_42);
+static const Pb::Register _R_76("ParticleDataImpl<Real>",
+ "sumMagnitude",
+ ParticleDataImpl<Real>::_W_43);
+static const Pb::Register _R_77("ParticleDataImpl<Real>",
+ "setConstIntFlag",
+ ParticleDataImpl<Real>::_W_44);
+static const Pb::Register _R_78("ParticleDataImpl<Real>",
+ "printPdata",
+ ParticleDataImpl<Real>::_W_45);
+static const Pb::Register _R_79("ParticleDataImpl<Real>", "save", ParticleDataImpl<Real>::_W_46);
+static const Pb::Register _R_80("ParticleDataImpl<Real>", "load", ParticleDataImpl<Real>::_W_47);
+static const Pb::Register _R_81("ParticleDataImpl<Real>",
+ "getDataPointer",
+ ParticleDataImpl<Real>::_W_48);
+static const Pb::Register _R_82("ParticleDataImpl<Vec3>",
+ "ParticleDataImpl<Vec3>",
+ "ParticleDataBase");
+template<> const char *Namify<ParticleDataImpl<Vec3>>::S = "ParticleDataImpl<Vec3>";
+static const Pb::Register _R_83("ParticleDataImpl<Vec3>",
+ "ParticleDataImpl",
+ ParticleDataImpl<Vec3>::_W_22);
+static const Pb::Register _R_84("ParticleDataImpl<Vec3>", "clear", ParticleDataImpl<Vec3>::_W_23);
+static const Pb::Register _R_85("ParticleDataImpl<Vec3>",
+ "setSource",
+ ParticleDataImpl<Vec3>::_W_24);
+static const Pb::Register _R_86("ParticleDataImpl<Vec3>",
+ "copyFrom",
+ ParticleDataImpl<Vec3>::_W_25);
+static const Pb::Register _R_87("ParticleDataImpl<Vec3>",
+ "setConst",
+ ParticleDataImpl<Vec3>::_W_26);
+static const Pb::Register _R_88("ParticleDataImpl<Vec3>",
+ "setConstRange",
+ ParticleDataImpl<Vec3>::_W_27);
+static const Pb::Register _R_89("ParticleDataImpl<Vec3>", "add", ParticleDataImpl<Vec3>::_W_28);
+static const Pb::Register _R_90("ParticleDataImpl<Vec3>", "sub", ParticleDataImpl<Vec3>::_W_29);
+static const Pb::Register _R_91("ParticleDataImpl<Vec3>",
+ "addConst",
+ ParticleDataImpl<Vec3>::_W_30);
+static const Pb::Register _R_92("ParticleDataImpl<Vec3>",
+ "addScaled",
+ ParticleDataImpl<Vec3>::_W_31);
+static const Pb::Register _R_93("ParticleDataImpl<Vec3>", "mult", ParticleDataImpl<Vec3>::_W_32);
+static const Pb::Register _R_94("ParticleDataImpl<Vec3>",
+ "multConst",
+ ParticleDataImpl<Vec3>::_W_33);
+static const Pb::Register _R_95("ParticleDataImpl<Vec3>",
+ "safeDiv",
+ ParticleDataImpl<Vec3>::_W_34);
+static const Pb::Register _R_96("ParticleDataImpl<Vec3>", "clamp", ParticleDataImpl<Vec3>::_W_35);
+static const Pb::Register _R_97("ParticleDataImpl<Vec3>",
+ "clampMin",
+ ParticleDataImpl<Vec3>::_W_36);
+static const Pb::Register _R_98("ParticleDataImpl<Vec3>",
+ "clampMax",
+ ParticleDataImpl<Vec3>::_W_37);
+static const Pb::Register _R_99("ParticleDataImpl<Vec3>",
+ "getMaxAbs",
+ ParticleDataImpl<Vec3>::_W_38);
+static const Pb::Register _R_100("ParticleDataImpl<Vec3>",
+ "getMax",
+ ParticleDataImpl<Vec3>::_W_39);
+static const Pb::Register _R_101("ParticleDataImpl<Vec3>",
+ "getMin",
+ ParticleDataImpl<Vec3>::_W_40);
+static const Pb::Register _R_102("ParticleDataImpl<Vec3>", "sum", ParticleDataImpl<Vec3>::_W_41);
+static const Pb::Register _R_103("ParticleDataImpl<Vec3>",
+ "sumSquare",
+ ParticleDataImpl<Vec3>::_W_42);
+static const Pb::Register _R_104("ParticleDataImpl<Vec3>",
+ "sumMagnitude",
+ ParticleDataImpl<Vec3>::_W_43);
+static const Pb::Register _R_105("ParticleDataImpl<Vec3>",
+ "setConstIntFlag",
+ ParticleDataImpl<Vec3>::_W_44);
+static const Pb::Register _R_106("ParticleDataImpl<Vec3>",
+ "printPdata",
+ ParticleDataImpl<Vec3>::_W_45);
+static const Pb::Register _R_107("ParticleDataImpl<Vec3>", "save", ParticleDataImpl<Vec3>::_W_46);
+static const Pb::Register _R_108("ParticleDataImpl<Vec3>", "load", ParticleDataImpl<Vec3>::_W_47);
+static const Pb::Register _R_109("ParticleDataImpl<Vec3>",
+ "getDataPointer",
+ ParticleDataImpl<Vec3>::_W_48);
+#endif
+#ifdef _C_ParticleIndexSystem
+static const Pb::Register _R_110("ParticleIndexSystem",
+ "ParticleIndexSystem",
+ "ParticleSystem<ParticleIndexData>");
+template<> const char *Namify<ParticleIndexSystem>::S = "ParticleIndexSystem";
+static const Pb::Register _R_111("ParticleIndexSystem",
+ "ParticleIndexSystem",
+ ParticleIndexSystem::_W_19);
+#endif
+#ifdef _C_ParticleSystem
+static const Pb::Register _R_112("ParticleSystem<BasicParticleData>",
+ "ParticleSystem<BasicParticleData>",
+ "ParticleBase");
+template<>
+const char *Namify<ParticleSystem<BasicParticleData>>::S = "ParticleSystem<BasicParticleData>";
+static const Pb::Register _R_113("ParticleSystem<BasicParticleData>",
+ "ParticleSystem",
+ ParticleSystem<BasicParticleData>::_W_2);
+static const Pb::Register _R_114("ParticleSystem<BasicParticleData>",
+ "pySize",
+ ParticleSystem<BasicParticleData>::_W_3);
+static const Pb::Register _R_115("ParticleSystem<BasicParticleData>",
+ "setPos",
+ ParticleSystem<BasicParticleData>::_W_4);
+static const Pb::Register _R_116("ParticleSystem<BasicParticleData>",
+ "getPos",
+ ParticleSystem<BasicParticleData>::_W_5);
+static const Pb::Register _R_117("ParticleSystem<BasicParticleData>",
+ "getPosPdata",
+ ParticleSystem<BasicParticleData>::_W_6);
+static const Pb::Register _R_118("ParticleSystem<BasicParticleData>",
+ "setPosPdata",
+ ParticleSystem<BasicParticleData>::_W_7);
+static const Pb::Register _R_119("ParticleSystem<BasicParticleData>",
+ "clear",
+ ParticleSystem<BasicParticleData>::_W_8);
+static const Pb::Register _R_120("ParticleSystem<BasicParticleData>",
+ "advectInGrid",
+ ParticleSystem<BasicParticleData>::_W_9);
+static const Pb::Register _R_121("ParticleSystem<BasicParticleData>",
+ "projectOutside",
+ ParticleSystem<BasicParticleData>::_W_10);
+static const Pb::Register _R_122("ParticleSystem<BasicParticleData>",
+ "projectOutOfBnd",
+ ParticleSystem<BasicParticleData>::_W_11);
+static const Pb::Register _R_123("ParticleSystem<ParticleIndexData>",
+ "ParticleSystem<ParticleIndexData>",
+ "ParticleBase");
+template<>
+const char *Namify<ParticleSystem<ParticleIndexData>>::S = "ParticleSystem<ParticleIndexData>";
+static const Pb::Register _R_124("ParticleSystem<ParticleIndexData>",
+ "ParticleSystem",
+ ParticleSystem<ParticleIndexData>::_W_2);
+static const Pb::Register _R_125("ParticleSystem<ParticleIndexData>",
+ "pySize",
+ ParticleSystem<ParticleIndexData>::_W_3);
+static const Pb::Register _R_126("ParticleSystem<ParticleIndexData>",
+ "setPos",
+ ParticleSystem<ParticleIndexData>::_W_4);
+static const Pb::Register _R_127("ParticleSystem<ParticleIndexData>",
+ "getPos",
+ ParticleSystem<ParticleIndexData>::_W_5);
+static const Pb::Register _R_128("ParticleSystem<ParticleIndexData>",
+ "getPosPdata",
+ ParticleSystem<ParticleIndexData>::_W_6);
+static const Pb::Register _R_129("ParticleSystem<ParticleIndexData>",
+ "setPosPdata",
+ ParticleSystem<ParticleIndexData>::_W_7);
+static const Pb::Register _R_130("ParticleSystem<ParticleIndexData>",
+ "clear",
+ ParticleSystem<ParticleIndexData>::_W_8);
+static const Pb::Register _R_131("ParticleSystem<ParticleIndexData>",
+ "advectInGrid",
+ ParticleSystem<ParticleIndexData>::_W_9);
+static const Pb::Register _R_132("ParticleSystem<ParticleIndexData>",
+ "projectOutside",
+ ParticleSystem<ParticleIndexData>::_W_10);
+static const Pb::Register _R_133("ParticleSystem<ParticleIndexData>",
+ "projectOutOfBnd",
+ ParticleSystem<ParticleIndexData>::_W_11);
+#endif
+static const Pb::Register _R_10("ParticleDataImpl<int>", "PdataInt", "");
+static const Pb::Register _R_11("ParticleDataImpl<Real>", "PdataReal", "");
+static const Pb::Register _R_12("ParticleDataImpl<Vec3>", "PdataVec3", "");
+extern "C" {
+void PbRegister_file_10()
+{
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+ KEEP_UNUSED(_R_101);
+ KEEP_UNUSED(_R_102);
+ KEEP_UNUSED(_R_103);
+ KEEP_UNUSED(_R_104);
+ KEEP_UNUSED(_R_105);
+ KEEP_UNUSED(_R_106);
+ KEEP_UNUSED(_R_107);
+ KEEP_UNUSED(_R_108);
+ KEEP_UNUSED(_R_109);
+ KEEP_UNUSED(_R_110);
+ KEEP_UNUSED(_R_111);
+ KEEP_UNUSED(_R_112);
+ KEEP_UNUSED(_R_113);
+ KEEP_UNUSED(_R_114);
+ KEEP_UNUSED(_R_115);
+ KEEP_UNUSED(_R_116);
+ KEEP_UNUSED(_R_117);
+ KEEP_UNUSED(_R_118);
+ KEEP_UNUSED(_R_119);
+ KEEP_UNUSED(_R_120);
+ KEEP_UNUSED(_R_121);
+ KEEP_UNUSED(_R_122);
+ KEEP_UNUSED(_R_123);
+ KEEP_UNUSED(_R_124);
+ KEEP_UNUSED(_R_125);
+ KEEP_UNUSED(_R_126);
+ KEEP_UNUSED(_R_127);
+ KEEP_UNUSED(_R_128);
+ KEEP_UNUSED(_R_129);
+ KEEP_UNUSED(_R_130);
+ KEEP_UNUSED(_R_131);
+ KEEP_UNUSED(_R_132);
+ KEEP_UNUSED(_R_133);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/plugin/advection.cpp b/extern/mantaflow/preprocessed/plugin/advection.cpp
new file mode 100644
index 00000000000..13f53140348
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/advection.cpp
@@ -0,0 +1,1521 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2015 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for advection
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+#include <limits>
+
+using namespace std;
+
+namespace Manta {
+
+//! Semi-Lagrange interpolation kernel
+
+template<class T> struct SemiLagrange : public KernelBase {
+ SemiLagrange(const FlagGrid &flags,
+ const MACGrid &vel,
+ Grid<T> &dst,
+ const Grid<T> &src,
+ Real dt,
+ bool isLevelset,
+ int orderSpace,
+ int orderTrace)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ vel(vel),
+ dst(dst),
+ src(src),
+ dt(dt),
+ isLevelset(isLevelset),
+ orderSpace(orderSpace),
+ orderTrace(orderTrace)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ Grid<T> &dst,
+ const Grid<T> &src,
+ Real dt,
+ bool isLevelset,
+ int orderSpace,
+ int orderTrace) const
+ {
+ if (orderTrace == 1) {
+ // traceback position
+ Vec3 pos = Vec3(i + 0.5f, j + 0.5f, k + 0.5f) - vel.getCentered(i, j, k) * dt;
+ dst(i, j, k) = src.getInterpolatedHi(pos, orderSpace);
+ }
+ else if (orderTrace == 2) {
+ // backtracing using explicit midpoint
+ Vec3 p0 = Vec3(i + 0.5f, j + 0.5f, k + 0.5f);
+ Vec3 p1 = p0 - vel.getCentered(i, j, k) * dt * 0.5;
+ Vec3 p2 = p0 - vel.getInterpolated(p1) * dt;
+ dst(i, j, k) = src.getInterpolatedHi(p2, orderSpace);
+ }
+ else {
+ assertMsg(false, "Unknown backtracing order " << orderTrace);
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline Grid<T> &getArg2()
+ {
+ return dst;
+ }
+ typedef Grid<T> type2;
+ inline const Grid<T> &getArg3()
+ {
+ return src;
+ }
+ typedef Grid<T> type3;
+ inline Real &getArg4()
+ {
+ return dt;
+ }
+ typedef Real type4;
+ inline bool &getArg5()
+ {
+ return isLevelset;
+ }
+ typedef bool type5;
+ inline int &getArg6()
+ {
+ return orderSpace;
+ }
+ typedef int type6;
+ inline int &getArg7()
+ {
+ return orderTrace;
+ }
+ typedef int type7;
+ void runMessage()
+ {
+ debMsg("Executing kernel SemiLagrange ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, dst, src, dt, isLevelset, orderSpace, orderTrace);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, dst, src, dt, isLevelset, orderSpace, orderTrace);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ Grid<T> &dst;
+ const Grid<T> &src;
+ Real dt;
+ bool isLevelset;
+ int orderSpace;
+ int orderTrace;
+};
+
+//! Semi-Lagrange interpolation kernel for MAC grids
+
+struct SemiLagrangeMAC : public KernelBase {
+ SemiLagrangeMAC(const FlagGrid &flags,
+ const MACGrid &vel,
+ MACGrid &dst,
+ const MACGrid &src,
+ Real dt,
+ int orderSpace,
+ int orderTrace)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ vel(vel),
+ dst(dst),
+ src(src),
+ dt(dt),
+ orderSpace(orderSpace),
+ orderTrace(orderTrace)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ MACGrid &dst,
+ const MACGrid &src,
+ Real dt,
+ int orderSpace,
+ int orderTrace) const
+ {
+ if (orderTrace == 1) {
+ // get currect velocity at MAC position
+ // no need to shift xpos etc. as lookup field is also shifted
+ Vec3 xpos = Vec3(i + 0.5f, j + 0.5f, k + 0.5f) - vel.getAtMACX(i, j, k) * dt;
+ Real vx = src.getInterpolatedComponentHi<0>(xpos, orderSpace);
+ Vec3 ypos = Vec3(i + 0.5f, j + 0.5f, k + 0.5f) - vel.getAtMACY(i, j, k) * dt;
+ Real vy = src.getInterpolatedComponentHi<1>(ypos, orderSpace);
+ Vec3 zpos = Vec3(i + 0.5f, j + 0.5f, k + 0.5f) - vel.getAtMACZ(i, j, k) * dt;
+ Real vz = src.getInterpolatedComponentHi<2>(zpos, orderSpace);
+
+ dst(i, j, k) = Vec3(vx, vy, vz);
+ }
+ else if (orderTrace == 2) {
+ Vec3 p0 = Vec3(i + 0.5, j + 0.5, k + 0.5);
+ Vec3 xp0 = Vec3(i, j + 0.5f, k + 0.5f);
+ Vec3 xp1 = xp0 - src.getAtMACX(i, j, k) * dt * 0.5;
+ Vec3 xp2 = p0 - src.getInterpolated(xp1) * dt;
+ Real vx = src.getInterpolatedComponentHi<0>(xp2, orderSpace);
+ Vec3 yp0 = Vec3(i + 0.5f, j, k + 0.5f);
+ Vec3 yp1 = yp0 - src.getAtMACY(i, j, k) * dt * 0.5;
+ Vec3 yp2 = p0 - src.getInterpolated(yp1) * dt;
+ Real vy = src.getInterpolatedComponentHi<1>(yp2, orderSpace);
+ Vec3 zp0 = Vec3(i + 0.5f, j + 0.5f, k);
+ Vec3 zp1 = zp0 - src.getAtMACZ(i, j, k) * dt * 0.5;
+ Vec3 zp2 = p0 - src.getInterpolated(zp1) * dt;
+ Real vz = src.getInterpolatedComponentHi<2>(zp2, orderSpace);
+
+ dst(i, j, k) = Vec3(vx, vy, vz);
+ }
+ else {
+ assertMsg(false, "Unknown backtracing order " << orderTrace);
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline MACGrid &getArg2()
+ {
+ return dst;
+ }
+ typedef MACGrid type2;
+ inline const MACGrid &getArg3()
+ {
+ return src;
+ }
+ typedef MACGrid type3;
+ inline Real &getArg4()
+ {
+ return dt;
+ }
+ typedef Real type4;
+ inline int &getArg5()
+ {
+ return orderSpace;
+ }
+ typedef int type5;
+ inline int &getArg6()
+ {
+ return orderTrace;
+ }
+ typedef int type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel SemiLagrangeMAC ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, dst, src, dt, orderSpace, orderTrace);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, dst, src, dt, orderSpace, orderTrace);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ MACGrid &dst;
+ const MACGrid &src;
+ Real dt;
+ int orderSpace;
+ int orderTrace;
+};
+
+//! Kernel: Correct based on forward and backward SL steps (for both centered & mac grids)
+
+template<class T> struct MacCormackCorrect : public KernelBase {
+ MacCormackCorrect(const FlagGrid &flags,
+ Grid<T> &dst,
+ const Grid<T> &old,
+ const Grid<T> &fwd,
+ const Grid<T> &bwd,
+ Real strength,
+ bool isLevelSet,
+ bool isMAC = false)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ dst(dst),
+ old(old),
+ fwd(fwd),
+ bwd(bwd),
+ strength(strength),
+ isLevelSet(isLevelSet),
+ isMAC(isMAC)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const FlagGrid &flags,
+ Grid<T> &dst,
+ const Grid<T> &old,
+ const Grid<T> &fwd,
+ const Grid<T> &bwd,
+ Real strength,
+ bool isLevelSet,
+ bool isMAC = false) const
+ {
+ dst[idx] = fwd[idx];
+
+ if (flags.isFluid(idx)) {
+ // only correct inside fluid region; note, strenth of correction can be modified here
+ dst[idx] += strength * 0.5 * (old[idx] - bwd[idx]);
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<T> &getArg1()
+ {
+ return dst;
+ }
+ typedef Grid<T> type1;
+ inline const Grid<T> &getArg2()
+ {
+ return old;
+ }
+ typedef Grid<T> type2;
+ inline const Grid<T> &getArg3()
+ {
+ return fwd;
+ }
+ typedef Grid<T> type3;
+ inline const Grid<T> &getArg4()
+ {
+ return bwd;
+ }
+ typedef Grid<T> type4;
+ inline Real &getArg5()
+ {
+ return strength;
+ }
+ typedef Real type5;
+ inline bool &getArg6()
+ {
+ return isLevelSet;
+ }
+ typedef bool type6;
+ inline bool &getArg7()
+ {
+ return isMAC;
+ }
+ typedef bool type7;
+ void runMessage()
+ {
+ debMsg("Executing kernel MacCormackCorrect ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, flags, dst, old, fwd, bwd, strength, isLevelSet, isMAC);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const FlagGrid &flags;
+ Grid<T> &dst;
+ const Grid<T> &old;
+ const Grid<T> &fwd;
+ const Grid<T> &bwd;
+ Real strength;
+ bool isLevelSet;
+ bool isMAC;
+};
+
+//! Kernel: Correct based on forward and backward SL steps (for both centered & mac grids)
+
+template<class T> struct MacCormackCorrectMAC : public KernelBase {
+ MacCormackCorrectMAC(const FlagGrid &flags,
+ Grid<T> &dst,
+ const Grid<T> &old,
+ const Grid<T> &fwd,
+ const Grid<T> &bwd,
+ Real strength,
+ bool isLevelSet,
+ bool isMAC = false)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ dst(dst),
+ old(old),
+ fwd(fwd),
+ bwd(bwd),
+ strength(strength),
+ isLevelSet(isLevelSet),
+ isMAC(isMAC)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<T> &dst,
+ const Grid<T> &old,
+ const Grid<T> &fwd,
+ const Grid<T> &bwd,
+ Real strength,
+ bool isLevelSet,
+ bool isMAC = false) const
+ {
+ bool skip[3] = {false, false, false};
+
+ if (!flags.isFluid(i, j, k))
+ skip[0] = skip[1] = skip[2] = true;
+ if (isMAC) {
+ if ((i > 0) && (!flags.isFluid(i - 1, j, k)))
+ skip[0] = true;
+ if ((j > 0) && (!flags.isFluid(i, j - 1, k)))
+ skip[1] = true;
+ if ((k > 0) && (!flags.isFluid(i, j, k - 1)))
+ skip[2] = true;
+ }
+
+ for (int c = 0; c < 3; ++c) {
+ if (skip[c]) {
+ dst(i, j, k)[c] = fwd(i, j, k)[c];
+ }
+ else {
+ // perform actual correction with given strength
+ dst(i, j, k)[c] = fwd(i, j, k)[c] + strength * 0.5 * (old(i, j, k)[c] - bwd(i, j, k)[c]);
+ }
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<T> &getArg1()
+ {
+ return dst;
+ }
+ typedef Grid<T> type1;
+ inline const Grid<T> &getArg2()
+ {
+ return old;
+ }
+ typedef Grid<T> type2;
+ inline const Grid<T> &getArg3()
+ {
+ return fwd;
+ }
+ typedef Grid<T> type3;
+ inline const Grid<T> &getArg4()
+ {
+ return bwd;
+ }
+ typedef Grid<T> type4;
+ inline Real &getArg5()
+ {
+ return strength;
+ }
+ typedef Real type5;
+ inline bool &getArg6()
+ {
+ return isLevelSet;
+ }
+ typedef bool type6;
+ inline bool &getArg7()
+ {
+ return isMAC;
+ }
+ typedef bool type7;
+ void runMessage()
+ {
+ debMsg("Executing kernel MacCormackCorrectMAC ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, dst, old, fwd, bwd, strength, isLevelSet, isMAC);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, dst, old, fwd, bwd, strength, isLevelSet, isMAC);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<T> &dst;
+ const Grid<T> &old;
+ const Grid<T> &fwd;
+ const Grid<T> &bwd;
+ Real strength;
+ bool isLevelSet;
+ bool isMAC;
+};
+
+// Helper to collect min/max in a template
+template<class T> inline void getMinMax(T &minv, T &maxv, const T &val)
+{
+ if (val < minv)
+ minv = val;
+ if (val > maxv)
+ maxv = val;
+}
+template<> inline void getMinMax<Vec3>(Vec3 &minv, Vec3 &maxv, const Vec3 &val)
+{
+ getMinMax(minv.x, maxv.x, val.x);
+ getMinMax(minv.y, maxv.y, val.y);
+ getMinMax(minv.z, maxv.z, val.z);
+}
+
+//! detect out of bounds value
+template<class T> inline bool cmpMinMax(T &minv, T &maxv, const T &val)
+{
+ if (val < minv)
+ return true;
+ if (val > maxv)
+ return true;
+ return false;
+}
+template<> inline bool cmpMinMax<Vec3>(Vec3 &minv, Vec3 &maxv, const Vec3 &val)
+{
+ return (cmpMinMax(minv.x, maxv.x, val.x) | cmpMinMax(minv.y, maxv.y, val.y) |
+ cmpMinMax(minv.z, maxv.z, val.z));
+}
+
+#define checkFlag(x, y, z) (flags((x), (y), (z)) & (FlagGrid::TypeFluid | FlagGrid::TypeEmpty))
+
+//! Helper function for clamping non-mac grids (those have specialized per component version below)
+// Note - 2 clamp modes, a sharper one (default, clampMode 1, also uses backward step),
+// and a softer version (clampMode 2) that is recommended in Andy's paper
+template<class T>
+inline T doClampComponent(const Vec3i &gridSize,
+ const FlagGrid &flags,
+ T dst,
+ const Grid<T> &orig,
+ const T fwd,
+ const Vec3 &pos,
+ const Vec3 &vel,
+ const int clampMode)
+{
+ T minv(std::numeric_limits<Real>::max()), maxv(-std::numeric_limits<Real>::max());
+ bool haveFl = false;
+
+ // forward (and optionally) backward
+ Vec3i positions[2];
+ int numPos = 1;
+ positions[0] = toVec3i(pos - vel);
+ if (clampMode == 1) {
+ numPos = 2;
+ positions[1] = toVec3i(pos + vel);
+ }
+
+ for (int l = 0; l < numPos; ++l) {
+ Vec3i &currPos = positions[l];
+
+ // clamp lookup to grid
+ const int i0 = clamp(currPos.x, 0, gridSize.x - 1); // note! gridsize already has -1 from call
+ const int j0 = clamp(currPos.y, 0, gridSize.y - 1);
+ const int k0 = clamp(currPos.z, 0, (orig.is3D() ? (gridSize.z - 1) : 1));
+ const int i1 = i0 + 1, j1 = j0 + 1, k1 = (orig.is3D() ? (k0 + 1) : k0);
+
+ // find min/max around source pos
+ if (checkFlag(i0, j0, k0)) {
+ getMinMax(minv, maxv, orig(i0, j0, k0));
+ haveFl = true;
+ }
+ if (checkFlag(i1, j0, k0)) {
+ getMinMax(minv, maxv, orig(i1, j0, k0));
+ haveFl = true;
+ }
+ if (checkFlag(i0, j1, k0)) {
+ getMinMax(minv, maxv, orig(i0, j1, k0));
+ haveFl = true;
+ }
+ if (checkFlag(i1, j1, k0)) {
+ getMinMax(minv, maxv, orig(i1, j1, k0));
+ haveFl = true;
+ }
+
+ if (orig.is3D()) {
+ if (checkFlag(i0, j0, k1)) {
+ getMinMax(minv, maxv, orig(i0, j0, k1));
+ haveFl = true;
+ }
+ if (checkFlag(i1, j0, k1)) {
+ getMinMax(minv, maxv, orig(i1, j0, k1));
+ haveFl = true;
+ }
+ if (checkFlag(i0, j1, k1)) {
+ getMinMax(minv, maxv, orig(i0, j1, k1));
+ haveFl = true;
+ }
+ if (checkFlag(i1, j1, k1)) {
+ getMinMax(minv, maxv, orig(i1, j1, k1));
+ haveFl = true;
+ }
+ }
+ }
+
+ if (!haveFl)
+ return fwd;
+ if (clampMode == 1) {
+ dst = clamp(dst, minv, maxv); // hard clamp
+ }
+ else {
+ if (cmpMinMax(minv, maxv, dst))
+ dst = fwd; // recommended in paper, "softer"
+ }
+ return dst;
+}
+
+//! Helper function for clamping MAC grids, slight differences in flag checks
+// similar to scalar version, just uses single component c of vec3 values
+// for symmetry, reverts to first order near boundaries for clampMode 2
+template<int c>
+inline Real doClampComponentMAC(const FlagGrid &flags,
+ const Vec3i &gridSize,
+ Real dst,
+ const MACGrid &orig,
+ Real fwd,
+ const Vec3 &pos,
+ const Vec3 &vel,
+ const int clampMode)
+{
+ Real minv = std::numeric_limits<Real>::max(), maxv = -std::numeric_limits<Real>::max();
+ // bool haveFl = false;
+
+ // forward (and optionally) backward
+ Vec3i positions[2];
+ int numPos = 1;
+ positions[0] = toVec3i(pos - vel);
+ if (clampMode == 1) {
+ numPos = 2;
+ positions[1] = toVec3i(pos + vel);
+ }
+
+ Vec3i oPos = toVec3i(pos);
+ Vec3i nbPos = oPos;
+ nbPos[c] -= 1;
+ if (clampMode == 2 &&
+ (!(checkFlag(oPos.x, oPos.y, oPos.z) && checkFlag(nbPos.x, nbPos.y, nbPos.z))))
+ return fwd; // replaces haveFl check
+
+ for (int l = 0; l < numPos; ++l) {
+ Vec3i &currPos = positions[l];
+
+ const int i0 = clamp(currPos.x, 0, gridSize.x - 1); // note! gridsize already has -1 from call
+ const int j0 = clamp(
+ currPos.y, 0, gridSize.y - 1); // but we need a clamp to -2 for the +1 offset below
+ const int k0 = clamp(currPos.z, 0, (orig.is3D() ? (gridSize.z - 1) : 0));
+ const int i1 = i0 + 1, j1 = j0 + 1, k1 = (orig.is3D() ? (k0 + 1) : k0);
+
+ // find min/max around source pos
+ getMinMax(minv, maxv, orig(i0, j0, k0)[c]);
+ getMinMax(minv, maxv, orig(i1, j0, k0)[c]);
+ getMinMax(minv, maxv, orig(i0, j1, k0)[c]);
+ getMinMax(minv, maxv, orig(i1, j1, k0)[c]);
+
+ if (orig.is3D()) {
+ getMinMax(minv, maxv, orig(i0, j0, k1)[c]);
+ getMinMax(minv, maxv, orig(i1, j0, k1)[c]);
+ getMinMax(minv, maxv, orig(i0, j1, k1)[c]);
+ getMinMax(minv, maxv, orig(i1, j1, k1)[c]);
+ }
+ }
+
+ if (clampMode == 1) {
+ dst = clamp(dst, minv, maxv); // hard clamp
+ }
+ else {
+ if (cmpMinMax(minv, maxv, dst))
+ dst = fwd; // recommended in paper, "softer"
+ }
+ return dst;
+}
+
+#undef checkFlag
+
+//! Kernel: Clamp obtained value to min/max in source area, and reset values that point out of grid
+//! or into boundaries
+// (note - MAC grids are handled below)
+
+template<class T> struct MacCormackClamp : public KernelBase {
+ MacCormackClamp(const FlagGrid &flags,
+ const MACGrid &vel,
+ Grid<T> &dst,
+ const Grid<T> &orig,
+ const Grid<T> &fwd,
+ Real dt,
+ const int clampMode)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ vel(vel),
+ dst(dst),
+ orig(orig),
+ fwd(fwd),
+ dt(dt),
+ clampMode(clampMode)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ Grid<T> &dst,
+ const Grid<T> &orig,
+ const Grid<T> &fwd,
+ Real dt,
+ const int clampMode) const
+ {
+ T dval = dst(i, j, k);
+ Vec3i gridUpper = flags.getSize() - 1;
+
+ dval = doClampComponent<T>(gridUpper,
+ flags,
+ dval,
+ orig,
+ fwd(i, j, k),
+ Vec3(i, j, k),
+ vel.getCentered(i, j, k) * dt,
+ clampMode);
+
+ if (1 && clampMode == 1) {
+ // lookup forward/backward , round to closest NB
+ Vec3i posFwd = toVec3i(Vec3(i, j, k) + Vec3(0.5, 0.5, 0.5) - vel.getCentered(i, j, k) * dt);
+ Vec3i posBwd = toVec3i(Vec3(i, j, k) + Vec3(0.5, 0.5, 0.5) + vel.getCentered(i, j, k) * dt);
+
+ // test if lookups point out of grid or into obstacle (note doClampComponent already checks
+ // sides, below is needed for valid flags access)
+ if (posFwd.x < 0 || posFwd.y < 0 || posFwd.z < 0 || posBwd.x < 0 || posBwd.y < 0 ||
+ posBwd.z < 0 || posFwd.x > gridUpper.x || posFwd.y > gridUpper.y ||
+ ((posFwd.z > gridUpper.z) && flags.is3D()) || posBwd.x > gridUpper.x ||
+ posBwd.y > gridUpper.y || ((posBwd.z > gridUpper.z) && flags.is3D()) ||
+ flags.isObstacle(posFwd) || flags.isObstacle(posBwd)) {
+ dval = fwd(i, j, k);
+ }
+ }
+ // clampMode 2 handles flags in doClampComponent call
+
+ dst(i, j, k) = dval;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline Grid<T> &getArg2()
+ {
+ return dst;
+ }
+ typedef Grid<T> type2;
+ inline const Grid<T> &getArg3()
+ {
+ return orig;
+ }
+ typedef Grid<T> type3;
+ inline const Grid<T> &getArg4()
+ {
+ return fwd;
+ }
+ typedef Grid<T> type4;
+ inline Real &getArg5()
+ {
+ return dt;
+ }
+ typedef Real type5;
+ inline const int &getArg6()
+ {
+ return clampMode;
+ }
+ typedef int type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel MacCormackClamp ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, dst, orig, fwd, dt, clampMode);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, dst, orig, fwd, dt, clampMode);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ Grid<T> &dst;
+ const Grid<T> &orig;
+ const Grid<T> &fwd;
+ Real dt;
+ const int clampMode;
+};
+
+//! Kernel: same as MacCormackClamp above, but specialized version for MAC grids
+
+struct MacCormackClampMAC : public KernelBase {
+ MacCormackClampMAC(const FlagGrid &flags,
+ const MACGrid &vel,
+ MACGrid &dst,
+ const MACGrid &orig,
+ const MACGrid &fwd,
+ Real dt,
+ const int clampMode)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ vel(vel),
+ dst(dst),
+ orig(orig),
+ fwd(fwd),
+ dt(dt),
+ clampMode(clampMode)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ MACGrid &dst,
+ const MACGrid &orig,
+ const MACGrid &fwd,
+ Real dt,
+ const int clampMode) const
+ {
+ Vec3 pos(i, j, k);
+ Vec3 dval = dst(i, j, k);
+ Vec3 dfwd = fwd(i, j, k);
+ Vec3i gridUpper = flags.getSize() - 1;
+
+ dval.x = doClampComponentMAC<0>(
+ flags, gridUpper, dval.x, orig, dfwd.x, pos, vel.getAtMACX(i, j, k) * dt, clampMode);
+ dval.y = doClampComponentMAC<1>(
+ flags, gridUpper, dval.y, orig, dfwd.y, pos, vel.getAtMACY(i, j, k) * dt, clampMode);
+ if (flags.is3D())
+ dval.z = doClampComponentMAC<2>(
+ flags, gridUpper, dval.z, orig, dfwd.z, pos, vel.getAtMACZ(i, j, k) * dt, clampMode);
+
+ // note - the MAC version currently does not check whether source points were inside an
+ // obstacle! (unlike centered version) this would need to be done for each face separately to
+ // stay symmetric...
+
+ dst(i, j, k) = dval;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline MACGrid &getArg2()
+ {
+ return dst;
+ }
+ typedef MACGrid type2;
+ inline const MACGrid &getArg3()
+ {
+ return orig;
+ }
+ typedef MACGrid type3;
+ inline const MACGrid &getArg4()
+ {
+ return fwd;
+ }
+ typedef MACGrid type4;
+ inline Real &getArg5()
+ {
+ return dt;
+ }
+ typedef Real type5;
+ inline const int &getArg6()
+ {
+ return clampMode;
+ }
+ typedef int type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel MacCormackClampMAC ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, dst, orig, fwd, dt, clampMode);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, dst, orig, fwd, dt, clampMode);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ MACGrid &dst;
+ const MACGrid &orig;
+ const MACGrid &fwd;
+ Real dt;
+ const int clampMode;
+};
+
+//! template function for performing SL advection
+//! (Note boundary width only needed for specialization for MAC grids below)
+template<class GridType>
+void fnAdvectSemiLagrange(FluidSolver *parent,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ GridType &orig,
+ int order,
+ Real strength,
+ int orderSpace,
+ int clampMode,
+ int orderTrace)
+{
+ typedef typename GridType::BASETYPE T;
+
+ Real dt = parent->getDt();
+ bool levelset = orig.getType() & GridBase::TypeLevelset;
+
+ // forward step
+ GridType fwd(parent);
+ SemiLagrange<T>(flags, vel, fwd, orig, dt, levelset, orderSpace, orderTrace);
+
+ if (order == 1) {
+ orig.swap(fwd);
+ }
+ else if (order == 2) { // MacCormack
+ GridType bwd(parent);
+ GridType newGrid(parent);
+
+ // bwd <- backwards step
+ SemiLagrange<T>(flags, vel, bwd, fwd, -dt, levelset, orderSpace, orderTrace);
+
+ // newGrid <- compute correction
+ MacCormackCorrect<T>(flags, newGrid, orig, fwd, bwd, strength, levelset);
+
+ // clamp values
+ MacCormackClamp<T>(flags, vel, newGrid, orig, fwd, dt, clampMode);
+
+ orig.swap(newGrid);
+ }
+}
+
+// outflow functions
+
+//! calculate local propagation velocity for cell (i,j,k)
+Vec3 getBulkVel(const FlagGrid &flags, const MACGrid &vel, int i, int j, int k)
+{
+ Vec3 avg = Vec3(0.);
+ int count = 0;
+ int size = 1; // stencil size
+ int nmax = (flags.is3D() ? size : 0);
+ // average the neighboring fluid / outflow cell's velocity
+ for (int n = -nmax; n <= nmax; n++) {
+ for (int m = -size; m <= size; m++) {
+ for (int l = -size; l <= size; l++) {
+ if (flags.isInBounds(Vec3i(i + l, j + m, k + n)) &&
+ (flags.isFluid(i + l, j + m, k + n) || flags.isOutflow(i + l, j + m, k + n))) {
+ avg += vel(i + l, j + m, k + n);
+ count++;
+ }
+ }
+ }
+ }
+ return count > 0 ? avg / count : avg;
+}
+
+//! extrapolate normal velocity components into outflow cell
+struct extrapolateVelConvectiveBC : public KernelBase {
+ extrapolateVelConvectiveBC(const FlagGrid &flags,
+ const MACGrid &vel,
+ MACGrid &velDst,
+ const MACGrid &velPrev,
+ Real timeStep)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ vel(vel),
+ velDst(velDst),
+ velPrev(velPrev),
+ timeStep(timeStep)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ MACGrid &velDst,
+ const MACGrid &velPrev,
+ Real timeStep) const
+ {
+ if (flags.isOutflow(i, j, k)) {
+ Vec3 bulkVel = getBulkVel(flags, vel, i, j, k);
+ int dim = flags.is3D() ? 3 : 2;
+ const Vec3i cur = Vec3i(i, j, k);
+ Vec3i low, up, flLow, flUp;
+ int cnt = 0;
+ // iterate over each velocity component x, y, z
+ for (int c = 0; c < dim; c++) {
+ low = up = flLow = flUp = cur;
+ Real factor = timeStep *
+ max((Real)1.0, bulkVel[c]); // prevent the extrapolated velocity from
+ // exploding when bulk velocity below 1
+ low[c] = flLow[c] = cur[c] - 1;
+ up[c] = flUp[c] = cur[c] + 1;
+ // iterate over bWidth to allow for extrapolation into more distant outflow cells;
+ // hard-coded extrapolation distance of two cells
+ for (int d = 0; d < 2; d++) {
+ bool extrapolateFromLower = flags.isInBounds(flLow) && flags.isFluid(flLow);
+ bool extrapolateFromUpper = flags.isInBounds(flUp) && flags.isFluid(flUp);
+ if (extrapolateFromLower || extrapolateFromUpper) {
+ if (extrapolateFromLower) {
+ velDst(i, j, k) += ((vel(i, j, k) - velPrev(i, j, k)) / factor) + vel(low);
+ cnt++;
+ }
+ if (extrapolateFromUpper) {
+ // check for cells equally far away from two fluid cells -> average value between
+ // both sides
+ velDst(i, j, k) += ((vel(i, j, k) - velPrev(i, j, k)) / factor) + vel(up);
+ cnt++;
+ }
+ break;
+ }
+ flLow[c]--;
+ flUp[c]++;
+ }
+ }
+ if (cnt > 0)
+ velDst(i, j, k) /= cnt;
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline MACGrid &getArg2()
+ {
+ return velDst;
+ }
+ typedef MACGrid type2;
+ inline const MACGrid &getArg3()
+ {
+ return velPrev;
+ }
+ typedef MACGrid type3;
+ inline Real &getArg4()
+ {
+ return timeStep;
+ }
+ typedef Real type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel extrapolateVelConvectiveBC ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, vel, velDst, velPrev, timeStep);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, vel, velDst, velPrev, timeStep);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ MACGrid &velDst;
+ const MACGrid &velPrev;
+ Real timeStep;
+};
+
+//! copy extrapolated velocity components
+struct copyChangedVels : public KernelBase {
+ copyChangedVels(const FlagGrid &flags, const MACGrid &velDst, MACGrid &vel)
+ : KernelBase(&flags, 0), flags(flags), velDst(velDst), vel(vel)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, const FlagGrid &flags, const MACGrid &velDst, MACGrid &vel) const
+ {
+ if (flags.isOutflow(i, j, k))
+ vel(i, j, k) = velDst(i, j, k);
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return velDst;
+ }
+ typedef MACGrid type1;
+ inline MACGrid &getArg2()
+ {
+ return vel;
+ }
+ typedef MACGrid type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel copyChangedVels ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, velDst, vel);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, velDst, vel);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ const MACGrid &velDst;
+ MACGrid &vel;
+};
+
+//! extrapolate normal velocity components into open boundary cells (marked as outflow cells)
+void applyOutflowBC(const FlagGrid &flags, MACGrid &vel, const MACGrid &velPrev, double timeStep)
+{
+ MACGrid velDst(vel.getParent()); // do not overwrite vel while it is read
+ extrapolateVelConvectiveBC(flags, vel, velDst, velPrev, max(1.0, timeStep * 4));
+ copyChangedVels(flags, velDst, vel);
+}
+
+// advection helpers
+
+//! prevent parts of the surface getting "stuck" in obstacle regions
+struct knResetPhiInObs : public KernelBase {
+ knResetPhiInObs(const FlagGrid &flags, Grid<Real> &sdf)
+ : KernelBase(&flags, 0), flags(flags), sdf(sdf)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const FlagGrid &flags, Grid<Real> &sdf) const
+ {
+ if (flags.isObstacle(i, j, k) && (sdf(i, j, k) < 0.)) {
+ sdf(i, j, k) = 0.1;
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return sdf;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knResetPhiInObs ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, sdf);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, sdf);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &sdf;
+};
+void resetPhiInObs(const FlagGrid &flags, Grid<Real> &sdf)
+{
+ knResetPhiInObs(flags, sdf);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "resetPhiInObs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &sdf = *_args.getPtr<Grid<Real>>("sdf", 1, &_lock);
+ _retval = getPyNone();
+ resetPhiInObs(flags, sdf);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "resetPhiInObs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("resetPhiInObs", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_resetPhiInObs("", "resetPhiInObs", _W_0);
+extern "C" {
+void PbRegister_resetPhiInObs()
+{
+ KEEP_UNUSED(_RP_resetPhiInObs);
+}
+}
+
+// advection main calls
+
+//! template function for performing SL advection: specialized version for MAC grids
+template<>
+void fnAdvectSemiLagrange<MACGrid>(FluidSolver *parent,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ MACGrid &orig,
+ int order,
+ Real strength,
+ int orderSpace,
+ int clampMode,
+ int orderTrace)
+{
+ Real dt = parent->getDt();
+
+ // forward step
+ MACGrid fwd(parent);
+ SemiLagrangeMAC(flags, vel, fwd, orig, dt, orderSpace, orderTrace);
+
+ if (orderSpace != 1) {
+ debMsg("Warning higher order for MAC grids not yet implemented...", 1);
+ }
+
+ if (order == 1) {
+ applyOutflowBC(flags, fwd, orig, dt);
+ orig.swap(fwd);
+ }
+ else if (order == 2) { // MacCormack
+ MACGrid bwd(parent);
+ MACGrid newGrid(parent);
+
+ // bwd <- backwards step
+ SemiLagrangeMAC(flags, vel, bwd, fwd, -dt, orderSpace, orderTrace);
+
+ // newGrid <- compute correction
+ MacCormackCorrectMAC<Vec3>(flags, newGrid, orig, fwd, bwd, strength, false, true);
+
+ // clamp values
+ MacCormackClampMAC(flags, vel, newGrid, orig, fwd, dt, clampMode);
+
+ applyOutflowBC(flags, newGrid, orig, dt);
+ orig.swap(newGrid);
+ }
+}
+
+//! Perform semi-lagrangian advection of target Real- or Vec3 grid
+//! Open boundary handling needs information about width of border
+//! Clamping modes: 1 regular clamp leading to more overshoot and sharper results, 2 revert to 1st
+//! order slightly smoother less overshoot (enable when 1 gives artifacts)
+
+void advectSemiLagrange(const FlagGrid *flags,
+ const MACGrid *vel,
+ GridBase *grid,
+ int order = 1,
+ Real strength = 1.0,
+ int orderSpace = 1,
+ bool openBounds = false,
+ int boundaryWidth = -1,
+ int clampMode = 2,
+ int orderTrace = 1)
+{
+ assertMsg(order == 1 || order == 2,
+ "AdvectSemiLagrange: Only order 1 (regular SL) and 2 (MacCormack) supported");
+ if ((boundaryWidth != -1) || (openBounds)) {
+ debMsg(
+ "Warning: boundaryWidth and openBounds parameters in AdvectSemiLagrange plugin are "
+ "deprecated (and have no more effect), please remove.",
+ 0);
+ }
+
+ // determine type of grid
+ if (grid->getType() & GridBase::TypeReal) {
+ fnAdvectSemiLagrange<Grid<Real>>(flags->getParent(),
+ *flags,
+ *vel,
+ *((Grid<Real> *)grid),
+ order,
+ strength,
+ orderSpace,
+ clampMode,
+ orderTrace);
+ }
+ else if (grid->getType() & GridBase::TypeMAC) {
+ fnAdvectSemiLagrange<MACGrid>(flags->getParent(),
+ *flags,
+ *vel,
+ *((MACGrid *)grid),
+ order,
+ strength,
+ orderSpace,
+ clampMode,
+ orderTrace);
+ }
+ else if (grid->getType() & GridBase::TypeVec3) {
+ fnAdvectSemiLagrange<Grid<Vec3>>(flags->getParent(),
+ *flags,
+ *vel,
+ *((Grid<Vec3> *)grid),
+ order,
+ strength,
+ orderSpace,
+ clampMode,
+ orderTrace);
+ }
+ else
+ errMsg("AdvectSemiLagrange: Grid Type is not supported (only Real, Vec3, MAC, Levelset)");
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "advectSemiLagrange", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid *flags = _args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const MACGrid *vel = _args.getPtr<MACGrid>("vel", 1, &_lock);
+ GridBase *grid = _args.getPtr<GridBase>("grid", 2, &_lock);
+ int order = _args.getOpt<int>("order", 3, 1, &_lock);
+ Real strength = _args.getOpt<Real>("strength", 4, 1.0, &_lock);
+ int orderSpace = _args.getOpt<int>("orderSpace", 5, 1, &_lock);
+ bool openBounds = _args.getOpt<bool>("openBounds", 6, false, &_lock);
+ int boundaryWidth = _args.getOpt<int>("boundaryWidth", 7, -1, &_lock);
+ int clampMode = _args.getOpt<int>("clampMode", 8, 2, &_lock);
+ int orderTrace = _args.getOpt<int>("orderTrace", 9, 1, &_lock);
+ _retval = getPyNone();
+ advectSemiLagrange(flags,
+ vel,
+ grid,
+ order,
+ strength,
+ orderSpace,
+ openBounds,
+ boundaryWidth,
+ clampMode,
+ orderTrace);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "advectSemiLagrange", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("advectSemiLagrange", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_advectSemiLagrange("", "advectSemiLagrange", _W_1);
+extern "C" {
+void PbRegister_advectSemiLagrange()
+{
+ KEEP_UNUSED(_RP_advectSemiLagrange);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/apic.cpp b/extern/mantaflow/preprocessed/plugin/apic.cpp
new file mode 100644
index 00000000000..6ff893014c9
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/apic.cpp
@@ -0,0 +1,496 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+// ----------------------------------------------------------------------------
+//
+// MantaFlow fluid solver framework
+// Copyright 2016-2017 Kiwon Um, Nils Thuerey
+//
+// This program is free software, distributed under the terms of the
+// Apache License, Version 2.0
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Affine Particle-In-Cell
+//
+// ----------------------------------------------------------------------------
+
+#include "particle.h"
+#include "grid.h"
+
+namespace Manta {
+
+struct knApicMapLinearVec3ToMACGrid : public KernelBase {
+ knApicMapLinearVec3ToMACGrid(const BasicParticleSystem &p,
+ MACGrid &mg,
+ MACGrid &vg,
+ const ParticleDataImpl<Vec3> &vp,
+ const ParticleDataImpl<Vec3> &cpx,
+ const ParticleDataImpl<Vec3> &cpy,
+ const ParticleDataImpl<Vec3> &cpz,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(p.size()),
+ p(p),
+ mg(mg),
+ vg(vg),
+ vp(vp),
+ cpx(cpx),
+ cpy(cpy),
+ cpz(cpz),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ MACGrid &mg,
+ MACGrid &vg,
+ const ParticleDataImpl<Vec3> &vp,
+ const ParticleDataImpl<Vec3> &cpx,
+ const ParticleDataImpl<Vec3> &cpy,
+ const ParticleDataImpl<Vec3> &cpz,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+ const IndexInt dX[2] = {0, vg.getStrideX()};
+ const IndexInt dY[2] = {0, vg.getStrideY()};
+ const IndexInt dZ[2] = {0, vg.getStrideZ()};
+
+ const Vec3 &pos = p[idx].pos, &vel = vp[idx];
+ const IndexInt fi = static_cast<IndexInt>(pos.x), fj = static_cast<IndexInt>(pos.y),
+ fk = static_cast<IndexInt>(pos.z);
+ const IndexInt ci = static_cast<IndexInt>(pos.x - 0.5),
+ cj = static_cast<IndexInt>(pos.y - 0.5),
+ ck = static_cast<IndexInt>(pos.z - 0.5);
+ const Real wfi = clamp(pos.x - fi, Real(0), Real(1)),
+ wfj = clamp(pos.y - fj, Real(0), Real(1)),
+ wfk = clamp(pos.z - fk, Real(0), Real(1));
+ const Real wci = clamp(Real(pos.x - ci - 0.5), Real(0), Real(1)),
+ wcj = clamp(Real(pos.y - cj - 0.5), Real(0), Real(1)),
+ wck = clamp(Real(pos.z - ck - 0.5), Real(0), Real(1));
+ // TODO: check index for safety
+ { // u-face
+ const IndexInt gidx = fi * dX[1] + cj * dY[1] + ck * dZ[1];
+ const Vec3 gpos(fi, cj + 0.5, ck + 0.5);
+ const Real wi[2] = {Real(1) - wfi, wfi};
+ const Real wj[2] = {Real(1) - wcj, wcj};
+ const Real wk[2] = {Real(1) - wck, wck};
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ for (int k = 0; k < 2; ++k) {
+ const Real w = wi[i] * wj[j] * wk[k];
+ mg[gidx + dX[i] + dY[j] + dZ[k]].x += w;
+ vg[gidx + dX[i] + dY[j] + dZ[k]].x += w * vel.x;
+ vg[gidx + dX[i] + dY[j] + dZ[k]].x += w * dot(cpx[idx], gpos + Vec3(i, j, k) - pos);
+ }
+ }
+ { // v-face
+ const IndexInt gidx = ci * dX[1] + fj * dY[1] + ck * dZ[1];
+ const Vec3 gpos(ci + 0.5, fj, ck + 0.5);
+ const Real wi[2] = {Real(1) - wci, wci};
+ const Real wj[2] = {Real(1) - wfj, wfj};
+ const Real wk[2] = {Real(1) - wck, wck};
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ for (int k = 0; k < 2; ++k) {
+ const Real w = wi[i] * wj[j] * wk[k];
+ mg[gidx + dX[i] + dY[j] + dZ[k]].y += w;
+ vg[gidx + dX[i] + dY[j] + dZ[k]].y += w * vel.y;
+ vg[gidx + dX[i] + dY[j] + dZ[k]].y += w * dot(cpy[idx], gpos + Vec3(i, j, k) - pos);
+ }
+ }
+ if (!vg.is3D())
+ return;
+ { // w-face
+ const IndexInt gidx = ci * dX[1] + cj * dY[1] + fk * dZ[1];
+ const Vec3 gpos(ci + 0.5, cj + 0.5, fk);
+ const Real wi[2] = {Real(1) - wci, wci};
+ const Real wj[2] = {Real(1) - wcj, wcj};
+ const Real wk[2] = {Real(1) - wfk, wfk};
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ for (int k = 0; k < 2; ++k) {
+ const Real w = wi[i] * wj[j] * wk[k];
+ mg[gidx + dX[i] + dY[j] + dZ[k]].z += w;
+ vg[gidx + dX[i] + dY[j] + dZ[k]].z += w * vel.z;
+ vg[gidx + dX[i] + dY[j] + dZ[k]].z += w * dot(cpz[idx], gpos + Vec3(i, j, k) - pos);
+ }
+ }
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline MACGrid &getArg1()
+ {
+ return mg;
+ }
+ typedef MACGrid type1;
+ inline MACGrid &getArg2()
+ {
+ return vg;
+ }
+ typedef MACGrid type2;
+ inline const ParticleDataImpl<Vec3> &getArg3()
+ {
+ return vp;
+ }
+ typedef ParticleDataImpl<Vec3> type3;
+ inline const ParticleDataImpl<Vec3> &getArg4()
+ {
+ return cpx;
+ }
+ typedef ParticleDataImpl<Vec3> type4;
+ inline const ParticleDataImpl<Vec3> &getArg5()
+ {
+ return cpy;
+ }
+ typedef ParticleDataImpl<Vec3> type5;
+ inline const ParticleDataImpl<Vec3> &getArg6()
+ {
+ return cpz;
+ }
+ typedef ParticleDataImpl<Vec3> type6;
+ inline const ParticleDataImpl<int> *getArg7()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type7;
+ inline const int &getArg8()
+ {
+ return exclude;
+ }
+ typedef int type8;
+ void runMessage()
+ {
+ debMsg("Executing kernel knApicMapLinearVec3ToMACGrid ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void run()
+ {
+ const IndexInt _sz = size;
+ for (IndexInt i = 0; i < _sz; i++)
+ op(i, p, mg, vg, vp, cpx, cpy, cpz, ptype, exclude);
+ }
+ const BasicParticleSystem &p;
+ MACGrid &mg;
+ MACGrid &vg;
+ const ParticleDataImpl<Vec3> &vp;
+ const ParticleDataImpl<Vec3> &cpx;
+ const ParticleDataImpl<Vec3> &cpy;
+ const ParticleDataImpl<Vec3> &cpz;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+void apicMapPartsToMAC(const FlagGrid &flags,
+ MACGrid &vel,
+ const BasicParticleSystem &parts,
+ const ParticleDataImpl<Vec3> &partVel,
+ const ParticleDataImpl<Vec3> &cpx,
+ const ParticleDataImpl<Vec3> &cpy,
+ const ParticleDataImpl<Vec3> &cpz,
+ MACGrid *mass = NULL,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // affine map
+ // let's assume that the particle mass is constant, 1.0
+ const bool freeMass = !mass;
+ if (!mass)
+ mass = new MACGrid(flags.getParent());
+ else
+ mass->clear();
+
+ vel.clear();
+ knApicMapLinearVec3ToMACGrid(parts, *mass, vel, partVel, cpx, cpy, cpz, ptype, exclude);
+ mass->stomp(VECTOR_EPSILON);
+ vel.safeDivide(*mass);
+
+ if (freeMass)
+ delete mass;
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "apicMapPartsToMAC", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ const ParticleDataImpl<Vec3> &partVel = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "partVel", 3, &_lock);
+ const ParticleDataImpl<Vec3> &cpx = *_args.getPtr<ParticleDataImpl<Vec3>>("cpx", 4, &_lock);
+ const ParticleDataImpl<Vec3> &cpy = *_args.getPtr<ParticleDataImpl<Vec3>>("cpy", 5, &_lock);
+ const ParticleDataImpl<Vec3> &cpz = *_args.getPtr<ParticleDataImpl<Vec3>>("cpz", 6, &_lock);
+ MACGrid *mass = _args.getPtrOpt<MACGrid>("mass", 7, NULL, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 8, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 9, 0, &_lock);
+ _retval = getPyNone();
+ apicMapPartsToMAC(flags, vel, parts, partVel, cpx, cpy, cpz, mass, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "apicMapPartsToMAC", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("apicMapPartsToMAC", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_apicMapPartsToMAC("", "apicMapPartsToMAC", _W_0);
+extern "C" {
+void PbRegister_apicMapPartsToMAC()
+{
+ KEEP_UNUSED(_RP_apicMapPartsToMAC);
+}
+}
+
+struct knApicMapLinearMACGridToVec3 : public KernelBase {
+ knApicMapLinearMACGridToVec3(ParticleDataImpl<Vec3> &vp,
+ ParticleDataImpl<Vec3> &cpx,
+ ParticleDataImpl<Vec3> &cpy,
+ ParticleDataImpl<Vec3> &cpz,
+ const BasicParticleSystem &p,
+ const MACGrid &vg,
+ const FlagGrid &flags,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(vp.size()),
+ vp(vp),
+ cpx(cpx),
+ cpy(cpy),
+ cpz(cpz),
+ p(p),
+ vg(vg),
+ flags(flags),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ ParticleDataImpl<Vec3> &vp,
+ ParticleDataImpl<Vec3> &cpx,
+ ParticleDataImpl<Vec3> &cpy,
+ ParticleDataImpl<Vec3> &cpz,
+ const BasicParticleSystem &p,
+ const MACGrid &vg,
+ const FlagGrid &flags,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+
+ vp[idx] = cpx[idx] = cpy[idx] = cpz[idx] = Vec3(Real(0));
+ const IndexInt dX[2] = {0, vg.getStrideX()}, dY[2] = {0, vg.getStrideY()},
+ dZ[2] = {0, vg.getStrideZ()};
+ const Real gw[2] = {-Real(1), Real(1)};
+
+ const Vec3 &pos = p[idx].pos;
+ const IndexInt fi = static_cast<IndexInt>(pos.x), fj = static_cast<IndexInt>(pos.y),
+ fk = static_cast<IndexInt>(pos.z);
+ const IndexInt ci = static_cast<IndexInt>(pos.x - 0.5),
+ cj = static_cast<IndexInt>(pos.y - 0.5),
+ ck = static_cast<IndexInt>(pos.z - 0.5);
+ const Real wfi = clamp(pos.x - fi, Real(0), Real(1)),
+ wfj = clamp(pos.y - fj, Real(0), Real(1)),
+ wfk = clamp(pos.z - fk, Real(0), Real(1));
+ const Real wci = clamp(Real(pos.x - ci - 0.5), Real(0), Real(1)),
+ wcj = clamp(Real(pos.y - cj - 0.5), Real(0), Real(1)),
+ wck = clamp(Real(pos.z - ck - 0.5), Real(0), Real(1));
+ // TODO: check index for safety
+ { // u
+ const IndexInt gidx = fi * dX[1] + cj * dY[1] + ck * dZ[1];
+ const Real wx[2] = {Real(1) - wfi, wfi};
+ const Real wy[2] = {Real(1) - wcj, wcj};
+ const Real wz[2] = {Real(1) - wck, wck};
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ for (int k = 0; k < 2; ++k) {
+ const IndexInt vidx = gidx + dX[i] + dY[j] + dZ[k];
+ Real vgx = vg[vidx].x;
+ vp[idx].x += wx[i] * wy[j] * wz[k] * vgx;
+ cpx[idx].x += gw[i] * wy[j] * wz[k] * vgx;
+ cpx[idx].y += wx[i] * gw[j] * wz[k] * vgx;
+ cpx[idx].z += wx[i] * wy[j] * gw[k] * vgx;
+ }
+ }
+ { // v
+ const IndexInt gidx = ci * dX[1] + fj * dY[1] + ck * dZ[1];
+ const Real wx[2] = {Real(1) - wci, wci};
+ const Real wy[2] = {Real(1) - wfj, wfj};
+ const Real wz[2] = {Real(1) - wck, wck};
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ for (int k = 0; k < 2; ++k) {
+ const IndexInt vidx = gidx + dX[i] + dY[j] + dZ[k];
+ Real vgy = vg[vidx].y;
+ vp[idx].y += wx[i] * wy[j] * wz[k] * vgy;
+ cpy[idx].x += gw[i] * wy[j] * wz[k] * vgy;
+ cpy[idx].y += wx[i] * gw[j] * wz[k] * vgy;
+ cpy[idx].z += wx[i] * wy[j] * gw[k] * vgy;
+ }
+ }
+ if (!vg.is3D())
+ return;
+ { // w
+ const IndexInt gidx = ci * dX[1] + cj * dY[1] + fk * dZ[1];
+ const Real wx[2] = {Real(1) - wci, wci};
+ const Real wy[2] = {Real(1) - wcj, wcj};
+ const Real wz[2] = {Real(1) - wfk, wfk};
+ for (int i = 0; i < 2; ++i)
+ for (int j = 0; j < 2; ++j)
+ for (int k = 0; k < 2; ++k) {
+ const IndexInt vidx = gidx + dX[i] + dY[j] + dZ[k];
+ Real vgz = vg[vidx].z;
+ vp[idx].z += wx[i] * wy[j] * wz[k] * vgz;
+ cpz[idx].x += gw[i] * wy[j] * wz[k] * vgz;
+ cpz[idx].y += wx[i] * gw[j] * wz[k] * vgz;
+ cpz[idx].z += wx[i] * wy[j] * gw[k] * vgz;
+ }
+ }
+ }
+ inline ParticleDataImpl<Vec3> &getArg0()
+ {
+ return vp;
+ }
+ typedef ParticleDataImpl<Vec3> type0;
+ inline ParticleDataImpl<Vec3> &getArg1()
+ {
+ return cpx;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ inline ParticleDataImpl<Vec3> &getArg2()
+ {
+ return cpy;
+ }
+ typedef ParticleDataImpl<Vec3> type2;
+ inline ParticleDataImpl<Vec3> &getArg3()
+ {
+ return cpz;
+ }
+ typedef ParticleDataImpl<Vec3> type3;
+ inline const BasicParticleSystem &getArg4()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type4;
+ inline const MACGrid &getArg5()
+ {
+ return vg;
+ }
+ typedef MACGrid type5;
+ inline const FlagGrid &getArg6()
+ {
+ return flags;
+ }
+ typedef FlagGrid type6;
+ inline const ParticleDataImpl<int> *getArg7()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type7;
+ inline const int &getArg8()
+ {
+ return exclude;
+ }
+ typedef int type8;
+ void runMessage()
+ {
+ debMsg("Executing kernel knApicMapLinearMACGridToVec3 ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, vp, cpx, cpy, cpz, p, vg, flags, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<Vec3> &vp;
+ ParticleDataImpl<Vec3> &cpx;
+ ParticleDataImpl<Vec3> &cpy;
+ ParticleDataImpl<Vec3> &cpz;
+ const BasicParticleSystem &p;
+ const MACGrid &vg;
+ const FlagGrid &flags;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+void apicMapMACGridToParts(ParticleDataImpl<Vec3> &partVel,
+ ParticleDataImpl<Vec3> &cpx,
+ ParticleDataImpl<Vec3> &cpy,
+ ParticleDataImpl<Vec3> &cpz,
+ const BasicParticleSystem &parts,
+ const MACGrid &vel,
+ const FlagGrid &flags,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ knApicMapLinearMACGridToVec3(partVel, cpx, cpy, cpz, parts, vel, flags, ptype, exclude);
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "apicMapMACGridToParts", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ ParticleDataImpl<Vec3> &partVel = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "partVel", 0, &_lock);
+ ParticleDataImpl<Vec3> &cpx = *_args.getPtr<ParticleDataImpl<Vec3>>("cpx", 1, &_lock);
+ ParticleDataImpl<Vec3> &cpy = *_args.getPtr<ParticleDataImpl<Vec3>>("cpy", 2, &_lock);
+ ParticleDataImpl<Vec3> &cpz = *_args.getPtr<ParticleDataImpl<Vec3>>("cpz", 3, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 4, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 5, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 6, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 7, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 8, 0, &_lock);
+ _retval = getPyNone();
+ apicMapMACGridToParts(partVel, cpx, cpy, cpz, parts, vel, flags, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "apicMapMACGridToParts", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("apicMapMACGridToParts", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_apicMapMACGridToParts("", "apicMapMACGridToParts", _W_1);
+extern "C" {
+void PbRegister_apicMapMACGridToParts()
+{
+ KEEP_UNUSED(_RP_apicMapMACGridToParts);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/extforces.cpp b/extern/mantaflow/preprocessed/plugin/extforces.cpp
new file mode 100644
index 00000000000..3e1e5733257
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/extforces.cpp
@@ -0,0 +1,1559 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * Set boundary conditions, gravity
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "commonkernels.h"
+#include "particle.h"
+
+using namespace std;
+
+namespace Manta {
+
+//! add constant force between fl/fl and fl/em cells
+struct KnApplyForceField : public KernelBase {
+ KnApplyForceField(const FlagGrid &flags,
+ MACGrid &vel,
+ const Grid<Vec3> &force,
+ const Grid<Real> *include,
+ bool additive,
+ bool isMAC)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ vel(vel),
+ force(force),
+ include(include),
+ additive(additive),
+ isMAC(isMAC)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ MACGrid &vel,
+ const Grid<Vec3> &force,
+ const Grid<Real> *include,
+ bool additive,
+ bool isMAC) const
+ {
+ bool curFluid = flags.isFluid(i, j, k);
+ bool curEmpty = flags.isEmpty(i, j, k);
+ if (!curFluid && !curEmpty)
+ return;
+ if (include && ((*include)(i, j, k) > 0.))
+ return;
+
+ Real forceX = (isMAC) ? force(i, j, k).x : 0.5 * (force(i - 1, j, k).x + force(i, j, k).x);
+ Real forceY = (isMAC) ? force(i, j, k).y : 0.5 * (force(i, j - 1, k).y + force(i, j, k).y);
+
+ Real forceZ = 0.;
+ if (vel.is3D())
+ forceZ = (isMAC) ? force(i, j, k).z : 0.5 * (force(i, j, k - 1).z + force(i, j, k).z);
+
+ if (flags.isFluid(i - 1, j, k) || (curFluid && flags.isEmpty(i - 1, j, k)))
+ vel(i, j, k).x = (additive) ? vel(i, j, k).x + forceX : forceX;
+ if (flags.isFluid(i, j - 1, k) || (curFluid && flags.isEmpty(i, j - 1, k)))
+ vel(i, j, k).y = (additive) ? vel(i, j, k).y + forceY : forceY;
+ if (vel.is3D() && (flags.isFluid(i, j, k - 1) || (curFluid && flags.isEmpty(i, j, k - 1))))
+ vel(i, j, k).z = (additive) ? vel(i, j, k).z + forceZ : forceZ;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline const Grid<Vec3> &getArg2()
+ {
+ return force;
+ }
+ typedef Grid<Vec3> type2;
+ inline const Grid<Real> *getArg3()
+ {
+ return include;
+ }
+ typedef Grid<Real> type3;
+ inline bool &getArg4()
+ {
+ return additive;
+ }
+ typedef bool type4;
+ inline bool &getArg5()
+ {
+ return isMAC;
+ }
+ typedef bool type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnApplyForceField ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, force, include, additive, isMAC);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, force, include, additive, isMAC);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ MACGrid &vel;
+ const Grid<Vec3> &force;
+ const Grid<Real> *include;
+ bool additive;
+ bool isMAC;
+};
+
+//! add constant force between fl/fl and fl/em cells
+struct KnApplyForce : public KernelBase {
+ KnApplyForce(
+ const FlagGrid &flags, MACGrid &vel, Vec3 force, const Grid<Real> *exclude, bool additive)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ vel(vel),
+ force(force),
+ exclude(exclude),
+ additive(additive)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ MACGrid &vel,
+ Vec3 force,
+ const Grid<Real> *exclude,
+ bool additive) const
+ {
+ bool curFluid = flags.isFluid(i, j, k);
+ bool curEmpty = flags.isEmpty(i, j, k);
+ if (!curFluid && !curEmpty)
+ return;
+ if (exclude && ((*exclude)(i, j, k) < 0.))
+ return;
+
+ if (flags.isFluid(i - 1, j, k) || (curFluid && flags.isEmpty(i - 1, j, k)))
+ vel(i, j, k).x = (additive) ? vel(i, j, k).x + force.x : force.x;
+ if (flags.isFluid(i, j - 1, k) || (curFluid && flags.isEmpty(i, j - 1, k)))
+ vel(i, j, k).y = (additive) ? vel(i, j, k).y + force.y : force.y;
+ if (vel.is3D() && (flags.isFluid(i, j, k - 1) || (curFluid && flags.isEmpty(i, j, k - 1))))
+ vel(i, j, k).z = (additive) ? vel(i, j, k).z + force.z : force.z;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline Vec3 &getArg2()
+ {
+ return force;
+ }
+ typedef Vec3 type2;
+ inline const Grid<Real> *getArg3()
+ {
+ return exclude;
+ }
+ typedef Grid<Real> type3;
+ inline bool &getArg4()
+ {
+ return additive;
+ }
+ typedef bool type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnApplyForce ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, force, exclude, additive);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, force, exclude, additive);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ MACGrid &vel;
+ Vec3 force;
+ const Grid<Real> *exclude;
+ bool additive;
+};
+
+//! add gravity forces to all fluid cells, automatically adapts to different grid sizes
+void addGravity(const FlagGrid &flags,
+ MACGrid &vel,
+ Vec3 gravity,
+ const Grid<Real> *exclude = NULL)
+{
+ Vec3 f = gravity * flags.getParent()->getDt() / flags.getDx();
+ KnApplyForce(flags, vel, f, exclude, true);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "addGravity", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ Vec3 gravity = _args.get<Vec3>("gravity", 2, &_lock);
+ const Grid<Real> *exclude = _args.getPtrOpt<Grid<Real>>("exclude", 3, NULL, &_lock);
+ _retval = getPyNone();
+ addGravity(flags, vel, gravity, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "addGravity", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("addGravity", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_addGravity("", "addGravity", _W_0);
+extern "C" {
+void PbRegister_addGravity()
+{
+ KEEP_UNUSED(_RP_addGravity);
+}
+}
+
+//! add gravity forces to all fluid cells , but dont account for changing cell size
+void addGravityNoScale(const FlagGrid &flags,
+ MACGrid &vel,
+ const Vec3 &gravity,
+ const Grid<Real> *exclude = NULL)
+{
+ const Vec3 f = gravity * flags.getParent()->getDt();
+ KnApplyForce(flags, vel, f, exclude, true);
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "addGravityNoScale", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const Vec3 &gravity = _args.get<Vec3>("gravity", 2, &_lock);
+ const Grid<Real> *exclude = _args.getPtrOpt<Grid<Real>>("exclude", 3, NULL, &_lock);
+ _retval = getPyNone();
+ addGravityNoScale(flags, vel, gravity, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "addGravityNoScale", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("addGravityNoScale", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_addGravityNoScale("", "addGravityNoScale", _W_1);
+extern "C" {
+void PbRegister_addGravityNoScale()
+{
+ KEEP_UNUSED(_RP_addGravityNoScale);
+}
+}
+
+//! kernel to add Buoyancy force
+struct KnAddBuoyancy : public KernelBase {
+ KnAddBuoyancy(const FlagGrid &flags, const Grid<Real> &factor, MACGrid &vel, Vec3 strength)
+ : KernelBase(&flags, 1), flags(flags), factor(factor), vel(vel), strength(strength)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ const Grid<Real> &factor,
+ MACGrid &vel,
+ Vec3 strength) const
+ {
+ if (!flags.isFluid(i, j, k))
+ return;
+ if (flags.isFluid(i - 1, j, k))
+ vel(i, j, k).x += (0.5 * strength.x) * (factor(i, j, k) + factor(i - 1, j, k));
+ if (flags.isFluid(i, j - 1, k))
+ vel(i, j, k).y += (0.5 * strength.y) * (factor(i, j, k) + factor(i, j - 1, k));
+ if (vel.is3D() && flags.isFluid(i, j, k - 1))
+ vel(i, j, k).z += (0.5 * strength.z) * (factor(i, j, k) + factor(i, j, k - 1));
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return factor;
+ }
+ typedef Grid<Real> type1;
+ inline MACGrid &getArg2()
+ {
+ return vel;
+ }
+ typedef MACGrid type2;
+ inline Vec3 &getArg3()
+ {
+ return strength;
+ }
+ typedef Vec3 type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnAddBuoyancy ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, factor, vel, strength);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, factor, vel, strength);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ const Grid<Real> &factor;
+ MACGrid &vel;
+ Vec3 strength;
+};
+
+//! add Buoyancy force based on fctor (e.g. smoke density)
+void addBuoyancy(const FlagGrid &flags,
+ const Grid<Real> &density,
+ MACGrid &vel,
+ Vec3 gravity,
+ Real coefficient = 1.)
+{
+ Vec3 f = -gravity * flags.getParent()->getDt() / flags.getParent()->getDx() * coefficient;
+ KnAddBuoyancy(flags, density, vel, f);
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "addBuoyancy", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 2, &_lock);
+ Vec3 gravity = _args.get<Vec3>("gravity", 3, &_lock);
+ Real coefficient = _args.getOpt<Real>("coefficient", 4, 1., &_lock);
+ _retval = getPyNone();
+ addBuoyancy(flags, density, vel, gravity, coefficient);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "addBuoyancy", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("addBuoyancy", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_addBuoyancy("", "addBuoyancy", _W_2);
+extern "C" {
+void PbRegister_addBuoyancy()
+{
+ KEEP_UNUSED(_RP_addBuoyancy);
+}
+}
+
+// inflow / outflow boundaries
+
+//! helper to parse openbounds string [xXyYzZ] , convert to vec3
+inline void convertDescToVec(const string &desc, Vector3D<bool> &lo, Vector3D<bool> &up)
+{
+ for (size_t i = 0; i < desc.size(); i++) {
+ if (desc[i] == 'x')
+ lo.x = true;
+ else if (desc[i] == 'y')
+ lo.y = true;
+ else if (desc[i] == 'z')
+ lo.z = true;
+ else if (desc[i] == 'X')
+ up.x = true;
+ else if (desc[i] == 'Y')
+ up.y = true;
+ else if (desc[i] == 'Z')
+ up.z = true;
+ else
+ errMsg("invalid character in boundary description string. Only [xyzXYZ] allowed.");
+ }
+}
+
+//! add empty and outflow flag to cells of open boundaries
+void setOpenBound(FlagGrid &flags,
+ int bWidth,
+ string openBound = "",
+ int type = FlagGrid::TypeOutflow | FlagGrid::TypeEmpty)
+{
+ if (openBound == "")
+ return;
+ Vector3D<bool> lo, up;
+ convertDescToVec(openBound, lo, up);
+
+ FOR_IJK(flags)
+ {
+ bool loX = lo.x && i <= bWidth; // a cell which belongs to the lower x open bound
+ bool loY = lo.y && j <= bWidth;
+ bool upX = up.x && i >= flags.getSizeX() - bWidth -
+ 1; // a cell which belongs to the upper x open bound
+ bool upY = up.y && j >= flags.getSizeY() - bWidth - 1;
+ bool innerI = i > bWidth &&
+ i < flags.getSizeX() - bWidth -
+ 1; // a cell which does not belong to the lower or upper x bound
+ bool innerJ = j > bWidth && j < flags.getSizeY() - bWidth - 1;
+
+ // when setting boundaries to open: don't set shared part of wall to empty if neighboring wall
+ // is not open
+ if ((!flags.is3D()) && (loX || upX || loY || upY)) {
+ if ((loX || upX || innerI) && (loY || upY || innerJ) && flags.isObstacle(i, j, k))
+ flags(i, j, k) = type;
+ }
+ else {
+ bool loZ = lo.z && k <= bWidth; // a cell which belongs to the lower z open bound
+ bool upZ = up.z && k >= flags.getSizeZ() - bWidth -
+ 1; // a cell which belongs to the upper z open bound
+ bool innerK = k > bWidth &&
+ k < flags.getSizeZ() - bWidth -
+ 1; // a cell which does not belong to the lower or upper z bound
+ if (loX || upX || loY || upY || loZ || upZ) {
+ if ((loX || upX || innerI) && (loY || upY || innerJ) && (loZ || upZ || innerK) &&
+ flags.isObstacle(i, j, k))
+ flags(i, j, k) = type;
+ }
+ }
+ }
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setOpenBound", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ int bWidth = _args.get<int>("bWidth", 1, &_lock);
+ string openBound = _args.getOpt<string>("openBound", 2, "", &_lock);
+ int type = _args.getOpt<int>("type", 3, FlagGrid::TypeOutflow | FlagGrid::TypeEmpty, &_lock);
+ _retval = getPyNone();
+ setOpenBound(flags, bWidth, openBound, type);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setOpenBound", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setOpenBound", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setOpenBound("", "setOpenBound", _W_3);
+extern "C" {
+void PbRegister_setOpenBound()
+{
+ KEEP_UNUSED(_RP_setOpenBound);
+}
+}
+
+//! delete fluid and ensure empty flag in outflow cells, delete particles and density and set phi
+//! to 0.5
+void resetOutflow(FlagGrid &flags,
+ Grid<Real> *phi = 0,
+ BasicParticleSystem *parts = 0,
+ Grid<Real> *real = 0,
+ Grid<int> *index = 0,
+ ParticleIndexSystem *indexSys = 0)
+{
+ // check if phi and parts -> pindex and gpi already created -> access particles from cell index,
+ // avoid extra looping over particles
+ if (parts && (!index || !indexSys)) {
+ if (phi)
+ debMsg(
+ "resetOpenBound for phi and particles, but missing index and indexSys for enhanced "
+ "particle access!",
+ 1);
+ for (int idx = 0; idx < (int)parts->size(); idx++)
+ if (parts->isActive(idx) && flags.isInBounds(parts->getPos(idx)) &&
+ flags.isOutflow(parts->getPos(idx)))
+ parts->kill(idx);
+ }
+ FOR_IJK(flags)
+ {
+ if (flags.isOutflow(i, j, k)) {
+ flags(i, j, k) = (flags(i, j, k) | FlagGrid::TypeEmpty) &
+ ~FlagGrid::TypeFluid; // make sure there is not fluid flag set and to reset
+ // the empty flag
+ // the particles in a cell i,j,k are particles[index(i,j,k)] to particles[index(i+1,j,k)-1]
+ if (parts && index && indexSys) {
+ int isysIdxS = index->index(i, j, k);
+ int pStart = (*index)(isysIdxS), pEnd = 0;
+ if (flags.isInBounds(isysIdxS + 1))
+ pEnd = (*index)(isysIdxS + 1);
+ else
+ pEnd = indexSys->size();
+ // now loop over particles in cell
+ for (int p = pStart; p < pEnd; ++p) {
+ int psrc = (*indexSys)[p].sourceIndex;
+ if (parts->isActive(psrc) && flags.isInBounds(parts->getPos(psrc)))
+ parts->kill(psrc);
+ }
+ }
+ if (phi)
+ (*phi)(i, j, k) = 0.5;
+ if (real)
+ (*real)(i, j, k) = 0;
+ }
+ }
+ if (parts)
+ parts->doCompress();
+}
+static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "resetOutflow", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 1, 0, &_lock);
+ BasicParticleSystem *parts = _args.getPtrOpt<BasicParticleSystem>("parts", 2, 0, &_lock);
+ Grid<Real> *real = _args.getPtrOpt<Grid<Real>>("real", 3, 0, &_lock);
+ Grid<int> *index = _args.getPtrOpt<Grid<int>>("index", 4, 0, &_lock);
+ ParticleIndexSystem *indexSys = _args.getPtrOpt<ParticleIndexSystem>(
+ "indexSys", 5, 0, &_lock);
+ _retval = getPyNone();
+ resetOutflow(flags, phi, parts, real, index, indexSys);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "resetOutflow", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("resetOutflow", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_resetOutflow("", "resetOutflow", _W_4);
+extern "C" {
+void PbRegister_resetOutflow()
+{
+ KEEP_UNUSED(_RP_resetOutflow);
+}
+}
+
+//! enforce a constant inflow/outflow at the grid boundaries
+struct KnSetInflow : public KernelBase {
+ KnSetInflow(MACGrid &vel, int dim, int p0, const Vec3 &val)
+ : KernelBase(&vel, 0), vel(vel), dim(dim), p0(p0), val(val)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, MACGrid &vel, int dim, int p0, const Vec3 &val) const
+ {
+ Vec3i p(i, j, k);
+ if (p[dim] == p0 || p[dim] == p0 + 1)
+ vel(i, j, k) = val;
+ }
+ inline MACGrid &getArg0()
+ {
+ return vel;
+ }
+ typedef MACGrid type0;
+ inline int &getArg1()
+ {
+ return dim;
+ }
+ typedef int type1;
+ inline int &getArg2()
+ {
+ return p0;
+ }
+ typedef int type2;
+ inline const Vec3 &getArg3()
+ {
+ return val;
+ }
+ typedef Vec3 type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnSetInflow ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, vel, dim, p0, val);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, vel, dim, p0, val);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ MACGrid &vel;
+ int dim;
+ int p0;
+ const Vec3 &val;
+};
+
+//! enforce a constant inflow/outflow at the grid boundaries
+void setInflowBcs(MACGrid &vel, string dir, Vec3 value)
+{
+ for (size_t i = 0; i < dir.size(); i++) {
+ if (dir[i] >= 'x' && dir[i] <= 'z') {
+ int dim = dir[i] - 'x';
+ KnSetInflow(vel, dim, 0, value);
+ }
+ else if (dir[i] >= 'X' && dir[i] <= 'Z') {
+ int dim = dir[i] - 'X';
+ KnSetInflow(vel, dim, vel.getSize()[dim] - 1, value);
+ }
+ else
+ errMsg("invalid character in direction string. Only [xyzXYZ] allowed.");
+ }
+}
+static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setInflowBcs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ string dir = _args.get<string>("dir", 1, &_lock);
+ Vec3 value = _args.get<Vec3>("value", 2, &_lock);
+ _retval = getPyNone();
+ setInflowBcs(vel, dir, value);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setInflowBcs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setInflowBcs", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setInflowBcs("", "setInflowBcs", _W_5);
+extern "C" {
+void PbRegister_setInflowBcs()
+{
+ KEEP_UNUSED(_RP_setInflowBcs);
+}
+}
+
+// set obstacle boundary conditions
+
+//! set no-stick wall boundary condition between ob/fl and ob/ob cells
+struct KnSetWallBcs : public KernelBase {
+ KnSetWallBcs(const FlagGrid &flags, MACGrid &vel, const MACGrid *obvel)
+ : KernelBase(&flags, 0), flags(flags), vel(vel), obvel(obvel)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, const FlagGrid &flags, MACGrid &vel, const MACGrid *obvel) const
+ {
+
+ bool curFluid = flags.isFluid(i, j, k);
+ bool curObs = flags.isObstacle(i, j, k);
+ Vec3 bcsVel(0., 0., 0.);
+ if (!curFluid && !curObs)
+ return;
+
+ if (obvel) {
+ bcsVel.x = (*obvel)(i, j, k).x;
+ bcsVel.y = (*obvel)(i, j, k).y;
+ if ((*obvel).is3D())
+ bcsVel.z = (*obvel)(i, j, k).z;
+ }
+
+ // we use i>0 instead of bnd=1 to check outer wall
+ if (i > 0 && flags.isObstacle(i - 1, j, k))
+ vel(i, j, k).x = bcsVel.x;
+ if (i > 0 && curObs && flags.isFluid(i - 1, j, k))
+ vel(i, j, k).x = bcsVel.x;
+ if (j > 0 && flags.isObstacle(i, j - 1, k))
+ vel(i, j, k).y = bcsVel.y;
+ if (j > 0 && curObs && flags.isFluid(i, j - 1, k))
+ vel(i, j, k).y = bcsVel.y;
+
+ if (!vel.is3D()) {
+ vel(i, j, k).z = 0;
+ }
+ else {
+ if (k > 0 && flags.isObstacle(i, j, k - 1))
+ vel(i, j, k).z = bcsVel.z;
+ if (k > 0 && curObs && flags.isFluid(i, j, k - 1))
+ vel(i, j, k).z = bcsVel.z;
+ }
+
+ if (curFluid) {
+ if ((i > 0 && flags.isStick(i - 1, j, k)) ||
+ (i < flags.getSizeX() - 1 && flags.isStick(i + 1, j, k)))
+ vel(i, j, k).y = vel(i, j, k).z = 0;
+ if ((j > 0 && flags.isStick(i, j - 1, k)) ||
+ (j < flags.getSizeY() - 1 && flags.isStick(i, j + 1, k)))
+ vel(i, j, k).x = vel(i, j, k).z = 0;
+ if (vel.is3D() && ((k > 0 && flags.isStick(i, j, k - 1)) ||
+ (k < flags.getSizeZ() - 1 && flags.isStick(i, j, k + 1))))
+ vel(i, j, k).x = vel(i, j, k).y = 0;
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline const MACGrid *getArg2()
+ {
+ return obvel;
+ }
+ typedef MACGrid type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnSetWallBcs ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, vel, obvel);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, vel, obvel);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ MACGrid &vel;
+ const MACGrid *obvel;
+};
+
+//! set wall BCs for fill fraction mode, note - only needs obstacle SDF
+
+struct KnSetWallBcsFrac : public KernelBase {
+ KnSetWallBcsFrac(const FlagGrid &flags,
+ const MACGrid &vel,
+ MACGrid &velTarget,
+ const MACGrid *obvel,
+ const Grid<Real> *phiObs,
+ const int &boundaryWidth = 0)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ vel(vel),
+ velTarget(velTarget),
+ obvel(obvel),
+ phiObs(phiObs),
+ boundaryWidth(boundaryWidth)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ MACGrid &velTarget,
+ const MACGrid *obvel,
+ const Grid<Real> *phiObs,
+ const int &boundaryWidth = 0) const
+ {
+ bool curFluid = flags.isFluid(i, j, k);
+ bool curObs = flags.isObstacle(i, j, k);
+ velTarget(i, j, k) = vel(i, j, k);
+ if (!curFluid && !curObs)
+ return;
+
+ // zero normal component in all obstacle regions
+ if (flags.isInBounds(Vec3i(i, j, k), 1)) {
+
+ if (curObs | flags.isObstacle(i - 1, j, k)) {
+ Vec3 dphi(0., 0., 0.);
+ const Real tmp1 = (phiObs->get(i, j, k) + phiObs->get(i - 1, j, k)) * .5;
+ Real tmp2 = (phiObs->get(i, j + 1, k) + phiObs->get(i - 1, j + 1, k)) * .5;
+ Real phi1 = (tmp1 + tmp2) * .5;
+ tmp2 = (phiObs->get(i, j - 1, k) + phiObs->get(i - 1, j - 1, k)) * .5;
+ Real phi2 = (tmp1 + tmp2) * .5;
+
+ dphi.x = phiObs->get(i, j, k) - phiObs->get(i - 1, j, k);
+ dphi.y = phi1 - phi2;
+
+ if (phiObs->is3D()) {
+ tmp2 = (phiObs->get(i, j, k + 1) + phiObs->get(i - 1, j, k + 1)) * .5;
+ phi1 = (tmp1 + tmp2) * .5;
+ tmp2 = (phiObs->get(i, j, k - 1) + phiObs->get(i - 1, j, k - 1)) * .5;
+ phi2 = (tmp1 + tmp2) * .5;
+ dphi.z = phi1 - phi2;
+ }
+
+ normalize(dphi);
+ Vec3 velMAC = vel.getAtMACX(i, j, k);
+ velTarget(i, j, k).x = velMAC.x - dot(dphi, velMAC) * dphi.x;
+ }
+
+ if (curObs | flags.isObstacle(i, j - 1, k)) {
+ Vec3 dphi(0., 0., 0.);
+ const Real tmp1 = (phiObs->get(i, j, k) + phiObs->get(i, j - 1, k)) * .5;
+ Real tmp2 = (phiObs->get(i + 1, j, k) + phiObs->get(i + 1, j - 1, k)) * .5;
+ Real phi1 = (tmp1 + tmp2) * .5;
+ tmp2 = (phiObs->get(i - 1, j, k) + phiObs->get(i - 1, j - 1, k)) * .5;
+ Real phi2 = (tmp1 + tmp2) * .5;
+
+ dphi.x = phi1 - phi2;
+ dphi.y = phiObs->get(i, j, k) - phiObs->get(i, j - 1, k);
+ if (phiObs->is3D()) {
+ tmp2 = (phiObs->get(i, j, k + 1) + phiObs->get(i, j - 1, k + 1)) * .5;
+ phi1 = (tmp1 + tmp2) * .5;
+ tmp2 = (phiObs->get(i, j, k - 1) + phiObs->get(i, j - 1, k - 1)) * .5;
+ phi2 = (tmp1 + tmp2) * .5;
+ dphi.z = phi1 - phi2;
+ }
+
+ normalize(dphi);
+ Vec3 velMAC = vel.getAtMACY(i, j, k);
+ velTarget(i, j, k).y = velMAC.y - dot(dphi, velMAC) * dphi.y;
+ }
+
+ if (phiObs->is3D() && (curObs | flags.isObstacle(i, j, k - 1))) {
+ Vec3 dphi(0., 0., 0.);
+ const Real tmp1 = (phiObs->get(i, j, k) + phiObs->get(i, j, k - 1)) * .5;
+
+ Real tmp2;
+ tmp2 = (phiObs->get(i + 1, j, k) + phiObs->get(i + 1, j, k - 1)) * .5;
+ Real phi1 = (tmp1 + tmp2) * .5;
+ tmp2 = (phiObs->get(i - 1, j, k) + phiObs->get(i - 1, j, k - 1)) * .5;
+ Real phi2 = (tmp1 + tmp2) * .5;
+ dphi.x = phi1 - phi2;
+
+ tmp2 = (phiObs->get(i, j + 1, k) + phiObs->get(i, j + 1, k - 1)) * .5;
+ phi1 = (tmp1 + tmp2) * .5;
+ tmp2 = (phiObs->get(i, j - 1, k) + phiObs->get(i, j - 1, k - 1)) * .5;
+ phi2 = (tmp1 + tmp2) * .5;
+ dphi.y = phi1 - phi2;
+
+ dphi.z = phiObs->get(i, j, k) - phiObs->get(i, j, k - 1);
+
+ normalize(dphi);
+ Vec3 velMAC = vel.getAtMACZ(i, j, k);
+ velTarget(i, j, k).z = velMAC.z - dot(dphi, velMAC) * dphi.z;
+ }
+ } // not at boundary
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline MACGrid &getArg2()
+ {
+ return velTarget;
+ }
+ typedef MACGrid type2;
+ inline const MACGrid *getArg3()
+ {
+ return obvel;
+ }
+ typedef MACGrid type3;
+ inline const Grid<Real> *getArg4()
+ {
+ return phiObs;
+ }
+ typedef Grid<Real> type4;
+ inline const int &getArg5()
+ {
+ return boundaryWidth;
+ }
+ typedef int type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnSetWallBcsFrac ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, vel, velTarget, obvel, phiObs, boundaryWidth);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, vel, velTarget, obvel, phiObs, boundaryWidth);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ MACGrid &velTarget;
+ const MACGrid *obvel;
+ const Grid<Real> *phiObs;
+ const int &boundaryWidth;
+};
+
+//! set zero normal velocity boundary condition on walls
+// (optionally with second order accuracy using the obstacle SDF , fractions grid currentlyl not
+// needed)
+void setWallBcs(const FlagGrid &flags,
+ MACGrid &vel,
+ const MACGrid *obvel = 0,
+ const MACGrid *fractions = 0,
+ const Grid<Real> *phiObs = 0,
+ int boundaryWidth = 0)
+{
+ if (!phiObs || !fractions) {
+ KnSetWallBcs(flags, vel, obvel);
+ }
+ else {
+ MACGrid tmpvel(vel.getParent());
+ KnSetWallBcsFrac(flags, vel, tmpvel, obvel, phiObs, boundaryWidth);
+ vel.swap(tmpvel);
+ }
+}
+static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setWallBcs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const MACGrid *obvel = _args.getPtrOpt<MACGrid>("obvel", 2, 0, &_lock);
+ const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 3, 0, &_lock);
+ const Grid<Real> *phiObs = _args.getPtrOpt<Grid<Real>>("phiObs", 4, 0, &_lock);
+ int boundaryWidth = _args.getOpt<int>("boundaryWidth", 5, 0, &_lock);
+ _retval = getPyNone();
+ setWallBcs(flags, vel, obvel, fractions, phiObs, boundaryWidth);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setWallBcs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setWallBcs", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setWallBcs("", "setWallBcs", _W_6);
+extern "C" {
+void PbRegister_setWallBcs()
+{
+ KEEP_UNUSED(_RP_setWallBcs);
+}
+}
+
+//! add Forces between fl/fl and fl/em cells (interpolate cell centered forces to MAC grid)
+struct KnAddForceIfLower : public KernelBase {
+ KnAddForceIfLower(const FlagGrid &flags, MACGrid &vel, const Grid<Vec3> &force)
+ : KernelBase(&flags, 1), flags(flags), vel(vel), force(force)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, const FlagGrid &flags, MACGrid &vel, const Grid<Vec3> &force) const
+ {
+ bool curFluid = flags.isFluid(i, j, k);
+ bool curEmpty = flags.isEmpty(i, j, k);
+ if (!curFluid && !curEmpty)
+ return;
+
+ if (flags.isFluid(i - 1, j, k) || (curFluid && flags.isEmpty(i - 1, j, k))) {
+ Real forceMACX = 0.5 * (force(i - 1, j, k).x + force(i, j, k).x);
+ Real min = std::min(vel(i, j, k).x, forceMACX);
+ Real max = std::max(vel(i, j, k).x, forceMACX);
+ Real sum = vel(i, j, k).x + forceMACX;
+ vel(i, j, k).x = (forceMACX > 0) ? std::min(sum, max) : std::max(sum, min);
+ }
+ if (flags.isFluid(i, j - 1, k) || (curFluid && flags.isEmpty(i, j - 1, k))) {
+ Real forceMACY = 0.5 * (force(i, j - 1, k).y + force(i, j, k).y);
+ Real min = std::min(vel(i, j, k).y, forceMACY);
+ Real max = std::max(vel(i, j, k).y, forceMACY);
+ Real sum = vel(i, j, k).y + forceMACY;
+ vel(i, j, k).y = (forceMACY > 0) ? std::min(sum, max) : std::max(sum, min);
+ }
+ if (vel.is3D() && (flags.isFluid(i, j, k - 1) || (curFluid && flags.isEmpty(i, j, k - 1)))) {
+ Real forceMACZ = 0.5 * (force(i, j, k - 1).z + force(i, j, k).z);
+ Real min = std::min(vel(i, j, k).z, forceMACZ);
+ Real max = std::max(vel(i, j, k).z, forceMACZ);
+ Real sum = vel(i, j, k).z + forceMACZ;
+ vel(i, j, k).z = (forceMACZ > 0) ? std::min(sum, max) : std::max(sum, min);
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline const Grid<Vec3> &getArg2()
+ {
+ return force;
+ }
+ typedef Grid<Vec3> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnAddForceIfLower ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, force);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, force);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ MACGrid &vel;
+ const Grid<Vec3> &force;
+};
+
+// Initial velocity for smoke
+void setInitialVelocity(const FlagGrid &flags, MACGrid &vel, const Grid<Vec3> &invel)
+{
+ KnAddForceIfLower(flags, vel, invel);
+}
+static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setInitialVelocity", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const Grid<Vec3> &invel = *_args.getPtr<Grid<Vec3>>("invel", 2, &_lock);
+ _retval = getPyNone();
+ setInitialVelocity(flags, vel, invel);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setInitialVelocity", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setInitialVelocity", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setInitialVelocity("", "setInitialVelocity", _W_7);
+extern "C" {
+void PbRegister_setInitialVelocity()
+{
+ KEEP_UNUSED(_RP_setInitialVelocity);
+}
+}
+
+//! Kernel: gradient norm operator
+struct KnConfForce : public KernelBase {
+ KnConfForce(Grid<Vec3> &force,
+ const Grid<Real> &grid,
+ const Grid<Vec3> &curl,
+ Real str,
+ const Grid<Real> *strGrid)
+ : KernelBase(&force, 1), force(force), grid(grid), curl(curl), str(str), strGrid(strGrid)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<Vec3> &force,
+ const Grid<Real> &grid,
+ const Grid<Vec3> &curl,
+ Real str,
+ const Grid<Real> *strGrid) const
+ {
+ Vec3 grad = 0.5 * Vec3(grid(i + 1, j, k) - grid(i - 1, j, k),
+ grid(i, j + 1, k) - grid(i, j - 1, k),
+ 0.);
+ if (grid.is3D())
+ grad[2] = 0.5 * (grid(i, j, k + 1) - grid(i, j, k - 1));
+ normalize(grad);
+ if (strGrid)
+ str += (*strGrid)(i, j, k);
+ force(i, j, k) = str * cross(grad, curl(i, j, k));
+ }
+ inline Grid<Vec3> &getArg0()
+ {
+ return force;
+ }
+ typedef Grid<Vec3> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return grid;
+ }
+ typedef Grid<Real> type1;
+ inline const Grid<Vec3> &getArg2()
+ {
+ return curl;
+ }
+ typedef Grid<Vec3> type2;
+ inline Real &getArg3()
+ {
+ return str;
+ }
+ typedef Real type3;
+ inline const Grid<Real> *getArg4()
+ {
+ return strGrid;
+ }
+ typedef Grid<Real> type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnConfForce ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, force, grid, curl, str, strGrid);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, force, grid, curl, str, strGrid);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<Vec3> &force;
+ const Grid<Real> &grid;
+ const Grid<Vec3> &curl;
+ Real str;
+ const Grid<Real> *strGrid;
+};
+
+void vorticityConfinement(MACGrid &vel,
+ const FlagGrid &flags,
+ Real strengthGlobal = 0,
+ const Grid<Real> *strengthCell = NULL)
+{
+ Grid<Vec3> velCenter(flags.getParent()), curl(flags.getParent()), force(flags.getParent());
+ Grid<Real> norm(flags.getParent());
+
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, curl);
+ GridNorm(norm, curl);
+ KnConfForce(force, norm, curl, strengthGlobal, strengthCell);
+ KnApplyForceField(flags, vel, force, NULL, true, false);
+}
+static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "vorticityConfinement", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ Real strengthGlobal = _args.getOpt<Real>("strengthGlobal", 2, 0, &_lock);
+ const Grid<Real> *strengthCell = _args.getPtrOpt<Grid<Real>>(
+ "strengthCell", 3, NULL, &_lock);
+ _retval = getPyNone();
+ vorticityConfinement(vel, flags, strengthGlobal, strengthCell);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "vorticityConfinement", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("vorticityConfinement", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_vorticityConfinement("", "vorticityConfinement", _W_8);
+extern "C" {
+void PbRegister_vorticityConfinement()
+{
+ KEEP_UNUSED(_RP_vorticityConfinement);
+}
+}
+
+void addForceField(const FlagGrid &flags,
+ MACGrid &vel,
+ const Grid<Vec3> &force,
+ const Grid<Real> *region = NULL,
+ bool isMAC = false)
+{
+ KnApplyForceField(flags, vel, force, region, true, isMAC);
+}
+static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "addForceField", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const Grid<Vec3> &force = *_args.getPtr<Grid<Vec3>>("force", 2, &_lock);
+ const Grid<Real> *region = _args.getPtrOpt<Grid<Real>>("region", 3, NULL, &_lock);
+ bool isMAC = _args.getOpt<bool>("isMAC", 4, false, &_lock);
+ _retval = getPyNone();
+ addForceField(flags, vel, force, region, isMAC);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "addForceField", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("addForceField", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_addForceField("", "addForceField", _W_9);
+extern "C" {
+void PbRegister_addForceField()
+{
+ KEEP_UNUSED(_RP_addForceField);
+}
+}
+
+void setForceField(const FlagGrid &flags,
+ MACGrid &vel,
+ const Grid<Vec3> &force,
+ const Grid<Real> *region = NULL,
+ bool isMAC = false)
+{
+ KnApplyForceField(flags, vel, force, region, false, isMAC);
+}
+static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setForceField", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const Grid<Vec3> &force = *_args.getPtr<Grid<Vec3>>("force", 2, &_lock);
+ const Grid<Real> *region = _args.getPtrOpt<Grid<Real>>("region", 3, NULL, &_lock);
+ bool isMAC = _args.getOpt<bool>("isMAC", 4, false, &_lock);
+ _retval = getPyNone();
+ setForceField(flags, vel, force, region, isMAC);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setForceField", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setForceField", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setForceField("", "setForceField", _W_10);
+extern "C" {
+void PbRegister_setForceField()
+{
+ KEEP_UNUSED(_RP_setForceField);
+}
+}
+
+void dissolveSmoke(const FlagGrid &flags,
+ Grid<Real> &density,
+ Grid<Real> *heat = NULL,
+ Grid<Real> *red = NULL,
+ Grid<Real> *green = NULL,
+ Grid<Real> *blue = NULL,
+ int speed = 5,
+ bool logFalloff = true)
+{
+ float dydx = 1.0f / (float)speed; // max density/speed = dydx
+ float fac = 1.0f - dydx;
+
+ FOR_IJK_BND(density, 0)
+ {
+ bool curFluid = flags.isFluid(i, j, k);
+ if (!curFluid)
+ continue;
+
+ if (logFalloff) {
+ density(i, j, k) *= fac;
+ if (heat) {
+ (*heat)(i, j, k) *= fac;
+ }
+ if (red) {
+ (*red)(i, j, k) *= fac;
+ (*green)(i, j, k) *= fac;
+ (*blue)(i, j, k) *= fac;
+ }
+ }
+ else { // linear falloff
+ float d = density(i, j, k);
+ density(i, j, k) -= dydx;
+ if (density(i, j, k) < 0.0f)
+ density(i, j, k) = 0.0f;
+ if (heat) {
+ if (fabs((*heat)(i, j, k)) < dydx)
+ (*heat)(i, j, k) = 0.0f;
+ else if ((*heat)(i, j, k) > 0.0f)
+ (*heat)(i, j, k) -= dydx;
+ else if ((*heat)(i, j, k) < 0.0f)
+ (*heat)(i, j, k) += dydx;
+ }
+ if (red && notZero(d)) {
+ (*red)(i, j, k) *= (density(i, j, k) / d);
+ (*green)(i, j, k) *= (density(i, j, k) / d);
+ (*blue)(i, j, k) *= (density(i, j, k) / d);
+ }
+ }
+ }
+}
+static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "dissolveSmoke", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
+ Grid<Real> *heat = _args.getPtrOpt<Grid<Real>>("heat", 2, NULL, &_lock);
+ Grid<Real> *red = _args.getPtrOpt<Grid<Real>>("red", 3, NULL, &_lock);
+ Grid<Real> *green = _args.getPtrOpt<Grid<Real>>("green", 4, NULL, &_lock);
+ Grid<Real> *blue = _args.getPtrOpt<Grid<Real>>("blue", 5, NULL, &_lock);
+ int speed = _args.getOpt<int>("speed", 6, 5, &_lock);
+ bool logFalloff = _args.getOpt<bool>("logFalloff", 7, true, &_lock);
+ _retval = getPyNone();
+ dissolveSmoke(flags, density, heat, red, green, blue, speed, logFalloff);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "dissolveSmoke", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("dissolveSmoke", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_dissolveSmoke("", "dissolveSmoke", _W_11);
+extern "C" {
+void PbRegister_dissolveSmoke()
+{
+ KEEP_UNUSED(_RP_dissolveSmoke);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/fire.cpp b/extern/mantaflow/preprocessed/plugin/fire.cpp
new file mode 100644
index 00000000000..9047d4bf8a1
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/fire.cpp
@@ -0,0 +1,435 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2016 Sebastian Barschkis, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Fire modeling plugin
+ *
+ ******************************************************************************/
+
+#include "general.h"
+#include "grid.h"
+#include "vectorbase.h"
+
+using namespace std;
+
+namespace Manta {
+
+struct KnProcessBurn : public KernelBase {
+ KnProcessBurn(Grid<Real> &fuel,
+ Grid<Real> &density,
+ Grid<Real> &react,
+ Grid<Real> *red,
+ Grid<Real> *green,
+ Grid<Real> *blue,
+ Grid<Real> *heat,
+ Real burningRate,
+ Real flameSmoke,
+ Real ignitionTemp,
+ Real maxTemp,
+ Real dt,
+ Vec3 flameSmokeColor)
+ : KernelBase(&fuel, 1),
+ fuel(fuel),
+ density(density),
+ react(react),
+ red(red),
+ green(green),
+ blue(blue),
+ heat(heat),
+ burningRate(burningRate),
+ flameSmoke(flameSmoke),
+ ignitionTemp(ignitionTemp),
+ maxTemp(maxTemp),
+ dt(dt),
+ flameSmokeColor(flameSmokeColor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<Real> &fuel,
+ Grid<Real> &density,
+ Grid<Real> &react,
+ Grid<Real> *red,
+ Grid<Real> *green,
+ Grid<Real> *blue,
+ Grid<Real> *heat,
+ Real burningRate,
+ Real flameSmoke,
+ Real ignitionTemp,
+ Real maxTemp,
+ Real dt,
+ Vec3 flameSmokeColor) const
+ {
+ // Save initial values
+ Real origFuel = fuel(i, j, k);
+ Real origSmoke = density(i, j, k);
+ Real smokeEmit = 0.0f;
+ Real flame = 0.0f;
+
+ // Process fuel
+ fuel(i, j, k) -= burningRate * dt;
+ if (fuel(i, j, k) < 0.0f)
+ fuel(i, j, k) = 0.0f;
+
+ // Process reaction coordinate
+ if (origFuel > VECTOR_EPSILON) {
+ react(i, j, k) *= fuel(i, j, k) / origFuel;
+ flame = pow(react(i, j, k), 0.5f);
+ }
+ else {
+ react(i, j, k) = 0.0f;
+ }
+
+ // Set fluid temperature based on fuel burn rate and "flameSmoke" factor
+ smokeEmit = (origFuel < 1.0f) ? (1.0 - origFuel) * 0.5f : 0.0f;
+ smokeEmit = (smokeEmit + 0.5f) * (origFuel - fuel(i, j, k)) * 0.1f * flameSmoke;
+ density(i, j, k) += smokeEmit;
+ clamp(density(i, j, k), (Real)0.0f, (Real)1.0f);
+
+ // Set fluid temperature from the flame temperature profile
+ if (heat && flame)
+ (*heat)(i, j, k) = (1.0f - flame) * ignitionTemp + flame * maxTemp;
+
+ // Mix new color
+ if (smokeEmit > VECTOR_EPSILON) {
+ float smokeFactor = density(i, j, k) / (origSmoke + smokeEmit);
+ if (red)
+ (*red)(i, j, k) = ((*red)(i, j, k) + flameSmokeColor.x * smokeEmit) * smokeFactor;
+ if (green)
+ (*green)(i, j, k) = ((*green)(i, j, k) + flameSmokeColor.y * smokeEmit) * smokeFactor;
+ if (blue)
+ (*blue)(i, j, k) = ((*blue)(i, j, k) + flameSmokeColor.z * smokeEmit) * smokeFactor;
+ }
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return fuel;
+ }
+ typedef Grid<Real> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return density;
+ }
+ typedef Grid<Real> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return react;
+ }
+ typedef Grid<Real> type2;
+ inline Grid<Real> *getArg3()
+ {
+ return red;
+ }
+ typedef Grid<Real> type3;
+ inline Grid<Real> *getArg4()
+ {
+ return green;
+ }
+ typedef Grid<Real> type4;
+ inline Grid<Real> *getArg5()
+ {
+ return blue;
+ }
+ typedef Grid<Real> type5;
+ inline Grid<Real> *getArg6()
+ {
+ return heat;
+ }
+ typedef Grid<Real> type6;
+ inline Real &getArg7()
+ {
+ return burningRate;
+ }
+ typedef Real type7;
+ inline Real &getArg8()
+ {
+ return flameSmoke;
+ }
+ typedef Real type8;
+ inline Real &getArg9()
+ {
+ return ignitionTemp;
+ }
+ typedef Real type9;
+ inline Real &getArg10()
+ {
+ return maxTemp;
+ }
+ typedef Real type10;
+ inline Real &getArg11()
+ {
+ return dt;
+ }
+ typedef Real type11;
+ inline Vec3 &getArg12()
+ {
+ return flameSmokeColor;
+ }
+ typedef Vec3 type12;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnProcessBurn ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ fuel,
+ density,
+ react,
+ red,
+ green,
+ blue,
+ heat,
+ burningRate,
+ flameSmoke,
+ ignitionTemp,
+ maxTemp,
+ dt,
+ flameSmokeColor);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ fuel,
+ density,
+ react,
+ red,
+ green,
+ blue,
+ heat,
+ burningRate,
+ flameSmoke,
+ ignitionTemp,
+ maxTemp,
+ dt,
+ flameSmokeColor);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<Real> &fuel;
+ Grid<Real> &density;
+ Grid<Real> &react;
+ Grid<Real> *red;
+ Grid<Real> *green;
+ Grid<Real> *blue;
+ Grid<Real> *heat;
+ Real burningRate;
+ Real flameSmoke;
+ Real ignitionTemp;
+ Real maxTemp;
+ Real dt;
+ Vec3 flameSmokeColor;
+};
+
+void processBurn(Grid<Real> &fuel,
+ Grid<Real> &density,
+ Grid<Real> &react,
+ Grid<Real> *red = NULL,
+ Grid<Real> *green = NULL,
+ Grid<Real> *blue = NULL,
+ Grid<Real> *heat = NULL,
+ Real burningRate = 0.75f,
+ Real flameSmoke = 1.0f,
+ Real ignitionTemp = 1.25f,
+ Real maxTemp = 1.75f,
+ Vec3 flameSmokeColor = Vec3(0.7f, 0.7f, 0.7f))
+{
+ Real dt = fuel.getParent()->getDt();
+ KnProcessBurn(fuel,
+ density,
+ react,
+ red,
+ green,
+ blue,
+ heat,
+ burningRate,
+ flameSmoke,
+ ignitionTemp,
+ maxTemp,
+ dt,
+ flameSmokeColor);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "processBurn", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &fuel = *_args.getPtr<Grid<Real>>("fuel", 0, &_lock);
+ Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
+ Grid<Real> &react = *_args.getPtr<Grid<Real>>("react", 2, &_lock);
+ Grid<Real> *red = _args.getPtrOpt<Grid<Real>>("red", 3, NULL, &_lock);
+ Grid<Real> *green = _args.getPtrOpt<Grid<Real>>("green", 4, NULL, &_lock);
+ Grid<Real> *blue = _args.getPtrOpt<Grid<Real>>("blue", 5, NULL, &_lock);
+ Grid<Real> *heat = _args.getPtrOpt<Grid<Real>>("heat", 6, NULL, &_lock);
+ Real burningRate = _args.getOpt<Real>("burningRate", 7, 0.75f, &_lock);
+ Real flameSmoke = _args.getOpt<Real>("flameSmoke", 8, 1.0f, &_lock);
+ Real ignitionTemp = _args.getOpt<Real>("ignitionTemp", 9, 1.25f, &_lock);
+ Real maxTemp = _args.getOpt<Real>("maxTemp", 10, 1.75f, &_lock);
+ Vec3 flameSmokeColor = _args.getOpt<Vec3>(
+ "flameSmokeColor", 11, Vec3(0.7f, 0.7f, 0.7f), &_lock);
+ _retval = getPyNone();
+ processBurn(fuel,
+ density,
+ react,
+ red,
+ green,
+ blue,
+ heat,
+ burningRate,
+ flameSmoke,
+ ignitionTemp,
+ maxTemp,
+ flameSmokeColor);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "processBurn", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("processBurn", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_processBurn("", "processBurn", _W_0);
+extern "C" {
+void PbRegister_processBurn()
+{
+ KEEP_UNUSED(_RP_processBurn);
+}
+}
+
+struct KnUpdateFlame : public KernelBase {
+ KnUpdateFlame(const Grid<Real> &react, Grid<Real> &flame)
+ : KernelBase(&react, 1), react(react), flame(flame)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const Grid<Real> &react, Grid<Real> &flame) const
+ {
+ if (react(i, j, k) > 0.0f)
+ flame(i, j, k) = pow(react(i, j, k), 0.5f);
+ else
+ flame(i, j, k) = 0.0f;
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return react;
+ }
+ typedef Grid<Real> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return flame;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnUpdateFlame ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, react, flame);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, react, flame);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const Grid<Real> &react;
+ Grid<Real> &flame;
+};
+
+void updateFlame(const Grid<Real> &react, Grid<Real> &flame)
+{
+ KnUpdateFlame(react, flame);
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "updateFlame", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Real> &react = *_args.getPtr<Grid<Real>>("react", 0, &_lock);
+ Grid<Real> &flame = *_args.getPtr<Grid<Real>>("flame", 1, &_lock);
+ _retval = getPyNone();
+ updateFlame(react, flame);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "updateFlame", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("updateFlame", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_updateFlame("", "updateFlame", _W_1);
+extern "C" {
+void PbRegister_updateFlame()
+{
+ KEEP_UNUSED(_RP_updateFlame);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/flip.cpp b/extern/mantaflow/preprocessed/plugin/flip.cpp
new file mode 100644
index 00000000000..f6d082900b5
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/flip.cpp
@@ -0,0 +1,2819 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * FLIP (fluid implicit particles)
+ * for use with particle data fields
+ *
+ ******************************************************************************/
+
+#include "particle.h"
+#include "grid.h"
+#include "commonkernels.h"
+#include "randomstream.h"
+#include "levelset.h"
+#include "shapes.h"
+#include "matrixbase.h"
+
+using namespace std;
+namespace Manta {
+
+// init
+
+//! note - this is a simplified version , sampleLevelsetWithParticles has more functionality
+
+void sampleFlagsWithParticles(const FlagGrid &flags,
+ BasicParticleSystem &parts,
+ const int discretization,
+ const Real randomness)
+{
+ const bool is3D = flags.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp(1.0 / discretization, 1.0 / discretization, 1.0 / discretization);
+ RandomStream mRand(9832);
+
+ FOR_IJK_BND(flags, 0)
+ {
+ if (flags.isObstacle(i, j, k))
+ continue;
+ if (flags.isFluid(i, j, k)) {
+ const Vec3 pos(i, j, k);
+ for (int dk = 0; dk < (is3D ? discretization : 1); dk++)
+ for (int dj = 0; dj < discretization; dj++)
+ for (int di = 0; di < discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5 + di, 0.5 + dj, 0.5 + dk);
+ subpos += jlen * (Vec3(1, 1, 1) - 2.0 * mRand.getVec3());
+ if (!is3D)
+ subpos[2] = 0.5;
+ parts.addBuffered(subpos);
+ }
+ }
+ }
+ parts.insertBufferedParticles();
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "sampleFlagsWithParticles", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 1, &_lock);
+ const int discretization = _args.get<int>("discretization", 2, &_lock);
+ const Real randomness = _args.get<Real>("randomness", 3, &_lock);
+ _retval = getPyNone();
+ sampleFlagsWithParticles(flags, parts, discretization, randomness);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "sampleFlagsWithParticles", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("sampleFlagsWithParticles", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_sampleFlagsWithParticles("", "sampleFlagsWithParticles", _W_0);
+extern "C" {
+void PbRegister_sampleFlagsWithParticles()
+{
+ KEEP_UNUSED(_RP_sampleFlagsWithParticles);
+}
+}
+
+//! sample a level set with particles, use reset to clear the particle buffer,
+//! and skipEmpty for a continuous inflow (in the latter case, only empty cells will
+//! be re-filled once they empty when calling sampleLevelsetWithParticles during
+//! the main loop).
+
+void sampleLevelsetWithParticles(const LevelsetGrid &phi,
+ const FlagGrid &flags,
+ BasicParticleSystem &parts,
+ const int discretization,
+ const Real randomness,
+ const bool reset = false,
+ const bool refillEmpty = false,
+ const int particleFlag = -1)
+{
+ const bool is3D = phi.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp(1.0 / discretization, 1.0 / discretization, 1.0 / discretization);
+ RandomStream mRand(9832);
+
+ if (reset) {
+ parts.clear();
+ parts.doCompress();
+ }
+
+ FOR_IJK_BND(phi, 0)
+ {
+ if (flags.isObstacle(i, j, k))
+ continue;
+ if (refillEmpty && flags.isFluid(i, j, k))
+ continue;
+ if (phi(i, j, k) < 1.733) {
+ const Vec3 pos(i, j, k);
+ for (int dk = 0; dk < (is3D ? discretization : 1); dk++)
+ for (int dj = 0; dj < discretization; dj++)
+ for (int di = 0; di < discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5 + di, 0.5 + dj, 0.5 + dk);
+ subpos += jlen * (Vec3(1, 1, 1) - 2.0 * mRand.getVec3());
+ if (!is3D)
+ subpos[2] = 0.5;
+ if (phi.getInterpolated(subpos) > 0.)
+ continue;
+ if (particleFlag < 0) {
+ parts.addBuffered(subpos);
+ }
+ else {
+ parts.addBuffered(subpos, particleFlag);
+ }
+ }
+ }
+ }
+
+ parts.insertBufferedParticles();
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "sampleLevelsetWithParticles", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ const int discretization = _args.get<int>("discretization", 3, &_lock);
+ const Real randomness = _args.get<Real>("randomness", 4, &_lock);
+ const bool reset = _args.getOpt<bool>("reset", 5, false, &_lock);
+ const bool refillEmpty = _args.getOpt<bool>("refillEmpty", 6, false, &_lock);
+ const int particleFlag = _args.getOpt<int>("particleFlag", 7, -1, &_lock);
+ _retval = getPyNone();
+ sampleLevelsetWithParticles(
+ phi, flags, parts, discretization, randomness, reset, refillEmpty, particleFlag);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "sampleLevelsetWithParticles", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("sampleLevelsetWithParticles", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_sampleLevelsetWithParticles("", "sampleLevelsetWithParticles", _W_1);
+extern "C" {
+void PbRegister_sampleLevelsetWithParticles()
+{
+ KEEP_UNUSED(_RP_sampleLevelsetWithParticles);
+}
+}
+
+//! sample a shape with particles, use reset to clear the particle buffer,
+//! and skipEmpty for a continuous inflow (in the latter case, only empty cells will
+//! be re-filled once they empty when calling sampleShapeWithParticles during
+//! the main loop).
+
+void sampleShapeWithParticles(const Shape &shape,
+ const FlagGrid &flags,
+ BasicParticleSystem &parts,
+ const int discretization,
+ const Real randomness,
+ const bool reset = false,
+ const bool refillEmpty = false,
+ const LevelsetGrid *exclude = NULL)
+{
+ const bool is3D = flags.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp(1.0 / discretization, 1.0 / discretization, 1.0 / discretization);
+ RandomStream mRand(9832);
+
+ if (reset) {
+ parts.clear();
+ parts.doCompress();
+ }
+
+ FOR_IJK_BND(flags, 0)
+ {
+ if (flags.isObstacle(i, j, k))
+ continue;
+ if (refillEmpty && flags.isFluid(i, j, k))
+ continue;
+ const Vec3 pos(i, j, k);
+ for (int dk = 0; dk < (is3D ? discretization : 1); dk++)
+ for (int dj = 0; dj < discretization; dj++)
+ for (int di = 0; di < discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5 + di, 0.5 + dj, 0.5 + dk);
+ subpos += jlen * (Vec3(1, 1, 1) - 2.0 * mRand.getVec3());
+ if (!is3D)
+ subpos[2] = 0.5;
+ if (exclude && exclude->getInterpolated(subpos) <= 0.)
+ continue;
+ if (!shape.isInside(subpos))
+ continue;
+ parts.addBuffered(subpos);
+ }
+ }
+
+ parts.insertBufferedParticles();
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "sampleShapeWithParticles", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Shape &shape = *_args.getPtr<Shape>("shape", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ const int discretization = _args.get<int>("discretization", 3, &_lock);
+ const Real randomness = _args.get<Real>("randomness", 4, &_lock);
+ const bool reset = _args.getOpt<bool>("reset", 5, false, &_lock);
+ const bool refillEmpty = _args.getOpt<bool>("refillEmpty", 6, false, &_lock);
+ const LevelsetGrid *exclude = _args.getPtrOpt<LevelsetGrid>("exclude", 7, NULL, &_lock);
+ _retval = getPyNone();
+ sampleShapeWithParticles(
+ shape, flags, parts, discretization, randomness, reset, refillEmpty, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "sampleShapeWithParticles", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("sampleShapeWithParticles", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_sampleShapeWithParticles("", "sampleShapeWithParticles", _W_2);
+extern "C" {
+void PbRegister_sampleShapeWithParticles()
+{
+ KEEP_UNUSED(_RP_sampleShapeWithParticles);
+}
+}
+
+//! mark fluid cells and helpers
+struct knClearFluidFlags : public KernelBase {
+ knClearFluidFlags(FlagGrid &flags, int dummy = 0)
+ : KernelBase(&flags, 0), flags(flags), dummy(dummy)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, FlagGrid &flags, int dummy = 0) const
+ {
+ if (flags.isFluid(i, j, k)) {
+ flags(i, j, k) = (flags(i, j, k) | FlagGrid::TypeEmpty) & ~FlagGrid::TypeFluid;
+ }
+ }
+ inline FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline int &getArg1()
+ {
+ return dummy;
+ }
+ typedef int type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knClearFluidFlags ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, dummy);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, dummy);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ FlagGrid &flags;
+ int dummy;
+};
+
+struct knSetNbObstacle : public KernelBase {
+ knSetNbObstacle(FlagGrid &nflags, const FlagGrid &flags, const Grid<Real> &phiObs)
+ : KernelBase(&nflags, 1), nflags(nflags), flags(flags), phiObs(phiObs)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, FlagGrid &nflags, const FlagGrid &flags, const Grid<Real> &phiObs) const
+ {
+ if (phiObs(i, j, k) > 0.)
+ return;
+ if (flags.isEmpty(i, j, k)) {
+ bool set = false;
+ if ((flags.isFluid(i - 1, j, k)) && (phiObs(i + 1, j, k) <= 0.))
+ set = true;
+ if ((flags.isFluid(i + 1, j, k)) && (phiObs(i - 1, j, k) <= 0.))
+ set = true;
+ if ((flags.isFluid(i, j - 1, k)) && (phiObs(i, j + 1, k) <= 0.))
+ set = true;
+ if ((flags.isFluid(i, j + 1, k)) && (phiObs(i, j - 1, k) <= 0.))
+ set = true;
+ if (flags.is3D()) {
+ if ((flags.isFluid(i, j, k - 1)) && (phiObs(i, j, k + 1) <= 0.))
+ set = true;
+ if ((flags.isFluid(i, j, k + 1)) && (phiObs(i, j, k - 1) <= 0.))
+ set = true;
+ }
+ if (set)
+ nflags(i, j, k) = (flags(i, j, k) | FlagGrid::TypeFluid) & ~FlagGrid::TypeEmpty;
+ }
+ }
+ inline FlagGrid &getArg0()
+ {
+ return nflags;
+ }
+ typedef FlagGrid type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return phiObs;
+ }
+ typedef Grid<Real> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetNbObstacle ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, nflags, flags, phiObs);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, nflags, flags, phiObs);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ FlagGrid &nflags;
+ const FlagGrid &flags;
+ const Grid<Real> &phiObs;
+};
+void markFluidCells(const BasicParticleSystem &parts,
+ FlagGrid &flags,
+ const Grid<Real> *phiObs = NULL,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // remove all fluid cells
+ knClearFluidFlags(flags, 0);
+
+ // mark all particles in flaggrid as fluid
+ for (IndexInt idx = 0; idx < parts.size(); idx++) {
+ if (!parts.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ continue;
+ Vec3i p = toVec3i(parts.getPos(idx));
+ if (flags.isInBounds(p) && flags.isEmpty(p))
+ flags(p) = (flags(p) | FlagGrid::TypeFluid) & ~FlagGrid::TypeEmpty;
+ }
+
+ // special for second order obstacle BCs, check empty cells in boundary region
+ if (phiObs) {
+ FlagGrid tmp(flags);
+ knSetNbObstacle(tmp, flags, *phiObs);
+ flags.swap(tmp);
+ }
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "markFluidCells", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ const Grid<Real> *phiObs = _args.getPtrOpt<Grid<Real>>("phiObs", 2, NULL, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 3, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 4, 0, &_lock);
+ _retval = getPyNone();
+ markFluidCells(parts, flags, phiObs, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "markFluidCells", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("markFluidCells", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_markFluidCells("", "markFluidCells", _W_3);
+extern "C" {
+void PbRegister_markFluidCells()
+{
+ KEEP_UNUSED(_RP_markFluidCells);
+}
+}
+
+// for testing purposes only...
+void testInitGridWithPos(Grid<Real> &grid)
+{
+ FOR_IJK(grid)
+ {
+ grid(i, j, k) = norm(Vec3(i, j, k));
+ }
+}
+static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "testInitGridWithPos", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &grid = *_args.getPtr<Grid<Real>>("grid", 0, &_lock);
+ _retval = getPyNone();
+ testInitGridWithPos(grid);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "testInitGridWithPos", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("testInitGridWithPos", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_testInitGridWithPos("", "testInitGridWithPos", _W_4);
+extern "C" {
+void PbRegister_testInitGridWithPos()
+{
+ KEEP_UNUSED(_RP_testInitGridWithPos);
+}
+}
+
+//! helper to calculate particle radius factor to cover the diagonal of a cell in 2d/3d
+inline Real calculateRadiusFactor(const Grid<Real> &grid, Real factor)
+{
+ return (grid.is3D() ? sqrt(3.) : sqrt(2.)) *
+ (factor + .01); // note, a 1% safety factor is added here
+}
+
+//! re-sample particles based on an input levelset
+// optionally skip seeding new particles in "exclude" SDF
+
+void adjustNumber(BasicParticleSystem &parts,
+ const MACGrid &vel,
+ const FlagGrid &flags,
+ int minParticles,
+ int maxParticles,
+ const LevelsetGrid &phi,
+ Real radiusFactor = 1.,
+ Real narrowBand = -1.,
+ const Grid<Real> *exclude = NULL)
+{
+ // which levelset to use as threshold
+ const Real SURFACE_LS = -1.0 * calculateRadiusFactor(phi, radiusFactor);
+ Grid<int> tmp(vel.getParent());
+ std::ostringstream out;
+
+ // count particles in cells, and delete excess particles
+ for (IndexInt idx = 0; idx < (int)parts.size(); idx++) {
+ if (parts.isActive(idx)) {
+ Vec3i p = toVec3i(parts.getPos(idx));
+ if (!tmp.isInBounds(p)) {
+ parts.kill(idx); // out of domain, remove
+ continue;
+ }
+
+ Real phiv = phi.getInterpolated(parts.getPos(idx));
+ if (phiv > 0) {
+ parts.kill(idx);
+ continue;
+ }
+ if (narrowBand > 0. && phiv < -narrowBand) {
+ parts.kill(idx);
+ continue;
+ }
+
+ bool atSurface = false;
+ if (phiv > SURFACE_LS)
+ atSurface = true;
+ int num = tmp(p);
+
+ // dont delete particles in non fluid cells here, the particles are "always right"
+ if (num > maxParticles && (!atSurface)) {
+ parts.kill(idx);
+ }
+ else {
+ tmp(p) = num + 1;
+ }
+ }
+ }
+
+ // seed new particles
+ RandomStream mRand(9832);
+ FOR_IJK(tmp)
+ {
+ int cnt = tmp(i, j, k);
+
+ // skip cells near surface
+ if (phi(i, j, k) > SURFACE_LS)
+ continue;
+ if (narrowBand > 0. && phi(i, j, k) < -narrowBand) {
+ continue;
+ }
+ if (exclude && ((*exclude)(i, j, k) < 0.)) {
+ continue;
+ }
+
+ if (flags.isFluid(i, j, k) && cnt < minParticles) {
+ for (int m = cnt; m < minParticles; m++) {
+ Vec3 pos = Vec3(i, j, k) + mRand.getVec3();
+ // Vec3 pos (i + 0.5, j + 0.5, k + 0.5); // cell center
+ parts.addBuffered(pos);
+ }
+ }
+ }
+
+ parts.doCompress();
+ parts.insertBufferedParticles();
+}
+static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "adjustNumber", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ int minParticles = _args.get<int>("minParticles", 3, &_lock);
+ int maxParticles = _args.get<int>("maxParticles", 4, &_lock);
+ const LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 5, &_lock);
+ Real radiusFactor = _args.getOpt<Real>("radiusFactor", 6, 1., &_lock);
+ Real narrowBand = _args.getOpt<Real>("narrowBand", 7, -1., &_lock);
+ const Grid<Real> *exclude = _args.getPtrOpt<Grid<Real>>("exclude", 8, NULL, &_lock);
+ _retval = getPyNone();
+ adjustNumber(
+ parts, vel, flags, minParticles, maxParticles, phi, radiusFactor, narrowBand, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "adjustNumber", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("adjustNumber", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_adjustNumber("", "adjustNumber", _W_5);
+extern "C" {
+void PbRegister_adjustNumber()
+{
+ KEEP_UNUSED(_RP_adjustNumber);
+}
+}
+
+// simple and slow helper conversion to show contents of int grids like a real grid in the ui
+// (use eg to quickly display contents of the particle-index grid)
+
+void debugIntToReal(const Grid<int> &source, Grid<Real> &dest, Real factor = 1.)
+{
+ FOR_IJK(source)
+ {
+ dest(i, j, k) = (Real)source(i, j, k) * factor;
+ }
+}
+static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "debugIntToReal", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<int> &source = *_args.getPtr<Grid<int>>("source", 0, &_lock);
+ Grid<Real> &dest = *_args.getPtr<Grid<Real>>("dest", 1, &_lock);
+ Real factor = _args.getOpt<Real>("factor", 2, 1., &_lock);
+ _retval = getPyNone();
+ debugIntToReal(source, dest, factor);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "debugIntToReal", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("debugIntToReal", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_debugIntToReal("", "debugIntToReal", _W_6);
+extern "C" {
+void PbRegister_debugIntToReal()
+{
+ KEEP_UNUSED(_RP_debugIntToReal);
+}
+}
+
+// build a grid that contains indices for a particle system
+// the particles in a cell i,j,k are particles[index(i,j,k)] to particles[index(i+1,j,k)-1]
+// (ie, particles[index(i+1,j,k)] already belongs to cell i+1,j,k)
+
+void gridParticleIndex(const BasicParticleSystem &parts,
+ ParticleIndexSystem &indexSys,
+ const FlagGrid &flags,
+ Grid<int> &index,
+ Grid<int> *counter = NULL)
+{
+ bool delCounter = false;
+ if (!counter) {
+ counter = new Grid<int>(flags.getParent());
+ delCounter = true;
+ }
+ else {
+ counter->clear();
+ }
+
+ // count particles in cells, and delete excess particles
+ index.clear();
+ int inactive = 0;
+ for (IndexInt idx = 0; idx < (IndexInt)parts.size(); idx++) {
+ if (parts.isActive(idx)) {
+ // check index for validity...
+ Vec3i p = toVec3i(parts.getPos(idx));
+ if (!index.isInBounds(p)) {
+ inactive++;
+ continue;
+ }
+
+ index(p)++;
+ }
+ else {
+ inactive++;
+ }
+ }
+
+ // note - this one might be smaller...
+ indexSys.resize(parts.size() - inactive);
+
+ // convert per cell number to continuous index
+ IndexInt idx = 0;
+ FOR_IJK(index)
+ {
+ int num = index(i, j, k);
+ index(i, j, k) = idx;
+ idx += num;
+ }
+
+ // add particles to indexed array, we still need a per cell particle counter
+ for (IndexInt idx = 0; idx < (IndexInt)parts.size(); idx++) {
+ if (!parts.isActive(idx))
+ continue;
+ Vec3i p = toVec3i(parts.getPos(idx));
+ if (!index.isInBounds(p)) {
+ continue;
+ }
+
+ // initialize position and index into original array
+ // indexSys[ index(p)+(*counter)(p) ].pos = parts[idx].pos;
+ indexSys[index(p) + (*counter)(p)].sourceIndex = idx;
+ (*counter)(p)++;
+ }
+
+ if (delCounter)
+ delete counter;
+}
+static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "gridParticleIndex", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ ParticleIndexSystem &indexSys = *_args.getPtr<ParticleIndexSystem>("indexSys", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ Grid<int> &index = *_args.getPtr<Grid<int>>("index", 3, &_lock);
+ Grid<int> *counter = _args.getPtrOpt<Grid<int>>("counter", 4, NULL, &_lock);
+ _retval = getPyNone();
+ gridParticleIndex(parts, indexSys, flags, index, counter);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "gridParticleIndex", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("gridParticleIndex", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_gridParticleIndex("", "gridParticleIndex", _W_7);
+extern "C" {
+void PbRegister_gridParticleIndex()
+{
+ KEEP_UNUSED(_RP_gridParticleIndex);
+}
+}
+
+struct ComputeUnionLevelsetPindex : public KernelBase {
+ ComputeUnionLevelsetPindex(const Grid<int> &index,
+ const BasicParticleSystem &parts,
+ const ParticleIndexSystem &indexSys,
+ LevelsetGrid &phi,
+ const Real radius,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(&index, 0),
+ index(index),
+ parts(parts),
+ indexSys(indexSys),
+ phi(phi),
+ radius(radius),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const Grid<int> &index,
+ const BasicParticleSystem &parts,
+ const ParticleIndexSystem &indexSys,
+ LevelsetGrid &phi,
+ const Real radius,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ const Vec3 gridPos = Vec3(i, j, k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.0; // outside
+
+ int r = int(radius) + 1;
+ int rZ = phi.is3D() ? r : 0;
+ for (int zj = k - rZ; zj <= k + rZ; zj++)
+ for (int yj = j - r; yj <= j + r; yj++)
+ for (int xj = i - r; xj <= i + r; xj++) {
+ if (!phi.isInBounds(Vec3i(xj, yj, zj)))
+ continue;
+
+ // note, for the particle indices in indexSys the access is periodic (ie, dont skip for
+ // eg inBounds(sx,10,10)
+ IndexInt isysIdxS = index.index(xj, yj, zj);
+ IndexInt pStart = index(isysIdxS), pEnd = 0;
+ if (phi.isInBounds(isysIdxS + 1))
+ pEnd = index(isysIdxS + 1);
+ else
+ pEnd = indexSys.size();
+
+ // now loop over particles in cell
+ for (IndexInt p = pStart; p < pEnd; ++p) {
+ const int psrc = indexSys[p].sourceIndex;
+ if (ptype && ((*ptype)[psrc] & exclude))
+ continue;
+ const Vec3 pos = parts[psrc].pos;
+ phiv = std::min(phiv, fabs(norm(gridPos - pos)) - radius);
+ }
+ }
+ phi(i, j, k) = phiv;
+ }
+ inline const Grid<int> &getArg0()
+ {
+ return index;
+ }
+ typedef Grid<int> type0;
+ inline const BasicParticleSystem &getArg1()
+ {
+ return parts;
+ }
+ typedef BasicParticleSystem type1;
+ inline const ParticleIndexSystem &getArg2()
+ {
+ return indexSys;
+ }
+ typedef ParticleIndexSystem type2;
+ inline LevelsetGrid &getArg3()
+ {
+ return phi;
+ }
+ typedef LevelsetGrid type3;
+ inline const Real &getArg4()
+ {
+ return radius;
+ }
+ typedef Real type4;
+ inline const ParticleDataImpl<int> *getArg5()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type5;
+ inline const int &getArg6()
+ {
+ return exclude;
+ }
+ typedef int type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel ComputeUnionLevelsetPindex ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, index, parts, indexSys, phi, radius, ptype, exclude);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, index, parts, indexSys, phi, radius, ptype, exclude);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const Grid<int> &index;
+ const BasicParticleSystem &parts;
+ const ParticleIndexSystem &indexSys;
+ LevelsetGrid &phi;
+ const Real radius;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+void unionParticleLevelset(const BasicParticleSystem &parts,
+ const ParticleIndexSystem &indexSys,
+ const FlagGrid &flags,
+ const Grid<int> &index,
+ LevelsetGrid &phi,
+ const Real radiusFactor = 1.,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // use half a cell diagonal as base radius
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor);
+ // no reset of phi necessary here
+ ComputeUnionLevelsetPindex(index, parts, indexSys, phi, radius, ptype, exclude);
+
+ phi.setBound(0.5, 0);
+}
+static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "unionParticleLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const ParticleIndexSystem &indexSys = *_args.getPtr<ParticleIndexSystem>(
+ "indexSys", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ const Grid<int> &index = *_args.getPtr<Grid<int>>("index", 3, &_lock);
+ LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 4, &_lock);
+ const Real radiusFactor = _args.getOpt<Real>("radiusFactor", 5, 1., &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 6, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 7, 0, &_lock);
+ _retval = getPyNone();
+ unionParticleLevelset(parts, indexSys, flags, index, phi, radiusFactor, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "unionParticleLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("unionParticleLevelset", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_unionParticleLevelset("", "unionParticleLevelset", _W_8);
+extern "C" {
+void PbRegister_unionParticleLevelset()
+{
+ KEEP_UNUSED(_RP_unionParticleLevelset);
+}
+}
+
+//! kernel for computing averaged particle level set weights
+
+struct ComputeAveragedLevelsetWeight : public KernelBase {
+ ComputeAveragedLevelsetWeight(const BasicParticleSystem &parts,
+ const Grid<int> &index,
+ const ParticleIndexSystem &indexSys,
+ LevelsetGrid &phi,
+ const Real radius,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude,
+ Grid<Vec3> *save_pAcc = NULL,
+ Grid<Real> *save_rAcc = NULL)
+ : KernelBase(&index, 0),
+ parts(parts),
+ index(index),
+ indexSys(indexSys),
+ phi(phi),
+ radius(radius),
+ ptype(ptype),
+ exclude(exclude),
+ save_pAcc(save_pAcc),
+ save_rAcc(save_rAcc)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const BasicParticleSystem &parts,
+ const Grid<int> &index,
+ const ParticleIndexSystem &indexSys,
+ LevelsetGrid &phi,
+ const Real radius,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude,
+ Grid<Vec3> *save_pAcc = NULL,
+ Grid<Real> *save_rAcc = NULL) const
+ {
+ const Vec3 gridPos = Vec3(i, j, k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.0; // outside
+
+ // loop over neighborhood, similar to ComputeUnionLevelsetPindex
+ const Real sradiusInv = 1. / (4. * radius * radius);
+ int r = int(1. * radius) + 1;
+ int rZ = phi.is3D() ? r : 0;
+ // accumulators
+ Real wacc = 0.;
+ Vec3 pacc = Vec3(0.);
+ Real racc = 0.;
+
+ for (int zj = k - rZ; zj <= k + rZ; zj++)
+ for (int yj = j - r; yj <= j + r; yj++)
+ for (int xj = i - r; xj <= i + r; xj++) {
+ if (!phi.isInBounds(Vec3i(xj, yj, zj)))
+ continue;
+
+ IndexInt isysIdxS = index.index(xj, yj, zj);
+ IndexInt pStart = index(isysIdxS), pEnd = 0;
+ if (phi.isInBounds(isysIdxS + 1))
+ pEnd = index(isysIdxS + 1);
+ else
+ pEnd = indexSys.size();
+ for (IndexInt p = pStart; p < pEnd; ++p) {
+ IndexInt psrc = indexSys[p].sourceIndex;
+ if (ptype && ((*ptype)[psrc] & exclude))
+ continue;
+
+ Vec3 pos = parts[psrc].pos;
+ Real s = normSquare(gridPos - pos) * sradiusInv;
+ // Real w = std::max(0., cubed(1.-s) );
+ Real w = std::max(0., (1. - s)); // a bit smoother
+ wacc += w;
+ racc += radius * w;
+ pacc += pos * w;
+ }
+ }
+
+ if (wacc > VECTOR_EPSILON) {
+ racc /= wacc;
+ pacc /= wacc;
+ phiv = fabs(norm(gridPos - pacc)) - racc;
+
+ if (save_pAcc)
+ (*save_pAcc)(i, j, k) = pacc;
+ if (save_rAcc)
+ (*save_rAcc)(i, j, k) = racc;
+ }
+ phi(i, j, k) = phiv;
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return parts;
+ }
+ typedef BasicParticleSystem type0;
+ inline const Grid<int> &getArg1()
+ {
+ return index;
+ }
+ typedef Grid<int> type1;
+ inline const ParticleIndexSystem &getArg2()
+ {
+ return indexSys;
+ }
+ typedef ParticleIndexSystem type2;
+ inline LevelsetGrid &getArg3()
+ {
+ return phi;
+ }
+ typedef LevelsetGrid type3;
+ inline const Real &getArg4()
+ {
+ return radius;
+ }
+ typedef Real type4;
+ inline const ParticleDataImpl<int> *getArg5()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type5;
+ inline const int &getArg6()
+ {
+ return exclude;
+ }
+ typedef int type6;
+ inline Grid<Vec3> *getArg7()
+ {
+ return save_pAcc;
+ }
+ typedef Grid<Vec3> type7;
+ inline Grid<Real> *getArg8()
+ {
+ return save_rAcc;
+ }
+ typedef Grid<Real> type8;
+ void runMessage()
+ {
+ debMsg("Executing kernel ComputeAveragedLevelsetWeight ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, parts, index, indexSys, phi, radius, ptype, exclude, save_pAcc, save_rAcc);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, parts, index, indexSys, phi, radius, ptype, exclude, save_pAcc, save_rAcc);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const BasicParticleSystem &parts;
+ const Grid<int> &index;
+ const ParticleIndexSystem &indexSys;
+ LevelsetGrid &phi;
+ const Real radius;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+ Grid<Vec3> *save_pAcc;
+ Grid<Real> *save_rAcc;
+};
+
+template<class T> T smoothingValue(const Grid<T> val, int i, int j, int k, T center)
+{
+ return val(i, j, k);
+}
+
+// smoothing, and
+
+template<class T> struct knSmoothGrid : public KernelBase {
+ knSmoothGrid(const Grid<T> &me, Grid<T> &tmp, Real factor)
+ : KernelBase(&me, 1), me(me), tmp(tmp), factor(factor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const Grid<T> &me, Grid<T> &tmp, Real factor) const
+ {
+ T val = me(i, j, k) + me(i + 1, j, k) + me(i - 1, j, k) + me(i, j + 1, k) + me(i, j - 1, k);
+ if (me.is3D()) {
+ val += me(i, j, k + 1) + me(i, j, k - 1);
+ }
+ tmp(i, j, k) = val * factor;
+ }
+ inline const Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline Grid<T> &getArg1()
+ {
+ return tmp;
+ }
+ typedef Grid<T> type1;
+ inline Real &getArg2()
+ {
+ return factor;
+ }
+ typedef Real type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSmoothGrid ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, me, tmp, factor);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, me, tmp, factor);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const Grid<T> &me;
+ Grid<T> &tmp;
+ Real factor;
+};
+
+template<class T> struct knSmoothGridNeg : public KernelBase {
+ knSmoothGridNeg(const Grid<T> &me, Grid<T> &tmp, Real factor)
+ : KernelBase(&me, 1), me(me), tmp(tmp), factor(factor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const Grid<T> &me, Grid<T> &tmp, Real factor) const
+ {
+ T val = me(i, j, k) + me(i + 1, j, k) + me(i - 1, j, k) + me(i, j + 1, k) + me(i, j - 1, k);
+ if (me.is3D()) {
+ val += me(i, j, k + 1) + me(i, j, k - 1);
+ }
+ val *= factor;
+ if (val < tmp(i, j, k))
+ tmp(i, j, k) = val;
+ else
+ tmp(i, j, k) = me(i, j, k);
+ }
+ inline const Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline Grid<T> &getArg1()
+ {
+ return tmp;
+ }
+ typedef Grid<T> type1;
+ inline Real &getArg2()
+ {
+ return factor;
+ }
+ typedef Real type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSmoothGridNeg ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, me, tmp, factor);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, me, tmp, factor);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const Grid<T> &me;
+ Grid<T> &tmp;
+ Real factor;
+};
+
+//! Zhu & Bridson particle level set creation
+
+void averagedParticleLevelset(const BasicParticleSystem &parts,
+ const ParticleIndexSystem &indexSys,
+ const FlagGrid &flags,
+ const Grid<int> &index,
+ LevelsetGrid &phi,
+ const Real radiusFactor = 1.,
+ const int smoothen = 1,
+ const int smoothenNeg = 1,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // use half a cell diagonal as base radius
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor);
+ ComputeAveragedLevelsetWeight(parts, index, indexSys, phi, radius, ptype, exclude);
+
+ // post-process level-set
+ for (int i = 0; i < std::max(smoothen, smoothenNeg); ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ if (i < smoothen) {
+ knSmoothGrid<Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ if (i < smoothenNeg) {
+ knSmoothGridNeg<Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ }
+ phi.setBound(0.5, 0);
+}
+static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "averagedParticleLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const ParticleIndexSystem &indexSys = *_args.getPtr<ParticleIndexSystem>(
+ "indexSys", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ const Grid<int> &index = *_args.getPtr<Grid<int>>("index", 3, &_lock);
+ LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 4, &_lock);
+ const Real radiusFactor = _args.getOpt<Real>("radiusFactor", 5, 1., &_lock);
+ const int smoothen = _args.getOpt<int>("smoothen", 6, 1, &_lock);
+ const int smoothenNeg = _args.getOpt<int>("smoothenNeg", 7, 1, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 8, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 9, 0, &_lock);
+ _retval = getPyNone();
+ averagedParticleLevelset(
+ parts, indexSys, flags, index, phi, radiusFactor, smoothen, smoothenNeg, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "averagedParticleLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("averagedParticleLevelset", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_averagedParticleLevelset("", "averagedParticleLevelset", _W_9);
+extern "C" {
+void PbRegister_averagedParticleLevelset()
+{
+ KEEP_UNUSED(_RP_averagedParticleLevelset);
+}
+}
+
+//! kernel for improvedParticleLevelset
+
+struct correctLevelset : public KernelBase {
+ correctLevelset(LevelsetGrid &phi,
+ const Grid<Vec3> &pAcc,
+ const Grid<Real> &rAcc,
+ const Real radius,
+ const Real t_low,
+ const Real t_high)
+ : KernelBase(&phi, 1),
+ phi(phi),
+ pAcc(pAcc),
+ rAcc(rAcc),
+ radius(radius),
+ t_low(t_low),
+ t_high(t_high)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ LevelsetGrid &phi,
+ const Grid<Vec3> &pAcc,
+ const Grid<Real> &rAcc,
+ const Real radius,
+ const Real t_low,
+ const Real t_high) const
+ {
+ if (rAcc(i, j, k) <= VECTOR_EPSILON)
+ return; // outside nothing happens
+ Real x = pAcc(i, j, k).x;
+
+ // create jacobian of pAcc via central differences
+ Matrix3x3f jacobian = Matrix3x3f(0.5 * (pAcc(i + 1, j, k).x - pAcc(i - 1, j, k).x),
+ 0.5 * (pAcc(i, j + 1, k).x - pAcc(i, j - 1, k).x),
+ 0.5 * (pAcc(i, j, k + 1).x - pAcc(i, j, k - 1).x),
+ 0.5 * (pAcc(i + 1, j, k).y - pAcc(i - 1, j, k).y),
+ 0.5 * (pAcc(i, j + 1, k).y - pAcc(i, j - 1, k).y),
+ 0.5 * (pAcc(i, j, k + 1).y - pAcc(i, j, k - 1).y),
+ 0.5 * (pAcc(i + 1, j, k).z - pAcc(i - 1, j, k).z),
+ 0.5 * (pAcc(i, j + 1, k).z - pAcc(i, j - 1, k).z),
+ 0.5 * (pAcc(i, j, k + 1).z - pAcc(i, j, k - 1).z));
+
+ // compute largest eigenvalue of jacobian
+ Vec3 EV = jacobian.eigenvalues();
+ Real maxEV = std::max(std::max(EV.x, EV.y), EV.z);
+
+ // calculate correction factor
+ Real correction = 1;
+ if (maxEV >= t_low) {
+ Real t = (t_high - maxEV) / (t_high - t_low);
+ correction = t * t * t - 3 * t * t + 3 * t;
+ }
+ correction = (correction < 0) ?
+ 0 :
+ correction; // enforce correction factor to [0,1] (not explicitly in paper)
+
+ const Vec3 gridPos = Vec3(i, j, k) + Vec3(0.5); // shifted by half cell
+ const Real correctedPhi = fabs(norm(gridPos - pAcc(i, j, k))) - rAcc(i, j, k) * correction;
+ phi(i, j, k) = (correctedPhi > radius) ?
+ radius :
+ correctedPhi; // adjust too high outside values when too few particles are
+ // nearby to make smoothing possible (not in paper)
+ }
+ inline LevelsetGrid &getArg0()
+ {
+ return phi;
+ }
+ typedef LevelsetGrid type0;
+ inline const Grid<Vec3> &getArg1()
+ {
+ return pAcc;
+ }
+ typedef Grid<Vec3> type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return rAcc;
+ }
+ typedef Grid<Real> type2;
+ inline const Real &getArg3()
+ {
+ return radius;
+ }
+ typedef Real type3;
+ inline const Real &getArg4()
+ {
+ return t_low;
+ }
+ typedef Real type4;
+ inline const Real &getArg5()
+ {
+ return t_high;
+ }
+ typedef Real type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel correctLevelset ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, phi, pAcc, rAcc, radius, t_low, t_high);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, phi, pAcc, rAcc, radius, t_low, t_high);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ LevelsetGrid &phi;
+ const Grid<Vec3> &pAcc;
+ const Grid<Real> &rAcc;
+ const Real radius;
+ const Real t_low;
+ const Real t_high;
+};
+
+//! Approach from "A unified particle model for fluid-solid interactions" by Solenthaler et al. in
+//! 2007
+
+void improvedParticleLevelset(const BasicParticleSystem &parts,
+ const ParticleIndexSystem &indexSys,
+ const FlagGrid &flags,
+ const Grid<int> &index,
+ LevelsetGrid &phi,
+ const Real radiusFactor = 1.,
+ const int smoothen = 1,
+ const int smoothenNeg = 1,
+ const Real t_low = 0.4,
+ const Real t_high = 3.5,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // create temporary grids to store values from levelset weight computation
+ Grid<Vec3> save_pAcc(flags.getParent());
+ Grid<Real> save_rAcc(flags.getParent());
+
+ const Real radius = 0.5 * calculateRadiusFactor(
+ phi, radiusFactor); // use half a cell diagonal as base radius
+ ComputeAveragedLevelsetWeight(
+ parts, index, indexSys, phi, radius, ptype, exclude, &save_pAcc, &save_rAcc);
+ correctLevelset(phi, save_pAcc, save_rAcc, radius, t_low, t_high);
+
+ // post-process level-set
+ for (int i = 0; i < std::max(smoothen, smoothenNeg); ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ if (i < smoothen) {
+ knSmoothGrid<Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ if (i < smoothenNeg) {
+ knSmoothGridNeg<Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ }
+ phi.setBound(0.5, 0);
+}
+static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "improvedParticleLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const ParticleIndexSystem &indexSys = *_args.getPtr<ParticleIndexSystem>(
+ "indexSys", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ const Grid<int> &index = *_args.getPtr<Grid<int>>("index", 3, &_lock);
+ LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 4, &_lock);
+ const Real radiusFactor = _args.getOpt<Real>("radiusFactor", 5, 1., &_lock);
+ const int smoothen = _args.getOpt<int>("smoothen", 6, 1, &_lock);
+ const int smoothenNeg = _args.getOpt<int>("smoothenNeg", 7, 1, &_lock);
+ const Real t_low = _args.getOpt<Real>("t_low", 8, 0.4, &_lock);
+ const Real t_high = _args.getOpt<Real>("t_high", 9, 3.5, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 10, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 11, 0, &_lock);
+ _retval = getPyNone();
+ improvedParticleLevelset(parts,
+ indexSys,
+ flags,
+ index,
+ phi,
+ radiusFactor,
+ smoothen,
+ smoothenNeg,
+ t_low,
+ t_high,
+ ptype,
+ exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "improvedParticleLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("improvedParticleLevelset", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_improvedParticleLevelset("", "improvedParticleLevelset", _W_10);
+extern "C" {
+void PbRegister_improvedParticleLevelset()
+{
+ KEEP_UNUSED(_RP_improvedParticleLevelset);
+}
+}
+
+struct knPushOutofObs : public KernelBase {
+ knPushOutofObs(BasicParticleSystem &parts,
+ const FlagGrid &flags,
+ const Grid<Real> &phiObs,
+ const Real shift,
+ const Real thresh,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(parts.size()),
+ parts(parts),
+ flags(flags),
+ phiObs(phiObs),
+ shift(shift),
+ thresh(thresh),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ BasicParticleSystem &parts,
+ const FlagGrid &flags,
+ const Grid<Real> &phiObs,
+ const Real shift,
+ const Real thresh,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (!parts.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+ Vec3i p = toVec3i(parts.getPos(idx));
+
+ if (!flags.isInBounds(p))
+ return;
+ Real v = phiObs.getInterpolated(parts.getPos(idx));
+ if (v < thresh) {
+ Vec3 grad = getGradient(phiObs, p.x, p.y, p.z);
+ if (normalize(grad) < VECTOR_EPSILON)
+ return;
+ parts.setPos(idx, parts.getPos(idx) + grad * (thresh - v + shift));
+ }
+ }
+ inline BasicParticleSystem &getArg0()
+ {
+ return parts;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return phiObs;
+ }
+ typedef Grid<Real> type2;
+ inline const Real &getArg3()
+ {
+ return shift;
+ }
+ typedef Real type3;
+ inline const Real &getArg4()
+ {
+ return thresh;
+ }
+ typedef Real type4;
+ inline const ParticleDataImpl<int> *getArg5()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type5;
+ inline const int &getArg6()
+ {
+ return exclude;
+ }
+ typedef int type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPushOutofObs ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, parts, flags, phiObs, shift, thresh, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ BasicParticleSystem &parts;
+ const FlagGrid &flags;
+ const Grid<Real> &phiObs;
+ const Real shift;
+ const Real thresh;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+//! push particles out of obstacle levelset
+
+void pushOutofObs(BasicParticleSystem &parts,
+ const FlagGrid &flags,
+ const Grid<Real> &phiObs,
+ const Real shift = 0,
+ const Real thresh = 0,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ knPushOutofObs(parts, flags, phiObs, shift, thresh, ptype, exclude);
+}
+static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "pushOutofObs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ const Grid<Real> &phiObs = *_args.getPtr<Grid<Real>>("phiObs", 2, &_lock);
+ const Real shift = _args.getOpt<Real>("shift", 3, 0, &_lock);
+ const Real thresh = _args.getOpt<Real>("thresh", 4, 0, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 5, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 6, 0, &_lock);
+ _retval = getPyNone();
+ pushOutofObs(parts, flags, phiObs, shift, thresh, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "pushOutofObs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("pushOutofObs", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_pushOutofObs("", "pushOutofObs", _W_11);
+extern "C" {
+void PbRegister_pushOutofObs()
+{
+ KEEP_UNUSED(_RP_pushOutofObs);
+}
+}
+
+//******************************************************************************
+// grid interpolation functions
+
+template<class T> struct knSafeDivReal : public KernelBase {
+ knSafeDivReal(Grid<T> &me, const Grid<Real> &other, Real cutoff = VECTOR_EPSILON)
+ : KernelBase(&me, 0), me(me), other(other), cutoff(cutoff)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ Grid<T> &me,
+ const Grid<Real> &other,
+ Real cutoff = VECTOR_EPSILON) const
+ {
+ if (other[idx] < cutoff) {
+ me[idx] = 0.;
+ }
+ else {
+ T div(other[idx]);
+ me[idx] = safeDivide(me[idx], div);
+ }
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid<Real> type1;
+ inline Real &getArg2()
+ {
+ return cutoff;
+ }
+ typedef Real type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSafeDivReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other, cutoff);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const Grid<Real> &other;
+ Real cutoff;
+};
+
+// Set velocities on the grid from the particle system
+
+struct knMapLinearVec3ToMACGrid : public KernelBase {
+ knMapLinearVec3ToMACGrid(const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ Grid<Vec3> &tmp,
+ const ParticleDataImpl<Vec3> &pvel,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(p.size()),
+ p(p),
+ flags(flags),
+ vel(vel),
+ tmp(tmp),
+ pvel(pvel),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ Grid<Vec3> &tmp,
+ const ParticleDataImpl<Vec3> &pvel,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ {
+ unusedParameter(flags);
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+ vel.setInterpolated(p[idx].pos, pvel[idx], &tmp[0]);
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return vel;
+ }
+ typedef MACGrid type2;
+ inline Grid<Vec3> &getArg3()
+ {
+ return tmp;
+ }
+ typedef Grid<Vec3> type3;
+ inline const ParticleDataImpl<Vec3> &getArg4()
+ {
+ return pvel;
+ }
+ typedef ParticleDataImpl<Vec3> type4;
+ inline const ParticleDataImpl<int> *getArg5()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type5;
+ inline const int &getArg6()
+ {
+ return exclude;
+ }
+ typedef int type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMapLinearVec3ToMACGrid ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void run()
+ {
+ const IndexInt _sz = size;
+ for (IndexInt i = 0; i < _sz; i++)
+ op(i, p, flags, vel, tmp, pvel, ptype, exclude);
+ }
+ const BasicParticleSystem &p;
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ Grid<Vec3> &tmp;
+ const ParticleDataImpl<Vec3> &pvel;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+// optionally , this function can use an existing vec3 grid to store the weights
+// this is useful in combination with the simple extrapolation function
+
+void mapPartsToMAC(const FlagGrid &flags,
+ MACGrid &vel,
+ MACGrid &velOld,
+ const BasicParticleSystem &parts,
+ const ParticleDataImpl<Vec3> &partVel,
+ Grid<Vec3> *weight = NULL,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // interpol -> grid. tmpgrid for particle contribution weights
+ bool freeTmp = false;
+ if (!weight) {
+ weight = new Grid<Vec3>(flags.getParent());
+ freeTmp = true;
+ }
+ else {
+ weight->clear(); // make sure we start with a zero grid!
+ }
+ vel.clear();
+ knMapLinearVec3ToMACGrid(parts, flags, vel, *weight, partVel, ptype, exclude);
+
+ // stomp small values in weight to zero to prevent roundoff errors
+ weight->stomp(Vec3(VECTOR_EPSILON));
+ vel.safeDivide(*weight);
+
+ // store original state
+ velOld.copyFrom(vel);
+ if (freeTmp)
+ delete weight;
+}
+static PyObject *_W_12(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "mapPartsToMAC", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ MACGrid &velOld = *_args.getPtr<MACGrid>("velOld", 2, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 3, &_lock);
+ const ParticleDataImpl<Vec3> &partVel = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "partVel", 4, &_lock);
+ Grid<Vec3> *weight = _args.getPtrOpt<Grid<Vec3>>("weight", 5, NULL, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 6, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 7, 0, &_lock);
+ _retval = getPyNone();
+ mapPartsToMAC(flags, vel, velOld, parts, partVel, weight, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapPartsToMAC", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapPartsToMAC", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapPartsToMAC("", "mapPartsToMAC", _W_12);
+extern "C" {
+void PbRegister_mapPartsToMAC()
+{
+ KEEP_UNUSED(_RP_mapPartsToMAC);
+}
+}
+
+template<class T> struct knMapLinear : public KernelBase {
+ knMapLinear(const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const Grid<T> &target,
+ Grid<Real> &gtmp,
+ const ParticleDataImpl<T> &psource)
+ : KernelBase(p.size()), p(p), flags(flags), target(target), gtmp(gtmp), psource(psource)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const Grid<T> &target,
+ Grid<Real> &gtmp,
+ const ParticleDataImpl<T> &psource)
+ {
+ unusedParameter(flags);
+ if (!p.isActive(idx))
+ return;
+ target.setInterpolated(p[idx].pos, psource[idx], gtmp);
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const Grid<T> &getArg2()
+ {
+ return target;
+ }
+ typedef Grid<T> type2;
+ inline Grid<Real> &getArg3()
+ {
+ return gtmp;
+ }
+ typedef Grid<Real> type3;
+ inline const ParticleDataImpl<T> &getArg4()
+ {
+ return psource;
+ }
+ typedef ParticleDataImpl<T> type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMapLinear ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void run()
+ {
+ const IndexInt _sz = size;
+ for (IndexInt i = 0; i < _sz; i++)
+ op(i, p, flags, target, gtmp, psource);
+ }
+ const BasicParticleSystem &p;
+ const FlagGrid &flags;
+ const Grid<T> &target;
+ Grid<Real> &gtmp;
+ const ParticleDataImpl<T> &psource;
+};
+
+template<class T>
+void mapLinearRealHelper(const FlagGrid &flags,
+ Grid<T> &target,
+ const BasicParticleSystem &parts,
+ const ParticleDataImpl<T> &source)
+{
+ Grid<Real> tmp(flags.getParent());
+ target.clear();
+ knMapLinear<T>(parts, flags, target, tmp, source);
+ knSafeDivReal<T>(target, tmp);
+}
+
+void mapPartsToGrid(const FlagGrid &flags,
+ Grid<Real> &target,
+ const BasicParticleSystem &parts,
+ const ParticleDataImpl<Real> &source)
+{
+ mapLinearRealHelper<Real>(flags, target, parts, source);
+}
+static PyObject *_W_13(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "mapPartsToGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 1, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ const ParticleDataImpl<Real> &source = *_args.getPtr<ParticleDataImpl<Real>>(
+ "source", 3, &_lock);
+ _retval = getPyNone();
+ mapPartsToGrid(flags, target, parts, source);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapPartsToGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapPartsToGrid", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapPartsToGrid("", "mapPartsToGrid", _W_13);
+extern "C" {
+void PbRegister_mapPartsToGrid()
+{
+ KEEP_UNUSED(_RP_mapPartsToGrid);
+}
+}
+
+void mapPartsToGridVec3(const FlagGrid &flags,
+ Grid<Vec3> &target,
+ const BasicParticleSystem &parts,
+ const ParticleDataImpl<Vec3> &source)
+{
+ mapLinearRealHelper<Vec3>(flags, target, parts, source);
+}
+static PyObject *_W_14(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "mapPartsToGridVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ const ParticleDataImpl<Vec3> &source = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "source", 3, &_lock);
+ _retval = getPyNone();
+ mapPartsToGridVec3(flags, target, parts, source);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapPartsToGridVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapPartsToGridVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapPartsToGridVec3("", "mapPartsToGridVec3", _W_14);
+extern "C" {
+void PbRegister_mapPartsToGridVec3()
+{
+ KEEP_UNUSED(_RP_mapPartsToGridVec3);
+}
+}
+
+// integers need "max" mode, not yet implemented
+// PYTHON() void mapPartsToGridInt ( FlagGrid& flags, Grid<int >& target , BasicParticleSystem&
+// parts , ParticleDataImpl<int >& source ) { mapLinearRealHelper<int >(flags,target,parts,source);
+//}
+
+template<class T> struct knMapFromGrid : public KernelBase {
+ knMapFromGrid(const BasicParticleSystem &p, const Grid<T> &gsrc, ParticleDataImpl<T> &target)
+ : KernelBase(p.size()), p(p), gsrc(gsrc), target(target)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ const Grid<T> &gsrc,
+ ParticleDataImpl<T> &target) const
+ {
+ if (!p.isActive(idx))
+ return;
+ target[idx] = gsrc.getInterpolated(p[idx].pos);
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const Grid<T> &getArg1()
+ {
+ return gsrc;
+ }
+ typedef Grid<T> type1;
+ inline ParticleDataImpl<T> &getArg2()
+ {
+ return target;
+ }
+ typedef ParticleDataImpl<T> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMapFromGrid ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, gsrc, target);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystem &p;
+ const Grid<T> &gsrc;
+ ParticleDataImpl<T> &target;
+};
+void mapGridToParts(const Grid<Real> &source,
+ const BasicParticleSystem &parts,
+ ParticleDataImpl<Real> &target)
+{
+ knMapFromGrid<Real>(parts, source, target);
+}
+static PyObject *_W_15(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "mapGridToParts", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Real> &source = *_args.getPtr<Grid<Real>>("source", 0, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 1, &_lock);
+ ParticleDataImpl<Real> &target = *_args.getPtr<ParticleDataImpl<Real>>("target", 2, &_lock);
+ _retval = getPyNone();
+ mapGridToParts(source, parts, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapGridToParts", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapGridToParts", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapGridToParts("", "mapGridToParts", _W_15);
+extern "C" {
+void PbRegister_mapGridToParts()
+{
+ KEEP_UNUSED(_RP_mapGridToParts);
+}
+}
+
+void mapGridToPartsVec3(const Grid<Vec3> &source,
+ const BasicParticleSystem &parts,
+ ParticleDataImpl<Vec3> &target)
+{
+ knMapFromGrid<Vec3>(parts, source, target);
+}
+static PyObject *_W_16(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "mapGridToPartsVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Vec3> &source = *_args.getPtr<Grid<Vec3>>("source", 0, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 1, &_lock);
+ ParticleDataImpl<Vec3> &target = *_args.getPtr<ParticleDataImpl<Vec3>>("target", 2, &_lock);
+ _retval = getPyNone();
+ mapGridToPartsVec3(source, parts, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapGridToPartsVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapGridToPartsVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapGridToPartsVec3("", "mapGridToPartsVec3", _W_16);
+extern "C" {
+void PbRegister_mapGridToPartsVec3()
+{
+ KEEP_UNUSED(_RP_mapGridToPartsVec3);
+}
+}
+
+// Get velocities from grid
+
+struct knMapLinearMACGridToVec3_PIC : public KernelBase {
+ knMapLinearMACGridToVec3_PIC(const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ ParticleDataImpl<Vec3> &pvel,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(p.size()),
+ p(p),
+ flags(flags),
+ vel(vel),
+ pvel(pvel),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ ParticleDataImpl<Vec3> &pvel,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+ // pure PIC
+ pvel[idx] = vel.getInterpolated(p[idx].pos);
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return vel;
+ }
+ typedef MACGrid type2;
+ inline ParticleDataImpl<Vec3> &getArg3()
+ {
+ return pvel;
+ }
+ typedef ParticleDataImpl<Vec3> type3;
+ inline const ParticleDataImpl<int> *getArg4()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type4;
+ inline const int &getArg5()
+ {
+ return exclude;
+ }
+ typedef int type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMapLinearMACGridToVec3_PIC ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, flags, vel, pvel, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystem &p;
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ ParticleDataImpl<Vec3> &pvel;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+void mapMACToParts(const FlagGrid &flags,
+ const MACGrid &vel,
+ const BasicParticleSystem &parts,
+ ParticleDataImpl<Vec3> &partVel,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ knMapLinearMACGridToVec3_PIC(parts, flags, vel, partVel, ptype, exclude);
+}
+static PyObject *_W_17(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "mapMACToParts", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ ParticleDataImpl<Vec3> &partVel = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "partVel", 3, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 4, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 5, 0, &_lock);
+ _retval = getPyNone();
+ mapMACToParts(flags, vel, parts, partVel, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapMACToParts", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapMACToParts", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapMACToParts("", "mapMACToParts", _W_17);
+extern "C" {
+void PbRegister_mapMACToParts()
+{
+ KEEP_UNUSED(_RP_mapMACToParts);
+}
+}
+
+// with flip delta interpolation
+
+struct knMapLinearMACGridToVec3_FLIP : public KernelBase {
+ knMapLinearMACGridToVec3_FLIP(const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ const MACGrid &oldVel,
+ ParticleDataImpl<Vec3> &pvel,
+ const Real flipRatio,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(p.size()),
+ p(p),
+ flags(flags),
+ vel(vel),
+ oldVel(oldVel),
+ pvel(pvel),
+ flipRatio(flipRatio),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ const MACGrid &oldVel,
+ ParticleDataImpl<Vec3> &pvel,
+ const Real flipRatio,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+ Vec3 v = vel.getInterpolated(p[idx].pos);
+ Vec3 delta = v - oldVel.getInterpolated(p[idx].pos);
+ pvel[idx] = flipRatio * (pvel[idx] + delta) + (1.0 - flipRatio) * v;
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return vel;
+ }
+ typedef MACGrid type2;
+ inline const MACGrid &getArg3()
+ {
+ return oldVel;
+ }
+ typedef MACGrid type3;
+ inline ParticleDataImpl<Vec3> &getArg4()
+ {
+ return pvel;
+ }
+ typedef ParticleDataImpl<Vec3> type4;
+ inline const Real &getArg5()
+ {
+ return flipRatio;
+ }
+ typedef Real type5;
+ inline const ParticleDataImpl<int> *getArg6()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type6;
+ inline const int &getArg7()
+ {
+ return exclude;
+ }
+ typedef int type7;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMapLinearMACGridToVec3_FLIP ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, flags, vel, oldVel, pvel, flipRatio, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystem &p;
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ const MACGrid &oldVel;
+ ParticleDataImpl<Vec3> &pvel;
+ const Real flipRatio;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+void flipVelocityUpdate(const FlagGrid &flags,
+ const MACGrid &vel,
+ const MACGrid &velOld,
+ const BasicParticleSystem &parts,
+ ParticleDataImpl<Vec3> &partVel,
+ const Real flipRatio,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ knMapLinearMACGridToVec3_FLIP(parts, flags, vel, velOld, partVel, flipRatio, ptype, exclude);
+}
+static PyObject *_W_18(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "flipVelocityUpdate", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const MACGrid &velOld = *_args.getPtr<MACGrid>("velOld", 2, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 3, &_lock);
+ ParticleDataImpl<Vec3> &partVel = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "partVel", 4, &_lock);
+ const Real flipRatio = _args.get<Real>("flipRatio", 5, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 6, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 7, 0, &_lock);
+ _retval = getPyNone();
+ flipVelocityUpdate(flags, vel, velOld, parts, partVel, flipRatio, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipVelocityUpdate", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipVelocityUpdate", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipVelocityUpdate("", "flipVelocityUpdate", _W_18);
+extern "C" {
+void PbRegister_flipVelocityUpdate()
+{
+ KEEP_UNUSED(_RP_flipVelocityUpdate);
+}
+}
+
+//******************************************************************************
+// narrow band
+
+struct knCombineVels : public KernelBase {
+ knCombineVels(MACGrid &vel,
+ const Grid<Vec3> &w,
+ MACGrid &combineVel,
+ const LevelsetGrid *phi,
+ Real narrowBand,
+ Real thresh)
+ : KernelBase(&vel, 0),
+ vel(vel),
+ w(w),
+ combineVel(combineVel),
+ phi(phi),
+ narrowBand(narrowBand),
+ thresh(thresh)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ MACGrid &vel,
+ const Grid<Vec3> &w,
+ MACGrid &combineVel,
+ const LevelsetGrid *phi,
+ Real narrowBand,
+ Real thresh) const
+ {
+ int idx = vel.index(i, j, k);
+
+ for (int c = 0; c < 3; ++c) {
+ // Correct narrow-band FLIP
+ if (phi) {
+ Vec3 pos(i, j, k);
+ pos[(c + 1) % 3] += Real(0.5);
+ pos[(c + 2) % 3] += Real(0.5);
+ Real p = phi->getInterpolated(pos);
+ if (p < -narrowBand) {
+ vel[idx][c] = 0;
+ continue;
+ }
+ }
+
+ if (w[idx][c] > thresh) {
+ combineVel[idx][c] = vel[idx][c];
+ vel[idx][c] = -1;
+ }
+ else {
+ vel[idx][c] = 0;
+ }
+ }
+ }
+ inline MACGrid &getArg0()
+ {
+ return vel;
+ }
+ typedef MACGrid type0;
+ inline const Grid<Vec3> &getArg1()
+ {
+ return w;
+ }
+ typedef Grid<Vec3> type1;
+ inline MACGrid &getArg2()
+ {
+ return combineVel;
+ }
+ typedef MACGrid type2;
+ inline const LevelsetGrid *getArg3()
+ {
+ return phi;
+ }
+ typedef LevelsetGrid type3;
+ inline Real &getArg4()
+ {
+ return narrowBand;
+ }
+ typedef Real type4;
+ inline Real &getArg5()
+ {
+ return thresh;
+ }
+ typedef Real type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCombineVels ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, vel, w, combineVel, phi, narrowBand, thresh);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, vel, w, combineVel, phi, narrowBand, thresh);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ MACGrid &vel;
+ const Grid<Vec3> &w;
+ MACGrid &combineVel;
+ const LevelsetGrid *phi;
+ Real narrowBand;
+ Real thresh;
+};
+
+//! narrow band velocity combination
+
+void combineGridVel(MACGrid &vel,
+ const Grid<Vec3> &weight,
+ MACGrid &combineVel,
+ const LevelsetGrid *phi = NULL,
+ Real narrowBand = 0.0,
+ Real thresh = 0.0)
+{
+ knCombineVels(vel, weight, combineVel, phi, narrowBand, thresh);
+}
+static PyObject *_W_19(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "combineGridVel", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ const Grid<Vec3> &weight = *_args.getPtr<Grid<Vec3>>("weight", 1, &_lock);
+ MACGrid &combineVel = *_args.getPtr<MACGrid>("combineVel", 2, &_lock);
+ const LevelsetGrid *phi = _args.getPtrOpt<LevelsetGrid>("phi", 3, NULL, &_lock);
+ Real narrowBand = _args.getOpt<Real>("narrowBand", 4, 0.0, &_lock);
+ Real thresh = _args.getOpt<Real>("thresh", 5, 0.0, &_lock);
+ _retval = getPyNone();
+ combineGridVel(vel, weight, combineVel, phi, narrowBand, thresh);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "combineGridVel", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("combineGridVel", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_combineGridVel("", "combineGridVel", _W_19);
+extern "C" {
+void PbRegister_combineGridVel()
+{
+ KEEP_UNUSED(_RP_combineGridVel);
+}
+}
+
+//! surface tension helper
+void getLaplacian(Grid<Real> &laplacian, const Grid<Real> &grid)
+{
+ LaplaceOp(laplacian, grid);
+}
+static PyObject *_W_20(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getLaplacian", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &laplacian = *_args.getPtr<Grid<Real>>("laplacian", 0, &_lock);
+ const Grid<Real> &grid = *_args.getPtr<Grid<Real>>("grid", 1, &_lock);
+ _retval = getPyNone();
+ getLaplacian(laplacian, grid);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getLaplacian", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getLaplacian", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getLaplacian("", "getLaplacian", _W_20);
+extern "C" {
+void PbRegister_getLaplacian()
+{
+ KEEP_UNUSED(_RP_getLaplacian);
+}
+}
+
+void getCurvature(Grid<Real> &curv, const Grid<Real> &grid, const Real h = 1.0)
+{
+ CurvatureOp(curv, grid, h);
+}
+static PyObject *_W_21(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getCurvature", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &curv = *_args.getPtr<Grid<Real>>("curv", 0, &_lock);
+ const Grid<Real> &grid = *_args.getPtr<Grid<Real>>("grid", 1, &_lock);
+ const Real h = _args.getOpt<Real>("h", 2, 1.0, &_lock);
+ _retval = getPyNone();
+ getCurvature(curv, grid, h);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getCurvature", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getCurvature", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getCurvature("", "getCurvature", _W_21);
+extern "C" {
+void PbRegister_getCurvature()
+{
+ KEEP_UNUSED(_RP_getCurvature);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/fluidguiding.cpp b/extern/mantaflow/preprocessed/plugin/fluidguiding.cpp
new file mode 100644
index 00000000000..13383581123
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/fluidguiding.cpp
@@ -0,0 +1,802 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for pressure correction: solve_pressure, and ghost fluid helpers
+ *
+ ******************************************************************************/
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+#include "conjugategrad.h"
+#include "rcmatrix.h"
+
+using namespace std;
+namespace Manta {
+
+// only supports a single blur size for now, globals stored here
+bool gBlurPrecomputed = false;
+int gBlurKernelRadius = -1;
+Matrix gBlurKernel;
+
+// *****************************************************************************
+// Helper functions for fluid guiding
+
+//! creates a 1D (horizontal) Gaussian blur kernel of size n and standard deviation sigma
+Matrix get1DGaussianBlurKernel(const int n, const int sigma)
+{
+ Matrix x(n), y(n);
+ for (int j = 0; j < n; j++) {
+ x.add_to_element(0, j, -(n - 1) * 0.5);
+ y.add_to_element(0, j, j - (n - 1) * 0.5);
+ }
+ Matrix G(n);
+ Real sumG = 0;
+ for (int j = 0; j < n; j++) {
+ G.add_to_element(0,
+ j,
+ 1 / (2 * M_PI * sigma * sigma) *
+ exp(-(x(0, j) * x(0, j) + y(0, j) * y(0, j)) / (2 * sigma * sigma)));
+ sumG += G(0, j);
+ }
+ G = G * (1.0 / sumG);
+ return G;
+}
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the x-direction
+//! (out must be a grid of zeros)
+struct apply1DKernelDirX : public KernelBase {
+ apply1DKernelDirX(const MACGrid &in, MACGrid &out, const Matrix &kernel)
+ : KernelBase(&in, 0), in(in), out(out), kernel(kernel)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel) const
+ {
+ int nx = in.getSizeX();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, ii = i - kCentre; m < kn; m++, ind--, ii++) {
+ if (ii < 0)
+ continue;
+ else if (ii >= nx)
+ break;
+ else
+ out(i, j, k) += in(ii, j, k) * kernel(0, ind);
+ }
+ }
+ inline const MACGrid &getArg0()
+ {
+ return in;
+ }
+ typedef MACGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return out;
+ }
+ typedef MACGrid type1;
+ inline const Matrix &getArg2()
+ {
+ return kernel;
+ }
+ typedef Matrix type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel apply1DKernelDirX ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const MACGrid &in;
+ MACGrid &out;
+ const Matrix &kernel;
+};
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the y-direction
+//! (out must be a grid of zeros)
+struct apply1DKernelDirY : public KernelBase {
+ apply1DKernelDirY(const MACGrid &in, MACGrid &out, const Matrix &kernel)
+ : KernelBase(&in, 0), in(in), out(out), kernel(kernel)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel) const
+ {
+ int ny = in.getSizeY();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, jj = j - kCentre; m < kn; m++, ind--, jj++) {
+ if (jj < 0)
+ continue;
+ else if (jj >= ny)
+ break;
+ else
+ out(i, j, k) += in(i, jj, k) * kernel(0, ind);
+ }
+ }
+ inline const MACGrid &getArg0()
+ {
+ return in;
+ }
+ typedef MACGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return out;
+ }
+ typedef MACGrid type1;
+ inline const Matrix &getArg2()
+ {
+ return kernel;
+ }
+ typedef Matrix type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel apply1DKernelDirY ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const MACGrid &in;
+ MACGrid &out;
+ const Matrix &kernel;
+};
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the z-direction
+//! (out must be a grid of zeros)
+struct apply1DKernelDirZ : public KernelBase {
+ apply1DKernelDirZ(const MACGrid &in, MACGrid &out, const Matrix &kernel)
+ : KernelBase(&in, 0), in(in), out(out), kernel(kernel)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel) const
+ {
+ int nz = in.getSizeZ();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, kk = k - kCentre; m < kn; m++, ind--, kk++) {
+ if (kk < 0)
+ continue;
+ else if (kk >= nz)
+ break;
+ else
+ out(i, j, k) += in(i, j, kk) * kernel(0, ind);
+ }
+ }
+ inline const MACGrid &getArg0()
+ {
+ return in;
+ }
+ typedef MACGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return out;
+ }
+ typedef MACGrid type1;
+ inline const Matrix &getArg2()
+ {
+ return kernel;
+ }
+ typedef Matrix type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel apply1DKernelDirZ ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const MACGrid &in;
+ MACGrid &out;
+ const Matrix &kernel;
+};
+
+//! Apply separable Gaussian blur in 2D
+void applySeparableKernel2D(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel)
+{
+ // int nx = grid.getSizeX(), ny = grid.getSizeY();
+ // int kn = kernel.n;
+ // int kCentre = kn / 2;
+ FluidSolver *parent = grid.getParent();
+ MACGrid orig = MACGrid(parent);
+ orig.copyFrom(grid);
+ MACGrid gridX = MACGrid(parent);
+ apply1DKernelDirX(grid, gridX, kernel);
+ MACGrid gridXY = MACGrid(parent);
+ apply1DKernelDirY(gridX, gridXY, kernel);
+ grid.copyFrom(gridXY);
+ FOR_IJK(grid)
+ {
+ if ((i > 0 && flags.isObstacle(i - 1, j, k)) || (j > 0 && flags.isObstacle(i, j - 1, k)) ||
+ flags.isObstacle(i, j, k)) {
+ grid(i, j, k).x = orig(i, j, k).x;
+ grid(i, j, k).y = orig(i, j, k).y;
+ grid(i, j, k).z = orig(i, j, k).z;
+ }
+ }
+}
+
+//! Apply separable Gaussian blur in 3D
+void applySeparableKernel3D(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel)
+{
+ // int nx = grid.getSizeX(), ny = grid.getSizeY(), nz = grid.getSizeZ();
+ // int kn = kernel.n;
+ // int kCentre = kn / 2;
+ FluidSolver *parent = grid.getParent();
+ MACGrid orig = MACGrid(parent);
+ orig.copyFrom(grid);
+ MACGrid gridX = MACGrid(parent);
+ apply1DKernelDirX(grid, gridX, kernel);
+ MACGrid gridXY = MACGrid(parent);
+ apply1DKernelDirY(gridX, gridXY, kernel);
+ MACGrid gridXYZ = MACGrid(parent);
+ apply1DKernelDirZ(gridXY, gridXYZ, kernel);
+ grid.copyFrom(gridXYZ);
+ FOR_IJK(grid)
+ {
+ if ((i > 0 && flags.isObstacle(i - 1, j, k)) || (j > 0 && flags.isObstacle(i, j - 1, k)) ||
+ (k > 0 && flags.isObstacle(i, j, k - 1)) || flags.isObstacle(i, j, k)) {
+ grid(i, j, k).x = orig(i, j, k).x;
+ grid(i, j, k).y = orig(i, j, k).y;
+ grid(i, j, k).z = orig(i, j, k).z;
+ }
+ }
+}
+
+//! Apply separable Gaussian blur in 2D or 3D depending on input dimensions
+void applySeparableKernel(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel)
+{
+ if (!grid.is3D())
+ applySeparableKernel2D(grid, flags, kernel);
+ else
+ applySeparableKernel3D(grid, flags, kernel);
+}
+
+//! Compute r-norm for the stopping criterion
+Real getRNorm(const MACGrid &x, const MACGrid &z)
+{
+ MACGrid r = MACGrid(x.getParent());
+ r.copyFrom(x);
+ r.sub(z);
+ return r.getMaxAbs();
+}
+
+//! Compute s-norm for the stopping criterion
+Real getSNorm(const Real rho, const MACGrid &z, const MACGrid &z_prev)
+{
+ MACGrid s = MACGrid(z_prev.getParent());
+ s.copyFrom(z_prev);
+ s.sub(z);
+ s.multConst(rho);
+ return s.getMaxAbs();
+}
+
+//! Compute primal eps for the stopping criterion
+Real getEpsPri(const Real eps_abs, const Real eps_rel, const MACGrid &x, const MACGrid &z)
+{
+ Real max_norm = max(x.getMaxAbs(), z.getMaxAbs());
+ Real eps_pri = sqrt(x.is3D() ? 3.0 : 2.0) * eps_abs + eps_rel * max_norm;
+ return eps_pri;
+}
+
+//! Compute dual eps for the stopping criterion
+Real getEpsDual(const Real eps_abs, const Real eps_rel, const MACGrid &y)
+{
+ Real eps_dual = sqrt(y.is3D() ? 3.0 : 2.0) * eps_abs + eps_rel * y.getMaxAbs();
+ return eps_dual;
+}
+
+//! Create a spiral velocity field in 2D as a test scene (optionally in 3D)
+void getSpiralVelocity(const FlagGrid &flags,
+ MACGrid &vel,
+ Real strength = 1.0,
+ bool with3D = false)
+{
+ int nx = flags.getSizeX(), ny = flags.getSizeY(), nz = 1;
+ if (with3D)
+ nz = flags.getSizeZ();
+ Real midX = 0.5 * (Real)(nx - 1);
+ Real midY = 0.5 * (Real)(ny - 1);
+ Real midZ = 0.5 * (Real)(nz - 1);
+ for (int i = 0; i < nx; i++) {
+ for (int j = 0; j < ny; j++) {
+ for (int k = 0; k < nz; k++) {
+ int idx = flags.index(i, j, k);
+ Real diffX = midX - i;
+ Real diffY = midY - j;
+ Real hypotenuse = sqrt(diffX * diffX + diffY * diffY);
+ if (hypotenuse > 0) {
+ vel[idx].x = diffY / hypotenuse;
+ vel[idx].y = -diffX / hypotenuse;
+ }
+ }
+ }
+ }
+ vel.multConst(strength);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getSpiralVelocity", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ Real strength = _args.getOpt<Real>("strength", 2, 1.0, &_lock);
+ bool with3D = _args.getOpt<bool>("with3D", 3, false, &_lock);
+ _retval = getPyNone();
+ getSpiralVelocity(flags, vel, strength, with3D);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getSpiralVelocity", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getSpiralVelocity", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getSpiralVelocity("", "getSpiralVelocity", _W_0);
+extern "C" {
+void PbRegister_getSpiralVelocity()
+{
+ KEEP_UNUSED(_RP_getSpiralVelocity);
+}
+}
+
+//! Set the guiding weight W as a gradient in the y-direction
+void setGradientYWeight(
+ Grid<Real> &W, const int minY, const int maxY, const Real valAtMin, const Real valAtMax)
+{
+ FOR_IJK(W)
+ {
+ if (minY <= j && j <= maxY) {
+ Real val = valAtMin;
+ if (valAtMax != valAtMin) {
+ Real ratio = (Real)(j - minY) / (Real)(maxY - minY);
+ val = ratio * valAtMax + (1.0 - ratio) * valAtMin;
+ }
+ W(i, j, k) = val;
+ }
+ }
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setGradientYWeight", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &W = *_args.getPtr<Grid<Real>>("W", 0, &_lock);
+ const int minY = _args.get<int>("minY", 1, &_lock);
+ const int maxY = _args.get<int>("maxY", 2, &_lock);
+ const Real valAtMin = _args.get<Real>("valAtMin", 3, &_lock);
+ const Real valAtMax = _args.get<Real>("valAtMax", 4, &_lock);
+ _retval = getPyNone();
+ setGradientYWeight(W, minY, maxY, valAtMin, valAtMax);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setGradientYWeight", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setGradientYWeight", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setGradientYWeight("", "setGradientYWeight", _W_1);
+extern "C" {
+void PbRegister_setGradientYWeight()
+{
+ KEEP_UNUSED(_RP_setGradientYWeight);
+}
+}
+
+// *****************************************************************************
+// More helper functions for fluid guiding
+
+//! Apply Gaussian blur (either 2D or 3D) in a separable way
+void applySeparableGaussianBlur(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel1D)
+{
+ assertMsg(gBlurPrecomputed, "Error - blue kernel not precomputed");
+ applySeparableKernel(grid, flags, kernel1D);
+}
+
+//! Precomputation performed before the first PD iteration
+void ADMM_precompute_Separable(int blurRadius)
+{
+ if (gBlurPrecomputed) {
+ assertMsg(gBlurKernelRadius == blurRadius,
+ "More than a single blur radius not supported at the moment.");
+ return;
+ }
+ int kernelSize = 2 * blurRadius + 1;
+ gBlurKernel = get1DGaussianBlurKernel(kernelSize, kernelSize);
+ gBlurPrecomputed = true;
+ gBlurKernelRadius = blurRadius;
+}
+
+//! Apply approximate multiplication of inverse(M)
+void applyApproxInvM(MACGrid &v, const FlagGrid &flags, const MACGrid &invA)
+{
+ MACGrid v_new = MACGrid(v.getParent());
+ v_new.copyFrom(v);
+ v_new.mult(invA);
+ applySeparableGaussianBlur(v_new, flags, gBlurKernel);
+ applySeparableGaussianBlur(v_new, flags, gBlurKernel);
+ v_new.multConst(2.0);
+ v_new.mult(invA);
+ v.mult(invA);
+ v.sub(v_new);
+}
+
+//! Precompute Q, a reused quantity in the PD iterations
+//! Q = 2*G*G*(velT-velC)-sigma*velC
+void precomputeQ(MACGrid &Q,
+ const FlagGrid &flags,
+ const MACGrid &velT_region,
+ const MACGrid &velC,
+ const Matrix &gBlurKernel,
+ const Real sigma)
+{
+ Q.copyFrom(velT_region);
+ Q.sub(velC);
+ applySeparableGaussianBlur(Q, flags, gBlurKernel);
+ applySeparableGaussianBlur(Q, flags, gBlurKernel);
+ Q.multConst(2.0);
+ Q.addScaled(velC, -sigma);
+}
+
+//! Precompute inverse(A), a reused quantity in the PD iterations
+//! A = 2*S^2 + p*I, invA = elementwise 1/A
+void precomputeInvA(MACGrid &invA, const Grid<Real> &weight, const Real sigma)
+{
+ FOR_IJK(invA)
+ {
+ Real val = 2 * weight(i, j, k) * weight(i, j, k) + sigma;
+ if (val < 0.01)
+ val = 0.01;
+ Real invVal = 1.0 / val;
+ invA(i, j, k).x = invVal;
+ invA(i, j, k).y = invVal;
+ invA(i, j, k).z = invVal;
+ }
+}
+
+//! proximal operator of f , guiding
+void prox_f(MACGrid &v,
+ const FlagGrid &flags,
+ const MACGrid &Q,
+ const MACGrid &velC,
+ const Real sigma,
+ const MACGrid &invA)
+{
+ v.multConst(sigma);
+ v.add(Q);
+ applyApproxInvM(v, flags, invA);
+ v.add(velC);
+}
+
+// *****************************************************************************
+
+// re-uses main pressure solve from pressure.cpp
+void solvePressure(MACGrid &vel,
+ Grid<Real> &pressure,
+ const FlagGrid &flags,
+ Real cgAccuracy = 1e-3,
+ const Grid<Real> *phi = 0,
+ const Grid<Real> *perCellCorr = 0,
+ const MACGrid *fractions = 0,
+ const MACGrid *obvel = 0,
+ Real gfClamp = 1e-04,
+ Real cgMaxIterFac = 1.5,
+ bool precondition = true,
+ int preconditioner = 1,
+ bool enforceCompatibility = false,
+ bool useL2Norm = false,
+ bool zeroPressureFixing = false,
+ const Grid<Real> *curv = NULL,
+ const Real surfTens = 0.0,
+ Grid<Real> *retRhs = NULL);
+
+//! Main function for fluid guiding , includes "regular" pressure solve
+
+void PD_fluid_guiding(MACGrid &vel,
+ MACGrid &velT,
+ Grid<Real> &pressure,
+ FlagGrid &flags,
+ Grid<Real> &weight,
+ int blurRadius = 5,
+ Real theta = 1.0,
+ Real tau = 1.0,
+ Real sigma = 1.0,
+ Real epsRel = 1e-3,
+ Real epsAbs = 1e-3,
+ int maxIters = 200,
+ Grid<Real> *phi = 0,
+ Grid<Real> *perCellCorr = 0,
+ MACGrid *fractions = 0,
+ MACGrid *obvel = 0,
+ Real gfClamp = 1e-04,
+ Real cgMaxIterFac = 1.5,
+ Real cgAccuracy = 1e-3,
+ int preconditioner = 1,
+ bool zeroPressureFixing = false,
+ const Grid<Real> *curv = NULL,
+ const Real surfTens = 0.)
+{
+ FluidSolver *parent = vel.getParent();
+
+ // initialize dual/slack variables
+ MACGrid velC = MACGrid(parent);
+ velC.copyFrom(vel);
+ MACGrid x = MACGrid(parent);
+ MACGrid y = MACGrid(parent);
+ MACGrid z = MACGrid(parent);
+ MACGrid x0 = MACGrid(parent);
+ MACGrid z0 = MACGrid(parent);
+
+ // precomputation
+ ADMM_precompute_Separable(blurRadius);
+ MACGrid Q = MACGrid(parent);
+ precomputeQ(Q, flags, velT, velC, gBlurKernel, sigma);
+ MACGrid invA = MACGrid(parent);
+ precomputeInvA(invA, weight, sigma);
+
+ // loop
+ int iter = 0;
+ for (iter = 0; iter < maxIters; iter++) {
+ // x-update
+ x0.copyFrom(x);
+ x.multConst(1.0 / sigma);
+ x.add(y);
+ prox_f(x, flags, Q, velC, sigma, invA);
+ x.multConst(-sigma);
+ x.addScaled(y, sigma);
+ x.add(x0);
+
+ // z-update
+ z0.copyFrom(z);
+ z.addScaled(x, -tau);
+ Real cgAccuracyAdaptive = cgAccuracy;
+
+ solvePressure(z,
+ pressure,
+ flags,
+ cgAccuracyAdaptive,
+ phi,
+ perCellCorr,
+ fractions,
+ obvel,
+ gfClamp,
+ cgMaxIterFac,
+ true,
+ preconditioner,
+ false,
+ false,
+ zeroPressureFixing,
+ curv,
+ surfTens);
+
+ // y-update
+ y.copyFrom(z);
+ y.sub(z0);
+ y.multConst(theta);
+ y.add(z);
+
+ // stopping criterion
+ bool stop = (iter > 0 && getRNorm(z, z0) < getEpsDual(epsAbs, epsRel, z));
+
+ if (stop || (iter == maxIters - 1))
+ break;
+ }
+
+ // vel_new = z
+ vel.copyFrom(z);
+
+ debMsg("PD_fluid_guiding iterations:" << iter, 1);
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "PD_fluid_guiding", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ MACGrid &velT = *_args.getPtr<MACGrid>("velT", 1, &_lock);
+ Grid<Real> &pressure = *_args.getPtr<Grid<Real>>("pressure", 2, &_lock);
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 3, &_lock);
+ Grid<Real> &weight = *_args.getPtr<Grid<Real>>("weight", 4, &_lock);
+ int blurRadius = _args.getOpt<int>("blurRadius", 5, 5, &_lock);
+ Real theta = _args.getOpt<Real>("theta", 6, 1.0, &_lock);
+ Real tau = _args.getOpt<Real>("tau", 7, 1.0, &_lock);
+ Real sigma = _args.getOpt<Real>("sigma", 8, 1.0, &_lock);
+ Real epsRel = _args.getOpt<Real>("epsRel", 9, 1e-3, &_lock);
+ Real epsAbs = _args.getOpt<Real>("epsAbs", 10, 1e-3, &_lock);
+ int maxIters = _args.getOpt<int>("maxIters", 11, 200, &_lock);
+ Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 12, 0, &_lock);
+ Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>("perCellCorr", 13, 0, &_lock);
+ MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 14, 0, &_lock);
+ MACGrid *obvel = _args.getPtrOpt<MACGrid>("obvel", 15, 0, &_lock);
+ Real gfClamp = _args.getOpt<Real>("gfClamp", 16, 1e-04, &_lock);
+ Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 17, 1.5, &_lock);
+ Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 18, 1e-3, &_lock);
+ int preconditioner = _args.getOpt<int>("preconditioner", 19, 1, &_lock);
+ bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 20, false, &_lock);
+ const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 21, NULL, &_lock);
+ const Real surfTens = _args.getOpt<Real>("surfTens", 22, 0., &_lock);
+ _retval = getPyNone();
+ PD_fluid_guiding(vel,
+ velT,
+ pressure,
+ flags,
+ weight,
+ blurRadius,
+ theta,
+ tau,
+ sigma,
+ epsRel,
+ epsAbs,
+ maxIters,
+ phi,
+ perCellCorr,
+ fractions,
+ obvel,
+ gfClamp,
+ cgMaxIterFac,
+ cgAccuracy,
+ preconditioner,
+ zeroPressureFixing,
+ curv,
+ surfTens);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "PD_fluid_guiding", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("PD_fluid_guiding", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_PD_fluid_guiding("", "PD_fluid_guiding", _W_2);
+extern "C" {
+void PbRegister_PD_fluid_guiding()
+{
+ KEEP_UNUSED(_RP_PD_fluid_guiding);
+}
+}
+
+//! reset precomputation
+void releaseBlurPrecomp()
+{
+ gBlurPrecomputed = false;
+ gBlurKernelRadius = -1;
+ gBlurKernel = 0.f;
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "releaseBlurPrecomp", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ _retval = getPyNone();
+ releaseBlurPrecomp();
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "releaseBlurPrecomp", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("releaseBlurPrecomp", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_releaseBlurPrecomp("", "releaseBlurPrecomp", _W_3);
+extern "C" {
+void PbRegister_releaseBlurPrecomp()
+{
+ KEEP_UNUSED(_RP_releaseBlurPrecomp);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/initplugins.cpp b/extern/mantaflow/preprocessed/plugin/initplugins.cpp
new file mode 100644
index 00000000000..3e28c947424
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/initplugins.cpp
@@ -0,0 +1,2317 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Tools to setup fields and inflows
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include "noisefield.h"
+#include "simpleimage.h"
+#include "mesh.h"
+
+using namespace std;
+
+namespace Manta {
+
+//! Apply noise to grid
+
+struct KnApplyNoiseInfl : public KernelBase {
+ KnApplyNoiseInfl(const FlagGrid &flags,
+ Grid<Real> &density,
+ const WaveletNoiseField &noise,
+ const Grid<Real> &sdf,
+ Real scale,
+ Real sigma)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ density(density),
+ noise(noise),
+ sdf(sdf),
+ scale(scale),
+ sigma(sigma)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Real> &density,
+ const WaveletNoiseField &noise,
+ const Grid<Real> &sdf,
+ Real scale,
+ Real sigma) const
+ {
+ if (!flags.isFluid(i, j, k) || sdf(i, j, k) > sigma)
+ return;
+ Real factor = clamp(1.0 - 0.5 / sigma * (sdf(i, j, k) + sigma), 0.0, 1.0);
+
+ Real target = noise.evaluate(Vec3(i, j, k)) * scale * factor;
+ if (density(i, j, k) < target)
+ density(i, j, k) = target;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return density;
+ }
+ typedef Grid<Real> type1;
+ inline const WaveletNoiseField &getArg2()
+ {
+ return noise;
+ }
+ typedef WaveletNoiseField type2;
+ inline const Grid<Real> &getArg3()
+ {
+ return sdf;
+ }
+ typedef Grid<Real> type3;
+ inline Real &getArg4()
+ {
+ return scale;
+ }
+ typedef Real type4;
+ inline Real &getArg5()
+ {
+ return sigma;
+ }
+ typedef Real type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnApplyNoiseInfl ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, density, noise, sdf, scale, sigma);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, density, noise, sdf, scale, sigma);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &density;
+ const WaveletNoiseField &noise;
+ const Grid<Real> &sdf;
+ Real scale;
+ Real sigma;
+};
+
+//! Init noise-modulated density inside shape
+
+void densityInflow(const FlagGrid &flags,
+ Grid<Real> &density,
+ const WaveletNoiseField &noise,
+ Shape *shape,
+ Real scale = 1.0,
+ Real sigma = 0)
+{
+ Grid<Real> sdf = shape->computeLevelset();
+ KnApplyNoiseInfl(flags, density, noise, sdf, scale, sigma);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "densityInflow", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
+ const WaveletNoiseField &noise = *_args.getPtr<WaveletNoiseField>("noise", 2, &_lock);
+ Shape *shape = _args.getPtr<Shape>("shape", 3, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 4, 1.0, &_lock);
+ Real sigma = _args.getOpt<Real>("sigma", 5, 0, &_lock);
+ _retval = getPyNone();
+ densityInflow(flags, density, noise, shape, scale, sigma);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "densityInflow", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("densityInflow", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_densityInflow("", "densityInflow", _W_0);
+extern "C" {
+void PbRegister_densityInflow()
+{
+ KEEP_UNUSED(_RP_densityInflow);
+}
+}
+
+//! Apply noise to real grid based on an SDF
+struct KnAddNoise : public KernelBase {
+ KnAddNoise(const FlagGrid &flags,
+ Grid<Real> &density,
+ const WaveletNoiseField &noise,
+ const Grid<Real> *sdf,
+ Real scale)
+ : KernelBase(&flags, 0), flags(flags), density(density), noise(noise), sdf(sdf), scale(scale)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Real> &density,
+ const WaveletNoiseField &noise,
+ const Grid<Real> *sdf,
+ Real scale) const
+ {
+ if (!flags.isFluid(i, j, k) || (sdf && (*sdf)(i, j, k) > 0.))
+ return;
+ density(i, j, k) += noise.evaluate(Vec3(i, j, k)) * scale;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return density;
+ }
+ typedef Grid<Real> type1;
+ inline const WaveletNoiseField &getArg2()
+ {
+ return noise;
+ }
+ typedef WaveletNoiseField type2;
+ inline const Grid<Real> *getArg3()
+ {
+ return sdf;
+ }
+ typedef Grid<Real> type3;
+ inline Real &getArg4()
+ {
+ return scale;
+ }
+ typedef Real type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnAddNoise ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, density, noise, sdf, scale);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, density, noise, sdf, scale);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &density;
+ const WaveletNoiseField &noise;
+ const Grid<Real> *sdf;
+ Real scale;
+};
+void addNoise(const FlagGrid &flags,
+ Grid<Real> &density,
+ const WaveletNoiseField &noise,
+ const Grid<Real> *sdf = NULL,
+ Real scale = 1.0)
+{
+ KnAddNoise(flags, density, noise, sdf, scale);
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "addNoise", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
+ const WaveletNoiseField &noise = *_args.getPtr<WaveletNoiseField>("noise", 2, &_lock);
+ const Grid<Real> *sdf = _args.getPtrOpt<Grid<Real>>("sdf", 3, NULL, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 4, 1.0, &_lock);
+ _retval = getPyNone();
+ addNoise(flags, density, noise, sdf, scale);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "addNoise", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("addNoise", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_addNoise("", "addNoise", _W_1);
+extern "C" {
+void PbRegister_addNoise()
+{
+ KEEP_UNUSED(_RP_addNoise);
+}
+}
+
+//! sample noise field and set pdata with its values (for convenience, scale the noise values)
+
+template<class T> struct knSetPdataNoise : public KernelBase {
+ knSetPdataNoise(const BasicParticleSystem &parts,
+ ParticleDataImpl<T> &pdata,
+ const WaveletNoiseField &noise,
+ Real scale)
+ : KernelBase(parts.size()), parts(parts), pdata(pdata), noise(noise), scale(scale)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &parts,
+ ParticleDataImpl<T> &pdata,
+ const WaveletNoiseField &noise,
+ Real scale) const
+ {
+ pdata[idx] = noise.evaluate(parts.getPos(idx)) * scale;
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return parts;
+ }
+ typedef BasicParticleSystem type0;
+ inline ParticleDataImpl<T> &getArg1()
+ {
+ return pdata;
+ }
+ typedef ParticleDataImpl<T> type1;
+ inline const WaveletNoiseField &getArg2()
+ {
+ return noise;
+ }
+ typedef WaveletNoiseField type2;
+ inline Real &getArg3()
+ {
+ return scale;
+ }
+ typedef Real type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetPdataNoise ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, parts, pdata, noise, scale);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystem &parts;
+ ParticleDataImpl<T> &pdata;
+ const WaveletNoiseField &noise;
+ Real scale;
+};
+
+template<class T> struct knSetPdataNoiseVec : public KernelBase {
+ knSetPdataNoiseVec(const BasicParticleSystem &parts,
+ ParticleDataImpl<T> &pdata,
+ const WaveletNoiseField &noise,
+ Real scale)
+ : KernelBase(parts.size()), parts(parts), pdata(pdata), noise(noise), scale(scale)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &parts,
+ ParticleDataImpl<T> &pdata,
+ const WaveletNoiseField &noise,
+ Real scale) const
+ {
+ pdata[idx] = noise.evaluateVec(parts.getPos(idx)) * scale;
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return parts;
+ }
+ typedef BasicParticleSystem type0;
+ inline ParticleDataImpl<T> &getArg1()
+ {
+ return pdata;
+ }
+ typedef ParticleDataImpl<T> type1;
+ inline const WaveletNoiseField &getArg2()
+ {
+ return noise;
+ }
+ typedef WaveletNoiseField type2;
+ inline Real &getArg3()
+ {
+ return scale;
+ }
+ typedef Real type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetPdataNoiseVec ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, parts, pdata, noise, scale);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystem &parts;
+ ParticleDataImpl<T> &pdata;
+ const WaveletNoiseField &noise;
+ Real scale;
+};
+void setNoisePdata(const BasicParticleSystem &parts,
+ ParticleDataImpl<Real> &pd,
+ const WaveletNoiseField &noise,
+ Real scale = 1.)
+{
+ knSetPdataNoise<Real>(parts, pd, noise, scale);
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setNoisePdata", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ ParticleDataImpl<Real> &pd = *_args.getPtr<ParticleDataImpl<Real>>("pd", 1, &_lock);
+ const WaveletNoiseField &noise = *_args.getPtr<WaveletNoiseField>("noise", 2, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 3, 1., &_lock);
+ _retval = getPyNone();
+ setNoisePdata(parts, pd, noise, scale);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setNoisePdata", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setNoisePdata", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setNoisePdata("", "setNoisePdata", _W_2);
+extern "C" {
+void PbRegister_setNoisePdata()
+{
+ KEEP_UNUSED(_RP_setNoisePdata);
+}
+}
+
+void setNoisePdataVec3(const BasicParticleSystem &parts,
+ ParticleDataImpl<Vec3> &pd,
+ const WaveletNoiseField &noise,
+ Real scale = 1.)
+{
+ knSetPdataNoiseVec<Vec3>(parts, pd, noise, scale);
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setNoisePdataVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ ParticleDataImpl<Vec3> &pd = *_args.getPtr<ParticleDataImpl<Vec3>>("pd", 1, &_lock);
+ const WaveletNoiseField &noise = *_args.getPtr<WaveletNoiseField>("noise", 2, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 3, 1., &_lock);
+ _retval = getPyNone();
+ setNoisePdataVec3(parts, pd, noise, scale);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setNoisePdataVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setNoisePdataVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setNoisePdataVec3("", "setNoisePdataVec3", _W_3);
+extern "C" {
+void PbRegister_setNoisePdataVec3()
+{
+ KEEP_UNUSED(_RP_setNoisePdataVec3);
+}
+}
+
+void setNoisePdataInt(const BasicParticleSystem &parts,
+ ParticleDataImpl<int> &pd,
+ const WaveletNoiseField &noise,
+ Real scale = 1.)
+{
+ knSetPdataNoise<int>(parts, pd, noise, scale);
+}
+static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setNoisePdataInt", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ ParticleDataImpl<int> &pd = *_args.getPtr<ParticleDataImpl<int>>("pd", 1, &_lock);
+ const WaveletNoiseField &noise = *_args.getPtr<WaveletNoiseField>("noise", 2, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 3, 1., &_lock);
+ _retval = getPyNone();
+ setNoisePdataInt(parts, pd, noise, scale);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setNoisePdataInt", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setNoisePdataInt", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setNoisePdataInt("", "setNoisePdataInt", _W_4);
+extern "C" {
+void PbRegister_setNoisePdataInt()
+{
+ KEEP_UNUSED(_RP_setNoisePdataInt);
+}
+}
+
+//! SDF gradient from obstacle flags, for turbulence.py
+// FIXME, slow, without kernel...
+Grid<Vec3> obstacleGradient(const FlagGrid &flags)
+{
+ LevelsetGrid levelset(flags.getParent(), false);
+ Grid<Vec3> gradient(flags.getParent());
+
+ // rebuild obstacle levelset
+ FOR_IDX(levelset)
+ {
+ levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5;
+ }
+ levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved);
+
+ // build levelset gradient
+ GradientOp(gradient, levelset);
+
+ FOR_IDX(levelset)
+ {
+ Vec3 grad = gradient[idx];
+ Real s = normalize(grad);
+ if (s <= 0.1 || levelset[idx] >= 0)
+ grad = Vec3(0.);
+ gradient[idx] = grad * levelset[idx];
+ }
+
+ return gradient;
+}
+static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "obstacleGradient", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ _retval = toPy(obstacleGradient(flags));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "obstacleGradient", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("obstacleGradient", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_obstacleGradient("", "obstacleGradient", _W_5);
+extern "C" {
+void PbRegister_obstacleGradient()
+{
+ KEEP_UNUSED(_RP_obstacleGradient);
+}
+}
+
+//! SDF from obstacle flags, for turbulence.py
+LevelsetGrid obstacleLevelset(const FlagGrid &flags)
+{
+ LevelsetGrid levelset(flags.getParent(), false);
+
+ // rebuild obstacle levelset
+ FOR_IDX(levelset)
+ {
+ levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5;
+ }
+ levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved);
+
+ return levelset;
+}
+static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "obstacleLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ _retval = toPy(obstacleLevelset(flags));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "obstacleLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("obstacleLevelset", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_obstacleLevelset("", "obstacleLevelset", _W_6);
+extern "C" {
+void PbRegister_obstacleLevelset()
+{
+ KEEP_UNUSED(_RP_obstacleLevelset);
+}
+}
+
+//*****************************************************************************
+// blender init functions
+
+struct KnApplyEmission : public KernelBase {
+ KnApplyEmission(const FlagGrid &flags,
+ Grid<Real> &target,
+ const Grid<Real> &source,
+ const Grid<Real> *emissionTexture,
+ bool isAbsolute,
+ int type)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ target(target),
+ source(source),
+ emissionTexture(emissionTexture),
+ isAbsolute(isAbsolute),
+ type(type)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Real> &target,
+ const Grid<Real> &source,
+ const Grid<Real> *emissionTexture,
+ bool isAbsolute,
+ int type) const
+ {
+ // if type is given, only apply emission when celltype matches type from flaggrid
+ // and if emission texture is given, only apply emission when some emission is present at cell
+ // (important for emit from particles)
+ bool isInflow = (type & FlagGrid::TypeInflow && flags.isInflow(i, j, k));
+ bool isOutflow = (type & FlagGrid::TypeOutflow && flags.isOutflow(i, j, k));
+ if ((type && !isInflow && !isOutflow) && (emissionTexture && !(*emissionTexture)(i, j, k)))
+ return;
+
+ if (isAbsolute)
+ target(i, j, k) = source(i, j, k);
+ else
+ target(i, j, k) += source(i, j, k);
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return target;
+ }
+ typedef Grid<Real> type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return source;
+ }
+ typedef Grid<Real> type2;
+ inline const Grid<Real> *getArg3()
+ {
+ return emissionTexture;
+ }
+ typedef Grid<Real> type3;
+ inline bool &getArg4()
+ {
+ return isAbsolute;
+ }
+ typedef bool type4;
+ inline int &getArg5()
+ {
+ return type;
+ }
+ typedef int type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnApplyEmission ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, target, source, emissionTexture, isAbsolute, type);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, target, source, emissionTexture, isAbsolute, type);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &target;
+ const Grid<Real> &source;
+ const Grid<Real> *emissionTexture;
+ bool isAbsolute;
+ int type;
+};
+
+//! Add emission values
+// isAbsolute: whether to add emission values to existing, or replace
+void applyEmission(FlagGrid &flags,
+ Grid<Real> &target,
+ Grid<Real> &source,
+ Grid<Real> *emissionTexture = NULL,
+ bool isAbsolute = true,
+ int type = 0)
+{
+ KnApplyEmission(flags, target, source, emissionTexture, isAbsolute, type);
+}
+static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "applyEmission", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 1, &_lock);
+ Grid<Real> &source = *_args.getPtr<Grid<Real>>("source", 2, &_lock);
+ Grid<Real> *emissionTexture = _args.getPtrOpt<Grid<Real>>(
+ "emissionTexture", 3, NULL, &_lock);
+ bool isAbsolute = _args.getOpt<bool>("isAbsolute", 4, true, &_lock);
+ int type = _args.getOpt<int>("type", 5, 0, &_lock);
+ _retval = getPyNone();
+ applyEmission(flags, target, source, emissionTexture, isAbsolute, type);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "applyEmission", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("applyEmission", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_applyEmission("", "applyEmission", _W_7);
+extern "C" {
+void PbRegister_applyEmission()
+{
+ KEEP_UNUSED(_RP_applyEmission);
+}
+}
+
+// blender init functions for meshes
+
+struct KnApplyDensity : public KernelBase {
+ KnApplyDensity(
+ const FlagGrid &flags, Grid<Real> &density, const Grid<Real> &sdf, Real value, Real sigma)
+ : KernelBase(&flags, 0), flags(flags), density(density), sdf(sdf), value(value), sigma(sigma)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Real> &density,
+ const Grid<Real> &sdf,
+ Real value,
+ Real sigma) const
+ {
+ if (!flags.isFluid(i, j, k) || sdf(i, j, k) > sigma)
+ return;
+ density(i, j, k) = value;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return density;
+ }
+ typedef Grid<Real> type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return sdf;
+ }
+ typedef Grid<Real> type2;
+ inline Real &getArg3()
+ {
+ return value;
+ }
+ typedef Real type3;
+ inline Real &getArg4()
+ {
+ return sigma;
+ }
+ typedef Real type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnApplyDensity ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, density, sdf, value, sigma);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, density, sdf, value, sigma);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &density;
+ const Grid<Real> &sdf;
+ Real value;
+ Real sigma;
+};
+//! Init noise-modulated density inside mesh
+
+void densityInflowMeshNoise(const FlagGrid &flags,
+ Grid<Real> &density,
+ const WaveletNoiseField &noise,
+ Mesh *mesh,
+ Real scale = 1.0,
+ Real sigma = 0)
+{
+ LevelsetGrid sdf(density.getParent(), false);
+ mesh->computeLevelset(sdf, 1.);
+ KnApplyNoiseInfl(flags, density, noise, sdf, scale, sigma);
+}
+static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "densityInflowMeshNoise", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
+ const WaveletNoiseField &noise = *_args.getPtr<WaveletNoiseField>("noise", 2, &_lock);
+ Mesh *mesh = _args.getPtr<Mesh>("mesh", 3, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 4, 1.0, &_lock);
+ Real sigma = _args.getOpt<Real>("sigma", 5, 0, &_lock);
+ _retval = getPyNone();
+ densityInflowMeshNoise(flags, density, noise, mesh, scale, sigma);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "densityInflowMeshNoise", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("densityInflowMeshNoise", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_densityInflowMeshNoise("", "densityInflowMeshNoise", _W_8);
+extern "C" {
+void PbRegister_densityInflowMeshNoise()
+{
+ KEEP_UNUSED(_RP_densityInflowMeshNoise);
+}
+}
+
+//! Init constant density inside mesh
+
+void densityInflowMesh(const FlagGrid &flags,
+ Grid<Real> &density,
+ Mesh *mesh,
+ Real value = 1.,
+ Real cutoff = 7,
+ Real sigma = 0)
+{
+ LevelsetGrid sdf(density.getParent(), false);
+ mesh->computeLevelset(sdf, 2., cutoff);
+ KnApplyDensity(flags, density, sdf, value, sigma);
+}
+static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "densityInflowMesh", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
+ Mesh *mesh = _args.getPtr<Mesh>("mesh", 2, &_lock);
+ Real value = _args.getOpt<Real>("value", 3, 1., &_lock);
+ Real cutoff = _args.getOpt<Real>("cutoff", 4, 7, &_lock);
+ Real sigma = _args.getOpt<Real>("sigma", 5, 0, &_lock);
+ _retval = getPyNone();
+ densityInflowMesh(flags, density, mesh, value, cutoff, sigma);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "densityInflowMesh", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("densityInflowMesh", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_densityInflowMesh("", "densityInflowMesh", _W_9);
+extern "C" {
+void PbRegister_densityInflowMesh()
+{
+ KEEP_UNUSED(_RP_densityInflowMesh);
+}
+}
+
+//*****************************************************************************
+
+//! check for symmetry , optionally enfore by copying
+
+void checkSymmetry(
+ Grid<Real> &a, Grid<Real> *err = NULL, bool symmetrize = false, int axis = 0, int bound = 0)
+{
+ const int c = axis;
+ const int s = a.getSize()[c];
+ FOR_IJK(a)
+ {
+ Vec3i idx(i, j, k), mdx(i, j, k);
+ mdx[c] = s - 1 - idx[c];
+ if (bound > 0 && ((!a.isInBounds(idx, bound)) || (!a.isInBounds(mdx, bound))))
+ continue;
+
+ if (err)
+ (*err)(idx) = fabs((double)(a(idx) - a(mdx)));
+ if (symmetrize && (idx[c] < s / 2)) {
+ a(idx) = a(mdx);
+ }
+ }
+}
+static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "checkSymmetry", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &a = *_args.getPtr<Grid<Real>>("a", 0, &_lock);
+ Grid<Real> *err = _args.getPtrOpt<Grid<Real>>("err", 1, NULL, &_lock);
+ bool symmetrize = _args.getOpt<bool>("symmetrize", 2, false, &_lock);
+ int axis = _args.getOpt<int>("axis", 3, 0, &_lock);
+ int bound = _args.getOpt<int>("bound", 4, 0, &_lock);
+ _retval = getPyNone();
+ checkSymmetry(a, err, symmetrize, axis, bound);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "checkSymmetry", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("checkSymmetry", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_checkSymmetry("", "checkSymmetry", _W_10);
+extern "C" {
+void PbRegister_checkSymmetry()
+{
+ KEEP_UNUSED(_RP_checkSymmetry);
+}
+}
+
+//! check for symmetry , mac grid version
+
+void checkSymmetryVec3(Grid<Vec3> &a,
+ Grid<Real> *err = NULL,
+ bool symmetrize = false,
+ int axis = 0,
+ int bound = 0,
+ int disable = 0)
+{
+ if (err)
+ err->setConst(0.);
+
+ // each dimension is measured separately for flexibility (could be combined)
+ const int c = axis;
+ const int o1 = (c + 1) % 3;
+ const int o2 = (c + 2) % 3;
+
+ // x
+ if (!(disable & 1)) {
+ const int s = a.getSize()[c] + 1;
+ FOR_IJK(a)
+ {
+ Vec3i idx(i, j, k), mdx(i, j, k);
+ mdx[c] = s - 1 - idx[c];
+ if (mdx[c] >= a.getSize()[c])
+ continue;
+ if (bound > 0 && ((!a.isInBounds(idx, bound)) || (!a.isInBounds(mdx, bound))))
+ continue;
+
+ // special case: center "line" of values , should be zero!
+ if (mdx[c] == idx[c]) {
+ if (err)
+ (*err)(idx) += fabs((double)(a(idx)[c]));
+ if (symmetrize)
+ a(idx)[c] = 0.;
+ continue;
+ }
+
+ // note - the a(mdx) component needs to be inverted here!
+ if (err)
+ (*err)(idx) += fabs((double)(a(idx)[c] - (a(mdx)[c] * -1.)));
+ if (symmetrize && (idx[c] < s / 2)) {
+ a(idx)[c] = a(mdx)[c] * -1.;
+ }
+ }
+ }
+
+ // y
+ if (!(disable & 2)) {
+ const int s = a.getSize()[c];
+ FOR_IJK(a)
+ {
+ Vec3i idx(i, j, k), mdx(i, j, k);
+ mdx[c] = s - 1 - idx[c];
+ if (bound > 0 && ((!a.isInBounds(idx, bound)) || (!a.isInBounds(mdx, bound))))
+ continue;
+
+ if (err)
+ (*err)(idx) += fabs((double)(a(idx)[o1] - a(mdx)[o1]));
+ if (symmetrize && (idx[c] < s / 2)) {
+ a(idx)[o1] = a(mdx)[o1];
+ }
+ }
+ }
+
+ // z
+ if (!(disable & 4)) {
+ const int s = a.getSize()[c];
+ FOR_IJK(a)
+ {
+ Vec3i idx(i, j, k), mdx(i, j, k);
+ mdx[c] = s - 1 - idx[c];
+ if (bound > 0 && ((!a.isInBounds(idx, bound)) || (!a.isInBounds(mdx, bound))))
+ continue;
+
+ if (err)
+ (*err)(idx) += fabs((double)(a(idx)[o2] - a(mdx)[o2]));
+ if (symmetrize && (idx[c] < s / 2)) {
+ a(idx)[o2] = a(mdx)[o2];
+ }
+ }
+ }
+}
+static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "checkSymmetryVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &a = *_args.getPtr<Grid<Vec3>>("a", 0, &_lock);
+ Grid<Real> *err = _args.getPtrOpt<Grid<Real>>("err", 1, NULL, &_lock);
+ bool symmetrize = _args.getOpt<bool>("symmetrize", 2, false, &_lock);
+ int axis = _args.getOpt<int>("axis", 3, 0, &_lock);
+ int bound = _args.getOpt<int>("bound", 4, 0, &_lock);
+ int disable = _args.getOpt<int>("disable", 5, 0, &_lock);
+ _retval = getPyNone();
+ checkSymmetryVec3(a, err, symmetrize, axis, bound, disable);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "checkSymmetryVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("checkSymmetryVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_checkSymmetryVec3("", "checkSymmetryVec3", _W_11);
+extern "C" {
+void PbRegister_checkSymmetryVec3()
+{
+ KEEP_UNUSED(_RP_checkSymmetryVec3);
+}
+}
+
+// from simpleimage.cpp
+void projectImg(SimpleImage &img, const Grid<Real> &val, int shadeMode = 0, Real scale = 1.);
+
+//! output shaded (all 3 axes at once for 3D)
+//! shading modes: 0 smoke, 1 surfaces
+
+void projectPpmFull(const Grid<Real> &val, string name, int shadeMode = 0, Real scale = 1.)
+{
+ SimpleImage img;
+ projectImg(img, val, shadeMode, scale);
+ img.writePpm(name);
+}
+static PyObject *_W_12(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "projectPpmFull", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Real> &val = *_args.getPtr<Grid<Real>>("val", 0, &_lock);
+ string name = _args.get<string>("name", 1, &_lock);
+ int shadeMode = _args.getOpt<int>("shadeMode", 2, 0, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 3, 1., &_lock);
+ _retval = getPyNone();
+ projectPpmFull(val, name, shadeMode, scale);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "projectPpmFull", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("projectPpmFull", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_projectPpmFull("", "projectPpmFull", _W_12);
+extern "C" {
+void PbRegister_projectPpmFull()
+{
+ KEEP_UNUSED(_RP_projectPpmFull);
+}
+}
+
+// helper functions for pdata operator tests
+
+//! init some test particles at the origin
+
+void addTestParts(BasicParticleSystem &parts, int num)
+{
+ for (int i = 0; i < num; ++i)
+ parts.addBuffered(Vec3(0, 0, 0));
+
+ parts.doCompress();
+ parts.insertBufferedParticles();
+}
+static PyObject *_W_13(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "addTestParts", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ int num = _args.get<int>("num", 1, &_lock);
+ _retval = getPyNone();
+ addTestParts(parts, num);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "addTestParts", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("addTestParts", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_addTestParts("", "addTestParts", _W_13);
+extern "C" {
+void PbRegister_addTestParts()
+{
+ KEEP_UNUSED(_RP_addTestParts);
+}
+}
+
+//! calculate the difference between two pdata fields (note - slow!, not parallelized)
+
+Real pdataMaxDiff(const ParticleDataBase *a, const ParticleDataBase *b)
+{
+ double maxVal = 0.;
+ // debMsg(" PD "<< a->getType()<<" as"<<a->getSizeSlow()<<" bs"<<b->getSizeSlow() , 1);
+ assertMsg(a->getType() == b->getType(), "pdataMaxDiff problem - different pdata types!");
+ assertMsg(a->getSizeSlow() == b->getSizeSlow(), "pdataMaxDiff problem - different pdata sizes!");
+
+ if (a->getType() & ParticleDataBase::TypeReal) {
+ const ParticleDataImpl<Real> &av = *dynamic_cast<const ParticleDataImpl<Real> *>(a);
+ const ParticleDataImpl<Real> &bv = *dynamic_cast<const ParticleDataImpl<Real> *>(b);
+ FOR_PARTS(av)
+ {
+ maxVal = std::max(maxVal, (double)fabs(av[idx] - bv[idx]));
+ }
+ }
+ else if (a->getType() & ParticleDataBase::TypeInt) {
+ const ParticleDataImpl<int> &av = *dynamic_cast<const ParticleDataImpl<int> *>(a);
+ const ParticleDataImpl<int> &bv = *dynamic_cast<const ParticleDataImpl<int> *>(b);
+ FOR_PARTS(av)
+ {
+ maxVal = std::max(maxVal, (double)fabs((double)av[idx] - bv[idx]));
+ }
+ }
+ else if (a->getType() & ParticleDataBase::TypeVec3) {
+ const ParticleDataImpl<Vec3> &av = *dynamic_cast<const ParticleDataImpl<Vec3> *>(a);
+ const ParticleDataImpl<Vec3> &bv = *dynamic_cast<const ParticleDataImpl<Vec3> *>(b);
+ FOR_PARTS(av)
+ {
+ double d = 0.;
+ for (int c = 0; c < 3; ++c) {
+ d += fabs((double)av[idx][c] - (double)bv[idx][c]);
+ }
+ maxVal = std::max(maxVal, d);
+ }
+ }
+ else {
+ errMsg("pdataMaxDiff: Grid Type is not supported (only Real, Vec3, int)");
+ }
+
+ return maxVal;
+}
+static PyObject *_W_14(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "pdataMaxDiff", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const ParticleDataBase *a = _args.getPtr<ParticleDataBase>("a", 0, &_lock);
+ const ParticleDataBase *b = _args.getPtr<ParticleDataBase>("b", 1, &_lock);
+ _retval = toPy(pdataMaxDiff(a, b));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "pdataMaxDiff", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("pdataMaxDiff", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_pdataMaxDiff("", "pdataMaxDiff", _W_14);
+extern "C" {
+void PbRegister_pdataMaxDiff()
+{
+ KEEP_UNUSED(_RP_pdataMaxDiff);
+}
+}
+
+//! calculate center of mass given density grid, for re-centering
+
+Vec3 calcCenterOfMass(const Grid<Real> &density)
+{
+ Vec3 p(0.0f);
+ Real w = 0.0f;
+ FOR_IJK(density)
+ {
+ p += density(i, j, k) * Vec3(i + 0.5f, j + 0.5f, k + 0.5f);
+ w += density(i, j, k);
+ }
+ if (w > 1e-6f)
+ p /= w;
+ return p;
+}
+static PyObject *_W_15(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "calcCenterOfMass", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 0, &_lock);
+ _retval = toPy(calcCenterOfMass(density));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "calcCenterOfMass", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("calcCenterOfMass", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_calcCenterOfMass("", "calcCenterOfMass", _W_15);
+extern "C" {
+void PbRegister_calcCenterOfMass()
+{
+ KEEP_UNUSED(_RP_calcCenterOfMass);
+}
+}
+
+//*****************************************************************************
+// helper functions for volume fractions (which are needed for second order obstacle boundaries)
+
+inline static Real calcFraction(Real phi1, Real phi2, Real fracThreshold)
+{
+ if (phi1 > 0. && phi2 > 0.)
+ return 1.;
+ if (phi1 < 0. && phi2 < 0.)
+ return 0.;
+
+ // make sure phi1 < phi2
+ if (phi2 < phi1) {
+ Real t = phi1;
+ phi1 = phi2;
+ phi2 = t;
+ }
+ Real denom = phi1 - phi2;
+ if (denom > -1e-04)
+ return 0.5;
+
+ Real frac = 1. - phi1 / denom;
+ if (frac < fracThreshold)
+ frac = 0.; // stomp small values , dont mark as fluid
+ return std::min(Real(1), frac);
+}
+
+struct KnUpdateFractions : public KernelBase {
+ KnUpdateFractions(const FlagGrid &flags,
+ const Grid<Real> &phiObs,
+ MACGrid &fractions,
+ const int &boundaryWidth,
+ const Real fracThreshold)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ phiObs(phiObs),
+ fractions(fractions),
+ boundaryWidth(boundaryWidth),
+ fracThreshold(fracThreshold)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ const Grid<Real> &phiObs,
+ MACGrid &fractions,
+ const int &boundaryWidth,
+ const Real fracThreshold) const
+ {
+
+ // walls at domain bounds and inner objects
+ fractions(i, j, k).x = calcFraction(phiObs(i, j, k), phiObs(i - 1, j, k), fracThreshold);
+ fractions(i, j, k).y = calcFraction(phiObs(i, j, k), phiObs(i, j - 1, k), fracThreshold);
+ if (phiObs.is3D()) {
+ fractions(i, j, k).z = calcFraction(phiObs(i, j, k), phiObs(i, j, k - 1), fracThreshold);
+ }
+
+ // remaining BCs at the domain boundaries
+ const int w = boundaryWidth;
+ // only set if not in obstacle
+ if (phiObs(i, j, k) < 0.)
+ return;
+
+ // x-direction boundaries
+ if (i <= w + 1) { // min x
+ if ((flags.isInflow(i - 1, j, k)) || (flags.isOutflow(i - 1, j, k)) ||
+ (flags.isOpen(i - 1, j, k))) {
+ fractions(i, j, k).x = fractions(i, j, k).y = 1.;
+ if (flags.is3D())
+ fractions(i, j, k).z = 1.;
+ }
+ }
+ if (i >= flags.getSizeX() - w - 2) { // max x
+ if ((flags.isInflow(i + 1, j, k)) || (flags.isOutflow(i + 1, j, k)) ||
+ (flags.isOpen(i + 1, j, k))) {
+ fractions(i + 1, j, k).x = fractions(i + 1, j, k).y = 1.;
+ if (flags.is3D())
+ fractions(i + 1, j, k).z = 1.;
+ }
+ }
+ // y-direction boundaries
+ if (j <= w + 1) { // min y
+ if ((flags.isInflow(i, j - 1, k)) || (flags.isOutflow(i, j - 1, k)) ||
+ (flags.isOpen(i, j - 1, k))) {
+ fractions(i, j, k).x = fractions(i, j, k).y = 1.;
+ if (flags.is3D())
+ fractions(i, j, k).z = 1.;
+ }
+ }
+ if (j >= flags.getSizeY() - w - 2) { // max y
+ if ((flags.isInflow(i, j + 1, k)) || (flags.isOutflow(i, j + 1, k)) ||
+ (flags.isOpen(i, j + 1, k))) {
+ fractions(i, j + 1, k).x = fractions(i, j + 1, k).y = 1.;
+ if (flags.is3D())
+ fractions(i, j + 1, k).z = 1.;
+ }
+ }
+ // z-direction boundaries
+ if (flags.is3D()) {
+ if (k <= w + 1) { // min z
+ if ((flags.isInflow(i, j, k - 1)) || (flags.isOutflow(i, j, k - 1)) ||
+ (flags.isOpen(i, j, k - 1))) {
+ fractions(i, j, k).x = fractions(i, j, k).y = 1.;
+ if (flags.is3D())
+ fractions(i, j, k).z = 1.;
+ }
+ }
+ if (j >= flags.getSizeZ() - w - 2) { // max z
+ if ((flags.isInflow(i, j, k + 1)) || (flags.isOutflow(i, j, k + 1)) ||
+ (flags.isOpen(i, j, k + 1))) {
+ fractions(i, j, k + 1).x = fractions(i, j, k + 1).y = 1.;
+ if (flags.is3D())
+ fractions(i, j, k + 1).z = 1.;
+ }
+ }
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return phiObs;
+ }
+ typedef Grid<Real> type1;
+ inline MACGrid &getArg2()
+ {
+ return fractions;
+ }
+ typedef MACGrid type2;
+ inline const int &getArg3()
+ {
+ return boundaryWidth;
+ }
+ typedef int type3;
+ inline const Real &getArg4()
+ {
+ return fracThreshold;
+ }
+ typedef Real type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnUpdateFractions ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, phiObs, fractions, boundaryWidth, fracThreshold);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, phiObs, fractions, boundaryWidth, fracThreshold);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ const Grid<Real> &phiObs;
+ MACGrid &fractions;
+ const int &boundaryWidth;
+ const Real fracThreshold;
+};
+
+//! update fill fraction values
+void updateFractions(const FlagGrid &flags,
+ const Grid<Real> &phiObs,
+ MACGrid &fractions,
+ const int &boundaryWidth = 0,
+ const Real fracThreshold = 0.01)
+{
+ fractions.setConst(Vec3(0.));
+ KnUpdateFractions(flags, phiObs, fractions, boundaryWidth, fracThreshold);
+}
+static PyObject *_W_16(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "updateFractions", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const Grid<Real> &phiObs = *_args.getPtr<Grid<Real>>("phiObs", 1, &_lock);
+ MACGrid &fractions = *_args.getPtr<MACGrid>("fractions", 2, &_lock);
+ const int &boundaryWidth = _args.getOpt<int>("boundaryWidth", 3, 0, &_lock);
+ const Real fracThreshold = _args.getOpt<Real>("fracThreshold", 4, 0.01, &_lock);
+ _retval = getPyNone();
+ updateFractions(flags, phiObs, fractions, boundaryWidth, fracThreshold);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "updateFractions", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("updateFractions", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_updateFractions("", "updateFractions", _W_16);
+extern "C" {
+void PbRegister_updateFractions()
+{
+ KEEP_UNUSED(_RP_updateFractions);
+}
+}
+
+struct KnUpdateFlagsObs : public KernelBase {
+ KnUpdateFlagsObs(FlagGrid &flags,
+ const MACGrid *fractions,
+ const Grid<Real> &phiObs,
+ const Grid<Real> *phiOut,
+ const Grid<Real> *phiIn)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ fractions(fractions),
+ phiObs(phiObs),
+ phiOut(phiOut),
+ phiIn(phiIn)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ FlagGrid &flags,
+ const MACGrid *fractions,
+ const Grid<Real> &phiObs,
+ const Grid<Real> *phiOut,
+ const Grid<Real> *phiIn) const
+ {
+
+ bool isObs = false;
+ if (fractions) {
+ Real f = 0.;
+ f += fractions->get(i, j, k).x;
+ f += fractions->get(i + 1, j, k).x;
+ f += fractions->get(i, j, k).y;
+ f += fractions->get(i, j + 1, k).y;
+ if (flags.is3D()) {
+ f += fractions->get(i, j, k).z;
+ f += fractions->get(i, j, k + 1).z;
+ }
+ if (f == 0.)
+ isObs = true;
+ }
+ else {
+ if (phiObs(i, j, k) < 0.)
+ isObs = true;
+ }
+
+ bool isOutflow = false;
+ bool isInflow = false;
+ if (phiOut && (*phiOut)(i, j, k) < 0.)
+ isOutflow = true;
+ if (phiIn && (*phiIn)(i, j, k) < 0.)
+ isInflow = true;
+
+ if (isObs)
+ flags(i, j, k) = FlagGrid::TypeObstacle;
+ else if (isInflow)
+ flags(i, j, k) = (FlagGrid::TypeFluid | FlagGrid::TypeInflow);
+ else if (isOutflow)
+ flags(i, j, k) = (FlagGrid::TypeEmpty | FlagGrid::TypeOutflow);
+ else
+ flags(i, j, k) = FlagGrid::TypeEmpty;
+ }
+ inline FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid *getArg1()
+ {
+ return fractions;
+ }
+ typedef MACGrid type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return phiObs;
+ }
+ typedef Grid<Real> type2;
+ inline const Grid<Real> *getArg3()
+ {
+ return phiOut;
+ }
+ typedef Grid<Real> type3;
+ inline const Grid<Real> *getArg4()
+ {
+ return phiIn;
+ }
+ typedef Grid<Real> type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnUpdateFlagsObs ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fractions, phiObs, phiOut, phiIn);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fractions, phiObs, phiOut, phiIn);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ FlagGrid &flags;
+ const MACGrid *fractions;
+ const Grid<Real> &phiObs;
+ const Grid<Real> *phiOut;
+ const Grid<Real> *phiIn;
+};
+
+//! update obstacle and outflow flags from levelsets
+//! optionally uses fill fractions for obstacle
+void setObstacleFlags(FlagGrid &flags,
+ const Grid<Real> &phiObs,
+ const MACGrid *fractions = NULL,
+ const Grid<Real> *phiOut = NULL,
+ const Grid<Real> *phiIn = NULL)
+{
+ KnUpdateFlagsObs(flags, fractions, phiObs, phiOut, phiIn);
+}
+static PyObject *_W_17(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setObstacleFlags", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const Grid<Real> &phiObs = *_args.getPtr<Grid<Real>>("phiObs", 1, &_lock);
+ const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 2, NULL, &_lock);
+ const Grid<Real> *phiOut = _args.getPtrOpt<Grid<Real>>("phiOut", 3, NULL, &_lock);
+ const Grid<Real> *phiIn = _args.getPtrOpt<Grid<Real>>("phiIn", 4, NULL, &_lock);
+ _retval = getPyNone();
+ setObstacleFlags(flags, phiObs, fractions, phiOut, phiIn);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setObstacleFlags", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setObstacleFlags", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setObstacleFlags("", "setObstacleFlags", _W_17);
+extern "C" {
+void PbRegister_setObstacleFlags()
+{
+ KEEP_UNUSED(_RP_setObstacleFlags);
+}
+}
+
+//! small helper for test case test_1040_secOrderBnd.py
+struct kninitVortexVelocity : public KernelBase {
+ kninitVortexVelocity(const Grid<Real> &phiObs,
+ MACGrid &vel,
+ const Vec3 &center,
+ const Real &radius)
+ : KernelBase(&phiObs, 0), phiObs(phiObs), vel(vel), center(center), radius(radius)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const Grid<Real> &phiObs,
+ MACGrid &vel,
+ const Vec3 &center,
+ const Real &radius) const
+ {
+
+ if (phiObs(i, j, k) >= -1.) {
+
+ Real dx = i - center.x;
+ if (dx >= 0)
+ dx -= .5;
+ else
+ dx += .5;
+ Real dy = j - center.y;
+ Real r = std::sqrt(dx * dx + dy * dy);
+ Real alpha = atan2(dy, dx);
+
+ vel(i, j, k).x = -std::sin(alpha) * (r / radius);
+
+ dx = i - center.x;
+ dy = j - center.y;
+ if (dy >= 0)
+ dy -= .5;
+ else
+ dy += .5;
+ r = std::sqrt(dx * dx + dy * dy);
+ alpha = atan2(dy, dx);
+
+ vel(i, j, k).y = std::cos(alpha) * (r / radius);
+ }
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return phiObs;
+ }
+ typedef Grid<Real> type0;
+ inline MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline const Vec3 &getArg2()
+ {
+ return center;
+ }
+ typedef Vec3 type2;
+ inline const Real &getArg3()
+ {
+ return radius;
+ }
+ typedef Real type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel kninitVortexVelocity ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, phiObs, vel, center, radius);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, phiObs, vel, center, radius);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const Grid<Real> &phiObs;
+ MACGrid &vel;
+ const Vec3 &center;
+ const Real &radius;
+};
+
+void initVortexVelocity(const Grid<Real> &phiObs,
+ MACGrid &vel,
+ const Vec3 &center,
+ const Real &radius)
+{
+ kninitVortexVelocity(phiObs, vel, center, radius);
+}
+static PyObject *_W_18(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "initVortexVelocity", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Real> &phiObs = *_args.getPtr<Grid<Real>>("phiObs", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const Vec3 &center = _args.get<Vec3>("center", 2, &_lock);
+ const Real &radius = _args.get<Real>("radius", 3, &_lock);
+ _retval = getPyNone();
+ initVortexVelocity(phiObs, vel, center, radius);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "initVortexVelocity", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("initVortexVelocity", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_initVortexVelocity("", "initVortexVelocity", _W_18);
+extern "C" {
+void PbRegister_initVortexVelocity()
+{
+ KEEP_UNUSED(_RP_initVortexVelocity);
+}
+}
+
+//*****************************************************************************
+// helper functions for blurring
+
+//! class for Gaussian Blur
+struct GaussianKernelCreator {
+ public:
+ float mSigma;
+ int mDim;
+ float *mMat1D;
+
+ GaussianKernelCreator() : mSigma(0.0f), mDim(0), mMat1D(NULL)
+ {
+ }
+ GaussianKernelCreator(float sigma, int dim = 0) : mSigma(0.0f), mDim(0), mMat1D(NULL)
+ {
+ setGaussianSigma(sigma, dim);
+ }
+
+ Real getWeiAtDis(float disx, float disy)
+ {
+ float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma);
+ float v = m * exp(-(1.0 * disx * disx + 1.0 * disy * disy) / (2.0 * mSigma * mSigma));
+ return v;
+ }
+
+ Real getWeiAtDis(float disx, float disy, float disz)
+ {
+ float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma);
+ float v = m * exp(-(1.0 * disx * disx + 1.0 * disy * disy + 1.0 * disz * disz) /
+ (2.0 * mSigma * mSigma));
+ return v;
+ }
+
+ void setGaussianSigma(float sigma, int dim = 0)
+ {
+ mSigma = sigma;
+ if (dim < 3)
+ mDim = (int)(2.0 * 3.0 * sigma + 1.0f);
+ else
+ mDim = dim;
+ if (mDim < 3)
+ mDim = 3;
+
+ if (mDim % 2 == 0)
+ ++mDim; // make dim odd
+
+ float s2 = mSigma * mSigma;
+ int c = mDim / 2;
+ float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma);
+
+ // create 1D matrix
+ if (mMat1D)
+ delete[] mMat1D;
+ mMat1D = new float[mDim];
+ for (int i = 0; i < (mDim + 1) / 2; i++) {
+ float v = m * exp(-(1.0 * i * i) / (2.0 * s2));
+ mMat1D[c + i] = v;
+ mMat1D[c - i] = v;
+ }
+ }
+
+ ~GaussianKernelCreator()
+ {
+ if (mMat1D)
+ delete[] mMat1D;
+ }
+
+ float get1DKernelValue(int off)
+ {
+ assertMsg(off >= 0 && off < mDim, "off exceeded boundary in Gaussian Kernel 1D!");
+ return mMat1D[off];
+ }
+};
+
+template<class T>
+T convolveGrid(Grid<T> &originGrid, GaussianKernelCreator &gkSigma, Vec3 pos, int cdir)
+{
+ // pos should be the centre pos, e.g., 1.5, 4.5, 0.5 for grid pos 1,4,0
+ Vec3 step(1.0, 0.0, 0.0);
+ if (cdir == 1) // todo, z
+ step = Vec3(0.0, 1.0, 0.0);
+ else if (cdir == 2)
+ step = Vec3(0.0, 0.0, 1.0);
+ T pxResult(0);
+ for (int i = 0; i < gkSigma.mDim; ++i) {
+ Vec3i curpos = toVec3i(pos - step * (i - gkSigma.mDim / 2));
+ if (originGrid.isInBounds(curpos))
+ pxResult += gkSigma.get1DKernelValue(i) * originGrid.get(curpos);
+ else { // TODO , improve...
+ Vec3i curfitpos = curpos;
+ if (curfitpos.x < 0)
+ curfitpos.x = 0;
+ else if (curfitpos.x >= originGrid.getSizeX())
+ curfitpos.x = originGrid.getSizeX() - 1;
+ if (curfitpos.y < 0)
+ curfitpos.y = 0;
+ else if (curfitpos.y >= originGrid.getSizeY())
+ curfitpos.y = originGrid.getSizeY() - 1;
+ if (curfitpos.z < 0)
+ curfitpos.z = 0;
+ else if (curfitpos.z >= originGrid.getSizeZ())
+ curfitpos.z = originGrid.getSizeZ() - 1;
+ pxResult += gkSigma.get1DKernelValue(i) * originGrid.get(curfitpos);
+ }
+ }
+ return pxResult;
+}
+
+template<class T> struct knBlurGrid : public KernelBase {
+ knBlurGrid(Grid<T> &originGrid, Grid<T> &targetGrid, GaussianKernelCreator &gkSigma, int cdir)
+ : KernelBase(&originGrid, 0),
+ originGrid(originGrid),
+ targetGrid(targetGrid),
+ gkSigma(gkSigma),
+ cdir(cdir)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<T> &originGrid,
+ Grid<T> &targetGrid,
+ GaussianKernelCreator &gkSigma,
+ int cdir) const
+ {
+ targetGrid(i, j, k) = convolveGrid<T>(originGrid, gkSigma, Vec3(i, j, k), cdir);
+ }
+ inline Grid<T> &getArg0()
+ {
+ return originGrid;
+ }
+ typedef Grid<T> type0;
+ inline Grid<T> &getArg1()
+ {
+ return targetGrid;
+ }
+ typedef Grid<T> type1;
+ inline GaussianKernelCreator &getArg2()
+ {
+ return gkSigma;
+ }
+ typedef GaussianKernelCreator type2;
+ inline int &getArg3()
+ {
+ return cdir;
+ }
+ typedef int type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knBlurGrid ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, originGrid, targetGrid, gkSigma, cdir);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, originGrid, targetGrid, gkSigma, cdir);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<T> &originGrid;
+ Grid<T> &targetGrid;
+ GaussianKernelCreator &gkSigma;
+ int cdir;
+};
+
+template<class T> int blurGrid(Grid<T> &originGrid, Grid<T> &targetGrid, float sigma)
+{
+ GaussianKernelCreator tmGK(sigma);
+ Grid<T> tmpGrid(originGrid);
+ knBlurGrid<T>(originGrid, tmpGrid, tmGK, 0); // blur x
+ knBlurGrid<T>(tmpGrid, targetGrid, tmGK, 1); // blur y
+ if (targetGrid.is3D()) {
+ tmpGrid.copyFrom(targetGrid);
+ knBlurGrid<T>(tmpGrid, targetGrid, tmGK, 2);
+ }
+ return tmGK.mDim;
+}
+
+struct KnBlurMACGridGauss : public KernelBase {
+ KnBlurMACGridGauss(MACGrid &originGrid,
+ MACGrid &target,
+ GaussianKernelCreator &gkSigma,
+ int cdir)
+ : KernelBase(&originGrid, 0),
+ originGrid(originGrid),
+ target(target),
+ gkSigma(gkSigma),
+ cdir(cdir)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ MACGrid &originGrid,
+ MACGrid &target,
+ GaussianKernelCreator &gkSigma,
+ int cdir) const
+ {
+ Vec3 pos(i, j, k);
+ Vec3 step(1.0, 0.0, 0.0);
+ if (cdir == 1)
+ step = Vec3(0.0, 1.0, 0.0);
+ else if (cdir == 2)
+ step = Vec3(0.0, 0.0, 1.0);
+
+ Vec3 pxResult(0.0f);
+ for (int di = 0; di < gkSigma.mDim; ++di) {
+ Vec3i curpos = toVec3i(pos - step * (di - gkSigma.mDim / 2));
+ if (!originGrid.isInBounds(curpos)) {
+ if (curpos.x < 0)
+ curpos.x = 0;
+ else if (curpos.x >= originGrid.getSizeX())
+ curpos.x = originGrid.getSizeX() - 1;
+ if (curpos.y < 0)
+ curpos.y = 0;
+ else if (curpos.y >= originGrid.getSizeY())
+ curpos.y = originGrid.getSizeY() - 1;
+ if (curpos.z < 0)
+ curpos.z = 0;
+ else if (curpos.z >= originGrid.getSizeZ())
+ curpos.z = originGrid.getSizeZ() - 1;
+ }
+ pxResult += gkSigma.get1DKernelValue(di) * originGrid.get(curpos);
+ }
+ target(i, j, k) = pxResult;
+ }
+ inline MACGrid &getArg0()
+ {
+ return originGrid;
+ }
+ typedef MACGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return target;
+ }
+ typedef MACGrid type1;
+ inline GaussianKernelCreator &getArg2()
+ {
+ return gkSigma;
+ }
+ typedef GaussianKernelCreator type2;
+ inline int &getArg3()
+ {
+ return cdir;
+ }
+ typedef int type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnBlurMACGridGauss ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, originGrid, target, gkSigma, cdir);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, originGrid, target, gkSigma, cdir);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ MACGrid &originGrid;
+ MACGrid &target;
+ GaussianKernelCreator &gkSigma;
+ int cdir;
+};
+
+int blurMacGrid(MACGrid &oG, MACGrid &tG, float si)
+{
+ GaussianKernelCreator tmGK(si);
+ MACGrid tmpGrid(oG);
+ KnBlurMACGridGauss(oG, tmpGrid, tmGK, 0); // blur x
+ KnBlurMACGridGauss(tmpGrid, tG, tmGK, 1); // blur y
+ if (tG.is3D()) {
+ tmpGrid.copyFrom(tG);
+ KnBlurMACGridGauss(tmpGrid, tG, tmGK, 2);
+ }
+ return tmGK.mDim;
+}
+static PyObject *_W_19(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "blurMacGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &oG = *_args.getPtr<MACGrid>("oG", 0, &_lock);
+ MACGrid &tG = *_args.getPtr<MACGrid>("tG", 1, &_lock);
+ float si = _args.get<float>("si", 2, &_lock);
+ _retval = toPy(blurMacGrid(oG, tG, si));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "blurMacGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("blurMacGrid", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_blurMacGrid("", "blurMacGrid", _W_19);
+extern "C" {
+void PbRegister_blurMacGrid()
+{
+ KEEP_UNUSED(_RP_blurMacGrid);
+}
+}
+
+int blurRealGrid(Grid<Real> &oG, Grid<Real> &tG, float si)
+{
+ return blurGrid<Real>(oG, tG, si);
+}
+static PyObject *_W_20(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "blurRealGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &oG = *_args.getPtr<Grid<Real>>("oG", 0, &_lock);
+ Grid<Real> &tG = *_args.getPtr<Grid<Real>>("tG", 1, &_lock);
+ float si = _args.get<float>("si", 2, &_lock);
+ _retval = toPy(blurRealGrid(oG, tG, si));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "blurRealGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("blurRealGrid", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_blurRealGrid("", "blurRealGrid", _W_20);
+extern "C" {
+void PbRegister_blurRealGrid()
+{
+ KEEP_UNUSED(_RP_blurRealGrid);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/kepsilon.cpp b/extern/mantaflow/preprocessed/plugin/kepsilon.cpp
new file mode 100644
index 00000000000..306db9e20cc
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/kepsilon.cpp
@@ -0,0 +1,578 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Turbulence modeling plugins
+ *
+ ******************************************************************************/
+
+#include "grid.h"
+#include "commonkernels.h"
+#include "vortexsheet.h"
+#include "conjugategrad.h"
+
+using namespace std;
+
+namespace Manta {
+
+// k-epsilon model constants
+const Real keCmu = 0.09;
+const Real keC1 = 1.44;
+const Real keC2 = 1.92;
+const Real keS1 = 1.0;
+const Real keS2 = 1.3;
+
+// k-epsilon limiters
+const Real keU0 = 1.0;
+const Real keImin = 2e-3;
+const Real keImax = 1.0;
+const Real keNuMin = 1e-3;
+const Real keNuMax = 5.0;
+
+//! clamp k and epsilon to limits
+
+struct KnTurbulenceClamp : public KernelBase {
+ KnTurbulenceClamp(
+ Grid<Real> &kgrid, Grid<Real> &egrid, Real minK, Real maxK, Real minNu, Real maxNu)
+ : KernelBase(&kgrid, 0),
+ kgrid(kgrid),
+ egrid(egrid),
+ minK(minK),
+ maxK(maxK),
+ minNu(minNu),
+ maxNu(maxNu)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ Grid<Real> &kgrid,
+ Grid<Real> &egrid,
+ Real minK,
+ Real maxK,
+ Real minNu,
+ Real maxNu) const
+ {
+ Real eps = egrid[idx];
+ Real ke = clamp(kgrid[idx], minK, maxK);
+ Real nu = keCmu * square(ke) / eps;
+ if (nu > maxNu)
+ eps = keCmu * square(ke) / maxNu;
+ if (nu < minNu)
+ eps = keCmu * square(ke) / minNu;
+
+ kgrid[idx] = ke;
+ egrid[idx] = eps;
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return kgrid;
+ }
+ typedef Grid<Real> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return egrid;
+ }
+ typedef Grid<Real> type1;
+ inline Real &getArg2()
+ {
+ return minK;
+ }
+ typedef Real type2;
+ inline Real &getArg3()
+ {
+ return maxK;
+ }
+ typedef Real type3;
+ inline Real &getArg4()
+ {
+ return minNu;
+ }
+ typedef Real type4;
+ inline Real &getArg5()
+ {
+ return maxNu;
+ }
+ typedef Real type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnTurbulenceClamp ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, kgrid, egrid, minK, maxK, minNu, maxNu);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Real> &kgrid;
+ Grid<Real> &egrid;
+ Real minK;
+ Real maxK;
+ Real minNu;
+ Real maxNu;
+};
+
+//! Compute k-epsilon production term P = 2*nu_T*sum_ij(Sij^2) and the turbulent viscosity
+//! nu_T=C_mu*k^2/eps
+
+struct KnComputeProduction : public KernelBase {
+ KnComputeProduction(const MACGrid &vel,
+ const Grid<Vec3> &velCenter,
+ const Grid<Real> &ke,
+ const Grid<Real> &eps,
+ Grid<Real> &prod,
+ Grid<Real> &nuT,
+ Grid<Real> *strain,
+ Real pscale = 1.0f)
+ : KernelBase(&vel, 1),
+ vel(vel),
+ velCenter(velCenter),
+ ke(ke),
+ eps(eps),
+ prod(prod),
+ nuT(nuT),
+ strain(strain),
+ pscale(pscale)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const MACGrid &vel,
+ const Grid<Vec3> &velCenter,
+ const Grid<Real> &ke,
+ const Grid<Real> &eps,
+ Grid<Real> &prod,
+ Grid<Real> &nuT,
+ Grid<Real> *strain,
+ Real pscale = 1.0f) const
+ {
+ Real curEps = eps(i, j, k);
+ if (curEps > 0) {
+ // turbulent viscosity: nu_T = C_mu * k^2/eps
+ Real curNu = keCmu * square(ke(i, j, k)) / curEps;
+
+ // compute Sij = 1/2 * (dU_i/dx_j + dU_j/dx_i)
+ Vec3 diag = Vec3(vel(i + 1, j, k).x, vel(i, j + 1, k).y, vel(i, j, k + 1).z) - vel(i, j, k);
+ Vec3 ux = 0.5 * (velCenter(i + 1, j, k) - velCenter(i - 1, j, k));
+ Vec3 uy = 0.5 * (velCenter(i, j + 1, k) - velCenter(i, j - 1, k));
+ Vec3 uz = 0.5 * (velCenter(i, j, k + 1) - velCenter(i, j, k - 1));
+ Real S12 = 0.5 * (ux.y + uy.x);
+ Real S13 = 0.5 * (ux.z + uz.x);
+ Real S23 = 0.5 * (uy.z + uz.y);
+ Real S2 = square(diag.x) + square(diag.y) + square(diag.z) + 2.0 * square(S12) +
+ 2.0 * square(S13) + 2.0 * square(S23);
+
+ // P = 2*nu_T*sum_ij(Sij^2)
+ prod(i, j, k) = 2.0 * curNu * S2 * pscale;
+ nuT(i, j, k) = curNu;
+ if (strain)
+ (*strain)(i, j, k) = sqrt(S2);
+ }
+ else {
+ prod(i, j, k) = 0;
+ nuT(i, j, k) = 0;
+ if (strain)
+ (*strain)(i, j, k) = 0;
+ }
+ }
+ inline const MACGrid &getArg0()
+ {
+ return vel;
+ }
+ typedef MACGrid type0;
+ inline const Grid<Vec3> &getArg1()
+ {
+ return velCenter;
+ }
+ typedef Grid<Vec3> type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return ke;
+ }
+ typedef Grid<Real> type2;
+ inline const Grid<Real> &getArg3()
+ {
+ return eps;
+ }
+ typedef Grid<Real> type3;
+ inline Grid<Real> &getArg4()
+ {
+ return prod;
+ }
+ typedef Grid<Real> type4;
+ inline Grid<Real> &getArg5()
+ {
+ return nuT;
+ }
+ typedef Grid<Real> type5;
+ inline Grid<Real> *getArg6()
+ {
+ return strain;
+ }
+ typedef Grid<Real> type6;
+ inline Real &getArg7()
+ {
+ return pscale;
+ }
+ typedef Real type7;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnComputeProduction ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, velCenter, ke, eps, prod, nuT, strain, pscale);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, velCenter, ke, eps, prod, nuT, strain, pscale);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const MACGrid &vel;
+ const Grid<Vec3> &velCenter;
+ const Grid<Real> &ke;
+ const Grid<Real> &eps;
+ Grid<Real> &prod;
+ Grid<Real> &nuT;
+ Grid<Real> *strain;
+ Real pscale;
+};
+
+//! Compute k-epsilon production term P = 2*nu_T*sum_ij(Sij^2) and the turbulent viscosity
+//! nu_T=C_mu*k^2/eps
+
+void KEpsilonComputeProduction(const MACGrid &vel,
+ Grid<Real> &k,
+ Grid<Real> &eps,
+ Grid<Real> &prod,
+ Grid<Real> &nuT,
+ Grid<Real> *strain = 0,
+ Real pscale = 1.0f)
+{
+ // get centered velocity grid
+ Grid<Vec3> vcenter(k.getParent());
+ GetCentered(vcenter, vel);
+ FillInBoundary(vcenter, 1);
+
+ // compute limits
+ const Real minK = 1.5 * square(keU0) * square(keImin);
+ const Real maxK = 1.5 * square(keU0) * square(keImax);
+ KnTurbulenceClamp(k, eps, minK, maxK, keNuMin, keNuMax);
+
+ KnComputeProduction(vel, vcenter, k, eps, prod, nuT, strain, pscale);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "KEpsilonComputeProduction", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ Grid<Real> &k = *_args.getPtr<Grid<Real>>("k", 1, &_lock);
+ Grid<Real> &eps = *_args.getPtr<Grid<Real>>("eps", 2, &_lock);
+ Grid<Real> &prod = *_args.getPtr<Grid<Real>>("prod", 3, &_lock);
+ Grid<Real> &nuT = *_args.getPtr<Grid<Real>>("nuT", 4, &_lock);
+ Grid<Real> *strain = _args.getPtrOpt<Grid<Real>>("strain", 5, 0, &_lock);
+ Real pscale = _args.getOpt<Real>("pscale", 6, 1.0f, &_lock);
+ _retval = getPyNone();
+ KEpsilonComputeProduction(vel, k, eps, prod, nuT, strain, pscale);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "KEpsilonComputeProduction", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("KEpsilonComputeProduction", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_KEpsilonComputeProduction("", "KEpsilonComputeProduction", _W_0);
+extern "C" {
+void PbRegister_KEpsilonComputeProduction()
+{
+ KEEP_UNUSED(_RP_KEpsilonComputeProduction);
+}
+}
+
+//! Integrate source terms of k-epsilon equation
+
+struct KnAddTurbulenceSource : public KernelBase {
+ KnAddTurbulenceSource(Grid<Real> &kgrid, Grid<Real> &egrid, const Grid<Real> &pgrid, Real dt)
+ : KernelBase(&kgrid, 0), kgrid(kgrid), egrid(egrid), pgrid(pgrid), dt(dt)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ IndexInt idx, Grid<Real> &kgrid, Grid<Real> &egrid, const Grid<Real> &pgrid, Real dt) const
+ {
+ Real eps = egrid[idx], prod = pgrid[idx], ke = kgrid[idx];
+ if (ke <= 0)
+ ke = 1e-3; // pre-clamp to avoid nan
+
+ Real newK = ke + dt * (prod - eps);
+ Real newEps = eps + dt * (prod * keC1 - eps * keC2) * (eps / ke);
+ if (newEps <= 0)
+ newEps = 1e-4; // pre-clamp to avoid nan
+
+ kgrid[idx] = newK;
+ egrid[idx] = newEps;
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return kgrid;
+ }
+ typedef Grid<Real> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return egrid;
+ }
+ typedef Grid<Real> type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return pgrid;
+ }
+ typedef Grid<Real> type2;
+ inline Real &getArg3()
+ {
+ return dt;
+ }
+ typedef Real type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnAddTurbulenceSource ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, kgrid, egrid, pgrid, dt);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Real> &kgrid;
+ Grid<Real> &egrid;
+ const Grid<Real> &pgrid;
+ Real dt;
+};
+
+//! Integrate source terms of k-epsilon equation
+void KEpsilonSources(Grid<Real> &k, Grid<Real> &eps, Grid<Real> &prod)
+{
+ Real dt = k.getParent()->getDt();
+
+ KnAddTurbulenceSource(k, eps, prod, dt);
+
+ // compute limits
+ const Real minK = 1.5 * square(keU0) * square(keImin);
+ const Real maxK = 1.5 * square(keU0) * square(keImax);
+ KnTurbulenceClamp(k, eps, minK, maxK, keNuMin, keNuMax);
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "KEpsilonSources", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &k = *_args.getPtr<Grid<Real>>("k", 0, &_lock);
+ Grid<Real> &eps = *_args.getPtr<Grid<Real>>("eps", 1, &_lock);
+ Grid<Real> &prod = *_args.getPtr<Grid<Real>>("prod", 2, &_lock);
+ _retval = getPyNone();
+ KEpsilonSources(k, eps, prod);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "KEpsilonSources", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("KEpsilonSources", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_KEpsilonSources("", "KEpsilonSources", _W_1);
+extern "C" {
+void PbRegister_KEpsilonSources()
+{
+ KEEP_UNUSED(_RP_KEpsilonSources);
+}
+}
+
+//! Initialize the domain or boundary conditions
+void KEpsilonBcs(
+ const FlagGrid &flags, Grid<Real> &k, Grid<Real> &eps, Real intensity, Real nu, bool fillArea)
+{
+ // compute limits
+ const Real vk = 1.5 * square(keU0) * square(intensity);
+ const Real ve = keCmu * square(vk) / nu;
+
+ FOR_IDX(k)
+ {
+ if (fillArea || flags.isObstacle(idx)) {
+ k[idx] = vk;
+ eps[idx] = ve;
+ }
+ }
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "KEpsilonBcs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &k = *_args.getPtr<Grid<Real>>("k", 1, &_lock);
+ Grid<Real> &eps = *_args.getPtr<Grid<Real>>("eps", 2, &_lock);
+ Real intensity = _args.get<Real>("intensity", 3, &_lock);
+ Real nu = _args.get<Real>("nu", 4, &_lock);
+ bool fillArea = _args.get<bool>("fillArea", 5, &_lock);
+ _retval = getPyNone();
+ KEpsilonBcs(flags, k, eps, intensity, nu, fillArea);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "KEpsilonBcs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("KEpsilonBcs", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_KEpsilonBcs("", "KEpsilonBcs", _W_2);
+extern "C" {
+void PbRegister_KEpsilonBcs()
+{
+ KEEP_UNUSED(_RP_KEpsilonBcs);
+}
+}
+
+//! Gradient diffusion smoothing. Not unconditionally stable -- should probably do substepping etc.
+void ApplyGradDiff(
+ const Grid<Real> &grid, Grid<Real> &res, const Grid<Real> &nu, Real dt, Real sigma)
+{
+ // should do this (but requires better boundary handling)
+ /*MACGrid grad(grid.getParent());
+ GradientOpMAC(grad, grid);
+ grad *= nu;
+ DivergenceOpMAC(res, grad);
+ res *= dt/sigma; */
+
+ LaplaceOp(res, grid);
+ res *= nu;
+ res *= dt / sigma;
+}
+
+//! Compute k-epsilon turbulent viscosity
+void KEpsilonGradientDiffusion(
+ Grid<Real> &k, Grid<Real> &eps, Grid<Real> &nuT, Real sigmaU = 4.0, MACGrid *vel = 0)
+{
+ Real dt = k.getParent()->getDt();
+ Grid<Real> res(k.getParent());
+
+ // gradient diffusion of k
+ ApplyGradDiff(k, res, nuT, dt, keS1);
+ k += res;
+
+ // gradient diffusion of epsilon
+ ApplyGradDiff(eps, res, nuT, dt, keS2);
+ eps += res;
+
+ // gradient diffusion of velocity
+ if (vel) {
+ Grid<Real> vc(k.getParent());
+ for (int c = 0; c < 3; c++) {
+ GetComponent(*vel, vc, c);
+ ApplyGradDiff(vc, res, nuT, dt, sigmaU);
+ vc += res;
+ SetComponent(*vel, vc, c);
+ }
+ }
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "KEpsilonGradientDiffusion", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &k = *_args.getPtr<Grid<Real>>("k", 0, &_lock);
+ Grid<Real> &eps = *_args.getPtr<Grid<Real>>("eps", 1, &_lock);
+ Grid<Real> &nuT = *_args.getPtr<Grid<Real>>("nuT", 2, &_lock);
+ Real sigmaU = _args.getOpt<Real>("sigmaU", 3, 4.0, &_lock);
+ MACGrid *vel = _args.getPtrOpt<MACGrid>("vel", 4, 0, &_lock);
+ _retval = getPyNone();
+ KEpsilonGradientDiffusion(k, eps, nuT, sigmaU, vel);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "KEpsilonGradientDiffusion", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("KEpsilonGradientDiffusion", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_KEpsilonGradientDiffusion("", "KEpsilonGradientDiffusion", _W_3);
+extern "C" {
+void PbRegister_KEpsilonGradientDiffusion()
+{
+ KEEP_UNUSED(_RP_KEpsilonGradientDiffusion);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/meshplugins.cpp b/extern/mantaflow/preprocessed/plugin/meshplugins.cpp
new file mode 100644
index 00000000000..415bca153d0
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/meshplugins.cpp
@@ -0,0 +1,780 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Smoothing etc. for meshes
+ *
+ ******************************************************************************/
+
+/******************************************************************************/
+// Copyright note:
+//
+// These functions (C) Chris Wojtan
+// Long-term goal is to unify with his split&merge codebase
+//
+/******************************************************************************/
+
+#include <queue>
+#include <algorithm>
+#include "mesh.h"
+#include "kernel.h"
+#include "edgecollapse.h"
+#include <mesh.h>
+#include <stack>
+
+using namespace std;
+
+namespace Manta {
+
+//! Mesh smoothing
+/*! see Desbrun 99 "Implicit fairing of of irregular meshes using diffusion and curvature flow"*/
+void smoothMesh(Mesh &mesh, Real strength, int steps = 1, Real minLength = 1e-5)
+{
+ const Real dt = mesh.getParent()->getDt();
+ const Real str = min(dt * strength, (Real)1);
+ mesh.rebuildQuickCheck();
+
+ // calculate original mesh volume
+ Vec3 origCM;
+ Real origVolume = mesh.computeCenterOfMass(origCM);
+
+ // temp vertices
+ const int numCorners = mesh.numTris() * 3;
+ const int numNodes = mesh.numNodes();
+ vector<Vec3> temp(numNodes);
+ vector<bool> visited(numNodes);
+
+ for (int s = 0; s < steps; s++) {
+ // reset markers
+ for (size_t i = 0; i < visited.size(); i++)
+ visited[i] = false;
+
+ for (int c = 0; c < numCorners; c++) {
+ const int node = mesh.corners(c).node;
+ if (visited[node])
+ continue;
+
+ const Vec3 pos = mesh.nodes(node).pos;
+ Vec3 dx(0.0);
+ Real totalLen = 0;
+
+ // rotate around vertex
+ set<int> &ring = mesh.get1Ring(node).nodes;
+ for (set<int>::iterator it = ring.begin(); it != ring.end(); it++) {
+ Vec3 edge = mesh.nodes(*it).pos - pos;
+ Real len = norm(edge);
+
+ if (len > minLength) {
+ dx += edge * (1.0 / len);
+ totalLen += len;
+ }
+ else {
+ totalLen = 0.0;
+ break;
+ }
+ }
+ visited[node] = true;
+ temp[node] = pos;
+ if (totalLen != 0)
+ temp[node] += dx * (str / totalLen);
+ }
+
+ // copy back
+ for (int n = 0; n < numNodes; n++)
+ if (!mesh.isNodeFixed(n))
+ mesh.nodes(n).pos = temp[n];
+ }
+
+ // calculate new mesh volume
+ Vec3 newCM;
+ Real newVolume = mesh.computeCenterOfMass(newCM);
+
+ // preserve volume : scale relative to CM
+ Real beta;
+#if defined(WIN32) || defined(_WIN32)
+ beta = pow((Real)std::abs(origVolume / newVolume), (Real)(1. / 3.));
+#else
+ beta = cbrt(origVolume / newVolume);
+#endif
+
+ for (int n = 0; n < numNodes; n++)
+ if (!mesh.isNodeFixed(n))
+ mesh.nodes(n).pos = origCM + (mesh.nodes(n).pos - newCM) * beta;
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "smoothMesh", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
+ Real strength = _args.get<Real>("strength", 1, &_lock);
+ int steps = _args.getOpt<int>("steps", 2, 1, &_lock);
+ Real minLength = _args.getOpt<Real>("minLength", 3, 1e-5, &_lock);
+ _retval = getPyNone();
+ smoothMesh(mesh, strength, steps, minLength);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "smoothMesh", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("smoothMesh", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_smoothMesh("", "smoothMesh", _W_0);
+extern "C" {
+void PbRegister_smoothMesh()
+{
+ KEEP_UNUSED(_RP_smoothMesh);
+}
+}
+
+//! Subdivide and edgecollapse to guarantee mesh with edgelengths between
+//! min/maxLength and an angle below minAngle
+void subdivideMesh(
+ Mesh &mesh, Real minAngle, Real minLength, Real maxLength, bool cutTubes = false)
+{
+ // gather some statistics
+ int edgeSubdivs = 0, edgeCollsAngle = 0, edgeCollsLen = 0, edgeKill = 0;
+ mesh.rebuildQuickCheck();
+
+ vector<int> deletedNodes;
+ map<int, bool> taintedTris;
+ priority_queue<pair<Real, int>> pq;
+
+ //////////////////////////////////////////
+ // EDGE COLLAPSE //
+ // - particles marked for deletation //
+ //////////////////////////////////////////
+
+ for (int t = 0; t < mesh.numTris(); t++) {
+ if (taintedTris.find(t) != taintedTris.end())
+ continue;
+
+ // check if at least 2 nodes are marked for delete
+ bool k[3];
+ int numKill = 0;
+ for (int i = 0; i < 3; i++) {
+ k[i] = mesh.nodes(mesh.tris(t).c[i]).flags & Mesh::NfKillme;
+ if (k[i])
+ numKill++;
+ }
+ if (numKill < 2)
+ continue;
+
+ if (k[0] && k[1])
+ CollapseEdge(mesh,
+ t,
+ 2,
+ mesh.getEdge(t, 0),
+ mesh.getNode(t, 0),
+ deletedNodes,
+ taintedTris,
+ edgeKill,
+ cutTubes);
+ else if (k[1] && k[2])
+ CollapseEdge(mesh,
+ t,
+ 0,
+ mesh.getEdge(t, 1),
+ mesh.getNode(t, 1),
+ deletedNodes,
+ taintedTris,
+ edgeKill,
+ cutTubes);
+ else if (k[2] && k[0])
+ CollapseEdge(mesh,
+ t,
+ 1,
+ mesh.getEdge(t, 2),
+ mesh.getNode(t, 2),
+ deletedNodes,
+ taintedTris,
+ edgeKill,
+ cutTubes);
+ }
+
+ //////////////////////////////////////////
+ // EDGE COLLAPSING //
+ // - based on small triangle angle //
+ //////////////////////////////////////////
+
+ if (minAngle > 0) {
+ for (int t = 0; t < mesh.numTris(); t++) {
+ // we only want to run through the edge list ONCE.
+ // we achieve this in a method very similar to the above subdivision method.
+
+ // if this triangle has already been deleted, ignore it
+ if (taintedTris.find(t) != taintedTris.end())
+ continue;
+
+ // first we find the angles of this triangle
+ Vec3 e0 = mesh.getEdge(t, 0), e1 = mesh.getEdge(t, 1), e2 = mesh.getEdge(t, 2);
+ Vec3 ne0 = e0;
+ Vec3 ne1 = e1;
+ Vec3 ne2 = e2;
+ normalize(ne0);
+ normalize(ne1);
+ normalize(ne2);
+
+ // Real thisArea = sqrMag(cross(-e2,e0));
+ // small angle approximation says sin(x) = arcsin(x) = x,
+ // arccos(x) = pi/2 - arcsin(x),
+ // cos(x) = dot(A,B),
+ // so angle is approximately 1 - dot(A,B).
+ Real angle[3];
+ angle[0] = 1.0 - dot(ne0, -ne2);
+ angle[1] = 1.0 - dot(ne1, -ne0);
+ angle[2] = 1.0 - dot(ne2, -ne1);
+ Real worstAngle = angle[0];
+ int which = 0;
+ if (angle[1] < worstAngle) {
+ worstAngle = angle[1];
+ which = 1;
+ }
+ if (angle[2] < worstAngle) {
+ worstAngle = angle[2];
+ which = 2;
+ }
+
+ // then we see if the angle is too small
+ if (worstAngle < minAngle) {
+ Vec3 edgevect;
+ Vec3 endpoint;
+ switch (which) {
+ case 0:
+ endpoint = mesh.getNode(t, 1);
+ edgevect = e1;
+ break;
+ case 1:
+ endpoint = mesh.getNode(t, 2);
+ edgevect = e2;
+ break;
+ case 2:
+ endpoint = mesh.getNode(t, 0);
+ edgevect = e0;
+ break;
+ default:
+ break;
+ }
+
+ CollapseEdge(mesh,
+ t,
+ which,
+ edgevect,
+ endpoint,
+ deletedNodes,
+ taintedTris,
+ edgeCollsAngle,
+ cutTubes);
+ }
+ }
+ }
+
+ //////////////////////
+ // EDGE SUBDIVISION //
+ //////////////////////
+
+ Real maxLength2 = maxLength * maxLength;
+ for (int t = 0; t < mesh.numTris(); t++) {
+ // first we find the maximum length edge in this triangle
+ Vec3 e0 = mesh.getEdge(t, 0), e1 = mesh.getEdge(t, 1), e2 = mesh.getEdge(t, 2);
+ Real d0 = normSquare(e0);
+ Real d1 = normSquare(e1);
+ Real d2 = normSquare(e2);
+
+ Real longest = max(d0, max(d1, d2));
+ if (longest > maxLength2) {
+ pq.push(pair<Real, int>(longest, t));
+ }
+ }
+ if (maxLength > 0) {
+
+ while (!pq.empty() && pq.top().first > maxLength2) {
+ // we only want to run through the edge list ONCE
+ // and we want to subdivide the original edges before we subdivide any newer, shorter edges,
+ // so whenever we subdivide, we add the 2 new triangles on the end of the SurfaceTri vector
+ // and mark the original subdivided triangles for deletion.
+ // when we are done subdividing, we delete the obsolete triangles
+
+ int triA = pq.top().second;
+ pq.pop();
+
+ if (taintedTris.find(triA) != taintedTris.end())
+ continue;
+
+ // first we find the maximum length edge in this triangle
+ Vec3 e0 = mesh.getEdge(triA, 0), e1 = mesh.getEdge(triA, 1), e2 = mesh.getEdge(triA, 2);
+ Real d0 = normSquare(e0);
+ Real d1 = normSquare(e1);
+ Real d2 = normSquare(e2);
+
+ Vec3 edgevect;
+ Vec3 endpoint;
+ int which;
+ if (d0 > d1) {
+ if (d0 > d2) {
+ edgevect = e0;
+ endpoint = mesh.getNode(triA, 0);
+ ;
+ which = 2; // 2 opposite of edge 0-1
+ }
+ else {
+ edgevect = e2;
+ endpoint = mesh.getNode(triA, 2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ }
+ else {
+ if (d1 > d2) {
+ edgevect = e1;
+ endpoint = mesh.getNode(triA, 1);
+ which = 0; // 0 opposite of edge 1-2
+ }
+ else {
+ edgevect = e2;
+ endpoint = mesh.getNode(triA, 2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ }
+ // This edge is too long, so we split it in the middle
+
+ // *
+ // / \.
+ // /C0 \.
+ // / \.
+ // / \.
+ // / B \.
+ // / \.
+ // /C1 C2 \.
+ // *---------------*
+ // \C2 C1 /
+ // \ /
+ // \ A /
+ // \ /
+ // \ /
+ // \C0 /
+ // \ /
+ // *
+ //
+ // BECOMES
+ //
+ // *
+ // /|\.
+ // / | \.
+ // /C0|C0\.
+ // / | \.
+ // / B1 | B2 \.
+ // / | \.
+ // /C1 C2|C1 C2 \.
+ // *-------*-------*
+ // \C2 C1|C2 C1/
+ // \ | /
+ // \ A2 | A1 /
+ // \ | /
+ // \C0|C0/
+ // \ | /
+ // \|/
+ // *
+
+ int triB = -1;
+ bool haveB = false;
+ Corner ca_old[3], cb_old[3];
+ ca_old[0] = mesh.corners(triA, which);
+ ca_old[1] = mesh.corners(ca_old[0].next);
+ ca_old[2] = mesh.corners(ca_old[0].prev);
+ if (ca_old[0].opposite >= 0) {
+ cb_old[0] = mesh.corners(ca_old[0].opposite);
+ cb_old[1] = mesh.corners(cb_old[0].next);
+ cb_old[2] = mesh.corners(cb_old[0].prev);
+ triB = cb_old[0].tri;
+ haveB = true;
+ }
+ // else throw Error("nonmanifold");
+
+ // subdivide in the middle of the edge and create new triangles
+ Node newNode;
+ newNode.flags = 0;
+
+ newNode.pos = endpoint + 0.5 * edgevect; // fallback: linear average
+ // default: use butterfly
+ if (haveB)
+ newNode.pos = ModifiedButterflySubdivision(mesh, ca_old[0], cb_old[0], newNode.pos);
+
+ // find indices of two points of 'which'-edge
+ // merge flags
+ int P0 = ca_old[1].node;
+ int P1 = ca_old[2].node;
+ newNode.flags = mesh.nodes(P0).flags | mesh.nodes(P1).flags;
+
+ Real len0 = norm(mesh.nodes(P0).pos - newNode.pos);
+ Real len1 = norm(mesh.nodes(P1).pos - newNode.pos);
+
+ // remove P0/P1 1-ring connection
+ mesh.get1Ring(P0).nodes.erase(P1);
+ mesh.get1Ring(P1).nodes.erase(P0);
+ mesh.get1Ring(P0).tris.erase(triA);
+ mesh.get1Ring(P1).tris.erase(triA);
+ mesh.get1Ring(ca_old[0].node).tris.erase(triA);
+ if (haveB) {
+ mesh.get1Ring(P0).tris.erase(triB);
+ mesh.get1Ring(P1).tris.erase(triB);
+ mesh.get1Ring(cb_old[0].node).tris.erase(triB);
+ }
+
+ // init channel properties for new node
+ for (int i = 0; i < mesh.numNodeChannels(); i++) {
+ mesh.nodeChannel(i)->addInterpol(P0, P1, len0 / (len0 + len1));
+ }
+
+ // write to array
+ mesh.addTri(Triangle(ca_old[0].node, ca_old[1].node, mesh.numNodes()));
+ mesh.addTri(Triangle(ca_old[0].node, mesh.numNodes(), ca_old[2].node));
+ if (haveB) {
+ mesh.addTri(Triangle(cb_old[0].node, cb_old[1].node, mesh.numNodes()));
+ mesh.addTri(Triangle(cb_old[0].node, mesh.numNodes(), cb_old[2].node));
+ }
+ mesh.addNode(newNode);
+
+ const int nt = haveB ? 4 : 2;
+ int triA1 = mesh.numTris() - nt;
+ int triA2 = mesh.numTris() - nt + 1;
+ int triB1 = 0, triB2 = 0;
+ if (haveB) {
+ triB1 = mesh.numTris() - nt + 2;
+ triB2 = mesh.numTris() - nt + 3;
+ }
+ mesh.tris(triA1).flags = mesh.tris(triA).flags;
+ mesh.tris(triA2).flags = mesh.tris(triA).flags;
+ mesh.tris(triB1).flags = mesh.tris(triB).flags;
+ mesh.tris(triB2).flags = mesh.tris(triB).flags;
+
+ // connect new triangles to outside triangles,
+ // and connect outside triangles to these new ones
+ for (int c = 0; c < 3; c++)
+ mesh.addCorner(Corner(triA1, mesh.tris(triA1).c[c]));
+ for (int c = 0; c < 3; c++)
+ mesh.addCorner(Corner(triA2, mesh.tris(triA2).c[c]));
+ if (haveB) {
+ for (int c = 0; c < 3; c++)
+ mesh.addCorner(Corner(triB1, mesh.tris(triB1).c[c]));
+ for (int c = 0; c < 3; c++)
+ mesh.addCorner(Corner(triB2, mesh.tris(triB2).c[c]));
+ }
+
+ int baseIdx = 3 * (mesh.numTris() - nt);
+ Corner *cBase = &mesh.corners(baseIdx);
+
+ // set next/prev
+ for (int t = 0; t < nt; t++)
+ for (int c = 0; c < 3; c++) {
+ cBase[t * 3 + c].next = baseIdx + t * 3 + ((c + 1) % 3);
+ cBase[t * 3 + c].prev = baseIdx + t * 3 + ((c + 2) % 3);
+ }
+
+ // set opposites
+ // A1
+ cBase[0].opposite = haveB ? (baseIdx + 9) : -1;
+ cBase[1].opposite = baseIdx + 5;
+ cBase[2].opposite = -1;
+ if (ca_old[2].opposite >= 0) {
+ cBase[2].opposite = ca_old[2].opposite;
+ mesh.corners(cBase[2].opposite).opposite = baseIdx + 2;
+ }
+ // A2
+ cBase[3].opposite = haveB ? (baseIdx + 6) : -1;
+ cBase[4].opposite = -1;
+ if (ca_old[1].opposite >= 0) {
+ cBase[4].opposite = ca_old[1].opposite;
+ mesh.corners(cBase[4].opposite).opposite = baseIdx + 4;
+ }
+ cBase[5].opposite = baseIdx + 1;
+ if (haveB) {
+ // B1
+ cBase[6].opposite = baseIdx + 3;
+ cBase[7].opposite = baseIdx + 11;
+ cBase[8].opposite = -1;
+ if (cb_old[2].opposite >= 0) {
+ cBase[8].opposite = cb_old[2].opposite;
+ mesh.corners(cBase[8].opposite).opposite = baseIdx + 8;
+ }
+ // B2
+ cBase[9].opposite = baseIdx + 0;
+ cBase[10].opposite = -1;
+ if (cb_old[1].opposite >= 0) {
+ cBase[10].opposite = cb_old[1].opposite;
+ mesh.corners(cBase[10].opposite).opposite = baseIdx + 10;
+ }
+ cBase[11].opposite = baseIdx + 7;
+ }
+
+ ////////////////////
+ // mark the two original triangles for deletion
+ taintedTris[triA] = true;
+ mesh.removeTriFromLookup(triA);
+ if (haveB) {
+ taintedTris[triB] = true;
+ mesh.removeTriFromLookup(triB);
+ }
+
+ Real areaA1 = mesh.getFaceArea(triA1), areaA2 = mesh.getFaceArea(triA2);
+ Real areaB1 = 0, areaB2 = 0;
+ if (haveB) {
+ areaB1 = mesh.getFaceArea(triB1);
+ areaB2 = mesh.getFaceArea(triB2);
+ }
+
+ // add channel props for new triangles
+ for (int i = 0; i < mesh.numTriChannels(); i++) {
+ mesh.triChannel(i)->addSplit(triA, areaA1 / (areaA1 + areaA2));
+ mesh.triChannel(i)->addSplit(triA, areaA2 / (areaA1 + areaA2));
+ if (haveB) {
+ mesh.triChannel(i)->addSplit(triB, areaB1 / (areaB1 + areaB2));
+ mesh.triChannel(i)->addSplit(triB, areaB2 / (areaB1 + areaB2));
+ }
+ }
+
+ // add the four new triangles to the prority queue
+ for (int i = mesh.numTris() - nt; i < mesh.numTris(); i++) {
+ // find the maximum length edge in this triangle
+ Vec3 ne0 = mesh.getEdge(i, 0), ne1 = mesh.getEdge(i, 1), ne2 = mesh.getEdge(i, 2);
+ Real nd0 = normSquare(ne0);
+ Real nd1 = normSquare(ne1);
+ Real nd2 = normSquare(ne2);
+ Real longest = max(nd0, max(nd1, nd2));
+ // longest = (int)(longest * 1e2) / 1e2; // HACK: truncate
+ pq.push(pair<Real, int>(longest, i));
+ }
+ edgeSubdivs++;
+ }
+ }
+
+ //////////////////////////////////////////
+ // EDGE COLLAPSING //
+ // - based on short edge length //
+ //////////////////////////////////////////
+ if (minLength > 0) {
+ const Real minLength2 = minLength * minLength;
+ for (int t = 0; t < mesh.numTris(); t++) {
+ // we only want to run through the edge list ONCE.
+ // we achieve this in a method very similar to the above subdivision method.
+
+ // NOTE:
+ // priority queue does not work so great in the edge collapse case,
+ // because collapsing one triangle affects the edge lengths
+ // of many neighbor triangles,
+ // and we do not update their maximum edge length in the queue.
+
+ // if this triangle has already been deleted, ignore it
+ // if(taintedTris[t])
+ // continue;
+
+ if (taintedTris.find(t) != taintedTris.end())
+ continue;
+
+ // first we find the minimum length edge in this triangle
+ Vec3 e0 = mesh.getEdge(t, 0), e1 = mesh.getEdge(t, 1), e2 = mesh.getEdge(t, 2);
+ Real d0 = normSquare(e0);
+ Real d1 = normSquare(e1);
+ Real d2 = normSquare(e2);
+
+ Vec3 edgevect;
+ Vec3 endpoint;
+ Real dist2;
+ int which;
+ if (d0 < d1) {
+ if (d0 < d2) {
+ dist2 = d0;
+ edgevect = e0;
+ endpoint = mesh.getNode(t, 0);
+ which = 2; // 2 opposite of edge 0-1
+ }
+ else {
+ dist2 = d2;
+ edgevect = e2;
+ endpoint = mesh.getNode(t, 2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ }
+ else {
+ if (d1 < d2) {
+ dist2 = d1;
+ edgevect = e1;
+ endpoint = mesh.getNode(t, 1);
+ which = 0; // 0 opposite of edge 1-2
+ }
+ else {
+ dist2 = d2;
+ edgevect = e2;
+ endpoint = mesh.getNode(t, 2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ }
+ // then we see if the min length edge is too short
+ if (dist2 < minLength2) {
+ CollapseEdge(
+ mesh, t, which, edgevect, endpoint, deletedNodes, taintedTris, edgeCollsLen, cutTubes);
+ }
+ }
+ }
+ // cleanup nodes and triangles marked for deletion
+
+ // we run backwards through the deleted array,
+ // replacing triangles with ones from the back
+ // (this avoids the potential problem of overwriting a triangle
+ // with a to-be-deleted triangle)
+ std::map<int, bool>::reverse_iterator tti = taintedTris.rbegin();
+ for (; tti != taintedTris.rend(); tti++)
+ mesh.removeTri(tti->first);
+
+ mesh.removeNodes(deletedNodes);
+ cout << "Surface subdivision finished with " << mesh.numNodes() << " surface nodes and "
+ << mesh.numTris();
+ cout << " surface triangles, edgeSubdivs:" << edgeSubdivs << ", edgeCollapses: " << edgeCollsLen;
+ cout << " + " << edgeCollsAngle << " + " << edgeKill << endl;
+ // mesh.sanityCheck();
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "subdivideMesh", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
+ Real minAngle = _args.get<Real>("minAngle", 1, &_lock);
+ Real minLength = _args.get<Real>("minLength", 2, &_lock);
+ Real maxLength = _args.get<Real>("maxLength", 3, &_lock);
+ bool cutTubes = _args.getOpt<bool>("cutTubes", 4, false, &_lock);
+ _retval = getPyNone();
+ subdivideMesh(mesh, minAngle, minLength, maxLength, cutTubes);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "subdivideMesh", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("subdivideMesh", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_subdivideMesh("", "subdivideMesh", _W_1);
+extern "C" {
+void PbRegister_subdivideMesh()
+{
+ KEEP_UNUSED(_RP_subdivideMesh);
+}
+}
+
+void killSmallComponents(Mesh &mesh, int elements = 10)
+{
+ const int num = mesh.numTris();
+ vector<int> comp(num);
+ vector<int> numEl;
+ vector<int> deletedNodes;
+ vector<bool> isNodeDel(mesh.numNodes());
+ map<int, bool> taintedTris;
+ // enumerate components
+ int cur = 0;
+ for (int i = 0; i < num; i++) {
+ if (comp[i] == 0) {
+ cur++;
+ comp[i] = cur;
+
+ stack<int> stack;
+ stack.push(i);
+ int cnt = 1;
+ while (!stack.empty()) {
+ int tri = stack.top();
+ stack.pop();
+ for (int c = 0; c < 3; c++) {
+ int op = mesh.corners(tri, c).opposite;
+ if (op < 0)
+ continue;
+ int ntri = mesh.corners(op).tri;
+ if (comp[ntri] == 0) {
+ comp[ntri] = cur;
+ stack.push(ntri);
+ cnt++;
+ }
+ }
+ }
+ numEl.push_back(cnt);
+ }
+ }
+ // kill small components
+ for (int j = 0; j < num; j++) {
+ if (numEl[comp[j] - 1] < elements) {
+ taintedTris[j] = true;
+ for (int c = 0; c < 3; c++) {
+ int n = mesh.tris(j).c[c];
+ if (!isNodeDel[n]) {
+ isNodeDel[n] = true;
+ deletedNodes.push_back(n);
+ }
+ }
+ }
+ }
+
+ std::map<int, bool>::reverse_iterator tti = taintedTris.rbegin();
+ for (; tti != taintedTris.rend(); tti++)
+ mesh.removeTri(tti->first);
+
+ mesh.removeNodes(deletedNodes);
+
+ if (!taintedTris.empty())
+ cout << "Killed small components : " << deletedNodes.size() << " nodes, " << taintedTris.size()
+ << " tris deleted." << endl;
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "killSmallComponents", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
+ int elements = _args.getOpt<int>("elements", 1, 10, &_lock);
+ _retval = getPyNone();
+ killSmallComponents(mesh, elements);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "killSmallComponents", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("killSmallComponents", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_killSmallComponents("", "killSmallComponents", _W_2);
+extern "C" {
+void PbRegister_killSmallComponents()
+{
+ KEEP_UNUSED(_RP_killSmallComponents);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/pressure.cpp b/extern/mantaflow/preprocessed/plugin/pressure.cpp
new file mode 100644
index 00000000000..7def2669e36
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/pressure.cpp
@@ -0,0 +1,1511 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for pressure correction: solve_pressure, and ghost fluid helpers
+ *
+ ******************************************************************************/
+#include "vectorbase.h"
+#include "kernel.h"
+#include "conjugategrad.h"
+#include "multigrid.h"
+
+using namespace std;
+namespace Manta {
+
+//! Preconditioner for CG solver
+// - None: Use standard CG
+// - MIC: Modified incomplete Cholesky preconditioner
+// - MGDynamic: Multigrid preconditioner, rebuilt for each solve
+// - MGStatic: Multigrid preconditioner, built only once (faster than
+// MGDynamic, but works only if Poisson equation does not change)
+enum Preconditioner { PcNone = 0, PcMIC = 1, PcMGDynamic = 2, PcMGStatic = 3 };
+
+inline static Real surfTensHelper(const IndexInt idx,
+ const int offset,
+ const Grid<Real> &phi,
+ const Grid<Real> &curv,
+ const Real surfTens,
+ const Real gfClamp);
+
+//! Kernel: Construct the right-hand side of the poisson equation
+
+struct MakeRhs : public KernelBase {
+ MakeRhs(const FlagGrid &flags,
+ Grid<Real> &rhs,
+ const MACGrid &vel,
+ const Grid<Real> *perCellCorr,
+ const MACGrid *fractions,
+ const MACGrid *obvel,
+ const Grid<Real> *phi,
+ const Grid<Real> *curv,
+ const Real surfTens,
+ const Real gfClamp)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ rhs(rhs),
+ vel(vel),
+ perCellCorr(perCellCorr),
+ fractions(fractions),
+ obvel(obvel),
+ phi(phi),
+ curv(curv),
+ surfTens(surfTens),
+ gfClamp(gfClamp),
+ cnt(0),
+ sum(0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Real> &rhs,
+ const MACGrid &vel,
+ const Grid<Real> *perCellCorr,
+ const MACGrid *fractions,
+ const MACGrid *obvel,
+ const Grid<Real> *phi,
+ const Grid<Real> *curv,
+ const Real surfTens,
+ const Real gfClamp,
+ int &cnt,
+ double &sum)
+ {
+ if (!flags.isFluid(i, j, k)) {
+ rhs(i, j, k) = 0;
+ return;
+ }
+
+ // compute negative divergence
+ // no flag checks: assumes vel at obstacle interfaces is set to zero
+ Real set(0);
+ if (!fractions) {
+ set = vel(i, j, k).x - vel(i + 1, j, k).x + vel(i, j, k).y - vel(i, j + 1, k).y;
+ if (vel.is3D())
+ set += vel(i, j, k).z - vel(i, j, k + 1).z;
+ }
+ else {
+ set = (*fractions)(i, j, k).x * vel(i, j, k).x -
+ (*fractions)(i + 1, j, k).x * vel(i + 1, j, k).x +
+ (*fractions)(i, j, k).y * vel(i, j, k).y -
+ (*fractions)(i, j + 1, k).y * vel(i, j + 1, k).y;
+ if (vel.is3D())
+ set += (*fractions)(i, j, k).z * vel(i, j, k).z -
+ (*fractions)(i, j, k + 1).z * vel(i, j, k + 1).z;
+
+ // compute divergence from obstacle by using obstacle velocity (optional)
+ if (obvel) {
+ set += (1 - (*fractions)(i, j, k).x) * (*obvel)(i, j, k).x -
+ (1 - (*fractions)(i + 1, j, k).x) * (*obvel)(i + 1, j, k).x +
+ (1 - (*fractions)(i, j, k).y) * (*obvel)(i, j, k).y -
+ (1 - (*fractions)(i, j + 1, k).y) * (*obvel)(i, j + 1, k).y;
+ if (obvel->is3D())
+ set += (1 - (*fractions)(i, j, k).z) * (*obvel)(i, j, k).z -
+ (1 - (*fractions)(i, j, k + 1).z) * (*obvel)(i, j, k + 1).z;
+ }
+ }
+
+ // compute surface tension effect (optional)
+ if (phi && curv) {
+ const IndexInt idx = flags.index(i, j, k);
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ if (flags.isEmpty(i - 1, j, k))
+ set += surfTensHelper(idx, -X, *phi, *curv, surfTens, gfClamp);
+ if (flags.isEmpty(i + 1, j, k))
+ set += surfTensHelper(idx, +X, *phi, *curv, surfTens, gfClamp);
+ if (flags.isEmpty(i, j - 1, k))
+ set += surfTensHelper(idx, -Y, *phi, *curv, surfTens, gfClamp);
+ if (flags.isEmpty(i, j + 1, k))
+ set += surfTensHelper(idx, +Y, *phi, *curv, surfTens, gfClamp);
+ if (vel.is3D()) {
+ if (flags.isEmpty(i, j, k - 1))
+ set += surfTensHelper(idx, -Z, *phi, *curv, surfTens, gfClamp);
+ if (flags.isEmpty(i, j, k + 1))
+ set += surfTensHelper(idx, +Z, *phi, *curv, surfTens, gfClamp);
+ }
+ }
+
+ // per cell divergence correction (optional)
+ if (perCellCorr)
+ set += perCellCorr->get(i, j, k);
+
+ // obtain sum, cell count
+ sum += set;
+ cnt++;
+
+ rhs(i, j, k) = set;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return rhs;
+ }
+ typedef Grid<Real> type1;
+ inline const MACGrid &getArg2()
+ {
+ return vel;
+ }
+ typedef MACGrid type2;
+ inline const Grid<Real> *getArg3()
+ {
+ return perCellCorr;
+ }
+ typedef Grid<Real> type3;
+ inline const MACGrid *getArg4()
+ {
+ return fractions;
+ }
+ typedef MACGrid type4;
+ inline const MACGrid *getArg5()
+ {
+ return obvel;
+ }
+ typedef MACGrid type5;
+ inline const Grid<Real> *getArg6()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type6;
+ inline const Grid<Real> *getArg7()
+ {
+ return curv;
+ }
+ typedef Grid<Real> type7;
+ inline const Real &getArg8()
+ {
+ return surfTens;
+ }
+ typedef Real type8;
+ inline const Real &getArg9()
+ {
+ return gfClamp;
+ }
+ typedef Real type9;
+ void runMessage()
+ {
+ debMsg("Executing kernel MakeRhs ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ flags,
+ rhs,
+ vel,
+ perCellCorr,
+ fractions,
+ obvel,
+ phi,
+ curv,
+ surfTens,
+ gfClamp,
+ cnt,
+ sum);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ flags,
+ rhs,
+ vel,
+ perCellCorr,
+ fractions,
+ obvel,
+ phi,
+ curv,
+ surfTens,
+ gfClamp,
+ cnt,
+ sum);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ MakeRhs(MakeRhs &o, tbb::split)
+ : KernelBase(o),
+ flags(o.flags),
+ rhs(o.rhs),
+ vel(o.vel),
+ perCellCorr(o.perCellCorr),
+ fractions(o.fractions),
+ obvel(o.obvel),
+ phi(o.phi),
+ curv(o.curv),
+ surfTens(o.surfTens),
+ gfClamp(o.gfClamp),
+ cnt(0),
+ sum(0)
+ {
+ }
+ void join(const MakeRhs &o)
+ {
+ cnt += o.cnt;
+ sum += o.sum;
+ }
+ const FlagGrid &flags;
+ Grid<Real> &rhs;
+ const MACGrid &vel;
+ const Grid<Real> *perCellCorr;
+ const MACGrid *fractions;
+ const MACGrid *obvel;
+ const Grid<Real> *phi;
+ const Grid<Real> *curv;
+ const Real surfTens;
+ const Real gfClamp;
+ int cnt;
+ double sum;
+};
+
+//! Kernel: make velocity divergence free by subtracting pressure gradient
+
+struct knCorrectVelocity : public KernelBase {
+ knCorrectVelocity(const FlagGrid &flags, MACGrid &vel, const Grid<Real> &pressure)
+ : KernelBase(&flags, 1), flags(flags), vel(vel), pressure(pressure)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, const FlagGrid &flags, MACGrid &vel, const Grid<Real> &pressure) const
+ {
+ const IndexInt idx = flags.index(i, j, k);
+ if (flags.isFluid(idx)) {
+ if (flags.isFluid(i - 1, j, k))
+ vel[idx].x -= (pressure[idx] - pressure(i - 1, j, k));
+ if (flags.isFluid(i, j - 1, k))
+ vel[idx].y -= (pressure[idx] - pressure(i, j - 1, k));
+ if (flags.is3D() && flags.isFluid(i, j, k - 1))
+ vel[idx].z -= (pressure[idx] - pressure(i, j, k - 1));
+
+ if (flags.isEmpty(i - 1, j, k))
+ vel[idx].x -= pressure[idx];
+ if (flags.isEmpty(i, j - 1, k))
+ vel[idx].y -= pressure[idx];
+ if (flags.is3D() && flags.isEmpty(i, j, k - 1))
+ vel[idx].z -= pressure[idx];
+ }
+ else if (flags.isEmpty(idx) &&
+ !flags.isOutflow(idx)) { // don't change velocities in outflow cells
+ if (flags.isFluid(i - 1, j, k))
+ vel[idx].x += pressure(i - 1, j, k);
+ else
+ vel[idx].x = 0.f;
+ if (flags.isFluid(i, j - 1, k))
+ vel[idx].y += pressure(i, j - 1, k);
+ else
+ vel[idx].y = 0.f;
+ if (flags.is3D()) {
+ if (flags.isFluid(i, j, k - 1))
+ vel[idx].z += pressure(i, j, k - 1);
+ else
+ vel[idx].z = 0.f;
+ }
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return pressure;
+ }
+ typedef Grid<Real> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCorrectVelocity ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, pressure);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, vel, pressure);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ MACGrid &vel;
+ const Grid<Real> &pressure;
+};
+
+// *****************************************************************************
+// Ghost fluid helpers
+
+// calculate fraction filled with liquid (note, assumes inside value is < outside!)
+inline static Real thetaHelper(const Real inside, const Real outside)
+{
+ const Real denom = inside - outside;
+ if (denom > -1e-04)
+ return 0.5; // should always be neg, and large enough...
+ return std::max(Real(0), std::min(Real(1), inside / denom));
+}
+
+// calculate ghost fluid factor, cell at idx should be a fluid cell
+inline static Real ghostFluidHelper(const IndexInt idx,
+ const int offset,
+ const Grid<Real> &phi,
+ const Real gfClamp)
+{
+ Real alpha = thetaHelper(phi[idx], phi[idx + offset]);
+ if (alpha < gfClamp)
+ return alpha = gfClamp;
+ return (1. - (1. / alpha));
+}
+
+inline static Real surfTensHelper(const IndexInt idx,
+ const int offset,
+ const Grid<Real> &phi,
+ const Grid<Real> &curv,
+ const Real surfTens,
+ const Real gfClamp)
+{
+ return surfTens * (curv[idx + offset] - ghostFluidHelper(idx, offset, phi, gfClamp) * curv[idx]);
+}
+
+//! Kernel: Adapt A0 for ghost fluid
+
+struct ApplyGhostFluidDiagonal : public KernelBase {
+ ApplyGhostFluidDiagonal(Grid<Real> &A0,
+ const FlagGrid &flags,
+ const Grid<Real> &phi,
+ const Real gfClamp)
+ : KernelBase(&A0, 1), A0(A0), flags(flags), phi(phi), gfClamp(gfClamp)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<Real> &A0,
+ const FlagGrid &flags,
+ const Grid<Real> &phi,
+ const Real gfClamp) const
+ {
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ const IndexInt idx = flags.index(i, j, k);
+ if (!flags.isFluid(idx))
+ return;
+
+ if (flags.isEmpty(i - 1, j, k))
+ A0[idx] -= ghostFluidHelper(idx, -X, phi, gfClamp);
+ if (flags.isEmpty(i + 1, j, k))
+ A0[idx] -= ghostFluidHelper(idx, +X, phi, gfClamp);
+ if (flags.isEmpty(i, j - 1, k))
+ A0[idx] -= ghostFluidHelper(idx, -Y, phi, gfClamp);
+ if (flags.isEmpty(i, j + 1, k))
+ A0[idx] -= ghostFluidHelper(idx, +Y, phi, gfClamp);
+ if (flags.is3D()) {
+ if (flags.isEmpty(i, j, k - 1))
+ A0[idx] -= ghostFluidHelper(idx, -Z, phi, gfClamp);
+ if (flags.isEmpty(i, j, k + 1))
+ A0[idx] -= ghostFluidHelper(idx, +Z, phi, gfClamp);
+ }
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return A0;
+ }
+ typedef Grid<Real> type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type2;
+ inline const Real &getArg3()
+ {
+ return gfClamp;
+ }
+ typedef Real type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel ApplyGhostFluidDiagonal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, A0, flags, phi, gfClamp);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, A0, flags, phi, gfClamp);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<Real> &A0;
+ const FlagGrid &flags;
+ const Grid<Real> &phi;
+ const Real gfClamp;
+};
+
+//! Kernel: Apply velocity update: ghost fluid contribution
+
+struct knCorrectVelocityGhostFluid : public KernelBase {
+ knCorrectVelocityGhostFluid(MACGrid &vel,
+ const FlagGrid &flags,
+ const Grid<Real> &pressure,
+ const Grid<Real> &phi,
+ Real gfClamp,
+ const Grid<Real> *curv,
+ const Real surfTens)
+ : KernelBase(&vel, 1),
+ vel(vel),
+ flags(flags),
+ pressure(pressure),
+ phi(phi),
+ gfClamp(gfClamp),
+ curv(curv),
+ surfTens(surfTens)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ MACGrid &vel,
+ const FlagGrid &flags,
+ const Grid<Real> &pressure,
+ const Grid<Real> &phi,
+ Real gfClamp,
+ const Grid<Real> *curv,
+ const Real surfTens) const
+ {
+ const IndexInt X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ const IndexInt idx = flags.index(i, j, k);
+ if (flags.isFluid(idx)) {
+ if (flags.isEmpty(i - 1, j, k))
+ vel[idx][0] += pressure[idx] * ghostFluidHelper(idx, -X, phi, gfClamp);
+ if (flags.isEmpty(i, j - 1, k))
+ vel[idx][1] += pressure[idx] * ghostFluidHelper(idx, -Y, phi, gfClamp);
+ if (flags.is3D() && flags.isEmpty(i, j, k - 1))
+ vel[idx][2] += pressure[idx] * ghostFluidHelper(idx, -Z, phi, gfClamp);
+ }
+ else if (flags.isEmpty(idx) &&
+ !flags.isOutflow(idx)) { // do not change velocities in outflow cells
+ if (flags.isFluid(i - 1, j, k))
+ vel[idx][0] -= pressure(i - 1, j, k) * ghostFluidHelper(idx - X, +X, phi, gfClamp);
+ else
+ vel[idx].x = 0.f;
+ if (flags.isFluid(i, j - 1, k))
+ vel[idx][1] -= pressure(i, j - 1, k) * ghostFluidHelper(idx - Y, +Y, phi, gfClamp);
+ else
+ vel[idx].y = 0.f;
+ if (flags.is3D()) {
+ if (flags.isFluid(i, j, k - 1))
+ vel[idx][2] -= pressure(i, j, k - 1) * ghostFluidHelper(idx - Z, +Z, phi, gfClamp);
+ else
+ vel[idx].z = 0.f;
+ }
+ }
+
+ if (curv) {
+ if (flags.isFluid(idx)) {
+ if (flags.isEmpty(i - 1, j, k))
+ vel[idx].x += surfTensHelper(idx, -X, phi, *curv, surfTens, gfClamp);
+ if (flags.isEmpty(i, j - 1, k))
+ vel[idx].y += surfTensHelper(idx, -Y, phi, *curv, surfTens, gfClamp);
+ if (flags.is3D() && flags.isEmpty(i, j, k - 1))
+ vel[idx].z += surfTensHelper(idx, -Z, phi, *curv, surfTens, gfClamp);
+ }
+ else if (flags.isEmpty(idx) &&
+ !flags.isOutflow(idx)) { // do not change velocities in outflow cells
+ vel[idx].x -= (flags.isFluid(i - 1, j, k)) ?
+ surfTensHelper(idx - X, +X, phi, *curv, surfTens, gfClamp) :
+ 0.f;
+ vel[idx].y -= (flags.isFluid(i, j - 1, k)) ?
+ surfTensHelper(idx - Y, +Y, phi, *curv, surfTens, gfClamp) :
+ 0.f;
+ if (flags.is3D())
+ vel[idx].z -= (flags.isFluid(i, j, k - 1)) ?
+ surfTensHelper(idx - Z, +Z, phi, *curv, surfTens, gfClamp) :
+ 0.f;
+ }
+ }
+ }
+ inline MACGrid &getArg0()
+ {
+ return vel;
+ }
+ typedef MACGrid type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return pressure;
+ }
+ typedef Grid<Real> type2;
+ inline const Grid<Real> &getArg3()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type3;
+ inline Real &getArg4()
+ {
+ return gfClamp;
+ }
+ typedef Real type4;
+ inline const Grid<Real> *getArg5()
+ {
+ return curv;
+ }
+ typedef Grid<Real> type5;
+ inline const Real &getArg6()
+ {
+ return surfTens;
+ }
+ typedef Real type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCorrectVelocityGhostFluid ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, flags, pressure, phi, gfClamp, curv, surfTens);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, flags, pressure, phi, gfClamp, curv, surfTens);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ MACGrid &vel;
+ const FlagGrid &flags;
+ const Grid<Real> &pressure;
+ const Grid<Real> &phi;
+ Real gfClamp;
+ const Grid<Real> *curv;
+ const Real surfTens;
+};
+
+// improve behavior of clamping for large time steps:
+inline static Real ghostFluidWasClamped(const IndexInt idx,
+ const int offset,
+ const Grid<Real> &phi,
+ const Real gfClamp)
+{
+ const Real alpha = thetaHelper(phi[idx], phi[idx + offset]);
+ if (alpha < gfClamp)
+ return true;
+ return false;
+}
+
+struct knReplaceClampedGhostFluidVels : public KernelBase {
+ knReplaceClampedGhostFluidVels(MACGrid &vel,
+ const FlagGrid &flags,
+ const Grid<Real> &pressure,
+ const Grid<Real> &phi,
+ Real gfClamp)
+ : KernelBase(&vel, 1), vel(vel), flags(flags), pressure(pressure), phi(phi), gfClamp(gfClamp)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ MACGrid &vel,
+ const FlagGrid &flags,
+ const Grid<Real> &pressure,
+ const Grid<Real> &phi,
+ Real gfClamp) const
+ {
+ const IndexInt idx = flags.index(i, j, k);
+ const IndexInt X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ if (!flags.isEmpty(idx))
+ return;
+
+ if (flags.isFluid(i - 1, j, k) && ghostFluidWasClamped(idx - X, +X, phi, gfClamp))
+ vel[idx][0] = vel[idx - X][0];
+ if (flags.isFluid(i, j - 1, k) && ghostFluidWasClamped(idx - Y, +Y, phi, gfClamp))
+ vel[idx][1] = vel[idx - Y][1];
+ if (flags.is3D() && flags.isFluid(i, j, k - 1) &&
+ ghostFluidWasClamped(idx - Z, +Z, phi, gfClamp))
+ vel[idx][2] = vel[idx - Z][2];
+
+ if (flags.isFluid(i + 1, j, k) && ghostFluidWasClamped(idx + X, -X, phi, gfClamp))
+ vel[idx][0] = vel[idx + X][0];
+ if (flags.isFluid(i, j + 1, k) && ghostFluidWasClamped(idx + Y, -Y, phi, gfClamp))
+ vel[idx][1] = vel[idx + Y][1];
+ if (flags.is3D() && flags.isFluid(i, j, k + 1) &&
+ ghostFluidWasClamped(idx + Z, -Z, phi, gfClamp))
+ vel[idx][2] = vel[idx + Z][2];
+ }
+ inline MACGrid &getArg0()
+ {
+ return vel;
+ }
+ typedef MACGrid type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return pressure;
+ }
+ typedef Grid<Real> type2;
+ inline const Grid<Real> &getArg3()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type3;
+ inline Real &getArg4()
+ {
+ return gfClamp;
+ }
+ typedef Real type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knReplaceClampedGhostFluidVels ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, flags, pressure, phi, gfClamp);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, flags, pressure, phi, gfClamp);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ MACGrid &vel;
+ const FlagGrid &flags;
+ const Grid<Real> &pressure;
+ const Grid<Real> &phi;
+ Real gfClamp;
+};
+
+//! Kernel: Compute min value of Real grid
+
+struct CountEmptyCells : public KernelBase {
+ CountEmptyCells(const FlagGrid &flags) : KernelBase(&flags, 0), flags(flags), numEmpty(0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const FlagGrid &flags, int &numEmpty)
+ {
+ if (flags.isEmpty(idx))
+ numEmpty++;
+ }
+ inline operator int()
+ {
+ return numEmpty;
+ }
+ inline int &getRet()
+ {
+ return numEmpty;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel CountEmptyCells ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, flags, numEmpty);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ CountEmptyCells(CountEmptyCells &o, tbb::split) : KernelBase(o), flags(o.flags), numEmpty(0)
+ {
+ }
+ void join(const CountEmptyCells &o)
+ {
+ numEmpty += o.numEmpty;
+ }
+ const FlagGrid &flags;
+ int numEmpty;
+};
+
+// *****************************************************************************
+// Misc helpers
+
+//! Change 'A' and 'rhs' such that pressure at 'fixPidx' is fixed to 'value'
+void fixPressure(int fixPidx,
+ Real value,
+ Grid<Real> &rhs,
+ Grid<Real> &A0,
+ Grid<Real> &Ai,
+ Grid<Real> &Aj,
+ Grid<Real> &Ak)
+{
+ // Bring to rhs at neighbors
+ rhs[fixPidx + Ai.getStrideX()] -= Ai[fixPidx] * value;
+ rhs[fixPidx + Aj.getStrideY()] -= Aj[fixPidx] * value;
+ rhs[fixPidx - Ai.getStrideX()] -= Ai[fixPidx - Ai.getStrideX()] * value;
+ rhs[fixPidx - Aj.getStrideY()] -= Aj[fixPidx - Aj.getStrideY()] * value;
+ if (rhs.is3D()) {
+ rhs[fixPidx + Ak.getStrideZ()] -= Ak[fixPidx] * value;
+ rhs[fixPidx - Ak.getStrideZ()] -= Ak[fixPidx - Ak.getStrideZ()] * value;
+ }
+
+ // Trivialize equation at 'fixPidx' to: pressure[fixPidx] = value
+ rhs[fixPidx] = value;
+ A0[fixPidx] = Real(1);
+ Ai[fixPidx] = Aj[fixPidx] = Ak[fixPidx] = Real(0);
+ Ai[fixPidx - Ai.getStrideX()] = Real(0);
+ Aj[fixPidx - Aj.getStrideY()] = Real(0);
+ if (rhs.is3D()) {
+ Ak[fixPidx - Ak.getStrideZ()] = Real(0);
+ }
+}
+
+// for "static" MG mode, keep one MG data structure per fluid solver
+// leave cleanup to OS/user if nonzero at program termination (PcMGStatic mode)
+// alternatively, manually release in scene file with releaseMG
+static std::map<FluidSolver *, GridMg *> gMapMG;
+
+void releaseMG(FluidSolver *solver = nullptr)
+{
+ // release all?
+ if (!solver) {
+ for (std::map<FluidSolver *, GridMg *>::iterator it = gMapMG.begin(); it != gMapMG.end();
+ it++) {
+ if (it->first != nullptr)
+ releaseMG(it->first);
+ }
+ return;
+ }
+
+ GridMg *mg = gMapMG[solver];
+ if (mg) {
+ delete mg;
+ gMapMG[solver] = nullptr;
+ }
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "releaseMG", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FluidSolver *solver = _args.getPtrOpt<FluidSolver>("solver", 0, nullptr, &_lock);
+ _retval = getPyNone();
+ releaseMG(solver);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "releaseMG", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("releaseMG", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_releaseMG("", "releaseMG", _W_0);
+extern "C" {
+void PbRegister_releaseMG()
+{
+ KEEP_UNUSED(_RP_releaseMG);
+}
+}
+
+// *****************************************************************************
+// Main pressure solve
+
+// Note , all three pressure solve helper functions take
+// identical parameters, apart from the RHS grid (and different const values)
+
+//! Compute rhs for pressure solve
+
+void computePressureRhs(Grid<Real> &rhs,
+ const MACGrid &vel,
+ const Grid<Real> &pressure,
+ const FlagGrid &flags,
+ Real cgAccuracy = 1e-3,
+ const Grid<Real> *phi = 0,
+ const Grid<Real> *perCellCorr = 0,
+ const MACGrid *fractions = 0,
+ const MACGrid *obvel = 0,
+ Real gfClamp = 1e-04,
+ Real cgMaxIterFac = 1.5,
+ bool precondition = true,
+ int preconditioner = PcMIC,
+ bool enforceCompatibility = false,
+ bool useL2Norm = false,
+ bool zeroPressureFixing = false,
+ const Grid<Real> *curv = NULL,
+ const Real surfTens = 0.)
+{
+ // compute divergence and init right hand side
+ MakeRhs kernMakeRhs(
+ flags, rhs, vel, perCellCorr, fractions, obvel, phi, curv, surfTens, gfClamp);
+
+ if (enforceCompatibility)
+ rhs += (Real)(-kernMakeRhs.sum / (Real)kernMakeRhs.cnt);
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "computePressureRhs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &rhs = *_args.getPtr<Grid<Real>>("rhs", 0, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const Grid<Real> &pressure = *_args.getPtr<Grid<Real>>("pressure", 2, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 3, &_lock);
+ Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 4, 1e-3, &_lock);
+ const Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 5, 0, &_lock);
+ const Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>("perCellCorr", 6, 0, &_lock);
+ const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 7, 0, &_lock);
+ const MACGrid *obvel = _args.getPtrOpt<MACGrid>("obvel", 8, 0, &_lock);
+ Real gfClamp = _args.getOpt<Real>("gfClamp", 9, 1e-04, &_lock);
+ Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 10, 1.5, &_lock);
+ bool precondition = _args.getOpt<bool>("precondition", 11, true, &_lock);
+ int preconditioner = _args.getOpt<int>("preconditioner", 12, PcMIC, &_lock);
+ bool enforceCompatibility = _args.getOpt<bool>("enforceCompatibility", 13, false, &_lock);
+ bool useL2Norm = _args.getOpt<bool>("useL2Norm", 14, false, &_lock);
+ bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 15, false, &_lock);
+ const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 16, NULL, &_lock);
+ const Real surfTens = _args.getOpt<Real>("surfTens", 17, 0., &_lock);
+ _retval = getPyNone();
+ computePressureRhs(rhs,
+ vel,
+ pressure,
+ flags,
+ cgAccuracy,
+ phi,
+ perCellCorr,
+ fractions,
+ obvel,
+ gfClamp,
+ cgMaxIterFac,
+ precondition,
+ preconditioner,
+ enforceCompatibility,
+ useL2Norm,
+ zeroPressureFixing,
+ curv,
+ surfTens);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "computePressureRhs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("computePressureRhs", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_computePressureRhs("", "computePressureRhs", _W_1);
+extern "C" {
+void PbRegister_computePressureRhs()
+{
+ KEEP_UNUSED(_RP_computePressureRhs);
+}
+}
+
+//! Build and solve pressure system of equations
+//! perCellCorr: a divergence correction for each cell, optional
+//! fractions: for 2nd order obstacle boundaries, optional
+//! gfClamp: clamping threshold for ghost fluid method
+//! cgMaxIterFac: heuristic to determine maximal number of CG iteations, increase for more accurate
+//! solutions preconditioner: MIC, or MG (see Preconditioner enum) useL2Norm: use max norm by
+//! default, can be turned to L2 here zeroPressureFixing: remove null space by fixing a single
+//! pressure value, needed for MG curv: curvature for surface tension effects surfTens: surface
+//! tension coefficient retRhs: return RHS divergence, e.g., for debugging; optional
+
+void solvePressureSystem(Grid<Real> &rhs,
+ MACGrid &vel,
+ Grid<Real> &pressure,
+ const FlagGrid &flags,
+ Real cgAccuracy = 1e-3,
+ const Grid<Real> *phi = 0,
+ const Grid<Real> *perCellCorr = 0,
+ const MACGrid *fractions = 0,
+ Real gfClamp = 1e-04,
+ Real cgMaxIterFac = 1.5,
+ bool precondition = true,
+ int preconditioner = PcMIC,
+ const bool enforceCompatibility = false,
+ const bool useL2Norm = false,
+ const bool zeroPressureFixing = false,
+ const Grid<Real> *curv = NULL,
+ const Real surfTens = 0.)
+{
+ if (precondition == false)
+ preconditioner = PcNone; // for backwards compatibility
+
+ // reserve temp grids
+ FluidSolver *parent = flags.getParent();
+ Grid<Real> residual(parent);
+ Grid<Real> search(parent);
+ Grid<Real> A0(parent);
+ Grid<Real> Ai(parent);
+ Grid<Real> Aj(parent);
+ Grid<Real> Ak(parent);
+ Grid<Real> tmp(parent);
+
+ // setup matrix and boundaries
+ MakeLaplaceMatrix(flags, A0, Ai, Aj, Ak, fractions);
+
+ if (phi) {
+ ApplyGhostFluidDiagonal(A0, flags, *phi, gfClamp);
+ }
+
+ // check whether we need to fix some pressure value...
+ // (manually enable, or automatically for high accuracy, can cause asymmetries otherwise)
+ if (zeroPressureFixing || cgAccuracy < 1e-07) {
+ if (FLOATINGPOINT_PRECISION == 1)
+ debMsg(
+ "Warning - high CG accuracy with single-precision floating point accuracy might not "
+ "converge...",
+ 2);
+
+ int numEmpty = CountEmptyCells(flags);
+ IndexInt fixPidx = -1;
+ if (numEmpty == 0) {
+ // Determine appropriate fluid cell for pressure fixing
+ // 1) First check some preferred positions for approx. symmetric zeroPressureFixing
+ Vec3i topCenter(
+ flags.getSizeX() / 2, flags.getSizeY() - 1, flags.is3D() ? flags.getSizeZ() / 2 : 0);
+ Vec3i preferredPos[] = {topCenter, topCenter - Vec3i(0, 1, 0), topCenter - Vec3i(0, 2, 0)};
+
+ for (Vec3i pos : preferredPos) {
+ if (flags.isFluid(pos)) {
+ fixPidx = flags.index(pos);
+ break;
+ }
+ }
+
+ // 2) Then search whole domain
+ if (fixPidx == -1) {
+ FOR_IJK_BND(flags, 1)
+ {
+ if (flags.isFluid(i, j, k)) {
+ fixPidx = flags.index(i, j, k);
+ // break FOR_IJK_BND loop
+ i = flags.getSizeX() - 1;
+ j = flags.getSizeY() - 1;
+ k = __kmax;
+ }
+ }
+ }
+ // debMsg("No empty cells! Fixing pressure of cell "<<fixPidx<<" to zero",1);
+ }
+ if (fixPidx >= 0) {
+ fixPressure(fixPidx, Real(0), rhs, A0, Ai, Aj, Ak);
+ static bool msgOnce = false;
+ if (!msgOnce) {
+ debMsg("Pinning pressure of cell " << fixPidx << " to zero", 2);
+ msgOnce = true;
+ }
+ }
+ }
+
+ // CG setup
+ // note: the last factor increases the max iterations for 2d, which right now can't use a
+ // preconditioner
+ GridCgInterface *gcg;
+ if (vel.is3D())
+ gcg = new GridCg<ApplyMatrix>(pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+ else
+ gcg = new GridCg<ApplyMatrix2D>(
+ pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+
+ gcg->setAccuracy(cgAccuracy);
+ gcg->setUseL2Norm(useL2Norm);
+
+ int maxIter = 0;
+
+ Grid<Real> *pca0 = nullptr, *pca1 = nullptr, *pca2 = nullptr, *pca3 = nullptr;
+ GridMg *pmg = nullptr;
+
+ // optional preconditioning
+ if (preconditioner == PcNone || preconditioner == PcMIC) {
+ maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+
+ pca0 = new Grid<Real>(parent);
+ pca1 = new Grid<Real>(parent);
+ pca2 = new Grid<Real>(parent);
+ pca3 = new Grid<Real>(parent);
+
+ gcg->setICPreconditioner(preconditioner == PcMIC ? GridCgInterface::PC_mICP :
+ GridCgInterface::PC_None,
+ pca0,
+ pca1,
+ pca2,
+ pca3);
+ }
+ else if (preconditioner == PcMGDynamic || preconditioner == PcMGStatic) {
+ maxIter = 100;
+
+ pmg = gMapMG[parent];
+ if (!pmg) {
+ pmg = new GridMg(pressure.getSize());
+ gMapMG[parent] = pmg;
+ }
+
+ gcg->setMGPreconditioner(GridCgInterface::PC_MGP, pmg);
+ }
+
+ // CG solve
+ for (int iter = 0; iter < maxIter; iter++) {
+ if (!gcg->iterate())
+ iter = maxIter;
+ if (iter < maxIter)
+ debMsg("FluidSolver::solvePressure iteration " << iter
+ << ", residual: " << gcg->getResNorm(),
+ 9);
+ }
+ debMsg("FluidSolver::solvePressure done. Iterations:" << gcg->getIterations()
+ << ", residual:" << gcg->getResNorm(),
+ 2);
+
+ // Cleanup
+ if (gcg)
+ delete gcg;
+ if (pca0)
+ delete pca0;
+ if (pca1)
+ delete pca1;
+ if (pca2)
+ delete pca2;
+ if (pca3)
+ delete pca3;
+
+ // PcMGDynamic: always delete multigrid solver after use
+ // PcMGStatic: keep multigrid solver for next solve
+ if (pmg && preconditioner == PcMGDynamic)
+ releaseMG(parent);
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "solvePressureSystem", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &rhs = *_args.getPtr<Grid<Real>>("rhs", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ Grid<Real> &pressure = *_args.getPtr<Grid<Real>>("pressure", 2, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 3, &_lock);
+ Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 4, 1e-3, &_lock);
+ const Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 5, 0, &_lock);
+ const Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>("perCellCorr", 6, 0, &_lock);
+ const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 7, 0, &_lock);
+ Real gfClamp = _args.getOpt<Real>("gfClamp", 8, 1e-04, &_lock);
+ Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 9, 1.5, &_lock);
+ bool precondition = _args.getOpt<bool>("precondition", 10, true, &_lock);
+ int preconditioner = _args.getOpt<int>("preconditioner", 11, PcMIC, &_lock);
+ const bool enforceCompatibility = _args.getOpt<bool>(
+ "enforceCompatibility", 12, false, &_lock);
+ const bool useL2Norm = _args.getOpt<bool>("useL2Norm", 13, false, &_lock);
+ const bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 14, false, &_lock);
+ const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 15, NULL, &_lock);
+ const Real surfTens = _args.getOpt<Real>("surfTens", 16, 0., &_lock);
+ _retval = getPyNone();
+ solvePressureSystem(rhs,
+ vel,
+ pressure,
+ flags,
+ cgAccuracy,
+ phi,
+ perCellCorr,
+ fractions,
+ gfClamp,
+ cgMaxIterFac,
+ precondition,
+ preconditioner,
+ enforceCompatibility,
+ useL2Norm,
+ zeroPressureFixing,
+ curv,
+ surfTens);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "solvePressureSystem", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("solvePressureSystem", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_solvePressureSystem("", "solvePressureSystem", _W_2);
+extern "C" {
+void PbRegister_solvePressureSystem()
+{
+ KEEP_UNUSED(_RP_solvePressureSystem);
+}
+}
+
+//! Apply pressure gradient to make velocity field divergence free
+
+void correctVelocity(MACGrid &vel,
+ Grid<Real> &pressure,
+ const FlagGrid &flags,
+ Real cgAccuracy = 1e-3,
+ const Grid<Real> *phi = 0,
+ const Grid<Real> *perCellCorr = 0,
+ const MACGrid *fractions = 0,
+ Real gfClamp = 1e-04,
+ Real cgMaxIterFac = 1.5,
+ bool precondition = true,
+ int preconditioner = PcMIC,
+ bool enforceCompatibility = false,
+ bool useL2Norm = false,
+ bool zeroPressureFixing = false,
+ const Grid<Real> *curv = NULL,
+ const Real surfTens = 0.)
+{
+ knCorrectVelocity(flags, vel, pressure);
+ if (phi) {
+ knCorrectVelocityGhostFluid(vel, flags, pressure, *phi, gfClamp, curv, surfTens);
+ // improve behavior of clamping for large time steps:
+ knReplaceClampedGhostFluidVels(vel, flags, pressure, *phi, gfClamp);
+ }
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "correctVelocity", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ Grid<Real> &pressure = *_args.getPtr<Grid<Real>>("pressure", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 3, 1e-3, &_lock);
+ const Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 4, 0, &_lock);
+ const Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>("perCellCorr", 5, 0, &_lock);
+ const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 6, 0, &_lock);
+ Real gfClamp = _args.getOpt<Real>("gfClamp", 7, 1e-04, &_lock);
+ Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 8, 1.5, &_lock);
+ bool precondition = _args.getOpt<bool>("precondition", 9, true, &_lock);
+ int preconditioner = _args.getOpt<int>("preconditioner", 10, PcMIC, &_lock);
+ bool enforceCompatibility = _args.getOpt<bool>("enforceCompatibility", 11, false, &_lock);
+ bool useL2Norm = _args.getOpt<bool>("useL2Norm", 12, false, &_lock);
+ bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 13, false, &_lock);
+ const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 14, NULL, &_lock);
+ const Real surfTens = _args.getOpt<Real>("surfTens", 15, 0., &_lock);
+ _retval = getPyNone();
+ correctVelocity(vel,
+ pressure,
+ flags,
+ cgAccuracy,
+ phi,
+ perCellCorr,
+ fractions,
+ gfClamp,
+ cgMaxIterFac,
+ precondition,
+ preconditioner,
+ enforceCompatibility,
+ useL2Norm,
+ zeroPressureFixing,
+ curv,
+ surfTens);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "correctVelocity", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("correctVelocity", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_correctVelocity("", "correctVelocity", _W_3);
+extern "C" {
+void PbRegister_correctVelocity()
+{
+ KEEP_UNUSED(_RP_correctVelocity);
+}
+}
+
+//! Perform pressure projection of the velocity grid, calls
+//! all three pressure helper functions in a row.
+
+void solvePressure(MACGrid &vel,
+ Grid<Real> &pressure,
+ const FlagGrid &flags,
+ Real cgAccuracy = 1e-3,
+ const Grid<Real> *phi = 0,
+ const Grid<Real> *perCellCorr = 0,
+ const MACGrid *fractions = 0,
+ const MACGrid *obvel = 0,
+ Real gfClamp = 1e-04,
+ Real cgMaxIterFac = 1.5,
+ bool precondition = true,
+ int preconditioner = PcMIC,
+ bool enforceCompatibility = false,
+ bool useL2Norm = false,
+ bool zeroPressureFixing = false,
+ const Grid<Real> *curv = NULL,
+ const Real surfTens = 0.,
+ Grid<Real> *retRhs = NULL)
+{
+ Grid<Real> rhs(vel.getParent());
+
+ computePressureRhs(rhs,
+ vel,
+ pressure,
+ flags,
+ cgAccuracy,
+ phi,
+ perCellCorr,
+ fractions,
+ obvel,
+ gfClamp,
+ cgMaxIterFac,
+ precondition,
+ preconditioner,
+ enforceCompatibility,
+ useL2Norm,
+ zeroPressureFixing,
+ curv,
+ surfTens);
+
+ solvePressureSystem(rhs,
+ vel,
+ pressure,
+ flags,
+ cgAccuracy,
+ phi,
+ perCellCorr,
+ fractions,
+ gfClamp,
+ cgMaxIterFac,
+ precondition,
+ preconditioner,
+ enforceCompatibility,
+ useL2Norm,
+ zeroPressureFixing,
+ curv,
+ surfTens);
+
+ correctVelocity(vel,
+ pressure,
+ flags,
+ cgAccuracy,
+ phi,
+ perCellCorr,
+ fractions,
+ gfClamp,
+ cgMaxIterFac,
+ precondition,
+ preconditioner,
+ enforceCompatibility,
+ useL2Norm,
+ zeroPressureFixing,
+ curv,
+ surfTens);
+
+ // optionally , return RHS
+ if (retRhs) {
+ retRhs->copyFrom(rhs);
+ }
+}
+static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "solvePressure", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ Grid<Real> &pressure = *_args.getPtr<Grid<Real>>("pressure", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 3, 1e-3, &_lock);
+ const Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 4, 0, &_lock);
+ const Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>("perCellCorr", 5, 0, &_lock);
+ const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 6, 0, &_lock);
+ const MACGrid *obvel = _args.getPtrOpt<MACGrid>("obvel", 7, 0, &_lock);
+ Real gfClamp = _args.getOpt<Real>("gfClamp", 8, 1e-04, &_lock);
+ Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 9, 1.5, &_lock);
+ bool precondition = _args.getOpt<bool>("precondition", 10, true, &_lock);
+ int preconditioner = _args.getOpt<int>("preconditioner", 11, PcMIC, &_lock);
+ bool enforceCompatibility = _args.getOpt<bool>("enforceCompatibility", 12, false, &_lock);
+ bool useL2Norm = _args.getOpt<bool>("useL2Norm", 13, false, &_lock);
+ bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 14, false, &_lock);
+ const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 15, NULL, &_lock);
+ const Real surfTens = _args.getOpt<Real>("surfTens", 16, 0., &_lock);
+ Grid<Real> *retRhs = _args.getPtrOpt<Grid<Real>>("retRhs", 17, NULL, &_lock);
+ _retval = getPyNone();
+ solvePressure(vel,
+ pressure,
+ flags,
+ cgAccuracy,
+ phi,
+ perCellCorr,
+ fractions,
+ obvel,
+ gfClamp,
+ cgMaxIterFac,
+ precondition,
+ preconditioner,
+ enforceCompatibility,
+ useL2Norm,
+ zeroPressureFixing,
+ curv,
+ surfTens,
+ retRhs);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "solvePressure", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("solvePressure", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_solvePressure("", "solvePressure", _W_4);
+extern "C" {
+void PbRegister_solvePressure()
+{
+ KEEP_UNUSED(_RP_solvePressure);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/ptsplugins.cpp b/extern/mantaflow/preprocessed/plugin/ptsplugins.cpp
new file mode 100644
index 00000000000..a6bbccc5966
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/ptsplugins.cpp
@@ -0,0 +1,502 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+// ----------------------------------------------------------------------------
+//
+// MantaFlow fluid solver framework
+// Copyright 2018 Kiwon Um, Nils Thuerey
+//
+// This program is free software, distributed under the terms of the
+// GNU General Public License (GPL)
+// http://www.gnu.org/licenses
+//
+// Particle system helper
+//
+// ----------------------------------------------------------------------------
+
+#include "particle.h"
+
+namespace Manta {
+
+struct KnAddForcePvel : public KernelBase {
+ KnAddForcePvel(ParticleDataImpl<Vec3> &v,
+ const Vec3 &da,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(v.size()), v(v), da(da), ptype(ptype), exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ ParticleDataImpl<Vec3> &v,
+ const Vec3 &da,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (ptype && ((*ptype)[idx] & exclude))
+ return;
+ v[idx] += da;
+ }
+ inline ParticleDataImpl<Vec3> &getArg0()
+ {
+ return v;
+ }
+ typedef ParticleDataImpl<Vec3> type0;
+ inline const Vec3 &getArg1()
+ {
+ return da;
+ }
+ typedef Vec3 type1;
+ inline const ParticleDataImpl<int> *getArg2()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type2;
+ inline const int &getArg3()
+ {
+ return exclude;
+ }
+ typedef int type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnAddForcePvel ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, v, da, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<Vec3> &v;
+ const Vec3 &da;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+//! add force to vec3 particle data; a: acceleration
+
+void addForcePvel(ParticleDataImpl<Vec3> &vel,
+ const Vec3 &a,
+ const Real dt,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+{
+ KnAddForcePvel(vel, a * dt, ptype, exclude);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "addForcePvel", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ ParticleDataImpl<Vec3> &vel = *_args.getPtr<ParticleDataImpl<Vec3>>("vel", 0, &_lock);
+ const Vec3 &a = _args.get<Vec3>("a", 1, &_lock);
+ const Real dt = _args.get<Real>("dt", 2, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtr<ParticleDataImpl<int>>("ptype", 3, &_lock);
+ const int exclude = _args.get<int>("exclude", 4, &_lock);
+ _retval = getPyNone();
+ addForcePvel(vel, a, dt, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "addForcePvel", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("addForcePvel", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_addForcePvel("", "addForcePvel", _W_0);
+extern "C" {
+void PbRegister_addForcePvel()
+{
+ KEEP_UNUSED(_RP_addForcePvel);
+}
+}
+
+struct KnUpdateVelocityFromDeltaPos : public KernelBase {
+ KnUpdateVelocityFromDeltaPos(const BasicParticleSystem &p,
+ ParticleDataImpl<Vec3> &v,
+ const ParticleDataImpl<Vec3> &x_prev,
+ const Real over_dt,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(p.size()),
+ p(p),
+ v(v),
+ x_prev(x_prev),
+ over_dt(over_dt),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ ParticleDataImpl<Vec3> &v,
+ const ParticleDataImpl<Vec3> &x_prev,
+ const Real over_dt,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (ptype && ((*ptype)[idx] & exclude))
+ return;
+ v[idx] = (p[idx].pos - x_prev[idx]) * over_dt;
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline ParticleDataImpl<Vec3> &getArg1()
+ {
+ return v;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ inline const ParticleDataImpl<Vec3> &getArg2()
+ {
+ return x_prev;
+ }
+ typedef ParticleDataImpl<Vec3> type2;
+ inline const Real &getArg3()
+ {
+ return over_dt;
+ }
+ typedef Real type3;
+ inline const ParticleDataImpl<int> *getArg4()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type4;
+ inline const int &getArg5()
+ {
+ return exclude;
+ }
+ typedef int type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnUpdateVelocityFromDeltaPos ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, v, x_prev, over_dt, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystem &p;
+ ParticleDataImpl<Vec3> &v;
+ const ParticleDataImpl<Vec3> &x_prev;
+ const Real over_dt;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+//! retrieve velocity from position change
+
+void updateVelocityFromDeltaPos(const BasicParticleSystem &parts,
+ ParticleDataImpl<Vec3> &vel,
+ const ParticleDataImpl<Vec3> &x_prev,
+ const Real dt,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+{
+ KnUpdateVelocityFromDeltaPos(parts, vel, x_prev, 1.0 / dt, ptype, exclude);
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "updateVelocityFromDeltaPos", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ ParticleDataImpl<Vec3> &vel = *_args.getPtr<ParticleDataImpl<Vec3>>("vel", 1, &_lock);
+ const ParticleDataImpl<Vec3> &x_prev = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "x_prev", 2, &_lock);
+ const Real dt = _args.get<Real>("dt", 3, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtr<ParticleDataImpl<int>>("ptype", 4, &_lock);
+ const int exclude = _args.get<int>("exclude", 5, &_lock);
+ _retval = getPyNone();
+ updateVelocityFromDeltaPos(parts, vel, x_prev, dt, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "updateVelocityFromDeltaPos", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("updateVelocityFromDeltaPos", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_updateVelocityFromDeltaPos("", "updateVelocityFromDeltaPos", _W_1);
+extern "C" {
+void PbRegister_updateVelocityFromDeltaPos()
+{
+ KEEP_UNUSED(_RP_updateVelocityFromDeltaPos);
+}
+}
+
+struct KnStepEuler : public KernelBase {
+ KnStepEuler(BasicParticleSystem &p,
+ const ParticleDataImpl<Vec3> &v,
+ const Real dt,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(p.size()), p(p), v(v), dt(dt), ptype(ptype), exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ BasicParticleSystem &p,
+ const ParticleDataImpl<Vec3> &v,
+ const Real dt,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (ptype && ((*ptype)[idx] & exclude))
+ return;
+ p[idx].pos += v[idx] * dt;
+ }
+ inline BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const ParticleDataImpl<Vec3> &getArg1()
+ {
+ return v;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ inline const Real &getArg2()
+ {
+ return dt;
+ }
+ typedef Real type2;
+ inline const ParticleDataImpl<int> *getArg3()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type3;
+ inline const int &getArg4()
+ {
+ return exclude;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnStepEuler ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, v, dt, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ BasicParticleSystem &p;
+ const ParticleDataImpl<Vec3> &v;
+ const Real dt;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+//! simple foward Euler integration for particle system
+
+void eulerStep(BasicParticleSystem &parts,
+ const ParticleDataImpl<Vec3> &vel,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+{
+ KnStepEuler(parts, vel, parts.getParent()->getDt(), ptype, exclude);
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "eulerStep", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const ParticleDataImpl<Vec3> &vel = *_args.getPtr<ParticleDataImpl<Vec3>>("vel", 1, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtr<ParticleDataImpl<int>>("ptype", 2, &_lock);
+ const int exclude = _args.get<int>("exclude", 3, &_lock);
+ _retval = getPyNone();
+ eulerStep(parts, vel, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "eulerStep", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("eulerStep", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_eulerStep("", "eulerStep", _W_2);
+extern "C" {
+void PbRegister_eulerStep()
+{
+ KEEP_UNUSED(_RP_eulerStep);
+}
+}
+
+struct KnSetPartType : public KernelBase {
+ KnSetPartType(ParticleDataImpl<int> &ptype,
+ const BasicParticleSystem &part,
+ const int mark,
+ const int stype,
+ const FlagGrid &flags,
+ const int cflag)
+ : KernelBase(ptype.size()),
+ ptype(ptype),
+ part(part),
+ mark(mark),
+ stype(stype),
+ flags(flags),
+ cflag(cflag)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ ParticleDataImpl<int> &ptype,
+ const BasicParticleSystem &part,
+ const int mark,
+ const int stype,
+ const FlagGrid &flags,
+ const int cflag) const
+ {
+ if (flags.isInBounds(part.getPos(idx), 0) && (flags.getAt(part.getPos(idx)) & cflag) &&
+ (ptype[idx] & stype))
+ ptype[idx] = mark;
+ }
+ inline ParticleDataImpl<int> &getArg0()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type0;
+ inline const BasicParticleSystem &getArg1()
+ {
+ return part;
+ }
+ typedef BasicParticleSystem type1;
+ inline const int &getArg2()
+ {
+ return mark;
+ }
+ typedef int type2;
+ inline const int &getArg3()
+ {
+ return stype;
+ }
+ typedef int type3;
+ inline const FlagGrid &getArg4()
+ {
+ return flags;
+ }
+ typedef FlagGrid type4;
+ inline const int &getArg5()
+ {
+ return cflag;
+ }
+ typedef int type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnSetPartType ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, ptype, part, mark, stype, flags, cflag);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ ParticleDataImpl<int> &ptype;
+ const BasicParticleSystem &part;
+ const int mark;
+ const int stype;
+ const FlagGrid &flags;
+ const int cflag;
+};
+//! if particle is stype and in cflag cell, set ptype as mark
+
+void setPartType(const BasicParticleSystem &parts,
+ ParticleDataImpl<int> &ptype,
+ const int mark,
+ const int stype,
+ const FlagGrid &flags,
+ const int cflag)
+{
+ KnSetPartType(ptype, parts, mark, stype, flags, cflag);
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setPartType", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ ParticleDataImpl<int> &ptype = *_args.getPtr<ParticleDataImpl<int>>("ptype", 1, &_lock);
+ const int mark = _args.get<int>("mark", 2, &_lock);
+ const int stype = _args.get<int>("stype", 3, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 4, &_lock);
+ const int cflag = _args.get<int>("cflag", 5, &_lock);
+ _retval = getPyNone();
+ setPartType(parts, ptype, mark, stype, flags, cflag);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setPartType", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setPartType", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setPartType("", "setPartType", _W_3);
+extern "C" {
+void PbRegister_setPartType()
+{
+ KEEP_UNUSED(_RP_setPartType);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
new file mode 100644
index 00000000000..281e12ef04b
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
@@ -0,0 +1,3065 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2017 Georg Kohl, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * Secondary particle plugin for FLIP simulations
+ *
+ ******************************************************************************/
+
+#include "particle.h"
+#include "commonkernels.h"
+
+namespace Manta {
+
+#pragma region Secondary Particles for FLIP
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+// Secondary Particles for FLIP
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+
+// helper function that clamps the value in potential to the interval [tauMin, tauMax] and
+// normalizes it to [0, 1] afterwards
+Real clampPotential(Real potential, Real tauMin, Real tauMax)
+{
+ return (std::min(potential, tauMax) - std::min(potential, tauMin)) / (tauMax - tauMin);
+}
+
+// computes all three potentials(trapped air, wave crest, kinetic energy) and the neighbor ratio
+// for every fluid cell and stores it in the respective grid. Is less readable but significantly
+// faster than using seperate potential computation
+
+struct knFlipComputeSecondaryParticlePotentials : public KernelBase {
+ knFlipComputeSecondaryParticlePotentials(Grid<Real> &potTA,
+ Grid<Real> &potWC,
+ Grid<Real> &potKE,
+ Grid<Real> &neighborRatio,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const Grid<Vec3> &normal,
+ const int radius,
+ const Real tauMinTA,
+ const Real tauMaxTA,
+ const Real tauMinWC,
+ const Real tauMaxWC,
+ const Real tauMinKE,
+ const Real tauMaxKE,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeObstacle |
+ FlagGrid::TypeOutflow |
+ FlagGrid::TypeInflow)
+ : KernelBase(&potTA, radius),
+ potTA(potTA),
+ potWC(potWC),
+ potKE(potKE),
+ neighborRatio(neighborRatio),
+ flags(flags),
+ v(v),
+ normal(normal),
+ radius(radius),
+ tauMinTA(tauMinTA),
+ tauMaxTA(tauMaxTA),
+ tauMinWC(tauMinWC),
+ tauMaxWC(tauMaxWC),
+ tauMinKE(tauMinKE),
+ tauMaxKE(tauMaxKE),
+ scaleFromManta(scaleFromManta),
+ itype(itype),
+ jtype(jtype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<Real> &potTA,
+ Grid<Real> &potWC,
+ Grid<Real> &potKE,
+ Grid<Real> &neighborRatio,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const Grid<Vec3> &normal,
+ const int radius,
+ const Real tauMinTA,
+ const Real tauMaxTA,
+ const Real tauMinWC,
+ const Real tauMaxWC,
+ const Real tauMinKE,
+ const Real tauMaxKE,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeObstacle | FlagGrid::TypeOutflow |
+ FlagGrid::TypeInflow) const
+ {
+
+ if (!(flags(i, j, k) & itype))
+ return;
+
+ // compute trapped air potential + wave crest potential + neighbor ratio at once
+ const Vec3 &xi = scaleFromManta * Vec3(i, j, k); // scale to unit cube
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k);
+ const Vec3 &ni = getNormalized(normal(i, j, k));
+ Real vdiff = 0; // for trapped air
+ Real kappa = 0; // for wave crests
+ int countFluid = 0; // for neighbor ratio
+ int countMaxFluid = 0; // for neighbor ratio
+
+ // iterate over neighboring cells within radius
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || !flags.isInBounds(Vec3i(x, y, z)) ||
+ (flags(x, y, z) & jtype))
+ continue;
+
+ if (flags(x, y, z) & itype) {
+ countFluid++;
+ countMaxFluid++;
+ }
+ else {
+ countMaxFluid++;
+ }
+
+ const Vec3 &xj = scaleFromManta * Vec3(x, y, z); // scale to unit cube
+ const Vec3 &vj = scaleFromManta * v.getCentered(x, y, z);
+ const Vec3 &nj = getNormalized(normal(x, y, z));
+ const Vec3 xij = xi - xj;
+ const Vec3 vij = vi - vj;
+ Real h = !potTA.is3D() ?
+ 1.414 * radius :
+ 1.732 * radius; // estimate sqrt(2)*radius resp. sqrt(3)*radius for h, due
+ // to squared resp. cubic neighbor area
+ vdiff += norm(vij) * (1 - dot(getNormalized(vij), getNormalized(xij))) *
+ (1 - norm(xij) / h);
+
+ if (dot(getNormalized(xij), ni) < 0) { // identifies wave crests
+ kappa += (1 - dot(ni, nj)) * (1 - norm(xij) / h);
+ }
+ }
+ }
+ }
+
+ neighborRatio(i, j, k) = float(countFluid) / float(countMaxFluid);
+
+ potTA(i, j, k) = clampPotential(vdiff, tauMinTA, tauMaxTA);
+ if (dot(getNormalized(vi), ni) >= 0.6) { // avoid to mark boarders of the scene as wave crest
+ potWC(i, j, k) = clampPotential(kappa, tauMinWC, tauMaxWC);
+ }
+ else {
+ potWC(i, j, k) = Real(0);
+ }
+
+ // compute kinetic energy potential
+ Real ek =
+ Real(0.5) * 125 *
+ normSquare(
+ vi); // use arbitrary constant for mass, potential adjusts with thresholds anyways
+ potKE(i, j, k) = clampPotential(ek, tauMinKE, tauMaxKE);
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return potTA;
+ }
+ typedef Grid<Real> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return potWC;
+ }
+ typedef Grid<Real> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return potKE;
+ }
+ typedef Grid<Real> type2;
+ inline Grid<Real> &getArg3()
+ {
+ return neighborRatio;
+ }
+ typedef Grid<Real> type3;
+ inline const FlagGrid &getArg4()
+ {
+ return flags;
+ }
+ typedef FlagGrid type4;
+ inline const MACGrid &getArg5()
+ {
+ return v;
+ }
+ typedef MACGrid type5;
+ inline const Grid<Vec3> &getArg6()
+ {
+ return normal;
+ }
+ typedef Grid<Vec3> type6;
+ inline const int &getArg7()
+ {
+ return radius;
+ }
+ typedef int type7;
+ inline const Real &getArg8()
+ {
+ return tauMinTA;
+ }
+ typedef Real type8;
+ inline const Real &getArg9()
+ {
+ return tauMaxTA;
+ }
+ typedef Real type9;
+ inline const Real &getArg10()
+ {
+ return tauMinWC;
+ }
+ typedef Real type10;
+ inline const Real &getArg11()
+ {
+ return tauMaxWC;
+ }
+ typedef Real type11;
+ inline const Real &getArg12()
+ {
+ return tauMinKE;
+ }
+ typedef Real type12;
+ inline const Real &getArg13()
+ {
+ return tauMaxKE;
+ }
+ typedef Real type13;
+ inline const Real &getArg14()
+ {
+ return scaleFromManta;
+ }
+ typedef Real type14;
+ inline const int &getArg15()
+ {
+ return itype;
+ }
+ typedef int type15;
+ inline const int &getArg16()
+ {
+ return jtype;
+ }
+ typedef int type16;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipComputeSecondaryParticlePotentials ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = radius; j < _maxY; j++)
+ for (int i = radius; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ potTA,
+ potWC,
+ potKE,
+ neighborRatio,
+ flags,
+ v,
+ normal,
+ radius,
+ tauMinTA,
+ tauMaxTA,
+ tauMinWC,
+ tauMaxWC,
+ tauMinKE,
+ tauMaxKE,
+ scaleFromManta,
+ itype,
+ jtype);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = radius; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ potTA,
+ potWC,
+ potKE,
+ neighborRatio,
+ flags,
+ v,
+ normal,
+ radius,
+ tauMinTA,
+ tauMaxTA,
+ tauMinWC,
+ tauMaxWC,
+ tauMinKE,
+ tauMaxKE,
+ scaleFromManta,
+ itype,
+ jtype);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(radius, maxY), *this);
+ }
+ Grid<Real> &potTA;
+ Grid<Real> &potWC;
+ Grid<Real> &potKE;
+ Grid<Real> &neighborRatio;
+ const FlagGrid &flags;
+ const MACGrid &v;
+ const Grid<Vec3> &normal;
+ const int radius;
+ const Real tauMinTA;
+ const Real tauMaxTA;
+ const Real tauMinWC;
+ const Real tauMaxWC;
+ const Real tauMinKE;
+ const Real tauMaxKE;
+ const Real scaleFromManta;
+ const int itype;
+ const int jtype;
+};
+
+void flipComputeSecondaryParticlePotentials(Grid<Real> &potTA,
+ Grid<Real> &potWC,
+ Grid<Real> &potKE,
+ Grid<Real> &neighborRatio,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ Grid<Vec3> &normal,
+ const Grid<Real> &phi,
+ const int radius,
+ const Real tauMinTA,
+ const Real tauMaxTA,
+ const Real tauMinWC,
+ const Real tauMaxWC,
+ const Real tauMinKE,
+ const Real tauMaxKE,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeObstacle |
+ FlagGrid::TypeOutflow |
+ FlagGrid::TypeInflow)
+{
+ potTA.clear();
+ potWC.clear();
+ potKE.clear();
+ neighborRatio.clear();
+ GradientOp(normal, phi);
+ knFlipComputeSecondaryParticlePotentials(potTA,
+ potWC,
+ potKE,
+ neighborRatio,
+ flags,
+ v,
+ normal,
+ radius,
+ tauMinTA,
+ tauMaxTA,
+ tauMinWC,
+ tauMaxWC,
+ tauMinKE,
+ tauMaxKE,
+ scaleFromManta,
+ itype,
+ jtype);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "flipComputeSecondaryParticlePotentials", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &potTA = *_args.getPtr<Grid<Real>>("potTA", 0, &_lock);
+ Grid<Real> &potWC = *_args.getPtr<Grid<Real>>("potWC", 1, &_lock);
+ Grid<Real> &potKE = *_args.getPtr<Grid<Real>>("potKE", 2, &_lock);
+ Grid<Real> &neighborRatio = *_args.getPtr<Grid<Real>>("neighborRatio", 3, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 4, &_lock);
+ const MACGrid &v = *_args.getPtr<MACGrid>("v", 5, &_lock);
+ Grid<Vec3> &normal = *_args.getPtr<Grid<Vec3>>("normal", 6, &_lock);
+ const Grid<Real> &phi = *_args.getPtr<Grid<Real>>("phi", 7, &_lock);
+ const int radius = _args.get<int>("radius", 8, &_lock);
+ const Real tauMinTA = _args.get<Real>("tauMinTA", 9, &_lock);
+ const Real tauMaxTA = _args.get<Real>("tauMaxTA", 10, &_lock);
+ const Real tauMinWC = _args.get<Real>("tauMinWC", 11, &_lock);
+ const Real tauMaxWC = _args.get<Real>("tauMaxWC", 12, &_lock);
+ const Real tauMinKE = _args.get<Real>("tauMinKE", 13, &_lock);
+ const Real tauMaxKE = _args.get<Real>("tauMaxKE", 14, &_lock);
+ const Real scaleFromManta = _args.get<Real>("scaleFromManta", 15, &_lock);
+ const int itype = _args.getOpt<int>("itype", 16, FlagGrid::TypeFluid, &_lock);
+ const int jtype = _args.getOpt<int>("jtype",
+ 17,
+ FlagGrid::TypeObstacle | FlagGrid::TypeOutflow |
+ FlagGrid::TypeInflow,
+ &_lock);
+ _retval = getPyNone();
+ flipComputeSecondaryParticlePotentials(potTA,
+ potWC,
+ potKE,
+ neighborRatio,
+ flags,
+ v,
+ normal,
+ phi,
+ radius,
+ tauMinTA,
+ tauMaxTA,
+ tauMinWC,
+ tauMaxWC,
+ tauMinKE,
+ tauMaxKE,
+ scaleFromManta,
+ itype,
+ jtype);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipComputeSecondaryParticlePotentials", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipComputeSecondaryParticlePotentials", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipComputeSecondaryParticlePotentials(
+ "", "flipComputeSecondaryParticlePotentials", _W_0);
+extern "C" {
+void PbRegister_flipComputeSecondaryParticlePotentials()
+{
+ KEEP_UNUSED(_RP_flipComputeSecondaryParticlePotentials);
+}
+}
+
+// adds secondary particles to &pts_sec for every fluid cell in &flags according to the potential
+// grids &potTA, &potWC and &potKE secondary particles are uniformly sampled in every fluid cell in
+// a randomly offset cylinder in fluid movement direction In contrast to
+// flipSampleSecondaryParticles this uses more cylinders per cell and interpolates velocity and
+// potentials. To control number of cylinders in each dimension adjust radius(0.25=>2 cyl,
+// 0.1666=>3 cyl, 0.125=>3cyl etc.).
+
+struct knFlipSampleSecondaryParticlesMoreCylinders : public KernelBase {
+ knFlipSampleSecondaryParticlesMoreCylinders(const FlagGrid &flags,
+ const MACGrid &v,
+ BasicParticleSystem &pts_sec,
+ ParticleDataImpl<Vec3> &v_sec,
+ ParticleDataImpl<Real> &l_sec,
+ const Real lMin,
+ const Real lMax,
+ const Grid<Real> &potTA,
+ const Grid<Real> &potWC,
+ const Grid<Real> &potKE,
+ const Grid<Real> &neighborRatio,
+ const Real c_s,
+ const Real c_b,
+ const Real k_ta,
+ const Real k_wc,
+ const Real dt,
+ const int itype = FlagGrid::TypeFluid)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ v(v),
+ pts_sec(pts_sec),
+ v_sec(v_sec),
+ l_sec(l_sec),
+ lMin(lMin),
+ lMax(lMax),
+ potTA(potTA),
+ potWC(potWC),
+ potKE(potKE),
+ neighborRatio(neighborRatio),
+ c_s(c_s),
+ c_b(c_b),
+ k_ta(k_ta),
+ k_wc(k_wc),
+ dt(dt),
+ itype(itype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ BasicParticleSystem &pts_sec,
+ ParticleDataImpl<Vec3> &v_sec,
+ ParticleDataImpl<Real> &l_sec,
+ const Real lMin,
+ const Real lMax,
+ const Grid<Real> &potTA,
+ const Grid<Real> &potWC,
+ const Grid<Real> &potKE,
+ const Grid<Real> &neighborRatio,
+ const Real c_s,
+ const Real c_b,
+ const Real k_ta,
+ const Real k_wc,
+ const Real dt,
+ const int itype = FlagGrid::TypeFluid)
+ {
+
+ if (!(flags(i, j, k) & itype))
+ return;
+
+ RandomStream mRand(9832);
+ Real radius =
+ 0.25; // diameter=0.5 => sampling with two cylinders in each dimension since cell size=1
+ for (Real x = i - radius; x <= i + radius; x += 2 * radius) {
+ for (Real y = j - radius; y <= j + radius; y += 2 * radius) {
+ for (Real z = k - radius; z <= k + radius; z += 2 * radius) {
+
+ Vec3 xi = Vec3(x, y, z);
+ Real KE = potKE.getInterpolated(xi);
+ Real TA = potTA.getInterpolated(xi);
+ Real WC = potWC.getInterpolated(xi);
+
+ const int n = KE * (k_ta * TA + k_wc * WC) * dt; // number of secondary particles
+ if (n == 0)
+ continue;
+ Vec3 vi = v.getInterpolated(xi);
+ Vec3 dir = dt * vi; // direction of movement of current particle
+ Vec3 e1 = getNormalized(Vec3(dir.z, 0, -dir.x)); // perpendicular to dir
+ Vec3 e2 = getNormalized(
+ cross(e1, dir)); // perpendicular to dir and e1, so e1 and e1 create reference plane
+
+ for (int di = 0; di < n; di++) {
+ const Real r = radius * sqrt(mRand.getReal()); // distance to cylinder axis
+ const Real theta = mRand.getReal() * Real(2) * M_PI; // azimuth
+ const Real h = mRand.getReal() * norm(dt * vi); // distance to reference plane
+ Vec3 xd = xi + r * cos(theta) * e1 + r * sin(theta) * e2 + h * getNormalized(vi);
+ if (!flags.is3D())
+ xd.z = 0;
+ pts_sec.add(xd);
+
+ v_sec[v_sec.size() - 1] = r * cos(theta) * e1 + r * sin(theta) * e2 +
+ vi; // init velocity of new particle
+ Real temp = (KE + TA + WC) / 3;
+ l_sec[l_sec.size() - 1] = ((lMax - lMin) * temp) + lMin +
+ mRand.getReal() * 0.1; // init lifetime of new particle
+
+ // init type of new particle
+ if (neighborRatio(i, j, k) < c_s) {
+ pts_sec[pts_sec.size() - 1].flag = ParticleBase::PSPRAY;
+ }
+ else if (neighborRatio(i, j, k) > c_b) {
+ pts_sec[pts_sec.size() - 1].flag = ParticleBase::PBUBBLE;
+ }
+ else {
+ pts_sec[pts_sec.size() - 1].flag = ParticleBase::PFOAM;
+ }
+ }
+ }
+ }
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return v;
+ }
+ typedef MACGrid type1;
+ inline BasicParticleSystem &getArg2()
+ {
+ return pts_sec;
+ }
+ typedef BasicParticleSystem type2;
+ inline ParticleDataImpl<Vec3> &getArg3()
+ {
+ return v_sec;
+ }
+ typedef ParticleDataImpl<Vec3> type3;
+ inline ParticleDataImpl<Real> &getArg4()
+ {
+ return l_sec;
+ }
+ typedef ParticleDataImpl<Real> type4;
+ inline const Real &getArg5()
+ {
+ return lMin;
+ }
+ typedef Real type5;
+ inline const Real &getArg6()
+ {
+ return lMax;
+ }
+ typedef Real type6;
+ inline const Grid<Real> &getArg7()
+ {
+ return potTA;
+ }
+ typedef Grid<Real> type7;
+ inline const Grid<Real> &getArg8()
+ {
+ return potWC;
+ }
+ typedef Grid<Real> type8;
+ inline const Grid<Real> &getArg9()
+ {
+ return potKE;
+ }
+ typedef Grid<Real> type9;
+ inline const Grid<Real> &getArg10()
+ {
+ return neighborRatio;
+ }
+ typedef Grid<Real> type10;
+ inline const Real &getArg11()
+ {
+ return c_s;
+ }
+ typedef Real type11;
+ inline const Real &getArg12()
+ {
+ return c_b;
+ }
+ typedef Real type12;
+ inline const Real &getArg13()
+ {
+ return k_ta;
+ }
+ typedef Real type13;
+ inline const Real &getArg14()
+ {
+ return k_wc;
+ }
+ typedef Real type14;
+ inline const Real &getArg15()
+ {
+ return dt;
+ }
+ typedef Real type15;
+ inline const int &getArg16()
+ {
+ return itype;
+ }
+ typedef int type16;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipSampleSecondaryParticlesMoreCylinders ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void run()
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ for (int k = minZ; k < maxZ; k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ flags,
+ v,
+ pts_sec,
+ v_sec,
+ l_sec,
+ lMin,
+ lMax,
+ potTA,
+ potWC,
+ potKE,
+ neighborRatio,
+ c_s,
+ c_b,
+ k_ta,
+ k_wc,
+ dt,
+ itype);
+ }
+ const FlagGrid &flags;
+ const MACGrid &v;
+ BasicParticleSystem &pts_sec;
+ ParticleDataImpl<Vec3> &v_sec;
+ ParticleDataImpl<Real> &l_sec;
+ const Real lMin;
+ const Real lMax;
+ const Grid<Real> &potTA;
+ const Grid<Real> &potWC;
+ const Grid<Real> &potKE;
+ const Grid<Real> &neighborRatio;
+ const Real c_s;
+ const Real c_b;
+ const Real k_ta;
+ const Real k_wc;
+ const Real dt;
+ const int itype;
+};
+
+// adds secondary particles to &pts_sec for every fluid cell in &flags according to the potential
+// grids &potTA, &potWC and &potKE secondary particles are uniformly sampled in every fluid cell in
+// a randomly offset cylinder in fluid movement direction
+
+struct knFlipSampleSecondaryParticles : public KernelBase {
+ knFlipSampleSecondaryParticles(const FlagGrid &flags,
+ const MACGrid &v,
+ BasicParticleSystem &pts_sec,
+ ParticleDataImpl<Vec3> &v_sec,
+ ParticleDataImpl<Real> &l_sec,
+ const Real lMin,
+ const Real lMax,
+ const Grid<Real> &potTA,
+ const Grid<Real> &potWC,
+ const Grid<Real> &potKE,
+ const Grid<Real> &neighborRatio,
+ const Real c_s,
+ const Real c_b,
+ const Real k_ta,
+ const Real k_wc,
+ const Real dt,
+ const int itype = FlagGrid::TypeFluid)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ v(v),
+ pts_sec(pts_sec),
+ v_sec(v_sec),
+ l_sec(l_sec),
+ lMin(lMin),
+ lMax(lMax),
+ potTA(potTA),
+ potWC(potWC),
+ potKE(potKE),
+ neighborRatio(neighborRatio),
+ c_s(c_s),
+ c_b(c_b),
+ k_ta(k_ta),
+ k_wc(k_wc),
+ dt(dt),
+ itype(itype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ BasicParticleSystem &pts_sec,
+ ParticleDataImpl<Vec3> &v_sec,
+ ParticleDataImpl<Real> &l_sec,
+ const Real lMin,
+ const Real lMax,
+ const Grid<Real> &potTA,
+ const Grid<Real> &potWC,
+ const Grid<Real> &potKE,
+ const Grid<Real> &neighborRatio,
+ const Real c_s,
+ const Real c_b,
+ const Real k_ta,
+ const Real k_wc,
+ const Real dt,
+ const int itype = FlagGrid::TypeFluid)
+ {
+
+ if (!(flags(i, j, k) & itype))
+ return;
+
+ Real KE = potKE(i, j, k);
+ Real TA = potTA(i, j, k);
+ Real WC = potWC(i, j, k);
+
+ const int n = KE * (k_ta * TA + k_wc * WC) * dt; // number of secondary particles
+ if (n == 0)
+ return;
+ RandomStream mRand(9832);
+
+ Vec3 xi = Vec3(i + mRand.getReal(),
+ j + mRand.getReal(),
+ k + mRand.getReal()); // randomized offset uniform in cell
+ Vec3 vi = v.getInterpolated(xi);
+ Vec3 dir = dt * vi; // direction of movement of current particle
+ Vec3 e1 = getNormalized(Vec3(dir.z, 0, -dir.x)); // perpendicular to dir
+ Vec3 e2 = getNormalized(
+ cross(e1, dir)); // perpendicular to dir and e1, so e1 and e1 create reference plane
+
+ for (int di = 0; di < n; di++) {
+ const Real r = Real(0.5) * sqrt(mRand.getReal()); // distance to cylinder axis
+ const Real theta = mRand.getReal() * Real(2) * M_PI; // azimuth
+ const Real h = mRand.getReal() * norm(dt * vi); // distance to reference plane
+ Vec3 xd = xi + r * cos(theta) * e1 + r * sin(theta) * e2 + h * getNormalized(vi);
+ if (!flags.is3D())
+ xd.z = 0;
+ pts_sec.add(xd);
+
+ v_sec[v_sec.size() - 1] = r * cos(theta) * e1 + r * sin(theta) * e2 +
+ vi; // init velocity of new particle
+ Real temp = (KE + TA + WC) / 3;
+ l_sec[l_sec.size() - 1] = ((lMax - lMin) * temp) + lMin +
+ mRand.getReal() * 0.1; // init lifetime of new particle
+
+ // init type of new particle
+ if (neighborRatio(i, j, k) < c_s) {
+ pts_sec[pts_sec.size() - 1].flag = ParticleBase::PSPRAY;
+ }
+ else if (neighborRatio(i, j, k) > c_b) {
+ pts_sec[pts_sec.size() - 1].flag = ParticleBase::PBUBBLE;
+ }
+ else {
+ pts_sec[pts_sec.size() - 1].flag = ParticleBase::PFOAM;
+ }
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return v;
+ }
+ typedef MACGrid type1;
+ inline BasicParticleSystem &getArg2()
+ {
+ return pts_sec;
+ }
+ typedef BasicParticleSystem type2;
+ inline ParticleDataImpl<Vec3> &getArg3()
+ {
+ return v_sec;
+ }
+ typedef ParticleDataImpl<Vec3> type3;
+ inline ParticleDataImpl<Real> &getArg4()
+ {
+ return l_sec;
+ }
+ typedef ParticleDataImpl<Real> type4;
+ inline const Real &getArg5()
+ {
+ return lMin;
+ }
+ typedef Real type5;
+ inline const Real &getArg6()
+ {
+ return lMax;
+ }
+ typedef Real type6;
+ inline const Grid<Real> &getArg7()
+ {
+ return potTA;
+ }
+ typedef Grid<Real> type7;
+ inline const Grid<Real> &getArg8()
+ {
+ return potWC;
+ }
+ typedef Grid<Real> type8;
+ inline const Grid<Real> &getArg9()
+ {
+ return potKE;
+ }
+ typedef Grid<Real> type9;
+ inline const Grid<Real> &getArg10()
+ {
+ return neighborRatio;
+ }
+ typedef Grid<Real> type10;
+ inline const Real &getArg11()
+ {
+ return c_s;
+ }
+ typedef Real type11;
+ inline const Real &getArg12()
+ {
+ return c_b;
+ }
+ typedef Real type12;
+ inline const Real &getArg13()
+ {
+ return k_ta;
+ }
+ typedef Real type13;
+ inline const Real &getArg14()
+ {
+ return k_wc;
+ }
+ typedef Real type14;
+ inline const Real &getArg15()
+ {
+ return dt;
+ }
+ typedef Real type15;
+ inline const int &getArg16()
+ {
+ return itype;
+ }
+ typedef int type16;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipSampleSecondaryParticles ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void run()
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ for (int k = minZ; k < maxZ; k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ flags,
+ v,
+ pts_sec,
+ v_sec,
+ l_sec,
+ lMin,
+ lMax,
+ potTA,
+ potWC,
+ potKE,
+ neighborRatio,
+ c_s,
+ c_b,
+ k_ta,
+ k_wc,
+ dt,
+ itype);
+ }
+ const FlagGrid &flags;
+ const MACGrid &v;
+ BasicParticleSystem &pts_sec;
+ ParticleDataImpl<Vec3> &v_sec;
+ ParticleDataImpl<Real> &l_sec;
+ const Real lMin;
+ const Real lMax;
+ const Grid<Real> &potTA;
+ const Grid<Real> &potWC;
+ const Grid<Real> &potKE;
+ const Grid<Real> &neighborRatio;
+ const Real c_s;
+ const Real c_b;
+ const Real k_ta;
+ const Real k_wc;
+ const Real dt;
+ const int itype;
+};
+
+void flipSampleSecondaryParticles(const std::string mode,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ BasicParticleSystem &pts_sec,
+ ParticleDataImpl<Vec3> &v_sec,
+ ParticleDataImpl<Real> &l_sec,
+ const Real lMin,
+ const Real lMax,
+ const Grid<Real> &potTA,
+ const Grid<Real> &potWC,
+ const Grid<Real> &potKE,
+ const Grid<Real> &neighborRatio,
+ const Real c_s,
+ const Real c_b,
+ const Real k_ta,
+ const Real k_wc,
+ const Real dt,
+ const int itype = FlagGrid::TypeFluid)
+{
+ if (mode == "single") {
+ knFlipSampleSecondaryParticles(flags,
+ v,
+ pts_sec,
+ v_sec,
+ l_sec,
+ lMin,
+ lMax,
+ potTA,
+ potWC,
+ potKE,
+ neighborRatio,
+ c_s,
+ c_b,
+ k_ta,
+ k_wc,
+ dt,
+ itype);
+ }
+ else if (mode == "multiple") {
+ knFlipSampleSecondaryParticlesMoreCylinders(flags,
+ v,
+ pts_sec,
+ v_sec,
+ l_sec,
+ lMin,
+ lMax,
+ potTA,
+ potWC,
+ potKE,
+ neighborRatio,
+ c_s,
+ c_b,
+ k_ta,
+ k_wc,
+ dt,
+ itype);
+ }
+ else {
+ throw std::invalid_argument("Unknown mode: use \"single\" or \"multiple\" instead!");
+ }
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "flipSampleSecondaryParticles", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const std::string mode = _args.get<std::string>("mode", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ const MACGrid &v = *_args.getPtr<MACGrid>("v", 2, &_lock);
+ BasicParticleSystem &pts_sec = *_args.getPtr<BasicParticleSystem>("pts_sec", 3, &_lock);
+ ParticleDataImpl<Vec3> &v_sec = *_args.getPtr<ParticleDataImpl<Vec3>>("v_sec", 4, &_lock);
+ ParticleDataImpl<Real> &l_sec = *_args.getPtr<ParticleDataImpl<Real>>("l_sec", 5, &_lock);
+ const Real lMin = _args.get<Real>("lMin", 6, &_lock);
+ const Real lMax = _args.get<Real>("lMax", 7, &_lock);
+ const Grid<Real> &potTA = *_args.getPtr<Grid<Real>>("potTA", 8, &_lock);
+ const Grid<Real> &potWC = *_args.getPtr<Grid<Real>>("potWC", 9, &_lock);
+ const Grid<Real> &potKE = *_args.getPtr<Grid<Real>>("potKE", 10, &_lock);
+ const Grid<Real> &neighborRatio = *_args.getPtr<Grid<Real>>("neighborRatio", 11, &_lock);
+ const Real c_s = _args.get<Real>("c_s", 12, &_lock);
+ const Real c_b = _args.get<Real>("c_b", 13, &_lock);
+ const Real k_ta = _args.get<Real>("k_ta", 14, &_lock);
+ const Real k_wc = _args.get<Real>("k_wc", 15, &_lock);
+ const Real dt = _args.get<Real>("dt", 16, &_lock);
+ const int itype = _args.getOpt<int>("itype", 17, FlagGrid::TypeFluid, &_lock);
+ _retval = getPyNone();
+ flipSampleSecondaryParticles(mode,
+ flags,
+ v,
+ pts_sec,
+ v_sec,
+ l_sec,
+ lMin,
+ lMax,
+ potTA,
+ potWC,
+ potKE,
+ neighborRatio,
+ c_s,
+ c_b,
+ k_ta,
+ k_wc,
+ dt,
+ itype);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipSampleSecondaryParticles", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipSampleSecondaryParticles", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipSampleSecondaryParticles("",
+ "flipSampleSecondaryParticles",
+ _W_1);
+extern "C" {
+void PbRegister_flipSampleSecondaryParticles()
+{
+ KEEP_UNUSED(_RP_flipSampleSecondaryParticles);
+}
+}
+
+// evaluates cubic spline with radius h and distance l in dim dimensions
+Real cubicSpline(const Real h, const Real l, const int dim)
+{
+ const Real h2 = square(h), h3 = h2 * h, h4 = h3 * h, h5 = h4 * h;
+ const Real c[] = {
+ Real(2e0 / (3e0 * h)), Real(10e0 / (7e0 * M_PI * h2)), Real(1e0 / (M_PI * h3))};
+ const Real q = l / h;
+ if (q < 1e0)
+ return c[dim - 1] * (1e0 - 1.5 * square(q) + 0.75 * cubed(q));
+ else if (q < 2e0)
+ return c[dim - 1] * (0.25 * cubed(2e0 - q));
+ return 0;
+}
+
+// updates position &pts_sec.pos and velocity &v_sec of secondary particles according to the
+// particle type determined by the neighbor ratio with linear interpolation
+
+struct knFlipUpdateSecondaryParticlesLinear : public KernelBase {
+ knFlipUpdateSecondaryParticlesLinear(BasicParticleSystem &pts_sec,
+ ParticleDataImpl<Vec3> &v_sec,
+ ParticleDataImpl<Real> &l_sec,
+ const ParticleDataImpl<Vec3> &f_sec,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const Grid<Real> &neighborRatio,
+ const Vec3 gravity,
+ const Real k_b,
+ const Real k_d,
+ const Real c_s,
+ const Real c_b,
+ const Real dt,
+ const int exclude,
+ const int antitunneling)
+ : KernelBase(pts_sec.size()),
+ pts_sec(pts_sec),
+ v_sec(v_sec),
+ l_sec(l_sec),
+ f_sec(f_sec),
+ flags(flags),
+ v(v),
+ neighborRatio(neighborRatio),
+ gravity(gravity),
+ k_b(k_b),
+ k_d(k_d),
+ c_s(c_s),
+ c_b(c_b),
+ dt(dt),
+ exclude(exclude),
+ antitunneling(antitunneling)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ BasicParticleSystem &pts_sec,
+ ParticleDataImpl<Vec3> &v_sec,
+ ParticleDataImpl<Real> &l_sec,
+ const ParticleDataImpl<Vec3> &f_sec,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const Grid<Real> &neighborRatio,
+ const Vec3 gravity,
+ const Real k_b,
+ const Real k_d,
+ const Real c_s,
+ const Real c_b,
+ const Real dt,
+ const int exclude,
+ const int antitunneling) const
+ {
+
+ if (!pts_sec.isActive(idx) || pts_sec[idx].flag & exclude)
+ return;
+ if (!flags.isInBounds(pts_sec[idx].pos)) {
+ pts_sec.kill(idx);
+ return;
+ }
+
+ Vec3i gridpos = toVec3i(pts_sec[idx].pos);
+ int i = gridpos.x;
+ int j = gridpos.y;
+ int k = gridpos.z;
+
+ // spray particle
+ if (neighborRatio(gridpos) < c_s) {
+ pts_sec[idx].flag |= ParticleBase::PSPRAY;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PFOAM);
+ v_sec[idx] += dt *
+ ((f_sec[idx] / 1) + gravity); // TODO: if forces are added (e.g. fluid
+ // guiding), add parameter for mass instead of 1
+
+ // anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos +
+ ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ // air bubble particle
+ else if (neighborRatio(gridpos) > c_b) {
+ pts_sec[idx].flag |= ParticleBase::PBUBBLE;
+ pts_sec[idx].flag &= ~(ParticleBase::PSPRAY | ParticleBase::PFOAM);
+
+ const Vec3 vj = (v.getInterpolated(pts_sec[idx].pos) - v_sec[idx]) / dt;
+ v_sec[idx] += dt * (k_b * -gravity + k_d * vj);
+
+ // anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos +
+ ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ // foam particle
+ else {
+ pts_sec[idx].flag |= ParticleBase::PFOAM;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PSPRAY);
+
+ const Vec3 vj = v.getInterpolated(pts_sec[idx].pos);
+ // anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * vj);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v.getInterpolated(pts_sec[idx].pos);
+ }
+
+ // lifetime
+ l_sec[idx] -= dt;
+ if (l_sec[idx] <= Real(0)) {
+ pts_sec.kill(idx);
+ }
+ }
+ inline BasicParticleSystem &getArg0()
+ {
+ return pts_sec;
+ }
+ typedef BasicParticleSystem type0;
+ inline ParticleDataImpl<Vec3> &getArg1()
+ {
+ return v_sec;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ inline ParticleDataImpl<Real> &getArg2()
+ {
+ return l_sec;
+ }
+ typedef ParticleDataImpl<Real> type2;
+ inline const ParticleDataImpl<Vec3> &getArg3()
+ {
+ return f_sec;
+ }
+ typedef ParticleDataImpl<Vec3> type3;
+ inline const FlagGrid &getArg4()
+ {
+ return flags;
+ }
+ typedef FlagGrid type4;
+ inline const MACGrid &getArg5()
+ {
+ return v;
+ }
+ typedef MACGrid type5;
+ inline const Grid<Real> &getArg6()
+ {
+ return neighborRatio;
+ }
+ typedef Grid<Real> type6;
+ inline const Vec3 &getArg7()
+ {
+ return gravity;
+ }
+ typedef Vec3 type7;
+ inline const Real &getArg8()
+ {
+ return k_b;
+ }
+ typedef Real type8;
+ inline const Real &getArg9()
+ {
+ return k_d;
+ }
+ typedef Real type9;
+ inline const Real &getArg10()
+ {
+ return c_s;
+ }
+ typedef Real type10;
+ inline const Real &getArg11()
+ {
+ return c_b;
+ }
+ typedef Real type11;
+ inline const Real &getArg12()
+ {
+ return dt;
+ }
+ typedef Real type12;
+ inline const int &getArg13()
+ {
+ return exclude;
+ }
+ typedef int type13;
+ inline const int &getArg14()
+ {
+ return antitunneling;
+ }
+ typedef int type14;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipUpdateSecondaryParticlesLinear ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx,
+ pts_sec,
+ v_sec,
+ l_sec,
+ f_sec,
+ flags,
+ v,
+ neighborRatio,
+ gravity,
+ k_b,
+ k_d,
+ c_s,
+ c_b,
+ dt,
+ exclude,
+ antitunneling);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ BasicParticleSystem &pts_sec;
+ ParticleDataImpl<Vec3> &v_sec;
+ ParticleDataImpl<Real> &l_sec;
+ const ParticleDataImpl<Vec3> &f_sec;
+ const FlagGrid &flags;
+ const MACGrid &v;
+ const Grid<Real> &neighborRatio;
+ const Vec3 gravity;
+ const Real k_b;
+ const Real k_d;
+ const Real c_s;
+ const Real c_b;
+ const Real dt;
+ const int exclude;
+ const int antitunneling;
+};
+// updates position &pts_sec.pos and velocity &v_sec of secondary particles according to the
+// particle type determined by the neighbor ratio with cubic spline interpolation
+
+struct knFlipUpdateSecondaryParticlesCubic : public KernelBase {
+ knFlipUpdateSecondaryParticlesCubic(BasicParticleSystem &pts_sec,
+ ParticleDataImpl<Vec3> &v_sec,
+ ParticleDataImpl<Real> &l_sec,
+ const ParticleDataImpl<Vec3> &f_sec,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const Grid<Real> &neighborRatio,
+ const int radius,
+ const Vec3 gravity,
+ const Real k_b,
+ const Real k_d,
+ const Real c_s,
+ const Real c_b,
+ const Real dt,
+ const int exclude,
+ const int antitunneling,
+ const int itype)
+ : KernelBase(pts_sec.size()),
+ pts_sec(pts_sec),
+ v_sec(v_sec),
+ l_sec(l_sec),
+ f_sec(f_sec),
+ flags(flags),
+ v(v),
+ neighborRatio(neighborRatio),
+ radius(radius),
+ gravity(gravity),
+ k_b(k_b),
+ k_d(k_d),
+ c_s(c_s),
+ c_b(c_b),
+ dt(dt),
+ exclude(exclude),
+ antitunneling(antitunneling),
+ itype(itype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ BasicParticleSystem &pts_sec,
+ ParticleDataImpl<Vec3> &v_sec,
+ ParticleDataImpl<Real> &l_sec,
+ const ParticleDataImpl<Vec3> &f_sec,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const Grid<Real> &neighborRatio,
+ const int radius,
+ const Vec3 gravity,
+ const Real k_b,
+ const Real k_d,
+ const Real c_s,
+ const Real c_b,
+ const Real dt,
+ const int exclude,
+ const int antitunneling,
+ const int itype) const
+ {
+
+ if (!pts_sec.isActive(idx) || pts_sec[idx].flag & exclude)
+ return;
+ if (!flags.isInBounds(pts_sec[idx].pos)) {
+ pts_sec.kill(idx);
+ return;
+ }
+
+ Vec3i gridpos = toVec3i(pts_sec[idx].pos);
+ int i = gridpos.x;
+ int j = gridpos.y;
+ int k = gridpos.z;
+
+ // spray particle
+ if (neighborRatio(gridpos) < c_s) {
+ pts_sec[idx].flag |= ParticleBase::PSPRAY;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PFOAM);
+ v_sec[idx] += dt *
+ ((f_sec[idx] / 1) + gravity); // TODO: if forces are added (e.g. fluid
+ // guiding), add parameter for mass instead of 1
+
+ // anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos +
+ ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ // air bubble particle
+ else if (neighborRatio(gridpos) > c_b) {
+ pts_sec[idx].flag |= ParticleBase::PBUBBLE;
+ pts_sec[idx].flag &= ~(ParticleBase::PSPRAY | ParticleBase::PFOAM);
+ const Vec3 &xi = pts_sec[idx].pos;
+ Vec3 sumNumerator = Vec3(0, 0, 0);
+ Real sumDenominator = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ Vec3i xj = Vec3i(x, y, z);
+ if ((x == i && y == j && z == k) || !flags.isInBounds(xj))
+ continue;
+ if (!(flags(xj) & itype))
+ continue;
+ const Real len_xij = norm(xi - Vec3(x, y, z));
+
+ int dim = flags.is3D() ? 3 : 2;
+ Real dist = flags.is3D() ? 1.732 : 1.414;
+ Real weight = cubicSpline(radius * dist, len_xij, dim);
+ sumNumerator += v.getCentered(xj) *
+ weight; // estimate next position by current velocity
+ sumDenominator += weight;
+ }
+ }
+ }
+ const Vec3 temp = ((sumNumerator / sumDenominator) - v_sec[idx]) / dt;
+ v_sec[idx] += dt * (k_b * -gravity + k_d * temp);
+
+ // anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos +
+ ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ // foam particle
+ else {
+ pts_sec[idx].flag |= ParticleBase::PFOAM;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PSPRAY);
+ const Vec3 &xi = pts_sec[idx].pos;
+ Vec3 sumNumerator = Vec3(0, 0, 0);
+ Real sumDenominator = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ Vec3i xj = Vec3i(x, y, z);
+ if ((x == i && y == j && z == k) || !flags.isInBounds(xj))
+ continue;
+ if (!(flags(xj) & itype))
+ continue;
+ const Real len_xij = norm(xi - Vec3(x, y, z));
+
+ int dim = flags.is3D() ? 3 : 2;
+ Real dist = flags.is3D() ? 1.732 : 1.414;
+ Real weight = cubicSpline(radius * dist, len_xij, dim);
+ sumNumerator += v.getCentered(xj) *
+ weight; // estimate next position by current velocity
+ sumDenominator += weight;
+ }
+ }
+ }
+
+ // anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt *
+ (sumNumerator / sumDenominator));
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * (sumNumerator / sumDenominator);
+ }
+
+ // lifetime
+ l_sec[idx] -= dt;
+ if (l_sec[idx] <= Real(0)) {
+ pts_sec.kill(idx);
+ }
+ }
+ inline BasicParticleSystem &getArg0()
+ {
+ return pts_sec;
+ }
+ typedef BasicParticleSystem type0;
+ inline ParticleDataImpl<Vec3> &getArg1()
+ {
+ return v_sec;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ inline ParticleDataImpl<Real> &getArg2()
+ {
+ return l_sec;
+ }
+ typedef ParticleDataImpl<Real> type2;
+ inline const ParticleDataImpl<Vec3> &getArg3()
+ {
+ return f_sec;
+ }
+ typedef ParticleDataImpl<Vec3> type3;
+ inline const FlagGrid &getArg4()
+ {
+ return flags;
+ }
+ typedef FlagGrid type4;
+ inline const MACGrid &getArg5()
+ {
+ return v;
+ }
+ typedef MACGrid type5;
+ inline const Grid<Real> &getArg6()
+ {
+ return neighborRatio;
+ }
+ typedef Grid<Real> type6;
+ inline const int &getArg7()
+ {
+ return radius;
+ }
+ typedef int type7;
+ inline const Vec3 &getArg8()
+ {
+ return gravity;
+ }
+ typedef Vec3 type8;
+ inline const Real &getArg9()
+ {
+ return k_b;
+ }
+ typedef Real type9;
+ inline const Real &getArg10()
+ {
+ return k_d;
+ }
+ typedef Real type10;
+ inline const Real &getArg11()
+ {
+ return c_s;
+ }
+ typedef Real type11;
+ inline const Real &getArg12()
+ {
+ return c_b;
+ }
+ typedef Real type12;
+ inline const Real &getArg13()
+ {
+ return dt;
+ }
+ typedef Real type13;
+ inline const int &getArg14()
+ {
+ return exclude;
+ }
+ typedef int type14;
+ inline const int &getArg15()
+ {
+ return antitunneling;
+ }
+ typedef int type15;
+ inline const int &getArg16()
+ {
+ return itype;
+ }
+ typedef int type16;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipUpdateSecondaryParticlesCubic ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx,
+ pts_sec,
+ v_sec,
+ l_sec,
+ f_sec,
+ flags,
+ v,
+ neighborRatio,
+ radius,
+ gravity,
+ k_b,
+ k_d,
+ c_s,
+ c_b,
+ dt,
+ exclude,
+ antitunneling,
+ itype);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ BasicParticleSystem &pts_sec;
+ ParticleDataImpl<Vec3> &v_sec;
+ ParticleDataImpl<Real> &l_sec;
+ const ParticleDataImpl<Vec3> &f_sec;
+ const FlagGrid &flags;
+ const MACGrid &v;
+ const Grid<Real> &neighborRatio;
+ const int radius;
+ const Vec3 gravity;
+ const Real k_b;
+ const Real k_d;
+ const Real c_s;
+ const Real c_b;
+ const Real dt;
+ const int exclude;
+ const int antitunneling;
+ const int itype;
+};
+
+void flipUpdateSecondaryParticles(const std::string mode,
+ BasicParticleSystem &pts_sec,
+ ParticleDataImpl<Vec3> &v_sec,
+ ParticleDataImpl<Real> &l_sec,
+ const ParticleDataImpl<Vec3> &f_sec,
+ FlagGrid &flags,
+ const MACGrid &v,
+ const Grid<Real> &neighborRatio,
+ const int radius,
+ const Vec3 gravity,
+ const Real k_b,
+ const Real k_d,
+ const Real c_s,
+ const Real c_b,
+ const Real dt,
+ const int exclude = ParticleBase::PTRACER,
+ const int antitunneling = 0,
+ const int itype = FlagGrid::TypeFluid)
+{
+
+ Vec3 g = gravity / flags.getDx();
+ if (mode == "linear") {
+ knFlipUpdateSecondaryParticlesLinear(pts_sec,
+ v_sec,
+ l_sec,
+ f_sec,
+ flags,
+ v,
+ neighborRatio,
+ g,
+ k_b,
+ k_d,
+ c_s,
+ c_b,
+ dt,
+ exclude,
+ antitunneling);
+ }
+ else if (mode == "cubic") {
+ knFlipUpdateSecondaryParticlesCubic(pts_sec,
+ v_sec,
+ l_sec,
+ f_sec,
+ flags,
+ v,
+ neighborRatio,
+ radius,
+ g,
+ k_b,
+ k_d,
+ c_s,
+ c_b,
+ dt,
+ exclude,
+ antitunneling,
+ itype);
+ }
+ else {
+ throw std::invalid_argument("Unknown mode: use \"linear\" or \"cubic\" instead!");
+ }
+ pts_sec.doCompress();
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "flipUpdateSecondaryParticles", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const std::string mode = _args.get<std::string>("mode", 0, &_lock);
+ BasicParticleSystem &pts_sec = *_args.getPtr<BasicParticleSystem>("pts_sec", 1, &_lock);
+ ParticleDataImpl<Vec3> &v_sec = *_args.getPtr<ParticleDataImpl<Vec3>>("v_sec", 2, &_lock);
+ ParticleDataImpl<Real> &l_sec = *_args.getPtr<ParticleDataImpl<Real>>("l_sec", 3, &_lock);
+ const ParticleDataImpl<Vec3> &f_sec = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "f_sec", 4, &_lock);
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 5, &_lock);
+ const MACGrid &v = *_args.getPtr<MACGrid>("v", 6, &_lock);
+ const Grid<Real> &neighborRatio = *_args.getPtr<Grid<Real>>("neighborRatio", 7, &_lock);
+ const int radius = _args.get<int>("radius", 8, &_lock);
+ const Vec3 gravity = _args.get<Vec3>("gravity", 9, &_lock);
+ const Real k_b = _args.get<Real>("k_b", 10, &_lock);
+ const Real k_d = _args.get<Real>("k_d", 11, &_lock);
+ const Real c_s = _args.get<Real>("c_s", 12, &_lock);
+ const Real c_b = _args.get<Real>("c_b", 13, &_lock);
+ const Real dt = _args.get<Real>("dt", 14, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 15, ParticleBase::PTRACER, &_lock);
+ const int antitunneling = _args.getOpt<int>("antitunneling", 16, 0, &_lock);
+ const int itype = _args.getOpt<int>("itype", 17, FlagGrid::TypeFluid, &_lock);
+ _retval = getPyNone();
+ flipUpdateSecondaryParticles(mode,
+ pts_sec,
+ v_sec,
+ l_sec,
+ f_sec,
+ flags,
+ v,
+ neighborRatio,
+ radius,
+ gravity,
+ k_b,
+ k_d,
+ c_s,
+ c_b,
+ dt,
+ exclude,
+ antitunneling,
+ itype);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipUpdateSecondaryParticles", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipUpdateSecondaryParticles", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipUpdateSecondaryParticles("",
+ "flipUpdateSecondaryParticles",
+ _W_2);
+extern "C" {
+void PbRegister_flipUpdateSecondaryParticles()
+{
+ KEEP_UNUSED(_RP_flipUpdateSecondaryParticles);
+}
+}
+
+// removes secondary particles in &pts_sec that are inside boundaries (cells that are marked as
+// obstacle/outflow in &flags)
+
+struct knFlipDeleteParticlesInObstacle : public KernelBase {
+ knFlipDeleteParticlesInObstacle(BasicParticleSystem &pts, const FlagGrid &flags)
+ : KernelBase(pts.size()), pts(pts), flags(flags)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, BasicParticleSystem &pts, const FlagGrid &flags) const
+ {
+
+ if (!pts.isActive(idx))
+ return;
+
+ const Vec3 &xi = pts[idx].pos;
+ const Vec3i xidx = toVec3i(xi);
+ // remove particles that completely left the bounds
+ if (!flags.isInBounds(xidx)) {
+ pts.kill(idx);
+ return;
+ }
+ int gridIndex = flags.index(xidx);
+ // remove particles that penetrate obstacles
+ if (flags[gridIndex] == FlagGrid::TypeObstacle || flags[gridIndex] == FlagGrid::TypeOutflow) {
+ pts.kill(idx);
+ }
+ }
+ inline BasicParticleSystem &getArg0()
+ {
+ return pts;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipDeleteParticlesInObstacle ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, pts, flags);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ BasicParticleSystem &pts;
+ const FlagGrid &flags;
+};
+
+void flipDeleteParticlesInObstacle(BasicParticleSystem &pts, const FlagGrid &flags)
+{
+
+ knFlipDeleteParticlesInObstacle(pts, flags);
+ pts.doCompress();
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "flipDeleteParticlesInObstacle", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ BasicParticleSystem &pts = *_args.getPtr<BasicParticleSystem>("pts", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ _retval = getPyNone();
+ flipDeleteParticlesInObstacle(pts, flags);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipDeleteParticlesInObstacle", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipDeleteParticlesInObstacle", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipDeleteParticlesInObstacle("",
+ "flipDeleteParticlesInObstacle",
+ _W_3);
+extern "C" {
+void PbRegister_flipDeleteParticlesInObstacle()
+{
+ KEEP_UNUSED(_RP_flipDeleteParticlesInObstacle);
+}
+}
+
+// helper method to debug statistical data from grid
+
+void debugGridInfo(const FlagGrid &flags,
+ Grid<Real> &grid,
+ std::string name,
+ const int itype = FlagGrid::TypeFluid)
+{
+ FluidSolver *s = flags.getParent();
+ int countFluid = 0;
+ int countLargerZero = 0;
+ Real avg = 0;
+ Real max = 0;
+ Real sum = 0;
+ Real avgLargerZero = 0;
+ FOR_IJK_BND(grid, 1)
+ {
+ if (!(flags(i, j, k) & itype))
+ continue;
+ countFluid++;
+ if (grid(i, j, k) > 0)
+ countLargerZero++;
+ sum += grid(i, j, k);
+ if (grid(i, j, k) > max)
+ max = grid(i, j, k);
+ }
+ avg = sum / std::max(Real(countFluid), Real(1));
+ avgLargerZero = sum / std::max(Real(countLargerZero), Real(1));
+
+ debMsg("Step: " << s->mFrame << " - Grid " << name << "\n\tcountFluid \t\t" << countFluid
+ << "\n\tcountLargerZero \t" << countLargerZero << "\n\tsum \t\t\t" << sum
+ << "\n\tavg \t\t\t" << avg << "\n\tavgLargerZero \t\t" << avgLargerZero
+ << "\n\tmax \t\t\t" << max,
+ 1);
+}
+static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "debugGridInfo", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &grid = *_args.getPtr<Grid<Real>>("grid", 1, &_lock);
+ std::string name = _args.get<std::string>("name", 2, &_lock);
+ const int itype = _args.getOpt<int>("itype", 3, FlagGrid::TypeFluid, &_lock);
+ _retval = getPyNone();
+ debugGridInfo(flags, grid, name, itype);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "debugGridInfo", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("debugGridInfo", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_debugGridInfo("", "debugGridInfo", _W_4);
+extern "C" {
+void PbRegister_debugGridInfo()
+{
+ KEEP_UNUSED(_RP_debugGridInfo);
+}
+}
+
+// The following methods are helper functions to recreate the velocity and flag grid from the
+// underlying FLIP simulation. They cannot simply be loaded because of the upres to a higher
+// resolution, instead a levelset is used.
+
+struct knSetFlagsFromLevelset : public KernelBase {
+ knSetFlagsFromLevelset(FlagGrid &flags,
+ const Grid<Real> &phi,
+ const int exclude = FlagGrid::TypeObstacle,
+ const int itype = FlagGrid::TypeFluid)
+ : KernelBase(&flags, 0), flags(flags), phi(phi), exclude(exclude), itype(itype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ FlagGrid &flags,
+ const Grid<Real> &phi,
+ const int exclude = FlagGrid::TypeObstacle,
+ const int itype = FlagGrid::TypeFluid) const
+ {
+ if (phi(idx) < 0 && !(flags(idx) & exclude))
+ flags(idx) = itype;
+ }
+ inline FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type1;
+ inline const int &getArg2()
+ {
+ return exclude;
+ }
+ typedef int type2;
+ inline const int &getArg3()
+ {
+ return itype;
+ }
+ typedef int type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetFlagsFromLevelset ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, flags, phi, exclude, itype);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ FlagGrid &flags;
+ const Grid<Real> &phi;
+ const int exclude;
+ const int itype;
+};
+
+void setFlagsFromLevelset(FlagGrid &flags,
+ const Grid<Real> &phi,
+ const int exclude = FlagGrid::TypeObstacle,
+ const int itype = FlagGrid::TypeFluid)
+{
+ knSetFlagsFromLevelset(flags, phi, exclude, itype);
+}
+static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setFlagsFromLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const Grid<Real> &phi = *_args.getPtr<Grid<Real>>("phi", 1, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 2, FlagGrid::TypeObstacle, &_lock);
+ const int itype = _args.getOpt<int>("itype", 3, FlagGrid::TypeFluid, &_lock);
+ _retval = getPyNone();
+ setFlagsFromLevelset(flags, phi, exclude, itype);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setFlagsFromLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setFlagsFromLevelset", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setFlagsFromLevelset("", "setFlagsFromLevelset", _W_5);
+extern "C" {
+void PbRegister_setFlagsFromLevelset()
+{
+ KEEP_UNUSED(_RP_setFlagsFromLevelset);
+}
+}
+
+struct knSetMACFromLevelset : public KernelBase {
+ knSetMACFromLevelset(MACGrid &v, const Grid<Real> &phi, const Vec3 c)
+ : KernelBase(&v, 0), v(v), phi(phi), c(c)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, MACGrid &v, const Grid<Real> &phi, const Vec3 c) const
+ {
+ if (phi.getInterpolated(Vec3(i, j, k)) > 0)
+ v(i, j, k) = c;
+ }
+ inline MACGrid &getArg0()
+ {
+ return v;
+ }
+ typedef MACGrid type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type1;
+ inline const Vec3 &getArg2()
+ {
+ return c;
+ }
+ typedef Vec3 type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetMACFromLevelset ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, v, phi, c);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, v, phi, c);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ MACGrid &v;
+ const Grid<Real> &phi;
+ const Vec3 c;
+};
+
+void setMACFromLevelset(MACGrid &v, const Grid<Real> &phi, const Vec3 c)
+{
+ knSetMACFromLevelset(v, phi, c);
+}
+static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "setMACFromLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &v = *_args.getPtr<MACGrid>("v", 0, &_lock);
+ const Grid<Real> &phi = *_args.getPtr<Grid<Real>>("phi", 1, &_lock);
+ const Vec3 c = _args.get<Vec3>("c", 2, &_lock);
+ _retval = getPyNone();
+ setMACFromLevelset(v, phi, c);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "setMACFromLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("setMACFromLevelset", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_setMACFromLevelset("", "setMACFromLevelset", _W_6);
+extern "C" {
+void PbRegister_setMACFromLevelset()
+{
+ KEEP_UNUSED(_RP_setMACFromLevelset);
+}
+}
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+// END Secondary Particles for FLIP
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+#pragma endregion
+
+#pragma region Legacy Methods(still useful for debugging)
+//-----------------------------------------------------------------------------------------------------------------------------------
+//-----------------
+// Legacy Methods (still useful for debugging)
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes trapped air potential for all fluid cells in &flags and saves it in &pot
+
+struct knFlipComputePotentialTrappedAir : public KernelBase {
+ knFlipComputePotentialTrappedAir(Grid<Real> &pot,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const int radius,
+ const Real tauMin,
+ const Real tauMax,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeFluid)
+ : KernelBase(&pot, 1),
+ pot(pot),
+ flags(flags),
+ v(v),
+ radius(radius),
+ tauMin(tauMin),
+ tauMax(tauMax),
+ scaleFromManta(scaleFromManta),
+ itype(itype),
+ jtype(jtype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<Real> &pot,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const int radius,
+ const Real tauMin,
+ const Real tauMax,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeFluid) const
+ {
+
+ if (!(flags(i, j, k) & itype))
+ return;
+
+ const Vec3 &xi = scaleFromManta * Vec3(i, j, k); // scale to unit cube
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k);
+ Real vdiff = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || !(flags(x, y, z) & jtype))
+ continue;
+
+ const Vec3 &xj = scaleFromManta * Vec3(x, y, z); // scale to unit cube
+ const Vec3 &vj = scaleFromManta * v.getCentered(x, y, z);
+ const Vec3 xij = xi - xj;
+ const Vec3 vij = vi - vj;
+ Real h = !pot.is3D() ? 1.414 * radius :
+ 1.732 * radius; // estimate sqrt(2)*radius resp. sqrt(3)*radius
+ // for h, due to squared resp. cubic neighbor area
+ vdiff += norm(vij) * (1 - dot(getNormalized(vij), getNormalized(xij))) *
+ (1 - norm(xij) / h);
+ }
+ }
+ }
+ pot(i, j, k) = (std::min(vdiff, tauMax) - std::min(vdiff, tauMin)) / (tauMax - tauMin);
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return pot;
+ }
+ typedef Grid<Real> type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return v;
+ }
+ typedef MACGrid type2;
+ inline const int &getArg3()
+ {
+ return radius;
+ }
+ typedef int type3;
+ inline const Real &getArg4()
+ {
+ return tauMin;
+ }
+ typedef Real type4;
+ inline const Real &getArg5()
+ {
+ return tauMax;
+ }
+ typedef Real type5;
+ inline const Real &getArg6()
+ {
+ return scaleFromManta;
+ }
+ typedef Real type6;
+ inline const int &getArg7()
+ {
+ return itype;
+ }
+ typedef int type7;
+ inline const int &getArg8()
+ {
+ return jtype;
+ }
+ typedef int type8;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipComputePotentialTrappedAir ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, pot, flags, v, radius, tauMin, tauMax, scaleFromManta, itype, jtype);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, pot, flags, v, radius, tauMin, tauMax, scaleFromManta, itype, jtype);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<Real> &pot;
+ const FlagGrid &flags;
+ const MACGrid &v;
+ const int radius;
+ const Real tauMin;
+ const Real tauMax;
+ const Real scaleFromManta;
+ const int itype;
+ const int jtype;
+};
+
+void flipComputePotentialTrappedAir(Grid<Real> &pot,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const int radius,
+ const Real tauMin,
+ const Real tauMax,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeFluid)
+{
+ pot.clear();
+ knFlipComputePotentialTrappedAir(
+ pot, flags, v, radius, tauMin, tauMax, scaleFromManta, itype, jtype);
+}
+static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "flipComputePotentialTrappedAir", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &pot = *_args.getPtr<Grid<Real>>("pot", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ const MACGrid &v = *_args.getPtr<MACGrid>("v", 2, &_lock);
+ const int radius = _args.get<int>("radius", 3, &_lock);
+ const Real tauMin = _args.get<Real>("tauMin", 4, &_lock);
+ const Real tauMax = _args.get<Real>("tauMax", 5, &_lock);
+ const Real scaleFromManta = _args.get<Real>("scaleFromManta", 6, &_lock);
+ const int itype = _args.getOpt<int>("itype", 7, FlagGrid::TypeFluid, &_lock);
+ const int jtype = _args.getOpt<int>("jtype", 8, FlagGrid::TypeFluid, &_lock);
+ _retval = getPyNone();
+ flipComputePotentialTrappedAir(
+ pot, flags, v, radius, tauMin, tauMax, scaleFromManta, itype, jtype);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipComputePotentialTrappedAir", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipComputePotentialTrappedAir", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipComputePotentialTrappedAir("",
+ "flipComputePotentialTrappedAir",
+ _W_7);
+extern "C" {
+void PbRegister_flipComputePotentialTrappedAir()
+{
+ KEEP_UNUSED(_RP_flipComputePotentialTrappedAir);
+}
+}
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes kinetic energy potential for all fluid cells in &flags and saves it in &pot
+
+struct knFlipComputePotentialKineticEnergy : public KernelBase {
+ knFlipComputePotentialKineticEnergy(Grid<Real> &pot,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const Real tauMin,
+ const Real tauMax,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid)
+ : KernelBase(&pot, 0),
+ pot(pot),
+ flags(flags),
+ v(v),
+ tauMin(tauMin),
+ tauMax(tauMax),
+ scaleFromManta(scaleFromManta),
+ itype(itype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<Real> &pot,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const Real tauMin,
+ const Real tauMax,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid) const
+ {
+
+ if (!(flags(i, j, k) & itype))
+ return;
+
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k); // scale to unit cube
+ Real ek =
+ Real(0.5) * 125 *
+ normSquare(
+ vi); // use arbitrary constant for mass, potential adjusts with thresholds anyways
+ pot(i, j, k) = (std::min(ek, tauMax) - std::min(ek, tauMin)) / (tauMax - tauMin);
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return pot;
+ }
+ typedef Grid<Real> type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return v;
+ }
+ typedef MACGrid type2;
+ inline const Real &getArg3()
+ {
+ return tauMin;
+ }
+ typedef Real type3;
+ inline const Real &getArg4()
+ {
+ return tauMax;
+ }
+ typedef Real type4;
+ inline const Real &getArg5()
+ {
+ return scaleFromManta;
+ }
+ typedef Real type5;
+ inline const int &getArg6()
+ {
+ return itype;
+ }
+ typedef int type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipComputePotentialKineticEnergy ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, pot, flags, v, tauMin, tauMax, scaleFromManta, itype);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, pot, flags, v, tauMin, tauMax, scaleFromManta, itype);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<Real> &pot;
+ const FlagGrid &flags;
+ const MACGrid &v;
+ const Real tauMin;
+ const Real tauMax;
+ const Real scaleFromManta;
+ const int itype;
+};
+
+void flipComputePotentialKineticEnergy(Grid<Real> &pot,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const Real tauMin,
+ const Real tauMax,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid)
+{
+ pot.clear();
+ knFlipComputePotentialKineticEnergy(pot, flags, v, tauMin, tauMax, scaleFromManta, itype);
+}
+static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "flipComputePotentialKineticEnergy", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &pot = *_args.getPtr<Grid<Real>>("pot", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ const MACGrid &v = *_args.getPtr<MACGrid>("v", 2, &_lock);
+ const Real tauMin = _args.get<Real>("tauMin", 3, &_lock);
+ const Real tauMax = _args.get<Real>("tauMax", 4, &_lock);
+ const Real scaleFromManta = _args.get<Real>("scaleFromManta", 5, &_lock);
+ const int itype = _args.getOpt<int>("itype", 6, FlagGrid::TypeFluid, &_lock);
+ _retval = getPyNone();
+ flipComputePotentialKineticEnergy(pot, flags, v, tauMin, tauMax, scaleFromManta, itype);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipComputePotentialKineticEnergy", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipComputePotentialKineticEnergy", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipComputePotentialKineticEnergy(
+ "", "flipComputePotentialKineticEnergy", _W_8);
+extern "C" {
+void PbRegister_flipComputePotentialKineticEnergy()
+{
+ KEEP_UNUSED(_RP_flipComputePotentialKineticEnergy);
+}
+}
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes wave crest potential for all fluid cells in &flags and saves it in &pot
+
+struct knFlipComputePotentialWaveCrest : public KernelBase {
+ knFlipComputePotentialWaveCrest(Grid<Real> &pot,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const int radius,
+ Grid<Vec3> &normal,
+ const Real tauMin,
+ const Real tauMax,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeFluid)
+ : KernelBase(&pot, 1),
+ pot(pot),
+ flags(flags),
+ v(v),
+ radius(radius),
+ normal(normal),
+ tauMin(tauMin),
+ tauMax(tauMax),
+ scaleFromManta(scaleFromManta),
+ itype(itype),
+ jtype(jtype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<Real> &pot,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const int radius,
+ Grid<Vec3> &normal,
+ const Real tauMin,
+ const Real tauMax,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeFluid) const
+ {
+
+ if (!(flags(i, j, k) & itype))
+ return;
+
+ const Vec3 &xi = scaleFromManta * Vec3(i, j, k); // scale to unit cube
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k);
+ const Vec3 &ni = normal(i, j, k);
+ Real kappa = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || !(flags(x, y, z) & jtype))
+ continue;
+ const Vec3 &xj = scaleFromManta * Vec3(x, y, z); // scale to unit cube
+ const Vec3 &nj = normal(x, y, z);
+ const Vec3 xij = xi - xj;
+ if (dot(getNormalized(xij), ni) < 0) { // identifies wave crests
+ Real h = !pot.is3D() ?
+ 1.414 * radius :
+ 1.732 * radius; // estimate sqrt(2)*radius resp. sqrt(3)*radius for h,
+ // due to squared resp. cubic neighbor area
+ kappa += (1 - dot(ni, nj)) * (1 - norm(xij) / h);
+ }
+ }
+ }
+ }
+
+ if (dot(getNormalized(vi), ni) >= 0.6) { // avoid to mark boarders of the scene as wave crest
+ pot(i, j, k) = (std::min(kappa, tauMax) - std::min(kappa, tauMin)) / (tauMax - tauMin);
+ }
+ else {
+ pot(i, j, k) = Real(0);
+ }
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return pot;
+ }
+ typedef Grid<Real> type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return v;
+ }
+ typedef MACGrid type2;
+ inline const int &getArg3()
+ {
+ return radius;
+ }
+ typedef int type3;
+ inline Grid<Vec3> &getArg4()
+ {
+ return normal;
+ }
+ typedef Grid<Vec3> type4;
+ inline const Real &getArg5()
+ {
+ return tauMin;
+ }
+ typedef Real type5;
+ inline const Real &getArg6()
+ {
+ return tauMax;
+ }
+ typedef Real type6;
+ inline const Real &getArg7()
+ {
+ return scaleFromManta;
+ }
+ typedef Real type7;
+ inline const int &getArg8()
+ {
+ return itype;
+ }
+ typedef int type8;
+ inline const int &getArg9()
+ {
+ return jtype;
+ }
+ typedef int type9;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipComputePotentialWaveCrest ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ pot,
+ flags,
+ v,
+ radius,
+ normal,
+ tauMin,
+ tauMax,
+ scaleFromManta,
+ itype,
+ jtype);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, pot, flags, v, radius, normal, tauMin, tauMax, scaleFromManta, itype, jtype);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ Grid<Real> &pot;
+ const FlagGrid &flags;
+ const MACGrid &v;
+ const int radius;
+ Grid<Vec3> &normal;
+ const Real tauMin;
+ const Real tauMax;
+ const Real scaleFromManta;
+ const int itype;
+ const int jtype;
+};
+
+void flipComputePotentialWaveCrest(Grid<Real> &pot,
+ const FlagGrid &flags,
+ const MACGrid &v,
+ const int radius,
+ Grid<Vec3> &normal,
+ const Real tauMin,
+ const Real tauMax,
+ const Real scaleFromManta,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeFluid)
+{
+
+ pot.clear();
+ knFlipComputePotentialWaveCrest(
+ pot, flags, v, radius, normal, tauMin, tauMax, scaleFromManta, itype, jtype);
+}
+static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "flipComputePotentialWaveCrest", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &pot = *_args.getPtr<Grid<Real>>("pot", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ const MACGrid &v = *_args.getPtr<MACGrid>("v", 2, &_lock);
+ const int radius = _args.get<int>("radius", 3, &_lock);
+ Grid<Vec3> &normal = *_args.getPtr<Grid<Vec3>>("normal", 4, &_lock);
+ const Real tauMin = _args.get<Real>("tauMin", 5, &_lock);
+ const Real tauMax = _args.get<Real>("tauMax", 6, &_lock);
+ const Real scaleFromManta = _args.get<Real>("scaleFromManta", 7, &_lock);
+ const int itype = _args.getOpt<int>("itype", 8, FlagGrid::TypeFluid, &_lock);
+ const int jtype = _args.getOpt<int>("jtype", 9, FlagGrid::TypeFluid, &_lock);
+ _retval = getPyNone();
+ flipComputePotentialWaveCrest(
+ pot, flags, v, radius, normal, tauMin, tauMax, scaleFromManta, itype, jtype);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipComputePotentialWaveCrest", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipComputePotentialWaveCrest", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipComputePotentialWaveCrest("",
+ "flipComputePotentialWaveCrest",
+ _W_9);
+extern "C" {
+void PbRegister_flipComputePotentialWaveCrest()
+{
+ KEEP_UNUSED(_RP_flipComputePotentialWaveCrest);
+}
+}
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes normal grid &normal as gradient of levelset &phi and normalizes it
+
+struct knFlipComputeSurfaceNormals : public KernelBase {
+ knFlipComputeSurfaceNormals(Grid<Vec3> &normal, const Grid<Real> &phi)
+ : KernelBase(&normal, 0), normal(normal), phi(phi)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<Vec3> &normal, const Grid<Real> &phi) const
+ {
+ normal[idx] = getNormalized(normal[idx]);
+ }
+ inline Grid<Vec3> &getArg0()
+ {
+ return normal;
+ }
+ typedef Grid<Vec3> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipComputeSurfaceNormals ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, normal, phi);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Vec3> &normal;
+ const Grid<Real> &phi;
+};
+
+void flipComputeSurfaceNormals(Grid<Vec3> &normal, const Grid<Real> &phi)
+{
+ GradientOp(normal, phi);
+ knFlipComputeSurfaceNormals(normal, phi);
+}
+static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "flipComputeSurfaceNormals", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &normal = *_args.getPtr<Grid<Vec3>>("normal", 0, &_lock);
+ const Grid<Real> &phi = *_args.getPtr<Grid<Real>>("phi", 1, &_lock);
+ _retval = getPyNone();
+ flipComputeSurfaceNormals(normal, phi);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipComputeSurfaceNormals", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipComputeSurfaceNormals", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipComputeSurfaceNormals("", "flipComputeSurfaceNormals", _W_10);
+extern "C" {
+void PbRegister_flipComputeSurfaceNormals()
+{
+ KEEP_UNUSED(_RP_flipComputeSurfaceNormals);
+}
+}
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes the neighbor ratio for every fluid cell in &flags as the number of fluid neighbors over
+// the maximum possible number of fluid neighbors
+
+struct knFlipUpdateNeighborRatio : public KernelBase {
+ knFlipUpdateNeighborRatio(const FlagGrid &flags,
+ Grid<Real> &neighborRatio,
+ const int radius,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeObstacle)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ neighborRatio(neighborRatio),
+ radius(radius),
+ itype(itype),
+ jtype(jtype)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Real> &neighborRatio,
+ const int radius,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeObstacle) const
+ {
+
+ if (!(flags(i, j, k) & itype))
+ return;
+
+ int countFluid = 0;
+ int countMaxFluid = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || (flags(x, y, z) & jtype))
+ continue;
+ if (flags(x, y, z) & itype) {
+ countFluid++;
+ countMaxFluid++;
+ }
+ else {
+ countMaxFluid++;
+ }
+ }
+ }
+ }
+ neighborRatio(i, j, k) = float(countFluid) / float(countMaxFluid);
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return neighborRatio;
+ }
+ typedef Grid<Real> type1;
+ inline const int &getArg2()
+ {
+ return radius;
+ }
+ typedef int type2;
+ inline const int &getArg3()
+ {
+ return itype;
+ }
+ typedef int type3;
+ inline const int &getArg4()
+ {
+ return jtype;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knFlipUpdateNeighborRatio ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, neighborRatio, radius, itype, jtype);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, neighborRatio, radius, itype, jtype);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &neighborRatio;
+ const int radius;
+ const int itype;
+ const int jtype;
+};
+
+void flipUpdateNeighborRatio(const FlagGrid &flags,
+ Grid<Real> &neighborRatio,
+ const int radius,
+ const int itype = FlagGrid::TypeFluid,
+ const int jtype = FlagGrid::TypeObstacle)
+{
+
+ neighborRatio.clear();
+ knFlipUpdateNeighborRatio(flags, neighborRatio, radius, itype, jtype);
+}
+static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "flipUpdateNeighborRatio", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &neighborRatio = *_args.getPtr<Grid<Real>>("neighborRatio", 1, &_lock);
+ const int radius = _args.get<int>("radius", 2, &_lock);
+ const int itype = _args.getOpt<int>("itype", 3, FlagGrid::TypeFluid, &_lock);
+ const int jtype = _args.getOpt<int>("jtype", 4, FlagGrid::TypeObstacle, &_lock);
+ _retval = getPyNone();
+ flipUpdateNeighborRatio(flags, neighborRatio, radius, itype, jtype);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipUpdateNeighborRatio", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipUpdateNeighborRatio", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipUpdateNeighborRatio("", "flipUpdateNeighborRatio", _W_11);
+extern "C" {
+void PbRegister_flipUpdateNeighborRatio()
+{
+ KEEP_UNUSED(_RP_flipUpdateNeighborRatio);
+}
+}
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+// Legacy Methods (still useful for debugging)
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+#pragma endregion
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/surfaceturbulence.cpp b/extern/mantaflow/preprocessed/plugin/surfaceturbulence.cpp
new file mode 100644
index 00000000000..465314f51ed
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/surfaceturbulence.cpp
@@ -0,0 +1,2189 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2016 Olivier Mercier, oli.mercier@gmail.com
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Surface Turbulence for Particle-Based Liquid Simulations
+ * Mercier et al., SIGGRAPH Asia 2015
+ *
+ * Possible speedups :
+ * - only initialize surface points around coarse particles near the surface. Use the flags in the
+ *fluid grid and only use cells with non-fluid neighbors.
+ *
+ ******************************************************************************/
+
+// use chrono stl for detailed timing only if available
+#ifdef __GNUC__
+# if __GNUC__ < 5
+# define USE_CHRONO 0
+# endif
+#endif
+
+#if MANTA_WITHCPP11 == 1
+# ifndef USE_CHRONO
+# define USE_CHRONO 1
+# endif
+#endif
+
+#include <iomanip>
+#if USE_CHRONO == 1
+# include <chrono>
+#endif
+#include "particle.h"
+
+using namespace std;
+namespace Manta {
+
+// own namespace for globals
+namespace SurfaceTurbulence {
+
+//
+// **** surface turbulence parameters ****
+//
+struct SurfaceTurbulenceParameters {
+ int res;
+ Real outerRadius;
+ int surfaceDensity;
+ int nbSurfaceMaintenanceIterations;
+ Real dt;
+ Real waveSpeed;
+ Real waveDamping;
+ Real waveSeedFrequency;
+ Real waveMaxAmplitude;
+ Real waveMaxFrequency;
+ Real waveMaxSeedingAmplitude; // as ratio of max amp;
+ Real waveSeedingCurvatureThresholdRegionCenter;
+ Real waveSeedingCurvatureThresholdRegionRadius;
+ Real waveSeedStepSizeRatioOfMax;
+ Real innerRadius;
+ Real meanFineDistance;
+ Real constraintA;
+ Real normalRadius;
+ Real tangentRadius;
+ Real bndXm, bndXp, bndYm, bndYp, bndZm, bndZp;
+};
+SurfaceTurbulenceParameters params;
+
+//
+// **** acceleration grid for particle neighbor queries ****
+//
+struct ParticleAccelGrid {
+ int res;
+ vector<int> ***indices;
+
+ void init(int inRes)
+ {
+ res = inRes;
+ indices = new vector<int> **[res];
+ for (int i = 0; i < res; i++) {
+ indices[i] = new vector<int> *[res];
+ for (int j = 0; j < res; j++) {
+ indices[i][j] = new vector<int>[res];
+ }
+ }
+ }
+
+ void fillWith(const BasicParticleSystem &particles)
+ {
+ // clear
+ for (int i = 0; i < res; i++) {
+ for (int j = 0; j < res; j++) {
+ for (int k = 0; k < res; k++) {
+ indices[i][j][k].clear();
+ }
+ }
+ }
+
+ // fill
+ for (int id = 0; id < particles.size(); id++) {
+ Vec3 pos = particles.getPos(id);
+ int i = clamp<int>(floor(pos.x / params.res * res), 0, res - 1);
+ int j = clamp<int>(floor(pos.y / params.res * res), 0, res - 1);
+ int k = clamp<int>(floor(pos.z / params.res * res), 0, res - 1);
+ indices[i][j][k].push_back(id);
+ }
+ }
+
+ void fillWith(const ParticleDataImpl<Vec3> &particles)
+ {
+ // clear
+ for (int i = 0; i < res; i++) {
+ for (int j = 0; j < res; j++) {
+ for (int k = 0; k < res; k++) {
+ indices[i][j][k].clear();
+ }
+ }
+ }
+
+ // fill
+ for (int id = 0; id < particles.size(); id++) {
+ Vec3 pos = particles[id];
+ int i = clamp<int>(floor(pos.x / params.res * res), 0, res - 1);
+ int j = clamp<int>(floor(pos.y / params.res * res), 0, res - 1);
+ int k = clamp<int>(floor(pos.z / params.res * res), 0, res - 1);
+ indices[i][j][k].push_back(id);
+ }
+ }
+};
+
+#define LOOP_NEIGHBORS_BEGIN(points, center, radius) \
+ int minI = clamp<int>( \
+ floor((center.x - radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
+ int maxI = clamp<int>( \
+ floor((center.x + radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
+ int minJ = clamp<int>( \
+ floor((center.y - radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
+ int maxJ = clamp<int>( \
+ floor((center.y + radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
+ int minK = clamp<int>( \
+ floor((center.z - radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
+ int maxK = clamp<int>( \
+ floor((center.z + radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
+ for (int i = minI; i <= maxI; i++) { \
+ for (int j = minJ; j <= maxJ; j++) { \
+ for (int k = minK; k <= maxK; k++) { \
+ for (int idLOOPNEIGHBORS = 0; \
+ idLOOPNEIGHBORS < (int)points.accel->indices[i][j][k].size(); \
+ idLOOPNEIGHBORS++) { \
+ int idn = points.accel->indices[i][j][k][idLOOPNEIGHBORS]; \
+ if (points.isActive(idn)) {
+#define LOOP_NEIGHBORS_END \
+ } \
+ } \
+ } \
+ } \
+ }
+
+#define LOOP_GHOSTS_POS_BEGIN(pos, radius) \
+ int flagLOOPGHOSTS = -1; \
+ Vec3 gPos; \
+ while (flagLOOPGHOSTS < 6) { \
+ if (flagLOOPGHOSTS < 0 && pos.x - params.bndXm <= radius) { \
+ flagLOOPGHOSTS = 0; \
+ gPos = Vec3(2.f * params.bndXm - pos.x, pos.y, pos.z); \
+ } \
+ else if (flagLOOPGHOSTS < 1 && params.bndXp - pos.x <= radius) { \
+ flagLOOPGHOSTS = 1; \
+ gPos = Vec3(2.f * params.bndXp - pos.x, pos.y, pos.z); \
+ } \
+ else if (flagLOOPGHOSTS < 2 && pos.y - params.bndYm <= radius) { \
+ flagLOOPGHOSTS = 2; \
+ gPos = Vec3(pos.x, 2.f * params.bndYm - pos.y, pos.z); \
+ } \
+ else if (flagLOOPGHOSTS < 3 && params.bndYp - pos.y <= radius) { \
+ flagLOOPGHOSTS = 3; \
+ gPos = Vec3(pos.x, 2.f * params.bndYp - pos.y, pos.z); \
+ } \
+ else if (flagLOOPGHOSTS < 4 && pos.z - params.bndZm <= radius) { \
+ flagLOOPGHOSTS = 4; \
+ gPos = Vec3(pos.x, pos.y, 2.f * params.bndZm - pos.z); \
+ } \
+ else if (flagLOOPGHOSTS < 5 && params.bndZp - pos.Z <= radius) { \
+ flagLOOPGHOSTS = 5; \
+ gPos = Vec3(pos.x, pos.y, 2.f * params.bndZp - pos.z); \
+ } \
+ else { \
+ flagLOOPGHOSTS = 6; \
+ gPos = Vec3(pos.x, pos.y, pos.z); \
+ }
+#define LOOP_GHOSTS_POS_NORMAL_BEGIN(pos, normal, radius) \
+ int flagLOOPGHOSTS = -1; \
+ Vec3 gPos, gNormal; \
+ while (flagLOOPGHOSTS < 6) { \
+ if (flagLOOPGHOSTS < 0 && pos.x - params.bndXm <= radius) { \
+ flagLOOPGHOSTS = 0; \
+ gPos = Vec3(2.f * params.bndXm - pos.x, pos.y, pos.z); \
+ gNormal = Vec3(-normal.x, normal.y, normal.z); \
+ } \
+ else if (flagLOOPGHOSTS < 1 && params.bndXp - pos.x <= radius) { \
+ flagLOOPGHOSTS = 1; \
+ gPos = Vec3(2.f * params.bndXp - pos.x, pos.y, pos.z); \
+ gNormal = Vec3(-normal.x, normal.y, normal.z); \
+ } \
+ else if (flagLOOPGHOSTS < 2 && pos.y - params.bndYm <= radius) { \
+ flagLOOPGHOSTS = 2; \
+ gPos = Vec3(pos.x, 2.f * params.bndYm - pos.y, pos.z); \
+ gNormal = Vec3(normal.x, -normal.y, normal.z); \
+ } \
+ else if (flagLOOPGHOSTS < 3 && params.bndYp - pos.y <= radius) { \
+ flagLOOPGHOSTS = 3; \
+ gPos = Vec3(pos.x, 2.f * params.bndYp - pos.y, pos.z); \
+ gNormal = Vec3(normal.x, -normal.y, normal.z); \
+ } \
+ else if (flagLOOPGHOSTS < 4 && pos.z - params.bndZm <= radius) { \
+ flagLOOPGHOSTS = 4; \
+ gPos = Vec3(pos.x, pos.y, 2.f * params.bndZm - pos.z); \
+ gNormal = Vec3(normal.x, normal.y, -normal.z); \
+ } \
+ else if (flagLOOPGHOSTS < 5 && params.bndZp - pos.Z <= radius) { \
+ flagLOOPGHOSTS = 5; \
+ gPos = Vec3(pos.x, pos.y, 2.f * params.bndZp - pos.z); \
+ gNormal = Vec3(normal.x, normal.y, -normal.z); \
+ } \
+ else { \
+ flagLOOPGHOSTS = 6; \
+ gPos = pos; \
+ gNormal = normal; \
+ }
+#define LOOP_GHOSTS_END }
+
+//
+// **** Wrappers around point sets to attach it an acceleration grid ****
+//
+struct PointSetWrapper {
+ ParticleAccelGrid *accel;
+
+ PointSetWrapper(ParticleAccelGrid *inAccel)
+ {
+ accel = inAccel;
+ }
+ virtual void updateAccel() = 0;
+};
+
+struct BasicParticleSystemWrapper : PointSetWrapper {
+ BasicParticleSystem *points;
+
+ BasicParticleSystemWrapper(ParticleAccelGrid *inAccel) : PointSetWrapper(inAccel)
+ {
+ }
+
+ Vec3 getPos(int id) const
+ {
+ return points->getPos(id);
+ }
+ void setPos(int id, Vec3 pos)
+ {
+ points->setPos(id, pos);
+ }
+ void updateAccel()
+ {
+ accel->fillWith(*points);
+ }
+ void clear()
+ {
+ points->clear();
+ }
+ int size() const
+ {
+ return points->size();
+ }
+ bool isActive(int id) const
+ {
+ return points->isActive(id);
+ }
+ void addParticle(Vec3 pos)
+ {
+ points->addParticle(pos);
+ }
+ int getStatus(int id) const
+ {
+ return points->getStatus(id);
+ }
+ void addBuffered(Vec3 pos)
+ {
+ points->addBuffered(pos);
+ }
+ void doCompress()
+ {
+ points->doCompress();
+ }
+ void insertBufferedParticles()
+ {
+ points->insertBufferedParticles();
+ }
+ void kill(int id)
+ {
+ points->kill(id);
+ }
+
+ bool hasNeighbor(Vec3 pos, Real radius) const
+ {
+ bool answer = false;
+ int minI = clamp<int>(floor((pos.x - radius) / params.res * accel->res), 0, accel->res - 1);
+ int maxI = clamp<int>(floor((pos.x + radius) / params.res * accel->res), 0, accel->res - 1);
+ int minJ = clamp<int>(floor((pos.y - radius) / params.res * accel->res), 0, accel->res - 1);
+ int maxJ = clamp<int>(floor((pos.y + radius) / params.res * accel->res), 0, accel->res - 1);
+ int minK = clamp<int>(floor((pos.z - radius) / params.res * accel->res), 0, accel->res - 1);
+ int maxK = clamp<int>(floor((pos.z + radius) / params.res * accel->res), 0, accel->res - 1);
+ for (int i = minI; i <= maxI; i++) {
+ for (int j = minJ; j <= maxJ; j++) {
+ for (int k = minK; k <= maxK; k++) {
+ for (int id = 0; id < (int)accel->indices[i][j][k].size(); id++) {
+ if (points->isActive(accel->indices[i][j][k][id]) &&
+ norm(points->getPos(accel->indices[i][j][k][id]) - pos) <= radius) {
+ answer = true;
+ break;
+ }
+ }
+ if (answer)
+ break;
+ }
+ if (answer)
+ break;
+ }
+ if (answer)
+ break;
+ }
+ return answer;
+ }
+
+ bool hasNeighborOtherThanItself(int idx, Real radius) const
+ {
+ bool answer = false;
+ Vec3 pos = points->getPos(idx);
+ int minI = clamp<int>(floor((pos.x - radius) / params.res * accel->res), 0, accel->res - 1);
+ int maxI = clamp<int>(floor((pos.x + radius) / params.res * accel->res), 0, accel->res - 1);
+ int minJ = clamp<int>(floor((pos.y - radius) / params.res * accel->res), 0, accel->res - 1);
+ int maxJ = clamp<int>(floor((pos.y + radius) / params.res * accel->res), 0, accel->res - 1);
+ int minK = clamp<int>(floor((pos.z - radius) / params.res * accel->res), 0, accel->res - 1);
+ int maxK = clamp<int>(floor((pos.z + radius) / params.res * accel->res), 0, accel->res - 1);
+ for (int i = minI; i <= maxI; i++) {
+ for (int j = minJ; j <= maxJ; j++) {
+ for (int k = minK; k <= maxK; k++) {
+ for (int id = 0; id < (int)accel->indices[i][j][k].size(); id++) {
+ if (accel->indices[i][j][k][id] != idx &&
+ points->isActive(accel->indices[i][j][k][id]) &&
+ norm(points->getPos(accel->indices[i][j][k][id]) - pos) <= radius) {
+ answer = true;
+ break;
+ }
+ }
+ if (answer)
+ break;
+ }
+ if (answer)
+ break;
+ }
+ if (answer)
+ break;
+ }
+ return answer;
+ }
+
+ void removeInvalidIndices(vector<int> &indices)
+ {
+ vector<int> copy;
+ copy.resize(indices.size());
+ for (int i = 0; i < (int)indices.size(); i++) {
+ copy[i] = indices[i];
+ }
+ indices.clear();
+ for (int i = 0; i < (int)copy.size(); i++) {
+ if (points->isActive(copy[i])) {
+ indices.push_back(copy[i]);
+ }
+ }
+ }
+};
+
+struct ParticleDataImplVec3Wrapper : PointSetWrapper {
+ ParticleDataImpl<Vec3> *points;
+
+ ParticleDataImplVec3Wrapper(ParticleAccelGrid *inAccel) : PointSetWrapper(inAccel)
+ {
+ }
+
+ Vec3 getVec3(int id) const
+ {
+ return (*points)[id];
+ }
+ void setVec3(int id, Vec3 vec)
+ {
+ (*points)[id] = vec;
+ }
+ void updateAccel()
+ {
+ accel->fillWith(*points);
+ }
+ bool isActive(int i) const
+ {
+ return true;
+ }
+};
+
+//
+// **** globals ****
+//
+ParticleAccelGrid accelCoarse, accelSurface;
+BasicParticleSystemWrapper coarseParticles(&accelCoarse), surfacePoints(&accelSurface);
+ParticleDataImplVec3Wrapper coarseParticlesPrevPos(
+ &accelCoarse); // WARNING: reusing the coarse accel grid to save space, don't query
+ // coarseParticlesPrevPos and coarseParticles at the same time.
+vector<Vec3> tempSurfaceVec3; // to store misc info on surface points
+vector<Real> tempSurfaceFloat; // to store misc info on surface points
+int frameCount = 0;
+
+//
+//**** weighting kernels *****
+//
+Real triangularWeight(Real distance, Real radius)
+{
+ return 1.0f - distance / radius;
+}
+Real exponentialWeight(Real distance, Real radius, Real falloff)
+{
+ if (distance > radius)
+ return 0;
+ Real tmp = distance / radius;
+ return expf(-falloff * tmp * tmp);
+}
+
+Real weightKernelAdvection(Real distance)
+{
+ if (distance > 2.f * params.outerRadius) {
+ return 0;
+ }
+ else {
+ return triangularWeight(distance, 2.f * params.outerRadius);
+ }
+}
+
+Real weightKernelCoarseDensity(Real distance)
+{
+ return exponentialWeight(distance, params.outerRadius, 2.0f);
+}
+
+Real weightSurfaceNormal(Real distance)
+{
+ if (distance > params.normalRadius) {
+ return 0;
+ }
+ else {
+ return triangularWeight(distance, params.normalRadius);
+ }
+}
+
+Real weightSurfaceTangent(Real distance)
+{
+ if (distance > params.tangentRadius) {
+ return 0;
+ }
+ else {
+ return triangularWeight(distance, params.tangentRadius);
+ }
+}
+
+//
+// **** utility ****
+//
+
+bool isInDomain(Vec3 pos)
+{
+ return params.bndXm <= pos.x && pos.x <= params.bndXp && params.bndYm <= pos.y &&
+ pos.y <= params.bndYp && params.bndZm <= pos.z && pos.z <= params.bndZp;
+}
+
+Real smoothstep(Real edgeLeft, Real edgeRight, Real val)
+{
+ Real x = clamp((val - edgeLeft) / (edgeRight - edgeLeft), Real(0.), Real(1.));
+ return x * x * (3 - 2 * x);
+}
+
+//
+// **** surface initialization ****
+//
+
+void initFines(const BasicParticleSystemWrapper &coarseParticles,
+ BasicParticleSystemWrapper &surfacePoints,
+ const FlagGrid &flags)
+{
+ unsigned int discretization = (unsigned int)M_PI * (params.outerRadius + params.innerRadius) /
+ params.meanFineDistance;
+ Real dtheta = 2 * params.meanFineDistance / (params.outerRadius + params.innerRadius);
+ Real outerRadius2 = params.outerRadius * params.outerRadius;
+
+ surfacePoints.clear();
+ for (int idx = 0; idx < (int)coarseParticles.size(); idx++) {
+
+ if (idx % 500 == 0) {
+ cout << "Initializing surface points : " << setprecision(4)
+ << 100.f * idx / coarseParticles.size() << "%" << endl;
+ }
+
+ if (coarseParticles.isActive(idx)) {
+
+ // check flags if we are near surface
+ bool nearSurface = false;
+ Vec3 pos = coarseParticles.getPos(idx);
+ for (int i = -1; i <= 1; i++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int k = -1; k <= 1; k++) {
+ if (!flags.isFluid(((int)pos.x) + i, ((int)pos.y) + j, ((int)pos.z) + k)) {
+ nearSurface = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (nearSurface) {
+ for (unsigned int i = 0; i <= discretization / 2; ++i) {
+ Real discretization2 = Real(floor(2 * M_PI * sin(i * dtheta) / dtheta) + 1);
+ for (Real phi = 0; phi < 2 * M_PI; phi += Real(2 * M_PI / discretization2)) {
+ Real theta = i * dtheta;
+ Vec3 normal(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
+ Vec3 position = coarseParticles.getPos(idx) + params.outerRadius * normal;
+
+ bool valid = true;
+ LOOP_NEIGHBORS_BEGIN(coarseParticles, position, 2.f * params.outerRadius)
+ if (idx != idn && normSquare(position - coarseParticles.getPos(idn)) < outerRadius2) {
+ valid = false;
+ break;
+ }
+ LOOP_NEIGHBORS_END
+ if (valid) {
+ surfacePoints.addParticle(position);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+//
+// **** surface advection ****
+//
+
+struct advectSurfacePoints : public KernelBase {
+ advectSurfacePoints(BasicParticleSystemWrapper &surfacePoints,
+ const BasicParticleSystemWrapper &coarseParticles,
+ const ParticleDataImplVec3Wrapper &coarseParticlesPrevPos)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ coarseParticles(coarseParticles),
+ coarseParticlesPrevPos(coarseParticlesPrevPos)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ BasicParticleSystemWrapper &surfacePoints,
+ const BasicParticleSystemWrapper &coarseParticles,
+ const ParticleDataImplVec3Wrapper &coarseParticlesPrevPos) const
+ {
+ if (surfacePoints.isActive(idx)) {
+ Vec3 avgDisplacement(0, 0, 0);
+ Real totalWeight = 0;
+ Vec3 p = surfacePoints.getPos(idx);
+ LOOP_NEIGHBORS_BEGIN(
+ coarseParticlesPrevPos, surfacePoints.getPos(idx), 2.0f * params.outerRadius)
+ if ((coarseParticles.getStatus(idn) & ParticleBase::PNEW) == 0 &&
+ (coarseParticles.getStatus(idn) & ParticleBase::PDELETE) == 0) {
+ Vec3 disp = coarseParticles.getPos(idn) - coarseParticlesPrevPos.getVec3(idn);
+ Real distance = norm(coarseParticlesPrevPos.getVec3(idn) - p);
+ Real w = weightKernelAdvection(distance);
+ avgDisplacement += w * disp;
+ totalWeight += w;
+ }
+ LOOP_NEIGHBORS_END
+ if (totalWeight != 0)
+ avgDisplacement /= totalWeight;
+ surfacePoints.setPos(idx, p + avgDisplacement);
+ }
+ }
+ inline BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline const BasicParticleSystemWrapper &getArg1()
+ {
+ return coarseParticles;
+ }
+ typedef BasicParticleSystemWrapper type1;
+ inline const ParticleDataImplVec3Wrapper &getArg2()
+ {
+ return coarseParticlesPrevPos;
+ }
+ typedef ParticleDataImplVec3Wrapper type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel advectSurfacePoints ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, coarseParticles, coarseParticlesPrevPos);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ BasicParticleSystemWrapper &surfacePoints;
+ const BasicParticleSystemWrapper &coarseParticles;
+ const ParticleDataImplVec3Wrapper &coarseParticlesPrevPos;
+};
+
+//
+// **** value and gradient of level-set band constraint ****
+//
+Real computeConstraintLevel(const BasicParticleSystemWrapper &coarseParticles, Vec3 pos)
+{
+ Real lvl = 0.0f;
+ LOOP_NEIGHBORS_BEGIN(coarseParticles, pos, 1.5f * params.outerRadius)
+ lvl += expf(-params.constraintA * normSquare(coarseParticles.getPos(idn) - pos));
+ LOOP_NEIGHBORS_END
+ if (lvl > 1.0f)
+ lvl = 1.0f;
+ lvl = (sqrtf(-logf(lvl) / params.constraintA) - params.innerRadius) /
+ (params.outerRadius - params.innerRadius);
+ return lvl;
+}
+
+Vec3 computeConstraintGradient(const BasicParticleSystemWrapper &coarseParticles, Vec3 pos)
+{
+ Vec3 gradient(0, 0, 0);
+ LOOP_NEIGHBORS_BEGIN(coarseParticles, pos, 1.5f * params.outerRadius)
+ gradient += 2.f * params.constraintA *
+ (Real)(expf(-params.constraintA * normSquare(coarseParticles.getPos(idn) - pos))) *
+ (pos - coarseParticles.getPos(idn));
+ LOOP_NEIGHBORS_END
+ return getNormalized(gradient);
+}
+
+//
+// **** compute surface normals ****
+//
+
+struct computeSurfaceNormals : public KernelBase {
+ computeSurfaceNormals(const BasicParticleSystemWrapper &surfacePoints,
+ const BasicParticleSystemWrapper &coarseParticles,
+ ParticleDataImpl<Vec3> &surfaceNormals)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ coarseParticles(coarseParticles),
+ surfaceNormals(surfaceNormals)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ const BasicParticleSystemWrapper &coarseParticles,
+ ParticleDataImpl<Vec3> &surfaceNormals) const
+ {
+ Vec3 pos = surfacePoints.getPos(idx);
+
+ // approx normal with gradient
+ Vec3 gradient = computeConstraintGradient(coarseParticles, pos);
+
+ // get tangent frame
+ Vec3 n = getNormalized(gradient);
+ Vec3 vx(1, 0, 0);
+ Vec3 vy(0, 1, 0);
+ Real dotX = dot(n, vx);
+ Real dotY = dot(n, vy);
+ Vec3 t1 = getNormalized(fabs(dotX) < fabs(dotY) ? cross(n, vx) : cross(n, vy));
+ Vec3 t2 = getNormalized(cross(n, t1)); // initial frame
+
+ // linear fit of neighboring surface points in approximated tangent frame
+ Real sw = 0, swx = 0, swy = 0, swxy = 0, swx2 = 0, swy2 = 0, swxz = 0, swyz = 0, swz = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.normalRadius)
+ Real x = dot(gPos - pos, t1);
+ Real y = dot(gPos - pos, t2);
+ Real z = dot(gPos - pos, n);
+ Real w = weightSurfaceNormal(norm(pos - gPos));
+ swx2 += w * x * x;
+ swy2 += w * y * y;
+ swxy += w * x * y;
+ swxz += w * x * z;
+ swyz += w * y * z;
+ swx += w * x;
+ swy += w * y;
+ swz += w * z;
+ sw += w;
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ Real det = -sw * swxy * swxy + 2.f * swx * swxy * swy - swx2 * swy * swy - swx * swx * swy2 +
+ sw * swx2 * swy2;
+ if (det == 0) {
+ surfaceNormals[idx] = Vec3(0, 0, 0);
+ }
+ else {
+ Vec3 abc = 1.f / det *
+ Vec3(swxz * (-swy * swy + sw * swy2) + swyz * (-sw * swxy + swx * swy) +
+ swz * (swxy * swy - swx * swy2),
+ swxz * (-sw * swxy + swx * swy) + swyz * (-swx * swx + sw * swx2) +
+ swz * (swx * swxy - swx2 * swy),
+ swxz * (swxy * swy - swx * swy2) + swyz * (swx * swxy - swx2 * swy) +
+ swz * (-swxy * swxy + swx2 * swy2));
+ Vec3 normal = -getNormalized(t1 * abc.x + t2 * abc.y - n);
+ if (dot(gradient, normal) < 0) {
+ normal = -normal;
+ }
+ surfaceNormals[idx] = normal;
+ }
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline const BasicParticleSystemWrapper &getArg1()
+ {
+ return coarseParticles;
+ }
+ typedef BasicParticleSystemWrapper type1;
+ inline ParticleDataImpl<Vec3> &getArg2()
+ {
+ return surfaceNormals;
+ }
+ typedef ParticleDataImpl<Vec3> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel computeSurfaceNormals ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, coarseParticles, surfaceNormals);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ const BasicParticleSystemWrapper &coarseParticles;
+ ParticleDataImpl<Vec3> &surfaceNormals;
+};
+
+//
+// **** smooth surface normals ****
+//
+
+struct computeAveragedNormals : public KernelBase {
+ computeAveragedNormals(const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceNormals(surfaceNormals)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals) const
+ {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Vec3 newNormal = Vec3(0, 0, 0);
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+ Real w = weightSurfaceNormal(norm(pos - surfacePoints.getPos(idn)));
+ newNormal += w * surfaceNormals[idn];
+ LOOP_NEIGHBORS_END
+ tempSurfaceVec3[idx] = getNormalized(newNormal);
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline const ParticleDataImpl<Vec3> &getArg1()
+ {
+ return surfaceNormals;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel computeAveragedNormals ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, surfaceNormals);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ const ParticleDataImpl<Vec3> &surfaceNormals;
+};
+
+struct assignNormals : public KernelBase {
+ assignNormals(const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Vec3> &surfaceNormals)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceNormals(surfaceNormals)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Vec3> &surfaceNormals) const
+ {
+ surfaceNormals[idx] = tempSurfaceVec3[idx];
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline ParticleDataImpl<Vec3> &getArg1()
+ {
+ return surfaceNormals;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel assignNormals ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, surfaceNormals);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ ParticleDataImpl<Vec3> &surfaceNormals;
+};
+
+void smoothSurfaceNormals(const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Vec3> &surfaceNormals)
+{
+ tempSurfaceVec3.resize(surfacePoints.size());
+
+ computeAveragedNormals(surfacePoints, surfaceNormals);
+ assignNormals(surfacePoints, surfaceNormals);
+}
+
+//
+// **** addition/deletion of particles. Not parallel to prevent write/delete conflicts ****
+//
+
+void addDeleteSurfacePoints(BasicParticleSystemWrapper &surfacePoints)
+{
+ int fixedSize = surfacePoints.size();
+ for (int idx = 0; idx < fixedSize; idx++) {
+ // compute proxy tangent displacement
+ Vec3 pos = surfacePoints.getPos(idx);
+
+ Vec3 gradient = computeConstraintGradient(coarseParticles, pos);
+
+ Real wt = 0;
+ Vec3 tangentDisplacement(0, 0, 0);
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
+ if (idn != idx) {
+ Vec3 dir = pos - surfacePoints.getPos(idn);
+ Real length = norm(dir);
+ dir = getNormalized(dir);
+
+ // Decompose direction into normal and tangent directions.
+ Vec3 dn = dot(dir, gradient) * gradient;
+ Vec3 dt = dir - dn;
+
+ Real w = weightSurfaceTangent(length);
+ wt += w;
+ tangentDisplacement += w * dt;
+ }
+ LOOP_NEIGHBORS_END
+ if (norm(tangentDisplacement) != 0) {
+ tangentDisplacement = getNormalized(tangentDisplacement);
+ }
+
+ // check density criterion, add surface point if necessary
+ Vec3 creationPos = pos + params.meanFineDistance * tangentDisplacement;
+ if (isInDomain(creationPos) &&
+ !surfacePoints.hasNeighbor(creationPos, params.meanFineDistance - (1e-6))) {
+ // create point
+ surfacePoints.addBuffered(creationPos);
+ }
+ }
+
+ surfacePoints.doCompress();
+ surfacePoints.insertBufferedParticles();
+
+ // check density criterion, delete surface points if necessary
+ fixedSize = surfacePoints.size();
+ for (int idx = 0; idx < fixedSize; idx++) {
+ if (!isInDomain(surfacePoints.getPos(idx)) ||
+ surfacePoints.hasNeighborOtherThanItself(idx, 0.67 * params.meanFineDistance)) {
+ surfacePoints.kill(idx);
+ }
+ }
+
+ // delete surface points if no coarse neighbors in advection radius
+ fixedSize = surfacePoints.size();
+ for (int idx = 0; idx < fixedSize; idx++) {
+ Vec3 pos = surfacePoints.getPos(idx);
+ if (!coarseParticles.hasNeighbor(pos, 2.f * params.outerRadius)) {
+ surfacePoints.kill(idx);
+ }
+ }
+
+ // delete surface point if too far from constraint
+ fixedSize = surfacePoints.size();
+ for (int idx = 0; idx < fixedSize; idx++) {
+ Real level = computeConstraintLevel(coarseParticles, surfacePoints.getPos(idx));
+ if (level < -0.2 || level > 1.2) {
+ surfacePoints.kill(idx);
+ }
+ }
+
+ surfacePoints.doCompress();
+ surfacePoints.insertBufferedParticles();
+}
+
+//
+// **** surface maintenance ****
+//
+
+struct computeSurfaceDensities : public KernelBase {
+ computeSurfaceDensities(const BasicParticleSystemWrapper &surfacePoints, void *dummy)
+ : KernelBase(surfacePoints.size()), surfacePoints(surfacePoints), dummy(dummy)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper &surfacePoints, void *dummy) const
+ {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Real density = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.normalRadius)
+ density += weightSurfaceNormal(norm(pos - gPos));
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ tempSurfaceFloat[idx] = density;
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline void *getArg1()
+ {
+ return dummy;
+ }
+ typedef void type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel computeSurfaceDensities ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, dummy);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ void *dummy;
+};
+
+struct computeSurfaceDisplacements : public KernelBase {
+ computeSurfaceDisplacements(const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceNormals(surfaceNormals)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals) const
+ {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Vec3 normal = surfaceNormals[idx];
+
+ Vec3 displacementNormal(0, 0, 0);
+ Vec3 displacementTangent(0, 0, 0);
+ Real wTotal = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+
+ LOOP_GHOSTS_POS_NORMAL_BEGIN(
+ surfacePoints.getPos(idn), surfaceNormals[idn], params.normalRadius)
+ Vec3 dir = pos - gPos;
+ Real length = norm(dir);
+ Vec3 dn = dot(dir, surfaceNormals[idx]) * surfaceNormals[idx];
+ Vec3 dt = dir - dn;
+ if (tempSurfaceFloat[idn] == 0) {
+ continue;
+ }
+ Real w = weightSurfaceNormal(length) / tempSurfaceFloat[idn];
+
+ Vec3 crossVec = getNormalized(cross(normal, -dir));
+ Vec3 projectedNormal = getNormalized(gNormal - dot(crossVec, gNormal) * crossVec);
+ if (dot(projectedNormal, normal) < 0 || abs(dot(normal, normal + projectedNormal)) < 1e-6) {
+ continue;
+ }
+ dn = -dot(normal + projectedNormal, dir) / dot(normal, normal + projectedNormal) * normal;
+
+ displacementNormal += w * dn;
+ displacementTangent += w * getNormalized(dt);
+ wTotal += w;
+ LOOP_GHOSTS_END
+
+ LOOP_NEIGHBORS_END
+ if (wTotal != 0) {
+ displacementNormal /= wTotal;
+ displacementTangent /= wTotal;
+ }
+ displacementNormal *= .75f;
+ displacementTangent *= .25f * params.meanFineDistance;
+ tempSurfaceVec3[idx] = displacementNormal + displacementTangent;
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline const ParticleDataImpl<Vec3> &getArg1()
+ {
+ return surfaceNormals;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel computeSurfaceDisplacements ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, surfaceNormals);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ const ParticleDataImpl<Vec3> &surfaceNormals;
+};
+
+struct applySurfaceDisplacements : public KernelBase {
+ applySurfaceDisplacements(BasicParticleSystemWrapper &surfacePoints, void *dummy)
+ : KernelBase(surfacePoints.size()), surfacePoints(surfacePoints), dummy(dummy)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, BasicParticleSystemWrapper &surfacePoints, void *dummy) const
+ {
+ surfacePoints.setPos(idx, surfacePoints.getPos(idx) + tempSurfaceVec3[idx]);
+ }
+ inline BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline void *getArg1()
+ {
+ return dummy;
+ }
+ typedef void type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel applySurfaceDisplacements ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, dummy);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ BasicParticleSystemWrapper &surfacePoints;
+ void *dummy;
+};
+
+void regularizeSurfacePoints(BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals)
+{
+ tempSurfaceVec3.resize(surfacePoints.size());
+ tempSurfaceFloat.resize(surfacePoints.size());
+
+ computeSurfaceDensities(surfacePoints, 0);
+ computeSurfaceDisplacements(surfacePoints, surfaceNormals);
+ applySurfaceDisplacements(surfacePoints, 0);
+}
+
+struct constrainSurface : public KernelBase {
+ constrainSurface(BasicParticleSystemWrapper &surfacePoints,
+ const BasicParticleSystemWrapper &coarseParticles)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ coarseParticles(coarseParticles)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ BasicParticleSystemWrapper &surfacePoints,
+ const BasicParticleSystemWrapper &coarseParticles) const
+ {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Real level = computeConstraintLevel(coarseParticles, surfacePoints.getPos(idx));
+ if (level > 1) {
+ surfacePoints.setPos(
+ idx,
+ pos - (params.outerRadius - params.innerRadius) * (level - 1) *
+ computeConstraintGradient(coarseParticles, surfacePoints.getPos(idx)));
+ }
+ else if (level < 0) {
+ surfacePoints.setPos(
+ idx,
+ pos - (params.outerRadius - params.innerRadius) * level *
+ computeConstraintGradient(coarseParticles, surfacePoints.getPos(idx)));
+ }
+ }
+ inline BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline const BasicParticleSystemWrapper &getArg1()
+ {
+ return coarseParticles;
+ }
+ typedef BasicParticleSystemWrapper type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel constrainSurface ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, coarseParticles);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ BasicParticleSystemWrapper &surfacePoints;
+ const BasicParticleSystemWrapper &coarseParticles;
+};
+
+struct interpolateNewWaveData : public KernelBase {
+ interpolateNewWaveData(const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Real> &surfaceWaveH,
+ ParticleDataImpl<Real> &surfaceWaveDtH,
+ ParticleDataImpl<Real> &surfaceWaveSeed,
+ ParticleDataImpl<Real> &surfaceWaveSeedAmplitude)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceWaveH(surfaceWaveH),
+ surfaceWaveDtH(surfaceWaveDtH),
+ surfaceWaveSeed(surfaceWaveSeed),
+ surfaceWaveSeedAmplitude(surfaceWaveSeedAmplitude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Real> &surfaceWaveH,
+ ParticleDataImpl<Real> &surfaceWaveDtH,
+ ParticleDataImpl<Real> &surfaceWaveSeed,
+ ParticleDataImpl<Real> &surfaceWaveSeedAmplitude) const
+ {
+ if (surfacePoints.getStatus(idx) & ParticleBase::PNEW) {
+ Vec3 pos = surfacePoints.getPos(idx);
+ surfaceWaveH[idx] = 0;
+ surfaceWaveDtH[idx] = 0;
+ Real wTotal = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
+ if (!(surfacePoints.getStatus(idn) & ParticleBase::PNEW)) {
+ Real w = weightSurfaceTangent(norm(pos - surfacePoints.getPos(idn)));
+ surfaceWaveH[idx] += w * surfaceWaveH[idn];
+ surfaceWaveDtH[idx] += w * surfaceWaveDtH[idn];
+ surfaceWaveSeed[idx] += w * surfaceWaveSeed[idn];
+ surfaceWaveSeedAmplitude[idx] += w * surfaceWaveSeedAmplitude[idn];
+ wTotal += w;
+ }
+ LOOP_NEIGHBORS_END
+ if (wTotal != 0) {
+ surfaceWaveH[idx] /= wTotal;
+ surfaceWaveDtH[idx] /= wTotal;
+ surfaceWaveSeed[idx] /= wTotal;
+ surfaceWaveSeedAmplitude[idx] /= wTotal;
+ }
+ }
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline ParticleDataImpl<Real> &getArg1()
+ {
+ return surfaceWaveH;
+ }
+ typedef ParticleDataImpl<Real> type1;
+ inline ParticleDataImpl<Real> &getArg2()
+ {
+ return surfaceWaveDtH;
+ }
+ typedef ParticleDataImpl<Real> type2;
+ inline ParticleDataImpl<Real> &getArg3()
+ {
+ return surfaceWaveSeed;
+ }
+ typedef ParticleDataImpl<Real> type3;
+ inline ParticleDataImpl<Real> &getArg4()
+ {
+ return surfaceWaveSeedAmplitude;
+ }
+ typedef ParticleDataImpl<Real> type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel interpolateNewWaveData ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx,
+ surfacePoints,
+ surfaceWaveH,
+ surfaceWaveDtH,
+ surfaceWaveSeed,
+ surfaceWaveSeedAmplitude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ ParticleDataImpl<Real> &surfaceWaveH;
+ ParticleDataImpl<Real> &surfaceWaveDtH;
+ ParticleDataImpl<Real> &surfaceWaveSeed;
+ ParticleDataImpl<Real> &surfaceWaveSeedAmplitude;
+};
+
+void surfaceMaintenance(const BasicParticleSystemWrapper &coarseParticles,
+ BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Vec3> &surfaceNormals,
+ ParticleDataImpl<Real> &surfaceWaveH,
+ ParticleDataImpl<Real> &surfaceWaveDtH,
+ ParticleDataImpl<Real> &surfaceWaveSeed,
+ ParticleDataImpl<Real> &surfaceWaveSeedAmplitude,
+ int nbIterations)
+{
+ int countIterations = nbIterations;
+ while (countIterations > 0) {
+ addDeleteSurfacePoints(surfacePoints);
+ surfacePoints.updateAccel();
+ computeSurfaceNormals(surfacePoints, coarseParticles, surfaceNormals);
+ smoothSurfaceNormals(surfacePoints, surfaceNormals);
+
+ regularizeSurfacePoints(surfacePoints, surfaceNormals);
+ surfacePoints.updateAccel();
+ constrainSurface(surfacePoints, coarseParticles);
+ surfacePoints.updateAccel();
+
+ interpolateNewWaveData(
+ surfacePoints, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed, surfaceWaveSeedAmplitude);
+
+ countIterations--;
+ }
+}
+
+//
+// **** surface wave seeding and evolution ****
+//
+
+struct addSeed : public KernelBase {
+ addSeed(const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Real> &surfaceWaveH,
+ const ParticleDataImpl<Real> &surfaceWaveSeed)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceWaveH(surfaceWaveH),
+ surfaceWaveSeed(surfaceWaveSeed)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Real> &surfaceWaveH,
+ const ParticleDataImpl<Real> &surfaceWaveSeed) const
+ {
+ surfaceWaveH[idx] += surfaceWaveSeed[idx];
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline ParticleDataImpl<Real> &getArg1()
+ {
+ return surfaceWaveH;
+ }
+ typedef ParticleDataImpl<Real> type1;
+ inline const ParticleDataImpl<Real> &getArg2()
+ {
+ return surfaceWaveSeed;
+ }
+ typedef ParticleDataImpl<Real> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel addSeed ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, surfaceWaveH, surfaceWaveSeed);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ ParticleDataImpl<Real> &surfaceWaveH;
+ const ParticleDataImpl<Real> &surfaceWaveSeed;
+};
+
+struct computeSurfaceWaveNormal : public KernelBase {
+ computeSurfaceWaveNormal(const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals,
+ const ParticleDataImpl<Real> &surfaceWaveH)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceNormals(surfaceNormals),
+ surfaceWaveH(surfaceWaveH)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals,
+ const ParticleDataImpl<Real> &surfaceWaveH) const
+ {
+ Vec3 pos = surfacePoints.getPos(idx);
+
+ // get tangent frame
+ Vec3 n = getNormalized(surfaceNormals[idx]);
+ Vec3 vx(1, 0, 0);
+ Vec3 vy(0, 1, 0);
+ Real dotX = dot(n, vx);
+ Real dotY = dot(n, vy);
+ Vec3 t1 = getNormalized(fabs(dotX) < fabs(dotY) ? cross(n, vx) : cross(n, vy));
+ Vec3 t2 = getNormalized(cross(n, t1));
+
+ // linear fit
+ Real sw = 0, swx = 0, swy = 0, swxy = 0, swx2 = 0, swy2 = 0, swxz = 0, swyz = 0, swz = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.tangentRadius)
+ Real x = dot(gPos - pos, t1);
+ Real y = dot(gPos - pos, t2);
+ Real z = surfaceWaveH[idn];
+ Real w = weightSurfaceTangent(norm(pos - gPos));
+ swx2 += w * x * x;
+ swy2 += w * y * y;
+ swxy += w * x * y;
+ swxz += w * x * z;
+ swyz += w * y * z;
+ swx += w * x;
+ swy += w * y;
+ swz += w * z;
+ sw += w;
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ Real det = -sw * swxy * swxy + 2.f * swx * swxy * swy - swx2 * swy * swy - swx * swx * swy2 +
+ sw * swx2 * swy2;
+ if (det == 0) {
+ tempSurfaceVec3[idx] = Vec3(0, 0, 0);
+ }
+ else {
+ Vec3 abc = 1.f / det *
+ Vec3(swxz * (-swy * swy + sw * swy2) + swyz * (-sw * swxy + swx * swy) +
+ swz * (swxy * swy - swx * swy2),
+ swxz * (-sw * swxy + swx * swy) + swyz * (-swx * swx + sw * swx2) +
+ swz * (swx * swxy - swx2 * swy),
+ swxz * (swxy * swy - swx * swy2) + swyz * (swx * swxy - swx2 * swy) +
+ swz * (-swxy * swxy + swx2 * swy2));
+ Vec3 waveNormal = -getNormalized(vx * abc.x + vy * abc.y - Vec3(0, 0, 1));
+ tempSurfaceVec3[idx] = waveNormal;
+ }
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline const ParticleDataImpl<Vec3> &getArg1()
+ {
+ return surfaceNormals;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ inline const ParticleDataImpl<Real> &getArg2()
+ {
+ return surfaceWaveH;
+ }
+ typedef ParticleDataImpl<Real> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel computeSurfaceWaveNormal ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, surfaceNormals, surfaceWaveH);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ const ParticleDataImpl<Vec3> &surfaceNormals;
+ const ParticleDataImpl<Real> &surfaceWaveH;
+};
+
+struct computeSurfaceWaveLaplacians : public KernelBase {
+ computeSurfaceWaveLaplacians(const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals,
+ const ParticleDataImpl<Real> &surfaceWaveH)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceNormals(surfaceNormals),
+ surfaceWaveH(surfaceWaveH)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals,
+ const ParticleDataImpl<Real> &surfaceWaveH) const
+ {
+ Real laplacian = 0;
+ Real wTotal = 0;
+ Vec3 pPos = surfacePoints.getPos(idx);
+ Vec3 pNormal = surfaceNormals[idx];
+
+ Vec3 vx(1, 0, 0);
+ Vec3 vy(0, 1, 0);
+ Real dotX = dot(pNormal, vx);
+ Real dotY = dot(pNormal, vy);
+ Vec3 t1 = getNormalized(fabs(dotX) < fabs(dotY) ? cross(pNormal, vx) : cross(pNormal, vy));
+ Vec3 t2 = getNormalized(cross(pNormal, t1));
+
+ Vec3 pWaveNormal = tempSurfaceVec3[idx];
+ Real ph = surfaceWaveH[idx];
+ if (pWaveNormal.z == 0) {
+ tempSurfaceFloat[idx] = 0;
+ }
+ else {
+
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.tangentRadius)
+ Real nh = surfaceWaveH[idn];
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.tangentRadius)
+ Vec3 dir = gPos - pPos;
+ Real lengthDir = norm(dir);
+ if (lengthDir < 1e-5)
+ continue;
+ Vec3 tangentDir = lengthDir * getNormalized(dir - dot(dir, pNormal) * pNormal);
+ Real dirX = dot(tangentDir, t1);
+ Real dirY = dot(tangentDir, t2);
+ Real dz = nh - ph - (-pWaveNormal.x / pWaveNormal.z) * dirX -
+ (-pWaveNormal.y / pWaveNormal.z) * dirY;
+ Real w = weightSurfaceTangent(norm(pPos - gPos));
+ wTotal += w;
+ laplacian += clamp(w * 4 * dz / (lengthDir * lengthDir), Real(-100.), Real(100.));
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ if (wTotal != 0) {
+ tempSurfaceFloat[idx] = laplacian / wTotal;
+ }
+ else {
+ tempSurfaceFloat[idx] = 0;
+ }
+ }
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline const ParticleDataImpl<Vec3> &getArg1()
+ {
+ return surfaceNormals;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ inline const ParticleDataImpl<Real> &getArg2()
+ {
+ return surfaceWaveH;
+ }
+ typedef ParticleDataImpl<Real> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel computeSurfaceWaveLaplacians ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, surfaceNormals, surfaceWaveH);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ const ParticleDataImpl<Vec3> &surfaceNormals;
+ const ParticleDataImpl<Real> &surfaceWaveH;
+};
+
+struct evolveWave : public KernelBase {
+ evolveWave(const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Real> &surfaceWaveH,
+ ParticleDataImpl<Real> &surfaceWaveDtH,
+ const ParticleDataImpl<Real> &surfaceWaveSeed)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceWaveH(surfaceWaveH),
+ surfaceWaveDtH(surfaceWaveDtH),
+ surfaceWaveSeed(surfaceWaveSeed)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Real> &surfaceWaveH,
+ ParticleDataImpl<Real> &surfaceWaveDtH,
+ const ParticleDataImpl<Real> &surfaceWaveSeed) const
+ {
+ surfaceWaveDtH[idx] += params.waveSpeed * params.waveSpeed * params.dt * tempSurfaceFloat[idx];
+ surfaceWaveDtH[idx] /= (1 + params.dt * params.waveDamping);
+ surfaceWaveH[idx] += params.dt * surfaceWaveDtH[idx];
+ surfaceWaveH[idx] /= (1 + params.dt * params.waveDamping);
+ surfaceWaveH[idx] -= surfaceWaveSeed[idx];
+
+ // clamp H and DtH (to prevent rare extreme behaviors)
+ surfaceWaveDtH[idx] = clamp(surfaceWaveDtH[idx],
+ -params.waveMaxFrequency * params.waveMaxAmplitude,
+ params.waveMaxFrequency * params.waveMaxAmplitude);
+ surfaceWaveH[idx] = clamp(
+ surfaceWaveH[idx], -params.waveMaxAmplitude, params.waveMaxAmplitude);
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline ParticleDataImpl<Real> &getArg1()
+ {
+ return surfaceWaveH;
+ }
+ typedef ParticleDataImpl<Real> type1;
+ inline ParticleDataImpl<Real> &getArg2()
+ {
+ return surfaceWaveDtH;
+ }
+ typedef ParticleDataImpl<Real> type2;
+ inline const ParticleDataImpl<Real> &getArg3()
+ {
+ return surfaceWaveSeed;
+ }
+ typedef ParticleDataImpl<Real> type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel evolveWave ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ ParticleDataImpl<Real> &surfaceWaveH;
+ ParticleDataImpl<Real> &surfaceWaveDtH;
+ const ParticleDataImpl<Real> &surfaceWaveSeed;
+};
+
+struct computeSurfaceCurvature : public KernelBase {
+ computeSurfaceCurvature(const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceNormals(surfaceNormals)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals) const
+ {
+ Vec3 pPos = surfacePoints.getPos(idx);
+ Real wTotal = 0;
+ Real curv = 0;
+ Vec3 pNormal = surfaceNormals[idx];
+
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.normalRadius)
+ LOOP_GHOSTS_POS_NORMAL_BEGIN(
+ surfacePoints.getPos(idn), surfaceNormals[idn], params.normalRadius)
+ Vec3 dir = pPos - gPos;
+ if (dot(pNormal, gNormal) < 0) {
+ continue;
+ } // backfacing
+ Real dist = norm(dir);
+ if (dist < params.normalRadius / 100.f) {
+ continue;
+ }
+
+ Real distn = dot(dir, pNormal);
+
+ Real w = weightSurfaceNormal(dist);
+ curv += w * distn;
+ wTotal += w;
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ if (wTotal != 0) {
+ curv /= wTotal;
+ }
+ tempSurfaceFloat[idx] = fabs(curv);
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline const ParticleDataImpl<Vec3> &getArg1()
+ {
+ return surfaceNormals;
+ }
+ typedef ParticleDataImpl<Vec3> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel computeSurfaceCurvature ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, surfaceNormals);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ const ParticleDataImpl<Vec3> &surfaceNormals;
+};
+
+struct smoothCurvature : public KernelBase {
+ smoothCurvature(const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Real> &surfaceWaveSource)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceWaveSource(surfaceWaveSource)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Real> &surfaceWaveSource) const
+ {
+ Vec3 pPos = surfacePoints.getPos(idx);
+ Real curv = 0;
+ Real wTotal = 0;
+
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.normalRadius)
+ Real w = weightSurfaceNormal(norm(pPos - surfacePoints.getPos(idn)));
+ curv += w * tempSurfaceFloat[idn];
+ wTotal += w;
+ LOOP_NEIGHBORS_END
+ if (wTotal != 0) {
+ curv /= wTotal;
+ }
+ surfaceWaveSource[idx] = curv;
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline ParticleDataImpl<Real> &getArg1()
+ {
+ return surfaceWaveSource;
+ }
+ typedef ParticleDataImpl<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel smoothCurvature ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, surfaceWaveSource);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ ParticleDataImpl<Real> &surfaceWaveSource;
+};
+
+struct seedWaves : public KernelBase {
+ seedWaves(const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Real> &surfaceWaveSeed,
+ ParticleDataImpl<Real> &surfaceWaveSeedAmplitude,
+ ParticleDataImpl<Real> &surfaceWaveSource)
+ : KernelBase(surfacePoints.size()),
+ surfacePoints(surfacePoints),
+ surfaceWaveSeed(surfaceWaveSeed),
+ surfaceWaveSeedAmplitude(surfaceWaveSeedAmplitude),
+ surfaceWaveSource(surfaceWaveSource)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystemWrapper &surfacePoints,
+ ParticleDataImpl<Real> &surfaceWaveSeed,
+ ParticleDataImpl<Real> &surfaceWaveSeedAmplitude,
+ ParticleDataImpl<Real> &surfaceWaveSource) const
+ {
+ Real source = smoothstep(params.waveSeedingCurvatureThresholdRegionCenter -
+ params.waveSeedingCurvatureThresholdRegionRadius,
+ params.waveSeedingCurvatureThresholdRegionCenter +
+ params.waveSeedingCurvatureThresholdRegionRadius,
+ (Real)surfaceWaveSource[idx]) *
+ 2.f -
+ 1.f;
+ Real freq = params.waveSeedFrequency;
+ Real theta = params.dt * frameCount * params.waveSpeed * freq;
+ Real costheta = cosf(theta);
+ Real maxSeedAmplitude = params.waveMaxSeedingAmplitude * params.waveMaxAmplitude;
+
+ surfaceWaveSeedAmplitude[idx] = clamp<Real>(surfaceWaveSeedAmplitude[idx] +
+ source * params.waveSeedStepSizeRatioOfMax *
+ maxSeedAmplitude,
+ 0.f,
+ maxSeedAmplitude);
+ surfaceWaveSeed[idx] = surfaceWaveSeedAmplitude[idx] * costheta;
+
+ // source values for display (not used after this point anyway)
+ surfaceWaveSource[idx] = (source >= 0) ? 1 : 0;
+ }
+ inline const BasicParticleSystemWrapper &getArg0()
+ {
+ return surfacePoints;
+ }
+ typedef BasicParticleSystemWrapper type0;
+ inline ParticleDataImpl<Real> &getArg1()
+ {
+ return surfaceWaveSeed;
+ }
+ typedef ParticleDataImpl<Real> type1;
+ inline ParticleDataImpl<Real> &getArg2()
+ {
+ return surfaceWaveSeedAmplitude;
+ }
+ typedef ParticleDataImpl<Real> type2;
+ inline ParticleDataImpl<Real> &getArg3()
+ {
+ return surfaceWaveSource;
+ }
+ typedef ParticleDataImpl<Real> type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel seedWaves ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, surfacePoints, surfaceWaveSeed, surfaceWaveSeedAmplitude, surfaceWaveSource);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystemWrapper &surfacePoints;
+ ParticleDataImpl<Real> &surfaceWaveSeed;
+ ParticleDataImpl<Real> &surfaceWaveSeedAmplitude;
+ ParticleDataImpl<Real> &surfaceWaveSource;
+};
+
+void surfaceWaves(const BasicParticleSystemWrapper &surfacePoints,
+ const ParticleDataImpl<Vec3> &surfaceNormals,
+ ParticleDataImpl<Real> &surfaceWaveH,
+ ParticleDataImpl<Real> &surfaceWaveDtH,
+ ParticleDataImpl<Real> &surfaceWaveSource,
+ ParticleDataImpl<Real> &surfaceWaveSeed,
+ ParticleDataImpl<Real> &surfaceWaveSeedAmplitude)
+{
+ addSeed(surfacePoints, surfaceWaveH, surfaceWaveSeed);
+ computeSurfaceWaveNormal(surfacePoints, surfaceNormals, surfaceWaveH);
+ computeSurfaceWaveLaplacians(surfacePoints, surfaceNormals, surfaceWaveH);
+ evolveWave(surfacePoints, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed);
+ computeSurfaceCurvature(surfacePoints, surfaceNormals);
+ smoothCurvature(surfacePoints, surfaceWaveSource);
+ seedWaves(surfacePoints, surfaceWaveSeed, surfaceWaveSeedAmplitude, surfaceWaveSource);
+}
+
+//
+// **** main function ****
+//
+
+void particleSurfaceTurbulence(const FlagGrid &flags,
+ BasicParticleSystem &coarseParts,
+ ParticleDataImpl<Vec3> &coarsePartsPrevPos,
+ BasicParticleSystem &surfPoints,
+ ParticleDataImpl<Vec3> &surfaceNormals,
+ ParticleDataImpl<Real> &surfaceWaveH,
+ ParticleDataImpl<Real> &surfaceWaveDtH,
+ BasicParticleSystem &surfacePointsDisplaced,
+ ParticleDataImpl<Real> &surfaceWaveSource,
+ ParticleDataImpl<Real> &surfaceWaveSeed,
+ ParticleDataImpl<Real> &surfaceWaveSeedAmplitude,
+ int res,
+ Real outerRadius = 1.0f,
+ int surfaceDensity = 20,
+ int nbSurfaceMaintenanceIterations = 4,
+ Real dt = 0.005f,
+ Real waveSpeed = 16.0f,
+ Real waveDamping = 0.0f,
+ Real waveSeedFrequency = 4,
+ Real waveMaxAmplitude = 0.25f,
+ Real waveMaxFrequency = 800,
+ Real waveMaxSeedingAmplitude = 0.5,
+ Real waveSeedingCurvatureThresholdRegionCenter = 0.025f,
+ Real waveSeedingCurvatureThresholdRegionRadius = 0.01f,
+ Real waveSeedStepSizeRatioOfMax = 0.05f)
+{
+#if USE_CHRONO == 1
+ static std::chrono::high_resolution_clock::time_point begin, end;
+ end = std::chrono::high_resolution_clock::now();
+ cout << std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count() / 1000000000.f
+ << " : time sim" << endl;
+ begin = std::chrono::high_resolution_clock::now();
+#endif
+
+ // wrap data
+ coarseParticles.points = &coarseParts;
+ coarseParticlesPrevPos.points = &coarsePartsPrevPos;
+ surfacePoints.points = &surfPoints;
+
+ // copy parameters
+ params.res = res;
+ params.outerRadius = outerRadius;
+ params.surfaceDensity = surfaceDensity;
+ params.nbSurfaceMaintenanceIterations = nbSurfaceMaintenanceIterations;
+ params.dt = dt;
+ params.waveSpeed = waveSpeed;
+ params.waveDamping = waveDamping;
+ params.waveSeedFrequency = waveSeedFrequency;
+ params.waveMaxAmplitude = waveMaxAmplitude;
+ params.waveMaxFrequency = waveMaxFrequency;
+ params.waveMaxSeedingAmplitude = waveMaxSeedingAmplitude;
+ params.waveSeedingCurvatureThresholdRegionCenter = waveSeedingCurvatureThresholdRegionCenter;
+ params.waveSeedingCurvatureThresholdRegionRadius = waveSeedingCurvatureThresholdRegionRadius;
+ params.waveSeedStepSizeRatioOfMax = waveSeedStepSizeRatioOfMax;
+
+ // compute other parameters
+ params.innerRadius = params.outerRadius / 2.0;
+ params.meanFineDistance = M_PI * (params.outerRadius + params.innerRadius) /
+ params.surfaceDensity;
+ params.constraintA = logf(2.0f / (1.0f + weightKernelCoarseDensity(params.outerRadius +
+ params.innerRadius))) /
+ (powf((params.outerRadius + params.innerRadius) / 2, 2) -
+ params.innerRadius * params.innerRadius);
+ params.normalRadius = 0.5f * (params.outerRadius + params.innerRadius);
+ params.tangentRadius = 2.1f * params.meanFineDistance;
+ params.bndXm = params.bndYm = params.bndZm = 2;
+ params.bndXp = params.bndYp = params.bndZp = params.res - 2;
+
+ if (frameCount == 0) {
+
+ // initialize accel grids
+ accelCoarse.init(2.f * res / params.outerRadius);
+ accelSurface.init(1.f * res / (2.f * params.meanFineDistance));
+
+ // update coarse accel structure
+ coarseParticles.updateAccel();
+
+ // create surface points
+ initFines(coarseParticles, surfacePoints, flags);
+
+ // smooth surface
+ surfaceMaintenance(coarseParticles,
+ surfacePoints,
+ surfaceNormals,
+ surfaceWaveH,
+ surfaceWaveDtH,
+ surfaceWaveSeed,
+ surfaceWaveSeedAmplitude,
+ 6 * params.nbSurfaceMaintenanceIterations);
+
+ // set wave values to zero
+ for (int idx = 0; idx < surfacePoints.size(); idx++) {
+ surfaceWaveH[idx] = 0;
+ surfaceWaveDtH[idx] = 0;
+ surfaceWaveSeed[idx] = 0;
+ surfaceWaveSeedAmplitude[idx] = 0;
+ }
+ }
+ else {
+
+ // update coarse accel structure with previous coarse particles positions
+ coarseParticlesPrevPos.updateAccel();
+
+ // advect surface points following coarse particles
+ advectSurfacePoints(surfacePoints, coarseParticles, coarseParticlesPrevPos);
+ surfacePoints.updateAccel();
+
+ // update acceleration structure for surface points
+ coarseParticles.updateAccel();
+
+ // surface maintenance
+ surfaceMaintenance(coarseParticles,
+ surfacePoints,
+ surfaceNormals,
+ surfaceWaveH,
+ surfaceWaveDtH,
+ surfaceWaveSeed,
+ surfaceWaveSeedAmplitude,
+ params.nbSurfaceMaintenanceIterations);
+
+ // surface waves
+ surfaceWaves(surfacePoints,
+ surfaceNormals,
+ surfaceWaveH,
+ surfaceWaveDtH,
+ surfaceWaveSource,
+ surfaceWaveSeed,
+ surfaceWaveSeedAmplitude);
+ }
+ frameCount++;
+
+ // save positions as previous positions for next step
+ for (int id = 0; id < coarseParticles.size(); id++) {
+ if ((coarseParticles.getStatus(id) & ParticleBase::PNEW) == 0 &&
+ (coarseParticles.getStatus(id) & ParticleBase::PDELETE) == 0) {
+ coarseParticlesPrevPos.setVec3(id, coarseParticles.getPos(id));
+ }
+ }
+
+ // create displaced points for display
+ surfacePointsDisplaced.clear();
+ for (int idx = 0; idx < surfacePoints.size(); idx++) {
+ if ((surfacePoints.getStatus(idx) & ParticleBase::PDELETE) == 0) {
+ surfacePointsDisplaced.addParticle(surfacePoints.getPos(idx) +
+ surfaceNormals[idx] * surfaceWaveH[idx]);
+ }
+ }
+
+#if USE_CHRONO == 1
+ end = std::chrono::high_resolution_clock::now();
+ cout << std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count() / 1000000000.f
+ << " : time upres" << endl;
+ begin = std::chrono::high_resolution_clock::now();
+#endif
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "particleSurfaceTurbulence", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ BasicParticleSystem &coarseParts = *_args.getPtr<BasicParticleSystem>(
+ "coarseParts", 1, &_lock);
+ ParticleDataImpl<Vec3> &coarsePartsPrevPos = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "coarsePartsPrevPos", 2, &_lock);
+ BasicParticleSystem &surfPoints = *_args.getPtr<BasicParticleSystem>(
+ "surfPoints", 3, &_lock);
+ ParticleDataImpl<Vec3> &surfaceNormals = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "surfaceNormals", 4, &_lock);
+ ParticleDataImpl<Real> &surfaceWaveH = *_args.getPtr<ParticleDataImpl<Real>>(
+ "surfaceWaveH", 5, &_lock);
+ ParticleDataImpl<Real> &surfaceWaveDtH = *_args.getPtr<ParticleDataImpl<Real>>(
+ "surfaceWaveDtH", 6, &_lock);
+ BasicParticleSystem &surfacePointsDisplaced = *_args.getPtr<BasicParticleSystem>(
+ "surfacePointsDisplaced", 7, &_lock);
+ ParticleDataImpl<Real> &surfaceWaveSource = *_args.getPtr<ParticleDataImpl<Real>>(
+ "surfaceWaveSource", 8, &_lock);
+ ParticleDataImpl<Real> &surfaceWaveSeed = *_args.getPtr<ParticleDataImpl<Real>>(
+ "surfaceWaveSeed", 9, &_lock);
+ ParticleDataImpl<Real> &surfaceWaveSeedAmplitude = *_args.getPtr<ParticleDataImpl<Real>>(
+ "surfaceWaveSeedAmplitude", 10, &_lock);
+ int res = _args.get<int>("res", 11, &_lock);
+ Real outerRadius = _args.getOpt<Real>("outerRadius", 12, 1.0f, &_lock);
+ int surfaceDensity = _args.getOpt<int>("surfaceDensity", 13, 20, &_lock);
+ int nbSurfaceMaintenanceIterations = _args.getOpt<int>(
+ "nbSurfaceMaintenanceIterations", 14, 4, &_lock);
+ Real dt = _args.getOpt<Real>("dt", 15, 0.005f, &_lock);
+ Real waveSpeed = _args.getOpt<Real>("waveSpeed", 16, 16.0f, &_lock);
+ Real waveDamping = _args.getOpt<Real>("waveDamping", 17, 0.0f, &_lock);
+ Real waveSeedFrequency = _args.getOpt<Real>("waveSeedFrequency", 18, 4, &_lock);
+ Real waveMaxAmplitude = _args.getOpt<Real>("waveMaxAmplitude", 19, 0.25f, &_lock);
+ Real waveMaxFrequency = _args.getOpt<Real>("waveMaxFrequency", 20, 800, &_lock);
+ Real waveMaxSeedingAmplitude = _args.getOpt<Real>(
+ "waveMaxSeedingAmplitude", 21, 0.5, &_lock);
+ Real waveSeedingCurvatureThresholdRegionCenter = _args.getOpt<Real>(
+ "waveSeedingCurvatureThresholdRegionCenter", 22, 0.025f, &_lock);
+ Real waveSeedingCurvatureThresholdRegionRadius = _args.getOpt<Real>(
+ "waveSeedingCurvatureThresholdRegionRadius", 23, 0.01f, &_lock);
+ Real waveSeedStepSizeRatioOfMax = _args.getOpt<Real>(
+ "waveSeedStepSizeRatioOfMax", 24, 0.05f, &_lock);
+ _retval = getPyNone();
+ particleSurfaceTurbulence(flags,
+ coarseParts,
+ coarsePartsPrevPos,
+ surfPoints,
+ surfaceNormals,
+ surfaceWaveH,
+ surfaceWaveDtH,
+ surfacePointsDisplaced,
+ surfaceWaveSource,
+ surfaceWaveSeed,
+ surfaceWaveSeedAmplitude,
+ res,
+ outerRadius,
+ surfaceDensity,
+ nbSurfaceMaintenanceIterations,
+ dt,
+ waveSpeed,
+ waveDamping,
+ waveSeedFrequency,
+ waveMaxAmplitude,
+ waveMaxFrequency,
+ waveMaxSeedingAmplitude,
+ waveSeedingCurvatureThresholdRegionCenter,
+ waveSeedingCurvatureThresholdRegionRadius,
+ waveSeedStepSizeRatioOfMax);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "particleSurfaceTurbulence", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("particleSurfaceTurbulence", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_particleSurfaceTurbulence("", "particleSurfaceTurbulence", _W_0);
+extern "C" {
+void PbRegister_particleSurfaceTurbulence()
+{
+ KEEP_UNUSED(_RP_particleSurfaceTurbulence);
+}
+}
+
+void debugCheckParts(const BasicParticleSystem &parts, const FlagGrid &flags)
+{
+ for (int idx = 0; idx < parts.size(); idx++) {
+ Vec3i p = toVec3i(parts.getPos(idx));
+ if (!flags.isInBounds(p)) {
+ debMsg("bad position??? " << idx << " " << parts.getPos(idx), 1);
+ exit(1);
+ }
+ }
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "debugCheckParts", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ _retval = getPyNone();
+ debugCheckParts(parts, flags);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "debugCheckParts", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("debugCheckParts", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_debugCheckParts("", "debugCheckParts", _W_1);
+extern "C" {
+void PbRegister_debugCheckParts()
+{
+ KEEP_UNUSED(_RP_debugCheckParts);
+}
+}
+
+} // namespace SurfaceTurbulence
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/vortexplugins.cpp b/extern/mantaflow/preprocessed/plugin/vortexplugins.cpp
new file mode 100644
index 00000000000..c2a21d82689
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/vortexplugins.cpp
@@ -0,0 +1,695 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for using vortex sheet meshes
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include "vortexsheet.h"
+#include "vortexpart.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "conjugategrad.h"
+#include "randomstream.h"
+#include "levelset.h"
+
+using namespace std;
+
+namespace Manta {
+
+//! Mark area of mesh inside shape as fixed nodes.
+//! Remove all other fixed nodes if 'exclusive' is set
+
+void markAsFixed(Mesh &mesh, const Shape *shape, bool exclusive = true)
+{
+ for (int i = 0; i < mesh.numNodes(); i++) {
+ if (shape->isInside(mesh.nodes(i).pos))
+ mesh.nodes(i).flags |= Mesh::NfFixed;
+ else if (exclusive)
+ mesh.nodes(i).flags &= ~Mesh::NfFixed;
+ }
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "markAsFixed", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
+ const Shape *shape = _args.getPtr<Shape>("shape", 1, &_lock);
+ bool exclusive = _args.getOpt<bool>("exclusive", 2, true, &_lock);
+ _retval = getPyNone();
+ markAsFixed(mesh, shape, exclusive);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "markAsFixed", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("markAsFixed", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_markAsFixed("", "markAsFixed", _W_0);
+extern "C" {
+void PbRegister_markAsFixed()
+{
+ KEEP_UNUSED(_RP_markAsFixed);
+}
+}
+
+//! Adapt texture coordinates of mesh inside shape
+//! to obtain an effective inflow effect
+
+void texcoordInflow(VortexSheetMesh &mesh, const Shape *shape, const MACGrid &vel)
+{
+ static Vec3 t0 = Vec3::Zero;
+
+ // get mean velocity
+ int cnt = 0;
+ Vec3 meanV(0.0);
+ FOR_IJK(vel)
+ {
+ if (shape->isInsideGrid(i, j, k)) {
+ cnt++;
+ meanV += vel.getCentered(i, j, k);
+ }
+ }
+ meanV /= (Real)cnt;
+ t0 -= mesh.getParent()->getDt() * meanV;
+ mesh.setReferenceTexOffset(t0);
+
+ // apply mean velocity
+ for (int i = 0; i < mesh.numNodes(); i++) {
+ if (shape->isInside(mesh.nodes(i).pos)) {
+ Vec3 tc = mesh.nodes(i).pos + t0;
+ mesh.tex1(i) = tc;
+ mesh.tex2(i) = tc;
+ }
+ }
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "texcoordInflow", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ VortexSheetMesh &mesh = *_args.getPtr<VortexSheetMesh>("mesh", 0, &_lock);
+ const Shape *shape = _args.getPtr<Shape>("shape", 1, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 2, &_lock);
+ _retval = getPyNone();
+ texcoordInflow(mesh, shape, vel);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "texcoordInflow", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("texcoordInflow", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_texcoordInflow("", "texcoordInflow", _W_1);
+extern "C" {
+void PbRegister_texcoordInflow()
+{
+ KEEP_UNUSED(_RP_texcoordInflow);
+}
+}
+
+;
+
+//! Init smoke density values of the mesh surface inside source shape
+
+void meshSmokeInflow(VortexSheetMesh &mesh, const Shape *shape, Real amount)
+{
+ for (int t = 0; t < mesh.numTris(); t++) {
+ if (shape->isInside(mesh.getFaceCenter(t)))
+ mesh.sheet(t).smokeAmount = amount;
+ }
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "meshSmokeInflow", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ VortexSheetMesh &mesh = *_args.getPtr<VortexSheetMesh>("mesh", 0, &_lock);
+ const Shape *shape = _args.getPtr<Shape>("shape", 1, &_lock);
+ Real amount = _args.get<Real>("amount", 2, &_lock);
+ _retval = getPyNone();
+ meshSmokeInflow(mesh, shape, amount);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "meshSmokeInflow", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("meshSmokeInflow", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_meshSmokeInflow("", "meshSmokeInflow", _W_2);
+extern "C" {
+void PbRegister_meshSmokeInflow()
+{
+ KEEP_UNUSED(_RP_meshSmokeInflow);
+}
+}
+
+struct KnAcceleration : public KernelBase {
+ KnAcceleration(MACGrid &a, const MACGrid &v1, const MACGrid &v0, const Real idt)
+ : KernelBase(&a, 0), a(a), v1(v1), v0(v0), idt(idt)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ IndexInt idx, MACGrid &a, const MACGrid &v1, const MACGrid &v0, const Real idt) const
+ {
+ a[idx] = (v1[idx] - v0[idx]) * idt;
+ }
+ inline MACGrid &getArg0()
+ {
+ return a;
+ }
+ typedef MACGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return v1;
+ }
+ typedef MACGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return v0;
+ }
+ typedef MACGrid type2;
+ inline const Real &getArg3()
+ {
+ return idt;
+ }
+ typedef Real type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnAcceleration ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, a, v1, v0, idt);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ MACGrid &a;
+ const MACGrid &v1;
+ const MACGrid &v0;
+ const Real idt;
+};
+
+//! Add vorticity to vortex sheets based on buoyancy
+
+void vorticitySource(VortexSheetMesh &mesh,
+ Vec3 gravity,
+ const MACGrid *vel = NULL,
+ const MACGrid *velOld = NULL,
+ Real scale = 0.1,
+ Real maxAmount = 0,
+ Real mult = 1.0)
+{
+ Real dt = mesh.getParent()->getDt();
+ Real dx = mesh.getParent()->getDx();
+ MACGrid acceleration(mesh.getParent());
+ if (vel)
+ KnAcceleration(acceleration, *vel, *velOld, 1.0 / dt);
+ const Real A = -1.0;
+ Real maxV = 0, meanV = 0;
+
+ for (int t = 0; t < mesh.numTris(); t++) {
+ Vec3 fn = mesh.getFaceNormal(t);
+ Vec3 source;
+ if (vel) {
+ Vec3 a = acceleration.getInterpolated(mesh.getFaceCenter(t));
+ source = A * cross(fn, a - gravity) * scale;
+ }
+ else {
+ source = A * cross(fn, -gravity) * scale;
+ }
+
+ if (mesh.isTriangleFixed(t))
+ source = 0;
+
+ mesh.sheet(t).vorticity *= mult;
+ mesh.sheet(t).vorticity += dt * source / dx;
+ // upper limit
+ Real v = norm(mesh.sheet(t).vorticity);
+ if (maxAmount > 0 && v > maxAmount)
+ mesh.sheet(t).vorticity *= maxAmount / v;
+
+ // stats
+ if (v > maxV)
+ maxV = v;
+ meanV += v;
+ }
+
+ cout << "vorticity: max " << maxV << " / mean " << meanV / mesh.numTris() << endl;
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "vorticitySource", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ VortexSheetMesh &mesh = *_args.getPtr<VortexSheetMesh>("mesh", 0, &_lock);
+ Vec3 gravity = _args.get<Vec3>("gravity", 1, &_lock);
+ const MACGrid *vel = _args.getPtrOpt<MACGrid>("vel", 2, NULL, &_lock);
+ const MACGrid *velOld = _args.getPtrOpt<MACGrid>("velOld", 3, NULL, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 4, 0.1, &_lock);
+ Real maxAmount = _args.getOpt<Real>("maxAmount", 5, 0, &_lock);
+ Real mult = _args.getOpt<Real>("mult", 6, 1.0, &_lock);
+ _retval = getPyNone();
+ vorticitySource(mesh, gravity, vel, velOld, scale, maxAmount, mult);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "vorticitySource", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("vorticitySource", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_vorticitySource("", "vorticitySource", _W_3);
+extern "C" {
+void PbRegister_vorticitySource()
+{
+ KEEP_UNUSED(_RP_vorticitySource);
+}
+}
+
+void smoothVorticity(VortexSheetMesh &mesh, int iter = 1, Real sigma = 0.2, Real alpha = 0.8)
+{
+ const Real mult = -0.5 / sigma / sigma;
+
+ // pre-calculate positions and weights
+ vector<Vec3> vort(mesh.numTris()), pos(mesh.numTris());
+ vector<Real> weights(3 * mesh.numTris());
+ vector<int> index(3 * mesh.numTris());
+ for (int i = 0; i < mesh.numTris(); i++) {
+ pos[i] = mesh.getFaceCenter(i);
+ mesh.sheet(i).vorticitySmoothed = mesh.sheet(i).vorticity;
+ }
+ for (int i = 0; i < mesh.numTris(); i++) {
+ for (int c = 0; c < 3; c++) {
+ int oc = mesh.corners(i, c).opposite;
+ if (oc >= 0) {
+ int t = mesh.corners(oc).tri;
+ weights[3 * i + c] = exp(normSquare(pos[t] - pos[i]) * mult);
+ index[3 * i + c] = t;
+ }
+ else {
+ weights[3 * i + c] = 0;
+ index[3 * i + c] = 0;
+ }
+ }
+ }
+
+ for (int it = 0; it < iter; ++it) {
+ // first, preload
+ for (int i = 0; i < mesh.numTris(); i++)
+ vort[i] = mesh.sheet(i).vorticitySmoothed;
+
+ for (int i = 0, idx = 0; i < mesh.numTris(); i++) {
+ // loop over adjacent tris
+ Real sum = 1.0f;
+ Vec3 v = vort[i];
+ for (int c = 0; c < 3; c++, idx++) {
+ Real w = weights[index[idx]];
+ v += w * vort[index[idx]];
+ sum += w;
+ }
+ mesh.sheet(i).vorticitySmoothed = v / sum;
+ }
+ }
+ for (int i = 0; i < mesh.numTris(); i++)
+ mesh.sheet(i).vorticitySmoothed *= alpha;
+}
+static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "smoothVorticity", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ VortexSheetMesh &mesh = *_args.getPtr<VortexSheetMesh>("mesh", 0, &_lock);
+ int iter = _args.getOpt<int>("iter", 1, 1, &_lock);
+ Real sigma = _args.getOpt<Real>("sigma", 2, 0.2, &_lock);
+ Real alpha = _args.getOpt<Real>("alpha", 3, 0.8, &_lock);
+ _retval = getPyNone();
+ smoothVorticity(mesh, iter, sigma, alpha);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "smoothVorticity", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("smoothVorticity", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_smoothVorticity("", "smoothVorticity", _W_4);
+extern "C" {
+void PbRegister_smoothVorticity()
+{
+ KEEP_UNUSED(_RP_smoothVorticity);
+}
+}
+
+//! Seed Vortex Particles inside shape with K41 characteristics
+void VPseedK41(VortexParticleSystem &system,
+ const Shape *shape,
+ Real strength = 0,
+ Real sigma0 = 0.2,
+ Real sigma1 = 1.0,
+ Real probability = 1.0,
+ Real N = 3.0)
+{
+ Grid<Real> temp(system.getParent());
+ const Real dt = system.getParent()->getDt();
+ static RandomStream rand(3489572);
+ Real s0 = pow((Real)sigma0, (Real)(-N + 1.0));
+ Real s1 = pow((Real)sigma1, (Real)(-N + 1.0));
+
+ FOR_IJK(temp)
+ {
+ if (shape->isInsideGrid(i, j, k)) {
+ if (rand.getReal() < probability * dt) {
+ Real p = rand.getReal();
+ Real sigma = pow((1.0 - p) * s0 + p * s1, 1. / (-N + 1.0));
+ Vec3 randDir(rand.getReal(), rand.getReal(), rand.getReal());
+ Vec3 posUpd(i + rand.getReal(), j + rand.getReal(), k + rand.getReal());
+ normalize(randDir);
+ Vec3 vorticity = randDir * strength * pow((Real)sigma, (Real)(-10. / 6. + N / 2.0));
+ system.add(VortexParticleData(posUpd, vorticity, sigma));
+ }
+ }
+ }
+}
+static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "VPseedK41", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ VortexParticleSystem &system = *_args.getPtr<VortexParticleSystem>("system", 0, &_lock);
+ const Shape *shape = _args.getPtr<Shape>("shape", 1, &_lock);
+ Real strength = _args.getOpt<Real>("strength", 2, 0, &_lock);
+ Real sigma0 = _args.getOpt<Real>("sigma0", 3, 0.2, &_lock);
+ Real sigma1 = _args.getOpt<Real>("sigma1", 4, 1.0, &_lock);
+ Real probability = _args.getOpt<Real>("probability", 5, 1.0, &_lock);
+ Real N = _args.getOpt<Real>("N", 6, 3.0, &_lock);
+ _retval = getPyNone();
+ VPseedK41(system, shape, strength, sigma0, sigma1, probability, N);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "VPseedK41", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("VPseedK41", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_VPseedK41("", "VPseedK41", _W_5);
+extern "C" {
+void PbRegister_VPseedK41()
+{
+ KEEP_UNUSED(_RP_VPseedK41);
+}
+}
+
+//! Vortex-in-cell integration
+
+void VICintegration(VortexSheetMesh &mesh,
+ Real sigma,
+ Grid<Vec3> &vel,
+ const FlagGrid &flags,
+ Grid<Vec3> *vorticity = NULL,
+ Real cgMaxIterFac = 1.5,
+ Real cgAccuracy = 1e-3,
+ Real scale = 0.01,
+ int precondition = 0)
+{
+
+ MuTime t0;
+ const Real fac = 16.0; // experimental factor to balance out regularization
+
+ // if no vort grid is given, use a temporary one
+ Grid<Vec3> vortTemp(mesh.getParent());
+ Grid<Vec3> &vort = (vorticity) ? (*vorticity) : (vortTemp);
+ vort.clear();
+
+ // map vorticity to grid using Peskin kernel
+ int sgi = ceil(sigma);
+ Real pkfac = M_PI / sigma;
+ const int numTris = mesh.numTris();
+ for (int t = 0; t < numTris; t++) {
+ Vec3 pos = mesh.getFaceCenter(t);
+ Vec3 v = mesh.sheet(t).vorticity * mesh.getFaceArea(t) * fac;
+
+ // inner kernel
+ // first, summate
+ Real sum = 0;
+ for (int i = -sgi; i < sgi; i++) {
+ if (pos.x + i < 0 || (int)pos.x + i >= vort.getSizeX())
+ continue;
+ for (int j = -sgi; j < sgi; j++) {
+ if (pos.y + j < 0 || (int)pos.y + j >= vort.getSizeY())
+ continue;
+ for (int k = -sgi; k < sgi; k++) {
+ if (pos.z + k < 0 || (int)pos.z + k >= vort.getSizeZ())
+ continue;
+ Vec3i cell(pos.x + i, pos.y + j, pos.z + k);
+ if (!flags.isFluid(cell))
+ continue;
+ Vec3 d = pos -
+ Vec3(i + 0.5 + floor(pos.x), j + 0.5 + floor(pos.y), k + 0.5 + floor(pos.z));
+ Real dl = norm(d);
+ if (dl > sigma)
+ continue;
+ // precalc Peskin kernel
+ sum += 1.0 + cos(dl * pkfac);
+ }
+ }
+ }
+ // then, apply normalized kernel
+ Real wnorm = 1.0 / sum;
+ for (int i = -sgi; i < sgi; i++) {
+ if (pos.x + i < 0 || (int)pos.x + i >= vort.getSizeX())
+ continue;
+ for (int j = -sgi; j < sgi; j++) {
+ if (pos.y + j < 0 || (int)pos.y + j >= vort.getSizeY())
+ continue;
+ for (int k = -sgi; k < sgi; k++) {
+ if (pos.z + k < 0 || (int)pos.z + k >= vort.getSizeZ())
+ continue;
+ Vec3i cell(pos.x + i, pos.y + j, pos.z + k);
+ if (!flags.isFluid(cell))
+ continue;
+ Vec3 d = pos -
+ Vec3(i + 0.5 + floor(pos.x), j + 0.5 + floor(pos.y), k + 0.5 + floor(pos.z));
+ Real dl = norm(d);
+ if (dl > sigma)
+ continue;
+ Real w = (1.0 + cos(dl * pkfac)) * wnorm;
+ vort(cell) += v * w;
+ }
+ }
+ }
+ }
+
+ // Prepare grids for poisson solve
+ Grid<Vec3> vortexCurl(mesh.getParent());
+ Grid<Real> rhs(mesh.getParent());
+ Grid<Real> solution(mesh.getParent());
+ Grid<Real> residual(mesh.getParent());
+ Grid<Real> search(mesh.getParent());
+ Grid<Real> temp1(mesh.getParent());
+ Grid<Real> A0(mesh.getParent());
+ Grid<Real> Ai(mesh.getParent());
+ Grid<Real> Aj(mesh.getParent());
+ Grid<Real> Ak(mesh.getParent());
+ Grid<Real> pca0(mesh.getParent());
+ Grid<Real> pca1(mesh.getParent());
+ Grid<Real> pca2(mesh.getParent());
+ Grid<Real> pca3(mesh.getParent());
+
+ MakeLaplaceMatrix(flags, A0, Ai, Aj, Ak);
+ CurlOp(vort, vortexCurl);
+
+ // Solve vector poisson equation
+ for (int c = 0; c < 3; c++) {
+ // construct rhs
+ if (vel.getType() & GridBase::TypeMAC)
+ GetShiftedComponent(vortexCurl, rhs, c);
+ else
+ GetComponent(vortexCurl, rhs, c);
+
+ // prepare CG solver
+ const int maxIter = (int)(cgMaxIterFac * vel.getSize().max());
+ GridCgInterface *gcg = new GridCg<ApplyMatrix>(
+ solution, rhs, residual, search, flags, temp1, &A0, &Ai, &Aj, &Ak);
+ gcg->setAccuracy(cgAccuracy);
+ gcg->setUseL2Norm(true);
+ gcg->setICPreconditioner(
+ (GridCgInterface::PreconditionType)precondition, &pca0, &pca1, &pca2, &pca3);
+
+ // iterations
+ for (int iter = 0; iter < maxIter; iter++) {
+ if (!gcg->iterate())
+ iter = maxIter;
+ }
+ debMsg("VICintegration CG iterations:" << gcg->getIterations() << ", res:" << gcg->getSigma(),
+ 1);
+ delete gcg;
+
+ // copy back
+ solution *= scale;
+ SetComponent(vel, solution, c);
+ }
+}
+static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "VICintegration", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ VortexSheetMesh &mesh = *_args.getPtr<VortexSheetMesh>("mesh", 0, &_lock);
+ Real sigma = _args.get<Real>("sigma", 1, &_lock);
+ Grid<Vec3> &vel = *_args.getPtr<Grid<Vec3>>("vel", 2, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 3, &_lock);
+ Grid<Vec3> *vorticity = _args.getPtrOpt<Grid<Vec3>>("vorticity", 4, NULL, &_lock);
+ Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 5, 1.5, &_lock);
+ Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 6, 1e-3, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 7, 0.01, &_lock);
+ int precondition = _args.getOpt<int>("precondition", 8, 0, &_lock);
+ _retval = getPyNone();
+ VICintegration(
+ mesh, sigma, vel, flags, vorticity, cgMaxIterFac, cgAccuracy, scale, precondition);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "VICintegration", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("VICintegration", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_VICintegration("", "VICintegration", _W_6);
+extern "C" {
+void PbRegister_VICintegration()
+{
+ KEEP_UNUSED(_RP_VICintegration);
+}
+}
+
+//! Obtain density field from levelset with linear gradient of size sigma over the interface
+void densityFromLevelset(const LevelsetGrid &phi,
+ Grid<Real> &density,
+ Real value = 1.0,
+ Real sigma = 1.0)
+{
+ FOR_IJK(phi)
+ {
+ // remove boundary
+ if (i < 2 || j < 2 || k < 2 || i >= phi.getSizeX() - 2 || j >= phi.getSizeY() - 2 ||
+ k >= phi.getSizeZ() - 2)
+ density(i, j, k) = 0;
+ else if (phi(i, j, k) < -sigma)
+ density(i, j, k) = value;
+ else if (phi(i, j, k) > sigma)
+ density(i, j, k) = 0;
+ else
+ density(i, j, k) = clamp(
+ (Real)(0.5 * value / sigma * (1.0 - phi(i, j, k))), (Real)0.0, value);
+ }
+}
+static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "densityFromLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 0, &_lock);
+ Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
+ Real value = _args.getOpt<Real>("value", 2, 1.0, &_lock);
+ Real sigma = _args.getOpt<Real>("sigma", 3, 1.0, &_lock);
+ _retval = getPyNone();
+ densityFromLevelset(phi, density, value, sigma);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "densityFromLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("densityFromLevelset", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_densityFromLevelset("", "densityFromLevelset", _W_7);
+extern "C" {
+void PbRegister_densityFromLevelset()
+{
+ KEEP_UNUSED(_RP_densityFromLevelset);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/waveletturbulence.cpp b/extern/mantaflow/preprocessed/plugin/waveletturbulence.cpp
new file mode 100644
index 00000000000..9d3bdaa3f21
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/waveletturbulence.cpp
@@ -0,0 +1,1292 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Functions for calculating wavelet turbulence,
+ * plus helpers to compute vorticity, and strain rate magnitude
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "noisefield.h"
+
+using namespace std;
+
+namespace Manta {
+
+//*****************************************************************************
+
+// first some fairly generic interpolation functions for grids with multiple sizes
+
+//! same as in grid.h , but takes an additional optional "desired" size
+inline void calcGridSizeFactorMod(
+ Vec3i s1, Vec3i s2, Vec3i optSize, Vec3 scale, Vec3 &sourceFactor, Vec3 &retOff)
+{
+ for (int c = 0; c < 3; c++) {
+ if (optSize[c] > 0) {
+ s2[c] = optSize[c];
+ }
+ }
+ sourceFactor = calcGridSizeFactor(s1, s2) / scale;
+ retOff = -retOff * sourceFactor + sourceFactor * 0.5;
+}
+
+void interpolateGrid(Grid<Real> &target,
+ const Grid<Real> &source,
+ Vec3 scale = Vec3(1.),
+ Vec3 offset = Vec3(0.),
+ Vec3i size = Vec3i(-1, -1, -1),
+ int orderSpace = 1)
+{
+ Vec3 sourceFactor(1.), off2 = offset;
+ calcGridSizeFactorMod(source.getSize(), target.getSize(), size, scale, sourceFactor, off2);
+
+ // a brief note on a mantaflow specialty: the target grid has to be the first argument here!
+ // the parent fluidsolver object is taken from the first grid, and it determines the size of the
+ // loop for the kernel call. as we're writing into target, it's important to loop exactly over
+ // all cells of the target grid... (note, when calling the plugin in python, it doesnt matter
+ // anymore).
+
+ // sourceFactor offset necessary to shift eval points by half a small cell width
+ knInterpolateGridTempl<Real>(target, source, sourceFactor, off2, orderSpace);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "interpolateGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 0, &_lock);
+ const Grid<Real> &source = *_args.getPtr<Grid<Real>>("source", 1, &_lock);
+ Vec3 scale = _args.getOpt<Vec3>("scale", 2, Vec3(1.), &_lock);
+ Vec3 offset = _args.getOpt<Vec3>("offset", 3, Vec3(0.), &_lock);
+ Vec3i size = _args.getOpt<Vec3i>("size", 4, Vec3i(-1, -1, -1), &_lock);
+ int orderSpace = _args.getOpt<int>("orderSpace", 5, 1, &_lock);
+ _retval = getPyNone();
+ interpolateGrid(target, source, scale, offset, size, orderSpace);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "interpolateGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("interpolateGrid", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_interpolateGrid("", "interpolateGrid", _W_0);
+extern "C" {
+void PbRegister_interpolateGrid()
+{
+ KEEP_UNUSED(_RP_interpolateGrid);
+}
+}
+
+void interpolateGridVec3(Grid<Vec3> &target,
+ const Grid<Vec3> &source,
+ Vec3 scale = Vec3(1.),
+ Vec3 offset = Vec3(0.),
+ Vec3i size = Vec3i(-1, -1, -1),
+ int orderSpace = 1)
+{
+ Vec3 sourceFactor(1.), off2 = offset;
+ calcGridSizeFactorMod(source.getSize(), target.getSize(), size, scale, sourceFactor, off2);
+ knInterpolateGridTempl<Vec3>(target, source, sourceFactor, off2, orderSpace);
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "interpolateGridVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 0, &_lock);
+ const Grid<Vec3> &source = *_args.getPtr<Grid<Vec3>>("source", 1, &_lock);
+ Vec3 scale = _args.getOpt<Vec3>("scale", 2, Vec3(1.), &_lock);
+ Vec3 offset = _args.getOpt<Vec3>("offset", 3, Vec3(0.), &_lock);
+ Vec3i size = _args.getOpt<Vec3i>("size", 4, Vec3i(-1, -1, -1), &_lock);
+ int orderSpace = _args.getOpt<int>("orderSpace", 5, 1, &_lock);
+ _retval = getPyNone();
+ interpolateGridVec3(target, source, scale, offset, size, orderSpace);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "interpolateGridVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("interpolateGridVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_interpolateGridVec3("", "interpolateGridVec3", _W_1);
+extern "C" {
+void PbRegister_interpolateGridVec3()
+{
+ KEEP_UNUSED(_RP_interpolateGridVec3);
+}
+}
+
+//! interpolate a mac velocity grid from one size to another size
+
+struct KnInterpolateMACGrid : public KernelBase {
+ KnInterpolateMACGrid(MACGrid &target,
+ const MACGrid &source,
+ const Vec3 &sourceFactor,
+ const Vec3 &off,
+ int orderSpace)
+ : KernelBase(&target, 0),
+ target(target),
+ source(source),
+ sourceFactor(sourceFactor),
+ off(off),
+ orderSpace(orderSpace)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ MACGrid &target,
+ const MACGrid &source,
+ const Vec3 &sourceFactor,
+ const Vec3 &off,
+ int orderSpace) const
+ {
+ Vec3 pos = Vec3(i, j, k) * sourceFactor + off;
+
+ Real vx = source.getInterpolatedHi(pos - Vec3(0.5, 0, 0), orderSpace)[0];
+ Real vy = source.getInterpolatedHi(pos - Vec3(0, 0.5, 0), orderSpace)[1];
+ Real vz = 0.f;
+ if (source.is3D())
+ vz = source.getInterpolatedHi(pos - Vec3(0, 0, 0.5), orderSpace)[2];
+
+ target(i, j, k) = Vec3(vx, vy, vz);
+ }
+ inline MACGrid &getArg0()
+ {
+ return target;
+ }
+ typedef MACGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return source;
+ }
+ typedef MACGrid type1;
+ inline const Vec3 &getArg2()
+ {
+ return sourceFactor;
+ }
+ typedef Vec3 type2;
+ inline const Vec3 &getArg3()
+ {
+ return off;
+ }
+ typedef Vec3 type3;
+ inline int &getArg4()
+ {
+ return orderSpace;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnInterpolateMACGrid ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, target, source, sourceFactor, off, orderSpace);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, target, source, sourceFactor, off, orderSpace);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ MACGrid &target;
+ const MACGrid &source;
+ const Vec3 &sourceFactor;
+ const Vec3 &off;
+ int orderSpace;
+};
+
+void interpolateMACGrid(MACGrid &target,
+ const MACGrid &source,
+ Vec3 scale = Vec3(1.),
+ Vec3 offset = Vec3(0.),
+ Vec3i size = Vec3i(-1, -1, -1),
+ int orderSpace = 1)
+{
+ Vec3 sourceFactor(1.), off2 = offset;
+ calcGridSizeFactorMod(source.getSize(), target.getSize(), size, scale, sourceFactor, off2);
+ KnInterpolateMACGrid(target, source, sourceFactor, off2, orderSpace);
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "interpolateMACGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &target = *_args.getPtr<MACGrid>("target", 0, &_lock);
+ const MACGrid &source = *_args.getPtr<MACGrid>("source", 1, &_lock);
+ Vec3 scale = _args.getOpt<Vec3>("scale", 2, Vec3(1.), &_lock);
+ Vec3 offset = _args.getOpt<Vec3>("offset", 3, Vec3(0.), &_lock);
+ Vec3i size = _args.getOpt<Vec3i>("size", 4, Vec3i(-1, -1, -1), &_lock);
+ int orderSpace = _args.getOpt<int>("orderSpace", 5, 1, &_lock);
+ _retval = getPyNone();
+ interpolateMACGrid(target, source, scale, offset, size, orderSpace);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "interpolateMACGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("interpolateMACGrid", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_interpolateMACGrid("", "interpolateMACGrid", _W_2);
+extern "C" {
+void PbRegister_interpolateMACGrid()
+{
+ KEEP_UNUSED(_RP_interpolateMACGrid);
+}
+}
+
+//*****************************************************************************
+
+//! Apply vector noise to grid, this is a simplified version - no position scaling or UVs
+
+struct knApplySimpleNoiseVec3 : public KernelBase {
+ knApplySimpleNoiseVec3(const FlagGrid &flags,
+ Grid<Vec3> &target,
+ const WaveletNoiseField &noise,
+ Real scale,
+ const Grid<Real> *weight)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ target(target),
+ noise(noise),
+ scale(scale),
+ weight(weight)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Vec3> &target,
+ const WaveletNoiseField &noise,
+ Real scale,
+ const Grid<Real> *weight) const
+ {
+ if (!flags.isFluid(i, j, k))
+ return;
+ Real factor = 1;
+ if (weight)
+ factor = (*weight)(i, j, k);
+ target(i, j, k) += noise.evaluateCurl(Vec3(i, j, k) + Vec3(0.5)) * scale * factor;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Vec3> &getArg1()
+ {
+ return target;
+ }
+ typedef Grid<Vec3> type1;
+ inline const WaveletNoiseField &getArg2()
+ {
+ return noise;
+ }
+ typedef WaveletNoiseField type2;
+ inline Real &getArg3()
+ {
+ return scale;
+ }
+ typedef Real type3;
+ inline const Grid<Real> *getArg4()
+ {
+ return weight;
+ }
+ typedef Grid<Real> type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knApplySimpleNoiseVec3 ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, target, noise, scale, weight);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, target, noise, scale, weight);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Vec3> &target;
+ const WaveletNoiseField &noise;
+ Real scale;
+ const Grid<Real> *weight;
+};
+
+void applySimpleNoiseVec3(const FlagGrid &flags,
+ Grid<Vec3> &target,
+ const WaveletNoiseField &noise,
+ Real scale = 1.0,
+ const Grid<Real> *weight = NULL)
+{
+ // note - passing a MAC grid here is slightly inaccurate, we should evaluate each component
+ // separately
+ knApplySimpleNoiseVec3(flags, target, noise, scale, weight);
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "applySimpleNoiseVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock);
+ const WaveletNoiseField &noise = *_args.getPtr<WaveletNoiseField>("noise", 2, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 3, 1.0, &_lock);
+ const Grid<Real> *weight = _args.getPtrOpt<Grid<Real>>("weight", 4, NULL, &_lock);
+ _retval = getPyNone();
+ applySimpleNoiseVec3(flags, target, noise, scale, weight);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "applySimpleNoiseVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("applySimpleNoiseVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_applySimpleNoiseVec3("", "applySimpleNoiseVec3", _W_3);
+extern "C" {
+void PbRegister_applySimpleNoiseVec3()
+{
+ KEEP_UNUSED(_RP_applySimpleNoiseVec3);
+}
+}
+
+//! Simple noise for a real grid , follows applySimpleNoiseVec3
+
+struct knApplySimpleNoiseReal : public KernelBase {
+ knApplySimpleNoiseReal(const FlagGrid &flags,
+ Grid<Real> &target,
+ const WaveletNoiseField &noise,
+ Real scale,
+ const Grid<Real> *weight)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ target(target),
+ noise(noise),
+ scale(scale),
+ weight(weight)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Real> &target,
+ const WaveletNoiseField &noise,
+ Real scale,
+ const Grid<Real> *weight) const
+ {
+ if (!flags.isFluid(i, j, k))
+ return;
+ Real factor = 1;
+ if (weight)
+ factor = (*weight)(i, j, k);
+ target(i, j, k) += noise.evaluate(Vec3(i, j, k) + Vec3(0.5)) * scale * factor;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return target;
+ }
+ typedef Grid<Real> type1;
+ inline const WaveletNoiseField &getArg2()
+ {
+ return noise;
+ }
+ typedef WaveletNoiseField type2;
+ inline Real &getArg3()
+ {
+ return scale;
+ }
+ typedef Real type3;
+ inline const Grid<Real> *getArg4()
+ {
+ return weight;
+ }
+ typedef Grid<Real> type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knApplySimpleNoiseReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, target, noise, scale, weight);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, target, noise, scale, weight);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &target;
+ const WaveletNoiseField &noise;
+ Real scale;
+ const Grid<Real> *weight;
+};
+
+void applySimpleNoiseReal(const FlagGrid &flags,
+ Grid<Real> &target,
+ const WaveletNoiseField &noise,
+ Real scale = 1.0,
+ const Grid<Real> *weight = NULL)
+{
+ knApplySimpleNoiseReal(flags, target, noise, scale, weight);
+}
+static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "applySimpleNoiseReal", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 1, &_lock);
+ const WaveletNoiseField &noise = *_args.getPtr<WaveletNoiseField>("noise", 2, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 3, 1.0, &_lock);
+ const Grid<Real> *weight = _args.getPtrOpt<Grid<Real>>("weight", 4, NULL, &_lock);
+ _retval = getPyNone();
+ applySimpleNoiseReal(flags, target, noise, scale, weight);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "applySimpleNoiseReal", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("applySimpleNoiseReal", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_applySimpleNoiseReal("", "applySimpleNoiseReal", _W_4);
+extern "C" {
+void PbRegister_applySimpleNoiseReal()
+{
+ KEEP_UNUSED(_RP_applySimpleNoiseReal);
+}
+}
+
+//! Apply vector-based wavelet noise to target grid
+//! This is the version with more functionality - supports uv grids, and on-the-fly interpolation
+//! of input grids.
+
+struct knApplyNoiseVec3 : public KernelBase {
+ knApplyNoiseVec3(const FlagGrid &flags,
+ Grid<Vec3> &target,
+ const WaveletNoiseField &noise,
+ Real scale,
+ Real scaleSpatial,
+ const Grid<Real> *weight,
+ const Grid<Vec3> *uv,
+ bool uvInterpol,
+ const Vec3 &sourceFactor)
+ : KernelBase(&flags, 0),
+ flags(flags),
+ target(target),
+ noise(noise),
+ scale(scale),
+ scaleSpatial(scaleSpatial),
+ weight(weight),
+ uv(uv),
+ uvInterpol(uvInterpol),
+ sourceFactor(sourceFactor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Vec3> &target,
+ const WaveletNoiseField &noise,
+ Real scale,
+ Real scaleSpatial,
+ const Grid<Real> *weight,
+ const Grid<Vec3> *uv,
+ bool uvInterpol,
+ const Vec3 &sourceFactor) const
+ {
+ if (!flags.isFluid(i, j, k))
+ return;
+
+ // get weighting, interpolate if necessary
+ Real w = 1;
+ if (weight) {
+ if (!uvInterpol) {
+ w = (*weight)(i, j, k);
+ }
+ else {
+ w = weight->getInterpolated(Vec3(i, j, k) * sourceFactor);
+ }
+ }
+
+ // compute position where to evaluate the noise
+ Vec3 pos = Vec3(i, j, k) + Vec3(0.5);
+ if (uv) {
+ if (!uvInterpol) {
+ pos = (*uv)(i, j, k);
+ }
+ else {
+ pos = uv->getInterpolated(Vec3(i, j, k) * sourceFactor);
+ // uv coordinates are in local space - so we need to adjust the values of the positions
+ pos /= sourceFactor;
+ }
+ }
+ pos *= scaleSpatial;
+
+ Vec3 noiseVec3 = noise.evaluateCurl(pos) * scale * w;
+ // noiseVec3=pos; // debug , show interpolated positions
+ target(i, j, k) += noiseVec3;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Vec3> &getArg1()
+ {
+ return target;
+ }
+ typedef Grid<Vec3> type1;
+ inline const WaveletNoiseField &getArg2()
+ {
+ return noise;
+ }
+ typedef WaveletNoiseField type2;
+ inline Real &getArg3()
+ {
+ return scale;
+ }
+ typedef Real type3;
+ inline Real &getArg4()
+ {
+ return scaleSpatial;
+ }
+ typedef Real type4;
+ inline const Grid<Real> *getArg5()
+ {
+ return weight;
+ }
+ typedef Grid<Real> type5;
+ inline const Grid<Vec3> *getArg6()
+ {
+ return uv;
+ }
+ typedef Grid<Vec3> type6;
+ inline bool &getArg7()
+ {
+ return uvInterpol;
+ }
+ typedef bool type7;
+ inline const Vec3 &getArg8()
+ {
+ return sourceFactor;
+ }
+ typedef Vec3 type8;
+ void runMessage()
+ {
+ debMsg("Executing kernel knApplyNoiseVec3 ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ flags,
+ target,
+ noise,
+ scale,
+ scaleSpatial,
+ weight,
+ uv,
+ uvInterpol,
+ sourceFactor);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i,
+ j,
+ k,
+ flags,
+ target,
+ noise,
+ scale,
+ scaleSpatial,
+ weight,
+ uv,
+ uvInterpol,
+ sourceFactor);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Vec3> &target;
+ const WaveletNoiseField &noise;
+ Real scale;
+ Real scaleSpatial;
+ const Grid<Real> *weight;
+ const Grid<Vec3> *uv;
+ bool uvInterpol;
+ const Vec3 &sourceFactor;
+};
+
+void applyNoiseVec3(const FlagGrid &flags,
+ Grid<Vec3> &target,
+ const WaveletNoiseField &noise,
+ Real scale = 1.0,
+ Real scaleSpatial = 1.0,
+ const Grid<Real> *weight = NULL,
+ const Grid<Vec3> *uv = NULL)
+{
+ // check whether the uv grid has a different resolution
+ bool uvInterpol = false;
+ // and pre-compute conversion (only used if uvInterpol==true)
+ // used for both uv and weight grid...
+ Vec3 sourceFactor = Vec3(1.);
+ if (uv) {
+ uvInterpol = (target.getSize() != uv->getSize());
+ sourceFactor = calcGridSizeFactor(uv->getSize(), target.getSize());
+ }
+ else if (weight) {
+ uvInterpol = (target.getSize() != weight->getSize());
+ sourceFactor = calcGridSizeFactor(weight->getSize(), target.getSize());
+ }
+ if (uv && weight)
+ assertMsg(uv->getSize() == weight->getSize(), "UV and weight grid have to match!");
+
+ // note - passing a MAC grid here is slightly inaccurate, we should evaluate each component
+ // separately
+ knApplyNoiseVec3(
+ flags, target, noise, scale, scaleSpatial, weight, uv, uvInterpol, sourceFactor);
+}
+static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "applyNoiseVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock);
+ const WaveletNoiseField &noise = *_args.getPtr<WaveletNoiseField>("noise", 2, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 3, 1.0, &_lock);
+ Real scaleSpatial = _args.getOpt<Real>("scaleSpatial", 4, 1.0, &_lock);
+ const Grid<Real> *weight = _args.getPtrOpt<Grid<Real>>("weight", 5, NULL, &_lock);
+ const Grid<Vec3> *uv = _args.getPtrOpt<Grid<Vec3>>("uv", 6, NULL, &_lock);
+ _retval = getPyNone();
+ applyNoiseVec3(flags, target, noise, scale, scaleSpatial, weight, uv);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "applyNoiseVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("applyNoiseVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_applyNoiseVec3("", "applyNoiseVec3", _W_5);
+extern "C" {
+void PbRegister_applyNoiseVec3()
+{
+ KEEP_UNUSED(_RP_applyNoiseVec3);
+}
+}
+
+//! Compute energy of a staggered velocity field (at cell center)
+
+struct KnApplyComputeEnergy : public KernelBase {
+ KnApplyComputeEnergy(const FlagGrid &flags, const MACGrid &vel, Grid<Real> &energy)
+ : KernelBase(&flags, 0), flags(flags), vel(vel), energy(energy)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, const FlagGrid &flags, const MACGrid &vel, Grid<Real> &energy) const
+ {
+ Real e = 0.f;
+ if (flags.isFluid(i, j, k)) {
+ Vec3 v = vel.getCentered(i, j, k);
+ e = 0.5 * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ }
+ energy(i, j, k) = e;
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline const MACGrid &getArg1()
+ {
+ return vel;
+ }
+ typedef MACGrid type1;
+ inline Grid<Real> &getArg2()
+ {
+ return energy;
+ }
+ typedef Grid<Real> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnApplyComputeEnergy ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, vel, energy);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, flags, vel, energy);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ Grid<Real> &energy;
+};
+
+void computeEnergy(const FlagGrid &flags, const MACGrid &vel, Grid<Real> &energy)
+{
+ KnApplyComputeEnergy(flags, vel, energy);
+}
+static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "computeEnergy", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ Grid<Real> &energy = *_args.getPtr<Grid<Real>>("energy", 2, &_lock);
+ _retval = getPyNone();
+ computeEnergy(flags, vel, energy);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "computeEnergy", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("computeEnergy", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_computeEnergy("", "computeEnergy", _W_6);
+extern "C" {
+void PbRegister_computeEnergy()
+{
+ KEEP_UNUSED(_RP_computeEnergy);
+}
+}
+
+void computeWaveletCoeffs(Grid<Real> &input)
+{
+ Grid<Real> temp1(input.getParent()), temp2(input.getParent());
+ WaveletNoiseField::computeCoefficients(input, temp1, temp2);
+}
+static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "computeWaveletCoeffs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &input = *_args.getPtr<Grid<Real>>("input", 0, &_lock);
+ _retval = getPyNone();
+ computeWaveletCoeffs(input);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "computeWaveletCoeffs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("computeWaveletCoeffs", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_computeWaveletCoeffs("", "computeWaveletCoeffs", _W_7);
+extern "C" {
+void PbRegister_computeWaveletCoeffs()
+{
+ KEEP_UNUSED(_RP_computeWaveletCoeffs);
+}
+}
+
+// note - alomst the same as for vorticity confinement
+void computeVorticity(const MACGrid &vel, Grid<Vec3> &vorticity, Grid<Real> *norm = NULL)
+{
+ Grid<Vec3> velCenter(vel.getParent());
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, vorticity);
+ if (norm)
+ GridNorm(*norm, vorticity);
+}
+static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "computeVorticity", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ Grid<Vec3> &vorticity = *_args.getPtr<Grid<Vec3>>("vorticity", 1, &_lock);
+ Grid<Real> *norm = _args.getPtrOpt<Grid<Real>>("norm", 2, NULL, &_lock);
+ _retval = getPyNone();
+ computeVorticity(vel, vorticity, norm);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "computeVorticity", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("computeVorticity", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_computeVorticity("", "computeVorticity", _W_8);
+extern "C" {
+void PbRegister_computeVorticity()
+{
+ KEEP_UNUSED(_RP_computeVorticity);
+}
+}
+
+// note - very similar to KnComputeProductionStrain, but for use as wavelet turb weighting
+
+struct KnComputeStrainRateMag : public KernelBase {
+ KnComputeStrainRateMag(const MACGrid &vel, const Grid<Vec3> &velCenter, Grid<Real> &prod)
+ : KernelBase(&vel, 1), vel(vel), velCenter(velCenter), prod(prod)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, const MACGrid &vel, const Grid<Vec3> &velCenter, Grid<Real> &prod) const
+ {
+ // compute Sij = 1/2 * (dU_i/dx_j + dU_j/dx_i)
+ Vec3 diag = Vec3(vel(i + 1, j, k).x, vel(i, j + 1, k).y, 0.) - vel(i, j, k);
+ if (vel.is3D())
+ diag[2] += vel(i, j, k + 1).z;
+ else
+ diag[2] = 0.;
+
+ Vec3 ux = 0.5 * (velCenter(i + 1, j, k) - velCenter(i - 1, j, k));
+ Vec3 uy = 0.5 * (velCenter(i, j + 1, k) - velCenter(i, j - 1, k));
+ Vec3 uz;
+ if (vel.is3D())
+ uz = 0.5 * (velCenter(i, j, k + 1) - velCenter(i, j, k - 1));
+
+ Real S12 = 0.5 * (ux.y + uy.x);
+ Real S13 = 0.5 * (ux.z + uz.x);
+ Real S23 = 0.5 * (uy.z + uz.y);
+ Real S2 = square(diag.x) + square(diag.y) + square(diag.z) + 2.0 * square(S12) +
+ 2.0 * square(S13) + 2.0 * square(S23);
+ prod(i, j, k) = S2;
+ }
+ inline const MACGrid &getArg0()
+ {
+ return vel;
+ }
+ typedef MACGrid type0;
+ inline const Grid<Vec3> &getArg1()
+ {
+ return velCenter;
+ }
+ typedef Grid<Vec3> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return prod;
+ }
+ typedef Grid<Real> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnComputeStrainRateMag ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, velCenter, prod);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, vel, velCenter, prod);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const MACGrid &vel;
+ const Grid<Vec3> &velCenter;
+ Grid<Real> &prod;
+};
+void computeStrainRateMag(const MACGrid &vel, Grid<Real> &mag)
+{
+ Grid<Vec3> velCenter(vel.getParent());
+ GetCentered(velCenter, vel);
+ KnComputeStrainRateMag(vel, velCenter, mag);
+}
+static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "computeStrainRateMag", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ Grid<Real> &mag = *_args.getPtr<Grid<Real>>("mag", 1, &_lock);
+ _retval = getPyNone();
+ computeStrainRateMag(vel, mag);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "computeStrainRateMag", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("computeStrainRateMag", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_computeStrainRateMag("", "computeStrainRateMag", _W_9);
+extern "C" {
+void PbRegister_computeStrainRateMag()
+{
+ KEEP_UNUSED(_RP_computeStrainRateMag);
+}
+}
+
+// extrapolate a real grid into a flagged region (based on initial flags)
+// by default extrapolates from fluid to obstacle cells
+template<class T>
+void extrapolSimpleFlagsHelper(const FlagGrid &flags,
+ Grid<T> &val,
+ int distance = 4,
+ int flagFrom = FlagGrid::TypeFluid,
+ int flagTo = FlagGrid::TypeObstacle)
+{
+ Grid<int> tmp(flags.getParent());
+ int dim = (flags.is3D() ? 3 : 2);
+ const Vec3i nb[6] = {Vec3i(1, 0, 0),
+ Vec3i(-1, 0, 0),
+ Vec3i(0, 1, 0),
+ Vec3i(0, -1, 0),
+ Vec3i(0, 0, 1),
+ Vec3i(0, 0, -1)};
+
+ // remove all fluid cells (set to 1)
+ tmp.clear();
+ bool foundTarget = false;
+ FOR_IJK_BND(flags, 0)
+ {
+ if (flags(i, j, k) & flagFrom)
+ tmp(Vec3i(i, j, k)) = 1;
+ if (!foundTarget && (flags(i, j, k) & flagTo))
+ foundTarget = true;
+ }
+ // optimization, skip extrapolation if we dont have any cells to extrapolate to
+ if (!foundTarget) {
+ debMsg("No target cells found, skipping extrapolation", 1);
+ return;
+ }
+
+ // extrapolate for given distance
+ for (int d = 1; d < 1 + distance; ++d) {
+
+ // TODO, parallelize
+ FOR_IJK_BND(flags, 1)
+ {
+ if (tmp(i, j, k) != 0)
+ continue;
+ if (!(flags(i, j, k) & flagTo))
+ continue;
+
+ // copy from initialized neighbors
+ Vec3i p(i, j, k);
+ int nbs = 0;
+ T avgVal = 0.;
+ for (int n = 0; n < 2 * dim; ++n) {
+ if (tmp(p + nb[n]) == d) {
+ avgVal += val(p + nb[n]);
+ nbs++;
+ }
+ }
+
+ if (nbs > 0) {
+ tmp(p) = d + 1;
+ val(p) = avgVal / nbs;
+ }
+ }
+
+ } // distance
+}
+
+void extrapolateSimpleFlags(const FlagGrid &flags,
+ GridBase *val,
+ int distance = 4,
+ int flagFrom = FlagGrid::TypeFluid,
+ int flagTo = FlagGrid::TypeObstacle)
+{
+ if (val->getType() & GridBase::TypeReal) {
+ extrapolSimpleFlagsHelper<Real>(flags, *((Grid<Real> *)val), distance, flagFrom, flagTo);
+ }
+ else if (val->getType() & GridBase::TypeInt) {
+ extrapolSimpleFlagsHelper<int>(flags, *((Grid<int> *)val), distance, flagFrom, flagTo);
+ }
+ else if (val->getType() & GridBase::TypeVec3) {
+ extrapolSimpleFlagsHelper<Vec3>(flags, *((Grid<Vec3> *)val), distance, flagFrom, flagTo);
+ }
+ else
+ errMsg("extrapolateSimpleFlags: Grid Type is not supported (only int, Real, Vec3)");
+}
+static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "extrapolateSimpleFlags", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ GridBase *val = _args.getPtr<GridBase>("val", 1, &_lock);
+ int distance = _args.getOpt<int>("distance", 2, 4, &_lock);
+ int flagFrom = _args.getOpt<int>("flagFrom", 3, FlagGrid::TypeFluid, &_lock);
+ int flagTo = _args.getOpt<int>("flagTo", 4, FlagGrid::TypeObstacle, &_lock);
+ _retval = getPyNone();
+ extrapolateSimpleFlags(flags, val, distance, flagFrom, flagTo);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "extrapolateSimpleFlags", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("extrapolateSimpleFlags", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_extrapolateSimpleFlags("", "extrapolateSimpleFlags", _W_10);
+extern "C" {
+void PbRegister_extrapolateSimpleFlags()
+{
+ KEEP_UNUSED(_RP_extrapolateSimpleFlags);
+}
+}
+
+//! convert vel to a centered grid, then compute its curl
+void getCurl(const MACGrid &vel, Grid<Real> &vort, int comp)
+{
+ Grid<Vec3> velCenter(vel.getParent()), curl(vel.getParent());
+
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, curl);
+ GetComponent(curl, vort, comp);
+}
+static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "getCurl", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ Grid<Real> &vort = *_args.getPtr<Grid<Real>>("vort", 1, &_lock);
+ int comp = _args.get<int>("comp", 2, &_lock);
+ _retval = getPyNone();
+ getCurl(vel, vort, comp);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getCurl", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getCurl", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getCurl("", "getCurl", _W_11);
+extern "C" {
+void PbRegister_getCurl()
+{
+ KEEP_UNUSED(_RP_getCurl);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/plugin/waves.cpp b/extern/mantaflow/preprocessed/plugin/waves.cpp
new file mode 100644
index 00000000000..7745dce4711
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/waves.cpp
@@ -0,0 +1,483 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Wave equation
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include "conjugategrad.h"
+#include <cmath>
+
+using namespace std;
+
+namespace Manta {
+
+/******************************************************************************
+ *
+ * explicit integration
+ *
+ ******************************************************************************/
+
+struct knCalcSecDeriv2d : public KernelBase {
+ knCalcSecDeriv2d(const Grid<Real> &v, Grid<Real> &ret) : KernelBase(&v, 1), v(v), ret(ret)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const Grid<Real> &v, Grid<Real> &ret) const
+ {
+ ret(i, j, k) = (-4. * v(i, j, k) + v(i - 1, j, k) + v(i + 1, j, k) + v(i, j - 1, k) +
+ v(i, j + 1, k));
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return v;
+ }
+ typedef Grid<Real> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return ret;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCalcSecDeriv2d ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, v, ret);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, v, ret);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const Grid<Real> &v;
+ Grid<Real> &ret;
+};
+;
+
+//! calculate a second derivative for the wave equation
+void calcSecDeriv2d(const Grid<Real> &v, Grid<Real> &curv)
+{
+ knCalcSecDeriv2d(v, curv);
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "calcSecDeriv2d", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Real> &v = *_args.getPtr<Grid<Real>>("v", 0, &_lock);
+ Grid<Real> &curv = *_args.getPtr<Grid<Real>>("curv", 1, &_lock);
+ _retval = getPyNone();
+ calcSecDeriv2d(v, curv);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "calcSecDeriv2d", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("calcSecDeriv2d", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_calcSecDeriv2d("", "calcSecDeriv2d", _W_0);
+extern "C" {
+void PbRegister_calcSecDeriv2d()
+{
+ KEEP_UNUSED(_RP_calcSecDeriv2d);
+}
+}
+
+// mass conservation
+
+struct knTotalSum : public KernelBase {
+ knTotalSum(Grid<Real> &h) : KernelBase(&h, 1), h(h), sum(0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Real> &h, double &sum)
+ {
+ sum += h(i, j, k);
+ }
+ inline operator double()
+ {
+ return sum;
+ }
+ inline double &getRet()
+ {
+ return sum;
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return h;
+ }
+ typedef Grid<Real> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel knTotalSum ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, h, sum);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, h, sum);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ knTotalSum(knTotalSum &o, tbb::split) : KernelBase(o), h(o.h), sum(0)
+ {
+ }
+ void join(const knTotalSum &o)
+ {
+ sum += o.sum;
+ }
+ Grid<Real> &h;
+ double sum;
+};
+
+//! calculate the sum of all values in a grid (for wave equation solves)
+Real totalSum(Grid<Real> &height)
+{
+ knTotalSum ts(height);
+ return ts.sum;
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "totalSum", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &height = *_args.getPtr<Grid<Real>>("height", 0, &_lock);
+ _retval = toPy(totalSum(height));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "totalSum", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("totalSum", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_totalSum("", "totalSum", _W_1);
+extern "C" {
+void PbRegister_totalSum()
+{
+ KEEP_UNUSED(_RP_totalSum);
+}
+}
+
+//! normalize all values in a grid (for wave equation solves)
+void normalizeSumTo(Grid<Real> &height, Real target)
+{
+ knTotalSum ts(height);
+ Real factor = target / ts.sum;
+ height.multConst(factor);
+}
+static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "normalizeSumTo", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &height = *_args.getPtr<Grid<Real>>("height", 0, &_lock);
+ Real target = _args.get<Real>("target", 1, &_lock);
+ _retval = getPyNone();
+ normalizeSumTo(height, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "normalizeSumTo", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("normalizeSumTo", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_normalizeSumTo("", "normalizeSumTo", _W_2);
+extern "C" {
+void PbRegister_normalizeSumTo()
+{
+ KEEP_UNUSED(_RP_normalizeSumTo);
+}
+}
+
+/******************************************************************************
+ *
+ * implicit time integration
+ *
+ ******************************************************************************/
+
+//! Kernel: Construct the right-hand side of the poisson equation
+
+struct MakeRhsWE : public KernelBase {
+ MakeRhsWE(const FlagGrid &flags,
+ Grid<Real> &rhs,
+ const Grid<Real> &ut,
+ const Grid<Real> &utm1,
+ Real s,
+ bool crankNic = false)
+ : KernelBase(&flags, 1), flags(flags), rhs(rhs), ut(ut), utm1(utm1), s(s), crankNic(crankNic)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<Real> &rhs,
+ const Grid<Real> &ut,
+ const Grid<Real> &utm1,
+ Real s,
+ bool crankNic = false) const
+ {
+ rhs(i, j, k) = (2. * ut(i, j, k) - utm1(i, j, k));
+ if (crankNic) {
+ rhs(i, j, k) += s * (-4. * ut(i, j, k) + 1. * ut(i - 1, j, k) + 1. * ut(i + 1, j, k) +
+ 1. * ut(i, j - 1, k) + 1. * ut(i, j + 1, k));
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<Real> &getArg1()
+ {
+ return rhs;
+ }
+ typedef Grid<Real> type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return ut;
+ }
+ typedef Grid<Real> type2;
+ inline const Grid<Real> &getArg3()
+ {
+ return utm1;
+ }
+ typedef Grid<Real> type3;
+ inline Real &getArg4()
+ {
+ return s;
+ }
+ typedef Real type4;
+ inline bool &getArg5()
+ {
+ return crankNic;
+ }
+ typedef bool type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel MakeRhsWE ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, rhs, ut, utm1, s, crankNic);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, rhs, ut, utm1, s, crankNic);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<Real> &rhs;
+ const Grid<Real> &ut;
+ const Grid<Real> &utm1;
+ Real s;
+ bool crankNic;
+};
+
+//! do a CG solve for the wave equation (note, out grid only there for debugging... could be
+//! removed)
+
+void cgSolveWE(const FlagGrid &flags,
+ Grid<Real> &ut,
+ Grid<Real> &utm1,
+ Grid<Real> &out,
+ bool crankNic = false,
+ Real cSqr = 0.25,
+ Real cgMaxIterFac = 1.5,
+ Real cgAccuracy = 1e-5)
+{
+ // reserve temp grids
+ FluidSolver *parent = flags.getParent();
+ Grid<Real> rhs(parent);
+ Grid<Real> residual(parent);
+ Grid<Real> search(parent);
+ Grid<Real> A0(parent);
+ Grid<Real> Ai(parent);
+ Grid<Real> Aj(parent);
+ Grid<Real> Ak(parent);
+ Grid<Real> tmp(parent);
+ // solution...
+ out.clear();
+
+ // setup matrix and boundaries
+ MakeLaplaceMatrix(flags, A0, Ai, Aj, Ak);
+ Real dt = parent->getDt();
+ Real s = dt * dt * cSqr * 0.5;
+ FOR_IJK(flags)
+ {
+ Ai(i, j, k) *= s;
+ Aj(i, j, k) *= s;
+ Ak(i, j, k) *= s;
+ A0(i, j, k) *= s;
+ A0(i, j, k) += 1.;
+ }
+
+ // compute divergence and init right hand side
+ rhs.clear();
+ // h=dt
+ // rhs: = 2 ut - ut-1
+ // A: (h2 c2/ dx)=s , (1+4s)uij + s ui-1j + ...
+ // Cr.Nic.
+ // rhs: cr nic = 2 ut - ut-1 + h^2c^2/2 b
+ // A: (h2 c2/2 dx)=s , (1+4s)uij + s ui-1j + ...
+ MakeRhsWE kernMakeRhs(flags, rhs, ut, utm1, s, crankNic);
+
+ const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+ GridCgInterface *gcg;
+ if (flags.is3D())
+ gcg = new GridCg<ApplyMatrix>(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+ else
+ gcg = new GridCg<ApplyMatrix2D>(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+
+ gcg->setAccuracy(cgAccuracy);
+
+ // no preconditioning for now...
+ for (int iter = 0; iter < maxIter; iter++) {
+ if (!gcg->iterate())
+ iter = maxIter;
+ }
+ debMsg("cgSolveWaveEq iterations:" << gcg->getIterations() << ", res:" << gcg->getSigma(), 1);
+
+ utm1.swap(ut);
+ ut.copyFrom(out);
+
+ delete gcg;
+}
+static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "cgSolveWE", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &ut = *_args.getPtr<Grid<Real>>("ut", 1, &_lock);
+ Grid<Real> &utm1 = *_args.getPtr<Grid<Real>>("utm1", 2, &_lock);
+ Grid<Real> &out = *_args.getPtr<Grid<Real>>("out", 3, &_lock);
+ bool crankNic = _args.getOpt<bool>("crankNic", 4, false, &_lock);
+ Real cSqr = _args.getOpt<Real>("cSqr", 5, 0.25, &_lock);
+ Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 6, 1.5, &_lock);
+ Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 7, 1e-5, &_lock);
+ _retval = getPyNone();
+ cgSolveWE(flags, ut, utm1, out, crankNic, cSqr, cgMaxIterFac, cgAccuracy);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "cgSolveWE", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("cgSolveWE", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_cgSolveWE("", "cgSolveWE", _W_3);
+extern "C" {
+void PbRegister_cgSolveWE()
+{
+ KEEP_UNUSED(_RP_cgSolveWE);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/python/defines.py b/extern/mantaflow/preprocessed/python/defines.py
new file mode 100644
index 00000000000..1c7f01ab034
--- /dev/null
+++ b/extern/mantaflow/preprocessed/python/defines.py
@@ -0,0 +1,11 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
diff --git a/extern/mantaflow/preprocessed/python/defines.py.reg.cpp b/extern/mantaflow/preprocessed/python/defines.py.reg.cpp
new file mode 100644
index 00000000000..1866957534c
--- /dev/null
+++ b/extern/mantaflow/preprocessed/python/defines.py.reg.cpp
@@ -0,0 +1,24 @@
+#include "registry.h"
+static const Pb::Register _reg(
+ "python/defines.py",
+ "################################################################################\n#\n# "
+ "MantaFlow fluid solver framework\n# Copyright 2011 Tobias Pfaff, Nils Thuerey \n#\n# This "
+ "program is free software, distributed under the terms of the\n# Apache License, Version 2.0 "
+ "\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Defines some constants for use in "
+ "python "
+ "subprograms\n#\n#############################################################################"
+ "####\n\n# mantaflow conventions\nReal = float\n\n# some defines to make C code and scripts "
+ "more alike...\nfalse = False\ntrue = True\nVec3 = vec3\nVec4 = vec4\nVec3Grid = "
+ "VecGrid\n\n# grid flags\nFlagFluid = 1\nFlagObstacle = 2\nFlagEmpty = 4\nFlagInflow "
+ "= 8\nFlagOutflow = 16\nFlagStick = 64\nFlagReserved = 256\n# and same for "
+ "FlagGrid::CellType enum names:\nTypeFluid = 1\nTypeObstacle = 2\nTypeEmpty = "
+ "4\nTypeInflow = 8\nTypeOutflow = 16\nTypeStick = 64\nTypeReserved = 256\n\n# "
+ "integration mode\nIntEuler = 0\nIntRK2 = 1\nIntRK4 = 2\n\n# CG preconditioner\nPcNone "
+ " = 0\nPcMIC = 1\nPcMGDynamic = 2\nPcMGStatic = 3\n\n# particles\nPtypeSpray = "
+ "2\nPtypeBubble = 4\nPtypeFoam = 8\nPtypeTracer = 16\n\n\n\n\n");
+extern "C" {
+void PbRegister_file_0()
+{
+ KEEP_UNUSED(_reg);
+}
+} \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/registration.cpp b/extern/mantaflow/preprocessed/registration.cpp
new file mode 100644
index 00000000000..e86d19f7f7a
--- /dev/null
+++ b/extern/mantaflow/preprocessed/registration.cpp
@@ -0,0 +1,382 @@
+extern "C" {
+extern void PbRegister_mantaMsg();
+extern void PbRegister_printBuildInfo();
+extern void PbRegister_setDebugLevel();
+extern void PbRegister_assertNumpy();
+extern void PbRegister_cgSolveDiffusion();
+extern void PbRegister_gridMaxDiff();
+extern void PbRegister_gridMaxDiffInt();
+extern void PbRegister_gridMaxDiffVec3();
+extern void PbRegister_copyMacToVec3();
+extern void PbRegister_convertMacToVec3();
+extern void PbRegister_resampleVec3ToMac();
+extern void PbRegister_resampleMacToVec3();
+extern void PbRegister_copyLevelsetToReal();
+extern void PbRegister_copyVec3ToReal();
+extern void PbRegister_copyRealToVec3();
+extern void PbRegister_convertLevelsetToReal();
+extern void PbRegister_swapComponents();
+extern void PbRegister_getUvWeight();
+extern void PbRegister_resetUvGrid();
+extern void PbRegister_updateUvWeight();
+extern void PbRegister_getGridAvg();
+extern void PbRegister_getComponent();
+extern void PbRegister_setComponent();
+extern void PbRegister_markIsolatedFluidCell();
+extern void PbRegister_copyMACData();
+extern void PbRegister_getComp4d();
+extern void PbRegister_setComp4d();
+extern void PbRegister_grid4dMaxDiff();
+extern void PbRegister_grid4dMaxDiffInt();
+extern void PbRegister_grid4dMaxDiffVec3();
+extern void PbRegister_grid4dMaxDiffVec4();
+extern void PbRegister_setRegion4d();
+extern void PbRegister_setRegion4dVec4();
+extern void PbRegister_getSliceFrom4d();
+extern void PbRegister_getSliceFrom4dVec();
+extern void PbRegister_interpolateGrid4d();
+extern void PbRegister_interpolateGrid4dVec();
+extern void PbRegister_extrapolateMACSimple();
+extern void PbRegister_extrapolateMACFromWeight();
+extern void PbRegister_extrapolateLsSimple();
+extern void PbRegister_extrapolateVec3Simple();
+extern void PbRegister_getUniFileSize();
+extern void PbRegister_printUniFileInfoString();
+extern void PbRegister_getNpzFileSize();
+extern void PbRegister_quantizeGrid();
+extern void PbRegister_quantizeGridVec3();
+extern void PbRegister_resetPhiInObs();
+extern void PbRegister_advectSemiLagrange();
+extern void PbRegister_addGravity();
+extern void PbRegister_addGravityNoScale();
+extern void PbRegister_addBuoyancy();
+extern void PbRegister_setOpenBound();
+extern void PbRegister_resetOutflow();
+extern void PbRegister_setInflowBcs();
+extern void PbRegister_setWallBcs();
+extern void PbRegister_setInitialVelocity();
+extern void PbRegister_vorticityConfinement();
+extern void PbRegister_addForceField();
+extern void PbRegister_setForceField();
+extern void PbRegister_dissolveSmoke();
+extern void PbRegister_apicMapPartsToMAC();
+extern void PbRegister_apicMapMACGridToParts();
+extern void PbRegister_sampleFlagsWithParticles();
+extern void PbRegister_sampleLevelsetWithParticles();
+extern void PbRegister_sampleShapeWithParticles();
+extern void PbRegister_markFluidCells();
+extern void PbRegister_testInitGridWithPos();
+extern void PbRegister_adjustNumber();
+extern void PbRegister_debugIntToReal();
+extern void PbRegister_gridParticleIndex();
+extern void PbRegister_unionParticleLevelset();
+extern void PbRegister_averagedParticleLevelset();
+extern void PbRegister_improvedParticleLevelset();
+extern void PbRegister_pushOutofObs();
+extern void PbRegister_mapPartsToMAC();
+extern void PbRegister_mapPartsToGrid();
+extern void PbRegister_mapPartsToGridVec3();
+extern void PbRegister_mapGridToParts();
+extern void PbRegister_mapGridToPartsVec3();
+extern void PbRegister_mapMACToParts();
+extern void PbRegister_flipVelocityUpdate();
+extern void PbRegister_combineGridVel();
+extern void PbRegister_getLaplacian();
+extern void PbRegister_getCurvature();
+extern void PbRegister_processBurn();
+extern void PbRegister_updateFlame();
+extern void PbRegister_getSpiralVelocity();
+extern void PbRegister_setGradientYWeight();
+extern void PbRegister_PD_fluid_guiding();
+extern void PbRegister_releaseBlurPrecomp();
+extern void PbRegister_KEpsilonComputeProduction();
+extern void PbRegister_KEpsilonSources();
+extern void PbRegister_KEpsilonBcs();
+extern void PbRegister_KEpsilonGradientDiffusion();
+extern void PbRegister_densityInflow();
+extern void PbRegister_addNoise();
+extern void PbRegister_setNoisePdata();
+extern void PbRegister_setNoisePdataVec3();
+extern void PbRegister_setNoisePdataInt();
+extern void PbRegister_obstacleGradient();
+extern void PbRegister_obstacleLevelset();
+extern void PbRegister_applyEmission();
+extern void PbRegister_densityInflowMeshNoise();
+extern void PbRegister_densityInflowMesh();
+extern void PbRegister_checkSymmetry();
+extern void PbRegister_checkSymmetryVec3();
+extern void PbRegister_projectPpmFull();
+extern void PbRegister_addTestParts();
+extern void PbRegister_pdataMaxDiff();
+extern void PbRegister_calcCenterOfMass();
+extern void PbRegister_updateFractions();
+extern void PbRegister_setObstacleFlags();
+extern void PbRegister_initVortexVelocity();
+extern void PbRegister_blurMacGrid();
+extern void PbRegister_blurRealGrid();
+extern void PbRegister_smoothMesh();
+extern void PbRegister_subdivideMesh();
+extern void PbRegister_killSmallComponents();
+extern void PbRegister_releaseMG();
+extern void PbRegister_computePressureRhs();
+extern void PbRegister_solvePressureSystem();
+extern void PbRegister_correctVelocity();
+extern void PbRegister_solvePressure();
+extern void PbRegister_addForcePvel();
+extern void PbRegister_updateVelocityFromDeltaPos();
+extern void PbRegister_eulerStep();
+extern void PbRegister_setPartType();
+extern void PbRegister_flipComputeSecondaryParticlePotentials();
+extern void PbRegister_flipSampleSecondaryParticles();
+extern void PbRegister_flipUpdateSecondaryParticles();
+extern void PbRegister_flipDeleteParticlesInObstacle();
+extern void PbRegister_debugGridInfo();
+extern void PbRegister_setFlagsFromLevelset();
+extern void PbRegister_setMACFromLevelset();
+extern void PbRegister_flipComputePotentialTrappedAir();
+extern void PbRegister_flipComputePotentialKineticEnergy();
+extern void PbRegister_flipComputePotentialWaveCrest();
+extern void PbRegister_flipComputeSurfaceNormals();
+extern void PbRegister_flipUpdateNeighborRatio();
+extern void PbRegister_particleSurfaceTurbulence();
+extern void PbRegister_debugCheckParts();
+extern void PbRegister_markAsFixed();
+extern void PbRegister_texcoordInflow();
+extern void PbRegister_meshSmokeInflow();
+extern void PbRegister_vorticitySource();
+extern void PbRegister_smoothVorticity();
+extern void PbRegister_VPseedK41();
+extern void PbRegister_VICintegration();
+extern void PbRegister_densityFromLevelset();
+extern void PbRegister_interpolateGrid();
+extern void PbRegister_interpolateGridVec3();
+extern void PbRegister_interpolateMACGrid();
+extern void PbRegister_applySimpleNoiseVec3();
+extern void PbRegister_applySimpleNoiseReal();
+extern void PbRegister_applyNoiseVec3();
+extern void PbRegister_computeEnergy();
+extern void PbRegister_computeWaveletCoeffs();
+extern void PbRegister_computeVorticity();
+extern void PbRegister_computeStrainRateMag();
+extern void PbRegister_extrapolateSimpleFlags();
+extern void PbRegister_getCurl();
+extern void PbRegister_calcSecDeriv2d();
+extern void PbRegister_totalSum();
+extern void PbRegister_normalizeSumTo();
+extern void PbRegister_cgSolveWE();
+extern void PbRegister_file_0();
+extern void PbRegister_file_1();
+extern void PbRegister_file_2();
+extern void PbRegister_file_3();
+extern void PbRegister_file_4();
+extern void PbRegister_file_5();
+extern void PbRegister_file_6();
+extern void PbRegister_file_7();
+extern void PbRegister_file_8();
+extern void PbRegister_file_9();
+extern void PbRegister_file_10();
+extern void PbRegister_file_11();
+extern void PbRegister_file_12();
+extern void PbRegister_file_13();
+extern void PbRegister_file_14();
+extern void PbRegister_file_15();
+extern void PbRegister_file_16();
+extern void PbRegister_file_17();
+extern void PbRegister_file_18();
+extern void PbRegister_file_19();
+extern void PbRegister_file_20();
+extern void PbRegister_file_21();
+}
+
+namespace Pb {
+void MantaEnsureRegistration()
+{
+ PbRegister_mantaMsg();
+ PbRegister_printBuildInfo();
+ PbRegister_setDebugLevel();
+ PbRegister_assertNumpy();
+ PbRegister_cgSolveDiffusion();
+ PbRegister_gridMaxDiff();
+ PbRegister_gridMaxDiffInt();
+ PbRegister_gridMaxDiffVec3();
+ PbRegister_copyMacToVec3();
+ PbRegister_convertMacToVec3();
+ PbRegister_resampleVec3ToMac();
+ PbRegister_resampleMacToVec3();
+ PbRegister_copyLevelsetToReal();
+ PbRegister_copyVec3ToReal();
+ PbRegister_copyRealToVec3();
+ PbRegister_convertLevelsetToReal();
+ PbRegister_swapComponents();
+ PbRegister_getUvWeight();
+ PbRegister_resetUvGrid();
+ PbRegister_updateUvWeight();
+ PbRegister_getGridAvg();
+ PbRegister_getComponent();
+ PbRegister_setComponent();
+ PbRegister_markIsolatedFluidCell();
+ PbRegister_copyMACData();
+ PbRegister_getComp4d();
+ PbRegister_setComp4d();
+ PbRegister_grid4dMaxDiff();
+ PbRegister_grid4dMaxDiffInt();
+ PbRegister_grid4dMaxDiffVec3();
+ PbRegister_grid4dMaxDiffVec4();
+ PbRegister_setRegion4d();
+ PbRegister_setRegion4dVec4();
+ PbRegister_getSliceFrom4d();
+ PbRegister_getSliceFrom4dVec();
+ PbRegister_interpolateGrid4d();
+ PbRegister_interpolateGrid4dVec();
+ PbRegister_extrapolateMACSimple();
+ PbRegister_extrapolateMACFromWeight();
+ PbRegister_extrapolateLsSimple();
+ PbRegister_extrapolateVec3Simple();
+ PbRegister_getUniFileSize();
+ PbRegister_printUniFileInfoString();
+ PbRegister_getNpzFileSize();
+ PbRegister_quantizeGrid();
+ PbRegister_quantizeGridVec3();
+ PbRegister_resetPhiInObs();
+ PbRegister_advectSemiLagrange();
+ PbRegister_addGravity();
+ PbRegister_addGravityNoScale();
+ PbRegister_addBuoyancy();
+ PbRegister_setOpenBound();
+ PbRegister_resetOutflow();
+ PbRegister_setInflowBcs();
+ PbRegister_setWallBcs();
+ PbRegister_setInitialVelocity();
+ PbRegister_vorticityConfinement();
+ PbRegister_addForceField();
+ PbRegister_setForceField();
+ PbRegister_dissolveSmoke();
+ PbRegister_apicMapPartsToMAC();
+ PbRegister_apicMapMACGridToParts();
+ PbRegister_sampleFlagsWithParticles();
+ PbRegister_sampleLevelsetWithParticles();
+ PbRegister_sampleShapeWithParticles();
+ PbRegister_markFluidCells();
+ PbRegister_testInitGridWithPos();
+ PbRegister_adjustNumber();
+ PbRegister_debugIntToReal();
+ PbRegister_gridParticleIndex();
+ PbRegister_unionParticleLevelset();
+ PbRegister_averagedParticleLevelset();
+ PbRegister_improvedParticleLevelset();
+ PbRegister_pushOutofObs();
+ PbRegister_mapPartsToMAC();
+ PbRegister_mapPartsToGrid();
+ PbRegister_mapPartsToGridVec3();
+ PbRegister_mapGridToParts();
+ PbRegister_mapGridToPartsVec3();
+ PbRegister_mapMACToParts();
+ PbRegister_flipVelocityUpdate();
+ PbRegister_combineGridVel();
+ PbRegister_getLaplacian();
+ PbRegister_getCurvature();
+ PbRegister_processBurn();
+ PbRegister_updateFlame();
+ PbRegister_getSpiralVelocity();
+ PbRegister_setGradientYWeight();
+ PbRegister_PD_fluid_guiding();
+ PbRegister_releaseBlurPrecomp();
+ PbRegister_KEpsilonComputeProduction();
+ PbRegister_KEpsilonSources();
+ PbRegister_KEpsilonBcs();
+ PbRegister_KEpsilonGradientDiffusion();
+ PbRegister_densityInflow();
+ PbRegister_addNoise();
+ PbRegister_setNoisePdata();
+ PbRegister_setNoisePdataVec3();
+ PbRegister_setNoisePdataInt();
+ PbRegister_obstacleGradient();
+ PbRegister_obstacleLevelset();
+ PbRegister_applyEmission();
+ PbRegister_densityInflowMeshNoise();
+ PbRegister_densityInflowMesh();
+ PbRegister_checkSymmetry();
+ PbRegister_checkSymmetryVec3();
+ PbRegister_projectPpmFull();
+ PbRegister_addTestParts();
+ PbRegister_pdataMaxDiff();
+ PbRegister_calcCenterOfMass();
+ PbRegister_updateFractions();
+ PbRegister_setObstacleFlags();
+ PbRegister_initVortexVelocity();
+ PbRegister_blurMacGrid();
+ PbRegister_blurRealGrid();
+ PbRegister_smoothMesh();
+ PbRegister_subdivideMesh();
+ PbRegister_killSmallComponents();
+ PbRegister_releaseMG();
+ PbRegister_computePressureRhs();
+ PbRegister_solvePressureSystem();
+ PbRegister_correctVelocity();
+ PbRegister_solvePressure();
+ PbRegister_addForcePvel();
+ PbRegister_updateVelocityFromDeltaPos();
+ PbRegister_eulerStep();
+ PbRegister_setPartType();
+ PbRegister_flipComputeSecondaryParticlePotentials();
+ PbRegister_flipSampleSecondaryParticles();
+ PbRegister_flipUpdateSecondaryParticles();
+ PbRegister_flipDeleteParticlesInObstacle();
+ PbRegister_debugGridInfo();
+ PbRegister_setFlagsFromLevelset();
+ PbRegister_setMACFromLevelset();
+ PbRegister_flipComputePotentialTrappedAir();
+ PbRegister_flipComputePotentialKineticEnergy();
+ PbRegister_flipComputePotentialWaveCrest();
+ PbRegister_flipComputeSurfaceNormals();
+ PbRegister_flipUpdateNeighborRatio();
+ PbRegister_particleSurfaceTurbulence();
+ PbRegister_debugCheckParts();
+ PbRegister_markAsFixed();
+ PbRegister_texcoordInflow();
+ PbRegister_meshSmokeInflow();
+ PbRegister_vorticitySource();
+ PbRegister_smoothVorticity();
+ PbRegister_VPseedK41();
+ PbRegister_VICintegration();
+ PbRegister_densityFromLevelset();
+ PbRegister_interpolateGrid();
+ PbRegister_interpolateGridVec3();
+ PbRegister_interpolateMACGrid();
+ PbRegister_applySimpleNoiseVec3();
+ PbRegister_applySimpleNoiseReal();
+ PbRegister_applyNoiseVec3();
+ PbRegister_computeEnergy();
+ PbRegister_computeWaveletCoeffs();
+ PbRegister_computeVorticity();
+ PbRegister_computeStrainRateMag();
+ PbRegister_extrapolateSimpleFlags();
+ PbRegister_getCurl();
+ PbRegister_calcSecDeriv2d();
+ PbRegister_totalSum();
+ PbRegister_normalizeSumTo();
+ PbRegister_cgSolveWE();
+ PbRegister_file_0();
+ PbRegister_file_1();
+ PbRegister_file_2();
+ PbRegister_file_3();
+ PbRegister_file_4();
+ PbRegister_file_5();
+ PbRegister_file_6();
+ PbRegister_file_7();
+ PbRegister_file_8();
+ PbRegister_file_9();
+ PbRegister_file_10();
+ PbRegister_file_11();
+ PbRegister_file_12();
+ PbRegister_file_13();
+ PbRegister_file_14();
+ PbRegister_file_15();
+ PbRegister_file_16();
+ PbRegister_file_17();
+ PbRegister_file_18();
+ PbRegister_file_19();
+ PbRegister_file_20();
+ PbRegister_file_21();
+}
+} // namespace Pb
diff --git a/extern/mantaflow/preprocessed/shapes.cpp b/extern/mantaflow/preprocessed/shapes.cpp
new file mode 100644
index 00000000000..4095758cbc0
--- /dev/null
+++ b/extern/mantaflow/preprocessed/shapes.cpp
@@ -0,0 +1,1010 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Shape classes
+ *
+ ******************************************************************************/
+
+#include "shapes.h"
+#include "commonkernels.h"
+#include "mesh.h"
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// Shape class members
+
+Shape::Shape(FluidSolver *parent) : PbClass(parent), mType(TypeNone)
+{
+}
+
+LevelsetGrid Shape::computeLevelset()
+{
+ // note - 3d check deactivated! TODO double check...
+ LevelsetGrid phi(getParent());
+ generateLevelset(phi);
+ return phi;
+}
+
+bool Shape::isInside(const Vec3 &pos) const
+{
+ return false;
+}
+
+//! Kernel: Apply a shape to a grid, setting value inside
+
+template<class T> struct ApplyShapeToGrid : public KernelBase {
+ ApplyShapeToGrid(Grid<T> *grid, Shape *shape, T value, FlagGrid *respectFlags)
+ : KernelBase(grid, 0), grid(grid), shape(shape), value(value), respectFlags(respectFlags)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, Grid<T> *grid, Shape *shape, T value, FlagGrid *respectFlags) const
+ {
+ if (respectFlags && respectFlags->isObstacle(i, j, k))
+ return;
+ if (shape->isInsideGrid(i, j, k))
+ (*grid)(i, j, k) = value;
+ }
+ inline Grid<T> *getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<T> type0;
+ inline Shape *getArg1()
+ {
+ return shape;
+ }
+ typedef Shape type1;
+ inline T &getArg2()
+ {
+ return value;
+ }
+ typedef T type2;
+ inline FlagGrid *getArg3()
+ {
+ return respectFlags;
+ }
+ typedef FlagGrid type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel ApplyShapeToGrid ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, shape, value, respectFlags);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, shape, value, respectFlags);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<T> *grid;
+ Shape *shape;
+ T value;
+ FlagGrid *respectFlags;
+};
+
+//! Kernel: Apply a shape to a grid, setting value inside (scaling by SDF value)
+
+template<class T> struct ApplyShapeToGridSmooth : public KernelBase {
+ ApplyShapeToGridSmooth(
+ Grid<T> *grid, Grid<Real> &phi, Real sigma, Real shift, T value, FlagGrid *respectFlags)
+ : KernelBase(grid, 0),
+ grid(grid),
+ phi(phi),
+ sigma(sigma),
+ shift(shift),
+ value(value),
+ respectFlags(respectFlags)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ Grid<T> *grid,
+ Grid<Real> &phi,
+ Real sigma,
+ Real shift,
+ T value,
+ FlagGrid *respectFlags) const
+ {
+ if (respectFlags && respectFlags->isObstacle(i, j, k))
+ return;
+ const Real p = phi(i, j, k) - shift;
+ if (p < -sigma)
+ (*grid)(i, j, k) = value;
+ else if (p < sigma)
+ (*grid)(i, j, k) = value * (0.5f * (1.0f - p / sigma));
+ }
+ inline Grid<T> *getArg0()
+ {
+ return grid;
+ }
+ typedef Grid<T> type0;
+ inline Grid<Real> &getArg1()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type1;
+ inline Real &getArg2()
+ {
+ return sigma;
+ }
+ typedef Real type2;
+ inline Real &getArg3()
+ {
+ return shift;
+ }
+ typedef Real type3;
+ inline T &getArg4()
+ {
+ return value;
+ }
+ typedef T type4;
+ inline FlagGrid *getArg5()
+ {
+ return respectFlags;
+ }
+ typedef FlagGrid type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel ApplyShapeToGridSmooth ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, phi, sigma, shift, value, respectFlags);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, phi, sigma, shift, value, respectFlags);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<T> *grid;
+ Grid<Real> &phi;
+ Real sigma;
+ Real shift;
+ T value;
+ FlagGrid *respectFlags;
+};
+
+//! Kernel: Apply a shape to a MAC grid, setting value inside
+
+struct ApplyShapeToMACGrid : public KernelBase {
+ ApplyShapeToMACGrid(MACGrid *grid, Shape *shape, Vec3 value, FlagGrid *respectFlags)
+ : KernelBase(grid, 0), grid(grid), shape(shape), value(value), respectFlags(respectFlags)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, MACGrid *grid, Shape *shape, Vec3 value, FlagGrid *respectFlags) const
+ {
+ if (respectFlags && respectFlags->isObstacle(i, j, k))
+ return;
+ if (shape->isInside(Vec3(i, j + 0.5, k + 0.5)))
+ (*grid)(i, j, k).x = value.x;
+ if (shape->isInside(Vec3(i + 0.5, j, k + 0.5)))
+ (*grid)(i, j, k).y = value.y;
+ if (shape->isInside(Vec3(i + 0.5, j + 0.5, k)))
+ (*grid)(i, j, k).z = value.z;
+ }
+ inline MACGrid *getArg0()
+ {
+ return grid;
+ }
+ typedef MACGrid type0;
+ inline Shape *getArg1()
+ {
+ return shape;
+ }
+ typedef Shape type1;
+ inline Vec3 &getArg2()
+ {
+ return value;
+ }
+ typedef Vec3 type2;
+ inline FlagGrid *getArg3()
+ {
+ return respectFlags;
+ }
+ typedef FlagGrid type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel ApplyShapeToMACGrid ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, shape, value, respectFlags);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, grid, shape, value, respectFlags);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ MACGrid *grid;
+ Shape *shape;
+ Vec3 value;
+ FlagGrid *respectFlags;
+};
+
+void Shape::applyToGrid(GridBase *grid, FlagGrid *respectFlags)
+{
+#if NOPYTHON != 1
+ if (grid->getType() & GridBase::TypeInt)
+ ApplyShapeToGrid<int>((Grid<int> *)grid, this, _args.get<int>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeReal)
+ ApplyShapeToGrid<Real>((Grid<Real> *)grid, this, _args.get<Real>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeMAC)
+ ApplyShapeToMACGrid((MACGrid *)grid, this, _args.get<Vec3>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeVec3)
+ ApplyShapeToGrid<Vec3>((Grid<Vec3> *)grid, this, _args.get<Vec3>("value"), respectFlags);
+ else
+ errMsg("Shape::applyToGrid(): unknown grid type");
+#else
+ errMsg("Not yet supported...");
+#endif
+}
+
+void Shape::applyToGridSmooth(GridBase *grid, Real sigma, Real shift, FlagGrid *respectFlags)
+{
+ Grid<Real> phi(grid->getParent());
+ generateLevelset(phi);
+
+#if NOPYTHON != 1
+ if (grid->getType() & GridBase::TypeInt)
+ ApplyShapeToGridSmooth<int>(
+ (Grid<int> *)grid, phi, sigma, shift, _args.get<int>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeReal)
+ ApplyShapeToGridSmooth<Real>(
+ (Grid<Real> *)grid, phi, sigma, shift, _args.get<Real>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeVec3)
+ ApplyShapeToGridSmooth<Vec3>(
+ (Grid<Vec3> *)grid, phi, sigma, shift, _args.get<Vec3>("value"), respectFlags);
+ else
+ errMsg("Shape::applyToGridSmooth(): unknown grid type");
+#else
+ errMsg("Not yet supported...");
+#endif
+}
+
+void Shape::collideMesh(Mesh &mesh)
+{
+ const Real margin = 0.2;
+
+ Grid<Real> phi(getParent());
+ Grid<Vec3> grad(getParent());
+ generateLevelset(phi);
+ GradientOp(grad, phi);
+
+ const int num = mesh.numNodes();
+ for (int i = 0; i < num; i++) {
+ const Vec3 &p = mesh.nodes(i).pos;
+ mesh.nodes(i).flags &= ~(Mesh::NfCollide | Mesh::NfMarked);
+ if (!phi.isInBounds(p, 1))
+ continue;
+
+ for (int iter = 0; iter < 10; iter++) {
+ const Real dist = phi.getInterpolated(p);
+ if (dist < margin) {
+ Vec3 n = grad.getInterpolated(p);
+ normalize(n);
+ mesh.nodes(i).pos += (margin - dist) * n;
+ mesh.nodes(i).flags |= Mesh::NfCollide | Mesh::NfMarked;
+ }
+ else
+ break;
+ }
+ }
+}
+
+//******************************************************************************
+// Derived shape class members
+
+Box::Box(FluidSolver *parent, Vec3 center, Vec3 p0, Vec3 p1, Vec3 size) : Shape(parent)
+{
+ mType = TypeBox;
+ if (center.isValid() && size.isValid()) {
+ mP0 = center - size;
+ mP1 = center + size;
+ }
+ else if (p0.isValid() && p1.isValid()) {
+ mP0 = p0;
+ mP1 = p1;
+ }
+ else
+ errMsg("Box: specify either p0,p1 or size,center");
+}
+
+bool Box::isInside(const Vec3 &pos) const
+{
+ return (pos.x >= mP0.x && pos.y >= mP0.y && pos.z >= mP0.z && pos.x <= mP1.x && pos.y <= mP1.y &&
+ pos.z <= mP1.z);
+}
+
+void Box::generateMesh(Mesh *mesh)
+{
+ const int quadidx[24] = {0, 4, 6, 2, 3, 7, 5, 1, 0, 1, 5, 4, 6, 7, 3, 2, 0, 2, 3, 1, 5, 7, 6, 4};
+ const int nodebase = mesh->numNodes();
+ int oldtri = mesh->numTris();
+ for (int i = 0; i < 8; i++) {
+ Node p;
+ p.flags = 0;
+ p.pos = mP0;
+ if (i & 1)
+ p.pos.x = mP1.x;
+ if (i & 2)
+ p.pos.y = mP1.y;
+ if (i & 4)
+ p.pos.z = mP1.z;
+ mesh->addNode(p);
+ }
+ for (int i = 0; i < 6; i++) {
+ mesh->addTri(Triangle(nodebase + quadidx[i * 4 + 0],
+ nodebase + quadidx[i * 4 + 1],
+ nodebase + quadidx[i * 4 + 3]));
+ mesh->addTri(Triangle(nodebase + quadidx[i * 4 + 1],
+ nodebase + quadidx[i * 4 + 2],
+ nodebase + quadidx[i * 4 + 3]));
+ }
+ mesh->rebuildCorners(oldtri, -1);
+ mesh->rebuildLookup(oldtri, -1);
+}
+
+//! Kernel: Analytic SDF for box shape
+struct BoxSDF : public KernelBase {
+ BoxSDF(Grid<Real> &phi, const Vec3 &p1, const Vec3 &p2)
+ : KernelBase(&phi, 0), phi(phi), p1(p1), p2(p2)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Real> &phi, const Vec3 &p1, const Vec3 &p2) const
+ {
+ const Vec3 p(i + 0.5, j + 0.5, k + 0.5);
+ if (p.x <= p2.x && p.x >= p1.x && p.y <= p2.y && p.y >= p1.y && p.z <= p2.z && p.z >= p1.z) {
+ // inside: minimal surface distance
+ Real mx = max(p.x - p2.x, p1.x - p.x);
+ Real my = max(p.y - p2.y, p1.y - p.y);
+ Real mz = max(p.z - p2.z, p1.z - p.z);
+ if (!phi.is3D())
+ mz = mx; // skip for 2d...
+ phi(i, j, k) = max(mx, max(my, mz));
+ }
+ else if (p.y <= p2.y && p.y >= p1.y && p.z <= p2.z && p.z >= p1.z) {
+ // outside plane X
+ phi(i, j, k) = max(p.x - p2.x, p1.x - p.x);
+ }
+ else if (p.x <= p2.x && p.x >= p1.x && p.z <= p2.z && p.z >= p1.z) {
+ // outside plane Y
+ phi(i, j, k) = max(p.y - p2.y, p1.y - p.y);
+ }
+ else if (p.x <= p2.x && p.x >= p1.x && p.y <= p2.y && p.y >= p1.y) {
+ // outside plane Z
+ phi(i, j, k) = max(p.z - p2.z, p1.z - p.z);
+ }
+ else if (p.x > p1.x && p.x < p2.x) {
+ // lines X
+ Real m1 = sqrt(square(p1.y - p.y) + square(p1.z - p.z));
+ Real m2 = sqrt(square(p2.y - p.y) + square(p1.z - p.z));
+ Real m3 = sqrt(square(p1.y - p.y) + square(p2.z - p.z));
+ Real m4 = sqrt(square(p2.y - p.y) + square(p2.z - p.z));
+ phi(i, j, k) = min(m1, min(m2, min(m3, m4)));
+ }
+ else if (p.y > p1.y && p.y < p2.y) {
+ // lines Y
+ Real m1 = sqrt(square(p1.x - p.x) + square(p1.z - p.z));
+ Real m2 = sqrt(square(p2.x - p.x) + square(p1.z - p.z));
+ Real m3 = sqrt(square(p1.x - p.x) + square(p2.z - p.z));
+ Real m4 = sqrt(square(p2.x - p.x) + square(p2.z - p.z));
+ phi(i, j, k) = min(m1, min(m2, min(m3, m4)));
+ }
+ else if (p.z > p1.x && p.z < p2.z) {
+ // lines Z
+ Real m1 = sqrt(square(p1.y - p.y) + square(p1.x - p.x));
+ Real m2 = sqrt(square(p2.y - p.y) + square(p1.x - p.x));
+ Real m3 = sqrt(square(p1.y - p.y) + square(p2.x - p.x));
+ Real m4 = sqrt(square(p2.y - p.y) + square(p2.x - p.x));
+ phi(i, j, k) = min(m1, min(m2, min(m3, m4)));
+ }
+ else {
+ // points
+ Real m = norm(p - Vec3(p1.x, p1.y, p1.z));
+ m = min(m, norm(p - Vec3(p1.x, p1.y, p2.z)));
+ m = min(m, norm(p - Vec3(p1.x, p2.y, p1.z)));
+ m = min(m, norm(p - Vec3(p1.x, p2.y, p2.z)));
+ m = min(m, norm(p - Vec3(p2.x, p1.y, p1.z)));
+ m = min(m, norm(p - Vec3(p2.x, p1.y, p2.z)));
+ m = min(m, norm(p - Vec3(p2.x, p2.y, p1.z)));
+ m = min(m, norm(p - Vec3(p2.x, p2.y, p2.z)));
+ phi(i, j, k) = m;
+ }
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type0;
+ inline const Vec3 &getArg1()
+ {
+ return p1;
+ }
+ typedef Vec3 type1;
+ inline const Vec3 &getArg2()
+ {
+ return p2;
+ }
+ typedef Vec3 type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel BoxSDF ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, phi, p1, p2);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, phi, p1, p2);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<Real> &phi;
+ const Vec3 &p1;
+ const Vec3 &p2;
+};
+void Box::generateLevelset(Grid<Real> &phi)
+{
+ BoxSDF(phi, mP0, mP1);
+}
+
+Sphere::Sphere(FluidSolver *parent, Vec3 center, Real radius, Vec3 scale)
+ : Shape(parent), mCenter(center), mScale(scale), mRadius(radius)
+{
+ mType = TypeSphere;
+}
+
+bool Sphere::isInside(const Vec3 &pos) const
+{
+ return normSquare((pos - mCenter) / mScale) <= mRadius * mRadius;
+}
+
+struct Tri {
+ Vec3 t[3];
+ int i[3];
+ Tri(Vec3 a, Vec3 b, Vec3 c)
+ {
+ t[0] = a;
+ t[1] = b;
+ t[2] = c;
+ }
+};
+void Sphere::generateMesh(Mesh *mesh)
+{
+ vector<Tri> tris;
+ const int iterations = 3;
+ int oldtri = mesh->numTris();
+
+ // start with octahedron
+ const Real d = sqrt(0.5);
+ Vec3 p[6] = {Vec3(0, 1, 0),
+ Vec3(0, -1, 0),
+ Vec3(-d, 0, -d),
+ Vec3(d, 0, -d),
+ Vec3(d, 0, d),
+ Vec3(-d, 0, d)};
+ tris.push_back(Tri(p[0], p[4], p[3]));
+ tris.push_back(Tri(p[0], p[5], p[4]));
+ tris.push_back(Tri(p[0], p[2], p[5]));
+ tris.push_back(Tri(p[0], p[3], p[2]));
+ tris.push_back(Tri(p[1], p[3], p[4]));
+ tris.push_back(Tri(p[1], p[4], p[5]));
+ tris.push_back(Tri(p[1], p[5], p[2]));
+ tris.push_back(Tri(p[1], p[2], p[3]));
+
+ // Bisect each edge and move to the surface of a unit sphere
+ for (int it = 0; it < iterations; it++) {
+ int ntold = tris.size();
+ for (int i = 0; i < ntold; i++) {
+ Vec3 pa = 0.5 * (tris[i].t[0] + tris[i].t[1]);
+ Vec3 pb = 0.5 * (tris[i].t[1] + tris[i].t[2]);
+ Vec3 pc = 0.5 * (tris[i].t[2] + tris[i].t[0]);
+ normalize(pa);
+ normalize(pb);
+ normalize(pc);
+
+ tris.push_back(Tri(tris[i].t[0], pa, pc));
+ tris.push_back(Tri(pa, tris[i].t[1], pb));
+ tris.push_back(Tri(pb, tris[i].t[2], pc));
+ tris[i].t[0] = pa;
+ tris[i].t[1] = pb;
+ tris[i].t[2] = pc;
+ }
+ }
+
+ // index + scale
+ vector<Vec3> nodes;
+ for (size_t i = 0; i < tris.size(); i++) {
+ for (int t = 0; t < 3; t++) {
+ Vec3 p = mCenter + tris[i].t[t] * mRadius * mScale;
+ // vector already there ?
+ int idx = nodes.size();
+ for (size_t j = 0; j < nodes.size(); j++) {
+ if (p == nodes[j]) {
+ idx = j;
+ break;
+ }
+ }
+ if (idx == (int)nodes.size())
+ nodes.push_back(p);
+ tris[i].i[t] = idx;
+ }
+ }
+
+ // add the to mesh
+ const int ni = mesh->numNodes();
+ for (size_t i = 0; i < nodes.size(); i++) {
+ mesh->addNode(Node(nodes[i]));
+ }
+ for (size_t t = 0; t < tris.size(); t++)
+ mesh->addTri(Triangle(tris[t].i[0] + ni, tris[t].i[1] + ni, tris[t].i[2] + ni));
+
+ mesh->rebuildCorners(oldtri, -1);
+ mesh->rebuildLookup(oldtri, -1);
+}
+
+struct SphereSDF : public KernelBase {
+ SphereSDF(Grid<Real> &phi, Vec3 center, Real radius, Vec3 scale)
+ : KernelBase(&phi, 0), phi(phi), center(center), radius(radius), scale(scale)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, Grid<Real> &phi, Vec3 center, Real radius, Vec3 scale) const
+ {
+ phi(i, j, k) = norm((Vec3(i + 0.5, j + 0.5, k + 0.5) - center) / scale) - radius;
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type0;
+ inline Vec3 &getArg1()
+ {
+ return center;
+ }
+ typedef Vec3 type1;
+ inline Real &getArg2()
+ {
+ return radius;
+ }
+ typedef Real type2;
+ inline Vec3 &getArg3()
+ {
+ return scale;
+ }
+ typedef Vec3 type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel SphereSDF ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, phi, center, radius, scale);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, phi, center, radius, scale);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<Real> &phi;
+ Vec3 center;
+ Real radius;
+ Vec3 scale;
+};
+void Sphere::generateLevelset(Grid<Real> &phi)
+{
+ SphereSDF(phi, mCenter, mRadius, mScale);
+}
+
+Cylinder::Cylinder(FluidSolver *parent, Vec3 center, Real radius, Vec3 z)
+ : Shape(parent), mCenter(center), mRadius(radius)
+{
+ mType = TypeCylinder;
+ mZDir = z;
+ mZ = normalize(mZDir);
+}
+
+bool Cylinder::isInside(const Vec3 &pos) const
+{
+ Real z = dot(pos - mCenter, mZDir);
+ if (fabs(z) > mZ)
+ return false;
+ Real r2 = normSquare(pos - mCenter) - square(z);
+ return r2 < square(mRadius);
+}
+
+void Cylinder::generateMesh(Mesh *mesh)
+{
+ // generate coordinate system
+ Vec3 x = getOrthogonalVector(mZDir) * mRadius;
+ Vec3 y = cross(x, mZDir);
+ Vec3 z = mZDir * mZ;
+ int oldtri = mesh->numTris();
+
+ // construct node ring
+ const int N = 20;
+ const int base = mesh->numNodes();
+ for (int i = 0; i < N; i++) {
+ const Real phi = 2.0 * M_PI * (Real)i / (Real)N;
+ Vec3 r = x * cos(phi) + y * sin(phi) + mCenter;
+ mesh->addNode(Node(r + z));
+ mesh->addNode(Node(r - z));
+ }
+ // top/bottom center
+ mesh->addNode(Node(mCenter + z));
+ mesh->addNode(Node(mCenter - z));
+
+ // connect with tris
+ for (int i = 0; i < N; i++) {
+ int cur = base + 2 * i;
+ int next = base + 2 * ((i + 1) % N);
+ // outside
+ mesh->addTri(Triangle(cur, next, cur + 1));
+ mesh->addTri(Triangle(next, next + 1, cur + 1));
+ // upper / lower
+ mesh->addTri(Triangle(cur, base + 2 * N, next));
+ mesh->addTri(Triangle(cur + 1, next + 1, base + 2 * N + 1));
+ }
+
+ mesh->rebuildCorners(oldtri, -1);
+ mesh->rebuildLookup(oldtri, -1);
+}
+
+struct CylinderSDF : public KernelBase {
+ CylinderSDF(Grid<Real> &phi, Vec3 center, Real radius, Vec3 zaxis, Real maxz)
+ : KernelBase(&phi, 0), phi(phi), center(center), radius(radius), zaxis(zaxis), maxz(maxz)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, Grid<Real> &phi, Vec3 center, Real radius, Vec3 zaxis, Real maxz) const
+ {
+ Vec3 p = Vec3(i + 0.5, j + 0.5, k + 0.5) - center;
+ Real z = fabs(dot(p, zaxis));
+ Real r = sqrt(normSquare(p) - z * z);
+ if (z < maxz) {
+ // cylinder z area
+ if (r < radius)
+ phi(i, j, k) = max(r - radius, z - maxz);
+ else
+ phi(i, j, k) = r - radius;
+ }
+ else if (r < radius) {
+ // cylinder top area
+ phi(i, j, k) = fabs(z - maxz);
+ }
+ else {
+ // edge
+ phi(i, j, k) = sqrt(square(z - maxz) + square(r - radius));
+ }
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type0;
+ inline Vec3 &getArg1()
+ {
+ return center;
+ }
+ typedef Vec3 type1;
+ inline Real &getArg2()
+ {
+ return radius;
+ }
+ typedef Real type2;
+ inline Vec3 &getArg3()
+ {
+ return zaxis;
+ }
+ typedef Vec3 type3;
+ inline Real &getArg4()
+ {
+ return maxz;
+ }
+ typedef Real type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel CylinderSDF ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, phi, center, radius, zaxis, maxz);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, phi, center, radius, zaxis, maxz);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ Grid<Real> &phi;
+ Vec3 center;
+ Real radius;
+ Vec3 zaxis;
+ Real maxz;
+};
+void Cylinder::generateLevelset(Grid<Real> &phi)
+{
+ CylinderSDF(phi, mCenter, mRadius, mZDir, mZ);
+}
+
+Slope::Slope(FluidSolver *parent, Real anglexy, Real angleyz, Real origin, Vec3 gs)
+ : Shape(parent), mAnglexy(anglexy), mAngleyz(angleyz), mOrigin(origin), mGs(gs)
+{
+ mType = TypeSlope;
+}
+
+void Slope::generateMesh(Mesh *mesh)
+{
+
+ const int oldtri = mesh->numTris();
+
+ Vec3 v1(0., mOrigin, 0.);
+ mesh->addNode(Node(v1));
+
+ Real dy1 = mGs.z * std::tan(mAngleyz);
+ Vec3 v2(0., mOrigin - dy1, mGs.z);
+ mesh->addNode(Node(v2));
+
+ Real dy2 = mGs.x * std::tan(mAnglexy);
+ Vec3 v3(mGs.x, v2.y - dy2, mGs.z);
+ mesh->addNode(Node(v3));
+
+ Vec3 v4(mGs.x, mOrigin - dy2, 0.);
+ mesh->addNode(Node(v4));
+
+ mesh->addTri(Triangle(0, 1, 2));
+ mesh->addTri(Triangle(2, 3, 0));
+
+ mesh->rebuildCorners(oldtri, -1);
+ mesh->rebuildLookup(oldtri, -1);
+}
+
+bool Slope::isInside(const Vec3 &pos) const
+{
+
+ const Real alpha = -mAnglexy * M_PI / 180.;
+ const Real beta = -mAngleyz * M_PI / 180.;
+
+ Vec3 n(0, 1, 0);
+
+ n.x = std::sin(alpha) * std::cos(beta);
+ n.y = std::cos(alpha) * std::cos(beta);
+ n.z = std::sin(beta);
+
+ normalize(n);
+
+ const Real fac = std::sqrt(n.x * n.x + n.y * n.y + n.z * n.z);
+
+ return ((n.x * (double)pos.x + n.y * (double)pos.y + n.z * (double)pos.z - mOrigin) / fac) <= 0.;
+}
+
+struct SlopeSDF : public KernelBase {
+ SlopeSDF(const Vec3 &n, Grid<Real> &phiObs, const Real &fac, const Real &origin)
+ : KernelBase(&phiObs, 0), n(n), phiObs(phiObs), fac(fac), origin(origin)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const Vec3 &n,
+ Grid<Real> &phiObs,
+ const Real &fac,
+ const Real &origin) const
+ {
+
+ phiObs(i, j, k) = (n.x * (double)i + n.y * (double)j + n.z * (double)k - origin) * fac;
+ }
+ inline const Vec3 &getArg0()
+ {
+ return n;
+ }
+ typedef Vec3 type0;
+ inline Grid<Real> &getArg1()
+ {
+ return phiObs;
+ }
+ typedef Grid<Real> type1;
+ inline const Real &getArg2()
+ {
+ return fac;
+ }
+ typedef Real type2;
+ inline const Real &getArg3()
+ {
+ return origin;
+ }
+ typedef Real type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel SlopeSDF ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, n, phiObs, fac, origin);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, n, phiObs, fac, origin);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const Vec3 &n;
+ Grid<Real> &phiObs;
+ const Real &fac;
+ const Real &origin;
+};
+
+void Slope::generateLevelset(Grid<Real> &phi)
+{
+
+ const Real alpha = -mAnglexy * M_PI / 180.;
+ const Real beta = -mAngleyz * M_PI / 180.;
+
+ Vec3 n(0, 1, 0);
+
+ n.x = std::sin(alpha) * std::cos(beta);
+ n.y = std::cos(alpha) * std::cos(beta);
+ n.z = std::sin(beta);
+
+ normalize(n);
+
+ const Real fac = 1. / std::sqrt(n.x * n.x + n.y * n.y + n.z * n.z);
+
+ SlopeSDF(n, phi, fac, mOrigin);
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/shapes.h b/extern/mantaflow/preprocessed/shapes.h
new file mode 100644
index 00000000000..09d3d23d938
--- /dev/null
+++ b/extern/mantaflow/preprocessed/shapes.h
@@ -0,0 +1,665 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * shapes classes
+ *
+ ******************************************************************************/
+
+#ifndef _SHAPES_H
+#define _SHAPES_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "levelset.h"
+
+namespace Manta {
+
+// forward declaration
+class Mesh;
+
+//! Base class for all shapes
+class Shape : public PbClass {
+ public:
+ enum GridType { TypeNone = 0, TypeBox = 1, TypeSphere = 2, TypeCylinder = 3, TypeSlope = 4 };
+
+ Shape(FluidSolver *parent);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "Shape::Shape", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new Shape(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "Shape::Shape", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("Shape::Shape", e.what());
+ return -1;
+ }
+ }
+
+ //! Get the type of grid
+ inline GridType getType() const
+ {
+ return mType;
+ }
+
+ //! Apply shape to flag grid, set inside cells to <value>
+ void applyToGrid(GridBase *grid, FlagGrid *respectFlags = 0);
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Shape *pbo = dynamic_cast<Shape *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Shape::applyToGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ GridBase *grid = _args.getPtr<GridBase>("grid", 0, &_lock);
+ FlagGrid *respectFlags = _args.getPtrOpt<FlagGrid>("respectFlags", 1, 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->applyToGrid(grid, respectFlags);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Shape::applyToGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Shape::applyToGrid", e.what());
+ return 0;
+ }
+ }
+
+ void applyToGridSmooth(GridBase *grid,
+ Real sigma = 1.0,
+ Real shift = 0,
+ FlagGrid *respectFlags = 0);
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Shape *pbo = dynamic_cast<Shape *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Shape::applyToGridSmooth", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ GridBase *grid = _args.getPtr<GridBase>("grid", 0, &_lock);
+ Real sigma = _args.getOpt<Real>("sigma", 1, 1.0, &_lock);
+ Real shift = _args.getOpt<Real>("shift", 2, 0, &_lock);
+ FlagGrid *respectFlags = _args.getPtrOpt<FlagGrid>("respectFlags", 3, 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->applyToGridSmooth(grid, sigma, shift, respectFlags);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Shape::applyToGridSmooth", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Shape::applyToGridSmooth", e.what());
+ return 0;
+ }
+ }
+
+ LevelsetGrid computeLevelset();
+ static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Shape *pbo = dynamic_cast<Shape *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Shape::computeLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->computeLevelset());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Shape::computeLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Shape::computeLevelset", e.what());
+ return 0;
+ }
+ }
+
+ void collideMesh(Mesh &mesh);
+ static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Shape *pbo = dynamic_cast<Shape *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Shape::collideMesh", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->collideMesh(mesh);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Shape::collideMesh", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Shape::collideMesh", e.what());
+ return 0;
+ }
+ }
+
+ virtual Vec3 getCenter() const
+ {
+ return Vec3::Zero;
+ }
+ static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Shape *pbo = dynamic_cast<Shape *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Shape::getCenter", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getCenter());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Shape::getCenter", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Shape::getCenter", e.what());
+ return 0;
+ }
+ }
+
+ virtual void setCenter(const Vec3 &center)
+ {
+ }
+ static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Shape *pbo = dynamic_cast<Shape *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Shape::setCenter", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Vec3 &center = _args.get<Vec3>("center", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setCenter(center);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Shape::setCenter", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Shape::setCenter", e.what());
+ return 0;
+ }
+ }
+
+ virtual Vec3 getExtent() const
+ {
+ return Vec3::Zero;
+ }
+ static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Shape *pbo = dynamic_cast<Shape *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Shape::getExtent", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->getExtent());
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Shape::getExtent", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Shape::getExtent", e.what());
+ return 0;
+ }
+ }
+
+ //! Inside test of the shape
+ virtual bool isInside(const Vec3 &pos) const;
+ inline bool isInsideGrid(int i, int j, int k) const
+ {
+ return isInside(Vec3(i + 0.5, j + 0.5, k + 0.5));
+ };
+
+ virtual void generateMesh(Mesh *mesh){};
+ virtual void generateLevelset(Grid<Real> &phi){};
+
+ protected:
+ GridType mType;
+ public:
+ PbArgs _args;
+}
+#define _C_Shape
+;
+
+//! Dummy shape
+class NullShape : public Shape {
+ public:
+ NullShape(FluidSolver *parent) : Shape(parent)
+ {
+ }
+ static int _W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "NullShape::NullShape", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new NullShape(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "NullShape::NullShape", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("NullShape::NullShape", e.what());
+ return -1;
+ }
+ }
+
+ virtual bool isInside(const Vec3 &pos) const
+ {
+ return false;
+ }
+ virtual void generateMesh(Mesh *mesh)
+ {
+ }
+
+ protected:
+ virtual void generateLevelset(Grid<Real> &phi)
+ {
+ gridSetConst<Real>(phi, 1000.0f);
+ }
+ public:
+ PbArgs _args;
+}
+#define _C_NullShape
+;
+
+//! Box shape
+class Box : public Shape {
+ public:
+ Box(FluidSolver *parent,
+ Vec3 center = Vec3::Invalid,
+ Vec3 p0 = Vec3::Invalid,
+ Vec3 p1 = Vec3::Invalid,
+ Vec3 size = Vec3::Invalid);
+ static int _W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "Box::Box", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ Vec3 center = _args.getOpt<Vec3>("center", 1, Vec3::Invalid, &_lock);
+ Vec3 p0 = _args.getOpt<Vec3>("p0", 2, Vec3::Invalid, &_lock);
+ Vec3 p1 = _args.getOpt<Vec3>("p1", 3, Vec3::Invalid, &_lock);
+ Vec3 size = _args.getOpt<Vec3>("size", 4, Vec3::Invalid, &_lock);
+ obj = new Box(parent, center, p0, p1, size);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "Box::Box", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("Box::Box", e.what());
+ return -1;
+ }
+ }
+
+ inline Vec3 getSize() const
+ {
+ return mP1 - mP0;
+ }
+ inline Vec3 getP0() const
+ {
+ return mP0;
+ }
+ inline Vec3 getP1() const
+ {
+ return mP1;
+ }
+ virtual void setCenter(const Vec3 &center)
+ {
+ Vec3 dh = 0.5 * (mP1 - mP0);
+ mP0 = center - dh;
+ mP1 = center + dh;
+ }
+ virtual Vec3 getCenter() const
+ {
+ return 0.5 * (mP1 + mP0);
+ }
+ virtual Vec3 getExtent() const
+ {
+ return getSize();
+ }
+ virtual bool isInside(const Vec3 &pos) const;
+ virtual void generateMesh(Mesh *mesh);
+ virtual void generateLevelset(Grid<Real> &phi);
+
+ protected:
+ Vec3 mP0, mP1;
+ public:
+ PbArgs _args;
+}
+#define _C_Box
+;
+
+//! Spherical shape
+class Sphere : public Shape {
+ public:
+ Sphere(FluidSolver *parent, Vec3 center, Real radius, Vec3 scale = Vec3(1, 1, 1));
+ static int _W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "Sphere::Sphere", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ Vec3 center = _args.get<Vec3>("center", 1, &_lock);
+ Real radius = _args.get<Real>("radius", 2, &_lock);
+ Vec3 scale = _args.getOpt<Vec3>("scale", 3, Vec3(1, 1, 1), &_lock);
+ obj = new Sphere(parent, center, radius, scale);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "Sphere::Sphere", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("Sphere::Sphere", e.what());
+ return -1;
+ }
+ }
+
+ virtual void setCenter(const Vec3 &center)
+ {
+ mCenter = center;
+ }
+ virtual Vec3 getCenter() const
+ {
+ return mCenter;
+ }
+ inline Real getRadius() const
+ {
+ return mRadius;
+ }
+ virtual Vec3 getExtent() const
+ {
+ return Vec3(2.0 * mRadius);
+ }
+ virtual bool isInside(const Vec3 &pos) const;
+ virtual void generateMesh(Mesh *mesh);
+ virtual void generateLevelset(Grid<Real> &phi);
+
+ protected:
+ Vec3 mCenter, mScale;
+ Real mRadius;
+ public:
+ PbArgs _args;
+}
+#define _C_Sphere
+;
+
+//! Cylindrical shape
+class Cylinder : public Shape {
+ public:
+ Cylinder(FluidSolver *parent, Vec3 center, Real radius, Vec3 z);
+ static int _W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "Cylinder::Cylinder", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ Vec3 center = _args.get<Vec3>("center", 1, &_lock);
+ Real radius = _args.get<Real>("radius", 2, &_lock);
+ Vec3 z = _args.get<Vec3>("z", 3, &_lock);
+ obj = new Cylinder(parent, center, radius, z);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "Cylinder::Cylinder", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("Cylinder::Cylinder", e.what());
+ return -1;
+ }
+ }
+
+ void setRadius(Real r)
+ {
+ mRadius = r;
+ }
+ static PyObject *_W_12(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Cylinder *pbo = dynamic_cast<Cylinder *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Cylinder::setRadius", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real r = _args.get<Real>("r", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setRadius(r);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Cylinder::setRadius", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Cylinder::setRadius", e.what());
+ return 0;
+ }
+ }
+
+ void setZ(Vec3 z)
+ {
+ mZDir = z;
+ mZ = normalize(mZDir);
+ }
+ static PyObject *_W_13(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Cylinder *pbo = dynamic_cast<Cylinder *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Cylinder::setZ", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Vec3 z = _args.get<Vec3>("z", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->setZ(z);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Cylinder::setZ", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Cylinder::setZ", e.what());
+ return 0;
+ }
+ }
+
+ virtual void setCenter(const Vec3 &center)
+ {
+ mCenter = center;
+ }
+ virtual Vec3 getCenter() const
+ {
+ return mCenter;
+ }
+ inline Real getRadius() const
+ {
+ return mRadius;
+ }
+ inline Vec3 getZ() const
+ {
+ return mZ * mZDir;
+ }
+ virtual Vec3 getExtent() const
+ {
+ return Vec3(2.0 * sqrt(square(mZ) + square(mRadius)));
+ }
+ virtual bool isInside(const Vec3 &pos) const;
+ virtual void generateMesh(Mesh *mesh);
+ virtual void generateLevelset(Grid<Real> &phi);
+
+ protected:
+ Vec3 mCenter, mZDir;
+ Real mRadius, mZ;
+ public:
+ PbArgs _args;
+}
+#define _C_Cylinder
+;
+
+//! Slope shape
+// generates a levelset based on a plane
+// plane is specified by two angles and an offset on the y axis in (offset vector would be ( 0,
+// offset, 0) ) the two angles are specified in degrees, between: y-axis and x-axis
+// y-axis and z-axis
+class Slope : public Shape {
+ public:
+ Slope(FluidSolver *parent, Real anglexy, Real angleyz, Real origin, Vec3 gs);
+ static int _W_14(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "Slope::Slope", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ Real anglexy = _args.get<Real>("anglexy", 1, &_lock);
+ Real angleyz = _args.get<Real>("angleyz", 2, &_lock);
+ Real origin = _args.get<Real>("origin", 3, &_lock);
+ Vec3 gs = _args.get<Vec3>("gs", 4, &_lock);
+ obj = new Slope(parent, anglexy, angleyz, origin, gs);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "Slope::Slope", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("Slope::Slope", e.what());
+ return -1;
+ }
+ }
+
+ virtual void setOrigin(const Real &origin)
+ {
+ mOrigin = origin;
+ }
+ virtual void setAnglexy(const Real &anglexy)
+ {
+ mAnglexy = anglexy;
+ }
+ virtual void setAngleyz(const Real &angleyz)
+ {
+ mAnglexy = angleyz;
+ }
+
+ inline Real getOrigin() const
+ {
+ return mOrigin;
+ }
+ inline Real getmAnglexy() const
+ {
+ return mAnglexy;
+ }
+ inline Real getmAngleyz() const
+ {
+ return mAngleyz;
+ }
+ virtual bool isInside(const Vec3 &pos) const;
+ virtual void generateMesh(Mesh *mesh);
+ virtual void generateLevelset(Grid<Real> &phi);
+
+ protected:
+ Real mAnglexy, mAngleyz;
+ Real mOrigin;
+ Vec3 mGs;
+ public:
+ PbArgs _args;
+}
+#define _C_Slope
+;
+
+} // namespace Manta
+#endif
diff --git a/extern/mantaflow/preprocessed/shapes.h.reg.cpp b/extern/mantaflow/preprocessed/shapes.h.reg.cpp
new file mode 100644
index 00000000000..72c9c61284c
--- /dev/null
+++ b/extern/mantaflow/preprocessed/shapes.h.reg.cpp
@@ -0,0 +1,73 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "shapes.h"
+namespace Manta {
+#ifdef _C_Box
+static const Pb::Register _R_12("Box", "Box", "Shape");
+template<> const char *Namify<Box>::S = "Box";
+static const Pb::Register _R_13("Box", "Box", Box::_W_9);
+#endif
+#ifdef _C_Cylinder
+static const Pb::Register _R_14("Cylinder", "Cylinder", "Shape");
+template<> const char *Namify<Cylinder>::S = "Cylinder";
+static const Pb::Register _R_15("Cylinder", "Cylinder", Cylinder::_W_11);
+static const Pb::Register _R_16("Cylinder", "setRadius", Cylinder::_W_12);
+static const Pb::Register _R_17("Cylinder", "setZ", Cylinder::_W_13);
+#endif
+#ifdef _C_NullShape
+static const Pb::Register _R_18("NullShape", "NullShape", "Shape");
+template<> const char *Namify<NullShape>::S = "NullShape";
+static const Pb::Register _R_19("NullShape", "NullShape", NullShape::_W_8);
+#endif
+#ifdef _C_Shape
+static const Pb::Register _R_20("Shape", "Shape", "PbClass");
+template<> const char *Namify<Shape>::S = "Shape";
+static const Pb::Register _R_21("Shape", "Shape", Shape::_W_0);
+static const Pb::Register _R_22("Shape", "applyToGrid", Shape::_W_1);
+static const Pb::Register _R_23("Shape", "applyToGridSmooth", Shape::_W_2);
+static const Pb::Register _R_24("Shape", "computeLevelset", Shape::_W_3);
+static const Pb::Register _R_25("Shape", "collideMesh", Shape::_W_4);
+static const Pb::Register _R_26("Shape", "getCenter", Shape::_W_5);
+static const Pb::Register _R_27("Shape", "setCenter", Shape::_W_6);
+static const Pb::Register _R_28("Shape", "getExtent", Shape::_W_7);
+#endif
+#ifdef _C_Slope
+static const Pb::Register _R_29("Slope", "Slope", "Shape");
+template<> const char *Namify<Slope>::S = "Slope";
+static const Pb::Register _R_30("Slope", "Slope", Slope::_W_14);
+#endif
+#ifdef _C_Sphere
+static const Pb::Register _R_31("Sphere", "Sphere", "Shape");
+template<> const char *Namify<Sphere>::S = "Sphere";
+static const Pb::Register _R_32("Sphere", "Sphere", Sphere::_W_10);
+#endif
+extern "C" {
+void PbRegister_file_12()
+{
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/test.cpp b/extern/mantaflow/preprocessed/test.cpp
new file mode 100644
index 00000000000..b90c886efe7
--- /dev/null
+++ b/extern/mantaflow/preprocessed/test.cpp
@@ -0,0 +1,133 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Use this file to test new functionality
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include <cmath>
+
+using namespace std;
+
+namespace Manta {
+
+// two simple example kernels
+
+struct reductionTest : public KernelBase {
+ reductionTest(const Grid<Real> &v) : KernelBase(&v, 0), v(v), sum(0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Real> &v, double &sum)
+ {
+ sum += v[idx];
+ }
+ inline operator double()
+ {
+ return sum;
+ }
+ inline double &getRet()
+ {
+ return sum;
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return v;
+ }
+ typedef Grid<Real> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel reductionTest ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, v, sum);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ reductionTest(reductionTest &o, tbb::split) : KernelBase(o), v(o.v), sum(0)
+ {
+ }
+ void join(const reductionTest &o)
+ {
+ sum += o.sum;
+ }
+ const Grid<Real> &v;
+ double sum;
+};
+
+struct minReduction : public KernelBase {
+ minReduction(const Grid<Real> &v) : KernelBase(&v, 0), v(v), sum(0)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, const Grid<Real> &v, double &sum)
+ {
+ if (sum < v[idx])
+ sum = v[idx];
+ }
+ inline operator double()
+ {
+ return sum;
+ }
+ inline double &getRet()
+ {
+ return sum;
+ }
+ inline const Grid<Real> &getArg0()
+ {
+ return v;
+ }
+ typedef Grid<Real> type0;
+ void runMessage()
+ {
+ debMsg("Executing kernel minReduction ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r)
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, v, sum);
+ }
+ void run()
+ {
+ tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ minReduction(minReduction &o, tbb::split) : KernelBase(o), v(o.v), sum(0)
+ {
+ }
+ void join(const minReduction &o)
+ {
+ sum = min(sum, o.sum);
+ }
+ const Grid<Real> &v;
+ double sum;
+};
+
+// ... add more test code here if necessary ...
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/timing.cpp b/extern/mantaflow/preprocessed/timing.cpp
new file mode 100644
index 00000000000..ae572032e4a
--- /dev/null
+++ b/extern/mantaflow/preprocessed/timing.cpp
@@ -0,0 +1,128 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugin timing
+ *
+ ******************************************************************************/
+
+#include "timing.h"
+#include <fstream>
+
+using namespace std;
+namespace Manta {
+
+TimingData::TimingData() : updated(false), num(0)
+{
+}
+
+void TimingData::start(FluidSolver *parent, const string &name)
+{
+ mLastPlugin = name;
+ mPluginTimer.get();
+}
+
+void TimingData::stop(FluidSolver *parent, const string &name)
+{
+ if (mLastPlugin == name && name != "FluidSolver::step") {
+ updated = true;
+ const string parentName = parent ? parent->getName() : "";
+ MuTime diff = mPluginTimer.update();
+ vector<TimingSet> &cur = mData[name];
+ for (vector<TimingSet>::iterator it = cur.begin(); it != cur.end(); it++) {
+ if (it->solver == parentName) {
+ it->cur += diff;
+ it->updated = true;
+ return;
+ }
+ }
+ TimingSet s;
+ s.solver = parentName;
+ s.cur = diff;
+ s.updated = true;
+ cur.push_back(s);
+ }
+}
+
+void TimingData::step()
+{
+ if (updated)
+ num++;
+ std::map<std::string, std::vector<TimingSet>>::iterator it;
+ for (it = mData.begin(); it != mData.end(); it++) {
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) {
+ if (it2->updated) {
+ it2->total += it2->cur;
+ it2->num++;
+ }
+ it2->cur.clear();
+ it2->updated = false;
+ }
+ }
+ updated = false;
+}
+
+void TimingData::print()
+{
+ MuTime total;
+ total.clear();
+ std::map<std::string, std::vector<TimingSet>>::iterator it;
+ for (it = mData.begin(); it != mData.end(); it++)
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++)
+ total += it2->cur;
+
+ printf("\n-- STEP %3d ----------------------------\n", num);
+ for (it = mData.begin(); it != mData.end(); it++) {
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) {
+ if (!it2->updated)
+ continue;
+ string name = it->first;
+ if (it->second.size() > 1 && !it2->solver.empty())
+ name += "[" + it2->solver + "]";
+ printf("[%4.1f%%] %s (%s)\n",
+ 100.0 * ((Real)it2->cur.time / (Real)total.time),
+ name.c_str(),
+ it2->cur.toString().c_str());
+ }
+ }
+ step();
+
+ printf("----------------------------------------\n");
+ printf("Total : %s\n\n", total.toString().c_str());
+}
+
+void TimingData::saveMean(const string &filename)
+{
+ ofstream ofs(filename.c_str());
+ step();
+ if (!ofs.good())
+ errMsg("can't open " + filename + " as timing log");
+ ofs << "Mean timings of " << num << " steps :" << endl << endl;
+ MuTime total;
+ total.clear();
+ std::map<std::string, std::vector<TimingSet>>::iterator it;
+ for (it = mData.begin(); it != mData.end(); it++)
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) {
+ total += it2->cur;
+ string name = it->first;
+ if (it->second.size() > 1)
+ name += "[" + it2->solver + "]";
+
+ ofs << name << " " << (it2->total / it2->num) << endl;
+ }
+
+ ofs << endl << "Total : " << total << " (mean " << total / num << ")" << endl;
+ ofs.close();
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/timing.h b/extern/mantaflow/preprocessed/timing.h
new file mode 100644
index 00000000000..a05e5cd3323
--- /dev/null
+++ b/extern/mantaflow/preprocessed/timing.h
@@ -0,0 +1,157 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugin timing
+ *
+ ******************************************************************************/
+
+#ifndef _TIMING_H
+#define _TIMING_H
+
+#include "manta.h"
+#include <map>
+namespace Manta {
+
+class TimingData {
+ private:
+ TimingData();
+
+ public:
+ static TimingData &instance()
+ {
+ static TimingData a;
+ return a;
+ }
+
+ void print();
+ void saveMean(const std::string &filename);
+ void start(FluidSolver *parent, const std::string &name);
+ void stop(FluidSolver *parent, const std::string &name);
+
+ protected:
+ void step();
+ struct TimingSet {
+ TimingSet() : num(0), updated(false)
+ {
+ cur.clear();
+ total.clear();
+ }
+ MuTime cur, total;
+ int num;
+ bool updated;
+ std::string solver;
+ };
+ bool updated;
+
+ int num;
+ MuTime mPluginTimer;
+ std::string mLastPlugin;
+ std::map<std::string, std::vector<TimingSet>> mData;
+};
+
+// Python interface
+class Timings : public PbClass {
+ public:
+ Timings() : PbClass(0)
+ {
+ }
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "Timings::Timings", !noTiming);
+ {
+ ArgLocker _lock;
+ obj = new Timings();
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "Timings::Timings", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("Timings::Timings", e.what());
+ return -1;
+ }
+ }
+
+ void display()
+ {
+ TimingData::instance().print();
+ }
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Timings *pbo = dynamic_cast<Timings *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Timings::display", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->display();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Timings::display", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Timings::display", e.what());
+ return 0;
+ }
+ }
+ void saveMean(std::string file)
+ {
+ TimingData::instance().saveMean(file);
+ }
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ Timings *pbo = dynamic_cast<Timings *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "Timings::saveMean", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ std::string file = _args.get<std::string>("file", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->saveMean(file);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "Timings::saveMean", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("Timings::saveMean", e.what());
+ return 0;
+ }
+ }
+
+ public:
+ PbArgs _args;
+}
+#define _C_Timings
+;
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/timing.h.reg.cpp b/extern/mantaflow/preprocessed/timing.h.reg.cpp
new file mode 100644
index 00000000000..c0f63ec7850
--- /dev/null
+++ b/extern/mantaflow/preprocessed/timing.h.reg.cpp
@@ -0,0 +1,24 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "timing.h"
+namespace Manta {
+#ifdef _C_Timings
+static const Pb::Register _R_16("Timings", "Timings", "PbClass");
+template<> const char *Namify<Timings>::S = "Timings";
+static const Pb::Register _R_17("Timings", "Timings", Timings::_W_0);
+static const Pb::Register _R_18("Timings", "display", Timings::_W_1);
+static const Pb::Register _R_19("Timings", "saveMean", Timings::_W_2);
+#endif
+extern "C" {
+void PbRegister_file_16()
+{
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/turbulencepart.cpp b/extern/mantaflow/preprocessed/turbulencepart.cpp
new file mode 100644
index 00000000000..168ae9cc2f2
--- /dev/null
+++ b/extern/mantaflow/preprocessed/turbulencepart.cpp
@@ -0,0 +1,288 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.ynu.org/licenses
+ *
+ * Turbulence particles
+ *
+ ******************************************************************************/
+
+#include "turbulencepart.h"
+#include "shapes.h"
+#include "randomstream.h"
+
+using namespace std;
+namespace Manta {
+
+TurbulenceParticleSystem::TurbulenceParticleSystem(FluidSolver *parent, WaveletNoiseField &noise)
+ : ParticleSystem<TurbulenceParticleData>(parent), noise(noise)
+{
+}
+
+ParticleBase *TurbulenceParticleSystem::clone()
+{
+ TurbulenceParticleSystem *nm = new TurbulenceParticleSystem(getParent(), noise);
+ compress();
+
+ nm->mData = mData;
+ nm->setName(getName());
+ return nm;
+}
+
+inline Vec3 hsv2rgb(Real h, Real s, Real v)
+{
+ Real r = 0, g = 0, b = 0;
+
+ int i = (int)(h * 6);
+ Real f = h * 6 - i;
+ Real p = v * (1 - s);
+ Real q = v * (1 - f * s);
+ Real t = v * (1 - (1 - f) * s);
+
+ switch (i % 6) {
+ case 0:
+ r = v, g = t, b = p;
+ break;
+ case 1:
+ r = q, g = v, b = p;
+ break;
+ case 2:
+ r = p, g = v, b = t;
+ break;
+ case 3:
+ r = p, g = q, b = v;
+ break;
+ case 4:
+ r = t, g = p, b = v;
+ break;
+ case 5:
+ r = v, g = p, b = q;
+ break;
+ default:
+ break;
+ }
+
+ return Vec3(r, g, b);
+}
+
+void TurbulenceParticleSystem::seed(Shape *shape, int num)
+{
+ static RandomStream rand(34894231);
+ Vec3 sz = shape->getExtent(), p0 = shape->getCenter() - sz * 0.5;
+ for (int i = 0; i < num; i++) {
+ Vec3 p;
+ do {
+ p = rand.getVec3() * sz + p0;
+ } while (!shape->isInside(p));
+ Real z = (p.z - p0.z) / sz.z;
+ add(TurbulenceParticleData(p, hsv2rgb(z, 0.75, 1.0)));
+ }
+}
+
+void TurbulenceParticleSystem::resetTexCoords(int num, const Vec3 &inflow)
+{
+ if (num == 0) {
+ for (int i = 0; i < size(); i++)
+ mData[i].tex0 = mData[i].pos - inflow;
+ }
+ else {
+ for (int i = 0; i < size(); i++)
+ mData[i].tex1 = mData[i].pos - inflow;
+ }
+}
+
+struct KnSynthesizeTurbulence : public KernelBase {
+ KnSynthesizeTurbulence(TurbulenceParticleSystem &p,
+ FlagGrid &flags,
+ WaveletNoiseField &noise,
+ Grid<Real> &kGrid,
+ Real alpha,
+ Real dt,
+ int octaves,
+ Real scale,
+ Real invL0,
+ Real kmin)
+ : KernelBase(p.size()),
+ p(p),
+ flags(flags),
+ noise(noise),
+ kGrid(kGrid),
+ alpha(alpha),
+ dt(dt),
+ octaves(octaves),
+ scale(scale),
+ invL0(invL0),
+ kmin(kmin)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ TurbulenceParticleSystem &p,
+ FlagGrid &flags,
+ WaveletNoiseField &noise,
+ Grid<Real> &kGrid,
+ Real alpha,
+ Real dt,
+ int octaves,
+ Real scale,
+ Real invL0,
+ Real kmin) const
+ {
+ const Real PERSISTENCE = 0.56123f;
+
+ const Vec3 pos(p[idx].pos);
+ if (flags.isInBounds(pos)) { // && !flags.isObstacle(pos)) {
+ Real k2 = kGrid.getInterpolated(pos) - kmin;
+ Real ks = k2 < 0 ? 0.0 : sqrt(k2);
+
+ // Wavelet noise lookup
+ Real amplitude = scale * ks;
+ Real multiplier = invL0;
+ Vec3 vel(0.);
+ for (int o = 0; o < octaves; o++) {
+ // Vec3 ns = noise.evaluateCurl(p[i].pos * multiplier) * amplitude;
+ Vec3 n0 = noise.evaluateCurl(p[idx].tex0 * multiplier) * amplitude;
+ Vec3 n1 = noise.evaluateCurl(p[idx].tex1 * multiplier) * amplitude;
+ vel += alpha * n0 + (1.0f - alpha) * n1;
+
+ // next scale
+ amplitude *= PERSISTENCE;
+ multiplier *= 2.0f;
+ }
+
+ // advection
+ Vec3 dx = vel * dt;
+ p[idx].pos += dx;
+ p[idx].tex0 += dx;
+ p[idx].tex1 += dx;
+ }
+ }
+ inline TurbulenceParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef TurbulenceParticleSystem type0;
+ inline FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline WaveletNoiseField &getArg2()
+ {
+ return noise;
+ }
+ typedef WaveletNoiseField type2;
+ inline Grid<Real> &getArg3()
+ {
+ return kGrid;
+ }
+ typedef Grid<Real> type3;
+ inline Real &getArg4()
+ {
+ return alpha;
+ }
+ typedef Real type4;
+ inline Real &getArg5()
+ {
+ return dt;
+ }
+ typedef Real type5;
+ inline int &getArg6()
+ {
+ return octaves;
+ }
+ typedef int type6;
+ inline Real &getArg7()
+ {
+ return scale;
+ }
+ typedef Real type7;
+ inline Real &getArg8()
+ {
+ return invL0;
+ }
+ typedef Real type8;
+ inline Real &getArg9()
+ {
+ return kmin;
+ }
+ typedef Real type9;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnSynthesizeTurbulence ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, flags, noise, kGrid, alpha, dt, octaves, scale, invL0, kmin);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ TurbulenceParticleSystem &p;
+ FlagGrid &flags;
+ WaveletNoiseField &noise;
+ Grid<Real> &kGrid;
+ Real alpha;
+ Real dt;
+ int octaves;
+ Real scale;
+ Real invL0;
+ Real kmin;
+};
+
+void TurbulenceParticleSystem::synthesize(FlagGrid &flags,
+ Grid<Real> &k,
+ int octaves,
+ Real switchLength,
+ Real L0,
+ Real scale,
+ Vec3 inflowBias)
+{
+ static Real ctime = 0;
+ static Vec3 inflow(0.);
+ Real dt = getParent()->getDt();
+
+ // collect inflow bias
+ inflow += inflowBias * dt;
+
+ // alpha: hat function over time
+ Real oldAlpha = 2.0f * nmod(ctime / switchLength, Real(1.0));
+ ctime += dt;
+ Real alpha = 2.0f * nmod(ctime / switchLength, Real(1.0));
+
+ if (oldAlpha < 1.0f && alpha >= 1.0f)
+ resetTexCoords(0, inflow);
+ if (oldAlpha > alpha)
+ resetTexCoords(1, inflow);
+ if (alpha > 1.0f)
+ alpha = 2.0f - alpha;
+ alpha = 1.0;
+
+ KnSynthesizeTurbulence(
+ *this, flags, noise, k, alpha, dt, octaves, scale, 1.0f / L0, 1.5 * square(0.1));
+}
+
+void TurbulenceParticleSystem::deleteInObstacle(FlagGrid &flags)
+{
+ for (int i = 0; i < size(); i++)
+ if (flags.isObstacle(mData[i].pos))
+ mData[i].flag |= PDELETE;
+ compress();
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/turbulencepart.h b/extern/mantaflow/preprocessed/turbulencepart.h
new file mode 100644
index 00000000000..7e7fbae15fd
--- /dev/null
+++ b/extern/mantaflow/preprocessed/turbulencepart.h
@@ -0,0 +1,210 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Turbulence particles
+ *
+ ******************************************************************************/
+
+#ifndef _TURBULENCEPART_H_
+#define _TURBULENCEPART_H_
+
+#include "particle.h"
+#include "noisefield.h"
+
+namespace Manta {
+class Shape;
+
+struct TurbulenceParticleData {
+ TurbulenceParticleData() : pos(0.0), color(1.), tex0(0.0), tex1(0.0), flag(0)
+ {
+ }
+ TurbulenceParticleData(const Vec3 &p, const Vec3 &color = Vec3(1.))
+ : pos(p), color(color), tex0(p), tex1(p), flag(0)
+ {
+ }
+ Vec3 pos, color;
+ Vec3 tex0, tex1;
+ int flag;
+ static ParticleBase::SystemType getType()
+ {
+ return ParticleBase::TURBULENCE;
+ }
+};
+
+//! Turbulence particles
+class TurbulenceParticleSystem : public ParticleSystem<TurbulenceParticleData> {
+ public:
+ TurbulenceParticleSystem(FluidSolver *parent, WaveletNoiseField &noise);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "TurbulenceParticleSystem::TurbulenceParticleSystem", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ WaveletNoiseField &noise = *_args.getPtr<WaveletNoiseField>("noise", 1, &_lock);
+ obj = new TurbulenceParticleSystem(parent, noise);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(
+ obj->getParent(), "TurbulenceParticleSystem::TurbulenceParticleSystem", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("TurbulenceParticleSystem::TurbulenceParticleSystem", e.what());
+ return -1;
+ }
+ }
+
+ void resetTexCoords(int num, const Vec3 &inflow);
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ TurbulenceParticleSystem *pbo = dynamic_cast<TurbulenceParticleSystem *>(
+ Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::resetTexCoords", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ int num = _args.get<int>("num", 0, &_lock);
+ const Vec3 &inflow = _args.get<Vec3>("inflow", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->resetTexCoords(num, inflow);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "TurbulenceParticleSystem::resetTexCoords", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("TurbulenceParticleSystem::resetTexCoords", e.what());
+ return 0;
+ }
+ }
+
+ void seed(Shape *source, int num);
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ TurbulenceParticleSystem *pbo = dynamic_cast<TurbulenceParticleSystem *>(
+ Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::seed", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Shape *source = _args.getPtr<Shape>("source", 0, &_lock);
+ int num = _args.get<int>("num", 1, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->seed(source, num);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "TurbulenceParticleSystem::seed", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("TurbulenceParticleSystem::seed", e.what());
+ return 0;
+ }
+ }
+
+ void synthesize(FlagGrid &flags,
+ Grid<Real> &k,
+ int octaves = 2,
+ Real switchLength = 10.0,
+ Real L0 = 0.1,
+ Real scale = 1.0,
+ Vec3 inflowBias = 0.0);
+ static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ TurbulenceParticleSystem *pbo = dynamic_cast<TurbulenceParticleSystem *>(
+ Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::synthesize", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &k = *_args.getPtr<Grid<Real>>("k", 1, &_lock);
+ int octaves = _args.getOpt<int>("octaves", 2, 2, &_lock);
+ Real switchLength = _args.getOpt<Real>("switchLength", 3, 10.0, &_lock);
+ Real L0 = _args.getOpt<Real>("L0", 4, 0.1, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 5, 1.0, &_lock);
+ Vec3 inflowBias = _args.getOpt<Vec3>("inflowBias", 6, 0.0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->synthesize(flags, k, octaves, switchLength, L0, scale, inflowBias);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "TurbulenceParticleSystem::synthesize", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("TurbulenceParticleSystem::synthesize", e.what());
+ return 0;
+ }
+ }
+
+ void deleteInObstacle(FlagGrid &flags);
+ static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ TurbulenceParticleSystem *pbo = dynamic_cast<TurbulenceParticleSystem *>(
+ Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::deleteInObstacle", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->deleteInObstacle(flags);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "TurbulenceParticleSystem::deleteInObstacle", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("TurbulenceParticleSystem::deleteInObstacle", e.what());
+ return 0;
+ }
+ }
+
+ virtual ParticleBase *clone();
+
+ private:
+ WaveletNoiseField &noise;
+ public:
+ PbArgs _args;
+}
+#define _C_TurbulenceParticleSystem
+;
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/turbulencepart.h.reg.cpp b/extern/mantaflow/preprocessed/turbulencepart.h.reg.cpp
new file mode 100644
index 00000000000..1f035908830
--- /dev/null
+++ b/extern/mantaflow/preprocessed/turbulencepart.h.reg.cpp
@@ -0,0 +1,89 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "turbulencepart.h"
+namespace Manta {
+#ifdef _C_ParticleSystem
+static const Pb::Register _R_21("ParticleSystem<TurbulenceParticleData>",
+ "ParticleSystem<TurbulenceParticleData>",
+ "ParticleBase");
+template<>
+const char *Namify<ParticleSystem<TurbulenceParticleData>>::S =
+ "ParticleSystem<TurbulenceParticleData>";
+static const Pb::Register _R_22("ParticleSystem<TurbulenceParticleData>",
+ "ParticleSystem",
+ ParticleSystem<TurbulenceParticleData>::_W_2);
+static const Pb::Register _R_23("ParticleSystem<TurbulenceParticleData>",
+ "pySize",
+ ParticleSystem<TurbulenceParticleData>::_W_3);
+static const Pb::Register _R_24("ParticleSystem<TurbulenceParticleData>",
+ "setPos",
+ ParticleSystem<TurbulenceParticleData>::_W_4);
+static const Pb::Register _R_25("ParticleSystem<TurbulenceParticleData>",
+ "getPos",
+ ParticleSystem<TurbulenceParticleData>::_W_5);
+static const Pb::Register _R_26("ParticleSystem<TurbulenceParticleData>",
+ "getPosPdata",
+ ParticleSystem<TurbulenceParticleData>::_W_6);
+static const Pb::Register _R_27("ParticleSystem<TurbulenceParticleData>",
+ "setPosPdata",
+ ParticleSystem<TurbulenceParticleData>::_W_7);
+static const Pb::Register _R_28("ParticleSystem<TurbulenceParticleData>",
+ "clear",
+ ParticleSystem<TurbulenceParticleData>::_W_8);
+static const Pb::Register _R_29("ParticleSystem<TurbulenceParticleData>",
+ "advectInGrid",
+ ParticleSystem<TurbulenceParticleData>::_W_9);
+static const Pb::Register _R_30("ParticleSystem<TurbulenceParticleData>",
+ "projectOutside",
+ ParticleSystem<TurbulenceParticleData>::_W_10);
+static const Pb::Register _R_31("ParticleSystem<TurbulenceParticleData>",
+ "projectOutOfBnd",
+ ParticleSystem<TurbulenceParticleData>::_W_11);
+#endif
+#ifdef _C_TurbulenceParticleSystem
+static const Pb::Register _R_32("TurbulenceParticleSystem",
+ "TurbulenceParticleSystem",
+ "ParticleSystem<TurbulenceParticleData>");
+template<> const char *Namify<TurbulenceParticleSystem>::S = "TurbulenceParticleSystem";
+static const Pb::Register _R_33("TurbulenceParticleSystem",
+ "TurbulenceParticleSystem",
+ TurbulenceParticleSystem::_W_0);
+static const Pb::Register _R_34("TurbulenceParticleSystem",
+ "resetTexCoords",
+ TurbulenceParticleSystem::_W_1);
+static const Pb::Register _R_35("TurbulenceParticleSystem",
+ "seed",
+ TurbulenceParticleSystem::_W_2);
+static const Pb::Register _R_36("TurbulenceParticleSystem",
+ "synthesize",
+ TurbulenceParticleSystem::_W_3);
+static const Pb::Register _R_37("TurbulenceParticleSystem",
+ "deleteInObstacle",
+ TurbulenceParticleSystem::_W_4);
+#endif
+extern "C" {
+void PbRegister_file_21()
+{
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/vortexpart.cpp b/extern/mantaflow/preprocessed/vortexpart.cpp
new file mode 100644
index 00000000000..0eba2743ee8
--- /dev/null
+++ b/extern/mantaflow/preprocessed/vortexpart.cpp
@@ -0,0 +1,251 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex particles
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#include "vortexpart.h"
+#include "integrator.h"
+#include "mesh.h"
+
+using namespace std;
+namespace Manta {
+
+// vortex particle effect: (cyl coord around wp)
+// u = -|wp|*rho*exp( (-rho^2-z^2)/(2sigma^2) ) e_phi
+inline Vec3 VortexKernel(const Vec3 &p, const vector<VortexParticleData> &vp, Real scale)
+{
+ Vec3 u(0.0);
+ for (size_t i = 0; i < vp.size(); i++) {
+ if (vp[i].flag & ParticleBase::PDELETE)
+ continue;
+
+ // cutoff radius
+ const Vec3 r = p - vp[i].pos;
+ const Real rlen2 = normSquare(r);
+ const Real sigma2 = square(vp[i].sigma);
+ if (rlen2 > 6.0 * sigma2 || rlen2 < 1e-8)
+ continue;
+
+ // split vortex strength
+ Vec3 vortNorm = vp[i].vorticity;
+ Real strength = normalize(vortNorm) * scale;
+
+ // transform in cylinder coordinate system
+ const Real rlen = sqrt(rlen2);
+ const Real z = dot(r, vortNorm);
+ const Vec3 ePhi = cross(r, vortNorm) / rlen;
+ const Real rho2 = rlen2 - z * z;
+
+ Real vortex = 0;
+ if (rho2 > 1e-10) {
+ // evaluate Kernel
+ vortex = strength * sqrt(rho2) * exp(rlen2 * -0.5 / sigma2);
+ }
+ u += vortex * ePhi;
+ }
+ return u;
+}
+
+struct _KnVpAdvectMesh : public KernelBase {
+ _KnVpAdvectMesh(const KernelBase &base,
+ vector<Node> &nodes,
+ const vector<VortexParticleData> &vp,
+ Real scale,
+ vector<Vec3> &u)
+ : KernelBase(base), nodes(nodes), vp(vp), scale(scale), u(u)
+ {
+ }
+ inline void op(IndexInt idx,
+ vector<Node> &nodes,
+ const vector<VortexParticleData> &vp,
+ Real scale,
+ vector<Vec3> &u) const
+ {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = 0.0;
+ else
+ u[idx] = VortexKernel(nodes[idx].pos, vp, scale);
+ }
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, nodes, vp, scale, u);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ vector<Node> &nodes;
+ const vector<VortexParticleData> &vp;
+ Real scale;
+ vector<Vec3> &u;
+};
+struct KnVpAdvectMesh : public KernelBase {
+ KnVpAdvectMesh(vector<Node> &nodes, const vector<VortexParticleData> &vp, Real scale)
+ : KernelBase(nodes.size()),
+ _inner(KernelBase(nodes.size()), nodes, vp, scale, u),
+ nodes(nodes),
+ vp(vp),
+ scale(scale),
+ u((size))
+ {
+ runMessage();
+ run();
+ }
+ void run()
+ {
+ _inner.run();
+ }
+ inline operator vector<Vec3>()
+ {
+ return u;
+ }
+ inline vector<Vec3> &getRet()
+ {
+ return u;
+ }
+ inline vector<Node> &getArg0()
+ {
+ return nodes;
+ }
+ typedef vector<Node> type0;
+ inline const vector<VortexParticleData> &getArg1()
+ {
+ return vp;
+ }
+ typedef vector<VortexParticleData> type1;
+ inline Real &getArg2()
+ {
+ return scale;
+ }
+ typedef Real type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnVpAdvectMesh ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ _KnVpAdvectMesh _inner;
+ vector<Node> &nodes;
+ const vector<VortexParticleData> &vp;
+ Real scale;
+ vector<Vec3> u;
+};
+
+struct _KnVpAdvectSelf : public KernelBase {
+ _KnVpAdvectSelf(const KernelBase &base,
+ vector<VortexParticleData> &vp,
+ Real scale,
+ vector<Vec3> &u)
+ : KernelBase(base), vp(vp), scale(scale), u(u)
+ {
+ }
+ inline void op(IndexInt idx, vector<VortexParticleData> &vp, Real scale, vector<Vec3> &u) const
+ {
+ if (vp[idx].flag & ParticleBase::PDELETE)
+ u[idx] = 0.0;
+ else
+ u[idx] = VortexKernel(vp[idx].pos, vp, scale);
+ }
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, vp, scale, u);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ vector<VortexParticleData> &vp;
+ Real scale;
+ vector<Vec3> &u;
+};
+struct KnVpAdvectSelf : public KernelBase {
+ KnVpAdvectSelf(vector<VortexParticleData> &vp, Real scale)
+ : KernelBase(vp.size()),
+ _inner(KernelBase(vp.size()), vp, scale, u),
+ vp(vp),
+ scale(scale),
+ u((size))
+ {
+ runMessage();
+ run();
+ }
+ void run()
+ {
+ _inner.run();
+ }
+ inline operator vector<Vec3>()
+ {
+ return u;
+ }
+ inline vector<Vec3> &getRet()
+ {
+ return u;
+ }
+ inline vector<VortexParticleData> &getArg0()
+ {
+ return vp;
+ }
+ typedef vector<VortexParticleData> type0;
+ inline Real &getArg1()
+ {
+ return scale;
+ }
+ typedef Real type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnVpAdvectSelf ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ _KnVpAdvectSelf _inner;
+ vector<VortexParticleData> &vp;
+ Real scale;
+ vector<Vec3> u;
+};
+
+VortexParticleSystem::VortexParticleSystem(FluidSolver *parent)
+ : ParticleSystem<VortexParticleData>(parent)
+{
+}
+
+void VortexParticleSystem::advectSelf(Real scale, int integrationMode)
+{
+ KnVpAdvectSelf kernel(mData, scale * getParent()->getDt());
+ integratePointSet(kernel, integrationMode);
+}
+
+void VortexParticleSystem::applyToMesh(Mesh &mesh, Real scale, int integrationMode)
+{
+ KnVpAdvectMesh kernel(mesh.getNodeData(), mData, scale * getParent()->getDt());
+ integratePointSet(kernel, integrationMode);
+}
+
+ParticleBase *VortexParticleSystem::clone()
+{
+ VortexParticleSystem *nm = new VortexParticleSystem(getParent());
+ compress();
+
+ nm->mData = mData;
+ nm->setName(getName());
+ return nm;
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/vortexpart.h b/extern/mantaflow/preprocessed/vortexpart.h
new file mode 100644
index 00000000000..20335c20058
--- /dev/null
+++ b/extern/mantaflow/preprocessed/vortexpart.h
@@ -0,0 +1,138 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex particles
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#ifndef _VORTEXPART_H
+#define _VORTEXPART_H
+
+#include "particle.h"
+
+namespace Manta {
+class Mesh;
+
+struct VortexParticleData {
+ VortexParticleData() : pos(0.0), vorticity(0.0), sigma(0), flag(0)
+ {
+ }
+ VortexParticleData(const Vec3 &p, const Vec3 &v, Real sig)
+ : pos(p), vorticity(v), sigma(sig), flag(0)
+ {
+ }
+ Vec3 pos, vorticity;
+ Real sigma;
+ int flag;
+ static ParticleBase::SystemType getType()
+ {
+ return ParticleBase::VORTEX;
+ }
+};
+
+//! Vortex particles
+class VortexParticleSystem : public ParticleSystem<VortexParticleData> {
+ public:
+ VortexParticleSystem(FluidSolver *parent);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "VortexParticleSystem::VortexParticleSystem", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new VortexParticleSystem(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "VortexParticleSystem::VortexParticleSystem", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("VortexParticleSystem::VortexParticleSystem", e.what());
+ return -1;
+ }
+ }
+
+ void advectSelf(Real scale = 1.0, int integrationMode = IntRK4);
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ VortexParticleSystem *pbo = dynamic_cast<VortexParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "VortexParticleSystem::advectSelf", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Real scale = _args.getOpt<Real>("scale", 0, 1.0, &_lock);
+ int integrationMode = _args.getOpt<int>("integrationMode", 1, IntRK4, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->advectSelf(scale, integrationMode);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "VortexParticleSystem::advectSelf", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("VortexParticleSystem::advectSelf", e.what());
+ return 0;
+ }
+ }
+
+ void applyToMesh(Mesh &mesh, Real scale = 1.0, int integrationMode = IntRK4);
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ VortexParticleSystem *pbo = dynamic_cast<VortexParticleSystem *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "VortexParticleSystem::applyToMesh", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
+ Real scale = _args.getOpt<Real>("scale", 1, 1.0, &_lock);
+ int integrationMode = _args.getOpt<int>("integrationMode", 2, IntRK4, &_lock);
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->applyToMesh(mesh, scale, integrationMode);
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "VortexParticleSystem::applyToMesh", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("VortexParticleSystem::applyToMesh", e.what());
+ return 0;
+ }
+ }
+
+ virtual ParticleBase *clone();
+ public:
+ PbArgs _args;
+}
+#define _C_VortexParticleSystem
+;
+
+} // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/vortexpart.h.reg.cpp b/extern/mantaflow/preprocessed/vortexpart.h.reg.cpp
new file mode 100644
index 00000000000..0dad1802f3c
--- /dev/null
+++ b/extern/mantaflow/preprocessed/vortexpart.h.reg.cpp
@@ -0,0 +1,76 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "vortexpart.h"
+namespace Manta {
+#ifdef _C_ParticleSystem
+static const Pb::Register _R_20("ParticleSystem<VortexParticleData>",
+ "ParticleSystem<VortexParticleData>",
+ "ParticleBase");
+template<>
+const char *Namify<ParticleSystem<VortexParticleData>>::S = "ParticleSystem<VortexParticleData>";
+static const Pb::Register _R_21("ParticleSystem<VortexParticleData>",
+ "ParticleSystem",
+ ParticleSystem<VortexParticleData>::_W_2);
+static const Pb::Register _R_22("ParticleSystem<VortexParticleData>",
+ "pySize",
+ ParticleSystem<VortexParticleData>::_W_3);
+static const Pb::Register _R_23("ParticleSystem<VortexParticleData>",
+ "setPos",
+ ParticleSystem<VortexParticleData>::_W_4);
+static const Pb::Register _R_24("ParticleSystem<VortexParticleData>",
+ "getPos",
+ ParticleSystem<VortexParticleData>::_W_5);
+static const Pb::Register _R_25("ParticleSystem<VortexParticleData>",
+ "getPosPdata",
+ ParticleSystem<VortexParticleData>::_W_6);
+static const Pb::Register _R_26("ParticleSystem<VortexParticleData>",
+ "setPosPdata",
+ ParticleSystem<VortexParticleData>::_W_7);
+static const Pb::Register _R_27("ParticleSystem<VortexParticleData>",
+ "clear",
+ ParticleSystem<VortexParticleData>::_W_8);
+static const Pb::Register _R_28("ParticleSystem<VortexParticleData>",
+ "advectInGrid",
+ ParticleSystem<VortexParticleData>::_W_9);
+static const Pb::Register _R_29("ParticleSystem<VortexParticleData>",
+ "projectOutside",
+ ParticleSystem<VortexParticleData>::_W_10);
+static const Pb::Register _R_30("ParticleSystem<VortexParticleData>",
+ "projectOutOfBnd",
+ ParticleSystem<VortexParticleData>::_W_11);
+#endif
+#ifdef _C_VortexParticleSystem
+static const Pb::Register _R_31("VortexParticleSystem",
+ "VortexParticleSystem",
+ "ParticleSystem<VortexParticleData>");
+template<> const char *Namify<VortexParticleSystem>::S = "VortexParticleSystem";
+static const Pb::Register _R_32("VortexParticleSystem",
+ "VortexParticleSystem",
+ VortexParticleSystem::_W_0);
+static const Pb::Register _R_33("VortexParticleSystem", "advectSelf", VortexParticleSystem::_W_1);
+static const Pb::Register _R_34("VortexParticleSystem", "applyToMesh", VortexParticleSystem::_W_2);
+#endif
+extern "C" {
+void PbRegister_file_20()
+{
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/mantaflow/preprocessed/vortexsheet.cpp b/extern/mantaflow/preprocessed/vortexsheet.cpp
new file mode 100644
index 00000000000..695b881006d
--- /dev/null
+++ b/extern/mantaflow/preprocessed/vortexsheet.cpp
@@ -0,0 +1,116 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex sheets
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#include "vortexsheet.h"
+#include "solvana.h"
+
+using namespace std;
+namespace Manta {
+
+// *****************************************************************************
+// VorticityChannel class members
+
+// *****************************************************************************
+// VortexSheet Mesh class members
+
+VortexSheetMesh::VortexSheetMesh(FluidSolver *parent) : Mesh(parent), mTexOffset(0.0f)
+{
+ addTriChannel(&mVorticity);
+ addNodeChannel(&mTex1);
+ addNodeChannel(&mTex2);
+ addNodeChannel(&mTurb);
+}
+
+Mesh *VortexSheetMesh::clone()
+{
+ VortexSheetMesh *nm = new VortexSheetMesh(mParent);
+ *nm = *this;
+ nm->setName(getName());
+ return nm;
+}
+
+void VortexSheetMesh::calcVorticity()
+{
+ for (size_t tri = 0; tri < mTris.size(); tri++) {
+ VortexSheetInfo &v = mVorticity.data[tri];
+ Vec3 e0 = getEdge(tri, 0), e1 = getEdge(tri, 1), e2 = getEdge(tri, 2);
+ Real area = getFaceArea(tri);
+
+ if (area < 1e-10) {
+ v.smokeAmount = 0;
+ v.vorticity = 0;
+ }
+ else {
+ v.smokeAmount = 0;
+ v.vorticity = (v.circulation[0] * e0 + v.circulation[1] * e1 + v.circulation[2] * e2) / area;
+ }
+ }
+}
+
+void VortexSheetMesh::calcCirculation()
+{
+ for (size_t tri = 0; tri < mTris.size(); tri++) {
+ VortexSheetInfo &v = mVorticity.data[tri];
+ Vec3 e0 = getEdge(tri, 0), e1 = getEdge(tri, 1), e2 = getEdge(tri, 2);
+ Real area = getFaceArea(tri);
+
+ if (area < 1e-10 || normSquare(v.vorticity) < 1e-10) {
+ v.circulation = 0;
+ continue;
+ }
+
+ float cx, cy, cz;
+ SolveOverconstraint34(e0.x,
+ e0.y,
+ e0.z,
+ e1.x,
+ e1.y,
+ e1.z,
+ e2.x,
+ e2.y,
+ e2.z,
+ v.vorticity.x,
+ v.vorticity.y,
+ v.vorticity.z,
+ cx,
+ cy,
+ cz);
+ v.circulation = Vec3(cx, cy, cz) * area;
+ }
+}
+
+void VortexSheetMesh::resetTex1()
+{
+ for (size_t i = 0; i < mNodes.size(); i++)
+ mTex1.data[i] = mNodes[i].pos + mTexOffset;
+}
+
+void VortexSheetMesh::resetTex2()
+{
+ for (size_t i = 0; i < mNodes.size(); i++)
+ mTex2.data[i] = mNodes[i].pos + mTexOffset;
+}
+
+void VortexSheetMesh::reinitTexCoords()
+{
+ resetTex1();
+ resetTex2();
+}
+
+}; // namespace Manta
diff --git a/extern/mantaflow/preprocessed/vortexsheet.h b/extern/mantaflow/preprocessed/vortexsheet.h
new file mode 100644
index 00000000000..1fd53784f48
--- /dev/null
+++ b/extern/mantaflow/preprocessed/vortexsheet.h
@@ -0,0 +1,251 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex sheets
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#ifndef _VORTEXSHEET_H
+#define _VORTEXSHEET_H
+
+#include "mesh.h"
+
+namespace Manta {
+
+//! Stores vortex sheet info
+struct VortexSheetInfo {
+ VortexSheetInfo()
+ : vorticity(0.0),
+ vorticitySmoothed(0.0),
+ circulation(0.0),
+ smokeAmount(1.0),
+ smokeParticles(0.0)
+ {
+ }
+
+ Vec3 vorticity;
+ Vec3 vorticitySmoothed;
+ Vec3 circulation;
+ Real smokeAmount, smokeParticles;
+};
+
+//! Manages vortex sheet info
+struct VorticityChannel : public SimpleTriChannel<VortexSheetInfo> {
+ virtual TriChannel *clone()
+ {
+ VorticityChannel *vc = new VorticityChannel();
+ *vc = *this;
+ return vc;
+ }
+};
+
+//! Manages 3D texture coordinates
+struct TexCoord3Channel : public SimpleNodeChannel<Vec3> {
+ virtual NodeChannel *clone()
+ {
+ TexCoord3Channel *tc = new TexCoord3Channel();
+ *tc = *this;
+ return tc;
+ }
+
+ void addInterpol(int a, int b, Real alpha)
+ {
+ data.push_back((1.0 - alpha) * data[a] + alpha * data[b]);
+ }
+ void mergeWith(int node, int delnode, Real alpha)
+ {
+ data[node] = 0.5 * (data[node] + data[delnode]);
+ }
+};
+
+struct TurbulenceInfo {
+ TurbulenceInfo() : k(0.0), epsilon(0.0)
+ {
+ }
+ TurbulenceInfo(const TurbulenceInfo &a, const TurbulenceInfo &b, Real alpha)
+ : k((1.0 - alpha) * a.k + alpha * b.k),
+ epsilon((1.0 - alpha) * a.epsilon + alpha * b.epsilon)
+ {
+ }
+ Real k, epsilon;
+};
+
+//! Manages k-epsilon information
+struct TurbulenceChannel : public SimpleNodeChannel<TurbulenceInfo> {
+ virtual NodeChannel *clone()
+ {
+ TurbulenceChannel *tc = new TurbulenceChannel();
+ *tc = *this;
+ return tc;
+ }
+
+ void addInterpol(int a, int b, Real alpha)
+ {
+ data.push_back(TurbulenceInfo(data[a], data[b], alpha));
+ }
+ void mergeWith(int node, int delnode, Real alpha)
+ {
+ data[node] = TurbulenceInfo(data[node], data[delnode], 0.5);
+ }
+};
+
+//! Typed Mesh with a vorticity and 2 texcoord3 channels
+class VortexSheetMesh : public Mesh {
+ public:
+ VortexSheetMesh(FluidSolver *parent);
+ static int _W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ PbClass *obj = Pb::objFromPy(_self);
+ if (obj)
+ delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(0, "VortexSheetMesh::VortexSheetMesh", !noTiming);
+ {
+ ArgLocker _lock;
+ FluidSolver *parent = _args.getPtr<FluidSolver>("parent", 0, &_lock);
+ obj = new VortexSheetMesh(parent);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(), "VortexSheetMesh::VortexSheetMesh", !noTiming);
+ return 0;
+ }
+ catch (std::exception &e) {
+ pbSetError("VortexSheetMesh::VortexSheetMesh", e.what());
+ return -1;
+ }
+ }
+
+ virtual Mesh *clone();
+
+ virtual MeshType getType()
+ {
+ return TypeVortexSheet;
+ }
+
+ inline VortexSheetInfo &sheet(int i)
+ {
+ return mVorticity.data[i];
+ };
+ inline Vec3 &tex1(int i)
+ {
+ return mTex1.data[i];
+ }
+ inline Vec3 &tex2(int i)
+ {
+ return mTex2.data[i];
+ }
+ inline TurbulenceInfo &turb(int i)
+ {
+ return mTurb.data[i];
+ }
+ void setReferenceTexOffset(const Vec3 &ref)
+ {
+ mTexOffset = ref;
+ }
+ void resetTex1();
+ void resetTex2();
+
+ void calcCirculation();
+ static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ VortexSheetMesh *pbo = dynamic_cast<VortexSheetMesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::calcCirculation", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->calcCirculation();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "VortexSheetMesh::calcCirculation", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("VortexSheetMesh::calcCirculation", e.what());
+ return 0;
+ }
+ }
+
+ void calcVorticity();
+ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ VortexSheetMesh *pbo = dynamic_cast<VortexSheetMesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::calcVorticity", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->calcVorticity();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "VortexSheetMesh::calcVorticity", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("VortexSheetMesh::calcVorticity", e.what());
+ return 0;
+ }
+ }
+
+ void reinitTexCoords();
+ static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+ {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ VortexSheetMesh *pbo = dynamic_cast<VortexSheetMesh *>(Pb::objFromPy(_self));
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::reinitTexCoords", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ pbo->_args.copy(_args);
+ _retval = getPyNone();
+ pbo->reinitTexCoords();
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(), "VortexSheetMesh::reinitTexCoords", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("VortexSheetMesh::reinitTexCoords", e.what());
+ return 0;
+ }
+ }
+
+ protected:
+ Vec3 mTexOffset;
+ VorticityChannel mVorticity;
+ TexCoord3Channel mTex1, mTex2;
+ TurbulenceChannel mTurb;
+ public:
+ PbArgs _args;
+}
+#define _C_VortexSheetMesh
+;
+
+}; // namespace Manta
+
+#endif
diff --git a/extern/mantaflow/preprocessed/vortexsheet.h.reg.cpp b/extern/mantaflow/preprocessed/vortexsheet.h.reg.cpp
new file mode 100644
index 00000000000..c86f530f771
--- /dev/null
+++ b/extern/mantaflow/preprocessed/vortexsheet.h.reg.cpp
@@ -0,0 +1,26 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+#include "vortexsheet.h"
+namespace Manta {
+#ifdef _C_VortexSheetMesh
+static const Pb::Register _R_14("VortexSheetMesh", "VortexSheetMesh", "Mesh");
+template<> const char *Namify<VortexSheetMesh>::S = "VortexSheetMesh";
+static const Pb::Register _R_15("VortexSheetMesh", "VortexSheetMesh", VortexSheetMesh::_W_0);
+static const Pb::Register _R_16("VortexSheetMesh", "calcCirculation", VortexSheetMesh::_W_1);
+static const Pb::Register _R_17("VortexSheetMesh", "calcVorticity", VortexSheetMesh::_W_2);
+static const Pb::Register _R_18("VortexSheetMesh", "reinitTexCoords", VortexSheetMesh::_W_3);
+#endif
+extern "C" {
+void PbRegister_file_14()
+{
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+}
+}
+} // namespace Manta \ No newline at end of file
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt
index 7aa6d430906..b20b163a16a 100644
--- a/extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt
+++ b/extern/quadriflow/3rd/lemon-1.3.1/CMakeLists.txt
@@ -67,7 +67,7 @@ SET(LEMON_ENABLE_ILOG YES CACHE STRING "Enable ILOG (CPLEX) solver backend.")
SET(LEMON_ENABLE_COIN YES CACHE STRING "Enable COIN solver backend.")
SET(LEMON_ENABLE_SOPLEX YES CACHE STRING "Enable SoPlex solver backend.")
-IF(LEMON_ENABLE_GLPK)
+IF(LEMON_ENABLE_GLPK)
FIND_PACKAGE(GLPK 4.33)
ENDIF(LEMON_ENABLE_GLPK)
IF(LEMON_ENABLE_ILOG)
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake
index a09fc9a2753..584df4f6994 100644
--- a/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake
+++ b/extern/quadriflow/3rd/lemon-1.3.1/cmake/FindILOG.cmake
@@ -4,7 +4,7 @@ FIND_PATH(ILOG_ROOT_DIR
PATHS /opt/ibm/ILOG /usr/local/ibm/ILOG /usr/local/ILOG /usr/local/ilog
PATHS "$ENV{HOME}/ILOG" "$ENV{HOME}/.local/ILOG"
PATHS "$ENV{HOME}/ibm/ILOG" "$ENV{HOME}/.local/ibm/ILOG"
- PATHS "C:/Program Files/IBM/ILOG"
+ PATHS "C:/Program Files/IBM/ILOG"
PATH_SUFFIXES "CPLEX_Studio126" "CPLEX_Studio125"
"CPLEX_Studio124" "CPLEX_Studio123" "CPLEX_Studio122"
NO_DEFAULT_PATH
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt
index b6c11e2aad4..fd393bcc420 100644
--- a/extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt
+++ b/extern/quadriflow/3rd/lemon-1.3.1/contrib/CMakeLists.txt
@@ -16,4 +16,3 @@ LINK_DIRECTORIES(
# ADD_EXECUTABLE(myprog myprog-main.cc)
# TARGET_LINK_LIBRARIES(myprog lemon)
-
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt b/extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt
index 4e6567e49c7..f3501ca865b 100644
--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/CMakeLists.txt
@@ -88,4 +88,3 @@ INSTALL(
FILES ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc
DESTINATION lib/pkgconfig
)
-
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index e6b561c39b9..a5605e875a8 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -40,14 +40,6 @@ if(WITH_MOD_REMESH)
add_subdirectory(dualcon)
endif()
-if(WITH_MOD_FLUID)
- add_subdirectory(elbeem)
-endif()
-
-if(WITH_MOD_SMOKE)
- add_subdirectory(smoke)
-endif()
-
if(WITH_IK_SOLVER)
add_subdirectory(iksolver)
endif()
@@ -73,6 +65,10 @@ if(WIN32)
add_subdirectory(utfconv)
endif()
+if(WITH_MOD_FLUID)
+ add_subdirectory(mantaflow)
+endif()
+
if(WITH_OPENVDB)
add_subdirectory(openvdb)
endif()
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 013d86a560b..ee7ac7737c0 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -223,65 +223,95 @@ def system_info():
import _cycles
return _cycles.system_info()
-
-def register_passes(engine, scene, srl):
- engine.register_pass(scene, srl, "Combined", 4, "RGBA", 'COLOR')
-
- if srl.use_pass_z: engine.register_pass(scene, srl, "Depth", 1, "Z", 'VALUE')
- if srl.use_pass_mist: engine.register_pass(scene, srl, "Mist", 1, "Z", 'VALUE')
- if srl.use_pass_normal: engine.register_pass(scene, srl, "Normal", 3, "XYZ", 'VECTOR')
- if srl.use_pass_vector: engine.register_pass(scene, srl, "Vector", 4, "XYZW", 'VECTOR')
- if srl.use_pass_uv: engine.register_pass(scene, srl, "UV", 3, "UVA", 'VECTOR')
- if srl.use_pass_object_index: engine.register_pass(scene, srl, "IndexOB", 1, "X", 'VALUE')
- if srl.use_pass_material_index: engine.register_pass(scene, srl, "IndexMA", 1, "X", 'VALUE')
- if srl.use_pass_shadow: engine.register_pass(scene, srl, "Shadow", 3, "RGB", 'COLOR')
- if srl.use_pass_ambient_occlusion: engine.register_pass(scene, srl, "AO", 3, "RGB", 'COLOR')
- if srl.use_pass_diffuse_direct: engine.register_pass(scene, srl, "DiffDir", 3, "RGB", 'COLOR')
- if srl.use_pass_diffuse_indirect: engine.register_pass(scene, srl, "DiffInd", 3, "RGB", 'COLOR')
- if srl.use_pass_diffuse_color: engine.register_pass(scene, srl, "DiffCol", 3, "RGB", 'COLOR')
- if srl.use_pass_glossy_direct: engine.register_pass(scene, srl, "GlossDir", 3, "RGB", 'COLOR')
- if srl.use_pass_glossy_indirect: engine.register_pass(scene, srl, "GlossInd", 3, "RGB", 'COLOR')
- if srl.use_pass_glossy_color: engine.register_pass(scene, srl, "GlossCol", 3, "RGB", 'COLOR')
- if srl.use_pass_transmission_direct: engine.register_pass(scene, srl, "TransDir", 3, "RGB", 'COLOR')
- if srl.use_pass_transmission_indirect: engine.register_pass(scene, srl, "TransInd", 3, "RGB", 'COLOR')
- if srl.use_pass_transmission_color: engine.register_pass(scene, srl, "TransCol", 3, "RGB", 'COLOR')
- if srl.use_pass_subsurface_direct: engine.register_pass(scene, srl, "SubsurfaceDir", 3, "RGB", 'COLOR')
- if srl.use_pass_subsurface_indirect: engine.register_pass(scene, srl, "SubsurfaceInd", 3, "RGB", 'COLOR')
- if srl.use_pass_subsurface_color: engine.register_pass(scene, srl, "SubsurfaceCol", 3, "RGB", 'COLOR')
- if srl.use_pass_emit: engine.register_pass(scene, srl, "Emit", 3, "RGB", 'COLOR')
- if srl.use_pass_environment: engine.register_pass(scene, srl, "Env", 3, "RGB", 'COLOR')
-
+def list_render_passes(srl):
+ # Builtin Blender passes.
+ yield ("Combined", "RGBA", 'COLOR')
+
+ if srl.use_pass_z: yield ("Depth", "Z", 'VALUE')
+ if srl.use_pass_mist: yield ("Mist", "Z", 'VALUE')
+ if srl.use_pass_normal: yield ("Normal", "XYZ", 'VECTOR')
+ if srl.use_pass_vector: yield ("Vector", "XYZW", 'VECTOR')
+ if srl.use_pass_uv: yield ("UV", "UVA", 'VECTOR')
+ if srl.use_pass_object_index: yield ("IndexOB", "X", 'VALUE')
+ if srl.use_pass_material_index: yield ("IndexMA", "X", 'VALUE')
+ if srl.use_pass_shadow: yield ("Shadow", "RGB", 'COLOR')
+ if srl.use_pass_ambient_occlusion: yield ("AO", "RGB", 'COLOR')
+ if srl.use_pass_diffuse_direct: yield ("DiffDir", "RGB", 'COLOR')
+ if srl.use_pass_diffuse_indirect: yield ("DiffInd", "RGB", 'COLOR')
+ if srl.use_pass_diffuse_color: yield ("DiffCol", "RGB", 'COLOR')
+ if srl.use_pass_glossy_direct: yield ("GlossDir", "RGB", 'COLOR')
+ if srl.use_pass_glossy_indirect: yield ("GlossInd", "RGB", 'COLOR')
+ if srl.use_pass_glossy_color: yield ("GlossCol", "RGB", 'COLOR')
+ if srl.use_pass_transmission_direct: yield ("TransDir", "RGB", 'COLOR')
+ if srl.use_pass_transmission_indirect: yield ("TransInd", "RGB", 'COLOR')
+ if srl.use_pass_transmission_color: yield ("TransCol", "RGB", 'COLOR')
+ if srl.use_pass_subsurface_direct: yield ("SubsurfaceDir", "RGB", 'COLOR')
+ if srl.use_pass_subsurface_indirect: yield ("SubsurfaceInd", "RGB", 'COLOR')
+ if srl.use_pass_subsurface_color: yield ("SubsurfaceCol", "RGB", 'COLOR')
+ if srl.use_pass_emit: yield ("Emit", "RGB", 'COLOR')
+ if srl.use_pass_environment: yield ("Env", "RGB", 'COLOR')
+
+ # Cycles specific passes.
crl = srl.cycles
- if crl.pass_debug_render_time: engine.register_pass(scene, srl, "Debug Render Time", 1, "X", 'VALUE')
- if crl.pass_debug_bvh_traversed_nodes: engine.register_pass(scene, srl, "Debug BVH Traversed Nodes", 1, "X", 'VALUE')
- if crl.pass_debug_bvh_traversed_instances: engine.register_pass(scene, srl, "Debug BVH Traversed Instances", 1, "X", 'VALUE')
- if crl.pass_debug_bvh_intersections: engine.register_pass(scene, srl, "Debug BVH Intersections", 1, "X", 'VALUE')
- if crl.pass_debug_ray_bounces: engine.register_pass(scene, srl, "Debug Ray Bounces", 1, "X", 'VALUE')
- if crl.use_pass_volume_direct: engine.register_pass(scene, srl, "VolumeDir", 3, "RGB", 'COLOR')
- if crl.use_pass_volume_indirect: engine.register_pass(scene, srl, "VolumeInd", 3, "RGB", 'COLOR')
-
+ if crl.pass_debug_render_time: yield ("Debug Render Time", "X", 'VALUE')
+ if crl.pass_debug_bvh_traversed_nodes: yield ("Debug BVH Traversed Nodes", "X", 'VALUE')
+ if crl.pass_debug_bvh_traversed_instances: yield ("Debug BVH Traversed Instances", "X", 'VALUE')
+ if crl.pass_debug_bvh_intersections: yield ("Debug BVH Intersections", "X", 'VALUE')
+ if crl.pass_debug_ray_bounces: yield ("Debug Ray Bounces", "X", 'VALUE')
+ if crl.use_pass_volume_direct: yield ("VolumeDir", "RGB", 'COLOR')
+ if crl.use_pass_volume_indirect: yield ("VolumeInd", "RGB", 'COLOR')
+
+ # Cryptomatte passes.
if crl.use_pass_crypto_object:
for i in range(0, crl.pass_crypto_depth, 2):
- engine.register_pass(scene, srl, "CryptoObject" + '{:02d}'.format(i//2), 4, "RGBA", 'COLOR')
+ yield ("CryptoObject" + '{:02d}'.format(i//2), "RGBA", 'COLOR')
if crl.use_pass_crypto_material:
for i in range(0, crl.pass_crypto_depth, 2):
- engine.register_pass(scene, srl, "CryptoMaterial" + '{:02d}'.format(i//2), 4, "RGBA", 'COLOR')
+ yield ("CryptoMaterial" + '{:02d}'.format(i//2), "RGBA", 'COLOR')
if srl.cycles.use_pass_crypto_asset:
for i in range(0, srl.cycles.pass_crypto_depth, 2):
- engine.register_pass(scene, srl, "CryptoAsset" + '{:02d}'.format(i//2), 4, "RGBA", 'COLOR')
+ yield ("CryptoAsset" + '{:02d}'.format(i//2), "RGBA", 'COLOR')
+ # Denoising passes.
if crl.use_denoising or crl.denoising_store_passes:
- engine.register_pass(scene, srl, "Noisy Image", 4, "RGBA", 'COLOR')
+ yield ("Noisy Image", "RGBA", 'COLOR')
if crl.denoising_store_passes:
- engine.register_pass(scene, srl, "Denoising Normal", 3, "XYZ", 'VECTOR')
- engine.register_pass(scene, srl, "Denoising Albedo", 3, "RGB", 'COLOR')
- engine.register_pass(scene, srl, "Denoising Depth", 1, "Z", 'VALUE')
- engine.register_pass(scene, srl, "Denoising Shadowing", 1, "X", 'VALUE')
- engine.register_pass(scene, srl, "Denoising Variance", 3, "RGB", 'COLOR')
- engine.register_pass(scene, srl, "Denoising Intensity", 1, "X", 'VALUE')
+ yield ("Denoising Normal", "XYZ", 'VECTOR')
+ yield ("Denoising Albedo", "RGB", 'COLOR')
+ yield ("Denoising Depth", "Z", 'VALUE')
+ yield ("Denoising Shadowing", "X", 'VALUE')
+ yield ("Denoising Variance", "RGB", 'COLOR')
+ yield ("Denoising Intensity", "X", 'VALUE')
clean_options = ("denoising_diffuse_direct", "denoising_diffuse_indirect",
"denoising_glossy_direct", "denoising_glossy_indirect",
"denoising_transmission_direct", "denoising_transmission_indirect",
"denoising_subsurface_direct", "denoising_subsurface_indirect")
if any(getattr(crl, option) for option in clean_options):
- engine.register_pass(scene, srl, "Denoising Clean", 3, "RGB", 'COLOR')
+ yield ("Denoising Clean", "RGB", 'COLOR')
+
+ # Custom AOV passes.
+ for aov in crl.aovs:
+ if aov.type == 'VALUE':
+ yield (aov.name, "X", 'VALUE')
+ else:
+ yield (aov.name, "RGBA", 'COLOR')
+
+def register_passes(engine, scene, view_layer):
+ # Detect duplicate render pass names, first one wins.
+ listed = set()
+ for name, channelids, channeltype in list_render_passes(view_layer):
+ if name not in listed:
+ engine.register_pass(scene, view_layer, name, len(channelids), channelids, channeltype)
+ listed.add(name)
+
+def detect_conflicting_passes(view_layer):
+ # Detect conflicting render pass names for UI.
+ counter = {}
+ for name, _, _ in list_render_passes(view_layer):
+ counter[name] = counter.get(name, 0) + 1
+
+ for aov in view_layer.cycles.aovs:
+ if counter[aov.name] > 1:
+ aov.conflict = "Conflicts with another render pass with the same name"
+ else:
+ aov.conflict = ""
diff --git a/intern/cycles/blender/addon/operators.py b/intern/cycles/blender/addon/operators.py
index e75d3ab7549..80bb663330b 100644
--- a/intern/cycles/blender/addon/operators.py
+++ b/intern/cycles/blender/addon/operators.py
@@ -44,6 +44,36 @@ class CYCLES_OT_use_shading_nodes(Operator):
return {'FINISHED'}
+class CYCLES_OT_add_aov(bpy.types.Operator):
+ """Add an AOV pass"""
+ bl_idname="cycles.add_aov"
+ bl_label="Add AOV"
+
+ def execute(self, context):
+ view_layer = context.view_layer
+ cycles_view_layer = view_layer.cycles
+
+ cycles_view_layer.aovs.add()
+
+ view_layer.update_render_passes()
+ return {'FINISHED'}
+
+
+class CYCLES_OT_remove_aov(bpy.types.Operator):
+ """Remove an AOV pass"""
+ bl_idname="cycles.remove_aov"
+ bl_label="Remove AOV"
+
+ def execute(self, context):
+ view_layer = context.view_layer
+ cycles_view_layer = view_layer.cycles
+
+ cycles_view_layer.aovs.remove(cycles_view_layer.active_aov)
+
+ view_layer.update_render_passes()
+ return {'FINISHED'}
+
+
class CYCLES_OT_denoise_animation(Operator):
"Denoise rendered animation sequence using current scene and view " \
"layer settings. Requires denoising data passes and output to " \
@@ -167,6 +197,8 @@ class CYCLES_OT_merge_images(Operator):
classes = (
CYCLES_OT_use_shading_nodes,
+ CYCLES_OT_add_aov,
+ CYCLES_OT_remove_aov,
CYCLES_OT_denoise_animation,
CYCLES_OT_merge_images
)
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 26e1a6a223a..e09f15b46e8 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -19,6 +19,7 @@
import bpy
from bpy.props import (
BoolProperty,
+ CollectionProperty,
EnumProperty,
FloatProperty,
IntProperty,
@@ -31,6 +32,7 @@ from math import pi
# enums
import _cycles
+from . import engine
enum_devices = (
('CPU', "CPU", "Use CPU for rendering"),
@@ -190,6 +192,10 @@ enum_view3d_shading_render_pass= (
('MIST', "Mist", "Show the Mist render pass", 32),
)
+enum_aov_types = (
+ ('VALUE', "Value", "Write a Value pass", 0),
+ ('COLOR', "Color", "Write a Color pass", 1),
+)
class CyclesRenderSettings(bpy.types.PropertyGroup):
@@ -1218,8 +1224,29 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
def update_render_passes(self, context):
view_layer = context.view_layer
view_layer.update_render_passes()
+ engine.detect_conflicting_passes(view_layer)
+class CyclesAOVPass(bpy.types.PropertyGroup):
+ name: StringProperty(
+ name="Name",
+ description="Name of the pass, to use in the AOV Output shader node",
+ update=update_render_passes,
+ default="AOV"
+ )
+ type: EnumProperty(
+ name="Type",
+ description="Pass data type",
+ update=update_render_passes,
+ items=enum_aov_types,
+ default='COLOR'
+ )
+ conflict: StringProperty(
+ name="Conflict",
+ description="If there is a conflict with another render passes, message explaining why",
+ default=""
+ )
+
class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
pass_debug_bvh_traversed_nodes: BoolProperty(
@@ -1378,6 +1405,15 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
update=update_render_passes,
)
+ aovs: CollectionProperty(
+ type=CyclesAOVPass,
+ description="Custom render passes that can be output by shader nodes",
+ )
+ active_aov: IntProperty(
+ default=0,
+ min=0
+ )
+
@classmethod
def register(cls):
bpy.types.ViewLayer.cycles = PointerProperty(
@@ -1552,6 +1588,7 @@ def register():
bpy.utils.register_class(CyclesCurveRenderSettings)
bpy.utils.register_class(CyclesDeviceSettings)
bpy.utils.register_class(CyclesPreferences)
+ bpy.utils.register_class(CyclesAOVPass)
bpy.utils.register_class(CyclesRenderLayerSettings)
bpy.utils.register_class(CyclesView3DShadingSettings)
@@ -1573,5 +1610,6 @@ def unregister():
bpy.utils.unregister_class(CyclesCurveRenderSettings)
bpy.utils.unregister_class(CyclesDeviceSettings)
bpy.utils.unregister_class(CyclesPreferences)
+ bpy.utils.unregister_class(CyclesAOVPass)
bpy.utils.unregister_class(CyclesRenderLayerSettings)
bpy.utils.unregister_class(CyclesView3DShadingSettings)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 4ff154d4bcd..c4182ba564a 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -918,6 +918,42 @@ class CYCLES_RENDER_PT_passes_debug(CyclesButtonsPanel, Panel):
layout.prop(cycles_view_layer, "pass_debug_ray_bounces")
+class CYCLES_RENDER_UL_aov(bpy.types.UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+ row = layout.row()
+ split = row.split(factor=0.65)
+ icon = 'ERROR' if item.conflict else 'NONE'
+ split.row().prop(item, "name", text="", icon=icon, emboss=False)
+ split.row().prop(item, "type", text="", emboss=False)
+
+
+class CYCLES_RENDER_PT_passes_aov(CyclesButtonsPanel, Panel):
+ bl_label = "Shader AOV"
+ bl_context = "view_layer"
+ bl_parent_id = "CYCLES_RENDER_PT_passes"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ cycles_view_layer = context.view_layer.cycles
+
+ row = layout.row()
+ col = row.column()
+ col.template_list("CYCLES_RENDER_UL_aov", "aovs", cycles_view_layer, "aovs", cycles_view_layer, "active_aov", rows=2)
+
+ col = row.column()
+ sub = col.column(align=True)
+ sub.operator("cycles.add_aov", icon='ADD', text="")
+ sub.operator("cycles.remove_aov", icon='REMOVE', text="")
+
+ if cycles_view_layer.active_aov < len(cycles_view_layer.aovs):
+ active_aov = cycles_view_layer.aovs[cycles_view_layer.active_aov]
+ if active_aov.conflict:
+ layout.label(text=active_aov.conflict, icon='ERROR')
+
+
class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
bl_label = "Denoising"
bl_context = "view_layer"
@@ -1913,7 +1949,7 @@ class CYCLES_RENDER_PT_bake_output(CyclesButtonsPanel, Panel):
layout.prop(rd, "use_bake_clear", text="Clear Image")
if rd.bake_type == 'DISPLACEMENT':
- col.prop(rd, "use_bake_lores_mesh")
+ layout.prop(rd, "use_bake_lores_mesh")
else:
layout.prop(cbk, "margin")
@@ -2233,6 +2269,8 @@ classes = (
CYCLES_RENDER_PT_passes_light,
CYCLES_RENDER_PT_passes_crypto,
CYCLES_RENDER_PT_passes_debug,
+ CYCLES_RENDER_UL_aov,
+ CYCLES_RENDER_PT_passes_aov,
CYCLES_RENDER_PT_filter,
CYCLES_RENDER_PT_override,
CYCLES_RENDER_PT_denoising,
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 5c28404e745..b18f9a37948 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -283,7 +283,7 @@ static void mikk_compute_tangents(
static void create_mesh_volume_attribute(
BL::Object &b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std, float frame)
{
- BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
+ BL::FluidDomainSettings b_domain = object_fluid_domain_find(b_ob);
if (!b_domain)
return;
@@ -930,13 +930,13 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
if (scene->need_motion() == Scene::MOTION_NONE)
return;
- BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob);
+ BL::FluidDomainSettings b_fluid_domain = object_fluid_domain_find(b_ob);
if (!b_fluid_domain)
return;
/* If the mesh has modifiers following the fluid domain we can't export motion. */
- if (b_fluid_domain.fluid_mesh_vertices.length() != mesh->verts.size())
+ if (b_fluid_domain.mesh_vertices.length() != mesh->verts.size())
return;
/* Find or add attribute */
@@ -953,13 +953,12 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f;
float3 *mP = attr_mP->data_float3() + step * mesh->verts.size();
- BL::DomainFluidSettings::fluid_mesh_vertices_iterator fvi;
+ BL::FluidDomainSettings::mesh_vertices_iterator svi;
int i = 0;
- for (b_fluid_domain.fluid_mesh_vertices.begin(fvi);
- fvi != b_fluid_domain.fluid_mesh_vertices.end();
- ++fvi, ++i) {
- mP[i] = P[i] + get_float3(fvi->velocity()) * relative_time;
+ for (b_fluid_domain.mesh_vertices.begin(svi); svi != b_fluid_domain.mesh_vertices.end();
+ ++svi, ++i) {
+ mP[i] = P[i] + get_float3(svi->velocity()) * relative_time;
}
}
}
@@ -1099,7 +1098,7 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
}
mesh->geometry_flags = requested_geometry_flags;
- /* fluid motion */
+ /* mesh fluid motion mantaflow */
sync_mesh_fluid_motion(b_ob, scene, mesh);
/* tag update */
@@ -1148,8 +1147,8 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph &b_depsgraph,
* would need a more extensive check to see which objects are animated */
BL::Mesh b_mesh(PointerRNA_NULL);
- /* fluid motion is exported immediate with mesh, skip here */
- BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob);
+ /* manta motion is exported immediate with mesh, skip here */
+ BL::FluidDomainSettings b_fluid_domain = object_fluid_domain_find(b_ob);
if (b_fluid_domain)
return;
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 1f0816a6edb..26b04babce2 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -142,9 +142,9 @@ void BlenderSession::create_session()
scene->image_manager->builtin_image_info_cb = function_bind(
&BlenderSession::builtin_image_info, this, _1, _2, _3);
scene->image_manager->builtin_image_pixels_cb = function_bind(
- &BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4, _5, _6);
+ &BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4, _5, _6, _7);
scene->image_manager->builtin_image_float_pixels_cb = function_bind(
- &BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4, _5, _6);
+ &BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4, _5, _6, _7);
session->scene = scene;
@@ -793,18 +793,13 @@ void BlenderSession::do_write_update_render_result(BL::RenderLayer &b_rlay,
for (b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
BL::RenderPass b_pass(*b_iter);
-
- /* find matching pass type */
- PassType pass_type = BlenderSync::get_pass_type(b_pass);
int components = b_pass.channels();
- bool read = false;
- if (pass_type != PASS_NONE) {
- /* copy pixels */
- read = buffers->get_pass_rect(
- pass_type, exposure, sample, components, &pixels[0], b_pass.name());
- }
- else {
+ /* Copy pixels from regular render passes. */
+ bool read = buffers->get_pass_rect(b_pass.name(), exposure, sample, components, &pixels[0]);
+
+ /* If denoising pass, */
+ if (!read) {
int denoising_offset = BlenderSync::get_denoising_pass(b_pass);
if (denoising_offset >= 0) {
read = buffers->get_denoising_pass_rect(
@@ -822,7 +817,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderLayer &b_rlay,
else {
/* copy combined pass */
BL::RenderPass b_combined_pass(b_rlay.passes.find_by_name("Combined", b_rview_name.c_str()));
- if (buffers->get_pass_rect(PASS_COMBINED, exposure, sample, 4, &pixels[0], "Combined"))
+ if (buffers->get_pass_rect("Combined", exposure, sample, 4, &pixels[0]))
b_combined_pass.rect(&pixels[0]);
}
}
@@ -1163,7 +1158,7 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
else if (b_id.is_a(&RNA_Object)) {
/* smoke volume data */
BL::Object b_ob(b_id);
- BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
+ BL::FluidDomainSettings b_domain = object_fluid_domain_find(b_ob);
metadata.is_float = true;
metadata.depth = 1;
@@ -1185,7 +1180,7 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
return;
int3 resolution = get_int3(b_domain.domain_resolution());
- int amplify = (b_domain.use_high_resolution()) ? b_domain.amplify() + 1 : 1;
+ int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
/* Velocity and heat data is always low-resolution. */
if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
@@ -1215,6 +1210,7 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
bool BlenderSession::builtin_image_pixels(const string &builtin_name,
void *builtin_data,
+ int tile,
unsigned char *pixels,
const size_t pixels_size,
const bool associate_alpha,
@@ -1234,7 +1230,7 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name,
const int height = b_image.size()[1];
const int channels = b_image.channels();
- unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame);
+ unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile);
const size_t num_pixels = ((size_t)width) * height;
if (image_pixels && num_pixels * channels == pixels_size) {
@@ -1281,6 +1277,7 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name,
bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
void *builtin_data,
+ int tile,
float *pixels,
const size_t pixels_size,
const bool,
@@ -1304,7 +1301,7 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
const int channels = b_image.channels();
float *image_pixels;
- image_pixels = image_get_float_pixels_for_frame(b_image, frame);
+ image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile);
const size_t num_pixels = ((size_t)width) * height;
if (image_pixels && num_pixels * channels == pixels_size) {
@@ -1342,14 +1339,14 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
else if (b_id.is_a(&RNA_Object)) {
/* smoke volume data */
BL::Object b_ob(b_id);
- BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
+ BL::FluidDomainSettings b_domain = object_fluid_domain_find(b_ob);
if (!b_domain) {
return false;
}
int3 resolution = get_int3(b_domain.domain_resolution());
- int length, amplify = (b_domain.use_high_resolution()) ? b_domain.amplify() + 1 : 1;
+ int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
/* Velocity and heat data is always low-resolution. */
if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
@@ -1363,47 +1360,47 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
const size_t num_pixels = ((size_t)width) * height * depth;
if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
- SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
+ FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels) {
- SmokeDomainSettings_density_grid_get(&b_domain.ptr, pixels);
+ FluidDomainSettings_density_grid_get(&b_domain.ptr, pixels);
return true;
}
}
else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) {
/* this is in range 0..1, and interpreted by the OpenGL smoke viewer
* as 1500..3000 K with the first part faded to zero density */
- SmokeDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
+ FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels) {
- SmokeDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
+ FluidDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
return true;
}
}
else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
/* the RGB is "premultiplied" by density for better interpolation results */
- SmokeDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
+ FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels * 4) {
- SmokeDomainSettings_color_grid_get(&b_domain.ptr, pixels);
+ FluidDomainSettings_color_grid_get(&b_domain.ptr, pixels);
return true;
}
}
else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) {
- SmokeDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
+ FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels * 3) {
- SmokeDomainSettings_velocity_grid_get(&b_domain.ptr, pixels);
+ FluidDomainSettings_velocity_grid_get(&b_domain.ptr, pixels);
return true;
}
}
else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
- SmokeDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
+ FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels) {
- SmokeDomainSettings_heat_grid_get(&b_domain.ptr, pixels);
+ FluidDomainSettings_heat_grid_get(&b_domain.ptr, pixels);
return true;
}
}
else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) {
- SmokeDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
+ FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels) {
- SmokeDomainSettings_temperature_grid_get(&b_domain.ptr, pixels);
+ FluidDomainSettings_temperature_grid_get(&b_domain.ptr, pixels);
return true;
}
}
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index 7445fb53458..2f25ec740f9 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -157,12 +157,14 @@ class BlenderSession {
void builtin_image_info(const string &builtin_name, void *builtin_data, ImageMetaData &metadata);
bool builtin_image_pixels(const string &builtin_name,
void *builtin_data,
+ int tile,
unsigned char *pixels,
const size_t pixels_size,
const bool associate_alpha,
const bool free_cache);
bool builtin_image_float_pixels(const string &builtin_name,
void *builtin_data,
+ int tile,
float *pixels,
const size_t pixels_size,
const bool associate_alpha,
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 22dbc3fba79..206058259af 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -301,10 +301,14 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeMapRange b_map_range_node(b_node);
MapRangeNode *map_range_node = new MapRangeNode();
map_range_node->clamp = b_map_range_node.clamp();
+ map_range_node->type = (NodeMapRangeType)b_map_range_node.interpolation_type();
node = map_range_node;
}
else if (b_node.is_a(&RNA_ShaderNodeClamp)) {
- node = new ClampNode();
+ BL::ShaderNodeClamp b_clamp_node(b_node);
+ ClampNode *clamp_node = new ClampNode();
+ clamp_node->type = (NodeClampType)b_clamp_node.clamp_type();
+ node = clamp_node;
}
else if (b_node.is_a(&RNA_ShaderNodeMath)) {
BL::ShaderNodeMath b_math_node(b_node);
@@ -651,7 +655,8 @@ static ShaderNode *add_node(Scene *scene,
image->builtin_data = b_image.ptr.data;
}
else {
- image->filename = image_user_file_path(b_image_user, b_image, b_scene.frame_current());
+ image->filename = image_user_file_path(
+ b_image_user, b_image, b_scene.frame_current(), true);
image->builtin_data = NULL;
}
@@ -661,6 +666,12 @@ static ShaderNode *add_node(Scene *scene,
image->animated = b_image_node.image_user().use_auto_refresh();
image->alpha_type = get_image_alpha_type(b_image);
+ image->tiles.clear();
+ BL::Image::tiles_iterator b_iter;
+ for (b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) {
+ image->tiles.push_back(b_iter->number());
+ }
+
/* TODO: restore */
/* TODO(sergey): Does not work properly when we change builtin type. */
#if 0
@@ -699,7 +710,8 @@ static ShaderNode *add_node(Scene *scene,
env->builtin_data = b_image.ptr.data;
}
else {
- env->filename = image_user_file_path(b_image_user, b_image, b_scene.frame_current());
+ env->filename = image_user_file_path(
+ b_image_user, b_image, b_scene.frame_current(), false);
env->builtin_data = NULL;
}
@@ -917,6 +929,12 @@ static ShaderNode *add_node(Scene *scene,
disp->attribute = "";
node = disp;
}
+ else if (b_node.is_a(&RNA_ShaderNodeOutputAOV)) {
+ BL::ShaderNodeOutputAOV b_aov_node(b_node);
+ OutputAOVNode *aov = new OutputAOVNode();
+ aov->name = b_aov_node.name();
+ node = aov;
+ }
if (node) {
node->name = b_node.name();
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index f04455ff75e..332ee3575c0 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -531,7 +531,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLa
if (pass_type == PASS_MOTION && scene->integrator->motion_blur)
continue;
if (pass_type != PASS_NONE)
- Pass::add(pass_type, passes);
+ Pass::add(pass_type, passes, b_pass.name().c_str());
}
PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles");
@@ -570,32 +570,32 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLa
#ifdef __KERNEL_DEBUG__
if (get_boolean(crp, "pass_debug_bvh_traversed_nodes")) {
b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str());
- Pass::add(PASS_BVH_TRAVERSED_NODES, passes);
+ Pass::add(PASS_BVH_TRAVERSED_NODES, passes, "Debug BVH Traversed Nodes");
}
if (get_boolean(crp, "pass_debug_bvh_traversed_instances")) {
b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_view_layer.name().c_str());
- Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes);
+ Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes, "Debug BVH Traversed Instances");
}
if (get_boolean(crp, "pass_debug_bvh_intersections")) {
b_engine.add_pass("Debug BVH Intersections", 1, "X", b_view_layer.name().c_str());
- Pass::add(PASS_BVH_INTERSECTIONS, passes);
+ Pass::add(PASS_BVH_INTERSECTIONS, passes, "Debug BVH Intersections");
}
if (get_boolean(crp, "pass_debug_ray_bounces")) {
b_engine.add_pass("Debug Ray Bounces", 1, "X", b_view_layer.name().c_str());
- Pass::add(PASS_RAY_BOUNCES, passes);
+ Pass::add(PASS_RAY_BOUNCES, passes, "Debug Ray Bounces");
}
#endif
if (get_boolean(crp, "pass_debug_render_time")) {
b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str());
- Pass::add(PASS_RENDER_TIME, passes);
+ Pass::add(PASS_RENDER_TIME, passes, "Debug Render Time");
}
if (get_boolean(crp, "use_pass_volume_direct")) {
b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str());
- Pass::add(PASS_VOLUME_DIRECT, passes);
+ Pass::add(PASS_VOLUME_DIRECT, passes, "VolumeDir");
}
if (get_boolean(crp, "use_pass_volume_indirect")) {
b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str());
- Pass::add(PASS_VOLUME_INDIRECT, passes);
+ Pass::add(PASS_VOLUME_INDIRECT, passes, "VolumeInd");
}
/* Cryptomatte stores two ID/weight pairs per RGBA layer.
@@ -635,6 +635,21 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLa
CRYPT_ACCURATE);
}
+ RNA_BEGIN (&crp, b_aov, "aovs") {
+ bool is_color = (get_enum(b_aov, "type") == 1);
+ string name = get_string(b_aov, "name");
+
+ if (is_color) {
+ b_engine.add_pass(name.c_str(), 4, "RGBA", b_view_layer.name().c_str());
+ Pass::add(PASS_AOV_COLOR, passes, name.c_str());
+ }
+ else {
+ b_engine.add_pass(name.c_str(), 1, "X", b_view_layer.name().c_str());
+ Pass::add(PASS_AOV_VALUE, passes, name.c_str());
+ }
+ }
+ RNA_END;
+
return passes;
}
@@ -714,6 +729,9 @@ SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background)
params.bvh_layout = RNA_boolean_get(&cscene, "use_bvh_embree") ? BVH_LAYOUT_EMBREE :
params.bvh_layout;
#endif
+
+ params.background = background;
+
return params;
}
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 3625dd45ae2..bea30a20b8c 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -34,8 +34,8 @@
extern "C" {
void BKE_image_user_frame_calc(void *ima, void *iuser, int cfra);
void BKE_image_user_file_path(void *iuser, void *ima, char *path);
-unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame);
-float *BKE_image_get_float_pixels_for_frame(void *image, int frame);
+unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame, int tile);
+float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
}
CCL_NAMESPACE_BEGIN
@@ -159,7 +159,7 @@ static inline void curvemapping_to_array(BL::CurveMapping &cumap, array<float> &
data.resize(size);
for (int i = 0; i < size; i++) {
float t = (float)i / (float)(size - 1);
- data[i] = curve.evaluate(t);
+ data[i] = cumap.evaluate(curve, t);
}
}
@@ -197,15 +197,16 @@ static inline void curvemapping_color_to_array(BL::CurveMapping &cumap,
BL::CurveMap mapI = cumap.curves[3];
for (int i = 0; i < size; i++) {
const float t = min_x + (float)i / (float)(size - 1) * range_x;
- data[i] = make_float3(mapR.evaluate(mapI.evaluate(t)),
- mapG.evaluate(mapI.evaluate(t)),
- mapB.evaluate(mapI.evaluate(t)));
+ data[i] = make_float3(cumap.evaluate(mapR, cumap.evaluate(mapI, t)),
+ cumap.evaluate(mapG, cumap.evaluate(mapI, t)),
+ cumap.evaluate(mapB, cumap.evaluate(mapI, t)));
}
}
else {
for (int i = 0; i < size; i++) {
float t = min_x + (float)i / (float)(size - 1) * range_x;
- data[i] = make_float3(mapR.evaluate(t), mapG.evaluate(t), mapB.evaluate(t));
+ data[i] = make_float3(
+ cumap.evaluate(mapR, t), cumap.evaluate(mapG, t), cumap.evaluate(mapB, t));
}
}
}
@@ -230,12 +231,21 @@ static inline int render_resolution_y(BL::RenderSettings &b_render)
return b_render.resolution_y() * b_render.resolution_percentage() / 100;
}
-static inline string image_user_file_path(BL::ImageUser &iuser, BL::Image &ima, int cfra)
+static inline string image_user_file_path(BL::ImageUser &iuser,
+ BL::Image &ima,
+ int cfra,
+ bool load_tiled)
{
char filepath[1024];
+ iuser.tile(0);
BKE_image_user_frame_calc(NULL, iuser.ptr.data, cfra);
BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath);
- return string(filepath);
+
+ string filepath_str = string(filepath);
+ if (load_tiled && ima.source() == BL::Image::source_TILED) {
+ string_replace(filepath_str, "1001", "<UDIM>");
+ }
+ return filepath_str;
}
static inline int image_user_frame_number(BL::ImageUser &iuser, int cfra)
@@ -244,14 +254,14 @@ static inline int image_user_frame_number(BL::ImageUser &iuser, int cfra)
return iuser.frame_current();
}
-static inline unsigned char *image_get_pixels_for_frame(BL::Image &image, int frame)
+static inline unsigned char *image_get_pixels_for_frame(BL::Image &image, int frame, int tile)
{
- return BKE_image_get_pixels_for_frame(image.ptr.data, frame);
+ return BKE_image_get_pixels_for_frame(image.ptr.data, frame, tile);
}
-static inline float *image_get_float_pixels_for_frame(BL::Image &image, int frame)
+static inline float *image_get_float_pixels_for_frame(BL::Image &image, int frame, int tile)
{
- return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame);
+ return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame, tile);
}
static inline void render_add_metadata(BL::RenderResult &b_rr, string name, string value)
@@ -521,37 +531,20 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_
return use_deform_motion;
}
-static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object &b_ob)
-{
- BL::Object::modifiers_iterator b_mod;
-
- for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
- if (b_mod->is_a(&RNA_SmokeModifier)) {
- BL::SmokeModifier b_smd(*b_mod);
-
- if (b_smd.smoke_type() == BL::SmokeModifier::smoke_type_DOMAIN)
- return b_smd.domain_settings();
- }
- }
-
- return BL::SmokeDomainSettings(PointerRNA_NULL);
-}
-
-static inline BL::DomainFluidSettings object_fluid_domain_find(BL::Object b_ob)
+static inline BL::FluidDomainSettings object_fluid_domain_find(BL::Object &b_ob)
{
BL::Object::modifiers_iterator b_mod;
for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
- if (b_mod->is_a(&RNA_FluidSimulationModifier)) {
- BL::FluidSimulationModifier b_fmd(*b_mod);
- BL::FluidSettings fss = b_fmd.settings();
+ if (b_mod->is_a(&RNA_FluidModifier)) {
+ BL::FluidModifier b_mmd(*b_mod);
- if (fss.type() == BL::FluidSettings::type_DOMAIN)
- return (BL::DomainFluidSettings)b_fmd.settings();
+ if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN)
+ return b_mmd.domain_settings();
}
}
- return BL::DomainFluidSettings(PointerRNA_NULL);
+ return BL::FluidDomainSettings(PointerRNA_NULL);
}
static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp
index b3a9aab3266..86d755ab06a 100644
--- a/intern/cycles/bvh/bvh_optix.cpp
+++ b/intern/cycles/bvh/bvh_optix.cpp
@@ -49,7 +49,7 @@ void BVHOptiX::copy_to_device(Progress &progress, DeviceScene *dscene)
progress.set_status("Updating Scene BVH", "Building OptiX acceleration structure");
Device *const device = dscene->bvh_nodes.device;
- if (!device->build_optix_bvh(this, dscene->bvh_nodes))
+ if (!device->build_optix_bvh(this))
progress.set_error("Failed to build OptiX acceleration structure");
}
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 672d93c2581..66fcac921d3 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -407,7 +407,7 @@ class Device {
const DeviceDrawParams &draw_params);
/* acceleration structure building */
- virtual bool build_optix_bvh(BVH *, device_memory &)
+ virtual bool build_optix_bvh(BVH *)
{
return false;
}
diff --git a/intern/cycles/device/device_memory.cpp b/intern/cycles/device/device_memory.cpp
index c106b4505db..3a99a49dffc 100644
--- a/intern/cycles/device/device_memory.cpp
+++ b/intern/cycles/device/device_memory.cpp
@@ -47,31 +47,6 @@ device_memory::~device_memory()
assert(shared_counter == 0);
}
-device_memory::device_memory(device_memory &&other)
- : data_type(other.data_type),
- data_elements(other.data_elements),
- data_size(other.data_size),
- device_size(other.device_size),
- data_width(other.data_width),
- data_height(other.data_height),
- data_depth(other.data_depth),
- type(other.type),
- name(other.name),
- interpolation(other.interpolation),
- extension(other.extension),
- device(other.device),
- device_pointer(other.device_pointer),
- host_pointer(other.host_pointer),
- shared_pointer(other.shared_pointer),
- shared_counter(other.shared_counter)
-{
- other.device_size = 0;
- other.device_pointer = 0;
- other.host_pointer = 0;
- other.shared_pointer = 0;
- other.shared_counter = 0;
-}
-
void *device_memory::host_alloc(size_t size)
{
if (!size) {
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
index f8324e2a214..60740807568 100644
--- a/intern/cycles/device/device_memory.h
+++ b/intern/cycles/device/device_memory.h
@@ -235,9 +235,6 @@ class device_memory {
device_memory(const device_memory &) = delete;
device_memory &operator=(const device_memory &) = delete;
- /* But moving is possible. */
- device_memory(device_memory &&);
-
/* Host allocation on the device. All host_pointer memory should be
* allocated with these functions, for devices that support using
* the same pointer for host and device. */
@@ -275,11 +272,6 @@ template<typename T> class device_only_memory : public device_memory {
free();
}
- device_only_memory(device_only_memory &&other)
- : device_memory(static_cast<device_memory &&>(other))
- {
- }
-
void alloc_to_device(size_t num, bool shrink_to_fit = true)
{
size_t new_size = num;
@@ -338,10 +330,6 @@ template<typename T> class device_vector : public device_memory {
free();
}
- device_vector(device_vector &&other) : device_memory(static_cast<device_memory &&>(other))
- {
- }
-
/* Host memory allocation. */
T *alloc(size_t width, size_t height = 0, size_t depth = 0)
{
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index ac71be9dbea..b8587eb0a62 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -153,21 +153,13 @@ class MultiDevice : public Device {
return result;
}
- bool build_optix_bvh(BVH *bvh, device_memory &mem)
+ bool build_optix_bvh(BVH *bvh)
{
- device_ptr key = unique_key++;
-
// Broadcast acceleration structure build to all devices
foreach (SubDevice &sub, devices) {
- mem.device = sub.device;
- if (!sub.device->build_optix_bvh(bvh, mem))
+ if (!sub.device->build_optix_bvh(bvh))
return false;
- sub.ptr_map[key] = mem.device_pointer;
}
-
- mem.device = this;
- mem.device_pointer = key;
- stats.mem_alloc(mem.device_size);
return true;
}
diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
index e10bab5a0d8..7335e0bc64d 100644
--- a/intern/cycles/device/device_optix.cpp
+++ b/intern/cycles/device/device_optix.cpp
@@ -174,7 +174,7 @@ class OptiXDevice : public Device {
device_vector<SbtRecord> sbt_data;
device_vector<TextureInfo> texture_info;
device_only_memory<KernelParams> launch_params;
- vector<device_only_memory<uint8_t>> blas;
+ vector<CUdeviceptr> as_mem;
OptixTraversableHandle tlas_handle = 0;
// TODO(pmours): This is copied from device_cuda.cpp, so move to common code eventually
@@ -268,8 +268,11 @@ class OptiXDevice : public Device {
// Stop processing any more tasks
task_pool.stop();
- // Clean up all memory before destroying context
- blas.clear();
+ // Free all acceleration structures
+ for (CUdeviceptr mem : as_mem) {
+ cuMemFree(mem);
+ }
+ as_mem.clear();
sbt_data.free();
texture_info.free();
@@ -290,8 +293,8 @@ class OptiXDevice : public Device {
optixPipelineDestroy(pipelines[i]);
// Destroy launch streams
- for (int i = 0; i < info.cpu_threads; ++i)
- cuStreamDestroy(cuda_stream[i]);
+ for (CUstream stream : cuda_stream)
+ cuStreamDestroy(stream);
// Destroy OptiX and CUDA context
optixDeviceContextDestroy(context);
@@ -831,7 +834,6 @@ class OptiXDevice : public Device {
bool build_optix_bvh(const OptixBuildInput &build_input,
uint16_t num_motion_steps,
- device_memory &out_data,
OptixTraversableHandle &out_handle)
{
out_handle = 0;
@@ -842,7 +844,15 @@ class OptiXDevice : public Device {
OptixAccelBufferSizes sizes = {};
OptixAccelBuildOptions options;
options.operation = OPTIX_BUILD_OPERATION_BUILD;
- options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE;
+ if (background) {
+ // Prefer best performance and lowest memory consumption in background
+ options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE | OPTIX_BUILD_FLAG_ALLOW_COMPACTION;
+ }
+ else {
+ // Prefer fast updates in viewport
+ options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_BUILD;
+ }
+
options.motionOptions.numKeys = num_motion_steps;
options.motionOptions.flags = OPTIX_MOTION_FLAG_START_VANISH | OPTIX_MOTION_FLAG_END_VANISH;
options.motionOptions.timeBegin = 0.0f;
@@ -853,43 +863,91 @@ class OptiXDevice : public Device {
// Allocate required output buffers
device_only_memory<char> temp_mem(this, "temp_build_mem");
- temp_mem.alloc_to_device(sizes.tempSizeInBytes);
+ temp_mem.alloc_to_device(align_up(sizes.tempSizeInBytes, 8) + 8);
+ if (!temp_mem.device_pointer)
+ return false; // Make sure temporary memory allocation succeeded
- out_data.type = MEM_DEVICE_ONLY;
- out_data.data_type = TYPE_UNKNOWN;
- out_data.data_elements = 1;
- out_data.data_size = sizes.outputSizeInBytes;
- mem_alloc(out_data);
+ // Move textures to host memory if there is not enough room
+ size_t size = 0, free = 0;
+ cuMemGetInfo(&free, &size);
+ size = sizes.outputSizeInBytes + device_working_headroom;
+ if (size >= free && can_map_host) {
+ move_textures_to_host(size - free, false);
+ }
+
+ CUdeviceptr out_data = 0;
+ check_result_cuda_ret(cuMemAlloc(&out_data, sizes.outputSizeInBytes));
+ as_mem.push_back(out_data);
// Finally build the acceleration structure
+ OptixAccelEmitDesc compacted_size_prop;
+ compacted_size_prop.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE;
+ // A tiny space was allocated for this property at the end of the temporary buffer above
+ // Make sure this pointer is 8-byte aligned
+ compacted_size_prop.result = align_up(temp_mem.device_pointer + sizes.tempSizeInBytes, 8);
+
check_result_optix_ret(optixAccelBuild(context,
NULL,
&options,
&build_input,
1,
temp_mem.device_pointer,
- sizes.tempSizeInBytes,
- out_data.device_pointer,
+ temp_mem.device_size,
+ out_data,
sizes.outputSizeInBytes,
&out_handle,
- NULL,
- 0));
+ &compacted_size_prop,
+ 1));
// Wait for all operations to finish
check_result_cuda_ret(cuStreamSynchronize(NULL));
+ // Compact acceleration structure to save memory (do not do this in viewport for faster builds)
+ if (background) {
+ uint64_t compacted_size = sizes.outputSizeInBytes;
+ check_result_cuda_ret(
+ cuMemcpyDtoH(&compacted_size, compacted_size_prop.result, sizeof(compacted_size)));
+
+ // Temporary memory is no longer needed, so free it now to make space
+ temp_mem.free();
+
+ // There is no point compacting if the size does not change
+ if (compacted_size < sizes.outputSizeInBytes) {
+ CUdeviceptr compacted_data = 0;
+ if (cuMemAlloc(&compacted_data, compacted_size) != CUDA_SUCCESS)
+ // Do not compact if memory allocation for compacted acceleration structure fails
+ // Can just use the uncompacted one then, so succeed here regardless
+ return true;
+ as_mem.push_back(compacted_data);
+
+ check_result_optix_ret(optixAccelCompact(
+ context, NULL, out_handle, compacted_data, compacted_size, &out_handle));
+
+ // Wait for compaction to finish
+ check_result_cuda_ret(cuStreamSynchronize(NULL));
+
+ // Free uncompacted acceleration structure
+ cuMemFree(out_data);
+ as_mem.erase(as_mem.end() - 2); // Remove 'out_data' from 'as_mem' array
+ }
+ }
+
return true;
}
- bool build_optix_bvh(BVH *bvh, device_memory &out_data) override
+ bool build_optix_bvh(BVH *bvh) override
{
assert(bvh->params.top_level);
unsigned int num_instances = 0;
unordered_map<Mesh *, vector<OptixTraversableHandle>> meshes;
+ meshes.reserve(bvh->meshes.size());
- // Clear all previous AS
- blas.clear();
+ // Free all previous acceleration structures
+ for (CUdeviceptr mem : as_mem) {
+ cuMemFree(mem);
+ }
+ as_mem.clear();
// Build bottom level acceleration structures (BLAS)
// Note: Always keep this logic in sync with bvh_optix.cpp!
@@ -900,6 +958,7 @@ class OptiXDevice : public Device {
Mesh *const mesh = ob->mesh;
vector<OptixTraversableHandle> handles;
+ handles.reserve(2);
// Build BLAS for curve primitives
if (bvh->params.primitive_mask & PRIMITIVE_ALL_CURVE && mesh->num_curves() > 0) {
@@ -966,9 +1025,8 @@ class OptiXDevice : public Device {
build_input.aabbArray.primitiveIndexOffset = mesh->prim_offset;
// Allocate memory for new BLAS and build it
- blas.emplace_back(this, "blas");
handles.emplace_back();
- if (!build_optix_bvh(build_input, num_motion_steps, blas.back(), handles.back()))
+ if (!build_optix_bvh(build_input, num_motion_steps, handles.back()))
return false;
}
@@ -1032,9 +1090,8 @@ class OptiXDevice : public Device {
build_input.triangleArray.primitiveIndexOffset = mesh->prim_offset + mesh->num_segments();
// Allocate memory for new BLAS and build it
- blas.emplace_back(this, "blas");
handles.emplace_back();
- if (!build_optix_bvh(build_input, num_motion_steps, blas.back(), handles.back()))
+ if (!build_optix_bvh(build_input, num_motion_steps, handles.back()))
return false;
}
@@ -1051,6 +1108,7 @@ class OptiXDevice : public Device {
// Skip non-traceable objects
if (!ob->is_traceable())
continue;
+
// Create separate instance for triangle/curve meshes of an object
for (OptixTraversableHandle handle : meshes[ob->mesh]) {
OptixAabb &aabb = aabbs[num_instances];
@@ -1078,15 +1136,17 @@ class OptiXDevice : public Device {
// Insert motion traversable if object has motion
if (motion_blur && ob->use_motion()) {
- blas.emplace_back(this, "motion_transform");
- device_only_memory<uint8_t> &motion_transform_gpu = blas.back();
- motion_transform_gpu.alloc_to_device(sizeof(OptixSRTMotionTransform) +
- (max(ob->motion.size(), 2) - 2) *
- sizeof(OptixSRTData));
+ size_t motion_keys = max(ob->motion.size(), 2) - 2;
+ size_t motion_transform_size = sizeof(OptixSRTMotionTransform) +
+ motion_keys * sizeof(OptixSRTData);
+
+ CUdeviceptr motion_transform_gpu = 0;
+ check_result_cuda_ret(cuMemAlloc(&motion_transform_gpu, motion_transform_size));
+ as_mem.push_back(motion_transform_gpu);
// Allocate host side memory for motion transform and fill it with transform data
OptixSRTMotionTransform &motion_transform = *reinterpret_cast<OptixSRTMotionTransform *>(
- motion_transform_gpu.host_pointer = new uint8_t[motion_transform_gpu.memory_size()]);
+ new uint8_t[motion_transform_size]);
motion_transform.child = handle;
motion_transform.motionOptions.numKeys = ob->motion.size();
motion_transform.motionOptions.flags = OPTIX_MOTION_FLAG_NONE;
@@ -1098,38 +1158,43 @@ class OptiXDevice : public Device {
transform_motion_decompose(decomp.data(), ob->motion.data(), ob->motion.size());
for (size_t i = 0; i < ob->motion.size(); ++i) {
- // scaling
- srt_data[i].a = decomp[i].z.x; // scale.x.y
- srt_data[i].b = decomp[i].z.y; // scale.x.z
- srt_data[i].c = decomp[i].w.x; // scale.y.z
+ // Scale
srt_data[i].sx = decomp[i].y.w; // scale.x.x
srt_data[i].sy = decomp[i].z.w; // scale.y.y
srt_data[i].sz = decomp[i].w.w; // scale.z.z
- srt_data[i].pvx = 0;
- srt_data[i].pvy = 0;
- srt_data[i].pvz = 0;
- // rotation
+
+ // Shear
+ srt_data[i].a = decomp[i].z.x; // scale.x.y
+ srt_data[i].b = decomp[i].z.y; // scale.x.z
+ srt_data[i].c = decomp[i].w.x; // scale.y.z
+
+ // Pivot point
+ srt_data[i].pvx = 0.0f;
+ srt_data[i].pvy = 0.0f;
+ srt_data[i].pvz = 0.0f;
+
+ // Rotation
srt_data[i].qx = decomp[i].x.x;
srt_data[i].qy = decomp[i].x.y;
srt_data[i].qz = decomp[i].x.z;
srt_data[i].qw = decomp[i].x.w;
- // transform
+
+ // Translation
srt_data[i].tx = decomp[i].y.x;
srt_data[i].ty = decomp[i].y.y;
srt_data[i].tz = decomp[i].y.z;
}
// Upload motion transform to GPU
- mem_copy_to(motion_transform_gpu);
- delete[] reinterpret_cast<uint8_t *>(motion_transform_gpu.host_pointer);
- motion_transform_gpu.host_pointer = 0;
+ cuMemcpyHtoD(motion_transform_gpu, &motion_transform, motion_transform_size);
+ delete[] reinterpret_cast<uint8_t *>(&motion_transform);
// Disable instance transform if object uses motion transform already
instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
// Get traversable handle to motion transform
optixConvertPointerToTraversableHandle(context,
- motion_transform_gpu.device_pointer,
+ motion_transform_gpu,
OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM,
&instance.traversableHandle);
}
@@ -1157,7 +1222,7 @@ class OptiXDevice : public Device {
instances.resize(num_instances);
instances.copy_to_device();
- // Build top-level acceleration structure
+ // Build top-level acceleration structure (TLAS)
OptixBuildInput build_input = {};
build_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES;
build_input.instanceArray.instances = instances.device_pointer;
@@ -1165,7 +1230,7 @@ class OptiXDevice : public Device {
build_input.instanceArray.aabbs = aabbs.device_pointer;
build_input.instanceArray.numAabbs = num_instances;
- return build_optix_bvh(build_input, 0 /* TLAS has no motion itself */, out_data, tlas_handle);
+ return build_optix_bvh(build_input, 0, tlas_handle);
}
void update_texture_info()
diff --git a/intern/cycles/device/opencl/memory_manager.cpp b/intern/cycles/device/opencl/memory_manager.cpp
index f85aadce1c2..06d4746a86e 100644
--- a/intern/cycles/device/opencl/memory_manager.cpp
+++ b/intern/cycles/device/opencl/memory_manager.cpp
@@ -251,7 +251,7 @@ void MemoryManager::set_kernel_arg_buffers(cl_kernel kernel, cl_uint *narg)
device->kernel_set_args(kernel, (*narg)++, *device_buffer.buffer);
}
else {
- device->kernel_set_args(kernel, (*narg)++, device->null_mem);
+ device->kernel_set_args(kernel, (*narg)++, 0);
}
}
}
diff --git a/intern/cycles/device/opencl/opencl.h b/intern/cycles/device/opencl/opencl.h
index 82b961b8de7..61b1e3e3b6b 100644
--- a/intern/cycles/device/opencl/opencl.h
+++ b/intern/cycles/device/opencl/opencl.h
@@ -381,7 +381,6 @@ class OpenCLDevice : public Device {
ConstMemMap const_mem_map;
MemMap mem_map;
- device_ptr null_mem;
bool device_initialized;
string platform_name;
diff --git a/intern/cycles/device/opencl/opencl_split.cpp b/intern/cycles/device/opencl/opencl_split.cpp
index eea5cf2fb8a..76f9ce7a18f 100644
--- a/intern/cycles/device/opencl/opencl_split.cpp
+++ b/intern/cycles/device/opencl/opencl_split.cpp
@@ -611,7 +611,6 @@ OpenCLDevice::OpenCLDevice(DeviceInfo &info, Stats &stats, Profiler &profiler, b
cdDevice = NULL;
cxContext = NULL;
cqCommandQueue = NULL;
- null_mem = 0;
device_initialized = false;
textures_need_update = true;
use_preview_kernels = !background;
@@ -662,12 +661,6 @@ OpenCLDevice::OpenCLDevice(DeviceInfo &info, Stats &stats, Profiler &profiler, b
return;
}
- null_mem = (device_ptr)clCreateBuffer(cxContext, CL_MEM_READ_ONLY, 1, NULL, &ciErr);
- if (opencl_error(ciErr)) {
- opencl_error("OpenCL: Error creating memory buffer for NULL");
- return;
- }
-
/* Allocate this right away so that texture_info
* is placed at offset 0 in the device memory buffers. */
texture_info.resize(1);
@@ -689,9 +682,6 @@ OpenCLDevice::~OpenCLDevice()
memory_manager.free();
- if (null_mem)
- clReleaseMemObject(CL_MEM_PTR(null_mem));
-
ConstMemMap::iterator mt;
for (mt = const_mem_map.begin(); mt != const_mem_map.end(); mt++) {
delete mt->second;
@@ -962,7 +952,7 @@ void OpenCLDevice::mem_alloc(device_memory &mem)
opencl_assert_err(ciErr, "clCreateBuffer");
}
else {
- mem.device_pointer = null_mem;
+ mem.device_pointer = 0;
}
stats.mem_alloc(size);
@@ -1084,7 +1074,7 @@ void OpenCLDevice::mem_free(device_memory &mem)
}
else {
if (mem.device_pointer) {
- if (mem.device_pointer != null_mem) {
+ if (mem.device_pointer != 0) {
opencl_assert(clReleaseMemObject(CL_MEM_PTR(mem.device_pointer)));
}
mem.device_pointer = 0;
@@ -1120,7 +1110,7 @@ device_ptr OpenCLDevice::mem_alloc_sub_ptr(device_memory &mem, int offset, int s
void OpenCLDevice::mem_free_sub_ptr(device_ptr device_pointer)
{
- if (device_pointer && device_pointer != null_mem) {
+ if (device_pointer != 0) {
opencl_assert(clReleaseMemObject(CL_MEM_PTR(device_pointer)));
}
}
@@ -1239,8 +1229,7 @@ void OpenCLDevice::set_kernel_arg_mem(cl_kernel kernel, cl_uint *narg, const cha
ptr = CL_MEM_PTR(i->second);
}
else {
- /* work around NULL not working, even though the spec says otherwise */
- ptr = CL_MEM_PTR(null_mem);
+ ptr = 0;
}
opencl_assert(clSetKernelArg(kernel, (*narg)++, sizeof(ptr), (void *)&ptr));
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 4077a1ad516..99172f30b8b 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -129,6 +129,7 @@ set(SRC_HEADERS
kernel_types.h
kernel_volume.h
kernel_work_stealing.h
+ kernel_write_passes.h
)
set(SRC_KERNELS_CPU_HEADERS
@@ -182,6 +183,7 @@ set(SRC_CLOSURE_HEADERS
set(SRC_SVM_HEADERS
svm/svm.h
svm/svm_ao.h
+ svm/svm_aov.h
svm/svm_attribute.h
svm/svm_bevel.h
svm/svm_blackbody.h
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index 2f73434706c..2884ea62a18 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -37,6 +37,7 @@ CCL_NAMESPACE_BEGIN
typedef ccl_addr_space struct MicrofacetExtra {
float3 color, cspec0;
+ float3 fresnel_color;
float clearcoat;
} MicrofacetExtra;
@@ -276,6 +277,22 @@ ccl_device_forceinline float D_GTR1(float NdotH, float alpha)
return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t);
}
+ccl_device_forceinline void bsdf_microfacet_fresnel_color(const ShaderData *sd,
+ MicrofacetBsdf *bsdf)
+{
+ kernel_assert(CLOSURE_IS_BSDF_MICROFACET_FRESNEL(bsdf->type));
+
+ float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
+ bsdf->extra->fresnel_color = interpolate_fresnel_color(
+ sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0);
+
+ if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) {
+ bsdf->extra->fresnel_color *= 0.25f * bsdf->extra->clearcoat;
+ }
+
+ bsdf->sample_weight *= average(bsdf->extra->fresnel_color);
+}
+
/* GGX microfacet with Smith shadow-masking from:
*
* Microfacet Models for Refraction through Rough Surfaces
@@ -305,15 +322,13 @@ ccl_device int bsdf_microfacet_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const Sha
{
bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
- float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
- float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
- bsdf->sample_weight *= F;
-
bsdf->alpha_x = saturate(bsdf->alpha_x);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID;
+ bsdf_microfacet_fresnel_color(sd, bsdf);
+
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
@@ -321,15 +336,13 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(MicrofacetBsdf *bsdf, const S
{
bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
- float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
- float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
- bsdf->sample_weight *= 0.25f * bsdf->extra->clearcoat * F;
-
bsdf->alpha_x = saturate(bsdf->alpha_x);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID;
+ bsdf_microfacet_fresnel_color(sd, bsdf);
+
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
@@ -364,15 +377,13 @@ ccl_device int bsdf_microfacet_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf, con
{
bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
- float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
- float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
- bsdf->sample_weight *= F;
-
bsdf->alpha_x = saturate(bsdf->alpha_x);
bsdf->alpha_y = saturate(bsdf->alpha_y);
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID;
+ bsdf_microfacet_fresnel_color(sd, bsdf);
+
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
index 9780dd87415..a5fe989bcd1 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
@@ -402,9 +402,7 @@ ccl_device int bsdf_microfacet_multi_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsd
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID;
- float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
- float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
- bsdf->sample_weight *= F;
+ bsdf_microfacet_fresnel_color(sd, bsdf);
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
@@ -424,9 +422,7 @@ ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(MicrofacetBsdf *bsdf, con
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID;
- float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
- float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
- bsdf->sample_weight *= F;
+ bsdf_microfacet_fresnel_color(sd, bsdf);
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
@@ -582,9 +578,7 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsd
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID;
- float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
- float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
- bsdf->sample_weight *= F;
+ bsdf_microfacet_fresnel_color(sd, bsdf);
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
}
diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h
index 46a51f5a560..606c288649a 100644
--- a/intern/cycles/kernel/kernel_accumulate.h
+++ b/intern/cycles/kernel/kernel_accumulate.h
@@ -174,13 +174,13 @@ ccl_device_inline float3 bsdf_eval_sum(const BsdfEval *eval)
* visible as the first non-transparent hit, while indirectly visible are the
* bounces after that. */
-ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
+ccl_device_inline void path_radiance_init(KernelGlobals *kg, PathRadiance *L)
{
/* clear all */
#ifdef __PASSES__
- L->use_light_pass = use_light_pass;
+ L->use_light_pass = kernel_data.film.use_light_pass;
- if (use_light_pass) {
+ if (kernel_data.film.use_light_pass) {
L->indirect = make_float3(0.0f, 0.0f, 0.0f);
L->direct_emission = make_float3(0.0f, 0.0f, 0.0f);
@@ -285,7 +285,37 @@ ccl_device_inline void path_radiance_bsdf_bounce(KernelGlobals *kg,
}
}
-ccl_device_inline void path_radiance_accum_emission(PathRadiance *L,
+#ifdef __CLAMP_SAMPLE__
+ccl_device_forceinline void path_radiance_clamp(KernelGlobals *kg, float3 *L, int bounce)
+{
+ float limit = (bounce > 0) ? kernel_data.integrator.sample_clamp_indirect :
+ kernel_data.integrator.sample_clamp_direct;
+ float sum = reduce_add(fabs(*L));
+ if (sum > limit) {
+ *L *= limit / sum;
+ }
+}
+
+ccl_device_forceinline void path_radiance_clamp_throughput(KernelGlobals *kg,
+ float3 *L,
+ float3 *throughput,
+ int bounce)
+{
+ float limit = (bounce > 0) ? kernel_data.integrator.sample_clamp_indirect :
+ kernel_data.integrator.sample_clamp_direct;
+
+ float sum = reduce_add(fabs(*L));
+ if (sum > limit) {
+ float clamp_factor = limit / sum;
+ *L *= clamp_factor;
+ *throughput *= clamp_factor;
+ }
+}
+
+#endif
+
+ccl_device_inline void path_radiance_accum_emission(KernelGlobals *kg,
+ PathRadiance *L,
ccl_addr_space PathState *state,
float3 throughput,
float3 value)
@@ -296,23 +326,29 @@ ccl_device_inline void path_radiance_accum_emission(PathRadiance *L,
}
#endif
+ float3 contribution = throughput * value;
+#ifdef __CLAMP_SAMPLE__
+ path_radiance_clamp(kg, &contribution, state->bounce - 1);
+#endif
+
#ifdef __PASSES__
if (L->use_light_pass) {
if (state->bounce == 0)
- L->emission += throughput * value;
+ L->emission += contribution;
else if (state->bounce == 1)
- L->direct_emission += throughput * value;
+ L->direct_emission += contribution;
else
- L->indirect += throughput * value;
+ L->indirect += contribution;
}
else
#endif
{
- L->emission += throughput * value;
+ L->emission += contribution;
}
}
-ccl_device_inline void path_radiance_accum_ao(PathRadiance *L,
+ccl_device_inline void path_radiance_accum_ao(KernelGlobals *kg,
+ PathRadiance *L,
ccl_addr_space PathState *state,
float3 throughput,
float3 alpha,
@@ -339,21 +375,23 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L,
}
#endif
+ float3 contribution = throughput * bsdf * ao;
+
#ifdef __PASSES__
if (L->use_light_pass) {
if (state->bounce == 0) {
/* Directly visible lighting. */
- L->direct_diffuse += throughput * bsdf * ao;
+ L->direct_diffuse += contribution;
}
else {
/* Indirectly visible lighting after BSDF bounce. */
- L->indirect += throughput * bsdf * ao;
+ L->indirect += contribution;
}
}
else
#endif
{
- L->emission += throughput * bsdf * ao;
+ L->emission += contribution;
}
}
@@ -374,7 +412,8 @@ ccl_device_inline void path_radiance_accum_total_ao(PathRadiance *L,
#endif
}
-ccl_device_inline void path_radiance_accum_light(PathRadiance *L,
+ccl_device_inline void path_radiance_accum_light(KernelGlobals *kg,
+ PathRadiance *L,
ccl_addr_space PathState *state,
float3 throughput,
BsdfEval *bsdf_eval,
@@ -394,15 +433,24 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L,
}
#endif
+ float3 shaded_throughput = throughput * shadow;
+
#ifdef __PASSES__
if (L->use_light_pass) {
+ /* Compute the clamping based on the total contribution.
+ * The resulting scale is then be applied to all individual components. */
+ float3 full_contribution = shaded_throughput * bsdf_eval_sum(bsdf_eval);
+# ifdef __CLAMP_SAMPLE__
+ path_radiance_clamp_throughput(kg, &full_contribution, &shaded_throughput, state->bounce);
+# endif
+
if (state->bounce == 0) {
/* directly visible lighting */
- L->direct_diffuse += throughput * bsdf_eval->diffuse * shadow;
- L->direct_glossy += throughput * bsdf_eval->glossy * shadow;
- L->direct_transmission += throughput * bsdf_eval->transmission * shadow;
- L->direct_subsurface += throughput * bsdf_eval->subsurface * shadow;
- L->direct_scatter += throughput * bsdf_eval->scatter * shadow;
+ L->direct_diffuse += shaded_throughput * bsdf_eval->diffuse;
+ L->direct_glossy += shaded_throughput * bsdf_eval->glossy;
+ L->direct_transmission += shaded_throughput * bsdf_eval->transmission;
+ L->direct_subsurface += shaded_throughput * bsdf_eval->subsurface;
+ L->direct_scatter += shaded_throughput * bsdf_eval->scatter;
if (is_lamp) {
L->shadow.x += shadow.x * shadow_fac;
@@ -412,13 +460,15 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L,
}
else {
/* indirectly visible lighting after BSDF bounce */
- L->indirect += throughput * bsdf_eval_sum(bsdf_eval) * shadow;
+ L->indirect += full_contribution;
}
}
else
#endif
{
- L->emission += throughput * bsdf_eval->diffuse * shadow;
+ float3 contribution = shaded_throughput * bsdf_eval->diffuse;
+ path_radiance_clamp(kg, &contribution, state->bounce);
+ L->emission += contribution;
}
}
@@ -439,7 +489,8 @@ ccl_device_inline void path_radiance_accum_total_light(PathRadiance *L,
#endif
}
-ccl_device_inline void path_radiance_accum_background(PathRadiance *L,
+ccl_device_inline void path_radiance_accum_background(KernelGlobals *kg,
+ PathRadiance *L,
ccl_addr_space PathState *state,
float3 throughput,
float3 value)
@@ -456,19 +507,24 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L,
}
#endif
+ float3 contribution = throughput * value;
+#ifdef __CLAMP_SAMPLE__
+ path_radiance_clamp(kg, &contribution, state->bounce - 1);
+#endif
+
#ifdef __PASSES__
if (L->use_light_pass) {
if (state->flag & PATH_RAY_TRANSPARENT_BACKGROUND)
- L->background += throughput * value;
+ L->background += contribution;
else if (state->bounce == 1)
- L->direct_emission += throughput * value;
+ L->direct_emission += contribution;
else
- L->indirect += throughput * value;
+ L->indirect += contribution;
}
else
#endif
{
- L->emission += throughput * value;
+ L->emission += contribution;
}
#ifdef __DENOISING_FEATURES__
@@ -587,8 +643,6 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg,
/* Light Passes are used */
#ifdef __PASSES__
float3 L_direct, L_indirect;
- float clamp_direct = kernel_data.integrator.sample_clamp_direct;
- float clamp_indirect = kernel_data.integrator.sample_clamp_indirect;
if (L->use_light_pass) {
path_radiance_sum_indirect(L);
@@ -622,44 +676,6 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg,
L->emission = make_float3(0.0f, 0.0f, 0.0f);
}
-
- /* Clamp direct and indirect samples */
-# ifdef __CLAMP_SAMPLE__
- else if (sum > clamp_direct || sum > clamp_indirect) {
- float scale;
-
- /* Direct */
- float sum_direct = fabsf(L_direct.x) + fabsf(L_direct.y) + fabsf(L_direct.z);
- if (sum_direct > clamp_direct) {
- scale = clamp_direct / sum_direct;
- L_direct *= scale;
-
- L->direct_diffuse *= scale;
- L->direct_glossy *= scale;
- L->direct_transmission *= scale;
- L->direct_subsurface *= scale;
- L->direct_scatter *= scale;
- L->emission *= scale;
- L->background *= scale;
- }
-
- /* Indirect */
- float sum_indirect = fabsf(L_indirect.x) + fabsf(L_indirect.y) + fabsf(L_indirect.z);
- if (sum_indirect > clamp_indirect) {
- scale = clamp_indirect / sum_indirect;
- L_indirect *= scale;
-
- L->indirect_diffuse *= scale;
- L->indirect_glossy *= scale;
- L->indirect_transmission *= scale;
- L->indirect_subsurface *= scale;
- L->indirect_scatter *= scale;
- }
-
- /* Sum again, after clamping */
- L_sum = L_direct + L_indirect;
- }
-# endif
}
/* No Light Passes */
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index cd1ca5ea7ec..a349b225abb 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -39,13 +39,13 @@ ccl_device_inline void compute_light_pass(
# endif
/* init radiance */
- path_radiance_init(&L_sample, kernel_data.film.use_light_pass);
+ path_radiance_init(kg, &L_sample);
/* init path state */
path_state_init(kg, &emission_sd, &state, rng_hash, sample, NULL);
/* evaluate surface shader */
- shader_eval_surface(kg, sd, &state, state.flag);
+ shader_eval_surface(kg, sd, &state, NULL, state.flag);
/* TODO, disable more closures we don't need besides transparent */
shader_bsdf_disable_transparency(kg, sd);
@@ -64,7 +64,7 @@ ccl_device_inline void compute_light_pass(
/* sample emission */
if ((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) {
float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf);
- path_radiance_accum_emission(&L_sample, &state, throughput, emission);
+ path_radiance_accum_emission(kg, &L_sample, &state, throughput, emission);
}
bool is_sss_sample = false;
@@ -118,7 +118,7 @@ ccl_device_inline void compute_light_pass(
/* sample emission */
if ((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) {
float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf);
- path_radiance_accum_emission(&L_sample, &state, throughput, emission);
+ path_radiance_accum_emission(kg, &L_sample, &state, throughput, emission);
}
# ifdef __SUBSURFACE__
@@ -209,12 +209,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
}
else {
/* surface color of the pass only */
- shader_eval_surface(kg, sd, state, 0);
+ shader_eval_surface(kg, sd, state, NULL, 0);
return kernel_bake_shader_bsdf(kg, sd, type);
}
}
else {
- shader_eval_surface(kg, sd, state, 0);
+ shader_eval_surface(kg, sd, state, NULL, 0);
color = kernel_bake_shader_bsdf(kg, sd, type);
}
@@ -287,7 +287,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg,
/* light passes */
PathRadiance L;
- path_radiance_init(&L, kernel_data.film.use_light_pass);
+ path_radiance_init(kg, &L);
shader_setup_from_sample(
kg,
@@ -332,7 +332,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg,
case SHADER_EVAL_EMISSION: {
if (type != SHADER_EVAL_NORMAL || (sd.flag & SD_HAS_BUMP)) {
int path_flag = (type == SHADER_EVAL_EMISSION) ? PATH_RAY_EMISSION : 0;
- shader_eval_surface(kg, &sd, &state, path_flag);
+ shader_eval_surface(kg, &sd, &state, NULL, path_flag);
}
if (type == SHADER_EVAL_NORMAL) {
@@ -445,7 +445,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg,
/* evaluate */
int path_flag = 0; /* we can't know which type of BSDF this is for */
- shader_eval_surface(kg, &sd, &state, path_flag | PATH_RAY_EMISSION);
+ shader_eval_surface(kg, &sd, &state, NULL, path_flag | PATH_RAY_EMISSION);
out = shader_background_eval(&sd);
break;
}
@@ -524,7 +524,7 @@ ccl_device void kernel_background_evaluate(KernelGlobals *kg,
/* evaluate */
int path_flag = 0; /* we can't know which type of BSDF this is for */
- shader_eval_surface(kg, &sd, &state, path_flag | PATH_RAY_EMISSION);
+ shader_eval_surface(kg, &sd, &state, NULL, path_flag | PATH_RAY_EMISSION);
float3 color = shader_background_eval(&sd);
/* write output */
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
index 552734cc361..4963f1cd196 100644
--- a/intern/cycles/kernel/kernel_compat_opencl.h
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -126,6 +126,8 @@
#define fminf(x, y) fmin(((float)(x)), ((float)(y)))
#define fmodf(x, y) fmod((float)(x), (float)(y))
#define sinhf(x) sinh(((float)(x)))
+#define coshf(x) cosh(((float)(x)))
+#define tanhf(x) tanh(((float)(x)))
/* Use native functions with possibly lower precision for performance,
* no issues found so far. */
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index 459280cf433..c63d1149d03 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -73,7 +73,7 @@ ccl_device_noinline_cpu float3 direct_emissive_eval(KernelGlobals *kg,
/* No proper path flag, we're evaluating this for all closures. that's
* weak but we'd have to do multiple evaluations otherwise. */
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, emission_sd, state, PATH_RAY_EMISSION);
+ shader_eval_surface(kg, emission_sd, state, NULL, PATH_RAY_EMISSION);
path_state_modify_bounce(state, false);
/* Evaluate closures. */
@@ -234,14 +234,13 @@ ccl_device_noinline_cpu float3 indirect_primitive_emission(
/* Indirect Lamp Emission */
-ccl_device_noinline_cpu bool indirect_lamp_emission(KernelGlobals *kg,
+ccl_device_noinline_cpu void indirect_lamp_emission(KernelGlobals *kg,
ShaderData *emission_sd,
ccl_addr_space PathState *state,
+ PathRadiance *L,
Ray *ray,
- float3 *emission)
+ float3 throughput)
{
- bool hit_lamp = false;
-
for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) {
LightSample ls ccl_optional_struct_init;
@@ -261,7 +260,7 @@ ccl_device_noinline_cpu bool indirect_lamp_emission(KernelGlobals *kg,
}
#endif
- float3 L = direct_emissive_eval(
+ float3 lamp_L = direct_emissive_eval(
kg, emission_sd, &ls, state, -ray->D, ray->dD, ls.t, ray->time);
#ifdef __VOLUME__
@@ -271,7 +270,7 @@ ccl_device_noinline_cpu bool indirect_lamp_emission(KernelGlobals *kg,
volume_ray.t = ls.t;
float3 volume_tp = make_float3(1.0f, 1.0f, 1.0f);
kernel_volume_shadow(kg, emission_sd, state, &volume_ray, &volume_tp);
- L *= volume_tp;
+ lamp_L *= volume_tp;
}
#endif
@@ -279,14 +278,11 @@ ccl_device_noinline_cpu bool indirect_lamp_emission(KernelGlobals *kg,
/* multiple importance sampling, get regular light pdf,
* and compute weight with respect to BSDF pdf */
float mis_weight = power_heuristic(state->ray_pdf, ls.pdf);
- L *= mis_weight;
+ lamp_L *= mis_weight;
}
- *emission += L;
- hit_lamp = true;
+ path_radiance_accum_emission(kg, L, state, throughput, lamp_L);
}
-
- return hit_lamp;
}
/* Indirect Background */
@@ -294,6 +290,7 @@ ccl_device_noinline_cpu bool indirect_lamp_emission(KernelGlobals *kg,
ccl_device_noinline_cpu float3 indirect_background(KernelGlobals *kg,
ShaderData *emission_sd,
ccl_addr_space PathState *state,
+ ccl_global float *buffer,
ccl_addr_space Ray *ray)
{
#ifdef __BACKGROUND__
@@ -322,7 +319,7 @@ ccl_device_noinline_cpu float3 indirect_background(KernelGlobals *kg,
# endif
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, emission_sd, state, state->flag | PATH_RAY_EMISSION);
+ shader_eval_surface(kg, emission_sd, state, buffer, state->flag | PATH_RAY_EMISSION);
path_state_modify_bounce(state, false);
L = shader_background_eval(emission_sd);
diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
index c1d74dddc2a..828add9dc13 100644
--- a/intern/cycles/kernel/kernel_passes.h
+++ b/intern/cycles/kernel/kernel_passes.h
@@ -14,85 +14,11 @@
* limitations under the License.
*/
-#if defined(__SPLIT_KERNEL__) || defined(__KERNEL_CUDA__)
-# define __ATOMIC_PASS_WRITE__
-#endif
-
#include "kernel/kernel_id_passes.h"
CCL_NAMESPACE_BEGIN
-ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, float value)
-{
- ccl_global float *buf = buffer;
-#ifdef __ATOMIC_PASS_WRITE__
- atomic_add_and_fetch_float(buf, value);
-#else
- *buf += value;
-#endif
-}
-
-ccl_device_inline void kernel_write_pass_float3(ccl_global float *buffer, float3 value)
-{
-#ifdef __ATOMIC_PASS_WRITE__
- ccl_global float *buf_x = buffer + 0;
- ccl_global float *buf_y = buffer + 1;
- ccl_global float *buf_z = buffer + 2;
-
- atomic_add_and_fetch_float(buf_x, value.x);
- atomic_add_and_fetch_float(buf_y, value.y);
- atomic_add_and_fetch_float(buf_z, value.z);
-#else
- ccl_global float3 *buf = (ccl_global float3 *)buffer;
- *buf += value;
-#endif
-}
-
-ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, float4 value)
-{
-#ifdef __ATOMIC_PASS_WRITE__
- ccl_global float *buf_x = buffer + 0;
- ccl_global float *buf_y = buffer + 1;
- ccl_global float *buf_z = buffer + 2;
- ccl_global float *buf_w = buffer + 3;
-
- atomic_add_and_fetch_float(buf_x, value.x);
- atomic_add_and_fetch_float(buf_y, value.y);
- atomic_add_and_fetch_float(buf_z, value.z);
- atomic_add_and_fetch_float(buf_w, value.w);
-#else
- ccl_global float4 *buf = (ccl_global float4 *)buffer;
- *buf += value;
-#endif
-}
-
#ifdef __DENOISING_FEATURES__
-ccl_device_inline void kernel_write_pass_float_variance(ccl_global float *buffer, float value)
-{
- kernel_write_pass_float(buffer, value);
-
- /* The online one-pass variance update that's used for the mega-kernel can't easily be
- * implemented with atomics,
- * so for the split kernel the E[x^2] - 1/N * (E[x])^2 fallback is used. */
- kernel_write_pass_float(buffer + 1, value * value);
-}
-
-# ifdef __ATOMIC_PASS_WRITE__
-# define kernel_write_pass_float3_unaligned kernel_write_pass_float3
-# else
-ccl_device_inline void kernel_write_pass_float3_unaligned(ccl_global float *buffer, float3 value)
-{
- buffer[0] += value.x;
- buffer[1] += value.y;
- buffer[2] += value.z;
-}
-# endif
-
-ccl_device_inline void kernel_write_pass_float3_variance(ccl_global float *buffer, float3 value)
-{
- kernel_write_pass_float3_unaligned(buffer, value);
- kernel_write_pass_float3_unaligned(buffer + 3, value * value);
-}
ccl_device_inline void kernel_write_denoising_shadow(KernelGlobals *kg,
ccl_global float *buffer,
@@ -145,7 +71,17 @@ ccl_device_inline void kernel_update_denoising_features(KernelGlobals *kg,
normal += sc->N * sc->sample_weight;
sum_weight += sc->sample_weight;
if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) {
- albedo += sc->weight;
+ float3 closure_albedo = sc->weight;
+ /* Closures that include a Fresnel term typically have weights close to 1 even though their
+ * actual contribution is significantly lower.
+ * To account for this, we scale their weight by the average fresnel factor (the same is also
+ * done for the sample weight in the BSDF setup, so we don't need to scale that here). */
+ if (CLOSURE_IS_BSDF_MICROFACET_FRESNEL(sc->type)) {
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc;
+ closure_albedo *= bsdf->extra->fresnel_color;
+ }
+
+ albedo += closure_albedo;
sum_nonspecular_weight += sc->sample_weight;
}
}
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 55abe39c465..1a0b67275a7 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -27,6 +27,7 @@
#include "kernel/geom/geom.h"
#include "kernel/bvh/bvh.h"
+#include "kernel/kernel_write_passes.h"
#include "kernel/kernel_accumulate.h"
#include "kernel/kernel_shader.h"
#include "kernel/kernel_light.h"
@@ -103,10 +104,7 @@ ccl_device_forceinline void kernel_path_lamp_emission(KernelGlobals *kg,
light_ray.dP = ray->dP;
/* intersect with lamp */
- float3 emission = make_float3(0.0f, 0.0f, 0.0f);
-
- if (indirect_lamp_emission(kg, emission_sd, state, &light_ray, &emission))
- path_radiance_accum_emission(L, state, throughput, emission);
+ indirect_lamp_emission(kg, emission_sd, state, L, &light_ray, throughput);
}
#endif /* __LAMP_MIS__ */
}
@@ -116,6 +114,7 @@ ccl_device_forceinline void kernel_path_background(KernelGlobals *kg,
ccl_addr_space Ray *ray,
float3 throughput,
ShaderData *sd,
+ ccl_global float *buffer,
PathRadiance *L)
{
/* eval background shader if nothing hit */
@@ -136,8 +135,8 @@ ccl_device_forceinline void kernel_path_background(KernelGlobals *kg,
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, sd, state, ray);
- path_radiance_accum_background(L, state, throughput, L_background);
+ float3 L_background = indirect_background(kg, sd, state, buffer, ray);
+ path_radiance_accum_background(kg, L, state, throughput, L_background);
#endif /* __BACKGROUND__ */
}
@@ -187,7 +186,7 @@ ccl_device_forceinline VolumeIntegrateResult kernel_path_volume(KernelGlobals *k
/* emission */
if (volume_segment.closure_flag & SD_EMISSION)
- path_radiance_accum_emission(L, state, *throughput, volume_segment.accum_emission);
+ path_radiance_accum_emission(kg, L, state, *throughput, volume_segment.accum_emission);
/* scattering */
VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED;
@@ -267,7 +266,7 @@ ccl_device_forceinline bool kernel_path_shader_apply(KernelGlobals *kg,
float3 bg = make_float3(0.0f, 0.0f, 0.0f);
if (!kernel_data.background.transparent) {
- bg = indirect_background(kg, emission_sd, state, ray);
+ bg = indirect_background(kg, emission_sd, state, NULL, ray);
}
path_radiance_accum_shadowcatcher(L, throughput, bg);
}
@@ -319,7 +318,7 @@ ccl_device_forceinline bool kernel_path_shader_apply(KernelGlobals *kg,
if (sd->flag & SD_EMISSION) {
float3 emission = indirect_primitive_emission(
kg, sd, sd->ray_length, state->flag, state->ray_pdf);
- path_radiance_accum_emission(L, state, throughput, emission);
+ path_radiance_accum_emission(kg, L, state, throughput, emission);
}
#endif /* __EMISSION__ */
@@ -367,7 +366,7 @@ ccl_device_noinline
light_ray.dD = differential3_zero();
if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &ao_shadow)) {
- path_radiance_accum_ao(L, state, throughput, ao_alpha, ao_bsdf, ao_shadow);
+ path_radiance_accum_ao(kg, L, state, throughput, ao_alpha, ao_bsdf, ao_shadow);
}
else {
path_radiance_accum_total_ao(L, state, throughput, ao_bsdf);
@@ -418,7 +417,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
/* Shade background. */
if (!hit) {
- kernel_path_background(kg, state, ray, throughput, sd, L);
+ kernel_path_background(kg, state, ray, throughput, sd, NULL, L);
break;
}
else if (path_state_ao_bounce(kg, state)) {
@@ -434,7 +433,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
# endif
/* Evaluate shader. */
- shader_eval_surface(kg, sd, state, state->flag);
+ shader_eval_surface(kg, sd, state, NULL, state->flag);
shader_prepare_closures(sd, state);
/* Apply shadow catcher, holdout, emission. */
@@ -556,7 +555,7 @@ ccl_device_forceinline void kernel_path_integrate(KernelGlobals *kg,
/* Shade background. */
if (!hit) {
- kernel_path_background(kg, state, ray, throughput, &sd, L);
+ kernel_path_background(kg, state, ray, throughput, &sd, buffer, L);
break;
}
else if (path_state_ao_bounce(kg, state)) {
@@ -572,7 +571,7 @@ ccl_device_forceinline void kernel_path_integrate(KernelGlobals *kg,
# endif
/* Evaluate shader. */
- shader_eval_surface(kg, &sd, state, state->flag);
+ shader_eval_surface(kg, &sd, state, buffer, state->flag);
shader_prepare_closures(&sd, state);
/* Apply shadow catcher, holdout, emission. */
@@ -673,7 +672,7 @@ ccl_device void kernel_path_trace(
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
PathRadiance L;
- path_radiance_init(&L, kernel_data.film.use_light_pass);
+ path_radiance_init(kg, &L);
ShaderDataTinyStorage emission_sd_storage;
ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h
index ea6b23e7eb4..f75e4ab4c97 100644
--- a/intern/cycles/kernel/kernel_path_branched.h
+++ b/intern/cycles/kernel/kernel_path_branched.h
@@ -55,7 +55,7 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg,
if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &ao_shadow)) {
path_radiance_accum_ao(
- L, state, throughput * num_samples_inv, ao_alpha, ao_bsdf, ao_shadow);
+ kg, L, state, throughput * num_samples_inv, ao_alpha, ao_bsdf, ao_shadow);
}
else {
path_radiance_accum_total_ao(L, state, throughput * num_samples_inv, ao_bsdf);
@@ -146,7 +146,7 @@ ccl_device_forceinline void kernel_branched_path_volume(KernelGlobals *kg,
/* emission and transmittance */
if (volume_segment.closure_flag & SD_EMISSION)
- path_radiance_accum_emission(L, state, *throughput, volume_segment.accum_emission);
+ path_radiance_accum_emission(kg, L, state, *throughput, volume_segment.accum_emission);
*throughput *= volume_segment.accum_transmittance;
/* free cached steps */
@@ -376,7 +376,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
/* initialize */
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
- path_radiance_init(L, kernel_data.film.use_light_pass);
+ path_radiance_init(kg, L);
/* shader data memory used for both volumes and surfaces, saves stack space */
ShaderData sd;
@@ -405,7 +405,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
/* Shade background. */
if (!hit) {
- kernel_path_background(kg, &state, &ray, throughput, &sd, L);
+ kernel_path_background(kg, &state, &ray, throughput, &sd, buffer, L);
break;
}
@@ -417,7 +417,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
if (!(sd.flag & SD_HAS_ONLY_VOLUME)) {
# endif
- shader_eval_surface(kg, &sd, &state, state.flag);
+ shader_eval_surface(kg, &sd, &state, buffer, state.flag);
shader_merge_closures(&sd);
/* Apply shadow catcher, holdout, emission. */
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index a32690d51eb..ba48c0bdfc4 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -121,8 +121,14 @@ ccl_device_noinline_cpu void kernel_branched_path_surface_connect_light(
if (has_emission) {
if (!blocked) {
/* accumulate */
- path_radiance_accum_light(
- L, state, throughput * num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp);
+ path_radiance_accum_light(kg,
+ L,
+ state,
+ throughput * num_samples_inv,
+ &L_light,
+ shadow,
+ num_samples_inv,
+ is_lamp);
}
else {
path_radiance_accum_total_light(L, state, throughput * num_samples_inv, &L_light);
@@ -250,7 +256,7 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg,
if (has_emission) {
if (!blocked) {
/* accumulate */
- path_radiance_accum_light(L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
+ path_radiance_accum_light(kg, L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
}
else {
path_radiance_accum_total_light(L, state, throughput, &L_light);
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index db10629ee9f..a787910e65c 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -57,7 +57,7 @@ ccl_device_inline void kernel_path_volume_connect_light(KernelGlobals *kg,
if (has_emission && !blocked) {
/* accumulate */
- path_radiance_accum_light(L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
+ path_radiance_accum_light(kg, L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
}
# endif /* __EMISSION__ */
}
@@ -247,7 +247,7 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg,
if (has_emission && !blocked) {
/* accumulate */
path_radiance_accum_light(
- L, state, tp * num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp);
+ kg, L, state, tp * num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp);
}
}
}
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 7ccb99cad2a..d03faff4242 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -1076,6 +1076,7 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
ccl_device void shader_eval_surface(KernelGlobals *kg,
ShaderData *sd,
ccl_addr_space PathState *state,
+ ccl_global float *buffer,
int path_flag)
{
PROFILING_INIT(kg, PROFILING_SHADER_EVAL);
@@ -1107,7 +1108,7 @@ ccl_device void shader_eval_surface(KernelGlobals *kg,
#endif
{
#ifdef __SVM__
- svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag);
+ svm_eval_nodes(kg, sd, state, buffer, SHADER_TYPE_SURFACE, path_flag);
#else
if (sd->object == OBJECT_NONE) {
sd->closure_emission_background = make_float3(0.8f, 0.8f, 0.8f);
@@ -1319,7 +1320,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg,
else
# endif
{
- svm_eval_nodes(kg, sd, state, SHADER_TYPE_VOLUME, path_flag);
+ svm_eval_nodes(kg, sd, state, NULL, SHADER_TYPE_VOLUME, path_flag);
}
# endif
@@ -1348,7 +1349,7 @@ ccl_device void shader_eval_displacement(KernelGlobals *kg,
else
# endif
{
- svm_eval_nodes(kg, sd, state, SHADER_TYPE_DISPLACEMENT, 0);
+ svm_eval_nodes(kg, sd, state, NULL, SHADER_TYPE_DISPLACEMENT, 0);
}
#endif
}
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index 61fcc61264a..b3ae29932da 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -71,7 +71,7 @@ ccl_device_forceinline bool shadow_handle_transparent_isect(KernelGlobals *kg,
/* Attenuation from transparent surface. */
if (!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, shadow_sd, state, PATH_RAY_SHADOW);
+ shader_eval_surface(kg, shadow_sd, state, NULL, PATH_RAY_SHADOW);
path_state_modify_bounce(state, false);
*throughput *= shader_bsdf_transparency(kg, shadow_sd);
}
diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h
index dbe2c12ce81..23e30db1b08 100644
--- a/intern/cycles/kernel/kernel_subsurface.h
+++ b/intern/cycles/kernel/kernel_subsurface.h
@@ -138,7 +138,7 @@ ccl_device void subsurface_color_bump_blur(
if (bump || texture_blur > 0.0f) {
/* average color and normal at incoming point */
- shader_eval_surface(kg, sd, state, state->flag);
+ shader_eval_surface(kg, sd, state, NULL, state->flag);
float3 in_color = shader_bssrdf_sum(sd, (bump) ? N : NULL, NULL);
/* we simply divide out the average color and multiply with the average
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 7306c32d7c8..c35e345763a 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -222,6 +222,8 @@ typedef enum ShaderEvalType {
SHADER_EVAL_TRANSMISSION_COLOR,
SHADER_EVAL_SUBSURFACE_COLOR,
SHADER_EVAL_EMISSION,
+ SHADER_EVAL_AOV_COLOR,
+ SHADER_EVAL_AOV_VALUE,
/* light passes */
SHADER_EVAL_AO,
@@ -371,6 +373,8 @@ typedef enum PassType {
#endif
PASS_RENDER_TIME,
PASS_CRYPTOMATTE,
+ PASS_AOV_COLOR,
+ PASS_AOV_VALUE,
PASS_CATEGORY_MAIN_END = 31,
PASS_MIST = 32,
@@ -1244,6 +1248,11 @@ typedef struct KernelFilm {
int pass_denoising_clean;
int denoising_flags;
+ int pass_aov_color;
+ int pass_aov_value;
+ int pad1;
+ int pad2;
+
/* XYZ to rendering color space transform. float4 instead of float3 to
* ensure consistent padding/alignment across devices. */
float4 xyz_to_r;
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 4ddcbec0fef..f443bb88463 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -504,7 +504,7 @@ kernel_volume_integrate_homogeneous(KernelGlobals *kg,
float3 transmittance = volume_color_transmittance(coeff.sigma_t, ray->t);
float3 emission = kernel_volume_emission_integrate(
&coeff, closure_flag, transmittance, ray->t);
- path_radiance_accum_emission(L, state, *throughput, emission);
+ path_radiance_accum_emission(kg, L, state, *throughput, emission);
}
/* modify throughput */
@@ -629,7 +629,7 @@ kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg,
if (L && (closure_flag & SD_EMISSION)) {
float3 emission = kernel_volume_emission_integrate(
&coeff, closure_flag, transmittance, dt);
- path_radiance_accum_emission(L, state, tp, emission);
+ path_radiance_accum_emission(kg, L, state, tp, emission);
}
/* modify throughput */
diff --git a/intern/cycles/kernel/kernel_write_passes.h b/intern/cycles/kernel/kernel_write_passes.h
new file mode 100644
index 00000000000..410218d91d4
--- /dev/null
+++ b/intern/cycles/kernel/kernel_write_passes.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(__SPLIT_KERNEL__) || defined(__KERNEL_CUDA__)
+# define __ATOMIC_PASS_WRITE__
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, float value)
+{
+ ccl_global float *buf = buffer;
+#ifdef __ATOMIC_PASS_WRITE__
+ atomic_add_and_fetch_float(buf, value);
+#else
+ *buf += value;
+#endif
+}
+
+ccl_device_inline void kernel_write_pass_float3(ccl_global float *buffer, float3 value)
+{
+#ifdef __ATOMIC_PASS_WRITE__
+ ccl_global float *buf_x = buffer + 0;
+ ccl_global float *buf_y = buffer + 1;
+ ccl_global float *buf_z = buffer + 2;
+
+ atomic_add_and_fetch_float(buf_x, value.x);
+ atomic_add_and_fetch_float(buf_y, value.y);
+ atomic_add_and_fetch_float(buf_z, value.z);
+#else
+ ccl_global float3 *buf = (ccl_global float3 *)buffer;
+ *buf += value;
+#endif
+}
+
+ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, float4 value)
+{
+#ifdef __ATOMIC_PASS_WRITE__
+ ccl_global float *buf_x = buffer + 0;
+ ccl_global float *buf_y = buffer + 1;
+ ccl_global float *buf_z = buffer + 2;
+ ccl_global float *buf_w = buffer + 3;
+
+ atomic_add_and_fetch_float(buf_x, value.x);
+ atomic_add_and_fetch_float(buf_y, value.y);
+ atomic_add_and_fetch_float(buf_z, value.z);
+ atomic_add_and_fetch_float(buf_w, value.w);
+#else
+ ccl_global float4 *buf = (ccl_global float4 *)buffer;
+ *buf += value;
+#endif
+}
+
+#ifdef __DENOISING_FEATURES__
+ccl_device_inline void kernel_write_pass_float_variance(ccl_global float *buffer, float value)
+{
+ kernel_write_pass_float(buffer, value);
+
+ /* The online one-pass variance update that's used for the megakernel can't easily be implemented
+ * with atomics, so for the split kernel the E[x^2] - 1/N * (E[x])^2 fallback is used. */
+ kernel_write_pass_float(buffer + 1, value * value);
+}
+
+# ifdef __ATOMIC_PASS_WRITE__
+# define kernel_write_pass_float3_unaligned kernel_write_pass_float3
+# else
+ccl_device_inline void kernel_write_pass_float3_unaligned(ccl_global float *buffer, float3 value)
+{
+ buffer[0] += value.x;
+ buffer[1] += value.y;
+ buffer[2] += value.z;
+}
+# endif
+
+ccl_device_inline void kernel_write_pass_float3_variance(ccl_global float *buffer, float3 value)
+{
+ kernel_write_pass_float3_unaligned(buffer, value);
+ kernel_write_pass_float3_unaligned(buffer + 3, value * value);
+}
+#endif /* __DENOISING_FEATURES__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 1b161fbc8ee..767bd7702ae 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -44,6 +44,7 @@
#include "kernel/kernel_globals.h"
#include "kernel/kernel_color.h"
#include "kernel/kernel_random.h"
+#include "kernel/kernel_write_passes.h"
#include "kernel/kernel_projection.h"
#include "kernel/kernel_differential.h"
#include "kernel/kernel_montecarlo.h"
diff --git a/intern/cycles/kernel/shaders/node_clamp.osl b/intern/cycles/kernel/shaders/node_clamp.osl
index 87dc1ccdb12..d689ba7f809 100644
--- a/intern/cycles/kernel/shaders/node_clamp.osl
+++ b/intern/cycles/kernel/shaders/node_clamp.osl
@@ -16,7 +16,11 @@
#include "stdosl.h"
-shader node_clamp(float Value = 1.0, float Min = 0.0, float Max = 1.0, output float Result = 0.0)
+shader node_clamp(string type = "minmax",
+ float Value = 1.0,
+ float Min = 0.0,
+ float Max = 1.0,
+ output float Result = 0.0)
{
- Result = clamp(Value, Min, Max);
+ Result = (type == "range" && (Min > Max)) ? clamp(Value, Max, Min) : clamp(Value, Min, Max);
}
diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl
index f78ca7ec0e8..9a0f2d054ea 100644
--- a/intern/cycles/kernel/shaders/node_image_texture.osl
+++ b/intern/cycles/kernel/shaders/node_image_texture.osl
@@ -63,11 +63,21 @@ color image_texture_lookup(string filename,
int ignore_alpha,
int unassociate_alpha,
int is_float,
+ int is_tiled,
string interpolation,
string extension)
{
+ /* Flip the y coordinate, but preserve UDIM tiles. */
+ float flip_v;
+ if (is_tiled) {
+ float v_i = (int)v;
+ flip_v = v_i + (1.0 - (v - v_i));
+ }
+ else {
+ flip_v = 1.0 - v;
+ }
color rgb = (color)texture(
- filename, u, 1.0 - v, "wrap", extension, "interp", interpolation, "alpha", Alpha);
+ filename, u, flip_v, "wrap", extension, "interp", interpolation, "alpha", Alpha);
if (ignore_alpha) {
Alpha = 1.0;
@@ -97,6 +107,7 @@ shader node_image_texture(int use_mapping = 0,
int compress_as_srgb = 0,
int ignore_alpha = 0,
int unassociate_alpha = 0,
+ int is_tiled = 0,
int is_float = 1,
output color Color = 0.0,
output float Alpha = 1.0)
@@ -115,6 +126,7 @@ shader node_image_texture(int use_mapping = 0,
ignore_alpha,
unassociate_alpha,
is_float,
+ is_tiled,
interpolation,
extension);
}
@@ -193,6 +205,7 @@ shader node_image_texture(int use_mapping = 0,
ignore_alpha,
unassociate_alpha,
is_float,
+ 0,
interpolation,
extension);
Alpha += weight[0] * tmp_alpha;
@@ -206,6 +219,7 @@ shader node_image_texture(int use_mapping = 0,
ignore_alpha,
unassociate_alpha,
is_float,
+ 0,
interpolation,
extension);
Alpha += weight[1] * tmp_alpha;
@@ -219,6 +233,7 @@ shader node_image_texture(int use_mapping = 0,
ignore_alpha,
unassociate_alpha,
is_float,
+ 0,
interpolation,
extension);
Alpha += weight[2] * tmp_alpha;
@@ -234,6 +249,7 @@ shader node_image_texture(int use_mapping = 0,
ignore_alpha,
unassociate_alpha,
is_float,
+ 0,
interpolation,
extension);
}
@@ -247,6 +263,7 @@ shader node_image_texture(int use_mapping = 0,
ignore_alpha,
unassociate_alpha,
is_float,
+ 0,
interpolation,
extension);
}
diff --git a/intern/cycles/kernel/shaders/node_map_range.osl b/intern/cycles/kernel/shaders/node_map_range.osl
index 8a28edf5f35..242ec4271ed 100644
--- a/intern/cycles/kernel/shaders/node_map_range.osl
+++ b/intern/cycles/kernel/shaders/node_map_range.osl
@@ -16,14 +16,43 @@
#include "stdosl.h"
-shader node_map_range(float Value = 1.0,
+float safe_divide(float a, float b)
+{
+ return (b != 0.0) ? a / b : 0.0;
+}
+
+float smootherstep(float edge0, float edge1, float x)
+{
+ float t = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0);
+ return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
+}
+
+shader node_map_range(string type = "linear",
+ float Value = 1.0,
float FromMin = 0.0,
float FromMax = 1.0,
float ToMin = 0.0,
float ToMax = 1.0,
+ float Steps = 4.0,
output float Result = 0.0)
{
if (FromMax != FromMin) {
- Result = ToMin + ((Value - FromMin) / (FromMax - FromMin)) * (ToMax - ToMin);
+ float Factor = Value;
+ if (type == "stepped") {
+ Factor = (Value - FromMin) / (FromMax - FromMin);
+ Factor = (Steps > 0) ? floor(Factor * (Steps + 1.0)) / Steps : 0.0;
+ }
+ else if (type == "smoothstep") {
+ Factor = (FromMin > FromMax) ? 1.0 - smoothstep(FromMax, FromMin, Value) :
+ smoothstep(FromMin, FromMax, Value);
+ }
+ else if (type == "smootherstep") {
+ Factor = (FromMin > FromMax) ? 1.0 - smootherstep(FromMax, FromMin, Value) :
+ smootherstep(FromMin, FromMax, Value);
+ }
+ else {
+ Factor = (Value - FromMin) / (FromMax - FromMin);
+ }
+ Result = ToMin + Factor * (ToMax - ToMin);
}
}
diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl
index 13e4c91ba10..1eccb56405b 100644
--- a/intern/cycles/kernel/shaders/node_math.osl
+++ b/intern/cycles/kernel/shaders/node_math.osl
@@ -26,6 +26,35 @@ float safe_modulo(float a, float b)
return (b != 0.0) ? fmod(a, b) : 0.0;
}
+float fract(float a)
+{
+ return a - floor(a);
+}
+
+/* Adapted from godotengine math_funcs.h. */
+float wrap(float value, float max, float min)
+{
+ float range = max - min;
+ return (range != 0.0) ? value - (range * floor((value - min) / range)) : min;
+}
+
+/* See: https://www.iquilezles.org/www/articles/smin/smin.htm. */
+float smoothmin(float a, float b, float c)
+{
+ if (c != 0.0) {
+ float h = max(c - abs(a - b), 0.0) / c;
+ return min(a, b) - h * h * h * c * (1.0 / 6.0);
+ }
+ else {
+ return min(a, b);
+ }
+}
+
+float pingpong(float a, float b)
+{
+ return (b != 0.0) ? abs(fract((a - b) / (b * 2.0)) * b * 2.0 - b) : 0.0;
+}
+
float safe_sqrt(float a)
{
return (a > 0.0) ? sqrt(a) : 0.0;
@@ -40,6 +69,7 @@ float safe_log(float a, float b)
shader node_math(string type = "add",
float Value1 = 0.5,
float Value2 = 0.5,
+ float Value3 = 0.5,
output float Value = 0.0)
{
if (type == "add")
@@ -56,8 +86,14 @@ shader node_math(string type = "add",
Value = safe_log(Value1, Value2);
else if (type == "sqrt")
Value = safe_sqrt(Value1);
+ else if (type == "inversesqrt")
+ Value = inversesqrt(Value1);
else if (type == "absolute")
Value = fabs(Value1);
+ else if (type == "radians")
+ Value = radians(Value1);
+ else if (type == "degrees")
+ Value = degrees(Value1);
else if (type == "minimum")
Value = min(Value1, Value2);
else if (type == "maximum")
@@ -76,12 +112,26 @@ shader node_math(string type = "add",
Value = Value1 - floor(Value1);
else if (type == "modulo")
Value = safe_modulo(Value1, Value2);
+ else if (type == "trunc")
+ Value = trunc(Value1);
+ else if (type == "snap")
+ Value = floor(safe_divide(Value1, Value2)) * Value2;
+ else if (type == "wrap")
+ Value = wrap(Value1, Value2, Value3);
+ else if (type == "pingpong")
+ Value = pingpong(Value1, Value2);
else if (type == "sine")
Value = sin(Value1);
else if (type == "cosine")
Value = cos(Value1);
else if (type == "tangent")
Value = tan(Value1);
+ else if (type == "sinh")
+ Value = sinh(Value1);
+ else if (type == "cosh")
+ Value = cosh(Value1);
+ else if (type == "tanh")
+ Value = tanh(Value1);
else if (type == "arcsine")
Value = asin(Value1);
else if (type == "arccosine")
@@ -90,6 +140,18 @@ shader node_math(string type = "add",
Value = atan(Value1);
else if (type == "arctan2")
Value = atan2(Value1, Value2);
+ else if (type == "sign")
+ Value = sign(Value1);
+ else if (type == "exponent")
+ Value = exp(Value1);
+ else if (type == "compare")
+ Value = ((Value1 == Value2) || (abs(Value1 - Value2) <= max(Value3, 1e-5))) ? 1.0 : 0.0;
+ else if (type == "multiply_add")
+ Value = Value1 * Value2 + Value3;
+ else if (type == "smoothmin")
+ Value = smoothmin(Value1, Value2, Value3);
+ else if (type == "smoothmax")
+ Value = -(smoothmin(-Value1, -Value2, Value3));
else
warning("%s", "Unknown math operator!");
}
diff --git a/intern/cycles/kernel/shaders/node_noise_texture.osl b/intern/cycles/kernel/shaders/node_noise_texture.osl
index e3da2d16371..6cff1cdab2c 100644
--- a/intern/cycles/kernel/shaders/node_noise_texture.osl
+++ b/intern/cycles/kernel/shaders/node_noise_texture.osl
@@ -59,7 +59,7 @@ float noise_texture(float co, float detail, float distortion, output color Color
{
float p = co;
if (distortion != 0.0) {
- p += safe_noise(p + random_float_offset(0.0)) * distortion;
+ p += safe_snoise(p + random_float_offset(0.0)) * distortion;
}
float value = fractal_noise(p, detail);
@@ -73,8 +73,8 @@ float noise_texture(vector2 co, float detail, float distortion, output color Col
{
vector2 p = co;
if (distortion != 0.0) {
- p += vector2(safe_noise(p + random_vector2_offset(0.0)) * distortion,
- safe_noise(p + random_vector2_offset(1.0)) * distortion);
+ p += vector2(safe_snoise(p + random_vector2_offset(0.0)) * distortion,
+ safe_snoise(p + random_vector2_offset(1.0)) * distortion);
}
float value = fractal_noise(p, detail);
@@ -88,9 +88,9 @@ float noise_texture(vector3 co, float detail, float distortion, output color Col
{
vector3 p = co;
if (distortion != 0.0) {
- p += vector3(safe_noise(p + random_vector3_offset(0.0)) * distortion,
- safe_noise(p + random_vector3_offset(1.0)) * distortion,
- safe_noise(p + random_vector3_offset(2.0)) * distortion);
+ p += vector3(safe_snoise(p + random_vector3_offset(0.0)) * distortion,
+ safe_snoise(p + random_vector3_offset(1.0)) * distortion,
+ safe_snoise(p + random_vector3_offset(2.0)) * distortion);
}
float value = fractal_noise(p, detail);
@@ -104,10 +104,10 @@ float noise_texture(vector4 co, float detail, float distortion, output color Col
{
vector4 p = co;
if (distortion != 0.0) {
- p += vector4(safe_noise(p + random_vector4_offset(0.0)) * distortion,
- safe_noise(p + random_vector4_offset(1.0)) * distortion,
- safe_noise(p + random_vector4_offset(2.0)) * distortion,
- safe_noise(p + random_vector4_offset(3.0)) * distortion);
+ p += vector4(safe_snoise(p + random_vector4_offset(0.0)) * distortion,
+ safe_snoise(p + random_vector4_offset(1.0)) * distortion,
+ safe_snoise(p + random_vector4_offset(2.0)) * distortion,
+ safe_snoise(p + random_vector4_offset(3.0)) * distortion);
}
float value = fractal_noise(p, detail);
diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl
index 60591b79b33..a706c442368 100644
--- a/intern/cycles/kernel/shaders/node_wave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_wave_texture.osl
@@ -31,7 +31,7 @@ float wave(point p, string type, string profile, float detail, float distortion,
}
if (distortion != 0.0) {
- n = n + (distortion * fractal_noise(p * dscale, detail));
+ n = n + (distortion * (fractal_noise(p * dscale, detail) * 2.0 - 1.0));
}
if (profile == "sine") {
diff --git a/intern/cycles/kernel/split/kernel_branched.h b/intern/cycles/kernel/split/kernel_branched.h
index e08d87ab618..bfcd21baac4 100644
--- a/intern/cycles/kernel/split/kernel_branched.h
+++ b/intern/cycles/kernel/split/kernel_branched.h
@@ -106,7 +106,7 @@ ccl_device_inline bool kernel_split_branched_indirect_start_shared(KernelGlobals
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
PathRadiance *inactive_L = &kernel_split_state.path_radiance[inactive_ray];
- path_radiance_init(inactive_L, kernel_data.film.use_light_pass);
+ path_radiance_init(kg, inactive_L);
path_radiance_copy_indirect(inactive_L, L);
ray_state[inactive_ray] = RAY_REGENERATED;
diff --git a/intern/cycles/kernel/split/kernel_buffer_update.h b/intern/cycles/kernel/split/kernel_buffer_update.h
index e37be5b405e..dba1768f03f 100644
--- a/intern/cycles/kernel/split/kernel_buffer_update.h
+++ b/intern/cycles/kernel/split/kernel_buffer_update.h
@@ -135,7 +135,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg,
* These rays proceed with path-iteration.
*/
*throughput = make_float3(1.0f, 1.0f, 1.0f);
- path_radiance_init(L, kernel_data.film.use_light_pass);
+ path_radiance_init(kg, L);
path_state_init(kg,
AS_SHADER_DATA(&kernel_split_state.sd_DL_shadow[ray_index]),
state,
diff --git a/intern/cycles/kernel/split/kernel_indirect_background.h b/intern/cycles/kernel/split/kernel_indirect_background.h
index b1c65f61e2c..6d500650cc0 100644
--- a/intern/cycles/kernel/split/kernel_indirect_background.h
+++ b/intern/cycles/kernel/split/kernel_indirect_background.h
@@ -58,8 +58,10 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg)
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
float3 throughput = kernel_split_state.throughput[ray_index];
ShaderData *sd = kernel_split_sd(sd, ray_index);
+ uint buffer_offset = kernel_split_state.buffer_offset[ray_index];
+ ccl_global float *buffer = kernel_split_params.tile.buffer + buffer_offset;
- kernel_path_background(kg, state, ray, throughput, sd, L);
+ kernel_path_background(kg, state, ray, throughput, sd, buffer, L);
kernel_split_path_end(kg, ray_index);
}
}
diff --git a/intern/cycles/kernel/split/kernel_path_init.h b/intern/cycles/kernel/split/kernel_path_init.h
index 3faa3208341..82b0f583d8d 100644
--- a/intern/cycles/kernel/split/kernel_path_init.h
+++ b/intern/cycles/kernel/split/kernel_path_init.h
@@ -59,8 +59,7 @@ ccl_device void kernel_path_init(KernelGlobals *kg)
* These rays proceed with path-iteration.
*/
kernel_split_state.throughput[ray_index] = make_float3(1.0f, 1.0f, 1.0f);
- path_radiance_init(&kernel_split_state.path_radiance[ray_index],
- kernel_data.film.use_light_pass);
+ path_radiance_init(kg, &kernel_split_state.path_radiance[ray_index]);
path_state_init(kg,
AS_SHADER_DATA(&kernel_split_state.sd_DL_shadow[ray_index]),
&kernel_split_state.path_state[ray_index],
diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h
index 8e39c9797e5..c760a2b2049 100644
--- a/intern/cycles/kernel/split/kernel_shader_eval.h
+++ b/intern/cycles/kernel/split/kernel_shader_eval.h
@@ -50,8 +50,10 @@ ccl_device void kernel_shader_eval(KernelGlobals *kg)
ccl_global char *ray_state = kernel_split_state.ray_state;
if (IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
+ uint buffer_offset = kernel_split_state.buffer_offset[ray_index];
+ ccl_global float *buffer = kernel_split_params.tile.buffer + buffer_offset;
- shader_eval_surface(kg, kernel_split_sd(sd, ray_index), state, state->flag);
+ shader_eval_surface(kg, kernel_split_sd(sd, ray_index), state, buffer, state->flag);
#ifdef __BRANCHED_PATH__
if (kernel_data.integrator.branched) {
shader_merge_closures(kernel_split_sd(sd, ray_index));
diff --git a/intern/cycles/kernel/split/kernel_shadow_blocked_dl.h b/intern/cycles/kernel/split/kernel_shadow_blocked_dl.h
index 82990ce9fae..5e46d300bca 100644
--- a/intern/cycles/kernel/split/kernel_shadow_blocked_dl.h
+++ b/intern/cycles/kernel/split/kernel_shadow_blocked_dl.h
@@ -87,7 +87,7 @@ ccl_device void kernel_shadow_blocked_dl(KernelGlobals *kg)
if (!shadow_blocked(kg, sd, emission_sd, state, &ray, &shadow)) {
/* accumulate */
- path_radiance_accum_light(L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
+ path_radiance_accum_light(kg, L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
}
else {
path_radiance_accum_total_light(L, state, throughput, &L_light);
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 18f086d6726..fd2833ee687 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -164,6 +164,7 @@ CCL_NAMESPACE_END
#include "kernel/svm/svm_math_util.h"
#include "kernel/svm/svm_mapping_util.h"
+#include "kernel/svm/svm_aov.h"
#include "kernel/svm/svm_attribute.h"
#include "kernel/svm/svm_gradient.h"
#include "kernel/svm/svm_blackbody.h"
@@ -218,6 +219,7 @@ CCL_NAMESPACE_BEGIN
ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
ShaderData *sd,
ccl_addr_space PathState *state,
+ ccl_global float *buffer,
ShaderType type,
int path_flag)
{
@@ -309,7 +311,7 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */
# ifdef __TEXTURES__
case NODE_TEX_IMAGE:
- svm_node_tex_image(kg, sd, stack, node);
+ svm_node_tex_image(kg, sd, stack, node, &offset);
break;
case NODE_TEX_IMAGE_BOX:
svm_node_tex_image_box(kg, sd, stack, node);
@@ -467,6 +469,17 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
case NODE_IES:
svm_node_ies(kg, sd, stack, node, &offset);
break;
+ case NODE_AOV_START:
+ if (!svm_node_aov_check(state, buffer)) {
+ return;
+ }
+ break;
+ case NODE_AOV_COLOR:
+ svm_node_aov_color(kg, sd, stack, node, buffer);
+ break;
+ case NODE_AOV_VALUE:
+ svm_node_aov_value(kg, sd, stack, node, buffer);
+ break;
# endif /* __EXTRA_NODES__ */
#endif /* NODES_GROUP(NODE_GROUP_LEVEL_2) */
diff --git a/intern/cycles/kernel/svm/svm_aov.h b/intern/cycles/kernel/svm/svm_aov.h
new file mode 100644
index 00000000000..899e466d099
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_aov.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline bool svm_node_aov_check(ccl_addr_space PathState *state,
+ ccl_global float *buffer)
+{
+ int path_flag = state->flag;
+
+ bool is_primary = (path_flag & PATH_RAY_CAMERA) && (!(path_flag & PATH_RAY_SINGLE_PASS_DONE));
+
+ return ((buffer != NULL) && is_primary);
+}
+
+ccl_device void svm_node_aov_color(
+ KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, ccl_global float *buffer)
+{
+ float3 val = stack_load_float3(stack, node.y);
+
+ if (buffer) {
+ kernel_write_pass_float4(buffer + kernel_data.film.pass_aov_color + 4 * node.z,
+ make_float4(val.x, val.y, val.z, 1.0f));
+ }
+}
+
+ccl_device void svm_node_aov_value(
+ KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, ccl_global float *buffer)
+{
+ float val = stack_load_float(stack, node.y);
+
+ if (buffer) {
+ kernel_write_pass_float(buffer + kernel_data.film.pass_aov_value + node.z, val);
+ }
+}
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_bevel.h b/intern/cycles/kernel/svm/svm_bevel.h
index 434502f31f9..bf5957ec9e4 100644
--- a/intern/cycles/kernel/svm/svm_bevel.h
+++ b/intern/cycles/kernel/svm/svm_bevel.h
@@ -53,7 +53,7 @@ ccl_device_noinline float3 svm_bevel(KernelGlobals *kg,
float3 sum_N = make_float3(0.0f, 0.0f, 0.0f);
for (int sample = 0; sample < num_samples; sample++) {
- float disk_u = 0.0f, disk_v = 0.0f;
+ float disk_u, disk_v;
path_branched_rng_2D(
kg, state->rng_hash, state, sample, num_samples, PRNG_BEVEL_U, &disk_u, &disk_v);
diff --git a/intern/cycles/kernel/svm/svm_clamp.h b/intern/cycles/kernel/svm/svm_clamp.h
index a45e70a3f15..a85fd82754e 100644
--- a/intern/cycles/kernel/svm/svm_clamp.h
+++ b/intern/cycles/kernel/svm/svm_clamp.h
@@ -26,8 +26,8 @@ ccl_device void svm_node_clamp(KernelGlobals *kg,
uint result_stack_offset,
int *offset)
{
- uint min_stack_offset, max_stack_offset;
- svm_unpack_node_uchar2(parameters_stack_offsets, &min_stack_offset, &max_stack_offset);
+ uint min_stack_offset, max_stack_offset, type;
+ svm_unpack_node_uchar3(parameters_stack_offsets, &min_stack_offset, &max_stack_offset, &type);
uint4 defaults = read_node(kg, offset);
@@ -35,7 +35,12 @@ ccl_device void svm_node_clamp(KernelGlobals *kg,
float min = stack_load_float_default(stack, min_stack_offset, defaults.x);
float max = stack_load_float_default(stack, max_stack_offset, defaults.y);
- stack_store_float(stack, result_stack_offset, clamp(value, min, max));
+ if (type == NODE_CLAMP_RANGE && (min > max)) {
+ stack_store_float(stack, result_stack_offset, clamp(value, max, min));
+ }
+ else {
+ stack_store_float(stack, result_stack_offset, clamp(value, min, max));
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
index 64abdd2d8b3..90f1a7845c7 100644
--- a/intern/cycles/kernel/svm/svm_image.h
+++ b/intern/cycles/kernel/svm/svm_image.h
@@ -20,6 +20,11 @@ CCL_NAMESPACE_BEGIN
ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint flags)
{
+ if (id == -1) {
+ return make_float4(
+ TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
+ }
+
float4 r = kernel_tex_image_interp(kg, id, x, y);
const float alpha = r.w;
@@ -45,9 +50,9 @@ ccl_device_inline float3 texco_remap_square(float3 co)
return (co - make_float3(0.5f, 0.5f, 0.5f)) * 2.0f;
}
-ccl_device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
+ccl_device void svm_node_tex_image(
+ KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
{
- uint id = node.y;
uint co_offset, out_offset, alpha_offset, flags;
svm_unpack_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &flags);
@@ -65,6 +70,50 @@ ccl_device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *sta
else {
tex_co = make_float2(co.x, co.y);
}
+
+ /* TODO(lukas): Consider moving tile information out of the SVM node.
+ * TextureInfo seems a reasonable candidate. */
+ int id = -1;
+ int num_nodes = (int)node.y;
+ if (num_nodes > 0) {
+ /* Remember the offset of the node following the tile nodes. */
+ int next_offset = (*offset) + num_nodes;
+
+ /* Find the tile that the UV lies in. */
+ int tx = (int)tex_co.x;
+ int ty = (int)tex_co.y;
+
+ /* Check that we're within a legitimate tile. */
+ if (tx >= 0 && ty >= 0 && tx < 10) {
+ int tile = 1001 + 10 * ty + tx;
+
+ /* Find the index of the tile. */
+ for (int i = 0; i < num_nodes; i++) {
+ uint4 tile_node = read_node(kg, offset);
+ if (tile_node.x == tile) {
+ id = tile_node.y;
+ break;
+ }
+ if (tile_node.z == tile) {
+ id = tile_node.w;
+ break;
+ }
+ }
+
+ /* If we found the tile, offset the UVs to be relative to it. */
+ if (id != -1) {
+ tex_co.x -= tx;
+ tex_co.y -= ty;
+ }
+ }
+
+ /* Skip over the remaining nodes. */
+ *offset = next_offset;
+ }
+ else {
+ id = -num_nodes;
+ }
+
float4 f = svm_image_texture(kg, id, tex_co.x, tex_co.y, flags);
if (stack_valid(out_offset))
diff --git a/intern/cycles/kernel/svm/svm_map_range.h b/intern/cycles/kernel/svm/svm_map_range.h
index f2a68adbe61..533a631c837 100644
--- a/intern/cycles/kernel/svm/svm_map_range.h
+++ b/intern/cycles/kernel/svm/svm_map_range.h
@@ -18,32 +18,66 @@ CCL_NAMESPACE_BEGIN
/* Map Range Node */
+ccl_device_inline float smootherstep(float edge0, float edge1, float x)
+{
+ x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0f, 1.0f);
+ return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f);
+}
+
ccl_device void svm_node_map_range(KernelGlobals *kg,
ShaderData *sd,
float *stack,
uint value_stack_offset,
uint parameters_stack_offsets,
- uint result_stack_offset,
+ uint results_stack_offsets,
int *offset)
{
uint from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset;
+ uint type_stack_offset, steps_stack_offset, result_stack_offset;
svm_unpack_node_uchar4(parameters_stack_offsets,
&from_min_stack_offset,
&from_max_stack_offset,
&to_min_stack_offset,
&to_max_stack_offset);
+ svm_unpack_node_uchar3(
+ results_stack_offsets, &type_stack_offset, &steps_stack_offset, &result_stack_offset);
uint4 defaults = read_node(kg, offset);
+ uint4 defaults2 = read_node(kg, offset);
float value = stack_load_float(stack, value_stack_offset);
float from_min = stack_load_float_default(stack, from_min_stack_offset, defaults.x);
float from_max = stack_load_float_default(stack, from_max_stack_offset, defaults.y);
float to_min = stack_load_float_default(stack, to_min_stack_offset, defaults.z);
float to_max = stack_load_float_default(stack, to_max_stack_offset, defaults.w);
+ float steps = stack_load_float_default(stack, steps_stack_offset, defaults2.x);
float result;
+
if (from_max != from_min) {
- result = to_min + ((value - from_min) / (from_max - from_min)) * (to_max - to_min);
+ float factor = value;
+ switch (type_stack_offset) {
+ default:
+ case NODE_MAP_RANGE_LINEAR:
+ factor = (value - from_min) / (from_max - from_min);
+ break;
+ case NODE_MAP_RANGE_STEPPED: {
+ factor = (value - from_min) / (from_max - from_min);
+ factor = (steps > 0.0f) ? floorf(factor * (steps + 1.0f)) / steps : 0.0f;
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ factor = (from_min > from_max) ? 1.0f - smoothstep(from_max, from_min, factor) :
+ smoothstep(from_min, from_max, factor);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ factor = (from_min > from_max) ? 1.0f - smootherstep(from_max, from_min, factor) :
+ smootherstep(from_min, from_max, factor);
+ break;
+ }
+ }
+ result = to_min + factor * (to_max - to_min);
}
else {
result = 0.0f;
diff --git a/intern/cycles/kernel/svm/svm_math.h b/intern/cycles/kernel/svm/svm_math.h
index d156dec497c..82cae7bbacf 100644
--- a/intern/cycles/kernel/svm/svm_math.h
+++ b/intern/cycles/kernel/svm/svm_math.h
@@ -24,12 +24,13 @@ ccl_device void svm_node_math(KernelGlobals *kg,
uint result_stack_offset,
int *offset)
{
- uint a_stack_offset, b_stack_offset;
- svm_unpack_node_uchar2(inputs_stack_offsets, &a_stack_offset, &b_stack_offset);
+ uint a_stack_offset, b_stack_offset, c_stack_offset;
+ svm_unpack_node_uchar3(inputs_stack_offsets, &a_stack_offset, &b_stack_offset, &c_stack_offset);
float a = stack_load_float(stack, a_stack_offset);
float b = stack_load_float(stack, b_stack_offset);
- float result = svm_math((NodeMathType)type, a, b);
+ float c = stack_load_float(stack, c_stack_offset);
+ float result = svm_math((NodeMathType)type, a, b, c);
stack_store_float(stack, result_stack_offset, result);
}
diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h
index c07a1e4ed98..7b9eaaeb710 100644
--- a/intern/cycles/kernel/svm/svm_math_util.h
+++ b/intern/cycles/kernel/svm/svm_math_util.h
@@ -86,7 +86,7 @@ ccl_device void svm_vector_math(
}
}
-ccl_device float svm_math(NodeMathType type, float a, float b)
+ccl_device float svm_math(NodeMathType type, float a, float b, float c)
{
switch (type) {
case NODE_MATH_ADD:
@@ -103,8 +103,14 @@ ccl_device float svm_math(NodeMathType type, float a, float b)
return safe_logf(a, b);
case NODE_MATH_SQRT:
return safe_sqrtf(a);
+ case NODE_MATH_INV_SQRT:
+ return inversesqrtf(a);
case NODE_MATH_ABSOLUTE:
return fabsf(a);
+ case NODE_MATH_RADIANS:
+ return a * (M_PI_F / 180.0f);
+ case NODE_MATH_DEGREES:
+ return a * (180.0f / M_PI_F);
case NODE_MATH_MINIMUM:
return fminf(a, b);
case NODE_MATH_MAXIMUM:
@@ -123,12 +129,26 @@ ccl_device float svm_math(NodeMathType type, float a, float b)
return a - floorf(a);
case NODE_MATH_MODULO:
return safe_modulo(a, b);
+ case NODE_MATH_TRUNC:
+ return a >= 0.0f ? floorf(a) : ceilf(a);
+ case NODE_MATH_SNAP:
+ return floorf(safe_divide(a, b)) * b;
+ case NODE_MATH_WRAP:
+ return wrapf(a, b, c);
+ case NODE_MATH_PINGPONG:
+ return pingpongf(a, b);
case NODE_MATH_SINE:
return sinf(a);
case NODE_MATH_COSINE:
return cosf(a);
case NODE_MATH_TANGENT:
return tanf(a);
+ case NODE_MATH_SINH:
+ return sinhf(a);
+ case NODE_MATH_COSH:
+ return coshf(a);
+ case NODE_MATH_TANH:
+ return tanhf(a);
case NODE_MATH_ARCSINE:
return safe_asinf(a);
case NODE_MATH_ARCCOSINE:
@@ -137,6 +157,18 @@ ccl_device float svm_math(NodeMathType type, float a, float b)
return atanf(a);
case NODE_MATH_ARCTAN2:
return atan2f(a, b);
+ case NODE_MATH_SIGN:
+ return compatible_signf(a);
+ case NODE_MATH_EXPONENT:
+ return expf(a);
+ case NODE_MATH_COMPARE:
+ return ((a == b) || (fabsf(a - b) <= fmaxf(c, FLT_EPSILON))) ? 1.0f : 0.0f;
+ case NODE_MATH_MULTIPLY_ADD:
+ return a * b + c;
+ case NODE_MATH_SMOOTH_MIN:
+ return smoothminf(a, b, c);
+ case NODE_MATH_SMOOTH_MAX:
+ return -smoothminf(-a, -b, c);
default:
return 0.0f;
}
diff --git a/intern/cycles/kernel/svm/svm_noisetex.h b/intern/cycles/kernel/svm/svm_noisetex.h
index c5a1e43a729..12884c6cb25 100644
--- a/intern/cycles/kernel/svm/svm_noisetex.h
+++ b/intern/cycles/kernel/svm/svm_noisetex.h
@@ -55,7 +55,7 @@ ccl_device void noise_texture_1d(
{
float p = co;
if (distortion != 0.0f) {
- p += noise_1d(p + random_float_offset(0.0f)) * distortion;
+ p += snoise_1d(p + random_float_offset(0.0f)) * distortion;
}
*value = fractal_noise_1d(p, detail);
@@ -71,8 +71,8 @@ ccl_device void noise_texture_2d(
{
float2 p = co;
if (distortion != 0.0f) {
- p += make_float2(noise_2d(p + random_float2_offset(0.0f)) * distortion,
- noise_2d(p + random_float2_offset(1.0f)) * distortion);
+ p += make_float2(snoise_2d(p + random_float2_offset(0.0f)) * distortion,
+ snoise_2d(p + random_float2_offset(1.0f)) * distortion);
}
*value = fractal_noise_2d(p, detail);
@@ -88,9 +88,9 @@ ccl_device void noise_texture_3d(
{
float3 p = co;
if (distortion != 0.0f) {
- p += make_float3(noise_3d(p + random_float3_offset(0.0f)) * distortion,
- noise_3d(p + random_float3_offset(1.0f)) * distortion,
- noise_3d(p + random_float3_offset(2.0f)) * distortion);
+ p += make_float3(snoise_3d(p + random_float3_offset(0.0f)) * distortion,
+ snoise_3d(p + random_float3_offset(1.0f)) * distortion,
+ snoise_3d(p + random_float3_offset(2.0f)) * distortion);
}
*value = fractal_noise_3d(p, detail);
@@ -106,10 +106,10 @@ ccl_device void noise_texture_4d(
{
float4 p = co;
if (distortion != 0.0f) {
- p += make_float4(noise_4d(p + random_float4_offset(0.0f)) * distortion,
- noise_4d(p + random_float4_offset(1.0f)) * distortion,
- noise_4d(p + random_float4_offset(2.0f)) * distortion,
- noise_4d(p + random_float4_offset(3.0f)) * distortion);
+ p += make_float4(snoise_4d(p + random_float4_offset(0.0f)) * distortion,
+ snoise_4d(p + random_float4_offset(1.0f)) * distortion,
+ snoise_4d(p + random_float4_offset(2.0f)) * distortion,
+ snoise_4d(p + random_float4_offset(3.0f)) * distortion);
}
*value = fractal_noise_4d(p, detail);
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index 01710f713ac..8dbb147e76a 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -150,6 +150,9 @@ typedef enum ShaderNodeType {
NODE_VERTEX_COLOR,
NODE_VERTEX_COLOR_BUMP_DX,
NODE_VERTEX_COLOR_BUMP_DY,
+ NODE_AOV_START,
+ NODE_AOV_VALUE,
+ NODE_AOV_COLOR,
} ShaderNodeType;
typedef enum NodeAttributeType {
@@ -281,6 +284,22 @@ typedef enum NodeMathType {
NODE_MATH_CEIL,
NODE_MATH_FRACTION,
NODE_MATH_SQRT,
+ NODE_MATH_INV_SQRT,
+ NODE_MATH_SIGN,
+ NODE_MATH_EXPONENT,
+ NODE_MATH_RADIANS,
+ NODE_MATH_DEGREES,
+ NODE_MATH_SINH,
+ NODE_MATH_COSH,
+ NODE_MATH_TANH,
+ NODE_MATH_TRUNC,
+ NODE_MATH_SNAP,
+ NODE_MATH_WRAP,
+ NODE_MATH_COMPARE,
+ NODE_MATH_MULTIPLY_ADD,
+ NODE_MATH_PINGPONG,
+ NODE_MATH_SMOOTH_MIN,
+ NODE_MATH_SMOOTH_MAX,
} NodeMathType;
typedef enum NodeVectorMathType {
@@ -309,6 +328,18 @@ typedef enum NodeVectorMathType {
NODE_VECTOR_MATH_MAXIMUM,
} NodeVectorMathType;
+typedef enum NodeClampType {
+ NODE_CLAMP_MINMAX,
+ NODE_CLAMP_RANGE,
+} NodeClampType;
+
+typedef enum NodeMapRangeType {
+ NODE_MAP_RANGE_LINEAR,
+ NODE_MAP_RANGE_STEPPED,
+ NODE_MAP_RANGE_SMOOTHSTEP,
+ NODE_MAP_RANGE_SMOOTHERSTEP,
+} NodeMapRangeType;
+
typedef enum NodeMappingType {
NODE_MAPPING_TYPE_POINT,
NODE_MAPPING_TYPE_TEXTURE,
@@ -552,6 +583,12 @@ typedef enum ClosureType {
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) || \
(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID))
+#define CLOSURE_IS_BSDF_MICROFACET_FRESNEL(type) \
+ (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID || \
+ type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID || \
+ type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID || \
+ type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID || \
+ type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID)
#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID)
#define CLOSURE_IS_BSSRDF(type) \
(type >= CLOSURE_BSSRDF_CUBIC_ID && type <= CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID)
diff --git a/intern/cycles/kernel/svm/svm_wave.h b/intern/cycles/kernel/svm/svm_wave.h
index 402c1c87414..50c868c0f82 100644
--- a/intern/cycles/kernel/svm/svm_wave.h
+++ b/intern/cycles/kernel/svm/svm_wave.h
@@ -33,7 +33,7 @@ ccl_device_noinline_cpu float svm_wave(NodeWaveType type,
n = len(p) * 20.0f;
if (distortion != 0.0f)
- n += distortion * fractal_noise_3d(p * dscale, detail);
+ n += distortion * (fractal_noise_3d(p * dscale, detail) * 2.0f - 1.0f);
if (profile == NODE_WAVE_PROFILE_SIN) {
return 0.5f + 0.5f * sinf(n);
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index 49e15d9eaf1..fe8606e1939 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -234,7 +234,7 @@ bool RenderBuffers::get_denoising_pass_rect(
}
bool RenderBuffers::get_pass_rect(
- PassType type, float exposure, int sample, int components, float *pixels, const string &name)
+ const string &name, float exposure, int sample, int components, float *pixels)
{
if (buffer.data() == NULL) {
return false;
@@ -245,18 +245,14 @@ bool RenderBuffers::get_pass_rect(
for (size_t j = 0; j < params.passes.size(); j++) {
Pass &pass = params.passes[j];
- if (pass.type != type) {
+ /* Pass is identified by both type and name, multiple of the same type
+ * may exist with a different name. */
+ if (pass.name != name) {
pass_offset += pass.components;
continue;
}
- /* Tell Cryptomatte passes apart by their name. */
- if (pass.type == PASS_CRYPTOMATTE) {
- if (pass.name != name) {
- pass_offset += pass.components;
- continue;
- }
- }
+ PassType type = pass.type;
float *in = buffer.data() + pass_offset;
int pass_stride = params.get_passes_size();
diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h
index 74bb656c5a4..1042b42810f 100644
--- a/intern/cycles/render/buffers.h
+++ b/intern/cycles/render/buffers.h
@@ -88,12 +88,8 @@ class RenderBuffers {
void zero();
bool copy_from_device();
- bool get_pass_rect(PassType type,
- float exposure,
- int sample,
- int components,
- float *pixels,
- const string &name);
+ bool get_pass_rect(
+ const string &name, float exposure, int sample, int components, float *pixels);
bool get_denoising_pass_rect(
int offset, float exposure, int sample, int components, float *pixels);
};
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index 7f5bec2a66e..bd274844b52 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -41,7 +41,34 @@ static bool compare_pass_order(const Pass &a, const Pass &b)
void Pass::add(PassType type, vector<Pass> &passes, const char *name)
{
for (size_t i = 0; i < passes.size(); i++) {
- if (passes[i].type == type && (name ? (passes[i].name == name) : passes[i].name.empty())) {
+ if (passes[i].type != type) {
+ continue;
+ }
+
+ /* An empty name is used as a placeholder to signal that any pass of
+ * that type is fine (because the content always is the same).
+ * This is important to support divide_type: If the pass that has a
+ * divide_type is added first, a pass for divide_type with an empty
+ * name will be added. Then, if a matching pass with a name is later
+ * requested, the existing placeholder will be renamed to that.
+ * If the divide_type is explicitly allocated with a name first and
+ * then again as part of another pass, the second one will just be
+ * skipped because that type already exists. */
+
+ /* If no name is specified, any pass of the correct type will match. */
+ if (name == NULL) {
+ return;
+ }
+
+ /* If we already have a placeholder pass, rename that one. */
+ if (passes[i].name.empty()) {
+ passes[i].name = name;
+ return;
+ }
+
+ /* If neither existing nor requested pass have placeholder name, they
+ * must match. */
+ if (name == passes[i].name) {
return;
}
}
@@ -163,6 +190,12 @@ void Pass::add(PassType type, vector<Pass> &passes, const char *name)
case PASS_CRYPTOMATTE:
pass.components = 4;
break;
+ case PASS_AOV_COLOR:
+ pass.components = 4;
+ break;
+ case PASS_AOV_VALUE:
+ pass.components = 1;
+ break;
default:
assert(false);
break;
@@ -281,8 +314,6 @@ NODE_DEFINE(Film)
SOCKET_FLOAT(mist_depth, "Mist Depth", 100.0f);
SOCKET_FLOAT(mist_falloff, "Mist Falloff", 1.0f);
- SOCKET_BOOLEAN(use_sample_clamp, "Use Sample Clamp", false);
-
SOCKET_BOOLEAN(denoising_data_pass, "Generate Denoising Data Pass", false);
SOCKET_BOOLEAN(denoising_clean_pass, "Generate Denoising Clean Pass", false);
SOCKET_BOOLEAN(denoising_prefiltered_pass, "Generate Denoising Prefiltered Pass", false);
@@ -325,9 +356,9 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
kfilm->light_pass_flag = 0;
kfilm->pass_stride = 0;
- kfilm->use_light_pass = use_light_visibility || use_sample_clamp;
+ kfilm->use_light_pass = use_light_visibility;
- bool have_cryptomatte = false;
+ bool have_cryptomatte = false, have_aov_color = false, have_aov_value = false;
for (size_t i = 0; i < passes.size(); i++) {
Pass &pass = passes[i];
@@ -464,6 +495,18 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
kfilm->pass_stride;
have_cryptomatte = true;
break;
+ case PASS_AOV_COLOR:
+ if (!have_aov_color) {
+ kfilm->pass_aov_color = kfilm->pass_stride;
+ have_aov_color = true;
+ }
+ break;
+ case PASS_AOV_VALUE:
+ if (!have_aov_value) {
+ kfilm->pass_aov_value = kfilm->pass_stride;
+ have_aov_value = true;
+ }
+ break;
default:
assert(false);
break;
@@ -569,4 +612,27 @@ void Film::tag_update(Scene * /*scene*/)
need_update = true;
}
+int Film::get_aov_offset(string name, bool &is_color)
+{
+ int num_color = 0, num_value = 0;
+ foreach (const Pass &pass, passes) {
+ if (pass.type == PASS_AOV_COLOR) {
+ num_color++;
+ }
+ else if (pass.type == PASS_AOV_VALUE) {
+ num_value++;
+ }
+ else {
+ continue;
+ }
+
+ if (pass.name == name) {
+ is_color = (pass.type == PASS_AOV_COLOR);
+ return (is_color ? num_color : num_value) - 1;
+ }
+ }
+
+ return -1;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/film.h b/intern/cycles/render/film.h
index 2c4e07d60ae..95e54cb54d8 100644
--- a/intern/cycles/render/film.h
+++ b/intern/cycles/render/film.h
@@ -78,7 +78,6 @@ class Film : public Node {
float mist_falloff;
bool use_light_visibility;
- bool use_sample_clamp;
CryptomatteType cryptomatte_passes;
int cryptomatte_depth;
@@ -93,6 +92,8 @@ class Film : public Node {
bool modified(const Film &film);
void tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes = true);
void tag_update(Scene *scene);
+
+ int get_aov_offset(string name, bool &is_color);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index 501d1e33a9b..0e520c700a7 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -55,6 +55,25 @@ bool check_node_inputs_traversed(const ShaderNode *node, const ShaderNodeSet &do
} /* namespace */
+/* Sockets */
+
+void ShaderInput::disconnect()
+{
+ if (link) {
+ link->links.erase(remove(link->links.begin(), link->links.end(), this), link->links.end());
+ }
+ link = NULL;
+}
+
+void ShaderOutput::disconnect()
+{
+ foreach (ShaderInput *sock, links) {
+ sock->link = NULL;
+ }
+
+ links.clear();
+}
+
/* Node */
ShaderNode::ShaderNode(const NodeType *type) : Node(type)
@@ -285,11 +304,7 @@ void ShaderGraph::disconnect(ShaderOutput *from)
assert(!finalized);
simplified = false;
- foreach (ShaderInput *sock, from->links) {
- sock->link = NULL;
- }
-
- from->links.clear();
+ from->disconnect();
}
void ShaderGraph::disconnect(ShaderInput *to)
@@ -298,10 +313,7 @@ void ShaderGraph::disconnect(ShaderInput *to)
assert(to->link);
simplified = false;
- ShaderOutput *from = to->link;
-
- to->link = NULL;
- from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
+ to->disconnect();
}
void ShaderGraph::relink(ShaderInput *from, ShaderInput *to)
@@ -782,6 +794,11 @@ void ShaderGraph::clean(Scene *scene)
/* break cycles */
break_cycles(output(), visited, on_stack);
+ foreach (ShaderNode *node, nodes) {
+ if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
+ break_cycles(node, visited, on_stack);
+ }
+ }
/* disconnect unused nodes */
foreach (ShaderNode *node, nodes) {
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
index cade04de374..0ea7935f714 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -67,6 +67,7 @@ enum ShaderNodeSpecialType {
SHADER_SPECIAL_TYPE_COMBINE_CLOSURE,
SHADER_SPECIAL_TYPE_OUTPUT,
SHADER_SPECIAL_TYPE_BUMP,
+ SHADER_SPECIAL_TYPE_OUTPUT_AOV,
};
/* Input
@@ -104,6 +105,8 @@ class ShaderInput {
((Node *)parent)->set(socket_type, f);
}
+ void disconnect();
+
const SocketType &socket_type;
ShaderNode *parent;
ShaderOutput *link;
@@ -130,6 +133,8 @@ class ShaderOutput {
return socket_type.type;
}
+ void disconnect();
+
const SocketType &socket_type;
ShaderNode *parent;
vector<ShaderInput *> links;
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 03ecc9bce52..212a867f9cd 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -630,6 +630,7 @@ bool ImageManager::file_load_image(Image *img,
if (FileFormat == TypeDesc::FLOAT) {
builtin_image_float_pixels_cb(img->filename,
img->builtin_data,
+ 0, /* TODO(lukas): Support tiles here? */
(float *)&pixels[0],
num_pixels * components,
image_associate_alpha(img),
@@ -638,6 +639,7 @@ bool ImageManager::file_load_image(Image *img,
else if (FileFormat == TypeDesc::UINT8) {
builtin_image_pixels_cb(img->filename,
img->builtin_data,
+ 0, /* TODO(lukas): Support tiles here? */
(uchar *)&pixels[0],
num_pixels * components,
image_associate_alpha(img),
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 459cd8c056c..bc04a667953 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -130,6 +130,7 @@ class ImageManager {
builtin_image_info_cb;
function<bool(const string &filename,
void *data,
+ int tile,
unsigned char *pixels,
const size_t pixels_size,
const bool associate_alpha,
@@ -137,6 +138,7 @@ class ImageManager {
builtin_image_pixels_cb;
function<bool(const string &filename,
void *data,
+ int tile,
float *pixels,
const size_t pixels_size,
const bool associate_alpha,
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index b41b0b7b260..530c32106b7 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -209,13 +209,6 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
dscene->sobol_directions.copy_to_device();
- /* Clamping. */
- bool use_sample_clamp = (sample_clamp_direct != 0.0f || sample_clamp_indirect != 0.0f);
- if (use_sample_clamp != scene->film->use_sample_clamp) {
- scene->film->use_sample_clamp = use_sample_clamp;
- scene->film->tag_update(scene);
- }
-
need_update = false;
}
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index dc3f7c8f8ac..06304205dc9 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -575,7 +575,8 @@ void LightManager::device_update_background(Device *device,
if (node->type == EnvironmentTextureNode::node_type) {
EnvironmentTextureNode *env = (EnvironmentTextureNode *)node;
ImageMetaData metadata;
- if (env->image_manager && env->image_manager->get_image_metadata(env->slot, metadata)) {
+ if (env->image_manager && !env->slots.empty() &&
+ env->image_manager->get_image_metadata(env->slots[0], metadata)) {
res.x = max(res.x, metadata.width);
res.y = max(res.y, metadata.height);
}
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index cffe2bfa70a..d9e6d998ebd 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -637,6 +637,50 @@ void Mesh::add_subd_face(int *corners, int num_corners, int shader_, bool smooth
subd_faces.push_back_reserved(face);
}
+static void get_uv_tiles_from_attribute(Attribute *attr, int num, unordered_set<int> &tiles)
+{
+ if (attr == NULL) {
+ return;
+ }
+
+ const float2 *uv = attr->data_float2();
+ for (int i = 0; i < num; i++, uv++) {
+ float u = uv->x, v = uv->y;
+ int x = (int)u, y = (int)v;
+
+ if (x < 0 || y < 0 || x >= 10) {
+ continue;
+ }
+
+ /* Be conservative in corners - precisely touching the right or upper edge of a tile
+ * should not load its right/upper neighbor as well. */
+ if (x > 0 && (u < x + 1e-6f)) {
+ x--;
+ }
+ if (y > 0 && (v < y + 1e-6f)) {
+ y--;
+ }
+
+ tiles.insert(1001 + 10 * y + x);
+ }
+}
+
+void Mesh::get_uv_tiles(ustring map, unordered_set<int> &tiles)
+{
+ if (map.empty()) {
+ get_uv_tiles_from_attribute(attributes.find(ATTR_STD_UV), num_triangles() * 3, tiles);
+ get_uv_tiles_from_attribute(
+ subd_attributes.find(ATTR_STD_UV), subd_face_corners.size() + num_ngons, tiles);
+ get_uv_tiles_from_attribute(curve_attributes.find(ATTR_STD_UV), num_curves(), tiles);
+ }
+ else {
+ get_uv_tiles_from_attribute(attributes.find(map), num_triangles() * 3, tiles);
+ get_uv_tiles_from_attribute(
+ subd_attributes.find(map), subd_face_corners.size() + num_ngons, tiles);
+ get_uv_tiles_from_attribute(curve_attributes.find(map), num_curves(), tiles);
+ }
+}
+
void Mesh::compute_bounds()
{
BoundBox bnds = BoundBox::empty;
@@ -2085,9 +2129,10 @@ void MeshManager::device_update_displacement_images(Device *device,
}
ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode *>(node);
- int slot = image_node->slot;
- if (slot != -1) {
- bump_images.insert(slot);
+ foreach (int slot, image_node->slots) {
+ if (slot != -1) {
+ bump_images.insert(slot);
+ }
}
}
}
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 4a24a9c2656..c5be0ba60b9 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -28,6 +28,7 @@
#include "util/util_list.h"
#include "util/util_map.h"
#include "util/util_param.h"
+#include "util/util_set.h"
#include "util/util_transform.h"
#include "util/util_types.h"
#include "util/util_vector.h"
@@ -314,6 +315,8 @@ class Mesh : public Node {
void add_vertex_normals();
void add_undisplaced();
+ void get_uv_tiles(ustring map, unordered_set<int> &tiles);
+
void pack_shaders(Scene *scene, uint *shader);
void pack_normals(float4 *vnormal);
void pack_verts(const vector<uint> &tri_prim_index,
diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp
index a5a35fc049e..40dd658eadd 100644
--- a/intern/cycles/render/mesh_subdivision.cpp
+++ b/intern/cycles/render/mesh_subdivision.cpp
@@ -394,7 +394,7 @@ void Mesh::tessellate(DiagSplit *split)
int num_faces = subd_faces.size();
Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL);
- float3 *vN = attr_vN->data_float3();
+ float3 *vN = (attr_vN) ? attr_vN->data_float3() : NULL;
/* count patches */
int num_patches = 0;
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index f637fbf3b37..e4339b40744 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -19,6 +19,7 @@
#include "render/image.h"
#include "render/integrator.h"
#include "render/light.h"
+#include "render/mesh.h"
#include "render/nodes.h"
#include "render/scene.h"
#include "render/svm.h"
@@ -204,6 +205,27 @@ void TextureMapping::compile(OSLCompiler &compiler)
/* Image Texture */
+ImageSlotTextureNode::~ImageSlotTextureNode()
+{
+ if (image_manager) {
+ foreach (int slot, slots) {
+ if (slot != -1) {
+ image_manager->remove_image(slot);
+ }
+ }
+ }
+}
+
+void ImageSlotTextureNode::add_image_user() const
+{
+ /* Increase image user count for new node. */
+ foreach (int slot, slots) {
+ if (slot != -1) {
+ image_manager->add_image_user(slot);
+ }
+ }
+}
+
NODE_DEFINE(ImageTextureNode)
{
NodeType *type = NodeType::add("image_texture", create, NodeType::SHADER);
@@ -253,30 +275,79 @@ NODE_DEFINE(ImageTextureNode)
ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(node_type)
{
- image_manager = NULL;
- slot = -1;
- is_float = -1;
+ is_float = false;
compress_as_srgb = false;
colorspace = u_colorspace_raw;
builtin_data = NULL;
animated = false;
+ tiles.push_back(1001);
}
-ImageTextureNode::~ImageTextureNode()
+ShaderNode *ImageTextureNode::clone() const
{
- if (image_manager) {
- image_manager->remove_image(
- filename.string(), builtin_data, interpolation, extension, alpha_type, colorspace);
- }
+ add_image_user();
+ return new ImageTextureNode(*this);
}
-ShaderNode *ImageTextureNode::clone() const
+void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph)
{
- /* Increase image user count for new node. */
- if (slot != -1) {
- image_manager->add_image_user(slot);
+ /* Box projection computes its own UVs that always lie in the
+ * 1001 tile, so there's no point in loading any others. */
+ if (projection == NODE_IMAGE_PROJ_BOX) {
+ tiles.clear();
+ tiles.push_back(1001);
+ return;
}
- return new ImageTextureNode(*this);
+
+ if (!scene->params.background) {
+ /* During interactive renders, all tiles are loaded.
+ * While we could support updating this when UVs change, that could lead
+ * to annoying interruptions when loading images while editing UVs. */
+ return;
+ }
+
+ /* Only check UVs for tile culling if there are multiple tiles. */
+ if (tiles.size() < 2) {
+ return;
+ }
+
+ ShaderInput *vector_in = input("Vector");
+ ustring attribute;
+ if (vector_in->link) {
+ ShaderNode *node = vector_in->link->parent;
+ if (node->type == UVMapNode::node_type) {
+ UVMapNode *uvmap = (UVMapNode *)node;
+ attribute = uvmap->attribute;
+ }
+ else if (node->type == TextureCoordinateNode::node_type) {
+ if (vector_in->link != node->output("UV")) {
+ return;
+ }
+ }
+ else {
+ return;
+ }
+ }
+
+ unordered_set<int> used_tiles;
+ /* TODO(lukas): This is quite inefficient. A fairly simple improvement would
+ * be to have a cache in each mesh that is indexed by attribute.
+ * Additionally, building a graph-to-meshes list once could help. */
+ foreach (Mesh *mesh, scene->meshes) {
+ foreach (Shader *shader, mesh->used_shaders) {
+ if (shader->graph == graph) {
+ mesh->get_uv_tiles(attribute, used_tiles);
+ }
+ }
+ }
+
+ ccl::vector<int> new_tiles;
+ foreach (int tile, tiles) {
+ if (used_tiles.count(tile)) {
+ new_tiles.push_back(tile);
+ }
+ }
+ tiles.swap(new_tiles);
}
void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -300,24 +371,47 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
ShaderOutput *color_out = output("Color");
ShaderOutput *alpha_out = output("Alpha");
- image_manager = compiler.image_manager;
- if (is_float == -1) {
- ImageMetaData metadata;
- slot = image_manager->add_image(filename.string(),
- builtin_data,
- animated,
- 0,
- interpolation,
- extension,
- alpha_type,
- colorspace,
- metadata);
- is_float = metadata.is_float;
- compress_as_srgb = metadata.compress_as_srgb;
- known_colorspace = metadata.colorspace;
+ image_manager = compiler.scene->image_manager;
+ if (slots.empty()) {
+ cull_tiles(compiler.scene, compiler.current_graph);
+ slots.reserve(tiles.size());
+
+ bool have_metadata = false;
+ foreach (int tile, tiles) {
+ string tile_name = filename.string();
+ string_replace(tile_name, "<UDIM>", string_printf("%04d", tile));
+
+ ImageMetaData metadata;
+ int slot = image_manager->add_image(tile_name,
+ builtin_data,
+ animated,
+ 0,
+ interpolation,
+ extension,
+ alpha_type,
+ colorspace,
+ metadata);
+ slots.push_back(slot);
+
+ /* We assume that all tiles have the same metadata. */
+ if (!have_metadata) {
+ is_float = metadata.is_float;
+ compress_as_srgb = metadata.compress_as_srgb;
+ known_colorspace = metadata.colorspace;
+ have_metadata = true;
+ }
+ }
}
- if (slot != -1) {
+ bool has_image = false;
+ foreach (int slot, slots) {
+ if (slot != -1) {
+ has_image = true;
+ break;
+ }
+ }
+
+ if (has_image) {
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
uint flags = 0;
@@ -335,17 +429,44 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
}
if (projection != NODE_IMAGE_PROJ_BOX) {
+ /* If there only is one image (a very common case), we encode it as a negative value. */
+ int num_nodes;
+ if (slots.size() == 1) {
+ num_nodes = -slots[0];
+ }
+ else {
+ num_nodes = divide_up(slots.size(), 2);
+ }
+
compiler.add_node(NODE_TEX_IMAGE,
- slot,
+ num_nodes,
compiler.encode_uchar4(vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
flags),
projection);
+
+ if (num_nodes > 0) {
+ for (int i = 0; i < num_nodes; i++) {
+ int4 node;
+ node.x = tiles[2 * i];
+ node.y = slots[2 * i];
+ if (2 * i + 1 < slots.size()) {
+ node.z = tiles[2 * i + 1];
+ node.w = slots[2 * i + 1];
+ }
+ else {
+ node.z = -1;
+ node.w = -1;
+ }
+ compiler.add_node(node.x, node.y, node.z, node.w);
+ }
+ }
}
else {
+ assert(slots.size() == 1);
compiler.add_node(NODE_TEX_IMAGE_BOX,
- slot,
+ slots[0],
compiler.encode_uchar4(vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
@@ -375,39 +496,44 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
tex_mapping.compile(compiler);
- image_manager = compiler.image_manager;
- if (is_float == -1) {
+ image_manager = compiler.scene->image_manager;
+ if (slots.size() == 0) {
ImageMetaData metadata;
if (builtin_data == NULL) {
- image_manager->get_image_metadata(filename.string(), NULL, colorspace, metadata);
+ string tile_name = filename.string();
+ string_replace(tile_name, "<UDIM>", "1001");
+ image_manager->get_image_metadata(tile_name, NULL, colorspace, metadata);
+ slots.push_back(-1);
}
else {
- slot = image_manager->add_image(filename.string(),
- builtin_data,
- animated,
- 0,
- interpolation,
- extension,
- alpha_type,
- colorspace,
- metadata);
+ int slot = image_manager->add_image(filename.string(),
+ builtin_data,
+ animated,
+ 0,
+ interpolation,
+ extension,
+ alpha_type,
+ colorspace,
+ metadata);
+ slots.push_back(slot);
}
is_float = metadata.is_float;
compress_as_srgb = metadata.compress_as_srgb;
known_colorspace = metadata.colorspace;
}
- if (slot == -1) {
+ if (slots[0] == -1) {
compiler.parameter_texture(
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
}
else {
- compiler.parameter_texture("filename", slot);
+ compiler.parameter_texture("filename", slots[0]);
}
const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
alpha_type == IMAGE_ALPHA_IGNORE);
+ const bool is_tiled = (filename.find("<UDIM>") != string::npos);
compiler.parameter(this, "projection");
compiler.parameter(this, "projection_blend");
@@ -415,6 +541,7 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
compiler.parameter("unassociate_alpha", !alpha_out->links.empty() && unassociate_alpha);
compiler.parameter("is_float", is_float);
+ compiler.parameter("is_tiled", is_tiled);
compiler.parameter(this, "interpolation");
compiler.parameter(this, "extension");
@@ -462,29 +589,16 @@ NODE_DEFINE(EnvironmentTextureNode)
EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(node_type)
{
- image_manager = NULL;
- slot = -1;
- is_float = -1;
+ is_float = false;
compress_as_srgb = false;
colorspace = u_colorspace_raw;
builtin_data = NULL;
animated = false;
}
-EnvironmentTextureNode::~EnvironmentTextureNode()
-{
- if (image_manager) {
- image_manager->remove_image(
- filename.string(), builtin_data, interpolation, EXTENSION_REPEAT, alpha_type, colorspace);
- }
-}
-
ShaderNode *EnvironmentTextureNode::clone() const
{
- /* Increase image user count for new node. */
- if (slot != -1) {
- image_manager->add_image_user(slot);
- }
+ add_image_user();
return new EnvironmentTextureNode(*this);
}
@@ -507,24 +621,25 @@ void EnvironmentTextureNode::compile(SVMCompiler &compiler)
ShaderOutput *color_out = output("Color");
ShaderOutput *alpha_out = output("Alpha");
- image_manager = compiler.image_manager;
- if (slot == -1) {
+ image_manager = compiler.scene->image_manager;
+ if (slots.empty()) {
ImageMetaData metadata;
- slot = image_manager->add_image(filename.string(),
- builtin_data,
- animated,
- 0,
- interpolation,
- EXTENSION_REPEAT,
- alpha_type,
- colorspace,
- metadata);
+ int slot = image_manager->add_image(filename.string(),
+ builtin_data,
+ animated,
+ 0,
+ interpolation,
+ EXTENSION_REPEAT,
+ alpha_type,
+ colorspace,
+ metadata);
+ slots.push_back(slot);
is_float = metadata.is_float;
compress_as_srgb = metadata.compress_as_srgb;
known_colorspace = metadata.colorspace;
}
- if (slot != -1) {
+ if (slots[0] != -1) {
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
uint flags = 0;
@@ -533,7 +648,7 @@ void EnvironmentTextureNode::compile(SVMCompiler &compiler)
}
compiler.add_node(NODE_TEX_ENVIRONMENT,
- slot,
+ slots[0],
compiler.encode_uchar4(vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
@@ -563,34 +678,36 @@ void EnvironmentTextureNode::compile(OSLCompiler &compiler)
/* See comments in ImageTextureNode::compile about support
* of builtin images.
*/
- image_manager = compiler.image_manager;
- if (is_float == -1) {
+ image_manager = compiler.scene->image_manager;
+ if (slots.empty()) {
ImageMetaData metadata;
if (builtin_data == NULL) {
image_manager->get_image_metadata(filename.string(), NULL, colorspace, metadata);
+ slots.push_back(-1);
}
else {
- slot = image_manager->add_image(filename.string(),
- builtin_data,
- animated,
- 0,
- interpolation,
- EXTENSION_REPEAT,
- alpha_type,
- colorspace,
- metadata);
+ int slot = image_manager->add_image(filename.string(),
+ builtin_data,
+ animated,
+ 0,
+ interpolation,
+ EXTENSION_REPEAT,
+ alpha_type,
+ colorspace,
+ metadata);
+ slots.push_back(slot);
}
is_float = metadata.is_float;
compress_as_srgb = metadata.compress_as_srgb;
known_colorspace = metadata.colorspace;
}
- if (slot == -1) {
+ if (slots[0] == -1) {
compiler.parameter_texture(
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
}
else {
- compiler.parameter_texture("filename", slot);
+ compiler.parameter_texture("filename", slots[0]);
}
compiler.parameter(this, "projection");
@@ -1123,7 +1240,7 @@ void IESLightNode::get_slot()
void IESLightNode::compile(SVMCompiler &compiler)
{
- light_manager = compiler.light_manager;
+ light_manager = compiler.scene->light_manager;
get_slot();
ShaderInput *strength_in = input("Strength");
@@ -1145,7 +1262,7 @@ void IESLightNode::compile(SVMCompiler &compiler)
void IESLightNode::compile(OSLCompiler &compiler)
{
- light_manager = compiler.light_manager;
+ light_manager = compiler.scene->light_manager;
get_slot();
tex_mapping.compile(compiler);
@@ -1663,7 +1780,7 @@ void PointDensityTextureNode::compile(SVMCompiler &compiler)
const bool use_density = !density_out->links.empty();
const bool use_color = !color_out->links.empty();
- image_manager = compiler.image_manager;
+ image_manager = compiler.scene->image_manager;
if (use_density || use_color) {
add_image();
@@ -1704,7 +1821,7 @@ void PointDensityTextureNode::compile(OSLCompiler &compiler)
const bool use_density = !density_out->links.empty();
const bool use_color = !color_out->links.empty();
- image_manager = compiler.image_manager;
+ image_manager = compiler.scene->image_manager;
if (use_density || use_color) {
add_image();
@@ -5561,11 +5678,19 @@ NODE_DEFINE(MapRangeNode)
{
NodeType *type = NodeType::add("map_range", create, NodeType::SHADER);
+ static NodeEnum type_enum;
+ type_enum.insert("linear", NODE_MAP_RANGE_LINEAR);
+ type_enum.insert("stepped", NODE_MAP_RANGE_STEPPED);
+ type_enum.insert("smoothstep", NODE_MAP_RANGE_SMOOTHSTEP);
+ type_enum.insert("smootherstep", NODE_MAP_RANGE_SMOOTHERSTEP);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_MAP_RANGE_LINEAR);
+
SOCKET_IN_FLOAT(value, "Value", 1.0f);
SOCKET_IN_FLOAT(from_min, "From Min", 0.0f);
SOCKET_IN_FLOAT(from_max, "From Max", 1.0f);
SOCKET_IN_FLOAT(to_min, "To Min", 0.0f);
SOCKET_IN_FLOAT(to_max, "To Max", 1.0f);
+ SOCKET_IN_FLOAT(steps, "Steps", 4.0f);
SOCKET_OUT_FLOAT(result, "Result");
@@ -5582,6 +5707,7 @@ void MapRangeNode::expand(ShaderGraph *graph)
ShaderOutput *result_out = output("Result");
if (!result_out->links.empty()) {
ClampNode *clamp_node = new ClampNode();
+ clamp_node->type = NODE_CLAMP_RANGE;
graph->add(clamp_node);
graph->relink(result_out, clamp_node->output("Result"));
graph->connect(result_out, clamp_node->input("Value"));
@@ -5601,20 +5727,6 @@ void MapRangeNode::expand(ShaderGraph *graph)
}
}
-void MapRangeNode::constant_fold(const ConstantFolder &folder)
-{
- if (folder.all_inputs_constant()) {
- float result;
- if (from_max != from_min) {
- result = to_min + ((value - from_min) / (from_max - from_min)) * (to_max - to_min);
- }
- else {
- result = 0.0f;
- }
- folder.make_constant(result);
- }
-}
-
void MapRangeNode::compile(SVMCompiler &compiler)
{
ShaderInput *value_in = input("Value");
@@ -5622,6 +5734,7 @@ void MapRangeNode::compile(SVMCompiler &compiler)
ShaderInput *from_max_in = input("From Max");
ShaderInput *to_min_in = input("To Min");
ShaderInput *to_max_in = input("To Max");
+ ShaderInput *steps_in = input("Steps");
ShaderOutput *result_out = output("Result");
int value_stack_offset = compiler.stack_assign(value_in);
@@ -5629,6 +5742,7 @@ void MapRangeNode::compile(SVMCompiler &compiler)
int from_max_stack_offset = compiler.stack_assign_if_linked(from_max_in);
int to_min_stack_offset = compiler.stack_assign_if_linked(to_min_in);
int to_max_stack_offset = compiler.stack_assign_if_linked(to_max_in);
+ int steps_stack_offset = compiler.stack_assign(steps_in);
int result_stack_offset = compiler.stack_assign(result_out);
compiler.add_node(
@@ -5636,16 +5750,18 @@ void MapRangeNode::compile(SVMCompiler &compiler)
value_stack_offset,
compiler.encode_uchar4(
from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset),
- result_stack_offset);
+ compiler.encode_uchar4(type, steps_stack_offset, result_stack_offset));
compiler.add_node(__float_as_int(from_min),
__float_as_int(from_max),
__float_as_int(to_min),
__float_as_int(to_max));
+ compiler.add_node(__float_as_int(steps));
}
void MapRangeNode::compile(OSLCompiler &compiler)
{
+ compiler.parameter(this, "type");
compiler.add(this, "node_map_range");
}
@@ -5655,6 +5771,11 @@ NODE_DEFINE(ClampNode)
{
NodeType *type = NodeType::add("clamp", create, NodeType::SHADER);
+ static NodeEnum type_enum;
+ type_enum.insert("minmax", NODE_CLAMP_MINMAX);
+ type_enum.insert("range", NODE_CLAMP_RANGE);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_CLAMP_MINMAX);
+
SOCKET_IN_FLOAT(value, "Value", 1.0f);
SOCKET_IN_FLOAT(min, "Min", 0.0f);
SOCKET_IN_FLOAT(max, "Max", 1.0f);
@@ -5671,7 +5792,12 @@ ClampNode::ClampNode() : ShaderNode(node_type)
void ClampNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
- folder.make_constant(clamp(value, min, max));
+ if (type == NODE_CLAMP_RANGE && (min > max)) {
+ folder.make_constant(clamp(value, max, min));
+ }
+ else {
+ folder.make_constant(clamp(value, min, max));
+ }
}
}
@@ -5689,16 +5815,69 @@ void ClampNode::compile(SVMCompiler &compiler)
compiler.add_node(NODE_CLAMP,
value_stack_offset,
- compiler.encode_uchar4(min_stack_offset, max_stack_offset),
+ compiler.encode_uchar4(min_stack_offset, max_stack_offset, type),
result_stack_offset);
compiler.add_node(__float_as_int(min), __float_as_int(max));
}
void ClampNode::compile(OSLCompiler &compiler)
{
+ compiler.parameter(this, "type");
compiler.add(this, "node_clamp");
}
+/* AOV Output */
+
+NODE_DEFINE(OutputAOVNode)
+{
+ NodeType *type = NodeType::add("aov_output", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_FLOAT(value, "Value", 0.0f);
+
+ SOCKET_STRING(name, "AOV Name", ustring(""));
+
+ return type;
+}
+
+OutputAOVNode::OutputAOVNode() : ShaderNode(node_type)
+{
+ special_type = SHADER_SPECIAL_TYPE_OUTPUT_AOV;
+ slot = -1;
+}
+
+void OutputAOVNode::simplify_settings(Scene *scene)
+{
+ slot = scene->film->get_aov_offset(name.string(), is_color);
+ if (slot == -1) {
+ slot = scene->film->get_aov_offset(name.string(), is_color);
+ }
+
+ if (slot == -1 || is_color) {
+ input("Value")->disconnect();
+ }
+ if (slot == -1 || !is_color) {
+ input("Color")->disconnect();
+ }
+}
+
+void OutputAOVNode::compile(SVMCompiler &compiler)
+{
+ assert(slot >= 0);
+
+ if (is_color) {
+ compiler.add_node(NODE_AOV_COLOR, compiler.stack_assign(input("Color")), slot);
+ }
+ else {
+ compiler.add_node(NODE_AOV_VALUE, compiler.stack_assign(input("Value")), slot);
+ }
+}
+
+void OutputAOVNode::compile(OSLCompiler & /*compiler*/)
+{
+ /* TODO */
+}
+
/* Math */
NODE_DEFINE(MathNode)
@@ -5710,9 +5889,13 @@ NODE_DEFINE(MathNode)
type_enum.insert("subtract", NODE_MATH_SUBTRACT);
type_enum.insert("multiply", NODE_MATH_MULTIPLY);
type_enum.insert("divide", NODE_MATH_DIVIDE);
+ type_enum.insert("multiply_add", NODE_MATH_MULTIPLY_ADD);
type_enum.insert("sine", NODE_MATH_SINE);
type_enum.insert("cosine", NODE_MATH_COSINE);
type_enum.insert("tangent", NODE_MATH_TANGENT);
+ type_enum.insert("sinh", NODE_MATH_SINH);
+ type_enum.insert("cosh", NODE_MATH_COSH);
+ type_enum.insert("tanh", NODE_MATH_TANH);
type_enum.insert("arcsine", NODE_MATH_ARCSINE);
type_enum.insert("arccosine", NODE_MATH_ARCCOSINE);
type_enum.insert("arctangent", NODE_MATH_ARCTANGENT);
@@ -5729,13 +5912,26 @@ NODE_DEFINE(MathNode)
type_enum.insert("floor", NODE_MATH_FLOOR);
type_enum.insert("ceil", NODE_MATH_CEIL);
type_enum.insert("fraction", NODE_MATH_FRACTION);
+ type_enum.insert("trunc", NODE_MATH_TRUNC);
+ type_enum.insert("snap", NODE_MATH_SNAP);
+ type_enum.insert("wrap", NODE_MATH_WRAP);
+ type_enum.insert("pingpong", NODE_MATH_PINGPONG);
type_enum.insert("sqrt", NODE_MATH_SQRT);
+ type_enum.insert("inversesqrt", NODE_MATH_INV_SQRT);
+ type_enum.insert("sign", NODE_MATH_SIGN);
+ type_enum.insert("exponent", NODE_MATH_EXPONENT);
+ type_enum.insert("radians", NODE_MATH_RADIANS);
+ type_enum.insert("degrees", NODE_MATH_DEGREES);
+ type_enum.insert("smoothmin", NODE_MATH_SMOOTH_MIN);
+ type_enum.insert("smoothmax", NODE_MATH_SMOOTH_MAX);
+ type_enum.insert("compare", NODE_MATH_COMPARE);
SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD);
SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
SOCKET_IN_FLOAT(value1, "Value1", 0.5f);
SOCKET_IN_FLOAT(value2, "Value2", 0.5f);
+ SOCKET_IN_FLOAT(value3, "Value3", 0.0f);
SOCKET_OUT_FLOAT(value, "Value");
@@ -5752,6 +5948,7 @@ void MathNode::expand(ShaderGraph *graph)
ShaderOutput *result_out = output("Value");
if (!result_out->links.empty()) {
ClampNode *clamp_node = new ClampNode();
+ clamp_node->type = NODE_CLAMP_MINMAX;
clamp_node->min = 0.0f;
clamp_node->max = 1.0f;
graph->add(clamp_node);
@@ -5764,7 +5961,7 @@ void MathNode::expand(ShaderGraph *graph)
void MathNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
- folder.make_constant(svm_math(type, value1, value2));
+ folder.make_constant(svm_math(type, value1, value2, value3));
}
else {
folder.fold_math(type);
@@ -5775,16 +5972,19 @@ void MathNode::compile(SVMCompiler &compiler)
{
ShaderInput *value1_in = input("Value1");
ShaderInput *value2_in = input("Value2");
+ ShaderInput *value3_in = input("Value3");
ShaderOutput *value_out = output("Value");
int value1_stack_offset = compiler.stack_assign(value1_in);
int value2_stack_offset = compiler.stack_assign(value2_in);
+ int value3_stack_offset = compiler.stack_assign(value3_in);
int value_stack_offset = compiler.stack_assign(value_out);
- compiler.add_node(NODE_MATH,
- type,
- compiler.encode_uchar4(value1_stack_offset, value2_stack_offset),
- value_stack_offset);
+ compiler.add_node(
+ NODE_MATH,
+ type,
+ compiler.encode_uchar4(value1_stack_offset, value2_stack_offset, value3_stack_offset),
+ value_stack_offset);
}
void MathNode::compile(OSLCompiler &compiler)
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 62037b0d381..a8fe7644957 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -77,14 +77,17 @@ class ImageSlotTextureNode : public TextureNode {
explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
+ image_manager = NULL;
}
- int slot;
+ ~ImageSlotTextureNode();
+ void add_image_user() const;
+ ImageManager *image_manager;
+ vector<int> slots;
};
class ImageTextureNode : public ImageSlotTextureNode {
public:
SHADER_NODE_NO_CLONE_CLASS(ImageTextureNode)
- ~ImageTextureNode();
ShaderNode *clone() const;
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency()
@@ -110,18 +113,20 @@ class ImageTextureNode : public ImageSlotTextureNode {
float projection_blend;
bool animated;
float3 vector;
+ ccl::vector<int> tiles;
/* Runtime. */
- ImageManager *image_manager;
- int is_float;
+ bool is_float;
bool compress_as_srgb;
ustring known_colorspace;
+
+ protected:
+ void cull_tiles(Scene *scene, ShaderGraph *graph);
};
class EnvironmentTextureNode : public ImageSlotTextureNode {
public:
SHADER_NODE_NO_CLONE_CLASS(EnvironmentTextureNode)
- ~EnvironmentTextureNode();
ShaderNode *clone() const;
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency()
@@ -151,8 +156,7 @@ class EnvironmentTextureNode : public ImageSlotTextureNode {
float3 vector;
/* Runtime. */
- ImageManager *image_manager;
- int is_float;
+ bool is_float;
bool compress_as_srgb;
ustring known_colorspace;
};
@@ -189,6 +193,26 @@ class OutputNode : public ShaderNode {
}
};
+class OutputAOVNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(OutputAOVNode)
+ virtual void simplify_settings(Scene *scene);
+
+ float value;
+ float3 color;
+
+ ustring name;
+
+ /* Don't allow output node de-duplication. */
+ virtual bool equals(const ShaderNode & /*other*/)
+ {
+ return false;
+ }
+
+ int slot;
+ bool is_color;
+};
+
class GradientTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(GradientTextureNode)
@@ -1290,14 +1314,14 @@ class BlackbodyNode : public ShaderNode {
class MapRangeNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MapRangeNode)
- void constant_fold(const ConstantFolder &folder);
virtual int get_group()
{
return NODE_GROUP_LEVEL_3;
}
void expand(ShaderGraph *graph);
- float value, from_min, from_max, to_min, to_max;
+ float value, from_min, from_max, to_min, to_max, steps;
+ NodeMapRangeType type;
bool clamp;
};
@@ -1310,6 +1334,7 @@ class ClampNode : public ShaderNode {
return NODE_GROUP_LEVEL_3;
}
float value, min, max;
+ NodeClampType type;
};
class MathNode : public ShaderNode {
@@ -1324,6 +1349,7 @@ class MathNode : public ShaderNode {
float value1;
float value2;
+ float value3;
NodeMathType type;
bool use_clamp;
};
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 889552f49cd..91f02e42071 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -118,9 +118,9 @@ void OSLShaderManager::device_update(Device *device,
* compile shaders alternating */
thread_scoped_lock lock(ss_mutex);
- OSLCompiler compiler(this, services, ss, scene->image_manager, scene->light_manager);
+ OSLCompiler compiler(this, services, ss, scene);
compiler.background = (shader == scene->default_background);
- compiler.compile(scene, og, shader);
+ compiler.compile(og, shader);
if (shader->use_mis && shader->has_surface_emission)
scene->light_manager->need_update = true;
@@ -566,13 +566,8 @@ OSLNode *OSLShaderManager::osl_node(const std::string &filepath,
OSLCompiler::OSLCompiler(OSLShaderManager *manager,
OSLRenderServices *services,
OSL::ShadingSystem *ss,
- ImageManager *image_manager,
- LightManager *light_manager)
- : image_manager(image_manager),
- light_manager(light_manager),
- manager(manager),
- services(services),
- ss(ss)
+ Scene *scene)
+ : scene(scene), manager(manager), services(services), ss(ss)
{
current_type = SHADER_TYPE_SURFACE;
current_shader = NULL;
@@ -1114,7 +1109,7 @@ OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph
return group;
}
-void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
+void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
{
if (shader->need_update) {
ShaderGraph *graph = shader->graph;
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index 17bf98a3433..62cbfebf7eb 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -131,10 +131,9 @@ class OSLCompiler {
OSLCompiler(OSLShaderManager *manager,
OSLRenderServices *services,
OSL::ShadingSystem *shadingsys,
- ImageManager *image_manager,
- LightManager *light_manager);
+ Scene *scene);
#endif
- void compile(Scene *scene, OSLGlobals *og, Shader *shader);
+ void compile(OSLGlobals *og, Shader *shader);
void add(ShaderNode *node, const char *name, bool isfilepath = false);
@@ -165,8 +164,7 @@ class OSLCompiler {
}
bool background;
- ImageManager *image_manager;
- LightManager *light_manager;
+ Scene *scene;
private:
#ifdef WITH_OSL
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 45997bccf5d..f99510d2d42 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -170,6 +170,8 @@ class SceneParams {
bool persistent_data;
int texture_limit;
+ bool background;
+
SceneParams()
{
shadingsystem = SHADINGSYSTEM_SVM;
@@ -180,6 +182,7 @@ class SceneParams {
num_bvh_time_steps = 0;
persistent_data = false;
texture_limit = 0;
+ background = true;
}
bool modified(const SceneParams &params)
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index 00d9cd5e672..3b73fa4139f 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -225,6 +225,13 @@ Shader::~Shader()
bool Shader::is_constant_emission(float3 *emission)
{
+ /* If the shader has AOVs, they need to be evaluated, so we can't skip the shader. */
+ foreach (ShaderNode *node, graph->nodes) {
+ if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
+ return false;
+ }
+ }
+
ShaderInput *surf = graph->output()->input("Surface");
if (surf->link == NULL) {
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index f69c89b1fd4..f42a2ea818d 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -57,9 +57,9 @@ void SVMShaderManager::device_update_shader(Scene *scene,
svm_nodes->push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
SVMCompiler::Summary summary;
- SVMCompiler compiler(scene->shader_manager, scene->image_manager, scene->light_manager);
+ SVMCompiler compiler(scene);
compiler.background = (shader == scene->default_background);
- compiler.compile(scene, shader, *svm_nodes, 0, &summary);
+ compiler.compile(shader, *svm_nodes, 0, &summary);
VLOG(2) << "Compilation summary:\n"
<< "Shader name: " << shader->name << "\n"
@@ -169,13 +169,8 @@ void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *s
/* Graph Compiler */
-SVMCompiler::SVMCompiler(ShaderManager *shader_manager_,
- ImageManager *image_manager_,
- LightManager *light_manager_)
+SVMCompiler::SVMCompiler(Scene *scene) : scene(scene)
{
- shader_manager = shader_manager_;
- image_manager = image_manager_;
- light_manager = light_manager_;
max_stack_use = 0;
current_type = SHADER_TYPE_SURFACE;
current_shader = NULL;
@@ -408,12 +403,12 @@ void SVMCompiler::add_node(const float4 &f)
uint SVMCompiler::attribute(ustring name)
{
- return shader_manager->get_attribute_id(name);
+ return scene->shader_manager->get_attribute_id(name);
}
uint SVMCompiler::attribute(AttributeStandard std)
{
- return shader_manager->get_attribute_id(std);
+ return scene->shader_manager->get_attribute_id(std);
}
uint SVMCompiler::attribute_standard(ustring name)
@@ -554,6 +549,24 @@ void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
}
}
+void SVMCompiler::generate_aov_node(ShaderNode *node, CompilerState *state)
+{
+ /* execute dependencies for node */
+ foreach (ShaderInput *in, node->inputs) {
+ if (in->link != NULL) {
+ ShaderNodeSet dependencies;
+ find_dependencies(dependencies, state->nodes_done, in);
+ generate_svm_nodes(dependencies, state);
+ }
+ }
+
+ /* compile node itself */
+ generate_node(node, state->nodes_done);
+
+ state->nodes_done.insert(node);
+ state->nodes_done_flag[node->id] = true;
+}
+
void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
ShaderNode *node,
CompilerState *state)
@@ -703,21 +716,21 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
current_graph = graph;
/* get input in output node */
- ShaderNode *node = graph->output();
+ ShaderNode *output = graph->output();
ShaderInput *clin = NULL;
switch (type) {
case SHADER_TYPE_SURFACE:
- clin = node->input("Surface");
+ clin = output->input("Surface");
break;
case SHADER_TYPE_VOLUME:
- clin = node->input("Volume");
+ clin = output->input("Volume");
break;
case SHADER_TYPE_DISPLACEMENT:
- clin = node->input("Displacement");
+ clin = output->input("Displacement");
break;
case SHADER_TYPE_BUMP:
- clin = node->input("Normal");
+ clin = output->input("Normal");
break;
default:
assert(0);
@@ -728,10 +741,10 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
memset((void *)&active_stack, 0, sizeof(active_stack));
current_svm_nodes.clear();
- foreach (ShaderNode *node_iter, graph->nodes) {
- foreach (ShaderInput *input, node_iter->inputs)
+ foreach (ShaderNode *node, graph->nodes) {
+ foreach (ShaderInput *input, node->inputs)
input->stack_offset = SVM_STACK_INVALID;
- foreach (ShaderOutput *output, node_iter->outputs)
+ foreach (ShaderOutput *output, node->outputs)
output->stack_offset = SVM_STACK_INVALID;
}
@@ -745,6 +758,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
}
if (shader->used) {
+ CompilerState state(graph);
if (clin->link) {
bool generate = false;
@@ -769,13 +783,36 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
}
if (generate) {
- CompilerState state(graph);
generate_multi_closure(clin->link->parent, clin->link->parent, &state);
}
}
/* compile output node */
- node->compile(*this);
+ output->compile(*this);
+
+ if (type == SHADER_TYPE_SURFACE) {
+ vector<OutputAOVNode *> aov_outputs;
+ foreach (ShaderNode *node, graph->nodes) {
+ if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
+ OutputAOVNode *aov_node = static_cast<OutputAOVNode *>(node);
+ if (aov_node->slot >= 0) {
+ aov_outputs.push_back(aov_node);
+ }
+ }
+ }
+ if (aov_outputs.size() > 0) {
+ /* AOV passes are only written if the object is directly visible, so
+ * there is no point in evaluating all the nodes generated only for the
+ * AOV outputs if that's not the case. Therefore, we insert
+ * NODE_AOV_START into the shader before the AOV-only nodes are
+ * generated which tells the kernel that it can stop evaluation
+ * early if AOVs will not be written. */
+ add_node(NODE_AOV_START, 0, 0, 0);
+ foreach (OutputAOVNode *node, aov_outputs) {
+ generate_aov_node(node, &state);
+ }
+ }
+ }
}
/* add node to restore state after bump shader has finished */
@@ -796,8 +833,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
}
}
-void SVMCompiler::compile(
- Scene *scene, Shader *shader, array<int4> &svm_nodes, int index, Summary *summary)
+void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary)
{
/* copy graph for shader with bump mapping */
ShaderNode *output = shader->graph->output();
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
index 7eac3e19bb3..61923fc40ac 100644
--- a/intern/cycles/render/svm.h
+++ b/intern/cycles/render/svm.h
@@ -93,11 +93,8 @@ class SVMCompiler {
string full_report() const;
};
- SVMCompiler(ShaderManager *shader_manager,
- ImageManager *image_manager,
- LightManager *light_manager);
- void compile(
- Scene *scene, Shader *shader, array<int4> &svm_nodes, int index, Summary *summary = NULL);
+ SVMCompiler(Scene *scene);
+ void compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary = NULL);
int stack_assign(ShaderOutput *output);
int stack_assign(ShaderInput *input);
@@ -126,9 +123,8 @@ class SVMCompiler {
return current_type;
}
- ImageManager *image_manager;
- ShaderManager *shader_manager;
- LightManager *light_manager;
+ Scene *scene;
+ ShaderGraph *current_graph;
bool background;
protected:
@@ -204,6 +200,7 @@ class SVMCompiler {
ShaderInput *input,
ShaderNode *skip_node = NULL);
void generate_node(ShaderNode *node, ShaderNodeSet &done);
+ void generate_aov_node(ShaderNode *node, CompilerState *state);
void generate_closure_node(ShaderNode *node, CompilerState *state);
void generated_shared_closure_nodes(ShaderNode *root_node,
ShaderNode *node,
@@ -220,7 +217,6 @@ class SVMCompiler {
array<int4> current_svm_nodes;
ShaderType current_type;
Shader *current_shader;
- ShaderGraph *current_graph;
Stack active_stack;
int max_stack_use;
uint mix_weight_offset;
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index 53e528de66e..737c834e073 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -344,6 +344,34 @@ ccl_device_inline int ceil_to_int(float f)
return float_to_int(ceilf(f));
}
+ccl_device_inline float fractf(float x)
+{
+ return x - floorf(x);
+}
+
+/* Adapted from godotengine math_funcs.h. */
+ccl_device_inline float wrapf(float value, float max, float min)
+{
+ float range = max - min;
+ return (range != 0.0f) ? value - (range * floorf((value - min) / range)) : min;
+}
+
+ccl_device_inline float pingpongf(float a, float b)
+{
+ return (b != 0.0f) ? fabsf(fractf((a - b) / (b * 2.0f)) * b * 2.0f - b) : 0.0f;
+}
+
+ccl_device_inline float smoothminf(float a, float b, float k)
+{
+ if (k != 0.0f) {
+ float h = fmaxf(k - fabsf(a - b), 0.0f) / k;
+ return fminf(a, b) - h * h * h * k * (1.0f / 6.0f);
+ }
+ else {
+ return fminf(a, b);
+ }
+}
+
ccl_device_inline float signf(float f)
{
return (f < 0.0f) ? -1.0f : 1.0f;
@@ -357,6 +385,17 @@ ccl_device_inline float nonzerof(float f, float eps)
return f;
}
+/* Signum function testing for zero. Matches GLSL and OSL functions. */
+ccl_device_inline float compatible_signf(float f)
+{
+ if (f == 0.0f) {
+ return 0.0f;
+ }
+ else {
+ return signf(f);
+ }
+}
+
ccl_device_inline float smoothstepf(float f)
{
float ff = f * f;
@@ -549,6 +588,11 @@ ccl_device_inline float safe_sqrtf(float f)
return sqrtf(max(f, 0.0f));
}
+ccl_device_inline float inversesqrtf(float f)
+{
+ return (f > 0.0f) ? 1.0f / sqrtf(f) : 0.0f;
+}
+
ccl_device float safe_asinf(float a)
{
return asinf(clamp(a, -1.0f, 1.0f));
diff --git a/intern/elbeem/CMakeLists.txt b/intern/elbeem/CMakeLists.txt
deleted file mode 100644
index 63a6af84323..00000000000
--- a/intern/elbeem/CMakeLists.txt
+++ /dev/null
@@ -1,130 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-# ***** END GPL LICENSE BLOCK *****
-
-set(INC
- extern
- ../guardedalloc
-)
-
-set(INC_SYS
- ${PNG_INCLUDE_DIRS}
- ${ZLIB_INCLUDE_DIRS}
-)
-
-set(SRC
- intern/attributes.cpp
- intern/controlparticles.cpp
- intern/elbeem.cpp
- intern/elbeem_control.cpp
- intern/isosurface.cpp
- intern/mvmcoords.cpp
- intern/ntl_blenderdumper.cpp
- intern/ntl_bsptree.cpp
- intern/ntl_geometrymodel.cpp
- intern/ntl_geometryobject.cpp
- intern/ntl_lighting.cpp
- intern/ntl_ray.cpp
- intern/ntl_world.cpp
- intern/parametrizer.cpp
- intern/particletracer.cpp
- intern/simulation_object.cpp
- intern/solver_adap.cpp
- intern/solver_control.cpp
- intern/solver_init.cpp
- intern/solver_interface.cpp
- intern/solver_main.cpp
- intern/solver_util.cpp
- intern/utilities.cpp
-
- extern/LBM_fluidsim.h
- extern/elbeem.h
- intern/attributes.h
- intern/controlparticles.h
- intern/elbeem_control.h
- intern/isosurface.h
- intern/loop_tools.h
- intern/mcubes_tables.h
- intern/mvmcoords.h
- intern/ntl_blenderdumper.h
- intern/ntl_bsptree.h
- intern/ntl_geometryclass.h
- intern/ntl_geometrymodel.h
- intern/ntl_geometryobject.h
- intern/ntl_geometryshader.h
- intern/ntl_lighting.h
- intern/ntl_matrices.h
- intern/ntl_ray.h
- intern/ntl_vector3dim.h
- intern/ntl_world.h
- intern/paraloopend.h
- intern/parametrizer.h
- intern/particletracer.h
- intern/simulation_object.h
- intern/solver_class.h
- intern/solver_control.h
- intern/solver_interface.h
- intern/solver_relax.h
- intern/utilities.h
- intern/globals.h
-)
-
-set(LIB
-)
-
-# elbeem has some harmless UNUSED warnings
-remove_strict_flags()
-
-add_definitions(
- -DNOGUI
- -DELBEEM_BLENDER=1
-)
-
-# not essential but quiet gcc's -Wundef
-add_definitions(
- -DLBM_PRECISION=1
- -DLBM_INCLUDE_TESTSOLVERS=0
- -DFSGR_STRICT_DEBUG=0
- -DELBEEM_MPI=0
- -DNEWDIRVELMOTEST=0
-)
-
-if(WIN32)
- # We need BLI_gzopen on win32 for unicode paths
- add_definitions(
- -DLBM_GZIP_OVERRIDE_H="${CMAKE_SOURCE_DIR}/source/blender/blenlib/BLI_fileops.h"
- -D LBM_GZIP_OPEN_FN="\(gzFile\)BLI_gzopen"
- )
-endif()
-
-if(WITH_OPENMP)
- add_definitions(-DPARALLEL=1)
-else()
- add_definitions(-DPARALLEL=0)
-endif()
-
-# Work around hang with GCC and ASAN.
-if(WITH_COMPILER_ASAN)
- if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
- set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fno-sanitize=vptr")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-sanitize=vptr")
- endif()
-endif()
-
-blender_add_lib_nolist(bf_intern_elbeem "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/intern/elbeem/COPYING b/intern/elbeem/COPYING
deleted file mode 100644
index 2600c731161..00000000000
--- a/intern/elbeem/COPYING
+++ /dev/null
@@ -1,358 +0,0 @@
- All code distributed as part of El'Beem is covered by the following
- version of the GNU General Public License.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- Copyright (c) 2003-2005 Nils Thuerey. All rights reserved.
-
-
-
-
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/intern/elbeem/COPYING_trimesh2 b/intern/elbeem/COPYING_trimesh2
deleted file mode 100644
index a214195fd60..00000000000
--- a/intern/elbeem/COPYING_trimesh2
+++ /dev/null
@@ -1,303 +0,0 @@
-This distribution includes source to "miniball", "freeGLUT",
-and "GLUI", which are covered under their own licenses.
-
-All other code distributed as part of trimesh2 is covered
-by the following license:
-
-
-Copyright (c) 2004 Szymon Rusinkiewicz.
-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.
-
-
-
-
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
diff --git a/intern/elbeem/extern/elbeem.h b/intern/elbeem/extern/elbeem.h
deleted file mode 100644
index 073055cf562..00000000000
--- a/intern/elbeem/extern/elbeem.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * API header
- */
-#ifndef ELBEEM_API_H
-#define ELBEEM_API_H
-
-
-// simulation run callback function type (elbeemSimulationSettings->runsimCallback)
-// best use with FLUIDSIM_CBxxx defines below.
-// >parameters
-// return values: 0=continue, 1=stop, 2=abort
-// data pointer: user data pointer from elbeemSimulationSettings->runsimUserData
-// status integer: 1=running simulation, 2=new frame saved
-// frame integer: if status is 1, contains current frame number
-typedef int (*elbeemRunSimulationCallback)(void *data, int status, int frame);
-#define FLUIDSIM_CBRET_CONTINUE 0
-#define FLUIDSIM_CBRET_STOP 1
-#define FLUIDSIM_CBRET_ABORT 2
-#define FLUIDSIM_CBSTATUS_STEP 1
-#define FLUIDSIM_CBSTATUS_NEWFRAME 2
-
-
-// global settings for the simulation
-typedef struct elbeemSimulationSettings {
- /* version number */
- short version;
- /* id number of simulation domain, needed if more than a
- * single domain should be simulated */
- short domainId; // unused within blender
-
- /* geometrical extent */
- float geoStart[3], geoSize[3];
-
- /* resolutions */
- short resolutionxyz;
- short previewresxyz;
- /* size of the domain in real units (meters along largest resolution x,y,z extent) */
- float realsize;
-
- /* fluid properties */
- double viscosity;
- /* gravity strength */
- float gravity[3];
- /* anim start end time */
- float animStart, aniFrameTime;
- /* no. of frames to simulate & output */
- short noOfFrames;
- /* g star param (LBM compressibility) */
- float gstar;
- /* activate refinement? */
- short maxRefine;
- /* probability for surface particle generation (0.0=off) */
- float generateParticles;
- /* amount of tracer particles to generate (0=off) */
- int numTracerParticles;
-
- /* store output path, and file prefix for baked fluid surface */
- char outputPath[160+80];
-
- /* channel for frame time, visc & gravity animations */
- int channelSizeFrameTime;
- float *channelFrameTime;
- int channelSizeViscosity;
- float *channelViscosity;
- int channelSizeGravity;
- float *channelGravity; // vector
-
- /* boundary types and settings for domain walls */
- short domainobsType;
- float domainobsPartslip;
-
- /* what surfaces to generate */
- int mFsSurfGenSetting;
-
- /* generate speed vectors for vertices (e.g. for image based motion blur)*/
- short generateVertexVectors;
- /* strength of surface smoothing */
- float surfaceSmoothing;
- /* no. of surface subdivisions */
- int surfaceSubdivs;
-
- /* global transformation to apply to fluidsim mesh */
- float surfaceTrafo[4*4];
-
- /* development variables, testing for upcoming releases...*/
- float farFieldSize;
-
- /* callback function to notify calling program of performed simulation steps
- * or newly available frame data, if NULL it is ignored */
- elbeemRunSimulationCallback runsimCallback;
- /* pointer passed to runsimCallback for user data storage */
- void* runsimUserData;
- /* simulation threads used by omp */
- int threads;
-
-} elbeemSimulationSettings;
-
-
-// defines for elbeemMesh->type below
-/* please keep in sync with DNA_object_fluidsim_types.h */
-#define OB_FLUIDSIM_FLUID 4
-#define OB_FLUIDSIM_OBSTACLE 8
-#define OB_FLUIDSIM_INFLOW 16
-#define OB_FLUIDSIM_OUTFLOW 32
-#define OB_FLUIDSIM_PARTICLE 64
-#define OB_FLUIDSIM_CONTROL 128
-
-// defines for elbeemMesh->obstacleType below (low bits) high bits (>=64) are reserved for mFsSurfGenSetting flags which are defined in solver_class.h
-#define FLUIDSIM_OBSTACLE_NOSLIP 1
-#define FLUIDSIM_OBSTACLE_PARTSLIP 2
-#define FLUIDSIM_OBSTACLE_FREESLIP 3
-#define FLUIDSIM_FSSG_NOOBS 64
-
-
-#define OB_VOLUMEINIT_VOLUME 1
-#define OB_VOLUMEINIT_SHELL 2
-#define OB_VOLUMEINIT_BOTH (OB_VOLUMEINIT_SHELL|OB_VOLUMEINIT_VOLUME)
-
-// a single mesh object
-typedef struct elbeemMesh {
- /* obstacle,fluid or inflow or control ... */
- short type;
- /* id of simulation domain it belongs to */
- short parentDomainId;
-
- /* vertices */
- int numVertices;
- float *vertices; // = float[n][3];
- /* animated vertices */
- int channelSizeVertices;
- float *channelVertices; // = float[channelSizeVertices* (n*3+1) ];
-
- /* triangles */
- int numTriangles;
- int *triangles; // = int[][3];
-
- /* animation channels */
- int channelSizeTranslation;
- float *channelTranslation;
- int channelSizeRotation;
- float *channelRotation;
- int channelSizeScale;
- float *channelScale;
-
- /* active channel */
- int channelSizeActive;
- float *channelActive;
- /* initial velocity channel (e.g. for inflow) */
- int channelSizeInitialVel;
- float *channelInitialVel; // vector
- /* use initial velocity in object coordinates? (e.g. for rotation) */
- short localInivelCoords;
- /* boundary types and settings */
- short obstacleType;
- float obstaclePartslip;
- /* amount of force transfer from fluid to obj, 0=off, 1=normal */
- float obstacleImpactFactor;
- /* init volume, shell or both? use OB_VOLUMEINIT_xxx defines above */
- short volumeInitType;
-
- /* name of the mesh, mostly for debugging */
- const char *name;
-
- /* fluid control settings */
- float cpsTimeStart;
- float cpsTimeEnd;
- float cpsQuality;
-
- int channelSizeAttractforceStrength;
- float *channelAttractforceStrength;
- int channelSizeAttractforceRadius;
- float *channelAttractforceRadius;
- int channelSizeVelocityforceStrength;
- float *channelVelocityforceStrength;
- int channelSizeVelocityforceRadius;
- float *channelVelocityforceRadius;
-} elbeemMesh;
-
-// API functions
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-
-// reset elbeemSimulationSettings struct with defaults
-void elbeemResetSettings(struct elbeemSimulationSettings*);
-
-// start fluidsim init (returns !=0 upon failure)
-int elbeemInit(void);
-
-// frees fluidsim
-int elbeemFree(void);
-
-// start fluidsim init (returns !=0 upon failure)
-int elbeemAddDomain(struct elbeemSimulationSettings*);
-
-// get failure message during simulation or init
-// if an error occured (the string is copied into buffer,
-// max. length = 256 chars )
-void elbeemGetErrorString(char *buffer);
-
-// reset elbeemMesh struct with zeroes
-void elbeemResetMesh(struct elbeemMesh*);
-
-// add mesh as fluidsim object
-int elbeemAddMesh(struct elbeemMesh*);
-
-// do the actual simulation
-int elbeemSimulate(void);
-
-// continue a previously stopped simulation
-int elbeemContinueSimulation(void);
-
-
-// helper functions
-
-// simplify animation channels
-// returns if the channel and its size changed
-int elbeemSimplifyChannelFloat(float *channel, int *size);
-int elbeemSimplifyChannelVec3(float *channel, int *size);
-
-// helper functions implemented in utilities.cpp
-
-/* set elbeem debug output level (0=off to 10=full on) */
-void elbeemSetDebugLevel(int level);
-/* elbeem debug output function, prints if debug level >0 */
-void elbeemDebugOut(char *msg);
-
-/* estimate how much memory a given setup will require */
-double elbeemEstimateMemreq(int res,
- float sx, float sy, float sz,
- int refine, char *retstr);
-
-
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-
-
-/******************************************************************************/
-// internal defines, do not use for initializing elbeemMesh
-// structs, for these use OB_xxx defines above
-
-/*! fluid geometry init types */
-// type "int" used, so max is 8
-#define FGI_FLAGSTART 16
-#define FGI_FLUID (1<<(FGI_FLAGSTART+ 0))
-#define FGI_NO_FLUID (1<<(FGI_FLAGSTART+ 1))
-#define FGI_BNDNO (1<<(FGI_FLAGSTART+ 2))
-#define FGI_BNDFREE (1<<(FGI_FLAGSTART+ 3))
-#define FGI_BNDPART (1<<(FGI_FLAGSTART+ 4))
-#define FGI_NO_BND (1<<(FGI_FLAGSTART+ 5))
-#define FGI_MBNDINFLOW (1<<(FGI_FLAGSTART+ 6))
-#define FGI_MBNDOUTFLOW (1<<(FGI_FLAGSTART+ 7))
-#define FGI_CONTROL (1<<(FGI_FLAGSTART+ 8))
-
-// all boundary types at once
-#define FGI_ALLBOUNDS ( FGI_BNDNO | FGI_BNDFREE | FGI_BNDPART | FGI_MBNDINFLOW | FGI_MBNDOUTFLOW )
-
-
-#endif // ELBEEM_API_H
diff --git a/intern/elbeem/intern/attributes.cpp b/intern/elbeem/intern/attributes.cpp
deleted file mode 100644
index beebc459c1a..00000000000
--- a/intern/elbeem/intern/attributes.cpp
+++ /dev/null
@@ -1,362 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * DEPRECATED - replaced by elbeem API, only channels are still used
- *
- *****************************************************************************/
-
-#include "attributes.h"
-#include "ntl_matrices.h"
-#include "elbeem.h"
-
-
-
-/******************************************************************************
- * attribute conversion functions
- *****************************************************************************/
-
-bool Attribute::initChannel(int elemSize) {
- elemSize=0; // remove warning
- return false;
-}
-string Attribute::getAsString(bool debug) {
- debug=false; // remove warning
- return string("");
-}
-int Attribute::getAsInt() {
- return 0;
-}
-bool Attribute::getAsBool() {
- return false;
-}
-double Attribute::getAsFloat() {
- return 0.;
-}
-ntlVec3d Attribute::getAsVec3d() {
- return ntlVec3d(0.);
-}
-void Attribute::getAsMat4Gfx(ntlMat4Gfx *mat) {
- mat=NULL; // remove warning
-}
-string Attribute::getCompleteString() {
- return string("");
-}
-
-
-/******************************************************************************
- * channel returns
- *****************************************************************************/
-
-AnimChannel<double> Attribute::getChannelFloat() {
- return AnimChannel<double>();
-}
-AnimChannel<int> Attribute::getChannelInt() {
- return AnimChannel<int>();
-}
-AnimChannel<ntlVec3d> Attribute::getChannelVec3d() {
- return AnimChannel<ntlVec3d>();
-}
-AnimChannel<ntlSetVec3f>
-Attribute::getChannelSetVec3f() {
- return AnimChannel<ntlSetVec3f>();
-}
-
-/******************************************************************************
- * check if there were unknown params
- *****************************************************************************/
-bool AttributeList::checkUnusedParams() {
- return false;
-}
-void AttributeList::setAllUsed() {
-}
-
-/******************************************************************************
- * Attribute list read functions
- *****************************************************************************/
-int AttributeList::readInt(string name, int defaultValue, string source,string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return defaultValue;
-}
-bool AttributeList::readBool(string name, bool defaultValue, string source,string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return defaultValue;
-}
-double AttributeList::readFloat(string name, double defaultValue, string source,string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return defaultValue;
-}
-string AttributeList::readString(string name, string defaultValue, string source,string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return defaultValue;
-}
-ntlVec3d AttributeList::readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return defaultValue;
-}
-
-void AttributeList::readMat4Gfx(string name, ntlMat4Gfx defaultValue, string source,string target, bool needed, ntlMat4Gfx *mat) {
- *mat = defaultValue;
- name=source=target=string(""); needed=false; mat=NULL; // remove warning
-}
-
-// set that a parameter can be given, and will be ignored...
-bool AttributeList::ignoreParameter(string name, string source) {
- name = source = ("");
- return false;
-}
-
-// read channels
-AnimChannel<int> AttributeList::readChannelInt(string name, int defaultValue, string source, string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<int>(defaultValue);
-}
-AnimChannel<double> AttributeList::readChannelFloat(string name, double defaultValue, string source, string target, bool needed ) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<double>(defaultValue);
-}
-AnimChannel<ntlVec3d> AttributeList::readChannelVec3d(string name, ntlVec3d defaultValue, string source, string target, bool needed ) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<ntlVec3d>(defaultValue);
-}
-AnimChannel<ntlSetVec3f> AttributeList::readChannelSetVec3f(string name, ntlSetVec3f defaultValue, string source, string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<ntlSetVec3f>(defaultValue);
-}
-AnimChannel<float> AttributeList::readChannelSinglePrecFloat(string name, float defaultValue, string source, string target, bool needed ) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<float>(defaultValue);
-}
-AnimChannel<ntlVec3f> AttributeList::readChannelVec3f(string name, ntlVec3f defaultValue, string source, string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<ntlVec3f>(defaultValue);
-}
-
-/******************************************************************************
- * destructor
- *****************************************************************************/
-AttributeList::~AttributeList() {
-};
-
-
-/******************************************************************************
- * debugging
- *****************************************************************************/
-
-//! debug function, prints value
-void Attribute::print() {
-}
-
-//! debug function, prints all attribs
-void AttributeList::print() {
-}
-
-
-/******************************************************************************
- * import attributes from other attribute list
- *****************************************************************************/
-void AttributeList::import(AttributeList *oal) {
- oal=NULL; // remove warning
-}
-
-
-/******************************************************************************
- * channel max finding
- *****************************************************************************/
-ntlVec3f channelFindMaxVf (AnimChannel<ntlVec3f> channel) {
- ntlVec3f ret(0.0);
- float maxLen = 0.0;
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- float nlen = normNoSqrt(channel.accessValues()[i]);
- if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
- }
- return ret;
-}
-ntlVec3d channelFindMaxVd (AnimChannel<ntlVec3d> channel) {
- ntlVec3d ret(0.0);
- float maxLen = 0.0;
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- float nlen = normNoSqrt(channel.accessValues()[i]);
- if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
- }
- return ret;
-}
-int channelFindMaxi (AnimChannel<float > channel) {
- int ret = 0;
- float maxLen = 0.0;
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- float nlen = ABS(channel.accessValues()[i]);
- if(nlen>maxLen) { ret= (int)channel.accessValues()[i]; maxLen=nlen; }
- }
- return ret;
-}
-float channelFindMaxf (AnimChannel<float > channel) {
- float ret = 0.0;
- float maxLen = 0.0;
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- float nlen = ABS(channel.accessValues()[i]);
- if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
- }
- return ret;
-}
-double channelFindMaxd (AnimChannel<double > channel) {
- double ret = 0.0;
- float maxLen = 0.0;
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- float nlen = ABS(channel.accessValues()[i]);
- if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
- }
- return ret;
-}
-
-/******************************************************************************
- // unoptimized channel simplification functions, use elbeem.cpp functions
- // warning - currently only with single precision
- *****************************************************************************/
-
-template<class SCALAR>
-static bool channelSimplifyScalarT(AnimChannel<SCALAR> &channel) {
- int size = channel.getSize();
- if(size<=1) return false;
- float *nchannel = new float[2*size];
- // convert to array
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- nchannel[i*2 + 0] = (float)channel.accessValues()[i];
- nchannel[i*2 + 1] = (float)channel.accessTimes()[i];
- }
- bool ret = elbeemSimplifyChannelFloat(nchannel, &size);
- if(ret) {
- vector<SCALAR> vals;
- vector<double> times;
- for(int i=0; i<size; i++) {
- vals.push_back( (SCALAR)(nchannel[i*2 + 0]) );
- times.push_back( (double)(nchannel[i*2 + 1]) );
- }
- channel = AnimChannel<SCALAR>(vals, times);
- }
- delete [] nchannel;
- return ret;
-}
-bool channelSimplifyi (AnimChannel<int > &channel) { return channelSimplifyScalarT<int>(channel); }
-bool channelSimplifyf (AnimChannel<float> &channel) { return channelSimplifyScalarT<float>(channel); }
-bool channelSimplifyd (AnimChannel<double > &channel) { return channelSimplifyScalarT<double>(channel); }
-template<class VEC>
-static bool channelSimplifyVecT(AnimChannel<VEC> &channel) {
- int size = channel.getSize();
- if(size<=1) return false;
- float *nchannel = new float[4*size];
- // convert to array
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- nchannel[i*4 + 0] = (float)channel.accessValues()[i][0];
- nchannel[i*4 + 1] = (float)channel.accessValues()[i][1];
- nchannel[i*4 + 2] = (float)channel.accessValues()[i][2];
- nchannel[i*4 + 3] = (float)channel.accessTimes()[i];
- }
- bool ret = elbeemSimplifyChannelVec3(nchannel, &size);
- if(ret) {
- vector<VEC> vals;
- vector<double> times;
- for(int i=0; i<size; i++) {
- vals.push_back( VEC(nchannel[i*4 + 0], nchannel[i*4 + 1], nchannel[i*4 + 2] ) );
- times.push_back( (double)(nchannel[i*4 + 3]) );
- }
- channel = AnimChannel<VEC>(vals, times);
- }
- delete [] nchannel;
- return ret;
-}
-bool channelSimplifyVf (AnimChannel<ntlVec3f> &channel) {
- return channelSimplifyVecT<ntlVec3f>(channel);
-}
-bool channelSimplifyVd (AnimChannel<ntlVec3d> &channel) {
- return channelSimplifyVecT<ntlVec3d>(channel);
-}
-
-//! debug function, prints channel as string
-template<class Scalar>
-string AnimChannel<Scalar>::printChannel() {
- std::ostringstream ostr;
- ostr << " CHANNEL #"<< mValue.size() <<" = { ";
- for(size_t i=0;i<mValue.size();i++) {
- ostr <<"'"<< mValue[i]<<"' ";
- ostr << "@"<<mTimes[i]<<"; ";
- }
- ostr << " } ";
- return ostr.str();
-} // */
-
-// is now in header file: debugPrintChannel()
-// hack to force instantiation
-void __forceAnimChannelInstantiation() {
- AnimChannel< float > tmp1;
- AnimChannel< double > tmp2;
- AnimChannel< string > tmp3;
- AnimChannel< ntlVector3Dim<float> > tmp4;
- AnimChannel< ntlVector3Dim<double> > tmp5;
- tmp1.debugPrintChannel();
- tmp2.debugPrintChannel();
- tmp3.debugPrintChannel();
- tmp4.debugPrintChannel();
- tmp5.debugPrintChannel();
-}
-
-
-ntlSetVec3f::ntlSetVec3f(double v ) {
- mVerts.clear();
- mVerts.push_back( ntlVec3f(v) );
-}
-const ntlSetVec3f&
-ntlSetVec3f::operator=(double v ) {
- mVerts.clear();
- mVerts.push_back( ntlVec3f(v) );
- return *this;
-}
-
-std::ostream& operator<<( std::ostream& os, const ntlSetVec3f& vs ) {
- os<< "{";
- for(int j=0;j<(int)vs.mVerts.size();j++) os<<vs.mVerts[j];
- os<< "}";
- return os;
-}
-
-ntlSetVec3f&
-ntlSetVec3f::operator+=( double v )
-{
- for(int j=0;j<(int)(mVerts.size()) ;j++) {
- mVerts[j] += v;
- }
- return *this;
-}
-
-ntlSetVec3f&
-ntlSetVec3f::operator+=( const ntlSetVec3f &v )
-{
- for(int j=0;j<(int)MIN(mVerts.size(),v.mVerts.size()) ;j++) {
- mVerts[j] += v.mVerts[j];
- }
- return *this;
-}
-
-ntlSetVec3f&
-ntlSetVec3f::operator*=( double v )
-{
- for(int j=0;j<(int)(mVerts.size()) ;j++) {
- mVerts[j] *= v;
- }
- return *this;
-}
-
-ntlSetVec3f&
-ntlSetVec3f::operator*=( const ntlSetVec3f &v )
-{
- for(int j=0;j<(int)MIN(mVerts.size(),v.mVerts.size()) ;j++) {
- mVerts[j] *= v.mVerts[j];
- }
- return *this;
-}
-
-
diff --git a/intern/elbeem/intern/attributes.h b/intern/elbeem/intern/attributes.h
deleted file mode 100644
index 2d3b85887f5..00000000000
--- a/intern/elbeem/intern/attributes.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * DEPRECATED - replaced by elbeem API, only channels are still used
- *
- *****************************************************************************/
-
-
-#ifndef NTL_ATTRIBUTES_H
-
-#include "utilities.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-template<class T> class ntlMatrix4x4;
-class ntlSetVec3f;
-std::ostream& operator<<( std::ostream& os, const ntlSetVec3f& i );
-
-
-
-//! An animated attribute channel
-template<class Scalar>
-class AnimChannel
-{
- public:
- // default constructor
- AnimChannel() :
- mValue(), mTimes() { mInited = false; debugPrintChannel(); }
-
- // null init constructor
- AnimChannel(Scalar null) :
- mValue(1), mTimes(1) { mValue[0]=null; mTimes[0]=0.0; mInited = true; debugPrintChannel(); }
-
- // proper init
- AnimChannel(vector<Scalar> &v, vector<double> &t) :
- mValue(v), mTimes(t) { mInited = true; debugPrintChannel(); }
-
- // desctructor, nothing to do
- ~AnimChannel() { };
-
- // get interpolated value at time t
- Scalar get(double t) const {
- if(!mInited) { Scalar null; null=(Scalar)(0.0); return null; }
- if(t<=mTimes[0]) { return mValue[0]; }
- if(t>=mTimes[mTimes.size()-1]) { return mValue[mTimes.size()-1]; }
- for(size_t i=0; i<mTimes.size()-1; i++) {
- // find first time thats in between
- if((mTimes[i]<=t)&&(mTimes[i+1]>t)) {
- // interpolate
- double d = mTimes[i+1]-mTimes[i];
- double f = (t-mTimes[i])/d;
- //return (Scalar)(mValue[i] * (1.0-f) + mValue[i+1] * f);
- Scalar ret,tmp;
- ret = mValue[i];
- ret *= 1.-f;
- tmp = mValue[i+1];
- tmp *= f;
- ret += tmp;
- return ret;
- }
- }
- // whats this...?
- return mValue[0];
- };
-
- // get uninterpolated value at time t
- Scalar getConstant(double t) const {
- //errMsg("DEBB","getc"<<t<<" ");
- if(!mInited) { Scalar null; null=(Scalar)0.0; return null; }
- if(t<=mTimes[0]) { return mValue[0]; }
- if(t>=mTimes[mTimes.size()-1]) { return mValue[mTimes.size()-1]; }
- for(size_t i=0; i<mTimes.size()-1; i++) {
- //errMsg("DEBB","getc i"<<i<<" "<<mTimes[i]);
- // find first time thats in between
- if((mTimes[i]<=t)&&(mTimes[i+1]>t)) { return mValue[i]; }
- }
- // whats this...?
- return mValue[0];
- };
-
- // reset to null value
- void reset(Scalar null) {
- mValue.clear();
- mTimes.clear();
- mValue.push_back(null);
- mTimes.push_back(0.0);
- }
-
- //! debug function, prints channel as string
- string printChannel();
- //! debug function, prints to stdout if DEBUG_CHANNELS flag is enabled, used in constructors
- void debugPrintChannel();
- //! valid init?
- bool isInited() const { return mInited; }
-
- //! get number of entries (value and time sizes have to be equal)
- int getSize() const { return mValue.size(); };
- //! raw access of value vector
- vector<Scalar> &accessValues() { return mValue; }
- //! raw access of time vector
- vector<double> &accessTimes() { return mTimes; }
-
- protected:
-
- /*! inited at least once? */
- bool mInited;
- /*! anim channel attribute values */
- vector<Scalar> mValue;
- /*! anim channel attr times */
- vector<double> mTimes;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:AnimChannel")
-#endif
-};
-
-
-// helper class (not templated) for animated meshes
-class ntlSetVec3f {
- public:
- ntlSetVec3f(): mVerts() {};
- ntlSetVec3f(double v);
- ntlSetVec3f(vector<ntlVec3f> &v) { mVerts = v; };
-
- const ntlSetVec3f& operator=(double v );
- ntlSetVec3f& operator+=( double v );
- ntlSetVec3f& operator+=( const ntlSetVec3f &v );
- ntlSetVec3f& operator*=( double v );
- ntlSetVec3f& operator*=( const ntlSetVec3f &v );
-
- vector<ntlVec3f> mVerts;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlSetVec3f")
-#endif
-};
-
-
-// warning: DEPRECATED - replaced by elbeem API
-class Attribute
-{
- public:
- Attribute(string mn, vector<string> &value, int setline,bool channel) {
- mn = string(""); setline=0; channel=false; value.clear(); // remove warnings
- };
- Attribute(Attribute &a) { a.getCompleteString(); };
- ~Attribute() { };
-
- void setUsed(bool set){ set=false; }
- bool getUsed() { return true; }
- void setIsChannel(bool set){ set=false; }
- bool getIsChannel() { return false; }
-
- string getAsString(bool debug=false);
- int getAsInt();
- bool getAsBool();
- double getAsFloat();
- ntlVec3d getAsVec3d();
- void getAsMat4Gfx(ntlMatrix4x4<gfxReal> *mat);
-
- AnimChannel<int> getChannelInt();
- AnimChannel<double> getChannelFloat();
- AnimChannel<ntlVec3d> getChannelVec3d();
- AnimChannel<ntlSetVec3f> getChannelSetVec3f();
-
- string getCompleteString();
- void print();
-
- protected:
-
- bool initChannel(int elemSize);
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:Attribute")
-#endif
-};
-
-
-// warning: DEPRECATED - replaced by elbeem API
-//! The list of configuration attributes
-class AttributeList
-{
- public:
- AttributeList(string name) { name=string(""); };
- ~AttributeList();
- void addAttr(string name, vector<string> &value, int line, bool isChannel) {
- name=string(""); value.clear(); line=0; isChannel=false; // remove warnings
- };
- bool exists(string name) { name=string(""); return false; }
- void setAllUsed();
- bool checkUnusedParams();
- void import(AttributeList *oal);
- int readInt(string name, int defaultValue, string source,string target, bool needed);
- bool readBool(string name, bool defaultValue, string source,string target, bool needed);
- double readFloat(string name, double defaultValue, string source,string target, bool needed);
- string readString(string name, string defaultValue, string source,string target, bool needed);
- ntlVec3d readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed);
- void readMat4Gfx(string name, ntlMatrix4x4<gfxReal> defaultValue, string source,string target, bool needed, ntlMatrix4x4<gfxReal> *mat);
- AnimChannel<int> readChannelInt( string name, int defaultValue=0, string source=string("src"), string target=string("dst"), bool needed=false );
- AnimChannel<double> readChannelFloat( string name, double defaultValue=0, string source=string("src"), string target=string("dst"), bool needed=false );
- AnimChannel<ntlVec3d> readChannelVec3d( string name, ntlVec3d defaultValue=ntlVec3d(0.), string source=string("src"), string target=string("dst"), bool needed=false );
- AnimChannel<ntlSetVec3f> readChannelSetVec3f(string name, ntlSetVec3f defaultValue=ntlSetVec3f(0.), string source=string("src"), string target=string("dst"), bool needed=false );
- AnimChannel<ntlVec3f> readChannelVec3f( string name, ntlVec3f defaultValue=ntlVec3f(0.), string source=string("src"), string target=string("dst"), bool needed=false );
- AnimChannel<float> readChannelSinglePrecFloat( string name, float defaultValue=0., string source=string("src"), string target=string("dst"), bool needed=false );
- bool ignoreParameter(string name, string source);
- void print();
- protected:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:AttributeList")
-#endif
-};
-
-ntlVec3f channelFindMaxVf (AnimChannel<ntlVec3f> channel);
-ntlVec3d channelFindMaxVd (AnimChannel<ntlVec3d> channel);
-int channelFindMaxi (AnimChannel<int > channel);
-float channelFindMaxf (AnimChannel<float > channel);
-double channelFindMaxd (AnimChannel<double > channel);
-
-// unoptimized channel simplification functions, use elbeem.cpp functions
-bool channelSimplifyVf (AnimChannel<ntlVec3f> &channel);
-bool channelSimplifyVd (AnimChannel<ntlVec3d> &channel);
-bool channelSimplifyi (AnimChannel<int > &channel);
-bool channelSimplifyf (AnimChannel<float > &channel);
-bool channelSimplifyd (AnimChannel<double > &channel);
-
-//! output channel values? on=1/off=0
-#define DEBUG_PCHANNELS 0
-
-//! debug function, prints to stdout if DEBUG_PCHANNELS flag is enabled, used in constructors
-template<class Scalar>
-void AnimChannel<Scalar>::debugPrintChannel() { }
-
-
-#define NTL_ATTRIBUTES_H
-#endif
-
diff --git a/intern/elbeem/intern/controlparticles.cpp b/intern/elbeem/intern/controlparticles.cpp
deleted file mode 100644
index efecb354890..00000000000
--- a/intern/elbeem/intern/controlparticles.cpp
+++ /dev/null
@@ -1,1465 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-// --------------------------------------------------------------------------
-//
-// El'Beem - the visual lattice boltzmann freesurface simulator
-// All code distributed as part of El'Beem is covered by the version 2 of the
-// GNU General Public License. See the file COPYING for details.
-//
-// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
-//
-// implementation of control particle handling
-//
-// --------------------------------------------------------------------------
-
-// indicator for LBM inclusion
-#include "ntl_geometrymodel.h"
-#include "ntl_world.h"
-#include "solver_class.h"
-#include "controlparticles.h"
-#include "mvmcoords.h"
-#include <zlib.h>
-
-#ifndef sqrtf
-#define sqrtf sqrt
-#endif
-
-// brute force circle test init in initTimeArray
-// replaced by mDebugInit
-//#define CP_FORCECIRCLEINIT 0
-
-
-void ControlParticles::initBlenderTest() {
- mPartSets.clear();
-
- ControlParticleSet cps;
- mPartSets.push_back(cps);
- int setCnt = mPartSets.size()-1;
- ControlParticle p;
-
- // set for time zero
- mPartSets[setCnt].time = 0.;
-
- // add single particle
- p.reset();
- p.pos = LbmVec(0.5, 0.5, -0.5);
- mPartSets[setCnt].particles.push_back(p);
-
- // add second set for animation
- mPartSets.push_back(cps);
- setCnt = mPartSets.size()-1;
- mPartSets[setCnt].time = 0.15;
-
- // insert new position
- p.reset();
- p.pos = LbmVec(-0.5, -0.5, 0.5);
- mPartSets[setCnt].particles.push_back(p);
-
- // applyTrafos();
- initTime(0. , 1.);
-}
-
-// blender control object gets converted to mvm flui control object
-int ControlParticles::initFromObject(ntlGeometryObjModel *model) {
- vector<ntlTriangle> triangles;
- vector<ntlVec3Gfx> vertices;
- vector<ntlVec3Gfx> normals;
-
- /*
- model->loadBobjModel(string(infile));
-
- model->setLoaded(true);
-
- model->setGeoInitId(gid);
-
-
- printf("a animated? %d\n", model->getIsAnimated());
- printf("b animated? %d\n", model->getMeshAnimated());
- */
-
- model->setGeoInitType(FGI_FLUID);
-
- model->getTriangles(mCPSTimeStart, &triangles, &vertices, &normals, 1 );
- // model->applyTransformation(mCPSTimeStart, &vertices, &normals, 0, vertices.size(), true);
-
- // valid mesh?
- if(triangles.size() <= 0) {
- return 0;
- }
-
- ntlRenderGlobals *glob = new ntlRenderGlobals;
- ntlScene *genscene = new ntlScene( glob, false );
- genscene->addGeoClass(model);
- genscene->addGeoObject(model);
- genscene->buildScene(0., false);
- char treeFlag = (1<<(4+model->getGeoInitId()));
-
- ntlTree *tree = new ntlTree(
- 15, 8, // TREEwarning - fixed values for depth & maxtriangles here...
- genscene, treeFlag );
-
- // TODO? use params
- ntlVec3Gfx start,end;
- model->getExtends(start,end);
- /*
- printf("start - x: %f, y: %f, z: %f\n", start[0], start[1], start[2]);
- printf("end - x: %f, y: %f, z: %f\n", end[0], end[1], end[2]);
- printf("mCPSWidth: %f\n");
-*/
- LbmFloat width = mCPSWidth;
- if(width<=LBM_EPSILON) { errMsg("ControlParticles::initFromMVMCMesh","Invalid mCPSWidth! "<<mCPSWidth); width=mCPSWidth=0.1; }
- ntlVec3Gfx org = start+ntlVec3Gfx(width*0.5);
- gfxReal distance = -1.;
- vector<ntlVec3Gfx> inspos;
-
- // printf("distance: %f, width: %f\n", distance, width);
-
- while(org[2]<end[2]) {
- while(org[1]<end[1]) {
- while(org[0]<end[0]) {
- if(checkPointInside(tree, org, distance)) {
- inspos.push_back(org);
- }
- // TODO optimize, use distance
- org[0] += width;
- }
- org[1] += width;
- org[0] = start[0];
- }
- org[2] += width;
- org[1] = start[1];
- }
-
- // printf("inspos.size(): %d\n", inspos.size());
-
- MeanValueMeshCoords mvm;
- mvm.calculateMVMCs(vertices,triangles, inspos, mCPSWeightFac);
- vector<ntlVec3Gfx> ninspos;
- mvm.transfer(vertices, ninspos);
-
- // init first set, check dist
- ControlParticleSet firstcps; //T
- mPartSets.push_back(firstcps);
- mPartSets[mPartSets.size()-1].time = mCPSTimeStart;
- vector<bool> useCP;
-
- for(int i=0; i<(int)inspos.size(); i++) {
- ControlParticle p; p.reset();
- p.pos = vec2L(inspos[i]);
-
- bool usecpv = true;
-
- mPartSets[mPartSets.size()-1].particles.push_back(p);
- useCP.push_back(usecpv);
- }
-
- // init further sets, temporal mesh sampling
- double tsampling = mCPSTimestep;
- // printf("tsampling: %f, ninspos.size(): %d, mCPSTimeEnd: %f\n", tsampling, ninspos.size(), mCPSTimeEnd);
-
- int tcnt=0;
- for(double t=mCPSTimeStart+tsampling; ((t<mCPSTimeEnd) && (ninspos.size()>0.)); t+=tsampling) {
- ControlParticleSet nextcps; //T
- mPartSets.push_back(nextcps);
- mPartSets[mPartSets.size()-1].time = (gfxReal)t;
-
- vertices.clear(); triangles.clear(); normals.clear();
- model->getTriangles(t, &triangles, &vertices, &normals, 1 );
- mvm.transfer(vertices, ninspos);
-
- tcnt++;
- for(size_t i=0; i < ninspos.size(); i++) {
-
- if(useCP[i]) {
- ControlParticle p; p.reset();
- p.pos = vec2L(ninspos[i]);
- mPartSets[mPartSets.size()-1].particles.push_back(p);
- }
- }
- }
-
- model->setGeoInitType(FGI_CONTROL);
-
- delete tree;
- delete genscene;
- delete glob;
-
- // do reverse here
- if(model->getGeoPartSlipValue())
- {
- mirrorTime();
- }
-
- return 1;
-}
-
-
-// init all zero / defaults for a single particle
-void ControlParticle::reset() {
- pos = LbmVec(0.,0.,0.);
- vel = LbmVec(0.,0.,0.);
- influence = 1.;
- size = 1.;
-#ifndef LBMDIM
-#ifdef MAIN_2D
- rotaxis = LbmVec(0.,1.,0.); // SPH xz
-#else // MAIN_2D
- // 3d - roate in xy plane, vortex
- rotaxis = LbmVec(0.,0.,1.);
- // 3d - rotate for wave
- //rotaxis = LbmVec(0.,1.,0.);
-#endif // MAIN_2D
-#else // LBMDIM
- rotaxis = LbmVec(0.,1.,0.); // LBM xy , is swapped afterwards
-#endif // LBMDIM
-
- density = 0.;
- densityWeight = 0.;
- avgVelAcc = avgVel = LbmVec(0.);
- avgVelWeight = 0.;
-}
-
-
-// default preset/empty init
-ControlParticles::ControlParticles() :
- _influenceTangential(0.f),
- _influenceAttraction(0.f),
- _influenceVelocity(0.f),
- _influenceMaxdist(0.f),
- _radiusAtt(1.0f),
- _radiusVel(1.0f),
- _radiusMinMaxd(2.0f),
- _radiusMaxd(3.0f),
- _currTime(-1.0), _currTimestep(1.),
- _initTimeScale(1.),
- _initPartOffset(0.), _initPartScale(1.),
- _initLastPartOffset(0.), _initLastPartScale(1.),
- _initMirror(""),
- _fluidSpacing(1.), _kernelWeight(-1.),
- _charLength(1.), _charLengthInv(1.),
- mvCPSStart(-10000.), mvCPSEnd(10000.),
- mCPSWidth(0.1), mCPSTimestep(0.02), // was 0.05
- mCPSTimeStart(0.), mCPSTimeEnd(0.5), mCPSWeightFac(1.),
- mDebugInit(0)
-{
- _radiusAtt = 0.15f;
- _radiusVel = 0.15f;
- _radiusMinMaxd = 0.16f;
- _radiusMaxd = 0.3;
-
- _influenceAttraction = 0.f;
- _influenceTangential = 0.f;
- _influenceVelocity = 0.f;
- // 3d tests */
-}
-
-
-
-ControlParticles::~ControlParticles() {
- // nothing to do...
-}
-
-LbmFloat ControlParticles::getControlTimStart() {
- if(mPartSets.size()>0) { return mPartSets[0].time; }
- return -1000.;
-}
-LbmFloat ControlParticles::getControlTimEnd() {
- if(mPartSets.size()>0) { return mPartSets[mPartSets.size()-1].time; }
- return -1000.;
-}
-
-// calculate for delta t
-void ControlParticles::setInfluenceVelocity(LbmFloat set, LbmFloat dt) {
- const LbmFloat dtInter = 0.01;
- LbmFloat facFv = 1.-set; //cparts->getInfluenceVelocity();
- // mLevel[mMaxRefine].timestep
- LbmFloat facNv = (LbmFloat)( 1.-pow( (double)facFv, (double)(dt/dtInter)) );
- //errMsg("vwcalc","ts:"<<dt<< " its:"<<(dt/dtInter) <<" fv"<<facFv<<" nv"<<facNv<<" test:"<< pow( (double)(1.-facNv),(double)(dtInter/dt)) );
- _influenceVelocity = facNv;
-}
-
-int ControlParticles::initExampleSet()
-{
- // unused
- return 0;
-}
-
-int ControlParticles::getTotalSize()
-{
- int s=0;
- for(int i=0; i<(int)mPartSets.size(); i++) {
- s+= mPartSets[i].particles.size();
- }
- return s;
-}
-
-// --------------------------------------------------------------------------
-// load positions & timing from text file
-// WARNING - make sure file has unix format, no win/dos linefeeds...
-#define LINE_LEN 100
-int ControlParticles::initFromTextFile(string filename)
-{
- /*
- const bool debugRead = false;
- char line[LINE_LEN];
- line[LINE_LEN-1] = '\0';
- mPartSets.clear();
- if(filename.size()<2) return 0;
-
- // HACK , use "cparts" suffix as old
- // e.g. "cpart2" as new
- if(filename[ filename.size()-1 ]=='s') {
- return initFromTextFileOld(filename);
- }
-
- FILE *infile = fopen(filename.c_str(), "r");
- if(!infile) {
- errMsg("ControlParticles::initFromTextFile","unable to open '"<<filename<<"' " );
- // try to open as gz sequence
- if(initFromBinaryFile(filename)) { return 1; }
- // try mesh MVCM generation
- if(initFromMVCMesh(filename)) { return 1; }
- // failed...
- return 0;
- }
-
- int haveNo = false;
- int haveScale = false;
- int haveTime = false;
- int noParts = -1;
- int partCnt = 0;
- int setCnt = 0;
- //ControlParticle p; p.reset();
- // scale times by constant factor while reading
- LbmFloat timeScale= 1.0;
- int lineCnt = 0;
- bool abortParse = false;
-#define LASTCP mPartSets[setCnt].particles[ mPartSets[setCnt].particles.size()-1 ]
-
- while( (!feof(infile)) && (!abortParse)) {
- lineCnt++;
- fgets(line, LINE_LEN, infile);
-
- //if(debugRead) printf("\nDEBUG%d r '%s'\n",lineCnt, line);
- if(!line) continue;
- size_t len = strlen(line);
-
- // skip empty lines and comments (#,//)
- if(len<1) continue;
- if( (line[0]=='#') || (line[0]=='\n') ) continue;
- if((len>1) && (line[0]=='/' && line[1]=='/')) continue;
-
- // debug remove newline
- if((len>=1)&&(line[len-1]=='\n')) line[len-1]='\0';
-
- switch(line[0]) {
-
- case 'N': { // total number of particles, more for debugging...
- noParts = atoi(line+2);
- if(noParts<=0) {
- errMsg("ControlParticles::initFromTextFile","file '"<<filename<<"' - invalid no of particles "<<noParts);
- mPartSets.clear(); fclose(infile); return 0;
- }
- if(debugRead) printf("CPDEBUG%d no parts '%d'\n",lineCnt, noParts );
- haveNo = true;
- } break;
-
- case 'T': { // global time scale
- timeScale *= (LbmFloat)atof(line+2);
- if(debugRead) printf("ControlParticles::initFromTextFile - line %d , set timescale '%f', org %f\n",lineCnt, timeScale , _initTimeScale);
- if(timeScale==0.) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error: timescale = 0.! reseting to 1 ...\n",lineCnt); timeScale=1.; }
- haveScale = true;
- } break;
-
- case 'I': { // influence settings, overrides others as of now...
- float val = (LbmFloat)atof(line+3);
- const char *setvar = "[invalid]";
- switch(line[1]) {
- //case 'f': { _influenceFalloff = val; setvar = "falloff"; } break;
- case 't': { _influenceTangential = val; setvar = "tangential"; } break;
- case 'a': { _influenceAttraction = val; setvar = "attraction"; } break;
- case 'v': { _influenceVelocity = val; setvar = "velocity"; } break;
- case 'm': { _influenceMaxdist = val; setvar = "maxdist"; } break;
- default:
- fprintf(stdout,"ControlParticles::initFromTextFile (%s) - line %d , invalid influence setting %c, %f\n",filename.c_str() ,lineCnt, line[1], val);
- }
- if(debugRead) printf("CPDEBUG%d set influence '%s'=%f \n",lineCnt, setvar, val);
- } break;
-
- case 'R': { // radius settings, overrides others as of now...
- float val = (LbmFloat)atof(line+3);
- const char *setvar = "[invalid]";
- switch(line[1]) {
- case 'a': { _radiusAtt = val; setvar = "r_attraction"; } break;
- case 'v': { _radiusVel = val; setvar = "r_velocity"; } break;
- case 'm': { _radiusMaxd = val; setvar = "r_maxdist"; } break;
- default:
- fprintf(stdout,"ControlParticles::initFromTextFile (%s) - line %d , invalid influence setting %c, %f\n",filename.c_str() ,lineCnt, line[1], val);
- }
- if(debugRead) printf("CPDEBUG%d set influence '%s'=%f \n",lineCnt, setvar, val);
- } break;
-
- case 'S': { // new particle set at time T
- ControlParticleSet cps;
- mPartSets.push_back(cps);
- setCnt = (int)mPartSets.size()-1;
-
- LbmFloat val = (LbmFloat)atof(line+2);
- mPartSets[setCnt].time = val * timeScale;
- if(debugRead) printf("CPDEBUG%d new set, time '%f', %d\n",lineCnt, mPartSets[setCnt].time, setCnt );
- haveTime = true;
- partCnt = -1;
- } break;
-
- case 'P': // new particle with pos
- case 'n': { // new particle without pos
- if((!haveTime)||(setCnt<0)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error: set missing!\n",lineCnt); abortParse=true; break; }
- partCnt++;
- if(partCnt>=noParts) {
- if(debugRead) printf("CPDEBUG%d partset done \n",lineCnt);
- haveTime = false;
- } else {
- ControlParticle p; p.reset();
- mPartSets[setCnt].particles.push_back(p);
- }
- }
- // only new part, or new with pos?
- if(line[0] == 'n') break;
-
- // particle properties
-
- case 'p': { // new particle set at time T
- if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|p: particle missing!\n",lineCnt); abortParse=true; break; }
- float px=0.,py=0.,pz=0.;
- if( sscanf(line+2,"%f %f %f",&px,&py,&pz) != 3) {
- fprintf(stdout,"CPDEBUG%d, unable to parse position!\n",lineCnt); abortParse=true; break;
- }
- if(!(finite(px)&&finite(py)&&finite(pz))) { px=py=pz=0.; }
- LASTCP.pos[0] = px;
- LASTCP.pos[1] = py;
- LASTCP.pos[2] = pz;
- if(debugRead) printf("CPDEBUG%d part%d,%d: position %f,%f,%f \n",lineCnt,setCnt,partCnt, px,py,pz);
- } break;
-
- case 's': { // particle size
- if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|s: particle missing!\n",lineCnt); abortParse=true; break; }
- float ps=1.;
- if( sscanf(line+2,"%f",&ps) != 1) {
- fprintf(stdout,"CPDEBUG%d, unable to parse size!\n",lineCnt); abortParse=true; break;
- }
- if(!(finite(ps))) { ps=0.; }
- LASTCP.size = ps;
- if(debugRead) printf("CPDEBUG%d part%d,%d: size %f \n",lineCnt,setCnt,partCnt, ps);
- } break;
-
- case 'i': { // particle influence
- if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|i: particle missing!\n",lineCnt); abortParse=true; break; }
- float pinf=1.;
- if( sscanf(line+2,"%f",&pinf) != 1) {
- fprintf(stdout,"CPDEBUG%d, unable to parse size!\n",lineCnt); abortParse=true; break;
- }
- if(!(finite(pinf))) { pinf=0.; }
- LASTCP.influence = pinf;
- if(debugRead) printf("CPDEBUG%d part%d,%d: influence %f \n",lineCnt,setCnt,partCnt, pinf);
- } break;
-
- case 'a': { // rotation axis
- if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|a: particle missing!\n",lineCnt); abortParse=true; break; }
- float px=0.,py=0.,pz=0.;
- if( sscanf(line+2,"%f %f %f",&px,&py,&pz) != 3) {
- fprintf(stdout,"CPDEBUG%d, unable to parse rotaxis!\n",lineCnt); abortParse=true; break;
- }
- if(!(finite(px)&&finite(py)&&finite(pz))) { px=py=pz=0.; }
- LASTCP.rotaxis[0] = px;
- LASTCP.rotaxis[1] = py;
- LASTCP.rotaxis[2] = pz;
- if(debugRead) printf("CPDEBUG%d part%d,%d: rotaxis %f,%f,%f \n",lineCnt,setCnt,partCnt, px,py,pz);
- } break;
-
-
- default:
- if(debugRead) printf("CPDEBUG%d ignored: '%s'\n",lineCnt, line );
- break;
- }
- }
- if(debugRead && abortParse) printf("CPDEBUG aborted parsing after set... %d\n",(int)mPartSets.size() );
-
- // sanity check
- for(int i=0; i<(int)mPartSets.size(); i++) {
- if( (int)mPartSets[i].particles.size()!=noParts) {
- fprintf(stdout,"ControlParticles::initFromTextFile (%s) - invalid no of particles in set %d, is:%d, shouldbe:%d \n",filename.c_str() ,i,(int)mPartSets[i].particles.size(), noParts);
- mPartSets.clear();
- fclose(infile);
- return 0;
- }
- }
-
- // print stats
- printf("ControlParticles::initFromTextFile (%s): Read %d sets, each %d particles\n",filename.c_str() ,
- (int)mPartSets.size(), noParts );
- if(mPartSets.size()>0) {
- printf("ControlParticles::initFromTextFile (%s): Time: %f,%f\n",filename.c_str() ,mPartSets[0].time, mPartSets[mPartSets.size()-1].time );
- }
-
- // done...
- fclose(infile);
- applyTrafos();
- */
- return 1;
-}
-
-
-int ControlParticles::initFromTextFileOld(string filename)
-{
- /*
- const bool debugRead = false;
- char line[LINE_LEN];
- line[LINE_LEN-1] = '\0';
- mPartSets.clear();
- if(filename.size()<1) return 0;
-
- FILE *infile = fopen(filename.c_str(), "r");
- if(!infile) {
- fprintf(stdout,"ControlParticles::initFromTextFileOld - unable to open '%s'\n",filename.c_str() );
- return 0;
- }
-
- int haveNo = false;
- int haveScale = false;
- int haveTime = false;
- int noParts = -1;
- int coordCnt = 0;
- int partCnt = 0;
- int setCnt = 0;
- ControlParticle p; p.reset();
- // scale times by constant factor while reading
- LbmFloat timeScale= 1.0;
- int lineCnt = 0;
-
- while(!feof(infile)) {
- lineCnt++;
- fgets(line, LINE_LEN, infile);
-
- if(debugRead) printf("\nDEBUG%d r '%s'\n",lineCnt, line);
-
- if(!line) continue;
- size_t len = strlen(line);
-
- // skip empty lines and comments (#,//)
- if(len<1) continue;
- if( (line[0]=='#') || (line[0]=='\n') ) continue;
- if((len>1) && (line[0]=='/' && line[1]=='/')) continue;
-
- // debug remove newline
- if((len>=1)&&(line[len-1]=='\n')) line[len-1]='\0';
-
- // first read no. of particles
- if(!haveNo) {
- noParts = atoi(line);
- if(noParts<=0) {
- fprintf(stdout,"ControlParticles::initFromTextFileOld - invalid no of particles %d\n",noParts);
- mPartSets.clear();
- fclose(infile);
- return 0;
- }
- if(debugRead) printf("DEBUG%d noparts '%d'\n",lineCnt, noParts );
- haveNo = true;
- }
-
- // then read time scale
- else if(!haveScale) {
- timeScale *= (LbmFloat)atof(line);
- if(debugRead) printf("DEBUG%d tsc '%f', org %f\n",lineCnt, timeScale , _initTimeScale);
- haveScale = true;
- }
-
- // then get set time
- else if(!haveTime) {
- ControlParticleSet cps;
- mPartSets.push_back(cps);
- setCnt = (int)mPartSets.size()-1;
-
- LbmFloat val = (LbmFloat)atof(line);
- mPartSets[setCnt].time = val * timeScale;
- if(debugRead) printf("DEBUG%d time '%f', %d\n",lineCnt, mPartSets[setCnt].time, setCnt );
- haveTime = true;
- }
-
- // default read all parts
- else {
- LbmFloat val = (LbmFloat)atof(line);
- if(debugRead) printf("DEBUG: l%d s%d,particle%d '%f' %d,%d/%d\n",lineCnt,(int)mPartSets.size(),(int)mPartSets[setCnt].particles.size(), val ,coordCnt,partCnt,noParts);
- p.pos[coordCnt] = val;
- coordCnt++;
- if(coordCnt>=3) {
- mPartSets[setCnt].particles.push_back(p);
- p.reset();
- coordCnt=0;
- partCnt++;
- }
- if(partCnt>=noParts) {
- partCnt = 0;
- haveTime = false;
- }
- //if(debugRead) printf("DEBUG%d par2 %d,%d/%d\n",lineCnt, coordCnt,partCnt,noParts);
- }
- //read pos, vel ...
- }
-
- // sanity check
- for(int i=0; i<(int)mPartSets.size(); i++) {
- if( (int)mPartSets[i].particles.size()!=noParts) {
- fprintf(stdout,"ControlParticles::initFromTextFileOld - invalid no of particles in set %d, is:%d, shouldbe:%d \n",i,(int)mPartSets[i].particles.size(), noParts);
- mPartSets.clear();
- fclose(infile);
- return 0;
- }
- }
- // print stats
- printf("ControlParticles::initFromTextFileOld: Read %d sets, each %d particles\n",
- (int)mPartSets.size(), noParts );
- if(mPartSets.size()>0) {
- printf("ControlParticles::initFromTextFileOld: Time: %f,%f\n",mPartSets[0].time, mPartSets[mPartSets.size()-1].time );
- }
-
- // done...
- fclose(infile);
- applyTrafos();
- */
- return 1;
-}
-
-// load positions & timing from gzipped binary file
-int ControlParticles::initFromBinaryFile(string filename) {
- mPartSets.clear();
- if(filename.size()<1) return 0;
- int fileNotFound=0;
- int fileFound=0;
- char ofile[256];
-
- for(int set=0; ((set<10000)&&(fileNotFound<10)); set++) {
- snprintf(ofile,256,"%s%04d.gz",filename.c_str(),set);
- //errMsg("ControlParticle::initFromBinaryFile","set"<<set<<" notf"<<fileNotFound<<" ff"<<fileFound);
-
- gzFile gzf;
- gzf = gzopen(ofile, "rb");
- if (!gzf) {
- //errMsg("ControlParticles::initFromBinaryFile","Unable to open file for reading '"<<ofile<<"' ");
- fileNotFound++;
- continue;
- }
- fileNotFound=0;
- fileFound++;
-
- ControlParticleSet cps;
- mPartSets.push_back(cps);
- int setCnt = (int)mPartSets.size()-1;
- //LbmFloat val = (LbmFloat)atof(line+2);
- mPartSets[setCnt].time = (gfxReal)set;
-
- int totpart = 0;
- gzread(gzf, &totpart, sizeof(totpart));
-
- for(int a=0; a<totpart; a++) {
- int ptype=0;
- float psize=0.0;
- ntlVec3Gfx ppos,pvel;
- gzread(gzf, &ptype, sizeof(ptype));
- gzread(gzf, &psize, sizeof(float));
-
- for (int j=0; j<3; j++) { gzread(gzf, &ppos[j], sizeof(float)); }
- for (int j=0; j<3; j++) { gzread(gzf, &pvel[j], sizeof(float)); }
-
- ControlParticle p;
- p.reset();
- p.pos = vec2L(ppos);
- mPartSets[setCnt].particles.push_back(p);
- }
-
- gzclose(gzf);
- //errMsg("ControlParticle::initFromBinaryFile","Read set "<<ofile<<", #"<<mPartSets[setCnt].particles.size() ); // DEBUG
- } // sets
-
- if(fileFound==0) return 0;
- applyTrafos();
- return 1;
-}
-
-int globCPIProblems =0;
-bool ControlParticles::checkPointInside(ntlTree *tree, ntlVec3Gfx org, gfxReal &distance) {
- // warning - stripped down version of geoInitCheckPointInside
- const int globGeoInitDebug = 0;
- const int flags = FGI_FLUID;
- org += ntlVec3Gfx(0.0001);
- ntlVec3Gfx dir = ntlVec3Gfx(1.0, 0.0, 0.0);
- int OId = -1;
- ntlRay ray(org, dir, 0, 1.0, NULL);
- bool done = false;
- bool inside = false;
- int mGiObjInside = 0;
- LbmFloat mGiObjDistance = -1.0;
- LbmFloat giObjFirstHistSide = 0;
-
- // if not inside, return distance to first hit
- gfxReal firstHit=-1.0;
- int firstOId = -1;
- if(globGeoInitDebug) errMsg("IIIstart"," isect "<<org);
-
- while(!done) {
- // find first inside intersection
- ntlTriangle *triIns = NULL;
- distance = -1.0;
- ntlVec3Gfx normal(0.0);
- tree->intersectX(ray,distance,normal, triIns, flags, true);
- if(triIns) {
- ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
- LbmFloat orientation = dot(normal, dir);
- OId = triIns->getObjectId();
- if(orientation<=0.0) {
- // outside hit
- normal *= -1.0;
- mGiObjInside++;
- if(giObjFirstHistSide==0) giObjFirstHistSide = 1;
- if(globGeoInitDebug) errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation);
- } else {
- // inside hit
- mGiObjInside++;
- if(mGiObjDistance<0.0) mGiObjDistance = distance;
- if(globGeoInitDebug) errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation);
- if(giObjFirstHistSide==0) giObjFirstHistSide = -1;
- }
- norg += normal * getVecEpsilon();
- ray = ntlRay(norg, dir, 0, 1.0, NULL);
- // remember first hit distance, in case we're not
- // inside anything
- if(firstHit<0.0) {
- firstHit = distance;
- firstOId = OId;
- }
- } else {
- // no more intersections... return false
- done = true;
- }
- }
-
- distance = -1.0;
- if(mGiObjInside>0) {
- bool mess = false;
- if((mGiObjInside%2)==1) {
- if(giObjFirstHistSide != -1) mess=true;
- } else {
- if(giObjFirstHistSide != 1) mess=true;
- }
- if(mess) {
- // ?
- //errMsg("IIIproblem","At "<<org<<" obj inside:"<<mGiObjInside<<" firstside:"<<giObjFirstHistSide );
- globCPIProblems++;
- mGiObjInside++; // believe first hit side...
- }
- }
-
- if(globGeoInitDebug) errMsg("CHIII"," ins="<<mGiObjInside<<" t"<<mGiObjDistance<<" d"<<distance);
- if(((mGiObjInside%2)==1)&&(mGiObjDistance>0.0)) {
- if( (distance<0.0) || // first intersection -> good
- ((distance>0.0)&&(distance>mGiObjDistance)) // more than one intersection -> use closest one
- ) {
- distance = mGiObjDistance;
- OId = 0;
- inside = true;
- }
- }
-
- if(!inside) {
- distance = firstHit;
- OId = firstOId;
- }
- if(globGeoInitDebug) errMsg("CHIII","ins"<<inside<<" fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId);
-
- return inside;
-}
-int ControlParticles::initFromMVCMesh(string filename) {
- myTime_t mvmstart = getTime();
- ntlGeometryObjModel *model = new ntlGeometryObjModel();
- int gid=1;
- char infile[256];
- vector<ntlTriangle> triangles;
- vector<ntlVec3Gfx> vertices;
- vector<ntlVec3Gfx> normals;
- snprintf(infile,256,"%s.bobj.gz", filename.c_str() );
- model->loadBobjModel(string(infile));
- model->setLoaded(true);
- model->setGeoInitId(gid);
- model->setGeoInitType(FGI_FLUID);
- debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG,"infile:"<<string(infile) ,4);
-
- //getTriangles(double t, vector<ntlTriangle> *triangles, vector<ntlVec3Gfx> *vertices, vector<ntlVec3Gfx> *normals, int objectId );
- model->getTriangles(mCPSTimeStart, &triangles, &vertices, &normals, 1 );
- debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG," tris:"<<triangles.size()<<" verts:"<<vertices.size()<<" norms:"<<normals.size() , 2);
-
- // valid mesh?
- if(triangles.size() <= 0) {
- return 0;
- }
-
- ntlRenderGlobals *glob = new ntlRenderGlobals;
- ntlScene *genscene = new ntlScene( glob, false );
- genscene->addGeoClass(model);
- genscene->addGeoObject(model);
- genscene->buildScene(0., false);
- char treeFlag = (1<<(4+gid));
-
- ntlTree *tree = new ntlTree(
- 15, 8, // TREEwarning - fixed values for depth & maxtriangles here...
- genscene, treeFlag );
-
- // TODO? use params
- ntlVec3Gfx start,end;
- model->getExtends(start,end);
-
- LbmFloat width = mCPSWidth;
- if(width<=LBM_EPSILON) { errMsg("ControlParticles::initFromMVMCMesh","Invalid mCPSWidth! "<<mCPSWidth); width=mCPSWidth=0.1; }
- ntlVec3Gfx org = start+ntlVec3Gfx(width*0.5);
- gfxReal distance = -1.;
- vector<ntlVec3Gfx> inspos;
- int approxmax = (int)( ((end[0]-start[0])/width)*((end[1]-start[1])/width)*((end[2]-start[2])/width) );
-
- debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG,"start"<<start<<" end"<<end<<" w="<<width<<" maxp:"<<approxmax, 5);
- while(org[2]<end[2]) {
- while(org[1]<end[1]) {
- while(org[0]<end[0]) {
- if(checkPointInside(tree, org, distance)) {
- inspos.push_back(org);
- //inspos.push_back(org+ntlVec3Gfx(width));
- //inspos.push_back(start+end*0.5);
- }
- // TODO optimize, use distance
- org[0] += width;
- }
- org[1] += width;
- org[0] = start[0];
- }
- org[2] += width;
- org[1] = start[1];
- }
- debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG,"points: "<<inspos.size()<<" initproblems: "<<globCPIProblems,5 );
-
- MeanValueMeshCoords mvm;
- mvm.calculateMVMCs(vertices,triangles, inspos, mCPSWeightFac);
- vector<ntlVec3Gfx> ninspos;
- mvm.transfer(vertices, ninspos);
-
- // init first set, check dist
- ControlParticleSet firstcps; //T
- mPartSets.push_back(firstcps);
- mPartSets[mPartSets.size()-1].time = (gfxReal)0.;
- vector<bool> useCP;
- bool debugPos=false;
-
- for(int i=0; i<(int)inspos.size(); i++) {
- ControlParticle p; p.reset();
- p.pos = vec2L(inspos[i]);
- //errMsg("COMP "," "<<inspos[i]<<" vs "<<ninspos[i] );
- double cpdist = norm(inspos[i]-ninspos[i]);
- bool usecpv = true;
- if(debugPos) errMsg("COMP "," "<<cpdist<<usecpv);
-
- mPartSets[mPartSets.size()-1].particles.push_back(p);
- useCP.push_back(usecpv);
- }
-
- // init further sets, temporal mesh sampling
- double tsampling = mCPSTimestep;
- int totcnt = (int)( (mCPSTimeEnd-mCPSTimeStart)/tsampling ), tcnt=0;
- for(double t=mCPSTimeStart+tsampling; ((t<mCPSTimeEnd) && (ninspos.size()>0.)); t+=tsampling) {
- ControlParticleSet nextcps; //T
- mPartSets.push_back(nextcps);
- mPartSets[mPartSets.size()-1].time = (gfxReal)t;
-
- vertices.clear(); triangles.clear(); normals.clear();
- model->getTriangles(t, &triangles, &vertices, &normals, 1 );
- mvm.transfer(vertices, ninspos);
- if(tcnt%(totcnt/10)==1) debMsgStd("MeanValueMeshCoords::calculateMVMCs",DM_MSG,"Transferring animation, frame: "<<tcnt<<"/"<<totcnt,5 );
- tcnt++;
- for(int i=0; i<(int)ninspos.size(); i++) {
- if(debugPos) errMsg("COMP "," "<<norm(inspos[i]-ninspos[i]) );
- if(useCP[i]) {
- ControlParticle p; p.reset();
- p.pos = vec2L(ninspos[i]);
- mPartSets[mPartSets.size()-1].particles.push_back(p);
- }
- }
- }
-
- applyTrafos();
-
- myTime_t mvmend = getTime();
- debMsgStd("ControlParticle::initFromMVMCMesh",DM_MSG,"t:"<<getTimeString(mvmend-mvmstart)<<" ",7 );
- delete tree;
- delete genscene;
- delete glob;
-//exit(1); // DEBUG
- return 1;
-}
-
-#define TRISWAP(v,a,b) { LbmFloat tmp = (v)[b]; (v)[b]=(v)[a]; (v)[a]=tmp; }
-#define TRISWAPALL(v,a,b) { \
- TRISWAP( (v).pos ,a,b ); \
- TRISWAP( (v).vel ,a,b ); \
- TRISWAP( (v).rotaxis ,a,b ); }
-
-// helper function for LBM 2D -> swap Y and Z components everywhere
-void ControlParticles::swapCoords(int a, int b) {
- //return;
- for(int i=0; i<(int)mPartSets.size(); i++) {
- for(int j=0; j<(int)mPartSets[i].particles.size(); j++) {
- TRISWAPALL( mPartSets[i].particles[j],a,b );
- }
- }
-}
-
-// helper function for LBM 2D -> mirror time
-void ControlParticles::mirrorTime() {
- LbmFloat maxtime = mPartSets[mPartSets.size()-1].time;
- const bool debugTimeswap = false;
-
- for(int i=0; i<(int)mPartSets.size(); i++) {
- mPartSets[i].time = maxtime - mPartSets[i].time;
- }
-
- for(int i=0; i<(int)mPartSets.size()/2; i++) {
- ControlParticleSet cps = mPartSets[i];
- if(debugTimeswap) errMsg("TIMESWAP", " s"<<i<<","<<mPartSets[i].time<<" and s"<<(mPartSets.size()-1-i)<<","<< mPartSets[mPartSets.size()-1-i].time <<" mt:"<<maxtime );
- mPartSets[i] = mPartSets[mPartSets.size()-1-i];
- mPartSets[mPartSets.size()-1-i] = cps;
- }
-
- for(int i=0; i<(int)mPartSets.size(); i++) {
- if(debugTimeswap) errMsg("TIMESWAP", "done: s"<<i<<","<<mPartSets[i].time<<" "<<mPartSets[i].particles.size() );
- }
-}
-
-// apply init transformations
-void ControlParticles::applyTrafos() {
- // apply trafos
- for(int i=0; i<(int)mPartSets.size(); i++) {
- mPartSets[i].time *= _initTimeScale;
- /*for(int j=0; j<(int)mPartSets[i].particles.size(); j++) {
- for(int k=0; k<3; k++) {
- mPartSets[i].particles[j].pos[k] *= _initPartScale[k];
- mPartSets[i].particles[j].pos[k] += _initPartOffset[k];
- }
- } now done in initarray */
- }
-
- // mirror coords...
- for(int l=0; l<(int)_initMirror.length(); l++) {
- switch(_initMirror[l]) {
- case 'X':
- case 'x':
- //printf("ControlParticles::applyTrafos - mirror x\n");
- swapCoords(1,2);
- break;
- case 'Y':
- case 'y':
- //printf("ControlParticles::applyTrafos - mirror y\n");
- swapCoords(0,2);
- break;
- case 'Z':
- case 'z':
- //printf("ControlParticles::applyTrafos - mirror z\n");
- swapCoords(0,1);
- break;
- case 'T':
- case 't':
- //printf("ControlParticles::applyTrafos - mirror time\n");
- mirrorTime();
- break;
- case ' ':
- case '-':
- case '\n':
- break;
- default:
- //printf("ControlParticles::applyTrafos - mirror unknown %c !?\n", _initMirror[l] );
- break;
- }
- }
-
- // reset 2d positions
-#if (CP_PROJECT2D==1) && ( defined(MAIN_2D) || LBMDIM==2 )
- for(size_t j=0; j<mPartSets.size(); j++)
- for(size_t i=0; i<mPartSets[j].particles.size(); i++) {
- // DEBUG
- mPartSets[j].particles[i].pos[1] = 0.f;
- }
-#endif
-
-#if defined(LBMDIM)
- //? if( (getenv("ELBEEM_CPINFILE")) || (getenv("ELBEEM_CPOUTFILE")) ){
- // gui control test, don swap...
- //? } else {
- //? swapCoords(1,2); // LBM 2D -> swap Y and Z components everywhere
- //? }
-#endif
-
- initTime(0.f, 0.f);
-}
-
-#undef TRISWAP
-
-// --------------------------------------------------------------------------
-// init for a given time
-void ControlParticles::initTime(LbmFloat t, LbmFloat dt)
-{
- //fprintf(stdout, "CPINITTIME init %f\n",t);
- _currTime = t;
- if(mPartSets.size()<1) return;
-
- // init zero velocities
- initTimeArray(t, _particles);
-
- // calculate velocities from prev. timestep?
- if(dt>0.) {
- _currTimestep = dt;
- std::vector<ControlParticle> prevparts;
- initTimeArray(t-dt, prevparts);
- LbmFloat invdt = 1.0/dt;
- for(size_t j=0; j<_particles.size(); j++) {
- ControlParticle &p = _particles[j];
- ControlParticle &prevp = prevparts[j];
- for(int k=0; k<3; k++) {
- p.pos[k] *= _initPartScale[k];
- p.pos[k] += _initPartOffset[k];
- prevp.pos[k] *= _initLastPartScale[k];
- prevp.pos[k] += _initLastPartOffset[k];
- }
- p.vel = (p.pos - prevp.pos)*invdt;
- }
-
- if(0) {
- LbmVec avgvel(0.);
- for(size_t j=0; j<_particles.size(); j++) {
- avgvel += _particles[j].vel;
- }
- avgvel /= (LbmFloat)_particles.size();
- //fprintf(stdout," AVGVEL %f,%f,%f \n",avgvel[0],avgvel[1],avgvel[2]); // DEBUG
- }
- }
-}
-
-// helper, init given array
-void ControlParticles::initTimeArray(LbmFloat t, std::vector<ControlParticle> &parts) {
- if(mPartSets.size()<1) return;
-
- if(parts.size()!=mPartSets[0].particles.size()) {
- //fprintf(stdout,"PRES \n");
- parts.resize(mPartSets[0].particles.size());
- // TODO reset all?
- for(size_t j=0; j<parts.size(); j++) {
- parts[j].reset();
- }
- }
- if(parts.size()<1) return;
-
- // debug inits
- if(mDebugInit==1) {
- // hard coded circle init
- for(size_t j=0; j<mPartSets[0].particles.size(); j++) {
- ControlParticle p = mPartSets[0].particles[j];
- // remember old
- p.density = parts[j].density;
- p.densityWeight = parts[j].densityWeight;
- p.avgVel = parts[j].avgVel;
- p.avgVelAcc = parts[j].avgVelAcc;
- p.avgVelWeight = parts[j].avgVelWeight;
- LbmVec ppos(0.); { // DEBUG
- const float tscale=10.;
- const float tprevo = 0.33;
- const LbmVec toff(50,50,0);
- const LbmVec oscale(30,30,0);
- ppos[0] = cos(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[0] + toff[0];
- ppos[1] = -sin(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[1] + toff[1];
- ppos[2] = toff[2]; } // DEBUG
- p.pos = ppos;
- parts[j] = p;
- //errMsg("ControlParticle::initTimeArray","j:"<<j<<" p:"<<parts[j].pos );
- }
- return;
- }
- else if(mDebugInit==2) {
- // hard coded spiral init
- const float tscale=-10.;
- const float tprevo = 0.33;
- LbmVec toff(50,0,-50);
- const LbmVec oscale(20,20,0);
- toff[2] += 30. * t +30.;
- for(size_t j=0; j<mPartSets[0].particles.size(); j++) {
- ControlParticle p = mPartSets[0].particles[j];
- // remember old
- p.density = parts[j].density;
- p.densityWeight = parts[j].densityWeight;
- p.avgVel = parts[j].avgVel;
- p.avgVelAcc = parts[j].avgVelAcc;
- p.avgVelWeight = parts[j].avgVelWeight;
- LbmVec ppos(0.);
- ppos[1] = toff[2];
- LbmFloat zscal = (ppos[1]+100.)/200.;
- ppos[0] = cos(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[0]*zscal + toff[0];
- ppos[2] = -sin(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[1]*zscal + toff[1];
- p.pos = ppos;
- parts[j] = p;
-
- toff[2] += 0.25;
- }
- return;
- }
-
- // use first set
- if((t<=mPartSets[0].time)||(mPartSets.size()==1)) {
- //fprintf(stdout,"PINI %f \n", t);
- //parts = mPartSets[0].particles;
- const int i=0;
- for(size_t j=0; j<mPartSets[i].particles.size(); j++) {
- ControlParticle p = mPartSets[i].particles[j];
- // remember old
- p.density = parts[j].density;
- p.densityWeight = parts[j].densityWeight;
- p.avgVel = parts[j].avgVel;
- p.avgVelAcc = parts[j].avgVelAcc;
- p.avgVelWeight = parts[j].avgVelWeight;
- parts[j] = p;
- }
- return;
- }
-
- for(int i=0; i<(int)mPartSets.size()-1; i++) {
- if((mPartSets[i].time<=t) && (mPartSets[i+1].time>t)) {
- LbmFloat d = mPartSets[i+1].time-mPartSets[i].time;
- LbmFloat f = (t-mPartSets[i].time)/d;
- LbmFloat omf = 1.0f - f;
-
- for(size_t j=0; j<mPartSets[i].particles.size(); j++) {
- ControlParticle *src1=&mPartSets[i ].particles[j];
- ControlParticle *src2=&mPartSets[i+1].particles[j];
- ControlParticle &p = parts[j];
- // do linear interpolation
- p.pos = src1->pos * omf + src2->pos *f;
- p.vel = LbmVec(0.); // reset, calculated later on src1->vel * omf + src2->vel *f;
- p.rotaxis = src1->rotaxis * omf + src2->rotaxis *f;
- p.influence = src1->influence * omf + src2->influence *f;
- p.size = src1->size * omf + src2->size *f;
- // dont modify: density, densityWeight
- }
- }
- }
-
- // after last?
- if(t>=mPartSets[ mPartSets.size() -1 ].time) {
- //parts = mPartSets[ mPartSets.size() -1 ].particles;
- const int i= (int)mPartSets.size() -1;
- for(size_t j=0; j<mPartSets[i].particles.size(); j++) {
- ControlParticle p = mPartSets[i].particles[j];
- // restore
- p.density = parts[j].density;
- p.densityWeight = parts[j].densityWeight;
- p.avgVel = parts[j].avgVel;
- p.avgVelAcc = parts[j].avgVelAcc;
- p.avgVelWeight = parts[j].avgVelWeight;
- parts[j] = p;
- }
- }
-}
-
-
-
-
-// --------------------------------------------------------------------------
-
-#define DEBUG_MODVEL 0
-
-// recalculate
-void ControlParticles::calculateKernelWeight() {
- const bool debugKernel = true;
-
- // calculate kernel area with respect to particlesize/cellsize
- LbmFloat kernelw = -1.;
- LbmFloat kernelnorm = -1.;
- LbmFloat krad = (_radiusAtt*0.75); // FIXME use real cone approximation...?
- //krad = (_influenceFalloff*1.);
-#if (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2)
- kernelw = CP_PI*krad*krad;
- kernelnorm = 1.0 / (_fluidSpacing * _fluidSpacing);
-#else // 2D
- kernelw = CP_PI*krad*krad*krad* (4./3.);
- kernelnorm = 1.0 / (_fluidSpacing * _fluidSpacing * _fluidSpacing);
-#endif // MAIN_2D
-
- if(debugKernel) debMsgStd("ControlParticles::calculateKernelWeight",DM_MSG,"kw"<<kernelw<<", norm"<<
- kernelnorm<<", w*n="<<(kernelw*kernelnorm)<<", rad"<<krad<<", sp"<<_fluidSpacing<<" ", 7);
- LbmFloat kernelws = kernelw*kernelnorm;
- _kernelWeight = kernelws;
- if(debugKernel) debMsgStd("ControlParticles::calculateKernelWeight",DM_MSG,"influence f="<<_radiusAtt<<" t="<<
- _influenceTangential<<" a="<<_influenceAttraction<<" v="<<_influenceVelocity<<" kweight="<<_kernelWeight, 7);
- if(_kernelWeight<=0.) {
- errMsg("ControlParticles::calculateKernelWeight", "invalid kernel! "<<_kernelWeight<<", resetting");
- _kernelWeight = 1.;
- }
-}
-
-void
-ControlParticles::prepareControl(LbmFloat simtime, LbmFloat dt, ControlParticles *motion) {
- debMsgStd("ControlParticle::prepareControl",DM_MSG," simtime="<<simtime<<" dt="<<dt<<" ", 5);
-
- //fprintf(stdout,"PREPARE \n");
- LbmFloat avgdw = 0.;
- for(size_t i=0; i<_particles.size(); i++) {
- ControlParticle *cp = &_particles[i];
-
- if(this->getInfluenceAttraction()<0.) {
- cp->density=
- cp->densityWeight = 1.0;
- continue;
- }
-
- // normalize by kernel
- //cp->densityWeight = (1.0 - (cp->density / _kernelWeight)); // store last
-#if (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2)
- cp->densityWeight = (1.0 - (cp->density / (_kernelWeight*cp->size*cp->size) )); // store last
-#else // 2D
- cp->densityWeight = (1.0 - (cp->density / (_kernelWeight*cp->size*cp->size*cp->size) )); // store last
-#endif // MAIN_2D
-
- if(i<10) debMsgStd("ControlParticle::prepareControl",DM_MSG,"kernelDebug i="<<i<<" densWei="<<cp->densityWeight<<" 1/kw"<<(1.0/_kernelWeight)<<" cpdensity="<<cp->density, 9 );
- if(cp->densityWeight<0.) cp->densityWeight=0.;
- if(cp->densityWeight>1.) cp->densityWeight=1.;
-
- avgdw += cp->densityWeight;
- // reset for next step
- cp->density = 0.;
-
- if(cp->avgVelWeight>0.) {
- cp->avgVel = cp->avgVelAcc/cp->avgVelWeight;
- cp->avgVelWeight = 0.;
- cp->avgVelAcc = LbmVec(0.,0.,0.);
- }
- }
- //if(debugKernel) for(size_t i=0; i<_particles.size(); i++) { ControlParticle *cp = &_particles[i]; fprintf(stdout,"A %f,%f \n",cp->density,cp->densityWeight); }
- avgdw /= (LbmFloat)(_particles.size());
- //if(motion) { printf("ControlParticle::kernel: avgdw:%f, kw%f, sp%f \n", avgdw, _kernelWeight, _fluidSpacing); }
-
- //if((simtime>=0.) && (simtime != _currTime))
- initTime(simtime, dt);
-
- if((motion) && (motion->getSize()>0)){
- ControlParticle *motionp = motion->getParticle(0);
- //printf("ControlParticle::prepareControl motion: pos[%f,%f,%f] vel[%f,%f,%f] \n", motionp->pos[0], motionp->pos[1], motionp->pos[2], motionp->vel[0], motionp->vel[1], motionp->vel[2] );
- for(size_t i=0; i<_particles.size(); i++) {
- ControlParticle *cp = &_particles[i];
- cp->pos = cp->pos + motionp->pos;
- cp->vel = cp->vel + motionp->vel;
- cp->size = cp->size * motionp->size;
- cp->influence = cp->size * motionp->influence;
- }
- }
-
- // reset to radiusAtt by default
- if(_radiusVel==0.) _radiusVel = _radiusAtt;
- if(_radiusMinMaxd==0.) _radiusMinMaxd = _radiusAtt;
- if(_radiusMaxd==0.) _radiusMaxd = 2.*_radiusAtt;
- // has to be radiusVel<radiusAtt<radiusMinMaxd<radiusMaxd
- if(_radiusVel>_radiusAtt) _radiusVel = _radiusAtt;
- if(_radiusAtt>_radiusMinMaxd) _radiusAtt = _radiusMinMaxd;
- if(_radiusMinMaxd>_radiusMaxd) _radiusMinMaxd = _radiusMaxd;
-
- //printf("ControlParticle::radii vel:%f att:%f min:%f max:%f \n", _radiusVel,_radiusAtt,_radiusMinMaxd,_radiusMaxd);
- // prepareControl done
-}
-
-void ControlParticles::finishControl(std::vector<ControlForces> &forces, LbmFloat iatt, LbmFloat ivel, LbmFloat imaxd) {
-
- //const LbmFloat iatt = this->getInfluenceAttraction() * this->getCurrTimestep();
- //const LbmFloat ivel = this->getInfluenceVelocity();
- //const LbmFloat imaxd = this->getInfluenceMaxdist() * this->getCurrTimestep();
- // prepare for usage
- iatt *= this->getCurrTimestep();
- ivel *= 1.; // not necessary!
- imaxd *= this->getCurrTimestep();
-
- // skip when size=0
- for(int i=0; i<(int)forces.size(); i++) {
- if(DEBUG_MODVEL) fprintf(stdout, "CPFORGF %d , wf:%f,f:%f,%f,%f , v:%f,%f,%f \n",i, forces[i].weightAtt, forces[i].forceAtt[0],forces[i].forceAtt[1],forces[i].forceAtt[2], forces[i].forceVel[0], forces[i].forceVel[1], forces[i].forceVel[2] );
- LbmFloat cfweight = forces[i].weightAtt; // always normalize
- if((cfweight!=0.)&&(iatt!=0.)) {
- // multiple kernels, normalize - note this does not normalize in d>r/2 region
- if(ABS(cfweight)>1.) { cfweight = 1.0/cfweight; }
- // multiply iatt afterwards to allow stronger force
- cfweight *= iatt;
- forces[i].forceAtt *= cfweight;
- } else {
- forces[i].weightAtt = 0.;
- forces[i].forceAtt = LbmVec(0.);
- }
-
- if( (cfweight==0.) && (imaxd>0.) && (forces[i].maxDistance>0.) ) {
- forces[i].forceMaxd *= imaxd;
- } else {
- forces[i].maxDistance= 0.;
- forces[i].forceMaxd = LbmVec(0.);
- }
-
- LbmFloat cvweight = forces[i].weightVel; // always normalize
- if(cvweight>0.) {
- forces[i].forceVel /= cvweight;
- forces[i].compAv /= cvweight;
- // now modify cvweight, and write back
- // important, cut at 1 - otherwise strong vel. influences...
- if(cvweight>1.) { cvweight = 1.; }
- // thus cvweight is in the range of 0..influenceVelocity, currently not normalized by numCParts
- cvweight *= ivel;
- if(cvweight<0.) cvweight=0.;
- if(cvweight>1.) cvweight=1.;
- // LBM, FIXME todo use relaxation factor
- //pvel = (cvel*0.5 * cvweight) + (pvel * (1.0-cvweight));
- forces[i].weightVel = cvweight;
-
- //errMsg("COMPAV","i"<<i<<" compav"<<forces[i].compAv<<" forcevel"<<forces[i].forceVel<<" ");
- } else {
- forces[i].weightVel = 0.;
- if(forces[i].maxDistance==0.) forces[i].forceVel = LbmVec(0.);
- forces[i].compAvWeight = 0.;
- forces[i].compAv = LbmVec(0.);
- }
- if(DEBUG_MODVEL) fprintf(stdout, "CPFINIF %d , wf:%f,f:%f,%f,%f , v:%f,%f,%f \n",i, forces[i].weightAtt, forces[i].forceAtt[0],forces[i].forceAtt[1],forces[i].forceAtt[2], forces[i].forceVel[0],forces[i].forceVel[1],forces[i].forceVel[2] );
- }
-
- // unused...
- if(DEBUG_MODVEL) fprintf(stdout,"MFC iatt:%f,%f ivel:%f,%f ifmd:%f,%f \n", iatt,_radiusAtt, ivel,_radiusVel, imaxd, _radiusMaxd);
- //for(size_t i=0; i<_particles.size(); i++) { ControlParticle *cp = &_particles[i]; fprintf(stdout," %f,%f,%f ",cp->density,cp->densityWeight, (1.0 - (12.0*cp->densityWeight))); }
- //fprintf(stdout,"\n\nCP DONE \n\n\n");
-}
-
-
-// --------------------------------------------------------------------------
-// calculate forces at given position, and modify velocity
-// according to timestep
-void ControlParticles::calculateCpInfluenceOpt(ControlParticle *cp, LbmVec fluidpos, LbmVec fluidvel, ControlForces *force, LbmFloat fillFactor) {
- // dont reset, only add...
- // test distance, simple squared distance reject
- const LbmFloat cpfo = _radiusAtt*cp->size;
-
- LbmVec posDelta;
- if(DEBUG_MODVEL) fprintf(stdout, "CP at %f,%f,%f bef fw:%f, f:%f,%f,%f , vw:%f, v:%f,%f,%f \n",fluidpos[0],fluidpos[1],fluidpos[2], force->weightAtt, force->forceAtt[0], force->forceAtt[1], force->forceAtt[2], force->weightVel, force->forceVel[0], force->forceVel[1], force->forceVel[2]);
- posDelta = cp->pos - fluidpos;
-#if LBMDIM==2 && (CP_PROJECT2D==1)
- posDelta[2] = 0.; // project to xy plane, z-velocity should already be gone...
-#endif
-
- const LbmFloat distsqr = posDelta[0]*posDelta[0]+posDelta[1]*posDelta[1]+posDelta[2]*posDelta[2];
- if(DEBUG_MODVEL) fprintf(stdout, " Pd at %f,%f,%f d%f \n",posDelta[0],posDelta[1],posDelta[2], distsqr);
- // cut at influence=0.5 , scaling not really makes sense
- if(cpfo*cpfo < distsqr) {
- /*if(cp->influence>0.5) {
- if(force->weightAtt == 0.) {
- if(force->maxDistance*force->maxDistance > distsqr) {
- const LbmFloat dis = sqrtf((float)distsqr);
- const LbmFloat sc = dis-cpfo;
- force->maxDistance = dis;
- force->forceMaxd = (posDelta)*(sc/dis);
- }
- } } */
- return;
- }
- force->weightAtt += 1e-6; // for distance
- force->maxDistance = 0.; // necessary for SPH?
-
- const LbmFloat pdistance = MAGNITUDE(posDelta);
- LbmFloat pdistinv = 0.;
- if(ABS(pdistance)>0.) pdistinv = 1./pdistance;
- posDelta *= pdistinv;
-
- LbmFloat falloffAtt = 0.; //CPKernel::kernel(cpfo * 1.0, pdistance);
- const LbmFloat qac = pdistance / cpfo ;
- if (qac < 1.0){ // return 0.;
- if(qac < 0.5) falloffAtt = 1.0f;
- else falloffAtt = (1.0f - qac) * 2.0f;
- }
-
- // vorticity force:
- // - //LbmVec forceVort;
- // - //CROSS(forceVort, posDelta, cp->rotaxis);
- // - //NORMALIZE(forceVort);
- // - if(falloffAtt>1.0) falloffAtt=1.0;
-
-#if (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2)
- // fillFactor *= 2.0 *0.75 * pdistance; // 2d>3d sampling
-#endif // (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2)
-
- LbmFloat signum = getInfluenceAttraction() > 0.0 ? 1.0 : -1.0;
- cp->density += falloffAtt * fillFactor;
- force->forceAtt += posDelta *cp->densityWeight *cp->influence *signum;
- force->weightAtt += falloffAtt*cp->densityWeight *cp->influence;
-
- LbmFloat falloffVel = 0.; //CPKernel::kernel(cpfo * 1.0, pdistance);
- const LbmFloat cpfv = _radiusVel*cp->size;
- if(cpfv*cpfv < distsqr) { return; }
- const LbmFloat qvc = pdistance / cpfo ;
- //if (qvc < 1.0){
- //if(qvc < 0.5) falloffVel = 1.0f;
- //else falloffVel = (1.0f - qvc) * 2.0f;
- //}
- falloffVel = 1.-qvc;
-
- LbmFloat pvWeight; // = (1.0-cp->densityWeight) * _currTimestep * falloffVel;
- pvWeight = falloffVel *cp->influence; // std, without density influence
- //pvWeight *= (1.0-cp->densityWeight); // use inverse density weight
- //pvWeight *= cp->densityWeight; // test, use density weight
- LbmVec modvel(0.);
- modvel += cp->vel * pvWeight;
- //pvWeight = 1.; modvel = partVel; // DEBUG!?
-
- if(pvWeight>0.) {
- force->forceVel += modvel;
- force->weightVel += pvWeight;
-
- cp->avgVelWeight += falloffVel;
- cp->avgVel += fluidvel;
- }
- if(DEBUG_MODVEL) fprintf(stdout, "CP at %f,%f,%f aft fw:%f, f:%f,%f,%f , vw:%f, v:%f,%f,%f \n",fluidpos[0],fluidpos[1],fluidpos[2], force->weightAtt, force->forceAtt[0], force->forceAtt[1], force->forceAtt[2], force->weightVel, force->forceVel[0], force->forceVel[1], force->forceVel[2]);
- return;
-}
-
-void ControlParticles::calculateMaxdForce(ControlParticle *cp, LbmVec fluidpos, ControlForces *force) {
- if(force->weightAtt != 0.) return; // maxd force off
- if(cp->influence <= 0.5) return; // ignore
-
- LbmVec posDelta;
- //if(DEBUG_MODVEL) fprintf(stdout, "CP at %f,%f,%f bef fw:%f, f:%f,%f,%f , vw:%f, v:%f,%f,%f \n",fluidpos[0],fluidpos[1],fluidpos[2], force->weightAtt, force->forceAtt[0], force->forceAtt[1], force->forceAtt[2], force->weightVel, force->forceVel[0], force->forceVel[1], force->forceVel[2]);
- posDelta = cp->pos - fluidpos;
-#if LBMDIM==2 && (CP_PROJECT2D==1)
- posDelta[2] = 0.; // project to xy plane, z-velocity should already be gone...
-#endif
-
- // dont reset, only add...
- // test distance, simple squared distance reject
- const LbmFloat distsqr = posDelta[0]*posDelta[0]+posDelta[1]*posDelta[1]+posDelta[2]*posDelta[2];
-
- // closer cp found
- if(force->maxDistance*force->maxDistance < distsqr) return;
-
- const LbmFloat dmin = _radiusMinMaxd*cp->size;
- if(distsqr<dmin*dmin) return; // inside min
- const LbmFloat dmax = _radiusMaxd*cp->size;
- if(distsqr>dmax*dmax) return; // outside
-
-
- if(DEBUG_MODVEL) fprintf(stdout, " Pd at %f,%f,%f d%f \n",posDelta[0],posDelta[1],posDelta[2], distsqr);
- // cut at influence=0.5 , scaling not really makes sense
- const LbmFloat dis = sqrtf((float)distsqr);
- //const LbmFloat sc = dis - dmin;
- const LbmFloat sc = (dis-dmin)/(dmax-dmin); // scale from 0-1
- force->maxDistance = dis;
- force->forceMaxd = (posDelta/dis) * sc;
- //debug errMsg("calculateMaxdForce","pos"<<fluidpos<<" dis"<<dis<<" sc"<<sc<<" dmin"<<dmin<<" maxd"<< force->maxDistance <<" fmd"<<force->forceMaxd );
- return;
-}
-
diff --git a/intern/elbeem/intern/controlparticles.h b/intern/elbeem/intern/controlparticles.h
deleted file mode 100644
index 37b694f7cf2..00000000000
--- a/intern/elbeem/intern/controlparticles.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-// --------------------------------------------------------------------------
-//
-// El'Beem - the visual lattice boltzmann freesurface simulator
-// All code distributed as part of El'Beem is covered by the version 2 of the
-// GNU General Public License. See the file COPYING for details.
-//
-// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
-//
-// control particle classes
-//
-// --------------------------------------------------------------------------
-
-#ifndef CONTROLPARTICLES_H
-#define CONTROLPARTICLES_H
-
-#include "ntl_geometrymodel.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-// indicator for LBM inclusion
-//#ifndef LBMDIM
-
-//#include <NxFoundation.h>
-//#include <vector>
-//class MultisphGUI;
-//#define NORMALIZE(a) a.normalize()
-//#define MAGNITUDE(a) a.magnitude()
-//#define CROSS(a,b,c) a.cross(b,c)
-//#define ABS(a) (a>0. ? (a) : -(a))
-//#include "cpdefines.h"
-
-//#else // LBMDIM
-
-// use compatibility defines
-//#define NORMALIZE(a) normalize(a)
-//#define MAGNITUDE(a) norm(a)
-//#define CROSS(a,b,c) a=cross(b,c)
-
-//#endif // LBMDIM
-
-#define MAGNITUDE(a) norm(a)
-
-// math.h compatibility
-#define CP_PI ((LbmFloat)3.14159265358979323846)
-
-// project 2d test cases onto plane?
-// if not, 3d distance is used for 2d sim as well
-#define CP_PROJECT2D 1
-
-
-// default init for mincpdist, ControlForces::maxDistance
-#define CPF_MAXDINIT 10000.
-
-// storage of influence for a fluid cell/particle in lbm/sph
-class ControlForces
-{
-public:
- ControlForces() { };
- ~ControlForces() {};
-
- // attraction force
- LbmFloat weightAtt;
- LbmVec forceAtt;
- // velocity influence
- LbmFloat weightVel;
- LbmVec forceVel;
- // maximal distance influence,
- // first is max. distance to first control particle
- // second attraction strength
- LbmFloat maxDistance;
- LbmVec forceMaxd;
-
- LbmFloat compAvWeight;
- LbmVec compAv;
-
- void resetForces() {
- weightAtt = weightVel = 0.;
- maxDistance = CPF_MAXDINIT;
- forceAtt = forceVel = forceMaxd = LbmVec(0.,0.,0.);
- compAvWeight=0.; compAv=LbmVec(0.);
- };
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ControlForces")
-#endif
-};
-
-
-// single control particle
-class ControlParticle
-{
-public:
- ControlParticle() { reset(); };
- ~ControlParticle() {};
-
- // control parameters
-
- // position
- LbmVec pos;
- // size (influences influence radius)
- LbmFloat size;
- // overall strength of influence
- LbmFloat influence;
- // rotation axis
- LbmVec rotaxis;
-
- // computed values
-
- // velocity
- LbmVec vel;
- // computed density
- LbmFloat density;
- LbmFloat densityWeight;
-
- LbmVec avgVel;
- LbmVec avgVelAcc;
- LbmFloat avgVelWeight;
-
- // init all zero / defaults
- void reset();
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ControlParticle")
-#endif
-};
-
-
-// container for a particle configuration at time t
-class ControlParticleSet
-{
-public:
-
- // time of particle set
- LbmFloat time;
- // particle positions
- std::vector<ControlParticle> particles;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ControlParticleSet")
-#endif
-};
-
-
-// container & management of control particles
-class ControlParticles
-{
-public:
- ControlParticles();
- ~ControlParticles();
-
- // reset datastructures for next influence step
- // if motion object is given, particle 1 of second system is used for overall
- // position and speed offset
- void prepareControl(LbmFloat simtime, LbmFloat dt, ControlParticles *motion);
- // post control operations
- void finishControl(std::vector<ControlForces> &forces, LbmFloat iatt, LbmFloat ivel, LbmFloat imaxd);
- // recalculate
- void calculateKernelWeight();
-
- // calculate forces at given position, and modify velocity
- // according to timestep (from initControl)
- void calculateCpInfluenceOpt (ControlParticle *cp, LbmVec fluidpos, LbmVec fluidvel, ControlForces *force, LbmFloat fillFactor);
- void calculateMaxdForce (ControlParticle *cp, LbmVec fluidpos, ControlForces *force);
-
- // no. of particles
- inline int getSize() { return (int)_particles.size(); }
- int getTotalSize();
- // get particle [i]
- inline ControlParticle* getParticle(int i){ return &_particles[i]; }
-
- // set influence parameters
- void setInfluenceTangential(LbmFloat set) { _influenceTangential=set; }
- void setInfluenceAttraction(LbmFloat set) { _influenceAttraction=set; }
- void setInfluenceMaxdist(LbmFloat set) { _influenceMaxdist=set; }
- // calculate for delta t
- void setInfluenceVelocity(LbmFloat set, LbmFloat dt);
- // get influence parameters
- inline LbmFloat getInfluenceAttraction() { return _influenceAttraction; }
- inline LbmFloat getInfluenceTangential() { return _influenceTangential; }
- inline LbmFloat getInfluenceVelocity() { return _influenceVelocity; }
- inline LbmFloat getInfluenceMaxdist() { return _influenceMaxdist; }
- inline LbmFloat getCurrTimestep() { return _currTimestep; }
-
- void setRadiusAtt(LbmFloat set) { _radiusAtt=set; }
- inline LbmFloat getRadiusAtt() { return _radiusAtt; }
- void setRadiusVel(LbmFloat set) { _radiusVel=set; }
- inline LbmFloat getRadiusVel() { return _radiusVel; }
- void setRadiusMaxd(LbmFloat set) { _radiusMaxd=set; }
- inline LbmFloat getRadiusMaxd() { return _radiusMaxd; }
- void setRadiusMinMaxd(LbmFloat set) { _radiusMinMaxd=set; }
- inline LbmFloat getRadiusMinMaxd() { return _radiusMinMaxd; }
-
- LbmFloat getControlTimStart();
- LbmFloat getControlTimEnd();
-
- // set/get characteristic length (and inverse)
- void setCharLength(LbmFloat set) { _charLength=set; _charLengthInv=1./_charLength; }
- inline LbmFloat getCharLength() { return _charLength;}
- inline LbmFloat getCharLengthInv() { return _charLengthInv;}
-
- // set init parameters
- void setInitTimeScale(LbmFloat set) { _initTimeScale = set; };
- void setInitMirror(string set) { _initMirror = set; };
- string getInitMirror() { return _initMirror; };
-
- void setLastOffset(LbmVec set) { _initLastPartOffset = set; };
- void setLastScale(LbmVec set) { _initLastPartScale = set; };
- void setOffset(LbmVec set) { _initPartOffset = set; };
- void setScale(LbmVec set) { _initPartScale = set; };
-
- // set/get cps params
- void setCPSWith(LbmFloat set) { mCPSWidth = set; };
- void setCPSTimestep(LbmFloat set) { mCPSTimestep = set; };
- void setCPSTimeStart(LbmFloat set) { mCPSTimeStart = set; };
- void setCPSTimeEnd(LbmFloat set) { mCPSTimeEnd = set; };
- void setCPSMvmWeightFac(LbmFloat set) { mCPSWeightFac = set; };
-
- LbmFloat getCPSWith() { return mCPSWidth; };
- LbmFloat getCPSTimestep() { return mCPSTimestep; };
- LbmFloat getCPSTimeStart() { return mCPSTimeStart; };
- LbmFloat getCPSTimeEnd() { return mCPSTimeEnd; };
- LbmFloat getCPSMvmWeightFac() { return mCPSWeightFac; };
-
- void setDebugInit(int set) { mDebugInit = set; };
-
- // set init parameters
- void setFluidSpacing(LbmFloat set) { _fluidSpacing = set; };
-
- // load positions & timing from text file
- int initFromTextFile(string filename);
- int initFromTextFileOld(string filename);
- // load positions & timing from gzipped binary file
- int initFromBinaryFile(string filename);
- int initFromMVCMesh(string filename);
- // init an example test case
- int initExampleSet();
-
- // init for a given time
- void initTime(LbmFloat t, LbmFloat dt);
-
- // blender test init
- void initBlenderTest();
-
- int initFromObject(ntlGeometryObjModel *model);
-
-protected:
- // sets influence params
- friend class MultisphGUI;
-
- // tangential and attraction influence
- LbmFloat _influenceTangential, _influenceAttraction;
- // direct velocity influence
- LbmFloat _influenceVelocity;
- // maximal distance influence
- LbmFloat _influenceMaxdist;
-
- // influence radii
- LbmFloat _radiusAtt, _radiusVel, _radiusMinMaxd, _radiusMaxd;
-
- // currently valid time & timestep
- LbmFloat _currTime, _currTimestep;
- // all particles
- std::vector<ControlParticle> _particles;
-
- // particle sets
- std::vector<ControlParticleSet> mPartSets;
-
- // additional parameters for initing particles
- LbmFloat _initTimeScale;
- LbmVec _initPartOffset;
- LbmVec _initPartScale;
- LbmVec _initLastPartOffset;
- LbmVec _initLastPartScale;
- // mirror particles for loading?
- string _initMirror;
-
- // row spacing paramter, e.g. use for approximation of kernel area/volume
- LbmFloat _fluidSpacing;
- // save current kernel weight
- LbmFloat _kernelWeight;
- // charateristic length in world coordinates for normalizatioon of forces
- LbmFloat _charLength, _charLengthInv;
-
-
- /*! do ani mesh CPS */
- void calculateCPS(string filename);
- //! ani mesh cps params
- ntlVec3Gfx mvCPSStart, mvCPSEnd;
- gfxReal mCPSWidth, mCPSTimestep;
- gfxReal mCPSTimeStart, mCPSTimeEnd;
- gfxReal mCPSWeightFac;
-
- int mDebugInit;
-
-
-protected:
- // apply init transformations
- void applyTrafos();
-
- // helper function for init -> swap components everywhere
- void swapCoords(int a,int b);
- // helper function for init -> mirror time
- void mirrorTime();
-
- // helper, init given array
- void initTimeArray(LbmFloat t, std::vector<ControlParticle> &parts);
-
- bool checkPointInside(ntlTree *tree, ntlVec3Gfx org, gfxReal &distance);
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ControlParticles")
-#endif
-};
-
-
-
-#endif
-
diff --git a/intern/elbeem/intern/elbeem.cpp b/intern/elbeem/intern/elbeem.cpp
deleted file mode 100644
index 01e4801fed2..00000000000
--- a/intern/elbeem/intern/elbeem.cpp
+++ /dev/null
@@ -1,430 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Main program functions
- */
-
-#include "elbeem.h"
-#include "ntl_blenderdumper.h"
-extern "C" void elbeemCheckDebugEnv(void);
-
-#include "ntl_world.h"
-#include "ntl_geometrymodel.h"
-
-/*****************************************************************************/
-// region of interest global vars
-// currently used by e.g. fsgr solver
-double guiRoiSX = 0.0;
-double guiRoiSY = 0.0;
-double guiRoiSZ = 0.0;
-double guiRoiEX = 1.0;
-double guiRoiEY = 1.0;
-double guiRoiEZ = 1.0;
-int guiRoiMaxLev=6, guiRoiMinLev=0;
-
-//! global raytracer pointer (=world)
-ntlWorld *gpWorld = NULL;
-
-
-
-// API
-
-// reset elbeemSimulationSettings struct with defaults
-extern "C"
-void elbeemResetSettings(elbeemSimulationSettings *set) {
- if(!set) return;
- set->version = 3;
- set->domainId = 0;
- for(int i=0 ; i<3; i++) set->geoStart[i] = 0.0;
- for(int i=0 ; i<3; i++) set->geoSize[i] = 1.0;
- set->resolutionxyz = 64;
- set->previewresxyz = 24;
- set->realsize = 1.0;
- set->viscosity = 0.000001;
-
- for(int i=0 ; i<2; i++) set->gravity[i] = 0.0;
- set->gravity[2] = -9.81;
-
- set->animStart = 0;
- set->aniFrameTime = 0.01;
- set->noOfFrames = 10;
- set->gstar = 0.005;
- set->maxRefine = -1;
- set->generateParticles = 0.0;
- set->numTracerParticles = 0;
- strcpy(set->outputPath,"./elbeemdata_");
-
- set->channelSizeFrameTime=0;
- set->channelFrameTime=NULL;
- set->channelSizeViscosity=0;
- set->channelViscosity=NULL;
- set->channelSizeGravity=0;
- set->channelGravity=NULL;
-
- set->domainobsType= FLUIDSIM_OBSTACLE_NOSLIP;
- set->domainobsPartslip= 0.;
- set->generateVertexVectors = 0;
- set->surfaceSmoothing = 1.;
- set->surfaceSubdivs = 1;
-
- set->farFieldSize = 0.;
- set->runsimCallback = NULL;
- set->runsimUserData = NULL;
-
- // init identity
- for(int i=0; i<16; i++) set->surfaceTrafo[i] = 0.0;
- for(int i=0; i<4; i++) set->surfaceTrafo[i*4+i] = 1.0;
-}
-
-// start fluidsim init
-extern "C"
-int elbeemInit() {
- setElbeemState( SIMWORLD_INITIALIZING );
- setElbeemErrorString("[none]");
- resetGlobalColorSetting();
-
- elbeemCheckDebugEnv();
- debMsgStd("performElbeemSimulation",DM_NOTIFY,"El'Beem Simulation Init Start as Plugin, debugLevel:"<<gDebugLevel<<" ...\n", 2);
-
- // create world object with initial settings
- ntlBlenderDumper *elbeem = new ntlBlenderDumper();
- gpWorld = elbeem;
- return 0;
-}
-
-// fluidsim end
-extern "C"
-int elbeemFree() {
-
- return 0;
-}
-
-// start fluidsim init
-extern "C"
-int elbeemAddDomain(elbeemSimulationSettings *settings) {
- // has to be inited...
- if((getElbeemState() == SIMWORLD_INVALID) && (!gpWorld)) { elbeemInit(); }
- if(getElbeemState() != SIMWORLD_INITIALIZING) { errFatal("elbeemAddDomain","Unable to init simulation world",SIMWORLD_INITERROR); }
- // create domain with given settings
- gpWorld->addDomain(settings);
- return 0;
-}
-
-// error message access
-extern "C"
-void elbeemGetErrorString(char *buffer) {
- if(!buffer) return;
- strncpy(buffer,getElbeemErrorString(),256);
-}
-
-// reset elbeemMesh struct with zeroes
-extern "C"
-void elbeemResetMesh(elbeemMesh *mesh) {
- if(!mesh) return;
- // init typedef struct elbeemMesh
- mesh->type = 0;
-
- mesh->parentDomainId = 0;
-
- /* vertices */
- mesh->numVertices = 0;
- mesh->vertices = NULL;
-
- mesh->channelSizeVertices = 0;
- mesh->channelVertices = NULL;
-
- /* triangles */
- mesh->numTriangles = 0;
- mesh->triangles = NULL;
-
- /* animation channels */
- mesh->channelSizeTranslation = 0;
- mesh->channelTranslation = NULL;
- mesh->channelSizeRotation = 0;
- mesh->channelRotation = NULL;
- mesh->channelSizeScale = 0;
- mesh->channelScale = NULL;
-
- /* active channel */
- mesh->channelSizeActive = 0;
- mesh->channelActive = NULL;
-
- mesh->channelSizeInitialVel = 0;
- mesh->channelInitialVel = NULL;
-
- mesh->localInivelCoords = 0;
-
- mesh->obstacleType= FLUIDSIM_OBSTACLE_NOSLIP;
- mesh->obstaclePartslip= 0.;
- mesh->obstacleImpactFactor= 1.;
-
- mesh->volumeInitType= OB_VOLUMEINIT_VOLUME;
-
- /* name of the mesh, mostly for debugging */
- mesh->name = "[unnamed]";
-
- /* fluid control settings */
- mesh->cpsTimeStart = 0;
- mesh->cpsTimeEnd = 0;
- mesh->cpsQuality = 0;
-
- mesh->channelSizeAttractforceStrength = 0;
- mesh->channelAttractforceStrength = NULL;
- mesh->channelSizeAttractforceRadius = 0;
- mesh->channelAttractforceRadius = NULL;
- mesh->channelSizeVelocityforceStrength = 0;
- mesh->channelVelocityforceStrength = NULL;
- mesh->channelSizeVelocityforceRadius = 0;
- mesh->channelVelocityforceRadius = NULL;
-}
-
-int globalMeshCounter = 1;
-// add mesh as fluidsim object
-extern "C"
-int elbeemAddMesh(elbeemMesh *mesh) {
- int initType;
- if(getElbeemState() != SIMWORLD_INITIALIZING) { errFatal("elbeemAddMesh","World and domain not initialized, call elbeemInit and elbeemAddDomain before...", SIMWORLD_INITERROR); }
-
- switch(mesh->type) {
- case OB_FLUIDSIM_OBSTACLE:
- if (mesh->obstacleType==FLUIDSIM_OBSTACLE_PARTSLIP) initType = FGI_BNDPART;
- else if(mesh->obstacleType==FLUIDSIM_OBSTACLE_FREESLIP) initType = FGI_BNDFREE;
- else /*if(mesh->obstacleType==FLUIDSIM_OBSTACLE_NOSLIP)*/ initType = FGI_BNDNO;
- break;
- case OB_FLUIDSIM_FLUID: initType = FGI_FLUID; break;
- case OB_FLUIDSIM_INFLOW: initType = FGI_MBNDINFLOW; break;
- case OB_FLUIDSIM_OUTFLOW: initType = FGI_MBNDOUTFLOW; break;
- case OB_FLUIDSIM_CONTROL: initType = FGI_CONTROL; break;
- default: return 1; // invalid type
- }
-
- ntlGeometryObjModel *obj = new ntlGeometryObjModel( );
- gpWorld->getRenderGlobals()->getSimScene()->addGeoClass( obj );
- gpWorld->getRenderGlobals()->getRenderScene()->addGeoClass(obj);
- obj->initModel(
- mesh->numVertices, mesh->vertices, mesh->numTriangles, mesh->triangles,
- mesh->channelSizeVertices, mesh->channelVertices );
- if(mesh->name) obj->setName(string(mesh->name));
- else {
- char meshname[100];
- snprintf(meshname,100,"mesh%04d",globalMeshCounter);
- obj->setName(string(meshname));
- }
- globalMeshCounter++;
- obj->setGeoInitId( mesh->parentDomainId+1 );
- obj->setGeoInitIntersect(true);
- obj->setGeoInitType(initType);
-
- // abuse partslip value for control fluid: reverse control keys or not
- if(initType == FGI_CONTROL)
- obj->setGeoPartSlipValue(mesh->obstacleType);
- else
- obj->setGeoPartSlipValue(mesh->obstaclePartslip);
-
- obj->setGeoImpactFactor(mesh->obstacleImpactFactor);
-
- /* fluid control features */
- obj->setCpsTimeStart(mesh->cpsTimeStart);
- obj->setCpsTimeEnd(mesh->cpsTimeEnd);
- obj->setCpsQuality(mesh->cpsQuality);
-
- if((mesh->volumeInitType<VOLUMEINIT_VOLUME)||(mesh->volumeInitType>VOLUMEINIT_BOTH)) mesh->volumeInitType = VOLUMEINIT_VOLUME;
- obj->setVolumeInit(mesh->volumeInitType);
- // use channel instead, obj->setInitialVelocity( ntlVec3Gfx(mesh->iniVelocity[0], mesh->iniVelocity[1], mesh->iniVelocity[2]) );
-
- obj->initChannels(
- mesh->channelSizeTranslation, mesh->channelTranslation,
- mesh->channelSizeRotation, mesh->channelRotation,
- mesh->channelSizeScale, mesh->channelScale,
- mesh->channelSizeActive, mesh->channelActive,
- mesh->channelSizeInitialVel, mesh->channelInitialVel,
- mesh->channelSizeAttractforceStrength, mesh->channelAttractforceStrength,
- mesh->channelSizeAttractforceRadius, mesh->channelAttractforceRadius,
- mesh->channelSizeVelocityforceStrength, mesh->channelVelocityforceStrength,
- mesh->channelSizeVelocityforceRadius, mesh->channelVelocityforceRadius
- );
- obj->setLocalCoordInivel( mesh->localInivelCoords );
-
- debMsgStd("elbeemAddMesh",DM_MSG,"Added elbeem mesh: "<<obj->getName()<<" type="<<initType<<" "<<obj->getIsAnimated(), 9 );
- return 0;
-}
-
-// do the actual simulation
-extern "C"
-int elbeemSimulate(void) {
- if(!gpWorld) return 1;
-
- gpWorld->finishWorldInit();
- if( isSimworldOk() ) {
- myTime_t timestart = getTime();
- gpWorld->renderAnimation();
- myTime_t timeend = getTime();
-
- if(getElbeemState() != SIMWORLD_STOP) {
- // ok, we're done...
- delete gpWorld;
-
- gpWorld = NULL;
- debMsgStd("elbeemSimulate",DM_NOTIFY, "El'Beem simulation done, time: "<<getTimeString(timeend-timestart)<<".\n", 2 );
- } else {
- debMsgStd("elbeemSimulate",DM_NOTIFY, "El'Beem simulation stopped, time so far: "<<getTimeString(timeend-timestart)<<".", 2 );
- }
- return 0;
- }
-
- // failure...
- return 1;
-}
-
-
-// continue a previously stopped simulation
-extern "C"
-int elbeemContinueSimulation(void) {
-
- if(getElbeemState() != SIMWORLD_STOP) {
- errMsg("elbeemContinueSimulation","No running simulation found! Aborting...");
- if(gpWorld) delete gpWorld;
- return 1;
- }
-
- myTime_t timestart = getTime();
- gpWorld->renderAnimation();
- myTime_t timeend = getTime();
-
- if(getElbeemState() != SIMWORLD_STOP) {
- // ok, we're done...
- delete gpWorld;
- gpWorld = NULL;
- debMsgStd("elbeemContinueSimulation",DM_NOTIFY, "El'Beem simulation done, time: "<<getTimeString(timeend-timestart)<<".\n", 2 );
- } else {
- debMsgStd("elbeemContinueSimulation",DM_NOTIFY, "El'Beem simulation stopped, time so far: "<<getTimeString(timeend-timestart)<<".", 2 );
- }
- return 0;
-}
-
-
-// global vector to flag values to remove
-vector<int> gKeepVal;
-
-#define SIMPLIFY_FLOAT_EPSILON (1e-6f)
-#define SIMPLIFY_DOUBLE_EPSILON (1e-12f)
-#define SFLOATEQ(x,y) (ABS((x)-(y)) < SIMPLIFY_FLOAT_EPSILON)
-#define SDOUBLEEQ(x,y) (ABS((x)-(y)) < SIMPLIFY_DOUBLE_EPSILON)
-#define SVECFLOATEQ(x,y) ( \
- (ABS((x)[0]-(y)[0]) < SIMPLIFY_FLOAT_EPSILON) && \
- (ABS((x)[1]-(y)[1]) < SIMPLIFY_FLOAT_EPSILON) && \
- (ABS((x)[2]-(y)[2]) < SIMPLIFY_FLOAT_EPSILON) )
-
-// helper function - simplify animation channels
-extern "C"
-int elbeemSimplifyChannelFloat(float *channel, int* size) {
- bool changed = false;
- int nsize = *size;
- int orgsize = *size;
- if(orgsize<1) return false;
- gKeepVal.resize( orgsize );
- for(int i=0; i<orgsize; i++) { gKeepVal[i] = true; }
- const bool debugSF = false;
-
- float last = channel[0 + 0];
- for(int i=1; i<orgsize; i++) {
- float curr = channel[2*i + 0];
- bool remove = false;
- if(SFLOATEQ(curr,last)) remove = true;
- // dont remove if next value is different
- if((remove)&&(i<orgsize-1)) {
- float next = channel[2*(i+1)+0];
- if(!SFLOATEQ(next,curr)) remove = false;
- }
- if(remove) {
- changed = true;
- gKeepVal[i] = false;
- nsize--;
- }
- if(debugSF) errMsg("elbeemSimplifyChannelFloat","i"<<i<<"/"<<orgsize<<" v"<<channel[ (i*2) + 0 ]<<" t"<<channel[ (i*2) + 1 ]<<" nsize="<<nsize<<" r"<<remove );
- last = curr;
- }
-
- if(changed) {
- nsize = 1;
- for(int i=1; i<orgsize; i++) {
- if(gKeepVal[i]) {
- channel[ (nsize*2) + 0 ] = channel[ (i*2) + 0 ];
- channel[ (nsize*2) + 1 ] = channel[ (i*2) + 1 ];
- nsize++;
- }
- }
- *size = nsize;
- }
-
- if(debugSF) for(int i=1; i<nsize; i++) {
- errMsg("elbeemSimplifyChannelFloat","n i"<<i<<"/"<<nsize<<" v"<<channel[ (i*2) + 0 ]<<" t"<<channel[ (i*2) + 1 ] );
- }
-
- return changed;
-}
-
-extern "C"
-int elbeemSimplifyChannelVec3(float *channel, int* size) {
- bool changed = false;
- int nsize = *size;
- int orgsize = *size;
- if(orgsize<1) return false;
- gKeepVal.resize( orgsize );
- for(int i=0; i<orgsize; i++) { gKeepVal[i] = true; }
- const bool debugVF = false;
-
- ntlVec3f last( channel[0 + 0], channel[0 + 1], channel[0 + 2] );
- for(int i=1; i<orgsize; i++) {
- ntlVec3f curr( channel[4*i + 0], channel[4*i + 1], channel[4*i + 2]);
- bool remove = false;
- if(SVECFLOATEQ(curr,last)) remove = true;
- // dont remove if next value is different
- if((remove)&&(i<orgsize-1)) {
- ntlVec3f next( channel[4*(i+1)+0], channel[4*(i+1)+1], channel[4*(i+1)+2]);
- if(!SVECFLOATEQ(next,curr)) remove = false;
- }
- if(remove) {
- changed = true;
- gKeepVal[i] = false;
- nsize--;
- }
- if(debugVF) errMsg("elbeemSimplifyChannelVec3","i"<<i<<"/"<<orgsize<<" v"<<
- channel[ (i*4) + 0 ]<<","<< channel[ (i*4) + 1 ]<<","<< channel[ (i*4) + 2 ]<<
- " t"<<channel[ (i*4) + 3 ]<<" nsize="<<nsize<<" r"<<remove );
- last = curr;
- }
-
- if(changed) {
- nsize = 1;
- for(int i=1; i<orgsize; i++) {
- if(gKeepVal[i]) {
- for(int j=0; j<4; j++){ channel[ (nsize*4) + j ] = channel[ (i*4) + j ]; }
- nsize++;
- }
- }
- *size = nsize;
- }
-
- if(debugVF) for(int i=1; i<nsize; i++) {
- errMsg("elbeemSimplifyChannelVec3","n i"<<i<<"/"<<nsize<<" v"<<
- channel[ (i*4) + 0 ]<<","<< channel[ (i*4) + 1 ]<<","<< channel[ (i*4) + 2 ]<<
- " t"<<channel[ (i*4) + 3 ] );
- }
-
- return changed;
-}
-
-
-#undef SIMPLIFY_FLOAT_EPSILON
-#undef SIMPLIFY_DOUBLE_EPSILON
-#undef SFLOATEQ
-#undef SDOUBLEEQ
-
diff --git a/intern/elbeem/intern/elbeem_control.cpp b/intern/elbeem/intern/elbeem_control.cpp
deleted file mode 100644
index d033f535979..00000000000
--- a/intern/elbeem/intern/elbeem_control.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Control API header
- */
-
-#include "elbeem.h"
-#include "elbeem_control.h"
-
-// add mesh as fluidsim object
-int elbeemControlAddSet(struct elbeemControl*) {
-
- return 0;
-}
-
-int elbeemControlComputeMesh(struct elbeemMesh*) {
-
-
- return 0;
-}
-
diff --git a/intern/elbeem/intern/elbeem_control.h b/intern/elbeem/intern/elbeem_control.h
deleted file mode 100644
index f8bb9798fc5..00000000000
--- a/intern/elbeem/intern/elbeem_control.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Control API header
- */
-#ifndef ELBEEMCONTROL_API_H
-#define ELBEEMCONTROL_API_H
-
-// a single control particle set
-typedef struct elbeemControl {
- /* influence forces */
- float influenceAttraction;
- float *channelInfluenceAttraction;
- float channelSizeInfluenceAttraction;
-
- float influenceVelocity;
- float *channelInfluenceVelocity;
- float channelSizeInfluenceVelocity;
-
- float influenceMaxdist;
- float *channelInfluenceMaxdist;
- float channelSizeInfluenceMaxdist;
-
- /* influence force radii */
- float radiusAttraction;
- float *channelRadiusAttraction;
- float channelSizeRadiusAttraction;
-
- float radiusVelocity;
- float *channelRadiusVelocity;
- float channelSizeRadiusVelocity;
-
- float radiusMindist;
- float *channelRadiusMindist;
- float channelSizeRadiusMindist;
- float radiusMaxdist;
- float *channelRadiusMaxdist;
- float channelSizeRadiusMaxdist;
-
- /* control particle positions/scale */
- float offset[3];
- float *channelOffset;
- float channelSizeOffset;
-
- float scale[3];
- float *channelScale;
- float channelSizeScale;
-
-} elbeemControl;
-
-
-// add mesh as fluidsim object
-int elbeemControlAddSet(struct elbeemControl*);
-
-// sample & track mesh control particles, TODO add return type...
-int elbeemControlComputeMesh(struct elbeemMesh*);
-
-#endif // ELBEEMCONTROL_API_H
diff --git a/intern/elbeem/intern/globals.h b/intern/elbeem/intern/globals.h
deleted file mode 100644
index 3e8e2691942..00000000000
--- a/intern/elbeem/intern/globals.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-
-// required globals
-
-extern bool glob_mpactive;
-
-extern int glob_mpnum;
-extern int glob_mpindex;
diff --git a/intern/elbeem/intern/isosurface.cpp b/intern/elbeem/intern/isosurface.cpp
deleted file mode 100644
index b270073a362..00000000000
--- a/intern/elbeem/intern/isosurface.cpp
+++ /dev/null
@@ -1,1122 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Marching Cubes surface mesh generation
- *
- *****************************************************************************/
-
-#include "isosurface.h"
-#include "mcubes_tables.h"
-#include "particletracer.h"
-#include <algorithm>
-#include <stdio.h>
-#include <cmath>
-
-#ifdef sun
-#include "ieeefp.h"
-#endif
-
-// just use default rounding for platforms where its not available
-#ifndef round
-#define round(x) (x)
-#endif
-
-using std::isfinite;
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-IsoSurface::IsoSurface(double iso) :
- ntlGeometryObject(),
- mSizex(-1), mSizey(-1), mSizez(-1),
- mpData(NULL),
- mIsoValue( iso ),
- mPoints(),
- mUseFullEdgeArrays(false),
- mpEdgeVerticesX(NULL), mpEdgeVerticesY(NULL), mpEdgeVerticesZ(NULL),
- mEdgeArSize(-1),
- mIndices(),
-
- mStart(0.0), mEnd(0.0), mDomainExtent(0.0),
- mInitDone(false),
- mSmoothSurface(0.0), mSmoothNormals(0.0),
- mAcrossEdge(), mAdjacentFaces(),
- mCutoff(-1), mCutArray(NULL), // off by default
- mpIsoParts(NULL), mPartSize(0.), mSubdivs(0),
- mFlagCnt(1),
- mSCrad1(0.), mSCrad2(0.), mSCcenter(0.)
-{
-}
-
-
-/******************************************************************************
- * The real init...
- *****************************************************************************/
-void IsoSurface::initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent)
-{
- // range 1-10 (max due to subd array in triangulate)
- if(mSubdivs<1) mSubdivs=1;
- if(mSubdivs>10) mSubdivs=10;
-
- // init solver and size
- mSizex = setx;
- mSizey = sety;
- if(setz == 1) {// 2D, create thin 2D surface
- setz = 5;
- }
- mSizez = setz;
- mDomainExtent = extent;
-
- /* check triangulation size (for raytraing) */
- if( ( mStart[0] >= mEnd[0] ) && ( mStart[1] >= mEnd[1] ) && ( mStart[2] >= mEnd[2] ) ){
- // extent was not set, use normalized one from parametrizer
- mStart = ntlVec3Gfx(0.0) - extent*0.5;
- mEnd = ntlVec3Gfx(0.0) + extent*0.5;
- }
-
- // init
- mIndices.clear();
- mPoints.clear();
-
- int nodes = mSizez*mSizey*mSizex;
- mpData = new float[nodes];
- for(int i=0;i<nodes;i++) { mpData[i] = 0.0; }
-
- // allocate edge arrays (last slices are never used...)
- int initsize = -1;
- if(mUseFullEdgeArrays) {
- mEdgeArSize = nodes;
- mpEdgeVerticesX = new int[nodes];
- mpEdgeVerticesY = new int[nodes];
- mpEdgeVerticesZ = new int[nodes];
- initsize = 3*nodes;
- } else {
- int sliceNodes = 2*mSizex*mSizey*mSubdivs*mSubdivs;
- mEdgeArSize = sliceNodes;
- mpEdgeVerticesX = new int[sliceNodes];
- mpEdgeVerticesY = new int[sliceNodes];
- mpEdgeVerticesZ = new int[sliceNodes];
- initsize = 3*sliceNodes;
- }
- for(int i=0;i<mEdgeArSize;i++) { mpEdgeVerticesX[i] = mpEdgeVerticesY[i] = mpEdgeVerticesZ[i] = -1; }
- // WARNING - make sure this is consistent with calculateMemreqEstimate
-
- // marching cubes are ready
- mInitDone = true;
- debMsgStd("IsoSurface::initializeIsosurface",DM_MSG,"Inited, edgenodes:"<<initsize<<" subdivs:"<<mSubdivs<<" fulledg:"<<mUseFullEdgeArrays , 10);
-}
-
-
-
-/*! Reset all values */
-void IsoSurface::resetAll(gfxReal val) {
- int nodes = mSizez*mSizey*mSizex;
- for(int i=0;i<nodes;i++) { mpData[i] = val; }
-}
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-IsoSurface::~IsoSurface( void )
-{
- if(mpData) delete [] mpData;
- if(mpEdgeVerticesX) delete [] mpEdgeVerticesX;
- if(mpEdgeVerticesY) delete [] mpEdgeVerticesY;
- if(mpEdgeVerticesZ) delete [] mpEdgeVerticesZ;
-}
-
-
-
-
-
-/******************************************************************************
- * triangulate the scalar field given by pointer
- *****************************************************************************/
-void IsoSurface::triangulate( void )
-{
- double gsx,gsy,gsz; // grid spacing in x,y,z direction
- double px,py,pz; // current position in grid in x,y,z direction
- IsoLevelCube cubie; // struct for a small subcube
- myTime_t tritimestart = getTime();
-
- if(!mpData) {
- errFatal("IsoSurface::triangulate","no LBM object, and no scalar field...!",SIMWORLD_INITERROR);
- return;
- }
-
- // get grid spacing (-2 to have same spacing as sim)
- gsx = (mEnd[0]-mStart[0])/(double)(mSizex-2.0);
- gsy = (mEnd[1]-mStart[1])/(double)(mSizey-2.0);
- gsz = (mEnd[2]-mStart[2])/(double)(mSizez-2.0);
-
- // clean up previous frame
- mIndices.clear();
- mPoints.clear();
-
- // reset edge vertices
- for(int i=0;i<mEdgeArSize;i++) {
- mpEdgeVerticesX[i] = -1;
- mpEdgeVerticesY[i] = -1;
- mpEdgeVerticesZ[i] = -1;
- }
-
- ntlVec3Gfx pos[8];
- float value[8];
- int cubeIndex; // index entry of the cube
- int triIndices[12]; // vertex indices
- int *eVert[12];
- IsoLevelVertex ilv;
-
- // edges between which points?
- const int mcEdges[24] = {
- 0,1, 1,2, 2,3, 3,0,
- 4,5, 5,6, 6,7, 7,4,
- 0,4, 1,5, 2,6, 3,7 };
-
- const int cubieOffsetX[8] = {
- 0,1,1,0, 0,1,1,0 };
- const int cubieOffsetY[8] = {
- 0,0,1,1, 0,0,1,1 };
- const int cubieOffsetZ[8] = {
- 0,0,0,0, 1,1,1,1 };
-
- const int coAdd=2;
- // let the cubes march
- if(mSubdivs<=1) {
-
- pz = mStart[2]-gsz*0.5;
- for(int k=1;k<(mSizez-2);k++) {
- pz += gsz;
- py = mStart[1]-gsy*0.5;
- for(int j=1;j<(mSizey-2);j++) {
- py += gsy;
- px = mStart[0]-gsx*0.5;
- for(int i=1;i<(mSizex-2);i++) {
- px += gsx;
-
- value[0] = *getData(i ,j ,k );
- value[1] = *getData(i+1,j ,k );
- value[2] = *getData(i+1,j+1,k );
- value[3] = *getData(i ,j+1,k );
- value[4] = *getData(i ,j ,k+1);
- value[5] = *getData(i+1,j ,k+1);
- value[6] = *getData(i+1,j+1,k+1);
- value[7] = *getData(i ,j+1,k+1);
-
- // check intersections of isosurface with edges, and calculate cubie index
- cubeIndex = 0;
- if (value[0] < mIsoValue) cubeIndex |= 1;
- if (value[1] < mIsoValue) cubeIndex |= 2;
- if (value[2] < mIsoValue) cubeIndex |= 4;
- if (value[3] < mIsoValue) cubeIndex |= 8;
- if (value[4] < mIsoValue) cubeIndex |= 16;
- if (value[5] < mIsoValue) cubeIndex |= 32;
- if (value[6] < mIsoValue) cubeIndex |= 64;
- if (value[7] < mIsoValue) cubeIndex |= 128;
-
- // No triangles to generate?
- if (mcEdgeTable[cubeIndex] == 0) {
- continue;
- }
-
- // where to look up if this point already exists
- int edgek = 0;
- if(mUseFullEdgeArrays) edgek=k;
- const int baseIn = ISOLEVEL_INDEX( i+0, j+0, edgek+0);
- eVert[ 0] = &mpEdgeVerticesX[ baseIn ];
- eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ];
- eVert[ 2] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+1, edgek+0) ];
- eVert[ 3] = &mpEdgeVerticesY[ baseIn ];
-
- eVert[ 4] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+0, edgek+1) ];
- eVert[ 5] = &mpEdgeVerticesY[ ISOLEVEL_INDEX( i+1, j+0, edgek+1) ];
- eVert[ 6] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+1, edgek+1) ];
- eVert[ 7] = &mpEdgeVerticesY[ ISOLEVEL_INDEX( i+0, j+0, edgek+1) ];
-
- eVert[ 8] = &mpEdgeVerticesZ[ baseIn ];
- eVert[ 9] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+1, j+0, edgek+0) ];
- eVert[10] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+1, j+1, edgek+0) ];
- eVert[11] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+0, j+1, edgek+0) ];
-
- // grid positions
- pos[0] = ntlVec3Gfx(px ,py ,pz);
- pos[1] = ntlVec3Gfx(px+gsx,py ,pz);
- pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz);
- pos[3] = ntlVec3Gfx(px ,py+gsy,pz);
- pos[4] = ntlVec3Gfx(px ,py ,pz+gsz);
- pos[5] = ntlVec3Gfx(px+gsx,py ,pz+gsz);
- pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz);
- pos[7] = ntlVec3Gfx(px ,py+gsy,pz+gsz);
-
- // check all edges
- for(int e=0;e<12;e++) {
- if (mcEdgeTable[cubeIndex] & (1<<e)) {
- // is the vertex already calculated?
- if(*eVert[ e ] < 0) {
- // interpolate edge
- const int e1 = mcEdges[e*2 ];
- const int e2 = mcEdges[e*2+1];
- const ntlVec3Gfx p1 = pos[ e1 ]; // scalar field pos 1
- const ntlVec3Gfx p2 = pos[ e2 ]; // scalar field pos 2
- const float valp1 = value[ e1 ]; // scalar field val 1
- const float valp2 = value[ e2 ]; // scalar field val 2
- const float mu = (mIsoValue - valp1) / (valp2 - valp1);
-
- // init isolevel vertex
- ilv.v = p1 + (p2-p1)*mu;
- ilv.n = getNormal( i+cubieOffsetX[e1], j+cubieOffsetY[e1], k+cubieOffsetZ[e1]) * (1.0-mu) +
- getNormal( i+cubieOffsetX[e2], j+cubieOffsetY[e2], k+cubieOffsetZ[e2]) * ( mu) ;
- mPoints.push_back( ilv );
-
- triIndices[e] = (mPoints.size()-1);
- // store vertex
- *eVert[ e ] = triIndices[e];
- } else {
- // retrieve from vert array
- triIndices[e] = *eVert[ e ];
- }
- } // along all edges
- }
-
- if( (i<coAdd+mCutoff) || (j<coAdd+mCutoff) ||
- ((mCutoff>0) && (k<coAdd)) ||// bottom layer
- (i>mSizex-2-coAdd-mCutoff) ||
- (j>mSizey-2-coAdd-mCutoff) ) {
- if(mCutArray) {
- if(k < mCutArray[j*this->mSizex+i]) continue;
- } else { continue; }
- }
-
- // Create the triangles...
- for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) {
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] );
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] );
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] );
- }
-
- }//i
- }// j
-
- // copy edge arrays
- if(!mUseFullEdgeArrays) {
- for(int j=0;j<(mSizey-0);j++)
- for(int i=0;i<(mSizex-0);i++) {
- //int edgek = 0;
- const int dst = ISOLEVEL_INDEX( i+0, j+0, 0);
- const int src = ISOLEVEL_INDEX( i+0, j+0, 1);
- mpEdgeVerticesX[ dst ] = mpEdgeVerticesX[ src ];
- mpEdgeVerticesY[ dst ] = mpEdgeVerticesY[ src ];
- mpEdgeVerticesZ[ dst ] = mpEdgeVerticesZ[ src ];
- mpEdgeVerticesX[ src ]=-1;
- mpEdgeVerticesY[ src ]=-1;
- mpEdgeVerticesZ[ src ]=-1;
- }
- } // */
-
- } // k
-
- // precalculate normals using an approximation of the scalar field gradient
- for(int ni=0;ni<(int)mPoints.size();ni++) { normalize( mPoints[ni].n ); }
-
- } else { // subdivs
-
-#define EDGEAR_INDEX(Ai,Aj,Ak, Bi,Bj) ((mSizex*mSizey*mSubdivs*mSubdivs*(Ak))+\
- (mSizex*mSubdivs*((Aj)*mSubdivs+(Bj)))+((Ai)*mSubdivs)+(Bi))
-
-#define ISOTRILININT(fi,fj,fk) ( \
- (1.-(fi))*(1.-(fj))*(1.-(fk))*orgval[0] + \
- ( (fi))*(1.-(fj))*(1.-(fk))*orgval[1] + \
- ( (fi))*( (fj))*(1.-(fk))*orgval[2] + \
- (1.-(fi))*( (fj))*(1.-(fk))*orgval[3] + \
- (1.-(fi))*(1.-(fj))*( (fk))*orgval[4] + \
- ( (fi))*(1.-(fj))*( (fk))*orgval[5] + \
- ( (fi))*( (fj))*( (fk))*orgval[6] + \
- (1.-(fi))*( (fj))*( (fk))*orgval[7] )
-
- // use subdivisions
- gfxReal subdfac = 1./(gfxReal)(mSubdivs);
- gfxReal orgGsx = gsx;
- gfxReal orgGsy = gsy;
- gfxReal orgGsz = gsz;
- gsx *= subdfac;
- gsy *= subdfac;
- gsz *= subdfac;
- if(mUseFullEdgeArrays) {
- errMsg("IsoSurface::triangulate","Disabling mUseFullEdgeArrays!");
- }
-
- // subdiv local arrays
- gfxReal orgval[8];
- gfxReal subdAr[2][11][11]; // max 10 subdivs!
- ParticleObject* *arppnt = new ParticleObject*[mSizez*mSizey*mSizex];
-
- // construct pointers
- // part test
- int pInUse = 0;
- int pUsedTest = 0;
- // reset particles
- // reset list array
- for(int k=0;k<(mSizez);k++)
- for(int j=0;j<(mSizey);j++)
- for(int i=0;i<(mSizex);i++) {
- arppnt[ISOLEVEL_INDEX(i,j,k)] = NULL;
- }
- if(mpIsoParts) {
- for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
- pit!= mpIsoParts->getParticlesEnd(); pit++) {
- if( (*pit).getActive()==false ) continue;
- if( (*pit).getType()!=PART_DROP) continue;
- (*pit).setNext(NULL);
- }
- // build per node lists
- for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
- pit!= mpIsoParts->getParticlesEnd(); pit++) {
- if( (*pit).getActive()==false ) continue;
- if( (*pit).getType()!=PART_DROP) continue;
- // check lifetime ignored here
- ParticleObject *p = &(*pit);
- const ntlVec3Gfx ppos = p->getPos();
- const int pi= (int)round(ppos[0])+0;
- const int pj= (int)round(ppos[1])+0;
- int pk= (int)round(ppos[2])+0;// no offset necessary
- // 2d should be handled by solver. if(LBMDIM==2) { pk = 0; }
-
- if(pi<0) continue;
- if(pj<0) continue;
- if(pk<0) continue;
- if(pi>mSizex-1) continue;
- if(pj>mSizey-1) continue;
- if(pk>mSizez-1) continue;
- ParticleObject* &pnt = arppnt[ISOLEVEL_INDEX(pi,pj,pk)];
- if(pnt) {
- // append
- ParticleObject* listpnt = pnt;
- while(listpnt) {
- if(!listpnt->getNext()) {
- listpnt->setNext(p); listpnt = NULL;
- } else {
- listpnt = listpnt->getNext();
- }
- }
- } else {
- // start new list
- pnt = p;
- }
- pInUse++;
- }
- } // mpIsoParts
-
- debMsgStd("IsoSurface::triangulate",DM_MSG,"Starting. Parts in use:"<<pInUse<<", Subdivs:"<<mSubdivs, 9);
- pz = mStart[2]-(double)(0.*gsz)-0.5*orgGsz;
- for(int ok=1;ok<(mSizez-2)*mSubdivs;ok++) {
- pz += gsz;
- const int k = ok/mSubdivs;
- if(k<=0) continue; // skip zero plane
- for(int j=1;j<(mSizey-2);j++) {
- for(int i=1;i<(mSizex-2);i++) {
-
- orgval[0] = *getData(i ,j ,k );
- orgval[1] = *getData(i+1,j ,k );
- orgval[2] = *getData(i+1,j+1,k ); // with subdivs
- orgval[3] = *getData(i ,j+1,k );
- orgval[4] = *getData(i ,j ,k+1);
- orgval[5] = *getData(i+1,j ,k+1);
- orgval[6] = *getData(i+1,j+1,k+1); // with subdivs
- orgval[7] = *getData(i ,j+1,k+1);
-
- // prebuild subsampled array slice
- const int sdkOffset = ok-k*mSubdivs;
- for(int sdk=0; sdk<2; sdk++)
- for(int sdj=0; sdj<mSubdivs+1; sdj++)
- for(int sdi=0; sdi<mSubdivs+1; sdi++) {
- subdAr[sdk][sdj][sdi] = ISOTRILININT(sdi*subdfac, sdj*subdfac, (sdkOffset+sdk)*subdfac);
- }
-
- const int poDistOffset=2;
- for(int pok=-poDistOffset; pok<1+poDistOffset; pok++) {
- if(k+pok<0) continue;
- if(k+pok>=mSizez-1) continue;
- for(int poj=-poDistOffset; poj<1+poDistOffset; poj++) {
- if(j+poj<0) continue;
- if(j+poj>=mSizey-1) continue;
- for(int poi=-poDistOffset; poi<1+poDistOffset; poi++) {
- if(i+poi<0) continue;
- if(i+poi>=mSizex-1) continue;
- ParticleObject *p;
- p = arppnt[ISOLEVEL_INDEX(i+poi,j+poj,k+pok)];
- while(p) { // */
- /*
- for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
- pit!= mpIsoParts->getParticlesEnd(); pit++) { { { {
- // debug test! , full list slow!
- if(( (*pit).getActive()==false ) || ( (*pit).getType()!=PART_DROP)) continue;
- ParticleObject *p;
- p = &(*pit); // */
-
- pUsedTest++;
- ntlVec3Gfx ppos = p->getPos();
- const int spi= (int)round( (ppos[0]+1.-(gfxReal)i) *(gfxReal)mSubdivs-1.5);
- const int spj= (int)round( (ppos[1]+1.-(gfxReal)j) *(gfxReal)mSubdivs-1.5);
- const int spk= (int)round( (ppos[2]+1.-(gfxReal)k) *(gfxReal)mSubdivs-1.5)-sdkOffset; // why -2?
- // 2d should be handled by solver. if(LBMDIM==2) { spk = 0; }
-
- gfxReal pfLen = p->getSize()*1.5*mPartSize; // test, was 1.1
- const gfxReal minPfLen = subdfac*0.8;
- if(pfLen<minPfLen) pfLen = minPfLen;
- //errMsg("ISOPPP"," at "<<PRINT_IJK<<" pp"<<ppos<<" sp"<<PRINT_VEC(spi,spj,spk)<<" pflen"<<pfLen );
- //errMsg("ISOPPP"," subdfac="<<subdfac<<" size"<<p->getSize()<<" ps"<<mPartSize );
- const int icellpsize = (int)(1.*pfLen*(gfxReal)mSubdivs)+1;
- for(int swk=-icellpsize; swk<=icellpsize; swk++) {
- if(spk+swk< 0) { continue; }
- if(spk+swk> 1) { continue; } // */
- for(int swj=-icellpsize; swj<=icellpsize; swj++) {
- if(spj+swj< 0) { continue; }
- if(spj+swj>mSubdivs+0) { continue; } // */
- for(int swi=-icellpsize; swi<=icellpsize; swi++) {
- if(spi+swi< 0) { continue; }
- if(spi+swi>mSubdivs+0) { continue; } // */
- ntlVec3Gfx cellp = ntlVec3Gfx(
- (1.5+(gfxReal)(spi+swi)) *subdfac + (gfxReal)(i-1),
- (1.5+(gfxReal)(spj+swj)) *subdfac + (gfxReal)(j-1),
- (1.5+(gfxReal)(spk+swk)+sdkOffset) *subdfac + (gfxReal)(k-1)
- );
- //if(swi==0 && swj==0 && swk==0) subdAr[spk][spj][spi] = 1.; // DEBUG
- // clip domain boundaries again
- if(cellp[0]<1.) { continue; }
- if(cellp[1]<1.) { continue; }
- if(cellp[2]<1.) { continue; }
- if(cellp[0]>(gfxReal)mSizex-3.) { continue; }
- if(cellp[1]>(gfxReal)mSizey-3.) { continue; }
- if(cellp[2]>(gfxReal)mSizez-3.) { continue; }
- gfxReal len = norm(cellp-ppos);
- gfxReal isoadd = 0.;
- const gfxReal baseIsoVal = mIsoValue*1.1;
- if(len<pfLen) {
- isoadd = baseIsoVal*1.;
- } else {
- // falloff linear with pfLen (kernel size=2pfLen
- isoadd = baseIsoVal*(1. - (len-pfLen)/(pfLen));
- }
- if(isoadd<0.) { continue; }
- //errMsg("ISOPPP"," at "<<PRINT_IJK<<" sp"<<PRINT_VEC(spi+swi,spj+swj,spk+swk)<<" cellp"<<cellp<<" pp"<<ppos << " l"<< len<< " add"<< isoadd);
- const gfxReal arval = subdAr[spk+swk][spj+swj][spi+swi];
- if(arval>1.) { continue; }
- subdAr[spk+swk][spj+swj][spi+swi] = arval + isoadd;
- } } }
-
- p = p->getNext();
- }
- } } } // poDist loops */
-
- py = mStart[1]+(((double)j-0.5)*orgGsy)-gsy;
- for(int sj=0;sj<mSubdivs;sj++) {
- py += gsy;
- px = mStart[0]+(((double)i-0.5)*orgGsx)-gsx;
- for(int si=0;si<mSubdivs;si++) {
- px += gsx;
- value[0] = subdAr[0+0][sj+0][si+0];
- value[1] = subdAr[0+0][sj+0][si+1];
- value[2] = subdAr[0+0][sj+1][si+1];
- value[3] = subdAr[0+0][sj+1][si+0];
- value[4] = subdAr[0+1][sj+0][si+0];
- value[5] = subdAr[0+1][sj+0][si+1];
- value[6] = subdAr[0+1][sj+1][si+1];
- value[7] = subdAr[0+1][sj+1][si+0];
-
- // check intersections of isosurface with edges, and calculate cubie index
- cubeIndex = 0;
- if (value[0] < mIsoValue) cubeIndex |= 1;
- if (value[1] < mIsoValue) cubeIndex |= 2; // with subdivs
- if (value[2] < mIsoValue) cubeIndex |= 4;
- if (value[3] < mIsoValue) cubeIndex |= 8;
- if (value[4] < mIsoValue) cubeIndex |= 16;
- if (value[5] < mIsoValue) cubeIndex |= 32; // with subdivs
- if (value[6] < mIsoValue) cubeIndex |= 64;
- if (value[7] < mIsoValue) cubeIndex |= 128;
-
- if (mcEdgeTable[cubeIndex] > 0) {
-
- // where to look up if this point already exists
- const int edgek = 0;
- const int baseIn = EDGEAR_INDEX( i+0, j+0, edgek+0, si,sj);
- eVert[ 0] = &mpEdgeVerticesX[ baseIn ];
- eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ];
- eVert[ 2] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ];
- eVert[ 3] = &mpEdgeVerticesY[ baseIn ];
-
- eVert[ 4] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ];
- eVert[ 5] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+1,sj+0) ]; // with subdivs
- eVert[ 6] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+1) ];
- eVert[ 7] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ];
-
- eVert[ 8] = &mpEdgeVerticesZ[ baseIn ];
- eVert[ 9] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+0) ]; // with subdivs
- eVert[10] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+1) ];
- eVert[11] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ];
-
- // grid positions
- pos[0] = ntlVec3Gfx(px ,py ,pz);
- pos[1] = ntlVec3Gfx(px+gsx,py ,pz);
- pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz); // with subdivs
- pos[3] = ntlVec3Gfx(px ,py+gsy,pz);
- pos[4] = ntlVec3Gfx(px ,py ,pz+gsz);
- pos[5] = ntlVec3Gfx(px+gsx,py ,pz+gsz);
- pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz); // with subdivs
- pos[7] = ntlVec3Gfx(px ,py+gsy,pz+gsz);
-
- // check all edges
- for(int e=0;e<12;e++) {
- if (mcEdgeTable[cubeIndex] & (1<<e)) {
- // is the vertex already calculated?
- if(*eVert[ e ] < 0) {
- // interpolate edge
- const int e1 = mcEdges[e*2 ];
- const int e2 = mcEdges[e*2+1];
- const ntlVec3Gfx p1 = pos[ e1 ]; // scalar field pos 1
- const ntlVec3Gfx p2 = pos[ e2 ]; // scalar field pos 2
- const float valp1 = value[ e1 ]; // scalar field val 1
- const float valp2 = value[ e2 ]; // scalar field val 2
- const float mu = (mIsoValue - valp1) / (valp2 - valp1);
-
- // init isolevel vertex
- ilv.v = p1 + (p2-p1)*mu; // with subdivs
- mPoints.push_back( ilv );
- triIndices[e] = (mPoints.size()-1);
- // store vertex
- *eVert[ e ] = triIndices[e];
- } else {
- // retrieve from vert array
- triIndices[e] = *eVert[ e ];
- }
- } // along all edges
- }
- // removed cutoff treatment...
-
- // Create the triangles...
- for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) {
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] );
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] ); // with subdivs
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] );
- //errMsg("TTT"," i1"<<mIndices[mIndices.size()-3]<<" "<< " i2"<<mIndices[mIndices.size()-2]<<" "<< " i3"<<mIndices[mIndices.size()-1]<<" "<< mIndices.size() );
- }
-
- } // triangles in edge table?
-
- }//si
- }// sj
-
- }//i
- }// j
-
- // copy edge arrays
- for(int j=0;j<(mSizey-0)*mSubdivs;j++)
- for(int i=0;i<(mSizex-0)*mSubdivs;i++) {
- //int edgek = 0;
- const int dst = EDGEAR_INDEX( 0, 0, 0, i,j);
- const int src = EDGEAR_INDEX( 0, 0, 1, i,j);
- mpEdgeVerticesX[ dst ] = mpEdgeVerticesX[ src ];
- mpEdgeVerticesY[ dst ] = mpEdgeVerticesY[ src ]; // with subdivs
- mpEdgeVerticesZ[ dst ] = mpEdgeVerticesZ[ src ];
- mpEdgeVerticesX[ src ]=-1;
- mpEdgeVerticesY[ src ]=-1; // with subdivs
- mpEdgeVerticesZ[ src ]=-1;
- }
- // */
-
- } // ok, k subdiv loop
-
- //delete [] subdAr;
- delete [] arppnt;
- computeNormals();
- } // with subdivs
-
- // perform smoothing
- float smoSubdfac = 1.;
- if(mSubdivs>0) {
- //smoSubdfac = 1./(float)(mSubdivs);
- smoSubdfac = pow(0.55,(double)mSubdivs); // slightly stronger
- }
- if(mSmoothSurface>0. || mSmoothNormals>0.) debMsgStd("IsoSurface::triangulate",DM_MSG,"Smoothing...",10);
- if(mSmoothSurface>0.0) {
- smoothSurface(mSmoothSurface*smoSubdfac, (mSmoothNormals<=0.0) );
- }
- if(mSmoothNormals>0.0) {
- smoothNormals(mSmoothNormals*smoSubdfac);
- }
-
- myTime_t tritimeend = getTime();
- debMsgStd("IsoSurface::triangulate",DM_MSG,"took "<< getTimeString(tritimeend-tritimestart)<<", S("<<mSmoothSurface<<","<<mSmoothNormals<<"),"<<
- " verts:"<<mPoints.size()<<" tris:"<<(mIndices.size()/3)<<" subdivs:"<<mSubdivs
- , 10 );
- if(mpIsoParts) debMsgStd("IsoSurface::triangulate",DM_MSG,"parts:"<<mpIsoParts->getNumParticles(), 10);
-}
-
-
-
-
-
-/******************************************************************************
- * Get triangles for rendering
- *****************************************************************************/
-void IsoSurface::getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId )
-{
- if(!mInitDone) {
- debugOut("IsoSurface::getTriangles warning: Not initialized! ", 10);
- return;
- }
- t = 0.;
- //return; // DEBUG
-
- /* triangulate field */
- triangulate();
- //errMsg("TRIS"," "<<mIndices.size() );
-
- // new output with vertice reuse
- int iniVertIndex = (*vertices).size();
- int iniNormIndex = (*normals).size();
- if(iniVertIndex != iniNormIndex) {
- errFatal("getTriangles Error","For '"<<mName<<"': Vertices and normal array sizes to not match!!!",SIMWORLD_GENERICERROR);
- return;
- }
- //errMsg("NM"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
- //errMsg("NM"," ovs"<<mVertices.size()<<" ons"<<mVertNormals.size()<<" ots"<<mIndices.size() );
-
- for(int i=0;i<(int)mPoints.size();i++) {
- vertices->push_back( mPoints[i].v );
- }
- for(int i=0;i<(int)mPoints.size();i++) {
- normals->push_back( mPoints[i].n );
- }
-
- //errMsg("N2"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
- //errMsg("N2"," ovs"<<mVertices.size()<<" ons"<<mVertNormals.size()<<" ots"<<mIndices.size() );
-
- for(int i=0;i<(int)mIndices.size();i+=3) {
- const int smooth = 1;
- int t1 = mIndices[i];
- int t2 = mIndices[i+1];
- int t3 = mIndices[i+2];
- //errMsg("NM"," tri"<<t1<<" "<<t2<<" "<<t3 );
-
- ntlTriangle tri;
-
- tri.getPoints()[0] = t1+iniVertIndex;
- tri.getPoints()[1] = t2+iniVertIndex;
- tri.getPoints()[2] = t3+iniVertIndex;
-
- /* init flags */
- int flag = 0;
- if(getVisible()){ flag |= TRI_GEOMETRY; }
- if(getCastShadows() ) {
- flag |= TRI_CASTSHADOWS; }
-
- /* init geo init id */
- int geoiId = getGeoInitId();
- if(geoiId > 0) {
- flag |= (1<< (geoiId+4));
- flag |= mGeoInitType;
- }
-
- tri.setFlags( flag );
-
- /* triangle normal missing */
- tri.setNormal( ntlVec3Gfx(0.0) );
- tri.setSmoothNormals( smooth );
- tri.setObjectId( objectId );
- triangles->push_back( tri );
- }
- //errMsg("N3"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
- return;
-}
-
-
-
-inline ntlVec3Gfx IsoSurface::getNormal(int i, int j,int k) {
- // WARNING - this requires a security boundary layer...
- ntlVec3Gfx ret(0.0);
- ret[0] = *getData(i-1,j ,k ) -
- *getData(i+1,j ,k );
- ret[1] = *getData(i ,j-1,k ) -
- *getData(i ,j+1,k );
- ret[2] = *getData(i ,j ,k-1 ) -
- *getData(i ,j ,k+1 );
- return ret;
-}
-
-
-
-
-/******************************************************************************
- *
- * Surface improvement, inspired by trimesh2 library
- * (http://www.cs.princeton.edu/gfx/proj/trimesh2/)
- *
- *****************************************************************************/
-
-void IsoSurface::setSmoothRad(float radi1, float radi2, ntlVec3Gfx mscc) {
- mSCrad1 = radi1*radi1;
- mSCrad2 = radi2*radi2;
- mSCcenter = mscc;
-}
-
-// compute normals for all generated triangles
-void IsoSurface::computeNormals() {
- for(int i=0;i<(int)mPoints.size();i++) {
- mPoints[i].n = ntlVec3Gfx(0.);
- }
-
- for(int i=0;i<(int)mIndices.size();i+=3) {
- const int t1 = mIndices[i];
- const int t2 = mIndices[i+1];
- const int t3 = mIndices[i+2];
- const ntlVec3Gfx p1 = mPoints[t1].v;
- const ntlVec3Gfx p2 = mPoints[t2].v;
- const ntlVec3Gfx p3 = mPoints[t3].v;
- const ntlVec3Gfx n1=p1-p2;
- const ntlVec3Gfx n2=p2-p3;
- const ntlVec3Gfx n3=p3-p1;
- const gfxReal len1 = normNoSqrt(n1);
- const gfxReal len2 = normNoSqrt(n2);
- const gfxReal len3 = normNoSqrt(n3);
- const ntlVec3Gfx norm = cross(n1,n2);
- mPoints[t1].n += norm * (1./(len1*len3));
- mPoints[t2].n += norm * (1./(len1*len2));
- mPoints[t3].n += norm * (1./(len2*len3));
- }
-
- for(int i=0;i<(int)mPoints.size();i++) {
- normalize(mPoints[i].n);
- }
-}
-
-// Diffuse a vector field at 1 vertex, weighted by
-// a gaussian of width 1/sqrt(invsigma2)
-bool IsoSurface::diffuseVertexField(ntlVec3Gfx *field, const int pointerScale, int src, float invsigma2, ntlVec3Gfx &target)
-{
- if((neighbors[src].size()<1) || (pointareas[src]<=0.0)) return 0;
- const ntlVec3Gfx srcp = mPoints[src].v;
- const ntlVec3Gfx srcn = mPoints[src].n;
- if(mSCrad1>0.0 && mSCrad2>0.0) {
- ntlVec3Gfx dp = mSCcenter-srcp; dp[2] = 0.0; // only xy-plane
- float rd = normNoSqrt(dp);
- if(rd > mSCrad2) {
- return 0;
- } else if(rd > mSCrad1) {
- // optimize?
- float org = 1.0/sqrt(invsigma2);
- org *= (1.0- (rd-mSCrad1) / (mSCrad2-mSCrad1));
- invsigma2 = 1.0/(org*org);
- //errMsg("TRi","p"<<srcp<<" rd:"<<rd<<" r1:"<<mSCrad1<<" r2:"<<mSCrad2<<" org:"<<org<<" is:"<<invsigma2);
- } else {
- }
- }
- target = ntlVec3Gfx(0.0);
- target += *(field+pointerScale*src) *pointareas[src];
- float smstrSum = pointareas[src];
-
- int flag = mFlagCnt;
- mFlagCnt++;
- flags[src] = flag;
- mDboundary = neighbors[src];
- while (!mDboundary.empty()) {
- const int bbn = mDboundary.back();
- mDboundary.pop_back();
- if(flags[bbn]==flag) continue;
- flags[bbn] = flag;
-
- // normal check
- const float nvdot = dot(srcn, mPoints[bbn].n); // faster than before d2 calc?
- if(nvdot <= 0.0f) continue;
-
- // gaussian weight of width 1/sqrt(invsigma2)
- const float d2 = invsigma2 * normNoSqrt(mPoints[bbn].v - srcp);
- if(d2 >= 9.0f) continue;
-
- // aggressive smoothing factor
- float smstr = nvdot * pointareas[bbn];
- // Accumulate weight times field at neighbor
- target += *(field+pointerScale*bbn)*smstr;
- smstrSum += smstr;
-
- for(int i = 0; i < (int)neighbors[bbn].size(); i++) {
- const int nn = neighbors[bbn][i];
- if (flags[nn] == flag) continue;
- mDboundary.push_back(nn);
- }
- }
- target /= smstrSum;
- return 1;
-}
-
-
-// perform smoothing of the surface (and possible normals)
-void IsoSurface::smoothSurface(float sigma, bool normSmooth)
-{
- int nv = mPoints.size();
- if ((int)flags.size() != nv) flags.resize(nv);
- int nf = mIndices.size()/3;
-
- { // need neighbors
- vector<int> numneighbors(mPoints.size());
- int i;
- for (i = 0; i < (int)mIndices.size()/3; i++) {
- numneighbors[mIndices[i*3+0]]++;
- numneighbors[mIndices[i*3+1]]++;
- numneighbors[mIndices[i*3+2]]++;
- }
-
- neighbors.clear();
- neighbors.resize(mPoints.size());
- for (i = 0; i < (int)mPoints.size(); i++) {
- neighbors[i].clear();
- neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries
- }
-
- for (i = 0; i < (int)mIndices.size()/3; i++) {
- for (int j = 0; j < 3; j++) {
- vector<int> &me = neighbors[ mIndices[i*3+j]];
- int n1 = mIndices[i*3+((j+1)%3)];
- int n2 = mIndices[i*3+((j+2)%3)];
- if (std::find(me.begin(), me.end(), n1) == me.end())
- me.push_back(n1);
- if (std::find(me.begin(), me.end(), n2) == me.end())
- me.push_back(n2);
- }
- }
- } // need neighbor
-
- { // need pointarea
- pointareas.clear();
- pointareas.resize(nv);
- cornerareas.clear();
- cornerareas.resize(nf);
-
- for (int i = 0; i < nf; i++) {
- // Edges
- ntlVec3Gfx e[3] = {
- mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v,
- mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v,
- mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v };
-
- // Compute corner weights
- float area = 0.5f * norm( cross(e[0], e[1]));
- float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) };
- float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
- l2[1] * (l2[2] + l2[0] - l2[1]),
- l2[2] * (l2[0] + l2[1] - l2[2]) };
- if (ew[0] <= 0.0f) {
- cornerareas[i][1] = -0.25f * l2[2] * area /
- dot(e[0] , e[2]);
- cornerareas[i][2] = -0.25f * l2[1] * area /
- dot(e[0] , e[1]);
- cornerareas[i][0] = area - cornerareas[i][1] -
- cornerareas[i][2];
- } else if (ew[1] <= 0.0f) {
- cornerareas[i][2] = -0.25f * l2[0] * area /
- dot(e[1] , e[0]);
- cornerareas[i][0] = -0.25f * l2[2] * area /
- dot(e[1] , e[2]);
- cornerareas[i][1] = area - cornerareas[i][2] -
- cornerareas[i][0];
- } else if (ew[2] <= 0.0f) {
- cornerareas[i][0] = -0.25f * l2[1] * area /
- dot(e[2] , e[1]);
- cornerareas[i][1] = -0.25f * l2[0] * area /
- dot(e[2] , e[0]);
- cornerareas[i][2] = area - cornerareas[i][0] -
- cornerareas[i][1];
- } else {
- float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
- for (int j = 0; j < 3; j++)
- cornerareas[i][j] = ewscale * (ew[(j+1)%3] +
- ew[(j+2)%3]);
- }
-
- // FIX T50887: ensure pointareas are finite
- if (!isfinite(cornerareas[i][0])) cornerareas[i][0] = 1e-6;
- if (!isfinite(cornerareas[i][1])) cornerareas[i][1] = 1e-6;
- if (!isfinite(cornerareas[i][2])) cornerareas[i][2] = 1e-6;
-
- pointareas[mIndices[i*3+0]] += cornerareas[i][0];
- pointareas[mIndices[i*3+1]] += cornerareas[i][1];
- pointareas[mIndices[i*3+2]] += cornerareas[i][2];
- }
-
- } // need pointarea
- // */
-
- float invsigma2 = 1.0f / (sigma*sigma);
-
- vector<ntlVec3Gfx> dflt(nv);
- for (int i = 0; i < nv; i++) {
- if(diffuseVertexField( &mPoints[0].v, 2,
- i, invsigma2, dflt[i])) {
- // Just keep the displacement
- dflt[i] -= mPoints[i].v;
- } else { dflt[i] = 0.0; } //?mPoints[i].v; }
- }
-
- // Slightly better small-neighborhood approximation
- for (int i = 0; i < nf; i++) {
- ntlVec3Gfx c = mPoints[mIndices[i*3+0]].v +
- mPoints[mIndices[i*3+1]].v +
- mPoints[mIndices[i*3+2]].v;
- c /= 3.0f;
- for (int j = 0; j < 3; j++) {
- int v = mIndices[i*3+j];
- ntlVec3Gfx d =(c - mPoints[v].v) * 0.5f;
- dflt[v] += d * (cornerareas[i][j] /
- pointareas[mIndices[i*3+j]] *
- exp(-0.5f * invsigma2 * normNoSqrt(d)) );
- }
- }
-
- // Filter displacement field
- vector<ntlVec3Gfx> dflt2(nv);
- for (int i = 0; i < nv; i++) {
- if(diffuseVertexField( &dflt[0], 1,
- i, invsigma2, dflt2[i])) { }
- else { /*mPoints[i].v=0.0;*/ dflt2[i] = 0.0; }//dflt2[i]; }
- }
-
- // Update vertex positions
- for (int i = 0; i < nv; i++) {
- mPoints[i].v += dflt[i] - dflt2[i]; // second Laplacian
- }
-
- // when normals smoothing off, this cleans up quite well
- // costs ca. 50% additional time though
- float nsFac = 1.5f;
- if(normSmooth) { float ninvsigma2 = 1.0f / (nsFac*nsFac*sigma*sigma);
- for (int i = 0; i < nv; i++) {
- if( diffuseVertexField( &mPoints[0].n, 2, i, ninvsigma2, dflt[i]) ) {
- normalize(dflt[i]);
- } else {
- dflt[i] = mPoints[i].n;
- }
- }
- for (int i = 0; i < nv; i++) {
- mPoints[i].n = dflt[i];
- }
- } // smoothNormals copy */
-
- //errMsg("SMSURF","done v:"<<sigma); // DEBUG
-}
-
-// only smoothen the normals
-void IsoSurface::smoothNormals(float sigma) {
- // reuse from smoothSurface
- if(neighbors.size() != mPoints.size()) {
- // need neighbor
- vector<int> numneighbors(mPoints.size());
- int i;
- for (i = 0; i < (int)mIndices.size()/3; i++) {
- numneighbors[mIndices[i*3+0]]++;
- numneighbors[mIndices[i*3+1]]++;
- numneighbors[mIndices[i*3+2]]++;
- }
-
- neighbors.clear();
- neighbors.resize(mPoints.size());
- for (i = 0; i < (int)mPoints.size(); i++) {
- neighbors[i].clear();
- neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries
- }
-
- for (i = 0; i < (int)mIndices.size()/3; i++) {
- for (int j = 0; j < 3; j++) {
- vector<int> &me = neighbors[ mIndices[i*3+j]];
- int n1 = mIndices[i*3+((j+1)%3)];
- int n2 = mIndices[i*3+((j+2)%3)];
- if (std::find(me.begin(), me.end(), n1) == me.end())
- me.push_back(n1);
- if (std::find(me.begin(), me.end(), n2) == me.end())
- me.push_back(n2);
- }
- }
- } // need neighbor
-
- { // need pointarea
- int nf = mIndices.size()/3, nv = mPoints.size();
- pointareas.clear();
- pointareas.resize(nv);
- cornerareas.clear();
- cornerareas.resize(nf);
-
- for (int i = 0; i < nf; i++) {
- // Edges
- ntlVec3Gfx e[3] = {
- mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v,
- mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v,
- mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v };
-
- // Compute corner weights
- float area = 0.5f * norm( cross(e[0], e[1]));
- float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) };
- float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
- l2[1] * (l2[2] + l2[0] - l2[1]),
- l2[2] * (l2[0] + l2[1] - l2[2]) };
- if (ew[0] <= 0.0f) {
- cornerareas[i][1] = -0.25f * l2[2] * area /
- dot(e[0] , e[2]);
- cornerareas[i][2] = -0.25f * l2[1] * area /
- dot(e[0] , e[1]);
- cornerareas[i][0] = area - cornerareas[i][1] -
- cornerareas[i][2];
- } else if (ew[1] <= 0.0f) {
- cornerareas[i][2] = -0.25f * l2[0] * area /
- dot(e[1] , e[0]);
- cornerareas[i][0] = -0.25f * l2[2] * area /
- dot(e[1] , e[2]);
- cornerareas[i][1] = area - cornerareas[i][2] -
- cornerareas[i][0];
- } else if (ew[2] <= 0.0f) {
- cornerareas[i][0] = -0.25f * l2[1] * area /
- dot(e[2] , e[1]);
- cornerareas[i][1] = -0.25f * l2[0] * area /
- dot(e[2] , e[0]);
- cornerareas[i][2] = area - cornerareas[i][0] -
- cornerareas[i][1];
- } else {
- float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
- for (int j = 0; j < 3; j++)
- cornerareas[i][j] = ewscale * (ew[(j+1)%3] +
- ew[(j+2)%3]);
- }
-
- // FIX T50887: ensure pointareas are finite
- if (!isfinite(cornerareas[i][0])) cornerareas[i][0] = 1e-6;
- if (!isfinite(cornerareas[i][1])) cornerareas[i][1] = 1e-6;
- if (!isfinite(cornerareas[i][2])) cornerareas[i][2] = 1e-6;
-
- pointareas[mIndices[i*3+0]] += cornerareas[i][0];
- pointareas[mIndices[i*3+1]] += cornerareas[i][1];
- pointareas[mIndices[i*3+2]] += cornerareas[i][2];
- }
-
- } // need pointarea
-
- int nv = mPoints.size();
- if ((int)flags.size() != nv) flags.resize(nv);
- float invsigma2 = 1.0f / (sigma*sigma);
-
- vector<ntlVec3Gfx> nflt(nv);
- for (int i = 0; i < nv; i++) {
- if(diffuseVertexField( &mPoints[0].n, 2, i, invsigma2, nflt[i])) {
- normalize(nflt[i]);
- } else { nflt[i]=mPoints[i].n; }
- }
-
- // copy results
- for (int i = 0; i < nv; i++) { mPoints[i].n = nflt[i]; }
-}
-
-
diff --git a/intern/elbeem/intern/isosurface.h b/intern/elbeem/intern/isosurface.h
deleted file mode 100644
index 93ea5ecb108..00000000000
--- a/intern/elbeem/intern/isosurface.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Marching Cubes "displayer"
- *
- *****************************************************************************/
-
-#ifndef ISOSURFACE_H
-
-#include "ntl_geometryobject.h"
-#include "ntl_bsptree.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-#define ISO_STRICT_DEBUG 0
-#define ISOSTRICT_EXIT *((int *)0)=0;
-
-/* access some 3d array */
-#define ISOLEVEL_INDEX(ii,ij,ik) ((mSizex*mSizey*(ik))+(mSizex*(ij))+((ii)))
-
-class ParticleTracer;
-
-/* struct for a small cube in the scalar field */
-typedef struct {
- ntlVec3Gfx pos[8];
- double value[8];
- int i,j,k;
-} IsoLevelCube;
-
-
-typedef struct {
- ntlVec3Gfx v; // vertex
- ntlVec3Gfx n; // vertex normal
-} IsoLevelVertex;
-
-//! class to triangulate a scalar field, e.g. for
-// the fluid surface, templated by scalar field access object
-class IsoSurface :
- public ntlGeometryObject //, public S
-{
-
- public:
-
- /*! Constructor */
- IsoSurface(double iso);
- /*! Destructor */
- virtual ~IsoSurface();
-
- /*! Init ararys etc. */
- virtual void initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent);
-
- /*! Reset all values */
- void resetAll(gfxReal val);
-
- /*! triangulate the scalar field given by pointer*/
- void triangulate( void );
-
- /*! set particle pointer */
- void setParticles(ParticleTracer *pnt,float psize){ mpIsoParts = pnt; mPartSize=psize; };
- /*! set # of subdivisions, this has to be done before init! */
- void setSubdivs(int s) {
- if(mInitDone) errFatal("IsoSurface::setSubdivs","Changing subdivs after init!", SIMWORLD_INITERROR);
- if(s<1) s=1;
- if(s>10) s=10;
- mSubdivs = s;
- }
- int getSubdivs() { return mSubdivs;}
- /*! set full edge settings, this has to be done before init! */
- void setUseFulledgeArrays(bool set) {
- if(mInitDone) errFatal("IsoSurface::setUseFulledgeArrays","Changing usefulledge after init!", SIMWORLD_INITERROR);
- mUseFullEdgeArrays = set;}
-
- protected:
-
- /* variables ... */
-
- //! size
- int mSizex, mSizey, mSizez;
-
- //! data pointer
- float *mpData;
-
- //! Level of the iso surface
- double mIsoValue;
-
- //! Store all the triangles vertices
- vector<IsoLevelVertex> mPoints;
-
- //! use full arrays? (not for farfield)
- bool mUseFullEdgeArrays;
- //! Store indices of calculated points along the cubie edges
- int *mpEdgeVerticesX;
- int *mpEdgeVerticesY;
- int *mpEdgeVerticesZ;
- int mEdgeArSize;
-
-
- //! vector for all the triangles (stored as 3 indices)
- vector<unsigned int> mIndices;
-
- //! start and end vectors for the triangulation region to create triangles in
- ntlVec3Gfx mStart, mEnd;
-
- //! normalized domain extent from parametrizer/visualizer
- ntlVec3Gfx mDomainExtent;
-
- //! initialized?
- bool mInitDone;
-
- //! amount of surface smoothing
- float mSmoothSurface;
- //! amount of normal smoothing
- float mSmoothNormals;
-
- //! grid data
- vector<int> mAcrossEdge;
- vector< vector<int> > mAdjacentFaces;
-
- //! cutoff border area
- int mCutoff;
- //! cutoff height values
- int *mCutArray;
- //! particle pointer
- ParticleTracer *mpIsoParts;
- //! particle size
- float mPartSize;
- //! no of subdivisions
- int mSubdivs;
-
- //! trimesh vars
- vector<int> flags;
- int mFlagCnt;
- vector<ntlVec3Gfx> cornerareas;
- vector<float> pointareas;
- vector< vector<int> > neighbors;
-
- public:
- // miscelleanous access functions
-
- //! set geometry start (for renderer)
- void setStart(ntlVec3Gfx set) { mStart = set; };
- ntlVec3Gfx getStart() { return mStart; };
- //! set geometry end (for renderer)
- void setEnd(ntlVec3Gfx set) { mEnd = set; };
- ntlVec3Gfx getEnd() { return mEnd; };
- //! set iso level value for surface reconstruction
- inline void setIsolevel(double set) { mIsoValue = set; };
- //! set loop subdiv num
- inline void setSmoothSurface(float set) { mSmoothSurface = set; };
- inline void setSmoothNormals(float set) { mSmoothNormals = set; };
- inline float getSmoothSurface() { return mSmoothSurface; }
- inline float getSmoothNormals() { return mSmoothNormals; }
-
- // geometry object functions
- virtual void getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId );
-
- //! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB
- virtual inline ntlVec3Gfx *getBBStart() { return &mStart; }
- virtual inline ntlVec3Gfx *getBBEnd() { return &mEnd; }
-
- //! access data array
- inline float* getData(){ return mpData; }
- inline float* getData(int ii, int jj, int kk){
-#if ISO_STRICT_DEBUG==1
- if(ii<0){ errMsg("IsoStrict"," invX- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(jj<0){ errMsg("IsoStrict"," invY- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(kk<0){ errMsg("IsoStrict"," invZ- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(ii>mSizex-1){ errMsg("IsoStrict"," invX+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(jj>mSizey-1){ errMsg("IsoStrict"," invY+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(kk>mSizez-1){ errMsg("IsoStrict"," invZ+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- return mpData + ISOLEVEL_INDEX(ii, jj, kk);
-#else //ISO_STRICT_DEBUG==1
- return mpData + ISOLEVEL_INDEX(ii, jj, kk);
-#endif
- }
- inline float* lbmGetData(int ii, int jj, int kk){
-#if ISO_STRICT_DEBUG==1
- ii++; jj++; kk++;
- if(ii<0){ errMsg("IsoStrict"," invX- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(jj<0){ errMsg("IsoStrict"," invY- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(kk<0){ errMsg("IsoStrict"," invZ- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(ii>mSizex-1){ errMsg("IsoStrict"," invX+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(jj>mSizey-1){ errMsg("IsoStrict"," invY+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(kk>mSizez-1){ errMsg("IsoStrict"," invZ+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- return mpData + ISOLEVEL_INDEX(ii, jj, kk);
-#else //ISO_STRICT_DEBUG==1
- return mpData + ISOLEVEL_INDEX(ii+1,jj+1,kk+1);
-#endif
- }
- //! set cut off border
- inline void setCutoff(int set) { mCutoff = set; };
- //! set cut off border
- inline void setCutArray(int *set) { mCutArray = set; };
-
- //! OpenGL viz "interface"
- unsigned int getIsoVertexCount() {
- return mPoints.size();
- }
- unsigned int getIsoIndexCount() {
- return mIndices.size();
- }
- char* getIsoVertexArray() {
- return (char *) &(mPoints[0]);
- }
- unsigned int *getIsoIndexArray() {
- return &(mIndices[0]);
- }
-
- // surface smoothing functions
- void setSmoothRad(float radi1, float radi2, ntlVec3Gfx mscc);
- void smoothSurface(float val, bool smoothNorm);
- void smoothNormals(float val);
- void computeNormals();
-
- protected:
-
- //! compute normal
- inline ntlVec3Gfx getNormal(int i, int j,int k);
- //! smoothing helper function
- bool diffuseVertexField(ntlVec3Gfx *field, int pointerScale, int v, float invsigma2, ntlVec3Gfx &flt);
- vector<int> mDboundary;
- float mSCrad1, mSCrad2;
- ntlVec3Gfx mSCcenter;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:IsoSurface")
-#endif
-};
-
-
-#define ISOSURFACE_H
-#endif
-
-
diff --git a/intern/elbeem/intern/loop_tools.h b/intern/elbeem/intern/loop_tools.h
deleted file mode 100644
index d1ef03d6667..00000000000
--- a/intern/elbeem/intern/loop_tools.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-
-// advance pointer in main loop
-#define ADVANCE_POINTERS(p) \
- ccel += (QCELLSTEP*(p)); \
- tcel += (QCELLSTEP*(p)); \
- pFlagSrc+= (p); \
- pFlagDst+= (p); \
- i+= (p);
-
-#define MAX_CALC_ARR 4
-
-// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-// init region vars
-#define GRID_REGION_INIT() \
- const int istart = -1+gridLoopBound; \
- const int iend = mLevel[mMaxRefine].lSizex-1-gridLoopBound; \
- LbmFloat calcCurrentMass=0; \
- LbmFloat calcCurrentVolume=0; \
- int calcCellsFilled=0; \
- int calcCellsEmptied=0; \
- int calcNumUsedCells=0; \
- /* This is a generic macro, and now all it's users are using all variables. */ \
- (void)calcCurrentMass; \
- (void)calcCellsFilled \
-
-
-
-
-// -----------------------------------------------------------------------------------
-// serial stuff
-#if PARALLEL!=1
-
-#define PERFORM_USQRMAXCHECK USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz);
-#define LIST_EMPTY(x) mListEmpty.push_back( x );
-#define LIST_FULL(x) mListFull.push_back( x );
-#define FSGR_ADDPART(x) mpParticles->addFullParticle( x );
-
-// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-#define GRID_REGION_START() \
- { /* main_region */ \
- int kstart=getForZMinBnd(), kend=getForZMaxBnd(mMaxRefine); \
- if(gridLoopBound>0){ kstart=getForZMin1(), kend=getForZMax1(mMaxRefine); } \
- int kdir = 1; \
- int jstart = gridLoopBound; \
- int jend = mLevel[mMaxRefine].lSizey-gridLoopBound; \
- const int id=0; \
- LbmFloat *ccel = NULL, *tcel = NULL; \
- CellFlagType *pFlagSrc=NULL, *pFlagDst=NULL; \
- if(mLevel[mMaxRefine].setCurr==1) { \
- kdir = -1; \
- int temp = kend; \
- kend = kstart-1; \
- kstart = temp-1; \
- temp = id; /* dummy remove warning */ \
- } \
-
-
-
-
-
-// -----------------------------------------------------------------------------------
-#else // PARALLEL==1
-
-//#include "paraloop.h"
-#define PERFORM_USQRMAXCHECK USQRMAXCHECK(usqr,ux,uy,uz, calcMaxVlen, calcMxvx,calcMxvy,calcMxvz);
-#define LIST_EMPTY(x) calcListEmpty.push_back( x );
-#define LIST_FULL(x) calcListFull.push_back( x );
-#define FSGR_ADDPART(x) calcListParts.push_back( x );
-
-
-// parallel region
-//was: # pragma omp parallel default(shared)
-#if COMPRESSGRIDS!=1
- // requires compressed grids...!
- ERROR!
-#endif
-
-// loop start
-#define GRID_REGION_START() \
- { \
- \
- \
- if(mSizez<2) { \
- mPanic = 1; \
- errFatal("ParaLoop::2D","Not valid...!", SIMWORLD_GENERICERROR); \
- } \
- \
- \
- vector<LbmPoint> calcListFull; \
- vector<LbmPoint> calcListEmpty; \
- vector<ParticleObject> calcListParts; \
- LbmFloat calcMxvx, calcMxvy, calcMxvz, calcMaxVlen; \
- calcMxvx = calcMxvy = calcMxvz = calcMaxVlen = 0.0; \
- calcListEmpty.reserve(mListEmpty.capacity() / omp_get_num_threads() ); \
- calcListFull.reserve( mListFull.capacity() / omp_get_num_threads() ); \
- calcListParts.reserve(mSizex); \
- \
- \
- const int id = omp_get_thread_num(); \
- const int Nthrds = omp_get_num_threads(); \
- \
- \
- \
- \
- \
- int kdir = 1; \
- \
- int kstart=getForZMinBnd(), kend=getForZMaxBnd(mMaxRefine); \
- if(gridLoopBound>0){ kstart=getForZMin1(); kend=getForZMax1(mMaxRefine); } \
- LbmFloat *ccel = NULL, *tcel = NULL; \
- CellFlagType *pFlagSrc=NULL, *pFlagDst=NULL; \
- \
- \
- if(mLevel[mMaxRefine].setCurr==1) { \
- kdir = -1; \
- int temp = kend; \
- kend = kstart-1; \
- kstart = temp-1; \
- } \
- \
- const int Nj = mLevel[mMaxRefine].lSizey; \
- int jstart = 0+( (id * Nj ) / Nthrds ); \
- int jend = 0+(((id+1) * Nj ) / Nthrds ); \
- if( ((Nj/Nthrds) *Nthrds) != Nj) { \
- errMsg("LbmFsgrSolver","Invalid domain size Nj="<<Nj<<" Nthrds="<<Nthrds); \
- } \
- \
- if(jstart<gridLoopBound) jstart = gridLoopBound; \
- if(jend>mLevel[mMaxRefine].lSizey-gridLoopBound) jend = mLevel[mMaxRefine].lSizey-gridLoopBound; \
- \
- debMsgStd("ParaLoop::OMP",DM_MSG,"Thread:"<<id<<" i:"<<istart<<"-"<<iend<<" j:"<<jstart<<"-"<<jend<<", k:"<<kstart<<"-"<<kend<<" ", 1); \
- \
-
-
-
-
-// para GRID LOOP END is parainc3
-
-#endif // PARALLEL==1
-
-
-// -----------------------------------------------------------------------------------
-
-// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-#define GRID_LOOP_START() \
- for(int k=kstart;k!=kend;k+=kdir) { \
- pFlagSrc = &RFLAG(lev, istart, jstart, k, SRCS(lev)); \
- pFlagDst = &RFLAG(lev, istart, jstart, k, TSET(lev)); \
- ccel = RACPNT(lev, istart, jstart, k, SRCS(lev)); \
- tcel = RACPNT(lev, istart, jstart, k, TSET(lev)); \
- for(int j=jstart;j!=jend;++j) { \
- /* for(int i=0;i<mLevel[lev].lSizex-2; ) { */ \
- for(int i=istart;i!=iend; ) { \
- ADVANCE_POINTERS(1); \
-
-
-
-
-// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-#define GRID_LOOPREG_END() \
- \
- } /* i */ \
- int i=0; \
- ADVANCE_POINTERS(2*gridLoopBound); \
- } /* j */ \
- /* COMPRESSGRIDS!=1 */ \
- /* int i=0; */ \
- /* ADVANCE_POINTERS(mLevel[lev].lSizex*2); */ \
- } /* all cell loop k,j,i */ \
- if(doReduce) { } /* dummy remove warning */ \
- } /* main_region */ \
- \
-
-
-
-
-// old loop for COMPRESSGRIDS==0
-#define old__GRID_LOOP_START() \
- for(int k=kstart;k<kend;++k) { \
- for(int j=1;j<mLevel[lev].lSizey-1;++j) { \
- for(int i=0;i<mLevel[lev].lSizex-2; ) {
-
-
diff --git a/intern/elbeem/intern/mcubes_tables.h b/intern/elbeem/intern/mcubes_tables.h
deleted file mode 100644
index df83578d176..00000000000
--- a/intern/elbeem/intern/mcubes_tables.h
+++ /dev/null
@@ -1,300 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-
-/* which edges are needed ? */
-/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
-static const short mcEdgeTable[256]={
- 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
- 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
- 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
- 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
- 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
- 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
- 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
- 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
- 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
- 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
- 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
- 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
- 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
- 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
- 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
- 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
- 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
- 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
- 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
- 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
- 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
- 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
- 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
- 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
- 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
- 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
- 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
- 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
- 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
- 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
- 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
- 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
-
-/* triangles for the 256 intersection possibilities */
-/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
-static const short mcTriTable[256][16] = {
- {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
- {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
- {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
- {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
- {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
- {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
- {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
- {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
- {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
- {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
- {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
- {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
- {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
- {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
- {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
- {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
- {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
- {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
- {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
- {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
- {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
- {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
- {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
- {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
- {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
- {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
- {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
- {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
- {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
- {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
- {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
- {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
- {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
- {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
- {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
- {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
- {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
- {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
- {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
- {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
- {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
- {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
- {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
- {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
- {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
- {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
- {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
- {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
- {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
- {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
- {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
- {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
- {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
- {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
- {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
- {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
- {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
- {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
- {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
- {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
- {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
- {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
- {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
- {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
- {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
- {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
- {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
- {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
- {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
- {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
- {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
- {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
- {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
- {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
- {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
- {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
- {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
- {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
- {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
- {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
- {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
- {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
- {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
- {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
- {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
- {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
- {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
- {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
- {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
- {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
- {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
- {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
- {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
- {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
- {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
- {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
- {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
- {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
- {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
- {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
- {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
- {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
- {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
- {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
- {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
- {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
- {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
- {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
- {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
- {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
- {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
- {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
- {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
- {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
- {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
- {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
- {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
- {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
- {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
- {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
- {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
- {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
- {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
- {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
- {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
- {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
- {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
- {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
- {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
- {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
- {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
- {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
- {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
- {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
- {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
- {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
- {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
- {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
- {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
- {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
- {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
- {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
- {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
- {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
- {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
- {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
- {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
- {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
- {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
- {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
- {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
- {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
- {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
- {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
- {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
- {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
- {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
- {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
- {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
- {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
- {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
- {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
- {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
- {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
- {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
- {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
- {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
- {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
- {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
- {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
- {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
- {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
- {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
- {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
- {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
- {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
- {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
- {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
- {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
-};
diff --git a/intern/elbeem/intern/mvmcoords.cpp b/intern/elbeem/intern/mvmcoords.cpp
deleted file mode 100644
index 407a1b426f3..00000000000
--- a/intern/elbeem/intern/mvmcoords.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
-// El'Beem - the visual lattice boltzmann freesurface simulator
-// All code distributed as part of El'Beem is covered by the version 2 of the
-// GNU General Public License. See the file COPYING for details.
-//
-// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
-//
- *
- * Mean Value Mesh Coords class
- *
- *****************************************************************************/
-
-#include "mvmcoords.h"
-#include <algorithm>
-#include <cmath>
-
-#if defined(_MSC_VER) && _MSC_VER > 1600
-// std::greater
-#include <functional>
-#endif
-
-
-using std::vector;
-using std::isfinite;
-
-void MeanValueMeshCoords::clear()
-{
- mVertices.resize(0);
- mNumVerts = 0;
-}
-
-void MeanValueMeshCoords::calculateMVMCs(vector<ntlVec3Gfx> &reference_vertices, vector<ntlTriangle> &tris,
- vector<ntlVec3Gfx> &points, gfxReal numweights)
-{
- clear();
- mvmTransferPoint tds;
- int mem = 0;
- int i = 0;
-
- mNumVerts = (int)reference_vertices.size();
-
- for (vector<ntlVec3Gfx>::iterator iter = points.begin(); iter != points.end(); ++iter, ++i) {
- /*
- if(i%(points.size()/10)==1) debMsgStd("MeanValueMeshCoords::calculateMVMCs",DM_MSG,"Computing weights, points: "<<i<<"/"<<points.size(),5 );
- */
- tds.lastpos = *iter;
- tds.weights.resize(0); // clear
- computeWeights(reference_vertices, tris, tds, numweights);
- mem += (int)tds.weights.size();
- mVertices.push_back(tds);
- }
- int mbmem = mem * sizeof(mvmFloat) / (1024*1024);
- debMsgStd("MeanValueMeshCoords::calculateMVMCs",DM_MSG,"vertices:"<<mNumVerts<<" points:"<<points.size()<<" weights:"<<mem<<", wmem:"<<mbmem<<"MB ",7 );
-}
-
-// from: mean value coordinates for closed triangular meshes
-// attention: fails if a point is exactly (or very close) to a vertex
-void MeanValueMeshCoords::computeWeights(vector<ntlVec3Gfx> &reference_vertices, vector<ntlTriangle>& tris,
- mvmTransferPoint& tds, gfxReal numweights)
-{
- const bool mvmFullDebug=false;
- //const ntlVec3Gfx cEPS = 1.0e-6;
- const mvmFloat cEPS = 1.0e-14;
-
- //mvmFloat d[3], s[3], phi[3],c[3];
- ntlVec3d u[3],c,d,s,phi;
- int indices[3];
-
- for (int i = 0; i < (int)reference_vertices.size(); ++i) {
- tds.weights.push_back(mvmIndexWeight(i, 0.0));
- }
-
- // for each triangle
- //for (vector<ntlTriangle>::iterator iter = tris.begin(); iter != tris.end();) {
- for(int t=0; t<(int)tris.size(); t++) {
-
- for (int i = 0; i < 3; ++i) { //, ++iter) {
- indices[i] = tris[t].getPoints()[i];
- u[i] = vec2D(reference_vertices[ indices[i] ]-tds.lastpos);
- d[i] = normalize(u[i]); //.normalize();
- //assert(d[i] != 0.);
- if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","t"<<t<<" i"<<indices[i] //<<" lp"<<tds.lastpos
- <<" v"<<reference_vertices[indices[i]]<<" u"<<u[i]<<" ");
- // on vertex!
- //? if(d[i]<=0.) continue;
- }
- //for (int i = 0; i < 3; ++i) { errMsg("III"," "<<i <<" i"<<indices[i]<<reference_vertices[ indices[i] ] ); }
-
- // arcsin is not needed, see paper
- phi[0] = 2.*asin( (mvmFloat)(0.5* norm(u[1]-u[2]) ) );
- phi[1] = 2.*asin( (mvmFloat)(0.5* norm(u[0]-u[2]) ) );
- phi[2] = 2.*asin( (mvmFloat)(0.5* norm(u[0]-u[1]) ) );
- mvmFloat h = (phi[0] + phi[1] + phi[2])*0.5;
- if (M_PI-h < cEPS) {
- if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","point on triangle");
- tds.weights.resize(0);
- tds.weights.push_back( mvmIndexWeight(indices[0], sin(phi[0])*d[1]*d[2]));
- tds.weights.push_back( mvmIndexWeight(indices[1], sin(phi[1])*d[0]*d[2]));
- tds.weights.push_back( mvmIndexWeight(indices[2], sin(phi[2])*d[1]*d[0]));
- break;
- }
- mvmFloat sinh = 2.*sin(h);
- c[0] = (sinh*sin(h-phi[0]))/(sin(phi[1])*sin(phi[2]))-1.;
- c[1] = (sinh*sin(h-phi[1]))/(sin(phi[0])*sin(phi[2]))-1.;
- c[2] = (sinh*sin(h-phi[2]))/(sin(phi[0])*sin(phi[1]))-1.;
- if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","c="<<c<<" phi="<<phi<<" d="<<d);
- //if (c[0] > 1. || c[0] < 0. || c[1] > 1. || c[1] < 0. || c[2] > 1. || c[2] < 0.) continue;
-
- s[0] = sqrt((float)(1.-c[0]*c[0]));
- s[1] = sqrt((float)(1.-c[1]*c[1]));
- s[2] = sqrt((float)(1.-c[2]*c[2]));
-
- if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","s");
- if (s[0] <= cEPS || s[1] <= cEPS || s[2] <= cEPS) {
- //MSG("position lies outside the triangle on the same plane -> ignore it");
- continue;
- }
- const mvmFloat u0x = u[0][0];
- const mvmFloat u0y = u[0][1];
- const mvmFloat u0z = u[0][2];
- const mvmFloat u1x = u[1][0];
- const mvmFloat u1y = u[1][1];
- const mvmFloat u1z = u[1][2];
- const mvmFloat u2x = u[2][0];
- const mvmFloat u2y = u[2][1];
- const mvmFloat u2z = u[2][2];
- mvmFloat det = u0x*u1y*u2z - u0x*u1z*u2y + u0y*u1z*u2x - u0y*u1x*u2z + u0z*u1x*u2y - u0z*u1y*u2x;
- //assert(det != 0.);
- if (det < 0.) {
- s[0] = -s[0];
- s[1] = -s[1];
- s[2] = -s[2];
- }
-
- tds.weights[indices[0]].weight += (phi[0]-c[1]*phi[2]-c[2]*phi[1])/(d[0]*sin(phi[1])*s[2]);
- tds.weights[indices[1]].weight += (phi[1]-c[2]*phi[0]-c[0]*phi[2])/(d[1]*sin(phi[2])*s[0]);
- tds.weights[indices[2]].weight += (phi[2]-c[0]*phi[1]-c[1]*phi[0])/(d[2]*sin(phi[0])*s[1]);
- if(mvmFullDebug) { errMsg("MeanValueMeshCoords::computeWeights","i"<<indices[0]<<" o"<<tds.weights[indices[0]].weight);
- errMsg("MeanValueMeshCoords::computeWeights","i"<<indices[1]<<" o"<<tds.weights[indices[1]].weight);
- errMsg("MeanValueMeshCoords::computeWeights","i"<<indices[2]<<" o"<<tds.weights[indices[2]].weight);
- errMsg("MeanValueMeshCoords::computeWeights","\n\n\n"); }
- }
-
- //sort weights
- if((numweights>0.)&& (numweights<1.) ) {
- //if( ((int)tds.weights.size() > maxNumWeights) && (maxNumWeights > 0) ) {
- int maxNumWeights = (int)(tds.weights.size()*numweights);
- if(maxNumWeights<=0) maxNumWeights = 1;
- std::sort(tds.weights.begin(), tds.weights.end(), std::greater<mvmIndexWeight>());
- // only use maxNumWeights-th largest weights
- tds.weights.resize(maxNumWeights);
- }
-
- // normalize weights
- mvmFloat totalWeight = 0.;
- for (vector<mvmIndexWeight>::const_iterator witer = tds.weights.begin();
- witer != tds.weights.end(); ++witer) {
- totalWeight += witer->weight;
- }
- mvmFloat invTotalWeight;
- if (totalWeight == 0.) {
- if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","totalWeight == 0");
- invTotalWeight = 0.0;
- } else {
- invTotalWeight = 1.0/totalWeight;
- }
-
- for (vector<mvmIndexWeight>::iterator viter = tds.weights.begin();
- viter != tds.weights.end(); ++viter) {
- viter->weight *= invTotalWeight;
- //assert(isfinite(viter->weight) != 0);
- if(!isfinite(viter->weight)) viter->weight=0.;
- }
-}
-
-void MeanValueMeshCoords::transfer(vector<ntlVec3Gfx> &vertices, vector<ntlVec3Gfx>& displacements)
-{
- displacements.resize(0);
-
- //debMsgStd("MeanValueMeshCoords::transfer",DM_MSG,"vertices:"<<mNumVerts<<" curr_verts:"<<vertices.size()<<" ",7 );
- if((int)vertices.size() != mNumVerts) {
- errMsg("MeanValueMeshCoords::transfer","Different no of verts: "<<vertices.size()<<" vs "<<mNumVerts);
- return;
- }
-
- for (vector<mvmTransferPoint>::iterator titer = mVertices.begin(); titer != mVertices.end(); ++titer) {
- mvmTransferPoint &tds = *titer;
- ntlVec3Gfx newpos(0.0);
-
- for (vector<mvmIndexWeight>::iterator witer = tds.weights.begin();
- witer != tds.weights.end(); ++witer) {
- newpos += vertices[witer->index] * witer->weight;
- //errMsg("transfer","np"<<newpos<<" v"<<vertices[witer->index]<<" w"<< witer->weight);
- }
-
- displacements.push_back(newpos);
- //displacements.push_back(newpos - tds.lastpos);
- //tds.lastpos = newpos;
- }
-}
-
diff --git a/intern/elbeem/intern/mvmcoords.h b/intern/elbeem/intern/mvmcoords.h
deleted file mode 100644
index d00215ebd0e..00000000000
--- a/intern/elbeem/intern/mvmcoords.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
-// El'Beem - the visual lattice boltzmann freesurface simulator
-// All code distributed as part of El'Beem is covered by the version 2 of the
-// GNU General Public License. See the file COPYING for details.
-//
-// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
-//
- *
- * Mean Value Mesh Coords class
- *
- *****************************************************************************/
-
-#ifndef MVMCOORDS_H
-#define MVMCOORDS_H
-
-#include "utilities.h"
-#include "ntl_ray.h"
-#include <vector>
-#define mvmFloat double
-
-#ifdef WIN32
-#include "float.h"
-#define isnan(n) _isnan(n)
-#define finite _finite
-#endif
-
-#ifdef sun
-#include "ieeefp.h"
-#endif
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-// weight and triangle index
-class mvmIndexWeight {
- public:
-
- mvmIndexWeight() : weight(0.0) {}
-
- mvmIndexWeight(int const& i, mvmFloat const& w) :
- weight(w), index(i) {}
-
- // for sorting
- bool operator> (mvmIndexWeight const& w) const { return this->weight > w.weight; }
- bool operator< (mvmIndexWeight const& w) const { return this->weight < w.weight; }
-
- mvmFloat weight;
- int index;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:mvmIndexWeight")
-#endif
-};
-
-// transfer point with weights
-class mvmTransferPoint {
- public:
- //! position of transfer point
- ntlVec3Gfx lastpos;
- //! triangle weights
- std::vector<mvmIndexWeight> weights;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:mvmTransferPoint")
-#endif
-};
-
-
-//! compute mvmcs
-class MeanValueMeshCoords {
-
- public:
-
- MeanValueMeshCoords() {}
- ~MeanValueMeshCoords() {
- clear();
- }
-
- void clear();
-
- void calculateMVMCs(std::vector<ntlVec3Gfx> &reference_vertices,
- std::vector<ntlTriangle> &tris, std::vector<ntlVec3Gfx> &points, gfxReal numweights);
-
- void transfer(std::vector<ntlVec3Gfx> &vertices, std::vector<ntlVec3Gfx>& displacements);
-
- protected:
-
- void computeWeights(std::vector<ntlVec3Gfx> &reference_vertices,
- std::vector<ntlTriangle> &tris, mvmTransferPoint& tds, gfxReal numweights);
-
- std::vector<mvmTransferPoint> mVertices;
- int mNumVerts;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:MeanValueMeshCoords")
-#endif
-};
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_blenderdumper.cpp b/intern/elbeem/intern/ntl_blenderdumper.cpp
deleted file mode 100644
index eca184ae717..00000000000
--- a/intern/elbeem/intern/ntl_blenderdumper.cpp
+++ /dev/null
@@ -1,270 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Replaces std. raytracer, and only dumps time dep. objects to disc
- *
- *****************************************************************************/
-
-#include <fstream>
-#include <sys/types.h>
-
-#include "utilities.h"
-#include "ntl_matrices.h"
-#include "ntl_blenderdumper.h"
-#include "ntl_world.h"
-#include "solver_interface.h"
-#include "globals.h"
-
-#include <zlib.h>
-
-#ifdef LBM_GZIP_OVERRIDE_H
-# include LBM_GZIP_OVERRIDE_H
-#else
-# define LBM_GZIP_OPEN_FN(a, b) gzopen(a, b)
-#endif
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-ntlBlenderDumper::ntlBlenderDumper() : ntlWorld()
-{
- // same as normal constructor here
-}
-ntlBlenderDumper::ntlBlenderDumper(string filename, bool commandlineMode) :
- ntlWorld(filename,commandlineMode)
-{
- // init world
-}
-
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlBlenderDumper::~ntlBlenderDumper()
-{
- debMsgStd("ntlBlenderDumper",DM_NOTIFY, "ntlBlenderDumper done", 10);
-}
-
-/******************************************************************************
- * Only dump time dep. objects to file
- *****************************************************************************/
-int ntlBlenderDumper::renderScene( void )
-{
- char nrStr[5]; /* nr conversion */
- ntlRenderGlobals *glob = mpGlob;
- ntlScene *scene = mpGlob->getSimScene();
- bool debugOut = false;
- bool debugRender = false;
-#if ELBEEM_PLUGIN==1
- debugOut = false;
-#endif // ELBEEM_PLUGIN==1
-
- vector<string> gmName; // gm names
- vector<string> gmMat; // materials for gm
- int numGMs = 0; // no. of .obj models created
-
- if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Dumping geometry data", 1);
- long startTime = getTime();
- snprintf(nrStr, 5, "%04d", glob->getAniCount() );
-
- // local scene vars
- vector<ntlTriangle> Triangles;
- vector<ntlVec3Gfx> Vertices;
- vector<ntlVec3Gfx> VertNormals;
-
- // check geo objects
- int idCnt = 0; // give IDs to objects
- for (vector<ntlGeometryClass*>::iterator iter = scene->getGeoClasses()->begin();
- iter != scene->getGeoClasses()->end(); iter++) {
- if(!(*iter)->getVisible()) continue;
- int tid = (*iter)->getTypeId();
-
- if(tid & GEOCLASSTID_OBJECT) {
- // normal geom. objects -> ignore
- }
- if(tid & GEOCLASSTID_SHADER) {
- ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); //dynamic_cast<ntlGeometryShader*>(*iter);
- string outname = geoshad->getOutFilename();
- if(outname.length()<1) outname = mpGlob->getOutFilename();
- geoshad->notifyShaderOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname);
-
- for (vector<ntlGeometryObject*>::iterator siter = geoshad->getObjectsBegin();
- siter != geoshad->getObjectsEnd();
- siter++) {
- if(debugOut) debMsgStd("ntlBlenderDumper::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName(), 8);
-
- (*siter)->notifyOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname, this->mSimulationTime);
- bool doDump = false;
- bool isPreview = false;
- // only dump final&preview surface meshes
- if( (*siter)->getName().find( "final" ) != string::npos) {
- doDump = true;
- } else if( (*siter)->getName().find( "preview" ) != string::npos) {
- doDump = true;
- isPreview = true;
- }
- if(!doDump) continue;
-
- // dont quit, some objects need notifyOfDump call
- if((glob_mpactive) && (glob_mpindex>0)) {
- continue; //return 0;
- }
-
- // only dump geo shader objects
- Triangles.clear();
- Vertices.clear();
- VertNormals.clear();
- (*siter)->initialize( mpGlob );
- (*siter)->getTriangles(this->mSimulationTime, &Triangles, &Vertices, &VertNormals, idCnt);
- idCnt ++;
-
- // WARNING - this is dirty, but simobjs are the only geoshaders right now
- SimulationObject *sim = (SimulationObject *)geoshad;
- LbmSolverInterface *lbm = sim->getSolver();
-
-
- // always dump mesh, even empty ones...
-
- // dump to binary file
- std::ostringstream boutfilename("");
- //boutfilename << ecrpath.str() << outname <<"_"<< (*siter)->getName() <<"_" << nrStr << ".obj";
- boutfilename << outname <<"_"<< (*siter)->getName() <<"_" << nrStr;
- if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"B-Dumping: "<< (*siter)->getName()
- <<", triangles:"<<Triangles.size()<<", vertices:"<<Vertices.size()<<
- " to "<<boutfilename.str() , 7);
- gzFile gzf;
-
- // output velocities if desired
- if((!isPreview) && (lbm->getDumpVelocities())) {
- std::ostringstream bvelfilename;
- bvelfilename << boutfilename.str();
- bvelfilename << ".bvel.gz";
- /* wraps gzopen */
- gzf = LBM_GZIP_OPEN_FN(bvelfilename.str().c_str(), "wb9");
- if(gzf) {
- int numVerts;
- if(sizeof(numVerts)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; }
- numVerts = Vertices.size();
- gzwrite(gzf, &numVerts, sizeof(numVerts));
- for(size_t i=0; i<Vertices.size(); i++) {
- // returns smoothed velocity, scaled by frame time
- ntlVec3Gfx v = lbm->getVelocityAt( Vertices[i][0], Vertices[i][1], Vertices[i][2] );
- // translation not necessary, test rotation & scaling?
- for(int j=0; j<3; j++) {
- float vertp = v[j];
- //if(i<20) errMsg("ntlBlenderDumper","DUMP_VEL final "<<i<<" = "<<v);
- gzwrite(gzf, &vertp, sizeof(vertp)); }
- }
- gzclose( gzf );
- }
- }
-
- // compress all bobj's
- boutfilename << ".bobj.gz";
- /* wraps gzopen */
- gzf = LBM_GZIP_OPEN_FN(boutfilename.str().c_str(), "wb1"); // wb9 is slow for large meshes!
- if (!gzf) {
- errMsg("ntlBlenderDumper::renderScene","Unable to open output '" + boutfilename.str() + "' ");
- return 1; }
-
- // dont transform velocity output, this is handled in blender
- // current transform matrix
- ntlMatrix4x4<gfxReal> *trafo;
- trafo = lbm->getDomainTrafo();
- if(trafo) {
- // transform into source space
- for(size_t i=0; i<Vertices.size(); i++) {
- Vertices[i] = (*trafo) * Vertices[i];
- }
- }
- // rotate vertnormals
- ntlMatrix4x4<gfxReal> rottrafo;
- rottrafo.initId();
- if(lbm->getDomainTrafo()) {
- // dont modifiy original!
- rottrafo = *lbm->getDomainTrafo();
- ntlVec3Gfx rTrans,rScale,rRot,rShear;
- rottrafo.decompose(rTrans,rScale,rRot,rShear);
- rottrafo.initRotationXYZ(rRot[0],rRot[1],rRot[2]);
- // only rotate here...
- for(size_t i=0; i<Vertices.size(); i++) {
- VertNormals[i] = rottrafo * VertNormals[i];
- normalize(VertNormals[i]); // remove scaling etc.
- }
- }
-
-
- // write to file
- int numVerts;
- if(sizeof(numVerts)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; }
- numVerts = Vertices.size();
- gzwrite(gzf, &numVerts, sizeof(numVerts));
- for(size_t i=0; i<Vertices.size(); i++) {
- for(int j=0; j<3; j++) {
- float vertp = Vertices[i][j];
- gzwrite(gzf, &vertp, sizeof(vertp)); }
- }
-
- // should be the same as Vertices.size
- if(VertNormals.size() != (size_t)numVerts) {
- errMsg("ntlBlenderDumper::renderScene","Normals have to have same size as vertices!");
- VertNormals.resize( Vertices.size() );
- }
- gzwrite(gzf, &numVerts, sizeof(numVerts));
- for(size_t i=0; i<VertNormals.size(); i++) {
- for(int j=0; j<3; j++) {
- float normp = VertNormals[i][j];
- gzwrite(gzf, &normp, sizeof(normp)); }
- }
-
- int numTris = Triangles.size();
- gzwrite(gzf, &numTris, sizeof(numTris));
- for(size_t i=0; i<Triangles.size(); i++) {
- for(int j=0; j<3; j++) {
- int triIndex = Triangles[i].getPoints()[j];
- gzwrite(gzf, &triIndex, sizeof(triIndex)); }
- }
- gzclose( gzf );
- debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY," Wrote: '"<<boutfilename.str()<<"' ", 2);
- numGMs++;
- }
- }
-
- }
-
- // output ecr config file
- if(numGMs>0) {
- if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Objects dumped: "<<numGMs, 10);
- } else {
- if((glob_mpactive) && (glob_mpindex>0)) {
- // ok, nothing to do anyway...
- } else {
- errFatal("ntlBlenderDumper::renderScene","No objects to dump! Aborting...",SIMWORLD_INITERROR);
- return 1;
- }
- }
-
- // debug timing
- long stopTime = getTime();
- debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Scene #"<<nrStr<<" dump time: "<< getTimeString(stopTime-startTime) <<" ", 10);
-
- // still render for preview...
- if(debugRender) {
- debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Performing preliminary render", 1);
- ntlWorld::renderScene(); }
- else {
- // next frame
- glob->setAniCount( glob->getAniCount() +1 );
- }
-
- return 0;
-}
-
-
-
diff --git a/intern/elbeem/intern/ntl_blenderdumper.h b/intern/elbeem/intern/ntl_blenderdumper.h
deleted file mode 100644
index e3c0e3df12b..00000000000
--- a/intern/elbeem/intern/ntl_blenderdumper.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Replaces std. raytracer, and only dumps time dep. objects to disc, header
- *
- *****************************************************************************/
-#ifndef NTL_BLENDERDUMPER_H
-#include "ntl_world.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlBlenderDumper :
- public ntlWorld
-{
-public:
- /*! Constructor */
- ntlBlenderDumper();
- ntlBlenderDumper(string filename, bool commandlineMode);
- /*! Destructor */
- virtual ~ntlBlenderDumper( void );
-
- /*! render scene (a single pictures) */
- virtual int renderScene( void );
-
-protected:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlBlenderDumper")
-#endif
-};
-
-#define NTL_BLENDERDUMPER_H
-#endif
-
diff --git a/intern/elbeem/intern/ntl_bsptree.cpp b/intern/elbeem/intern/ntl_bsptree.cpp
deleted file mode 100644
index 8d589e50cb4..00000000000
--- a/intern/elbeem/intern/ntl_bsptree.cpp
+++ /dev/null
@@ -1,945 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Tree container for fast triangle intersects
- *
- *****************************************************************************/
-
-
-#include "ntl_bsptree.h"
-#include "utilities.h"
-
-#include <algorithm>
-
-/*! Static global variable for sorting direction */
-int globalSortingAxis;
-/*! Access to points array for sorting */
-vector<ntlVec3Gfx> *globalSortingPoints;
-
-#define TREE_DOUBLEI 300
-
-/* try axis selection? */
-bool chooseAxis = 0;
-/* do median search? */
-int doSort = 0;
-
-
-//! struct for a single node in the bsp tree
-class BSPNode {
- public:
- BSPNode() {};
-
- ntlVec3Gfx min,max; /* AABB for node */
- vector<ntlTriangle *> *members; /* stored triangles */
- BSPNode *child[2]; /* pointer to children nodes */
- char axis; /* division axis */
- char cloneVec; /* is this vector a clone? */
-
- //! check if node is a leaf
- inline bool isLeaf() const {
- return (child[0] == NULL);
- }
-};
-
-
-//! an element node stack
-class BSPStackElement {
- public:
- //! tree node
- BSPNode *node;
- //! min and maximum distance along axis
- gfxReal mindist, maxdist;
-};
-
-//! bsp tree stack
-class BSPStack {
- public:
- //! current stack element
- int stackPtr;
- //! stack storage
- BSPStackElement elem[ BSP_STACK_SIZE ];
-};
-
-//! triangle bounding box for quick tree subdivision
-class TriangleBBox {
- public:
- //! start and end of triangle bounding box
- ntlVec3Gfx start, end;
-};
-
-
-/******************************************************************************
- * calculate tree statistics
- *****************************************************************************/
-void calcStats(BSPNode *node, int depth, int &noLeafs, gfxReal &avgDepth, gfxReal &triPerLeaf,int &totalTris)
-{
- if(node->members != NULL) {
- totalTris += node->members->size();
- }
- //depth = 15; // DBEUG!
-
- if( (node->child[0]==NULL) && (node->child[1]==NULL) ) {
- // leaf
- noLeafs++;
- avgDepth += depth;
- triPerLeaf += node->members->size();
- } else {
- for(int i=0;i<2;i++)
- calcStats(node->child[i], depth+1, noLeafs, avgDepth, triPerLeaf, totalTris);
- }
-}
-
-
-
-/******************************************************************************
- * triangle comparison function for median search
- *****************************************************************************/
-bool lessTriangleAverage(const ntlTriangle *x, const ntlTriangle *y)
-{
- return x->getAverage(globalSortingAxis) < y->getAverage(globalSortingAxis);
-}
-
-
-/******************************************************************************
- * triangle AABB intersection
- *****************************************************************************/
-bool ntlTree::checkAABBTriangle(ntlVec3Gfx &min, ntlVec3Gfx &max, ntlTriangle *tri)
-{
- // test only BB of triangle
- TriangleBBox *bbox = &mpTBB[ tri->getBBoxId() ];
- if( bbox->end[0] < min[0] ) return false;
- if( bbox->start[0] > max[0] ) return false;
- if( bbox->end[1] < min[1] ) return false;
- if( bbox->start[1] > max[1] ) return false;
- if( bbox->end[2] < min[2] ) return false;
- if( bbox->start[2] > max[2] ) return false;
- return true;
-}
-
-
-
-
-
-
-
-/******************************************************************************
- * Default constructor
- *****************************************************************************/
-ntlTree::ntlTree() :
- mStart(0.0), mEnd(0.0), mMaxDepth( 5 ), mMaxListLength( 5 ), mpRoot( NULL) ,
- mpNodeStack( NULL), mpVertices( NULL ), mpVertNormals( NULL ), mpTriangles( NULL ),
- mCurrentDepth(0), mCurrentNodes(0), mTriDoubles(0)
-{
- errFatal( "ntlTree","Uninitialized BSP Tree!\n",SIMWORLD_INITERROR );
- return;
-}
-
-
-/******************************************************************************
- * Constructor with init
- *****************************************************************************/
-//ntlTree::ntlTree(int depth, int objnum, vector<ntlVec3Gfx> *vertices, vector<ntlVec3Gfx> *normals, vector<ntlTriangle> *trilist) :
-ntlTree::ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask) :
- mStart(0.0), mEnd(0.0), mMaxDepth( depth ), mMaxListLength( objnum ), mpRoot( NULL) ,
- mpNodeStack( NULL), mpTBB( NULL ),
- mTriangleMask( 0xFFFF ),
- mCurrentDepth(0), mCurrentNodes(0), mTriDoubles(0)
-{
- // init scene data pointers
- mpVertices = scene->getVertexPointer();
- mpVertNormals = scene->getVertexNormalPointer();
- mpTriangles = scene->getTrianglePointer();
- mTriangleMask = triFlagMask;
-
- if(mpTriangles == NULL) {
- errFatal( "ntlTree Cons","no triangle list!\n",SIMWORLD_INITERROR);
- return;
- }
- if(mpTriangles->size() == 0) {
- warnMsg( "ntlTree::ntlTree","No triangles ("<< mpTriangles->size() <<")!\n");
- mStart = mEnd = ntlVec3Gfx(0,0,0);
- return;
- }
- if(depth>=BSP_STACK_SIZE) {
- errFatal( "ntlTree::ntlTree","Depth to high ("<< mMaxDepth <<")!\n", SIMWORLD_INITERROR );
- return;
- }
-
- /* check triangles (a bit inefficient, but we dont know which vertices belong
- to this tree), and generate bounding boxes */
- mppTriangles = new vector<ntlTriangle *>;
- int noOfTriangles = mpTriangles->size();
- mpTBB = new TriangleBBox[ noOfTriangles ];
- int bbCount = 0;
- mStart = mEnd = (*mpVertices)[ mpTriangles->front().getPoints()[0] ];
- //errMsg("TreeDebug","Start");
- for (vector<ntlTriangle>::iterator iter = mpTriangles->begin();
- iter != mpTriangles->end();
- iter++ ) {
- //errorOut(" d "<< convertFlags2String((int)(*iter).getFlags()) <<" "<< convertFlags2String( (int)mTriangleMask)<<" add? "<<( ((int)(*iter).getFlags() & (int)mTriangleMask) != 0 ) );
- // discard triangles that dont match mask
- if( ((int)(*iter).getFlags() & (int)mTriangleMask) == 0 ) {
- continue;
- }
-
- // test? TODO
- ntlVec3Gfx tnormal = (*mpVertNormals)[ (*iter).getPoints()[0] ]+
- (*mpVertNormals)[ (*iter).getPoints()[1] ]+
- (*mpVertNormals)[ (*iter).getPoints()[2] ];
- ntlVec3Gfx triangleNormal = (*iter).getNormal();
- if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) continue;
- if( equal( tnormal, ntlVec3Gfx(0.0)) ) continue;
- // */
-
- ntlVec3Gfx bbs, bbe;
- //errMsg("TreeDebug","Triangle");
- for(int i=0;i<3;i++) {
- int index = (*iter).getPoints()[i];
- ntlVec3Gfx tp = (*mpVertices)[ index ];
- //errMsg("TreeDebug"," Point "<<i<<" = "<<tp<<" ");
- if(tp[0] < mStart[0]) mStart[0]= tp[0];
- if(tp[0] > mEnd[0]) mEnd[0]= tp[0];
- if(tp[1] < mStart[1]) mStart[1]= tp[1];
- if(tp[1] > mEnd[1]) mEnd[1]= tp[1];
- if(tp[2] < mStart[2]) mStart[2]= tp[2];
- if(tp[2] > mEnd[2]) mEnd[2]= tp[2];
- if(i==0) {
- bbs = bbe = tp;
- } else {
- if( tp[0] < bbs[0] ) bbs[0] = tp[0];
- if( tp[0] > bbe[0] ) bbe[0] = tp[0];
- if( tp[1] < bbs[1] ) bbs[1] = tp[1];
- if( tp[1] > bbe[1] ) bbe[1] = tp[1];
- if( tp[2] < bbs[2] ) bbs[2] = tp[2];
- if( tp[2] > bbe[2] ) bbe[2] = tp[2];
- }
- }
- mppTriangles->push_back( &(*iter) );
- //errMsg("TreeDebug","Triangle "<<(*mpVertices)[(*iter).getPoints()[0]]<<" "<<(*mpVertices)[(*iter).getPoints()[1]]<<" "<<(*mpVertices)[(*iter).getPoints()[2]]<<" ");
-
- // add BB
- mpTBB[ bbCount ].start = bbs;
- mpTBB[ bbCount ].end = bbe;
- (*iter).setBBoxId( bbCount );
- bbCount++;
- }
-
-
-
- /* slighlty enlarge bounding tolerance for tree
- to avoid problems with triangles paralell to slabs */
- mStart -= ntlVec3Gfx( getVecEpsilon() );
- mEnd += ntlVec3Gfx( getVecEpsilon() );
-
- /* init root node and stack */
- mpNodeStack = new BSPStack;
- mpRoot = new BSPNode;
- mpRoot->min = mStart;
- mpRoot->max = mEnd;
- mpRoot->axis = AXIS_X;
- mpRoot->members = mppTriangles;
- mpRoot->child[0] = mpRoot->child[1] = NULL;
- mpRoot->cloneVec = 0;
- globalSortingPoints = mpVertices;
- mpTriDist = new char[ mppTriangles->size() ];
- mNumNodes = 1;
- mAbortSubdiv = 0;
-
- /* create tree */
- debugOutInter( "Generating BSP Tree... (Nodes "<< mCurrentNodes <<
- ", Depth "<<mCurrentDepth<< ") ", 2, 2000 );
- subdivide(mpRoot, 0, AXIS_X);
- debMsgStd("ntlTree::ntlTree",DM_MSG,"Generated Tree: Nodes "<< mCurrentNodes <<
- ", Depth "<<mCurrentDepth<< " with "<<noOfTriangles<<" triangles", 2 );
-
- delete [] mpTriDist;
- delete [] mpTBB;
- mpTriDist = NULL;
- mpTBB = NULL;
-
- /* calculate some stats about tree */
- int noLeafs = 0;
- gfxReal avgDepth = 0.0;
- gfxReal triPerLeaf = 0.0;
- int totalTris = 0;
-
- calcStats(mpRoot,0, noLeafs, avgDepth, triPerLeaf, totalTris);
- avgDepth /= (gfxReal)noLeafs;
- triPerLeaf /= (gfxReal)noLeafs;
- debMsgStd("ntlTree::ntlTree",DM_MSG,"Tree ("<<doSort<<","<<chooseAxis<<") Stats: Leafs:"<<noLeafs<<", avgDepth:"<<avgDepth<<
- ", triPerLeaf:"<<triPerLeaf<<", triDoubles:"<<mTriDoubles<<", totalTris:"<<totalTris
- <<" nodes:"<<mNumNodes
- //<<" T"<< (totalTris%3) // 0=ich, 1=f, 2=a
- , 2 );
-
- if(mAbortSubdiv) {
- errMsg("ntlTree::ntlTree","Aborted... "<<mNumNodes);
- deleteNode(mpRoot);
- mpRoot = NULL;
- }
-}
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlTree::~ntlTree()
-{
- /* delete tree, and all members except for the root node */
- deleteNode(mpRoot);
- if(mpNodeStack) delete mpNodeStack;
-}
-
-
-/******************************************************************************
- * subdivide tree
- *****************************************************************************/
-void ntlTree::subdivide(BSPNode *node, int depth, int axis)
-{
- int nextAxis=0; /* next axis to partition */
- int allTriDistSet = (1<<0)|(1<<1); // all mpTriDist flags set?
- //errorOut(" "<<node<<" depth:"<<depth<<" m:"<<node->members->size() <<" "<<node->min<<" - "<<node->max );
-
- if(depth>mCurrentDepth) mCurrentDepth = depth;
- node->child[0] = node->child[1] = NULL;
- if( ( (int)node->members->size() > mMaxListLength) &&
- (depth < mMaxDepth )
- && (node->cloneVec<10)
- && (!mAbortSubdiv)
- ) {
-
- gfxReal planeDiv = 0.499999; // position of plane division
-
- // determine next subdivision axis
- int newaxis = 0;
- gfxReal extX = node->max[0]-node->min[0];
- gfxReal extY = node->max[1]-node->min[1];
- gfxReal extZ = node->max[2]-node->min[2];
-
- if( extY>extX ) {
- if( extZ>extY ) {
- newaxis = 2;
- } else {
- newaxis = 1;
- }
- } else {
- if( extZ>extX ) {
- newaxis = 2;
- } else {
- newaxis = 0;
- }
- }
- axis = node->axis = newaxis;
-
- // init child nodes
- for( int i=0; i<2; i++) {
- /* status output */
- mCurrentNodes++;
- if(mCurrentNodes % 13973 ==0) {
- debugOutInter( "NTL Generating BSP Tree ("<<doSort<<","<<chooseAxis<<") ... (Nodes "<< mCurrentNodes <<
- ", Depth "<<mCurrentDepth<< ") " , 2, 2000);
- }
-
- /* create new node */
- node->child[i] = new BSPNode;
- node->child[i]->min = node->min;
- node->child[i]->max = node->max;
- node->child[i]->max = node->max;
- node->child[i]->child[0] = NULL;
- node->child[i]->child[1] = NULL;
- node->child[i]->members = NULL;
- nextAxis = (axis+1)%3;
- node->child[i]->axis = nextAxis;
- mNumNodes++;
- // abort when using 256MB only for tree...
- if(mNumNodes*sizeof(BSPNode)> 1024*1024*512) mAbortSubdiv = 1;
-
- /* current division plane */
- if(!i) {
- node->child[i]->min[axis] = node->min[axis];
- node->child[i]->max[axis] = node->min[axis] + planeDiv*
- (node->max[axis]-node->min[axis]);
- } else {
- node->child[i]->min[axis] = node->min[axis] + planeDiv*
- (node->max[axis]-node->min[axis]);
- node->child[i]->max[axis] = node->max[axis];
- }
- }
-
-
- /* process the two children */
- int thisTrisFor[2] = {0,0};
- int thisTriDoubles[2] = {0,0};
- for(int t=0;t<(int)node->members->size();t++) mpTriDist[t] = 0;
- for( int i=0; i<2; i++) {
- /* distribute triangles */
- int t = 0;
- for (vector<ntlTriangle *>::iterator iter = node->members->begin();
- iter != node->members->end(); iter++ ) {
-
- /* add triangle, check bounding box axis */
- TriangleBBox *bbox = &mpTBB[ (*iter)->getBBoxId() ];
- bool isintersect = true;
- if( bbox->end[axis] < node->child[i]->min[axis] ) isintersect = false;
- else if( bbox->start[axis] > node->child[i]->max[axis] ) isintersect = false;
- if(isintersect) {
- // add flag to vector
- mpTriDist[t] |= (1<<i);
- // count no. of triangles for vector init
- thisTrisFor[i]++;
- }
-
- if(mpTriDist[t] == allTriDistSet) {
- thisTriDoubles[i]++;
- mTriDoubles++; // TODO check for small geo tree??
- }
- t++;
- } /* end of loop over all triangles */
- } // i
-
- /* distribute triangles */
- bool haveCloneVec[2] = {false, false};
- for( int i=0; i<2; i++) {
- node->child[i]->members = new vector<ntlTriangle *>( thisTrisFor[i] );
- node->child[i]->cloneVec = 0;
- }
-
- int tind0 = 0;
- int tind1 = 0;
- if( (!haveCloneVec[0]) || (!haveCloneVec[1]) ){
- int t = 0; // triangle index counter
- for (vector<ntlTriangle *>::iterator iter = node->members->begin();
- iter != node->members->end(); iter++ ) {
- if(!haveCloneVec[0]) {
- if( (mpTriDist[t] & 1) == 1) {
- (*node->child[0]->members)[tind0] = (*iter); // dont use push_back for preinited size!
- tind0++;
- }
- }
- if(!haveCloneVec[1]) {
- if( (mpTriDist[t] & 2) == 2) {
- (*node->child[1]->members)[tind1] = (*iter); // dont use push_back for preinited size!
- tind1++;
- }
- }
- t++;
- } /* end of loop over all triangles */
- }
-
- // subdivide children
- for( int i=0; i<2; i++) {
- /* recurse */
- subdivide( node->child[i], depth+1, nextAxis );
- }
-
- /* if we are here, this are childs, so we dont need the members any more... */
- /* delete unecessary members */
- if( (!haveCloneVec[0]) && (!haveCloneVec[1]) && (node->cloneVec == 0) ){
- delete node->members;
- }
- node->members = NULL;
-
- } /* subdivision necessary */
-}
-
-/******************************************************************
- * triangle intersection with triangle pointer,
- * returns t,u,v by references
- */
-#if GFX_PRECISION==1
-// float values
-//! the minimal triangle determinant length
-#define RAY_TRIANGLE_EPSILON (1e-07)
-
-#else
-// double values
-//! the minimal triangle determinant length
-#define RAY_TRIANGLE_EPSILON (1e-15)
-
-#endif
-
-
-/******************************************************************************
- * intersect ray with BSPtree
- *****************************************************************************/
-inline void ntlRay::intersectTriangle(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
-{
- /* (cf. moeller&haines, page 305) */
- t = GFX_REAL_MAX;
- ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
- ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
- ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
- ntlVec3Gfx p = cross( mDirection, e2 );
- gfxReal divisor = dot(e1, p);
- if((divisor > -RAY_TRIANGLE_EPSILON)&&(divisor < RAY_TRIANGLE_EPSILON)) return;
-
- gfxReal invDivisor = 1/divisor;
- ntlVec3Gfx s = mOrigin - e0;
- u = invDivisor * dot(s, p);
- if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- ntlVec3Gfx q = cross( s,e1 );
- v = invDivisor * dot(mDirection, q);
- if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- t = invDivisor * dot(e2, q);
-}
-void ntlTree::intersect(const ntlRay &ray, gfxReal &distance,
- ntlVec3Gfx &normal,
- ntlTriangle *&tri,
- int flags, bool forceNonsmooth) const
-{
- gfxReal mint = GFX_REAL_MAX; /* current minimal t */
- ntlVec3Gfx retnormal; /* intersection (interpolated) normal */
- gfxReal mintu=0.0, mintv=0.0; /* u,v for min t intersection */
-
- BSPNode *curr, *nearChild, *farChild; /* current node and children */
- gfxReal planedist, mindist, maxdist;
- ntlVec3Gfx pos;
-
- ntlTriangle *hit = NULL;
- tri = NULL;
-
- ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist);
-
- if((maxdist < 0.0) ||
- (!mpRoot) ||
- (mindist == GFX_REAL_MAX) ||
- (maxdist == GFX_REAL_MAX) ) {
- distance = -1.0;
- return;
- }
- mindist -= getVecEpsilon();
- maxdist += getVecEpsilon();
-
- /* stack init */
- mpNodeStack->elem[0].node = NULL;
- mpNodeStack->stackPtr = 1;
-
- curr = mpRoot;
- mint = GFX_REAL_MAX;
- while(curr != NULL) {
-
- while( !curr->isLeaf() ) {
- planedist = distanceToPlane(curr, curr->child[0]->max, ray );
- getChildren(curr, ray.getOrigin(), nearChild, farChild );
-
- // check ray direction for small plane distances
- if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) {
- // ray origin on intersection plane
- planedist = 0.0;
- if(ray.getDirection()[curr->axis]>getVecEpsilon() ) {
- // larger coords
- curr = curr->child[1];
- } else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) {
- // smaller coords
- curr = curr->child[0];
- } else {
- // paralell, order doesnt really matter are min/max/plane ok?
- mpNodeStack->elem[ mpNodeStack->stackPtr ].node = curr->child[0];
- mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
- (mpNodeStack->stackPtr)++;
- curr = curr->child[1];
- maxdist = planedist;
- }
- } else {
- // normal ray
- if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) {
- curr = nearChild;
- } else if(planedist < mindist) {
- curr = farChild;
- } else {
- mpNodeStack->elem[ mpNodeStack->stackPtr ].node = farChild;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
- (mpNodeStack->stackPtr)++;
-
- curr = nearChild;
- maxdist = planedist;
- }
- }
- }
-
-
- /* intersect with current node */
- for (vector<ntlTriangle *>::iterator iter = curr->members->begin();
- iter != curr->members->end(); iter++ ) {
-
- /* check for triangle flags before intersecting */
- if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) {
-
- if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) {
- // was already intersected...
- } else {
- // we still need to intersect this triangle
- gfxReal u=0.0,v=0.0, t=-1.0;
- ray.intersectTriangle( mpVertices, (*iter), t,u,v);
- (*iter)->setLastRay( ray.getID() );
-
- if( (t > 0.0) && (t<mint) ) {
- mint = t;
- hit = (*iter);
- mintu = u; mintv = v;
- }
- }
-
- } // flags check
- }
-
- /* check if intersection is valid */
- if( (mint>0.0) && (mint < GFX_REAL_MAX) ) {
- pos = ray.getOrigin() + ray.getDirection()*mint;
-
- if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) &&
- (pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) &&
- (pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) )
- {
-
- if(forceNonsmooth) {
- // calculate triangle normal
- ntlVec3Gfx e0,e1,e2;
- e0 = (*mpVertices)[ hit->getPoints()[0] ];
- e1 = (*mpVertices)[ hit->getPoints()[1] ];
- e2 = (*mpVertices)[ hit->getPoints()[2] ];
- retnormal = cross( -(e2-e0), (e1-e0) );
- } else {
- // calculate interpolated normal
- retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
- (*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
- (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
- }
- normalize(retnormal);
- normal = retnormal;
- distance = mint;
- tri = hit;
- return;
- }
- }
-
- (mpNodeStack->stackPtr)--;
- curr = mpNodeStack->elem[ mpNodeStack->stackPtr ].node;
- mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist;
- maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist;
- } /* traverse tree */
-
- if(mint == GFX_REAL_MAX) {
- distance = -1.0;
- } else {
- // intersection outside the BSP bounding volumes might occur due to roundoff...
- //retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
- if(forceNonsmooth) {
- // calculate triangle normal
- ntlVec3Gfx e0,e1,e2;
- e0 = (*mpVertices)[ hit->getPoints()[0] ];
- e1 = (*mpVertices)[ hit->getPoints()[1] ];
- e2 = (*mpVertices)[ hit->getPoints()[2] ];
- retnormal = cross( -(e2-e0), (e1-e0) );
- } else {
- // calculate interpolated normal
- retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
- (*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
- (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
- }
-
- normalize(retnormal);
- normal = retnormal;
- distance = mint;
- tri = hit;
- }
- return;
-}
-
-inline void ntlRay::intersectTriangleX(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
-{
- /* (cf. moeller&haines, page 305) */
- t = GFX_REAL_MAX;
- ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
- ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
- ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
-
- //ntlVec3Gfx p = cross( mDirection, e2 );
- //ntlVector3Dim<Scalar> cp( (-), (- (1.0 *v[2])), ((1.0 *v[1]) -) );
- ntlVec3Gfx p(0.0, -e2[2], e2[1]);
-
- gfxReal divisor = dot(e1, p);
- if((divisor > -RAY_TRIANGLE_EPSILON)&&(divisor < RAY_TRIANGLE_EPSILON)) return;
-
- gfxReal invDivisor = 1/divisor;
- ntlVec3Gfx s = mOrigin - e0;
- u = invDivisor * dot(s, p);
- if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- ntlVec3Gfx q = cross( s,e1 );
- //v = invDivisor * dot(mDirection, q);
- v = invDivisor * q[0];
- if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- t = invDivisor * dot(e2, q);
-}
-void ntlTree::intersectX(const ntlRay &ray, gfxReal &distance,
- ntlVec3Gfx &normal,
- ntlTriangle *&tri,
- int flags, bool forceNonsmooth) const
-{
- gfxReal mint = GFX_REAL_MAX; /* current minimal t */
- ntlVec3Gfx retnormal; /* intersection (interpolated) normal */
- gfxReal mintu=0.0, mintv=0.0; /* u,v for min t intersection */
-
- BSPNode *curr, *nearChild, *farChild; /* current node and children */
- gfxReal planedist, mindist, maxdist;
- ntlVec3Gfx pos;
-
- ntlTriangle *hit = NULL;
- tri = NULL;
-
- ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist); // +X
-
- if((maxdist < 0.0) ||
- (!mpRoot) ||
- (mindist == GFX_REAL_MAX) ||
- (maxdist == GFX_REAL_MAX) ) {
- distance = -1.0;
- return;
- }
- mindist -= getVecEpsilon();
- maxdist += getVecEpsilon();
-
- /* stack init */
- mpNodeStack->elem[0].node = NULL;
- mpNodeStack->stackPtr = 1;
-
- curr = mpRoot;
- mint = GFX_REAL_MAX;
- while(curr != NULL) { // +X
-
- while( !curr->isLeaf() ) {
- planedist = distanceToPlane(curr, curr->child[0]->max, ray );
- getChildren(curr, ray.getOrigin(), nearChild, farChild );
-
- // check ray direction for small plane distances
- if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) {
- // ray origin on intersection plane
- planedist = 0.0;
- if(ray.getDirection()[curr->axis]>getVecEpsilon() ) {
- // larger coords
- curr = curr->child[1];
- } else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) {
- // smaller coords
- curr = curr->child[0];
- } else {
- // paralell, order doesnt really matter are min/max/plane ok?
- mpNodeStack->elem[ mpNodeStack->stackPtr ].node = curr->child[0];
- mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
- (mpNodeStack->stackPtr)++;
- curr = curr->child[1];
- maxdist = planedist;
- }
- } else {
- // normal ray
- if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) {
- curr = nearChild;
- } else if(planedist < mindist) {
- curr = farChild;
- } else {
- mpNodeStack->elem[ mpNodeStack->stackPtr ].node = farChild;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
- (mpNodeStack->stackPtr)++;
-
- curr = nearChild;
- maxdist = planedist;
- }
- }
- } // +X
-
-
- /* intersect with current node */
- for (vector<ntlTriangle *>::iterator iter = curr->members->begin();
- iter != curr->members->end(); iter++ ) {
-
- /* check for triangle flags before intersecting */
- if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) {
-
- if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) {
- // was already intersected...
- } else {
- // we still need to intersect this triangle
- gfxReal u=0.0,v=0.0, t=-1.0;
- ray.intersectTriangleX( mpVertices, (*iter), t,u,v);
- (*iter)->setLastRay( ray.getID() );
-
- if( (t > 0.0) && (t<mint) ) {
- mint = t;
- hit = (*iter);
- mintu = u; mintv = v;
- }
- }
-
- } // flags check
- } // +X
-
- /* check if intersection is valid */
- if( (mint>0.0) && (mint < GFX_REAL_MAX) ) {
- pos = ray.getOrigin() + ray.getDirection()*mint;
-
- if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) &&
- (pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) &&
- (pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) )
- {
-
- if(forceNonsmooth) {
- // calculate triangle normal
- ntlVec3Gfx e0,e1,e2;
- e0 = (*mpVertices)[ hit->getPoints()[0] ];
- e1 = (*mpVertices)[ hit->getPoints()[1] ];
- e2 = (*mpVertices)[ hit->getPoints()[2] ];
- retnormal = cross( -(e2-e0), (e1-e0) );
- } else {
- // calculate interpolated normal
- retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
- (*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
- (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
- }
- normalize(retnormal);
- normal = retnormal;
- distance = mint;
- tri = hit;
- return;
- }
- } // +X
-
- (mpNodeStack->stackPtr)--;
- curr = mpNodeStack->elem[ mpNodeStack->stackPtr ].node;
- mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist;
- maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist;
- } /* traverse tree */
-
- if(mint == GFX_REAL_MAX) {
- distance = -1.0;
- } else {
-
- // intersection outside the BSP bounding volumes might occur due to roundoff...
- if(forceNonsmooth) {
- // calculate triangle normal
- ntlVec3Gfx e0,e1,e2;
- e0 = (*mpVertices)[ hit->getPoints()[0] ];
- e1 = (*mpVertices)[ hit->getPoints()[1] ];
- e2 = (*mpVertices)[ hit->getPoints()[2] ];
- retnormal = cross( -(e2-e0), (e1-e0) );
- } else {
- // calculate interpolated normal
- retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
- (*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
- (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
- }
-
- normalize(retnormal);
- normal = retnormal;
- distance = mint;
- tri = hit;
- } // +X
- return;
-}
-
-
-
-/******************************************************************************
- * distance to plane function for nodes
- *****************************************************************************/
-gfxReal ntlTree::distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const
-{
- return ( (plane[curr->axis]-ray.getOrigin()[curr->axis]) / ray.getDirection()[curr->axis] );
-}
-
-
-/******************************************************************************
- * return ordering of children nodes relatice to origin point
- *****************************************************************************/
-void ntlTree::getChildren(BSPNode *curr, ntlVec3Gfx origin, BSPNode *&node_near, BSPNode *&node_far) const
-{
- if(curr->child[0]->max[ curr->axis ] >= origin[ curr->axis ]) {
- node_near = curr->child[0];
- node_far = curr->child[1];
- } else {
- node_near = curr->child[1];
- node_far = curr->child[0];
- }
-}
-
-
-/******************************************************************************
- * delete a node of the tree with all sub nodes
- * dont delete root members
- *****************************************************************************/
-void ntlTree::deleteNode(BSPNode *curr)
-{
- if(!curr) return;
-
- if(curr->child[0] != NULL)
- deleteNode(curr->child[0]);
- if(curr->child[1] != NULL)
- deleteNode(curr->child[1]);
-
- if(curr->members != NULL) delete curr->members;
- delete curr;
-}
-
-
-
-/******************************************************************
- * intersect only front or backsides
- * currently unused
- */
-inline void ntlRay::intersectTriangleFront(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
-{
- t = GFX_REAL_MAX;
- ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
- ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
- ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
- ntlVec3Gfx p = cross( mDirection, e2 );
- gfxReal a = dot(e1, p);
- //if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return;
- if(a < RAY_TRIANGLE_EPSILON) return; // cull backsides
-
- gfxReal f = 1/a;
- ntlVec3Gfx s = mOrigin - e0;
- u = f * dot(s, p);
- if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- ntlVec3Gfx q = cross( s,e1 );
- v = f * dot(mDirection, q);
- if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- t = f * dot(e2, q);
-}
-inline void ntlRay::intersectTriangleBack(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
-{
- t = GFX_REAL_MAX;
- ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
- ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
- ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
- ntlVec3Gfx p = cross( mDirection, e2 );
- gfxReal a = dot(e1, p);
- //if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return;
- if(a > -RAY_TRIANGLE_EPSILON) return; // cull frontsides
-
- gfxReal f = 1/a;
- ntlVec3Gfx s = mOrigin - e0;
- u = f * dot(s, p);
- if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- ntlVec3Gfx q = cross( s,e1 );
- v = f * dot(mDirection, q);
- if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- t = f * dot(e2, q);
-}
-
-
-
diff --git a/intern/elbeem/intern/ntl_bsptree.h b/intern/elbeem/intern/ntl_bsptree.h
deleted file mode 100644
index f6eaee069a9..00000000000
--- a/intern/elbeem/intern/ntl_bsptree.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Tree container for fast triangle intersects
- *
- *****************************************************************************/
-#ifndef NTL_TREE_H
-#define NTL_TREE_H
-
-#include "ntl_vector3dim.h"
-#include "ntl_ray.h"
-
-
-#define AXIS_X 0
-#define AXIS_Y 1
-#define AXIS_Z 2
-
-#define BSP_STACK_SIZE 50
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-//! bsp tree stack classes, defined in ntl_bsptree.cpp,
-// detailed definition unnecesseary here
-class BSPNode;
-class BSPStackElement;
-class BSPStack;
-class TriangleBBox;
-class ntlScene;
-class ntlTriangle;
-
-
-//! Class for a bsp tree for triangles
-class ntlTree
-{
- public:
-
- //! Default constructor
- ntlTree();
- //! Constructor with init
- ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask);
- //! Destructor
- ~ntlTree();
-
- //! subdivide tree
- void subdivide(BSPNode *node, int depth, int axis);
-
- //! intersect ray with BSPtree
- void intersect(const ntlRay &ray, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags, bool forceNonsmooth) const;
- //! intersect along +X ray
- void intersectX(const ntlRay &ray, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags, bool forceNonsmooth) const;
-
- //! Returns number of nodes
- int getCurrentNodes( void ) { return mCurrentNodes; }
-
- protected:
-
- // check if a triangle is in a node
- bool checkAABBTriangle(ntlVec3Gfx &min, ntlVec3Gfx &max, ntlTriangle *tri);
-
-
- // VARs
-
- //! distance to plane function for nodes
- gfxReal distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const;
-
- //! return ordering of children nodes relatice to origin point
- void getChildren(BSPNode *curr, ntlVec3Gfx origin, BSPNode *&node_near, BSPNode *&node_far) const;
-
- //! delete a node of the tree with all sub nodes, dont delete root members
- void deleteNode(BSPNode *curr);
-
- //inline bool isLeaf(BSPNode *node) const { return (node->child[0] == NULL); }
-
-
- //! AABB for tree
- ntlVec3Gfx mStart,mEnd;
-
- //! maximum depth of tree
- int mMaxDepth;
-
- //! maximum number of objects in one node
- int mMaxListLength;
-
- //! root node pointer
- BSPNode *mpRoot;
- //! count no. of node
- int mNumNodes;
- int mAbortSubdiv;
-
- //! stack for the node pointers
- BSPStack *mpNodeStack;
- //stack<BSPNode *> nodestack;
-
- //! pointer to vertex array
- vector<ntlVec3Gfx> *mpVertices;
-
- //! pointer to vertex array
- vector<ntlVec3Gfx> *mpVertNormals;
-
- //! vector for all the triangles
- vector<ntlTriangle> *mpTriangles;
- vector<ntlTriangle *> *mppTriangles;
-
- //! temporary array for triangle distribution to nodes
- char *mpTriDist;
-
- //! temporary array for triangle bounding boxes
- TriangleBBox *mpTBB;
-
- //! triangle mask - include only triangles that match mask
- int mTriangleMask;
-
- //! Status vars (max depth, # of current nodes)
- int mCurrentDepth, mCurrentNodes;
-
- //! duplicated triangles, inited during subdivide
- int mTriDoubles;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlTree")
-#endif
-};
-
-
-#endif
-
-
diff --git a/intern/elbeem/intern/ntl_geometryclass.h b/intern/elbeem/intern/ntl_geometryclass.h
deleted file mode 100644
index a5d44ad477a..00000000000
--- a/intern/elbeem/intern/ntl_geometryclass.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Base class for geometry shaders and objects
- *
- *****************************************************************************/
-
-
-#ifndef NTL_GEOMETRYCLASS_H
-#define NTL_GEOMETRYCLASS_H
-
-#include "attributes.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-//! geometry class type ids
-#define GEOCLASSTID_OBJECT 1
-#define GEOCLASSTID_SHADER 2
-#define GEOCLASSTID_BOX (GEOCLASSTID_OBJECT| 4)
-#define GEOCLASSTID_OBJMODEL (GEOCLASSTID_OBJECT| 8)
-#define GEOCLASSTID_SPHERE (GEOCLASSTID_OBJECT| 16)
-
-class ntlGeometryClass
-{
-
- public:
-
- //! Default constructor
- inline ntlGeometryClass() :
- mVisible( 1 ), mName( "[ObjNameUndef]" ),
- mObjectId(-1), mpAttrs( NULL ), mGeoInitId(-1)
- {
- mpAttrs = new AttributeList("objAttrs");
- mpSwsAttrs = new AttributeList("swsAttrs");
- };
-
- //! Default destructor
- virtual ~ntlGeometryClass() {
- delete mpAttrs;
- delete mpSwsAttrs;
- };
-
- //! Return type id
- virtual int getTypeId() = 0;
-
- /*! Set the object name */
- inline void setName(string set) { mName = set; }
- /*! Get the object name */
- inline string getName( void ) { return mName; }
-
- /*! Sets the visibility attribute
- * visibility can be determined at shader _and_ object level , hiding a shader
- * means comepletely decativating it */
- inline void setVisible(int set) { mVisible=set; }
- /*! Returns the visibility attribute */
- inline int getVisible() const { return mVisible; }
-
- /*! Sets the attribute list pointer */
- inline void setAttributeList(AttributeList *set) { mpAttrs=set; }
- /*! Returns the attribute list pointer */
- inline AttributeList *getAttributeList() { return mpAttrs; }
-
- /*! Get/Sets the attribute list pointer */
- inline void setSwsAttributeList(AttributeList *set) { mpSwsAttrs=set; }
- inline AttributeList *getSwsAttributeList() { return mpSwsAttrs; }
-
- /*! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB */
- virtual inline ntlVec3Gfx *getBBStart() { return NULL; }
- virtual inline ntlVec3Gfx *getBBEnd() { return NULL; }
-
- /*! Set/get the object id*/
- inline void setObjectId(int set) { mObjectId=set; }
- inline int getObjectId() const { return mObjectId; }
-
- /*! GUI - this function is called for selected objects to display debugging information with OpenGL */
- virtual void drawDebugDisplay() { /* do nothing by default */ }
- /*! GUI - this function is called for selected objects to display interactive information with OpenGL */
- virtual void drawInteractiveDisplay() { /* do nothing by default */ }
- /*! GUI - handle mouse movement for selection */
- virtual void setMousePos(int ,int , ntlVec3Gfx , ntlVec3Gfx ) { /* do nothing by default */ }
- /*! GUI - notify object that mouse was clicked at last pos */
- virtual void setMouseClick() { /* do nothing by default */ }
-
- /*! Returns the geo init id */
- inline void setGeoInitId(int set) { mGeoInitId=set; }
- /*! Returns the geo init id */
- inline int getGeoInitId() const { return mGeoInitId; }
-
- protected:
-
- /*! Object visible on/off */
- int mVisible;
-
- /*! Name of this object */
- string mName;
-
- /*! global scene object id */
- int mObjectId;
-
- /*! configuration attributes */
- AttributeList *mpAttrs;
- /*! sws configuration attributes */
- AttributeList *mpSwsAttrs;
-
- /* fluid init data */
- /*! id of fluid init (is used in solver initialization), additional data stored only for objects */
- int mGeoInitId;
-
- private:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlGeometryClass")
-#endif
-};
-
-
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_geometrymodel.cpp b/intern/elbeem/intern/ntl_geometrymodel.cpp
deleted file mode 100644
index 989fcac599b..00000000000
--- a/intern/elbeem/intern/ntl_geometrymodel.cpp
+++ /dev/null
@@ -1,477 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * A simple box object
- *
- *****************************************************************************/
-
-#include "ntl_geometrymodel.h"
-#include "ntl_ray.h"
-#include "ntl_world.h"
-#include "zlib.h"
-
-#ifdef WIN32
-#ifndef strncasecmp
-#define strncasecmp(a,b,c) strcmp(a,b)
-#endif
-#endif // WIN32
-
-
-/******************************************************************************
- * Default Constructor
- *****************************************************************************/
-ntlGeometryObjModel::ntlGeometryObjModel( void ) :
- ntlGeometryObject(),
- mvStart( 0.0 ), mvEnd( 1.0 ),
- mLoaded( false ),
- mTriangles(), mVertices(), mNormals(),
- mcAniVerts(), mcAniNorms(),
- mcAniTimes(), mAniTimeScale(1.), mAniTimeOffset(0.)
-{
-}
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlGeometryObjModel::~ntlGeometryObjModel()
-{
- if(!mLoaded) {
- errMsg("ntlGeometryObjModel","delete obj...");
- }
-}
-
-
-/*! is the mesh animated? */
-bool ntlGeometryObjModel::getMeshAnimated() {
- const bool ret = (mcAniVerts.getSize()>1);
- //errMsg("getMeshAnimated","ret="<<ret<<", size="<<mcAniVerts.getSize() );
- return ret;
-}
-
-/*! calculate max extends of (ani) mesh */
-void ntlGeometryObjModel::getExtends(ntlVec3Gfx &sstart, ntlVec3Gfx &send) {
- bool ini=false;
- ntlVec3Gfx start(0.),end(0.);
- for(int s=0; s<=(int)mcAniVerts.accessValues().size(); s++) {
- vector<ntlVec3f> *sverts;
- if(mcAniVerts.accessValues().size()>0) {
- if(s==(int)mcAniVerts.accessValues().size()) continue;
- sverts = &(mcAniVerts.accessValues()[s].mVerts);
- } else sverts = &mVertices;
-
- for(int i=0; i<(int)sverts->size(); i++) {
-
- if(!ini) {
- start=(*sverts)[i];
- end=(*sverts)[i];
- //errMsg("getExtends","ini "<<s<<","<<i<<" "<<start<<","<<end);
- ini=true;
- } else {
- for(int j=0; j<3; j++) {
- if(start[j] > (*sverts)[i][j]) { start[j]= (*sverts)[i][j]; }
- if(end[j] < (*sverts)[i][j]) { end[j] = (*sverts)[i][j]; }
- }
- //errMsg("getExtends","check "<<s<<","<<i<<" "<<start<<","<<end<<" "<< (*sverts)[i]);
- }
-
- }
- }
- sstart=start;
- send=end;
-}
-
-
-/*****************************************************************************/
-/* Init attributes etc. of this object */
-/*****************************************************************************/
-void ntlGeometryObjModel::initialize(ntlRenderGlobals *glob)
-{
- // perhaps the model is already inited from initModel below?
- if(mLoaded==1) {
- // init default material
- searchMaterial( glob->getMaterials() );
- return;
- }
-
- ntlGeometryObject::initialize(glob);
- mFilename = mpAttrs->readString("filename", mFilename,"ntlGeometryObjModel", "mFilename", true);
-
- if(mFilename == "") {
- errMsg("ntlGeometryObjModel::initialize","Filename not given!");
- return;
- }
-
- const char *suffix = strrchr(mFilename.c_str(), '.');
- if (suffix) {
- if (!strncasecmp(suffix, ".obj", 4)) {
- errMsg("ntlGeometryObjModel::initialize",".obj files not supported!");
- return;
- } else if (!strncasecmp(suffix, ".gz", 3)) {
- //mType = 1; // assume its .bobj.gz
- } else if (!strncasecmp(suffix, ".bobj", 5)) {
- //mType = 1;
- }
- }
-
- if(getAttributeList()->exists("ani_times") || (!mcAniTimes.isInited()) ) {
- mcAniTimes = mpAttrs->readChannelFloat("ani_times");
- }
- mAniTimeScale = mpAttrs->readFloat("ani_timescale", mAniTimeScale,"ntlGeometryObjModel", "mAniTimeScale", false);
- mAniTimeOffset = mpAttrs->readFloat("ani_timeoffset", mAniTimeOffset,"ntlGeometryObjModel", "mAniTimeOffset", false);
-
- // continue with standard obj
- if(loadBobjModel(mFilename)==0) mLoaded=1;
- if(!mLoaded) {
- debMsgStd("ntlGeometryObjModel",DM_WARNING,"Unable to load object file '"<<mFilename<<"' !", 0);
- }
- if(getMeshAnimated()) {
- this->mIsAnimated = true;
- }
-}
-
-/******************************************************************************
- * init model from given vertex and triangle arrays
- *****************************************************************************/
-
-int ntlGeometryObjModel::initModel(int numVertices, float *vertices, int numTriangles, int *triangles,
- int channelSize, float *channelVertices)
-{
- mVertices.clear();
- mVertices.resize( numVertices );
- mNormals.resize( numVertices );
- for(int i=0; i<numVertices; i++) {
- mVertices[i] = ntlVec3Gfx(vertices[i*3+0],vertices[i*3+1],vertices[i*3+2]);
- mNormals[i] = ntlVec3Gfx(1.0); // unused, set to !=0.0
- }
-
- mTriangles.clear();
- mTriangles.resize( 3*numTriangles );
- int triangleErrs=0;
- for(int i=0; i<numTriangles; i++) {
- for(int j=0;j<3;j++) {
- mTriangles[3*i+j] = triangles[i*3+j];
- if(mTriangles[3*i+j]<0) { mTriangles[3*i+j]=0; triangleErrs++; }
- if(mTriangles[3*i+j]>=numVertices) { mTriangles[3*i+j]=0; triangleErrs++; }
- }
- }
- if(triangleErrs>0) {
- errMsg("ntlGeometryObjModel::initModel","Triangle errors occurred ("<<triangleErrs<<")!");
- }
-
- //fprintf(stderr,"initModel DEBUG %d \n",channelSize);
- debMsgStd("ntlGeometryObjModel::initModel",DM_MSG, "Csize:"<<channelSize<<", Cvert:"<<(size_t)(channelVertices) ,10);
- if(channelVertices && (channelSize>0)) {
- vector<ntlSetVec3f> aniverts;
- vector<ntlSetVec3f> aninorms;
- vector<double> anitimes;
- aniverts.clear();
- aninorms.clear();
- anitimes.clear();
- for(int frame=0; frame<channelSize; frame++) {
- ntlSetVec3f averts; averts.mVerts.clear();
- ntlSetVec3f anorms; anorms.mVerts.clear();
- int setsize = (3*numVertices+1);
-
- ntlVec3Gfx p(0.),n(1.);
- for(int i=0; i<numVertices; i++) {
- for(int j=0; j<3; j++) p[j] = channelVertices[frame*setsize+ 3*i +j];
- averts.mVerts.push_back(p);
- anorms.mVerts.push_back(p);
- //debMsgStd("ntlGeometryObjModel::initModel",DM_MSG, "Frame:"<<frame<<",i:"<<i<<" "<<p,10);
- }
- if( ((int)averts.mVerts.size()==numVertices) &&
- ((int)anorms.mVerts.size()==numVertices) ) {
- aniverts.push_back(averts);
- aninorms.push_back(anorms);
- double time = (double)channelVertices[frame*setsize+ setsize-1];
- anitimes.push_back(time);
- } else {
- errMsg("ntlGeometryObjModel::initModel","Invalid mesh, obj="<<this->getName()<<" frame="<<frame<<" verts="<<averts.mVerts.size()<<"/"<<numVertices<<". Skipping...");
- }
- //debMsgStd("ntlGeometryObjModel::initModel",DM_MSG, "Frame:"<<frame<<" at t="<<time,10);
- }
-
- mcAniVerts = AnimChannel<ntlSetVec3f>(aniverts,anitimes);
- mcAniNorms = AnimChannel<ntlSetVec3f>(aninorms,anitimes);
- debMsgStd("ntlGeometryObjModel::initModel",DM_MSG, "Ani sets inited: "<< mcAniVerts.accessValues().size() <<","<<mcAniNorms.accessValues().size() <<" ", 1 );
- }
- if(getMeshAnimated()) {
- this->mIsAnimated = true;
- }
-
- // inited, no need to parse attribs etc.
- mLoaded = 1;
- return 0;
-}
-
-/*! init triangle divisions */
-void ntlGeometryObjModel::calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTriangle> &tris, gfxReal fsTri) {
- // warning - copied from geomobj calc!
- errMsg("ntlGeometryObjModel","calcTriangleDivs special!");
- mTriangleDivs1.resize( tris.size() );
- mTriangleDivs2.resize( tris.size() );
- for(size_t i=0; i<tris.size(); i++) {
- ntlVec3Gfx p0 = verts[ tris[i].getPoints()[0] ];
- ntlVec3Gfx p1 = verts[ tris[i].getPoints()[1] ];
- ntlVec3Gfx p2 = verts[ tris[i].getPoints()[2] ];
- ntlVec3Gfx side1 = p1 - p0;
- ntlVec3Gfx side2 = p2 - p0;
- ntlVec3Gfx side3 = p1 - p2;
- int divs1=0, divs2=0;
- if(normNoSqrt(side1) > fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); }
- if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); }
-
- // special handling
- // warning, requires objmodel triangle treatment (no verts dups)
- if(getMeshAnimated()) {
- vector<ntlSetVec3f> &sverts = mcAniVerts.accessValues();
- for(int s=0; s<(int)sverts.size(); s++) {
- p0 = sverts[s].mVerts[ tris[i].getPoints()[0] ];
- p1 = sverts[s].mVerts[ tris[i].getPoints()[1] ];
- p2 = sverts[s].mVerts[ tris[i].getPoints()[2] ];
- side1 = p1 - p0; side2 = p2 - p0; side3 = p1 - p2;
- int tdivs1=0, tdivs2=0;
- if(normNoSqrt(side1) > fsTri*fsTri) { tdivs1 = (int)(norm(side1)/fsTri); }
- if(normNoSqrt(side2) > fsTri*fsTri) { tdivs2 = (int)(norm(side2)/fsTri); }
- if(tdivs1>divs1) divs1=tdivs1;
- if(tdivs2>divs2) divs2=tdivs2;
- }
- } // */
- mTriangleDivs1[i] = divs1;
- mTriangleDivs2[i] = divs2;
- }
-}
-
-
-/******************************************************************************
- * load model from .obj file
- *****************************************************************************/
-
-int ntlGeometryObjModel::loadBobjModel(string filename)
-{
- bool haveAniSets=false;
- vector<ntlSetVec3f> aniverts;
- vector<ntlSetVec3f> aninorms;
- vector<double> anitimes;
-
- const bool debugPrint=false;
- const bool debugPrintFull=false;
- gzFile gzf;
- gzf = gzopen(filename.c_str(), "rb");
- if (!gzf) {
- errFatal("ntlGeometryObjModel::loadBobjModel","Reading GZ_BOBJ, Unable to open '"<< filename <<"'...\n", SIMWORLD_INITERROR );
- return 1;
- }
-
- int numVerts;
- if(sizeof(numVerts)!=4) { // paranoia check
- errMsg("Reading GZ_BOBJ"," Invalid int size, check compiler settings: int has to be 4 byte long");
- goto gzreaderror;
- }
- gzread(gzf, &numVerts, sizeof(numVerts) );
- if(numVerts<0 || numVerts>1e9) {
- errMsg("Reading GZ_BOBJ"," invalid num vertices "<< numVerts);
- goto gzreaderror;
- }
- mVertices.clear();
- mVertices.resize( numVerts );
- for(int i=0; i<numVerts; i++) {
- float x[3];
- for(int j=0; j<3; j++) {
- gzread(gzf, &(x[j]), sizeof( (x[j]) ) );
- }
- mVertices[i] = ntlVec3Gfx(x[0],x[1],x[2]);
- if(debugPrintFull) errMsg("FULLV"," "<<i<<" "<< mVertices[i] );
- }
- if(debugPrint) errMsg("NV"," "<<numVerts<<" "<< mVertices.size() );
-
- // should be the same as Vertices.size
- gzread(gzf, &numVerts, sizeof(numVerts) );
- if(numVerts<0 || numVerts>1e9) {
- errMsg("Reading GZ_BOBJ","invalid num normals "<< numVerts);
- goto gzreaderror;
- }
- mNormals.clear();
- mNormals.resize( numVerts );
- for(int i=0; i<numVerts; i++) {
- float n[3];
- for(int j=0; j<3; j++) {
- gzread(gzf, &(n[j]), sizeof( (n[j]) ) );
- }
- mNormals[i] = ntlVec3Gfx(n[0],n[1],n[2]);
- if(debugPrintFull) errMsg("FULLN"," "<<i<<" "<< mNormals[i] );
- }
- if(debugPrint) errMsg("NN"," "<<numVerts<<" "<< mNormals.size() );
-
- int numTris;
- gzread(gzf, &numTris, sizeof(numTris) );
- if(numTris<0 || numTris>1e9) {
- errMsg("Reading GZ_BOBJ","invalid num normals "<< numTris);
- goto gzreaderror;
- }
- mTriangles.resize( 3*numTris );
- for(int i=0; i<numTris; i++) {
- int tri[3];
- for(int j=0; j<3; j++) {
- gzread(gzf, &(tri[j]), sizeof( (tri[j]) ) );
- }
- mTriangles[3*i+0] = tri[0];
- mTriangles[3*i+1] = tri[1];
- mTriangles[3*i+2] = tri[2];
- }
- if(debugPrint) errMsg("NT"," "<<numTris<<" "<< mTriangles.size() );
-
- debMsgStd("ntlGeometryObjModel::loadBobjModel",DM_MSG, "File '"<<filename<<"' loaded, #Vertices: "<<mVertices.size()<<", #Normals: "<<mNormals.size()<<", #Triangles: "<<(mTriangles.size()/3)<<" ", 1 );
-
- // try to load animated mesh
- aniverts.clear();
- aninorms.clear();
- anitimes.clear();
- while(1) {
- //ntlVec3Gfx check;
- float x[3];
- float frameTime=0.;
- int bytesRead = 0;
- int numNorms2=-1, numVerts2=-1;
- //for(int j=0; j<3; j++) {
- //x[j] = 0.;
- //bytesRead += gzread(gzf, &(x[j]), sizeof(float) );
- //}
- //check = ntlVec3Gfx(x[0],x[1],x[2]);
- //if(debugPrint) errMsg("ANI_NV1"," "<<check<<" "<<" bytes:"<<bytesRead );
- bytesRead += gzread(gzf, &frameTime, sizeof(frameTime) );
- //if(bytesRead!=3*sizeof(float)) {
- if(bytesRead!=sizeof(float)) {
- debMsgStd("ntlGeometryObjModel::loadBobjModel",DM_MSG, "File '"<<filename<<"' end of gzfile. ", 10 );
- if(anitimes.size()>0) {
- // finally init channels and stop reading file
- mcAniVerts = AnimChannel<ntlSetVec3f>(aniverts,anitimes);
- mcAniNorms = AnimChannel<ntlSetVec3f>(aninorms,anitimes);
- }
- goto gzreaddone;
- }
- bytesRead += gzread(gzf, &numVerts2, sizeof(numVerts2) );
- haveAniSets=true;
- // continue to read new set
- vector<ntlVec3Gfx> vertset;
- vector<ntlVec3Gfx> normset;
- vertset.resize(numVerts);
- normset.resize(numVerts);
- //vertset[0] = check;
- if(debugPrintFull) errMsg("FUL1V"," "<<0<<" "<< vertset[0] );
-
- for(int i=0; i<numVerts; i++) { // start at one!
- for(int j=0; j<3; j++) {
- bytesRead += gzread(gzf, &(x[j]), sizeof( (x[j]) ) );
- }
- vertset[i] = ntlVec3Gfx(x[0],x[1],x[2]);
- if(debugPrintFull) errMsg("FUL2V"," "<<i<<" "<< vertset[i] );
- }
- if(debugPrint) errMsg("ANI_VV"," "<<numVerts<<" "<< vertset.size()<<" bytes:"<<bytesRead );
-
- bytesRead += gzread(gzf, &numNorms2, sizeof(numNorms2) );
- for(int i=0; i<numVerts; i++) {
- for(int j=0; j<3; j++) {
- bytesRead += gzread(gzf, &(x[j]), sizeof( (x[j]) ) );
- }
- normset[i] = ntlVec3Gfx(x[0],x[1],x[2]);
- if(debugPrintFull) errMsg("FUL2N"," "<<i<<" "<< normset[i] );
- }
- if(debugPrint) errMsg("ANI_NV"," "<<numVerts<<","<<numVerts2<<","<<numNorms2<<","<< normset.size()<<" bytes:"<<bytesRead );
-
- // set ok
- if(bytesRead== (int)( (numVerts*2*3+1) *sizeof(float)+2*sizeof(int) ) ) {
- if(aniverts.size()==0) {
- // TODO, ignore first mesh?
- double anitime = (double)(frameTime-1.); // start offset!? anitimes.size();
- // get for current frame entry
- if(mcAniTimes.getSize()>1) anitime = mcAniTimes.get(anitime);
- anitime = anitime*mAniTimeScale+mAniTimeOffset;
-
- anitimes.push_back( anitime );
- aniverts.push_back( ntlSetVec3f(mVertices) );
- aninorms.push_back( ntlSetVec3f(mNormals) );
- if(debugPrint) errMsg("ANI_NV","new set "<<mVertices.size()<<","<< mNormals.size()<<" time:"<<anitime );
- }
- double anitime = (double)(frameTime); //anitimes.size();
- // get for current frame entry
- if(mcAniTimes.getSize()>1) anitime = mcAniTimes.get(anitime);
- anitime = anitime*mAniTimeScale+mAniTimeOffset;
-
- anitimes.push_back( anitime );
- aniverts.push_back( ntlSetVec3f(vertset) );
- aninorms.push_back( ntlSetVec3f(normset) );
- if(debugPrint) errMsg("ANI_NV","new set "<<vertset.size()<<","<< normset.size()<<" time:"<<anitime );
- } else {
- errMsg("ntlGeometryObjModel::loadBobjModel","Malformed ani set! Aborting... ("<<bytesRead<<") ");
- goto gzreaddone;
- }
- } // anim sets */
-
-gzreaddone:
-
- if(haveAniSets) {
- debMsgStd("ntlGeometryObjModel::loadBobjModel",DM_MSG, "File '"<<filename<<"' ani sets loaded: "<< mcAniVerts.accessValues().size() <<","<<mcAniNorms.accessValues().size() <<" ", 1 );
- }
- gzclose( gzf );
- return 0;
-
-gzreaderror:
- mTriangles.clear();
- mVertices.clear();
- mNormals.clear();
- gzclose( gzf );
- errFatal("ntlGeometryObjModel::loadBobjModel","Reading GZ_BOBJ, Unable to load '"<< filename <<"', exiting...\n", SIMWORLD_INITERROR );
- return 1;
-}
-
-
-/******************************************************************************
- *
- *****************************************************************************/
-void
-ntlGeometryObjModel::getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId )
-{
- if(!mLoaded) { // invalid type...
- return;
- }
- if(mcAniVerts.getSize()>1) { mVertices = mcAniVerts.get(t).mVerts; }
- if(mcAniNorms.getSize()>1) { mNormals = mcAniNorms.get(t).mVerts; }
-
- int startvert = vertices->size();
- vertices->resize( vertices->size() + mVertices.size() );
- normals->resize( normals->size() + mVertices.size() );
- for(int i=0; i<(int)mVertices.size(); i++) {
- (*vertices)[startvert+i] = mVertices[i];
- (*normals)[startvert+i] = mNormals[i];
- }
-
- triangles->reserve(triangles->size() + mTriangles.size()/3 );
- for(int i=0; i<(int)mTriangles.size(); i+=3) {
- int trip[3];
- trip[0] = startvert+mTriangles[i+0];
- trip[1] = startvert+mTriangles[i+1];
- trip[2] = startvert+mTriangles[i+2];
-
- //sceneAddTriangle(
- //mVertices[trip[0]], mVertices[trip[1]], mVertices[trip[2]],
- //mNormals[trip[0]], mNormals[trip[1]], mNormals[trip[2]],
- //ntlVec3Gfx(0.0), 1 , triangles,vertices,normals ); /* normal unused */
- sceneAddTriangleNoVert( trip, ntlVec3Gfx(0.0), 1 , triangles ); /* normal unused */
- }
- objectId = -1; // remove warning
- // bobj
- return;
-}
-
-
-
-
-
diff --git a/intern/elbeem/intern/ntl_geometrymodel.h b/intern/elbeem/intern/ntl_geometrymodel.h
deleted file mode 100644
index a5f26ba17b8..00000000000
--- a/intern/elbeem/intern/ntl_geometrymodel.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * A model laoded from Wavefront .obj file
- *
- *****************************************************************************/
-#ifndef NTL_GEOMODEL_H
-#define NTL_GEOMODEL_H
-
-#include "ntl_geometryobject.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-/*! A simple box object generatedd by 12 triangles */
-class ntlGeometryObjModel : public ntlGeometryObject
-{
- public:
- /* Init constructor */
- ntlGeometryObjModel( void );
- /* Init constructor */
- //ntlGeometryObjModel( ntlVec3Gfx start, ntlVec3Gfx end );
- /* Destructor */
- virtual ~ntlGeometryObjModel( void );
-
- //! Return type id
- virtual int getTypeId() { return GEOCLASSTID_OBJMODEL; }
-
- /*! Filename setting etc. */
- virtual void initialize(ntlRenderGlobals *glob);
-
- /*! is the mesh animated? */
- virtual bool getMeshAnimated();
-
- /* create triangles from obj */
- virtual void getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId );
-
- /*! load model from .bobj file, returns !=0 upon error */
- int loadBobjModel(string filename);
- /*! init model from given vertex and triangle arrays */
- int initModel(int numVertices, float *vertices, int numTriangles, int *triangles,
- int channelSize, float *channelVertices);
- /*! init triangle divisions */
- virtual void calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTriangle> &tris, gfxReal fsTri);
-
- /*! calculate max extends of (ani) mesh */
- void getExtends(ntlVec3Gfx &start, ntlVec3Gfx &end);
-
- private:
-
- /*! Start and end points of box */
- ntlVec3Gfx mvStart, mvEnd;
-
- /*! was the model loaded? */
- bool mLoaded;
-
- /*! filename of the obj file */
- string mFilename;
-
- /*! for bobj models */
- vector<int> mTriangles;
- vector<ntlVec3Gfx> mVertices;
- vector<ntlVec3Gfx> mNormals;
-
- /*! animated channels for vertices, if given will override getris by default */
- AnimChannel<ntlSetVec3f> mcAniVerts;
- AnimChannel<ntlSetVec3f> mcAniNorms;
- /*! map entrie of anim mesh to sim times */
- AnimChannel<double> mcAniTimes;
- /*! timing mapping & offset for config files */
- double mAniTimeScale, mAniTimeOffset;
-
- public:
-
- /* Access methods */
- /*! Access start vector */
- inline ntlVec3Gfx getStart( void ){ return mvStart; }
- inline void setStart( const ntlVec3Gfx &set ){ mvStart = set; }
- /*! Access end vector */
- inline ntlVec3Gfx getEnd( void ){ return mvEnd; }
- inline void setEnd( const ntlVec3Gfx &set ){ mvEnd = set; }
-
- inline bool getLoaded( void ){ return mLoaded; }
- inline void setLoaded( bool set ){ mLoaded = set; }
-
- /*! set data file name */
- inline void setFilename(string set) { mFilename = set; }
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlGeometryObjModel")
-#endif
-};
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_geometryobject.cpp b/intern/elbeem/intern/ntl_geometryobject.cpp
deleted file mode 100644
index 7eb2df4ad3f..00000000000
--- a/intern/elbeem/intern/ntl_geometryobject.cpp
+++ /dev/null
@@ -1,806 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * a geometry object
- * all other geometry objects are derived from this one
- *
- *****************************************************************************/
-
-
-#include "ntl_geometryobject.h"
-#include "ntl_world.h"
-#include "ntl_matrices.h"
-
-// for FGI
-#include "elbeem.h"
-
-#define TRI_UVOFFSET (1./4.)
-//#define TRI_UVOFFSET (1./3.)
-
-
-/*****************************************************************************/
-/* Default constructor */
-/*****************************************************************************/
-ntlGeometryObject::ntlGeometryObject() :
- mIsInitialized(false), mpMaterial( NULL ),
- mMaterialName( "default" ),
- mCastShadows( 1 ), mReceiveShadows( 1 ),
- mGeoInitType( 0 ),
- mInitialVelocity(0.0), mcInitialVelocity(0.0), mLocalCoordInivel(false),
- mGeoInitIntersect(false),
- mGeoPartSlipValue(0.0),
- mcGeoImpactFactor(1.),
- mVolumeInit(VOLUMEINIT_VOLUME),
- mInitialPos(0.),
- mcTrans(0.), mcRot(0.), mcScale(1.),
- mIsAnimated(false),
- mMovPoints(), mMovNormals(),
- mHaveCachedMov(false),
- mCachedMovPoints(), mCachedMovNormals(),
- mTriangleDivs1(), mTriangleDivs2(),
- mMovPntsInited(-100.0), mMaxMovPnt(-1),
- mcGeoActive(1.),
- mCpsTimeStart(0.), mCpsTimeEnd(1.0), mCpsQuality(10.),
- mcAttrFStr(0.),mcAttrFRad(0.), mcVelFStr(0.), mcVelFRad(0.)
-{
-};
-
-
-/*****************************************************************************/
-/* Default destructor */
-/*****************************************************************************/
-ntlGeometryObject::~ntlGeometryObject()
-{
-}
-
-/*! is the mesh animated? */
-bool ntlGeometryObject::getMeshAnimated() {
- // off by default, on for e.g. ntlGeometryObjModel
- return false;
-}
-
-/*! init object anim flag */
-bool ntlGeometryObject::checkIsAnimated() {
- if( (mcTrans.accessValues().size()>1) // VALIDATE
- || (mcRot.accessValues().size()>1)
- || (mcScale.accessValues().size()>1)
- || (mcGeoActive.accessValues().size()>1)
- // mcGeoImpactFactor only needed when moving
- || (mcInitialVelocity.accessValues().size()>1)
- ) {
- mIsAnimated = true;
- }
-
- // fluid objects always have static init!
- if(mGeoInitType==FGI_FLUID) {
- mIsAnimated=false;
- }
- //errMsg("ntlGeometryObject::checkIsAnimated","obj="<<getName()<<" debug: trans:"<<mcTrans.accessValues().size()<<" rot:"<<mcRot.accessValues().size()<<" scale:"<<mcScale.accessValues().size()<<" active:"<<mcGeoActive.accessValues().size()<<" inivel:"<<mcInitialVelocity.accessValues().size()<<". isani?"<<mIsAnimated ); // DEBUG
- return mIsAnimated;
-}
-
-/*****************************************************************************/
-/* Init attributes etc. of this object */
-/*****************************************************************************/
-#define GEOINIT_STRINGS 10
-static const char *initStringStrs[GEOINIT_STRINGS] = {
- "fluid",
- "bnd_no","bnd_noslip",
- "bnd_free","bnd_freeslip",
- "bnd_part","bnd_partslip",
- "inflow", "outflow", "control",
-};
-static int initStringTypes[GEOINIT_STRINGS] = {
- FGI_FLUID,
- FGI_BNDNO, FGI_BNDNO,
- FGI_BNDFREE, FGI_BNDFREE,
- FGI_BNDPART, FGI_BNDPART,
- FGI_MBNDINFLOW, FGI_MBNDOUTFLOW,
- FGI_CONTROL
-};
-void ntlGeometryObject::initialize(ntlRenderGlobals *glob)
-{
- //debugOut("ntlGeometryObject::initialize: '"<<getName()<<"' ", 10);
- // initialize only once...
- if(mIsInitialized) return;
-
- // init material, always necessary
- searchMaterial( glob->getMaterials() );
-
- this->mGeoInitId = mpAttrs->readInt("geoinitid", this->mGeoInitId,"ntlGeometryObject", "mGeoInitId", false);
- mGeoInitIntersect = mpAttrs->readInt("geoinit_intersect", mGeoInitIntersect,"ntlGeometryObject", "mGeoInitIntersect", false);
- string ginitStr = mpAttrs->readString("geoinittype", "", "ntlGeometryObject", "mGeoInitType", false);
- if(this->mGeoInitId>=0) {
- bool gotit = false;
- for(int i=0; i<GEOINIT_STRINGS; i++) {
- if(ginitStr== initStringStrs[i]) {
- gotit = true;
- mGeoInitType = initStringTypes[i];
- }
- }
-
- if(!gotit) {
- errFatal("ntlGeometryObject::initialize","Obj '"<<mName<<"', Unknown 'geoinittype' value: '"<< ginitStr <<"' ", SIMWORLD_INITERROR);
- return;
- }
- }
-
- int geoActive = mpAttrs->readInt("geoinitactive", 1,"ntlGeometryObject", "geoActive", false);
- if(!geoActive) {
- // disable geo init again...
- this->mGeoInitId = -1;
- }
- mInitialVelocity = vec2G( mpAttrs->readVec3d("initial_velocity", vec2D(mInitialVelocity),"ntlGeometryObject", "mInitialVelocity", false));
- if(getAttributeList()->exists("initial_velocity") || (!mcInitialVelocity.isInited()) ) {
- mcInitialVelocity = mpAttrs->readChannelVec3f("initial_velocity");
- }
- // always use channel
- if(!mcInitialVelocity.isInited()) { mcInitialVelocity = AnimChannel<ntlVec3Gfx>(mInitialVelocity); }
- mLocalCoordInivel = mpAttrs->readBool("geoinit_localinivel", mLocalCoordInivel,"ntlGeometryObject", "mLocalCoordInivel", false);
-
- mGeoPartSlipValue = mpAttrs->readFloat("geoinit_partslip", mGeoPartSlipValue,"ntlGeometryObject", "mGeoPartSlipValue", false);
- bool mOnlyThinInit = false; // deprecated!
- mOnlyThinInit = mpAttrs->readBool("geoinit_onlythin", mOnlyThinInit,"ntlGeometryObject", "mOnlyThinInit", false);
- if(mOnlyThinInit) mVolumeInit = VOLUMEINIT_SHELL;
- mVolumeInit = mpAttrs->readInt("geoinit_volumeinit", mVolumeInit,"ntlGeometryObject", "mVolumeInit", false);
- if((mVolumeInit<VOLUMEINIT_VOLUME)||(mVolumeInit>VOLUMEINIT_BOTH)) mVolumeInit = VOLUMEINIT_VOLUME;
-
- // moving obs correction factor
- float impactfactor=1.;
- impactfactor = (float)mpAttrs->readFloat("impactfactor", impactfactor,"ntlGeometryObject", "impactfactor", false);
- if(getAttributeList()->exists("impactfactor") || (!mcGeoImpactFactor.isInited()) ) {
- mcGeoImpactFactor = mpAttrs->readChannelSinglePrecFloat("impactfactor");
- }
-
- // override cfg types
- mVisible = mpAttrs->readBool("visible", mVisible,"ntlGeometryObject", "mVisible", false);
- mReceiveShadows = mpAttrs->readBool("recv_shad", mReceiveShadows,"ntlGeometryObject", "mReceiveShadows", false);
- mCastShadows = mpAttrs->readBool("cast_shad", mCastShadows,"ntlGeometryObject", "mCastShadows", false);
-
- // read mesh animation channels
- ntlVec3d translation(0.0);
- translation = mpAttrs->readVec3d("translation", translation,"ntlGeometryObject", "translation", false);
- if(getAttributeList()->exists("translation") || (!mcTrans.isInited()) ) {
- mcTrans = mpAttrs->readChannelVec3f("translation");
- }
- ntlVec3d rotation(0.0);
- rotation = mpAttrs->readVec3d("rotation", rotation,"ntlGeometryObject", "rotation", false);
- if(getAttributeList()->exists("rotation") || (!mcRot.isInited()) ) {
- mcRot = mpAttrs->readChannelVec3f("rotation");
- }
- ntlVec3d scale(1.0);
- scale = mpAttrs->readVec3d("scale", scale,"ntlGeometryObject", "scale", false);
- if(getAttributeList()->exists("scale") || (!mcScale.isInited()) ) {
- mcScale = mpAttrs->readChannelVec3f("scale");
- }
-
- float geoactive=1.;
- geoactive = (float)mpAttrs->readFloat("geoactive", geoactive,"ntlGeometryObject", "geoactive", false);
- if(getAttributeList()->exists("geoactive") || (!mcGeoActive.isInited()) ) {
- mcGeoActive = mpAttrs->readChannelSinglePrecFloat("geoactive");
- }
- // always use channel
- if(!mcGeoActive.isInited()) { mcGeoActive = AnimChannel<float>(geoactive); }
-
- checkIsAnimated();
-
- mIsInitialized = true;
- debMsgStd("ntlGeometryObject::initialize",DM_MSG,"GeoObj '"<<this->getName()<<"': visible="<<this->mVisible<<" gid="<<this->mGeoInitId<<" gtype="<<mGeoInitType<<","<<ginitStr<<
- " gvel="<<mInitialVelocity<<" gisect="<<mGeoInitIntersect, 10); // debug
-}
-
-/*! notify object that dump is in progress (e.g. for particles) */
-// default action - do nothing...
-void ntlGeometryObject::notifyOfDump(int dumtp, int frameNr,char *frameNrStr,string outfilename, double simtime) {
- bool debugOut=false;
- if(debugOut) debMsgStd("ntlGeometryObject::notifyOfDump",DM_MSG," dt:"<<dumtp<<" obj:"<<this->getName()<<" frame:"<<frameNrStr<<","<<frameNr<<",t"<<simtime<<" to "<<outfilename, 10); // DEBUG
-}
-
-/*****************************************************************************/
-/* Search the material for this object from the material list */
-/*****************************************************************************/
-void ntlGeometryObject::searchMaterial(vector<ntlMaterial *> *mat)
-{
- /* search the list... */
- int i=0;
- for (vector<ntlMaterial*>::iterator iter = mat->begin();
- iter != mat->end(); iter++) {
- if( mMaterialName == (*iter)->getName() ) {
- //warnMsg("ntlGeometryObject::searchMaterial","for obj '"<<getName()<<"' found - '"<<(*iter)->getName()<<"' "<<i); // DEBUG
- mpMaterial = (*iter);
- return;
- }
- i++;
- }
- errFatal("ntlGeometryObject::searchMaterial","Unknown material '"<<mMaterialName<<"' ! ", SIMWORLD_INITERROR);
- mpMaterial = new ntlMaterial();
- return;
-}
-
-/******************************************************************************
- * static add triangle function
- *****************************************************************************/
-void ntlGeometryObject::sceneAddTriangle(
- ntlVec3Gfx p1,ntlVec3Gfx p2,ntlVec3Gfx p3,
- ntlVec3Gfx pn1,ntlVec3Gfx pn2,ntlVec3Gfx pn3,
- ntlVec3Gfx trin, bool smooth,
- vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals) {
- ntlTriangle tri;
- int tempVert;
-
- if(normals->size() != vertices->size()) {
- errFatal("ntlGeometryObject::sceneAddTriangle","For '"<<this->mName<<"': Vertices and normals sizes to not match!!!",SIMWORLD_GENERICERROR);
-
- } else {
-
- vertices->push_back( p1 );
- normals->push_back( pn1 );
- tempVert = normals->size()-1;
- tri.getPoints()[0] = tempVert;
-
- vertices->push_back( p2 );
- normals->push_back( pn2 );
- tempVert = normals->size()-1;
- tri.getPoints()[1] = tempVert;
-
- vertices->push_back( p3 );
- normals->push_back( pn3 );
- tempVert = normals->size()-1;
- tri.getPoints()[2] = tempVert;
-
-
- /* init flags from ntl_ray.h */
- int flag = 0;
- if(getVisible()){ flag |= TRI_GEOMETRY; }
- if(getCastShadows() ) {
- flag |= TRI_CASTSHADOWS; }
-
- /* init geo init id */
- int geoiId = getGeoInitId();
- //if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME) && (!mIsAnimated)) {
- if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME)) {
- flag |= (1<< (geoiId+4));
- flag |= mGeoInitType;
- }
- /*errMsg("ntlScene::addTriangle","DEBUG flag="<<convertFlags2String(flag) ); */
- tri.setFlags( flag );
-
- /* triangle normal missing */
- tri.setNormal( trin );
- tri.setSmoothNormals( smooth );
- tri.setObjectId( this->mObjectId );
- triangles->push_back( tri );
- } /* normals check*/
-}
-
-void ntlGeometryObject::sceneAddTriangleNoVert(int *trips,
- ntlVec3Gfx trin, bool smooth,
- vector<ntlTriangle> *triangles) {
- ntlTriangle tri;
-
- tri.getPoints()[0] = trips[0];
- tri.getPoints()[1] = trips[1];
- tri.getPoints()[2] = trips[2];
-
- // same as normal sceneAddTriangle
-
- /* init flags from ntl_ray.h */
- int flag = 0;
- if(getVisible()){ flag |= TRI_GEOMETRY; }
- if(getCastShadows() ) {
- flag |= TRI_CASTSHADOWS; }
-
- /* init geo init id */
- int geoiId = getGeoInitId();
- if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME)) {
- flag |= (1<< (geoiId+4));
- flag |= mGeoInitType;
- }
- /*errMsg("ntlScene::addTriangle","DEBUG flag="<<convertFlags2String(flag) ); */
- tri.setFlags( flag );
-
- /* triangle normal missing */
- tri.setNormal( trin );
- tri.setSmoothNormals( smooth );
- tri.setObjectId( this->mObjectId );
- triangles->push_back( tri );
-}
-
-
-/******************************************************************************/
-/* Init channels from float arrays (for elbeem API) */
-/******************************************************************************/
-
-#define ADD_CHANNEL_VEC(dst,nvals,val) \
- vals.clear(); time.clear(); elbeemSimplifyChannelVec3(val,&nvals); \
- for(int i=0; i<(nvals); i++) { \
- vals.push_back(ntlVec3Gfx((val)[i*4+0], (val)[i*4+1],(val)[i*4+2] )); \
- time.push_back( (val)[i*4+3] ); \
- } \
- (dst) = AnimChannel< ntlVec3Gfx >(vals,time);
-
-#define ADD_CHANNEL_FLOAT(dst,nvals,val) \
- valsfloat.clear(); time.clear(); elbeemSimplifyChannelFloat(val,&nvals); \
- for(int i=0; i<(nvals); i++) { \
- valsfloat.push_back( (val)[i*2+0] ); \
- time.push_back( (val)[i*2+1] ); \
- } \
- (dst) = AnimChannel< float >(valsfloat,time);
-
-void ntlGeometryObject::initChannels(
- int nTrans, float *trans, int nRot, float *rot, int nScale, float *scale,
- int nAct, float *act, int nIvel, float *ivel,
- int nAttrFStr, float *attrFStr,
- int nAttrFRad, float *attrFRad,
- int nVelFStr, float *velFStr,
- int nVelFRad, float *velFRad
- ) {
- const bool debugInitc=true;
- if(debugInitc) { debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"nt:"<<nTrans<<" nr:"<<nRot<<" ns:"<<nScale, 10);
- debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"na:"<<nAct<<" niv:"<<nIvel<<" ", 10); }
- vector<ntlVec3Gfx> vals;
- vector<float> valsfloat;
- vector<double> time;
- if((trans)&&(nTrans>0)) { ADD_CHANNEL_VEC(mcTrans, nTrans, trans); }
- if((rot)&&(nRot>0)) { ADD_CHANNEL_VEC(mcRot, nRot, rot); }
- if((scale)&&(nScale>0)) { ADD_CHANNEL_VEC(mcScale, nScale, scale); }
- if((act)&&(nAct>0)) { ADD_CHANNEL_FLOAT(mcGeoActive, nAct, act); }
- if((ivel)&&(nIvel>0)) { ADD_CHANNEL_VEC(mcInitialVelocity, nIvel, ivel); }
-
- /* fluid control channels */
- if((attrFStr)&&(nAttrFStr>0)) { ADD_CHANNEL_FLOAT(mcAttrFStr, nAttrFStr, attrFStr); }
- if((attrFRad)&&(nAttrFRad>0)) { ADD_CHANNEL_FLOAT(mcAttrFRad, nAttrFRad, attrFRad); }
- if((velFStr)&&(nVelFStr>0)) { ADD_CHANNEL_FLOAT(mcVelFStr, nAct, velFStr); }
- if((velFRad)&&(nVelFRad>0)) { ADD_CHANNEL_FLOAT(mcVelFRad, nVelFRad, velFRad); }
-
- checkIsAnimated();
-
- if(debugInitc) {
- debMsgStd("ntlGeometryObject::initChannels",DM_MSG,getName()<<
- " nt:"<<mcTrans.accessValues().size()<<" nr:"<<mcRot.accessValues().size()<<
- " ns:"<<mcScale.accessValues().size()<<" isAnim:"<<mIsAnimated, 10); }
-
- if(debugInitc) {
- std::ostringstream ostr;
- ostr << "trans: ";
- for(size_t i=0; i<mcTrans.accessValues().size(); i++) {
- ostr<<" "<<mcTrans.accessValues()[i]<<"@"<<mcTrans.accessTimes()[i]<<" ";
- } ostr<<"; ";
- ostr<<"rot: ";
- for(size_t i=0; i<mcRot.accessValues().size(); i++) {
- ostr<<" "<<mcRot.accessValues()[i]<<"@"<<mcRot.accessTimes()[i]<<" ";
- } ostr<<"; ";
- ostr<<"scale: ";
- for(size_t i=0; i<mcScale.accessValues().size(); i++) {
- ostr<<" "<<mcScale.accessValues()[i]<<"@"<<mcScale.accessTimes()[i]<<" ";
- } ostr<<"; ";
- ostr<<"act: ";
- for(size_t i=0; i<mcGeoActive.accessValues().size(); i++) {
- ostr<<" "<<mcGeoActive.accessValues()[i]<<"@"<<mcGeoActive.accessTimes()[i]<<" ";
- } ostr<<"; ";
- ostr<<"ivel: ";
- for(size_t i=0; i<mcInitialVelocity.accessValues().size(); i++) {
- ostr<<" "<<mcInitialVelocity.accessValues()[i]<<"@"<<mcInitialVelocity.accessTimes()[i]<<" ";
- } ostr<<"; ";
- debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"Inited "<<ostr.str(),10);
- }
-}
-#undef ADD_CHANNEL
-
-
-/*****************************************************************************/
-/* apply object translation at time t*/
-/*****************************************************************************/
-void ntlGeometryObject::applyTransformation(double t, vector<ntlVec3Gfx> *verts, vector<ntlVec3Gfx> *norms, int vstart, int vend, int forceTrafo) {
- if( (mcTrans.accessValues().size()>1) // VALIDATE
- || (mcRot.accessValues().size()>1)
- || (mcScale.accessValues().size()>1)
- || (forceTrafo)
- || (!mHaveCachedMov)
- ) {
- // transformation is animated, continue
- ntlVec3Gfx pos = getTranslation(t);
- ntlVec3Gfx scale = mcScale.get(t);
- ntlVec3Gfx rot = mcRot.get(t);
- ntlMat4Gfx rotMat;
- rotMat.initRotationXYZ(rot[0],rot[1],rot[2]);
- pos += mInitialPos;
- errMsg("ntlGeometryObject::applyTransformation","obj="<<getName()<<" t"<<pos<<" r"<<rot<<" s"<<scale);
- for(int i=vstart; i<vend; i++) {
- (*verts)[i] *= scale;
- (*verts)[i] = rotMat * (*verts)[i];
- (*verts)[i] += pos;
- //if(i<10) errMsg("ntlGeometryObject::applyTransformation"," v"<<i<<"/"<<vend<<"="<<(*verts)[i]);
- }
- if(norms) {
- for(int i=vstart; i<vend; i++) {
- (*norms)[i] = rotMat * (*norms)[i];
- }
- }
- } else {
- // not animated, cached points were already returned
- errMsg ("ntlGeometryObject::applyTransformation","Object "<<getName()<<" used cached points ");
- }
-}
-
-/*! init triangle divisions */
-void ntlGeometryObject::calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTriangle> &tris, gfxReal fsTri) {
- mTriangleDivs1.resize( tris.size() );
- mTriangleDivs2.resize( tris.size() );
-
- //fsTri *= 2.; // DEBUG! , wrong init!
-
- for(size_t i=0; i<tris.size(); i++) {
- const ntlVec3Gfx p0 = verts[ tris[i].getPoints()[0] ];
- const ntlVec3Gfx p1 = verts[ tris[i].getPoints()[1] ];
- const ntlVec3Gfx p2 = verts[ tris[i].getPoints()[2] ];
- const ntlVec3Gfx side1 = p1 - p0;
- const ntlVec3Gfx side2 = p2 - p0;
- int divs1=0, divs2=0;
- if(normNoSqrt(side1) > fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); }
- if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); }
-
- mTriangleDivs1[i] = divs1;
- mTriangleDivs2[i] = divs2;
- }
-}
-
-/*! Prepare points for moving objects */
-void ntlGeometryObject::initMovingPoints(double time, gfxReal featureSize) {
- if((mMovPntsInited==featureSize)&&(!getMeshAnimated())) return;
- const bool debugMoinit=false;
-
- vector<ntlTriangle> triangles;
- vector<ntlVec3Gfx> vertices;
- vector<ntlVec3Gfx> vnormals;
- int objectId = 1;
- this->getTriangles(time, &triangles,&vertices,&vnormals,objectId);
-
- mMovPoints.clear();
- mMovNormals.clear();
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","Object "<<getName()<<" has v:"<<vertices.size()<<" t:"<<triangles.size() );
- // no points?
- if(vertices.size()<1) {
- mMaxMovPnt=-1;
- return;
- }
- ntlVec3f maxscale = channelFindMaxVf(mcScale);
- float maxpart = ABS(maxscale[0]);
- if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
- if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
- float scaleFac = 1.0/(maxpart);
- // TODO - better reinit from time to time?
- const gfxReal fsTri = featureSize*0.5 *scaleFac;
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","maxscale:"<<maxpart<<" featureSize:"<<featureSize<<" fsTri:"<<fsTri );
-
- if(mTriangleDivs1.size()!=triangles.size()) {
- calcTriangleDivs(vertices,triangles,fsTri);
- }
-
- // debug: count points to init
- /*if(debugMoinit) {
- errMsg("ntlGeometryObject::initMovingPoints","Object "<<getName()<<" estimating...");
- int countp=vertices.size()*2;
- for(size_t i=0; i<triangles.size(); i++) {
- ntlVec3Gfx p0 = vertices[ triangles[i].getPoints()[0] ];
- ntlVec3Gfx side1 = vertices[ triangles[i].getPoints()[1] ] - p0;
- ntlVec3Gfx side2 = vertices[ triangles[i].getPoints()[2] ] - p0;
- int divs1=0, divs2=0;
- if(normNoSqrt(side1) > fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); }
- if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); }
- errMsg("ntlGeometryObject::initMovingPoints","tri:"<<i<<" p:"<<p0<<" s1:"<<side1<<" s2:"<<side2<<" -> "<<divs1<<","<<divs2 );
- if(divs1+divs2 > 0) {
- for(int u=0; u<=divs1; u++) {
- for(int v=0; v<=divs2; v++) {
- const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0);
- const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0);
- if(uf+vf>1.0) continue;
- countp+=2;
- }
- }
- }
- }
- errMsg("ntlGeometryObject::initMovingPoints","Object "<<getName()<<" requires:"<<countp*2);
- } // */
-
- bool discardInflowBack = false;
- if( (mGeoInitType==FGI_MBNDINFLOW) && (mcInitialVelocity.accessValues().size()<1) ) discardInflowBack = true;
- discardInflowBack = false; // DEBUG disable for now
-
-
- // init std points
- for(size_t i=0; i<vertices.size(); i++) {
- ntlVec3Gfx p = vertices[ i ];
- ntlVec3Gfx n = vnormals[ i ];
- // discard inflow backsides
- //if( (mGeoInitType==FGI_MBNDINFLOW) && (!mIsAnimated)) {
- if(discardInflowBack) { //if( (mGeoInitType==FGI_MBNDINFLOW) && (!mIsAnimated)) {
- if(dot(mInitialVelocity,n)<0.0) continue;
- }
- mMovPoints.push_back(p);
- mMovNormals.push_back(n);
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","std"<<i<<" p"<<p<<" n"<<n<<" ");
- }
- // init points & refine...
- for(size_t i=0; i<triangles.size(); i++) {
- int *trips = triangles[i].getPoints();
- const ntlVec3Gfx p0 = vertices[ trips[0] ];
- const ntlVec3Gfx side1 = vertices[ trips[1] ] - p0;
- const ntlVec3Gfx side2 = vertices[ trips[2] ] - p0;
- int divs1=mTriangleDivs1[i], divs2=mTriangleDivs2[i];
-
- const ntlVec3Gfx trinormOrg = getNormalized(cross(side1,side2));
- const ntlVec3Gfx trinorm = trinormOrg*0.25*featureSize;
- if(discardInflowBack) {
- if(dot(mInitialVelocity,trinorm)<0.0) continue;
- }
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","Tri1 "<<vertices[trips[0]]<<","<<vertices[trips[1]]<<","<<vertices[trips[2]]<<" "<<divs1<<","<<divs2 );
- if(divs1+divs2 > 0) {
- for(int u=0; u<=divs1; u++) {
- for(int v=0; v<=divs2; v++) {
- const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0);
- const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0);
- if(uf+vf>1.0) continue;
- ntlVec3Gfx p =
- vertices[ trips[0] ] * (1.0-uf-vf)+
- vertices[ trips[1] ] * uf +
- vertices[ trips[2] ] * vf;
- //ntlVec3Gfx n = vnormals[
- //trips[0] ] * (1.0-uf-vf)+
- //vnormals[ trips[1] ]*uf +
- //vnormals[ trips[2] ]*vf;
- //normalize(n);
- // discard inflow backsides
-
- mMovPoints.push_back(p + trinorm); // NEW!?
- mMovPoints.push_back(p - trinorm);
- mMovNormals.push_back(trinormOrg);
- mMovNormals.push_back(trinormOrg);
- //errMsg("TRINORM","p"<<p<<" n"<<n<<" trin"<<trinorm);
- }
- }
- }
- }
-
- // find max point
- mMaxMovPnt = 0;
- gfxReal dist = normNoSqrt(mMovPoints[0]);
- for(size_t i=0; i<mMovPoints.size(); i++) {
- if(normNoSqrt(mMovPoints[i])>dist) {
- mMaxMovPnt = i;
- dist = normNoSqrt(mMovPoints[0]);
- }
- }
-
- if( (this->getMeshAnimated())
- || (mcTrans.accessValues().size()>1) // VALIDATE
- || (mcRot.accessValues().size()>1)
- || (mcScale.accessValues().size()>1)
- ) {
- // also do trafo...
- } else {
- mCachedMovPoints = mMovPoints;
- mCachedMovNormals = mMovNormals;
- //applyTransformation(time, &mCachedMovPoints, &mCachedMovNormals, 0, mCachedMovPoints.size(), true);
- applyTransformation(time, &mCachedMovPoints, NULL, 0, mCachedMovPoints.size(), true);
- mHaveCachedMov = true;
- debMsgStd("ntlGeometryObject::initMovingPoints",DM_MSG,"Object "<<getName()<<" cached points ", 7);
- }
-
- mMovPntsInited = featureSize;
- debMsgStd("ntlGeometryObject::initMovingPoints",DM_MSG,"Object "<<getName()<<" inited v:"<<vertices.size()<<"->"<<mMovPoints.size() , 5);
-}
-/*! Prepare points for animated objects,
- * init both sets, never used cached points
- * discardInflowBack ignore */
-void ntlGeometryObject::initMovingPointsAnim(
- double srctime, vector<ntlVec3Gfx> &srcmovPoints,
- double dsttime, vector<ntlVec3Gfx> &dstmovPoints,
- vector<ntlVec3Gfx> *dstmovNormals,
- gfxReal featureSize,
- ntlVec3Gfx geostart, ntlVec3Gfx geoend
- ) {
- const bool debugMoinit=false;
-
- vector<ntlTriangle> srctriangles;
- vector<ntlVec3Gfx> srcvertices;
- vector<ntlVec3Gfx> unused_normals;
- vector<ntlTriangle> dsttriangles;
- vector<ntlVec3Gfx> dstvertices;
- vector<ntlVec3Gfx> dstnormals;
- int objectId = 1;
- // TODO optimize? , get rid of normals?
- unused_normals.clear();
- this->getTriangles(srctime, &srctriangles,&srcvertices,&unused_normals,objectId);
- unused_normals.clear();
- this->getTriangles(dsttime, &dsttriangles,&dstvertices,&dstnormals,objectId);
-
- srcmovPoints.clear();
- dstmovPoints.clear();
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","Object "<<getName()<<" has srcv:"<<srcvertices.size()<<" srct:"<<srctriangles.size() );
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","Object "<<getName()<<" has dstv:"<<dstvertices.size()<<" dstt:"<<dsttriangles.size() );
- // no points?
- if(srcvertices.size()<1) {
- mMaxMovPnt=-1;
- return;
- }
- if((srctriangles.size() != dsttriangles.size()) ||
- (srcvertices.size() != dstvertices.size()) ) {
- errMsg("ntlGeometryObject::initMovingPointsAnim","Invalid triangle numbers! Aborting...");
- return;
- }
- ntlVec3f maxscale = channelFindMaxVf(mcScale);
- float maxpart = ABS(maxscale[0]);
- if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
- if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
- float scaleFac = 1.0/(maxpart);
- // TODO - better reinit from time to time?
- const gfxReal fsTri = featureSize*0.5 *scaleFac;
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","maxscale:"<<maxpart<<" featureSize:"<<featureSize<<" fsTri:"<<fsTri );
-
- if(mTriangleDivs1.size()!=srctriangles.size()) {
- calcTriangleDivs(srcvertices,srctriangles,fsTri);
- }
-
-
- // init std points
- for(size_t i=0; i<srcvertices.size(); i++) {
- srcmovPoints.push_back(srcvertices[i]);
- //srcmovNormals.push_back(srcnormals[i]);
- }
- for(size_t i=0; i<dstvertices.size(); i++) {
- dstmovPoints.push_back(dstvertices[i]);
- if(dstmovNormals) (*dstmovNormals).push_back(dstnormals[i]);
- }
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","stats src:"<<srcmovPoints.size()<<" dst:"<<dstmovPoints.size()<<" " );
- // init points & refine...
- for(size_t i=0; i<srctriangles.size(); i++) {
- const int divs1=mTriangleDivs1[i];
- const int divs2=mTriangleDivs2[i];
- if(divs1+divs2 > 0) {
- int *srctrips = srctriangles[i].getPoints();
- int *dsttrips = dsttriangles[i].getPoints();
- const ntlVec3Gfx srcp0 = srcvertices[ srctrips[0] ];
- const ntlVec3Gfx srcside1 = srcvertices[ srctrips[1] ] - srcp0;
- const ntlVec3Gfx srcside2 = srcvertices[ srctrips[2] ] - srcp0;
- const ntlVec3Gfx dstp0 = dstvertices[ dsttrips[0] ];
- const ntlVec3Gfx dstside1 = dstvertices[ dsttrips[1] ] - dstp0;
- const ntlVec3Gfx dstside2 = dstvertices[ dsttrips[2] ] - dstp0;
- const ntlVec3Gfx src_trinorm = getNormalized(cross(srcside1,srcside2))*0.25*featureSize;
- const ntlVec3Gfx dst_trinormOrg = getNormalized(cross(dstside1,dstside2));
- const ntlVec3Gfx dst_trinorm = dst_trinormOrg *0.25*featureSize;
- //errMsg("ntlGeometryObject::initMovingPointsAnim","Tri1 "<<srcvertices[srctrips[0]]<<","<<srcvertices[srctrips[1]]<<","<<srcvertices[srctrips[2]]<<" "<<divs1<<","<<divs2 );
- for(int u=0; u<=divs1; u++) {
- for(int v=0; v<=divs2; v++) {
- const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0);
- const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0);
- if(uf+vf>1.0) continue;
- ntlVec3Gfx srcp =
- srcvertices[ srctrips[0] ] * (1.0-uf-vf)+
- srcvertices[ srctrips[1] ] * uf +
- srcvertices[ srctrips[2] ] * vf;
- ntlVec3Gfx dstp =
- dstvertices[ dsttrips[0] ] * (1.0-uf-vf)+
- dstvertices[ dsttrips[1] ] * uf +
- dstvertices[ dsttrips[2] ] * vf;
-
- // cutoffDomain
- if((srcp[0]<geostart[0]) && (dstp[0]<geostart[0])) continue;
- if((srcp[1]<geostart[1]) && (dstp[1]<geostart[1])) continue;
- if((srcp[2]<geostart[2]) && (dstp[2]<geostart[2])) continue;
- if((srcp[0]>geoend[0] ) && (dstp[0]>geoend[0] )) continue;
- if((srcp[1]>geoend[1] ) && (dstp[1]>geoend[1] )) continue;
- if((srcp[2]>geoend[2] ) && (dstp[2]>geoend[2] )) continue;
-
- srcmovPoints.push_back(srcp+src_trinorm); // SURFENHTEST
- srcmovPoints.push_back(srcp-src_trinorm);
-
- dstmovPoints.push_back(dstp+dst_trinorm); // SURFENHTEST
- dstmovPoints.push_back(dstp-dst_trinorm);
- if(dstmovNormals) {
- (*dstmovNormals).push_back(dst_trinormOrg);
- (*dstmovNormals).push_back(dst_trinormOrg); }
- }
- }
- }
- }
-
- // find max point not necessary
- debMsgStd("ntlGeometryObject::initMovingPointsAnim",DM_MSG,"Object "<<getName()<<" inited v:"<<srcvertices.size()<<"->"<<srcmovPoints.size()<<","<<dstmovPoints.size() , 5);
-}
-
-/*! Prepare points for moving objects */
-void ntlGeometryObject::getMovingPoints(vector<ntlVec3Gfx> &ret, vector<ntlVec3Gfx> *norms) {
- if(mHaveCachedMov) {
- ret = mCachedMovPoints;
- if(norms) {
- *norms = mCachedMovNormals;
- //errMsg("ntlGeometryObject","getMovingPoints - Normals currently unused!");
- }
- //errMsg ("ntlGeometryObject::getMovingPoints","Object "<<getName()<<" used cached points "); // DEBUG
- return;
- }
-
- ret = mMovPoints;
- if(norms) {
- //errMsg("ntlGeometryObject","getMovingPoints - Normals currently unused!");
- *norms = mMovNormals;
- }
-}
-
-
-/*! Calculate max. velocity on object from t1 to t2 */
-ntlVec3Gfx ntlGeometryObject::calculateMaxVel(double t1, double t2) {
- ntlVec3Gfx vel(0.);
- if(mMaxMovPnt<0) return vel;
-
- vector<ntlVec3Gfx> verts1,verts2;
- verts1.push_back(mMovPoints[mMaxMovPnt]);
- verts2 = verts1;
- applyTransformation(t1,&verts1,NULL, 0,verts1.size(), true);
- applyTransformation(t2,&verts2,NULL, 0,verts2.size(), true);
-
- vel = (verts2[0]-verts1[0]); // /(t2-t1);
- //errMsg("ntlGeometryObject::calculateMaxVel","t1="<<t1<<" t2="<<t2<<" p1="<<verts1[0]<<" p2="<<verts2[0]<<" v="<<vel);
- return vel;
-}
-
-/*! get translation at time t*/
-ntlVec3Gfx ntlGeometryObject::getTranslation(double t) {
- ntlVec3Gfx pos = mcTrans.get(t);
- // DEBUG CP_FORCECIRCLEINIT 1
- /*if(
- (mName.compare(string("0__ts1"))==0) ||
- (mName.compare(string("1__ts1"))==0) ||
- (mName.compare(string("2__ts1"))==0) ||
- (mName.compare(string("3__ts1"))==0) ||
- (mName.compare(string("4__ts1"))==0) ||
- (mName.compare(string("5__ts1"))==0) ||
- (mName.compare(string("6__ts1"))==0) ||
- (mName.compare(string("7__ts1"))==0) ||
- (mName.compare(string("8__ts1"))==0) ||
- (mName.compare(string("9__ts1"))==0)
- ) { int j=mName[0]-'0';
- ntlVec3Gfx ppos(0.); { // DEBUG
- const float tscale=10.;
- const float tprevo = 0.33;
- const ntlVec3Gfx toff(50,50,0);
- const ntlVec3Gfx oscale(30,30,0);
- ppos[0] = cos(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[0] + toff[0];
- ppos[1] = -sin(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[1] + toff[1];
- ppos[2] = toff[2]; } // DEBUG
- pos = ppos;
- pos[2] = 0.15;
- }
- // DEBUG CP_FORCECIRCLEINIT 1 */
- return pos;
-}
-/*! get active flag time t*/
-float ntlGeometryObject::getGeoActive(double t) {
- float act = (mcGeoActive.get(t) >= 1.) ? 1.0 : 0.0;
- return act;
-}
-
-void ntlGeometryObject::setInitialVelocity(ntlVec3Gfx set) {
- mInitialVelocity=set;
- mcInitialVelocity = AnimChannel<ntlVec3Gfx>(set);
-}
-ntlVec3Gfx ntlGeometryObject::getInitialVelocity(double t) {
- ntlVec3Gfx v = mcInitialVelocity.get(t); //return mInitialVelocity;
- if(!mLocalCoordInivel) return v;
-
- ntlVec3Gfx rot = mcRot.get(t);
- ntlMat4Gfx rotMat;
- rotMat.initRotationXYZ(rot[0],rot[1],rot[2]);
- v = rotMat * v;
- return v;
-}
-
-
diff --git a/intern/elbeem/intern/ntl_geometryobject.h b/intern/elbeem/intern/ntl_geometryobject.h
deleted file mode 100644
index 7e5e90d6493..00000000000
--- a/intern/elbeem/intern/ntl_geometryobject.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * a geometry object
- * all other geometry objects are derived from this one
- *
- *****************************************************************************/
-#ifndef NTL_GEOMETRYOBJECT_H
-#define NTL_GEOMETRYOBJECT_H
-
-#include "ntl_geometryclass.h"
-#include "ntl_lighting.h"
-#include "ntl_ray.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlRenderGlobals;
-class ntlTriangle;
-
-#define DUMP_FULLGEOMETRY 1
-#define DUMP_PARTIAL 2
-
-#define VOLUMEINIT_VOLUME 1
-#define VOLUMEINIT_SHELL 2
-#define VOLUMEINIT_BOTH (VOLUMEINIT_SHELL|VOLUMEINIT_VOLUME)
-
-class ntlGeometryObject : public ntlGeometryClass
-{
-
- public:
- //! Default constructor
- ntlGeometryObject();
- //! Default destructor
- virtual ~ntlGeometryObject();
-
- //! Return type id
- virtual int getTypeId() { return GEOCLASSTID_OBJECT; }
-
- /*! Init attributes etc. of this object */
- virtual void initialize(ntlRenderGlobals *glob);
-
- /*! Get the triangles from this object */
- virtual void getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId ) = 0;
-
- /*! notify object that dump is in progress (e.g. for particles) */
- virtual void notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime);
-
- /*! Search the material for this object from the material list */
- void searchMaterial(vector<ntlMaterial *> *mat);
-
- /* Acces methods */
- /*! Set the property of this object */
- inline void setMaterial(ntlMaterial *p) { mpMaterial = p; }
- /*! Get the surface property of this object */
- inline ntlMaterial *getMaterial( void ) { return mpMaterial; }
- /*! Set the object property name */
- inline void setMaterialName(string set) { mMaterialName = set; }
- /*! Get the object property name */
- inline string getMaterialName( void ) { return mMaterialName; }
-
- /*! Sets the receive shadows attribute */
- inline void setReceiveShadows(int set) { mReceiveShadows=set; }
- /*! Returns the receive shadows attribute */
- inline int getReceiveShadows() const { return mReceiveShadows; }
-
- /*! Sets the cast shadows attribute */
- inline void setCastShadows(int set) { mCastShadows=set; }
- /*! Returns the cast shadows attribute */
- inline int getCastShadows() const { return mCastShadows; }
-
- /*! Returns the geo init typ */
- inline void setGeoInitType(int set) { mGeoInitType=set; }
- /*! Returns the geo init typ */
- inline int getGeoInitType() const { return mGeoInitType; }
-
- /*! Set/get the intersect init flag */
- inline bool getGeoInitIntersect() const { return mGeoInitIntersect; }
- inline void setGeoInitIntersect(bool set) { mGeoInitIntersect=set; }
-
- /*! Set/get the part slip value*/
- inline float getGeoPartSlipValue() const { return mGeoPartSlipValue; }
- inline void setGeoPartSlipValue(float set) { mGeoPartSlipValue=set; }
-
- /*! Set/get the impact corr factor channel */
- inline float getGeoImpactFactor(double t) { return mcGeoImpactFactor.get(t); }
- inline void setGeoImpactFactor(float set) { mcGeoImpactFactor = AnimChannel<float>(set); }
-
- /*! Set/get the part slip value*/
- inline int getVolumeInit() const { return mVolumeInit; }
- inline void setVolumeInit(int set) { mVolumeInit=set; }
-
- /*! Set/get the cast initial veocity attribute */
- void setInitialVelocity(ntlVec3Gfx set);
- ntlVec3Gfx getInitialVelocity(double t);
-
- /*! Set/get the local inivel coords flag */
- inline bool getLocalCoordInivel() const { return mLocalCoordInivel; }
- inline void setLocalCoordInivel(bool set) { mLocalCoordInivel=set; }
-
- /****************************************/
- /* fluid control features */
- /****************************************/
- /*! Set/get the particle control set attract force strength */
- inline float getCpsTimeStart() const { return mCpsTimeStart; }
- inline void setCpsTimeStart(float set) { mCpsTimeStart=set; }
-
- /*! Set/get the particle control set attract force strength */
- inline float getCpsTimeEnd() const { return mCpsTimeEnd; }
- inline void setCpsTimeEnd(float set) { mCpsTimeEnd=set; }
-
- /*! Set/get the particle control set quality */
- inline float getCpsQuality() const { return mCpsQuality; }
- inline void setCpsQuality(float set) { mCpsQuality=set; }
-
- inline AnimChannel<float> getCpsAttrFStr() const { return mcAttrFStr; }
- inline AnimChannel<float> getCpsAttrFRad() const { return mcAttrFRad; }
- inline AnimChannel<float> getCpsVelFStr() const { return mcVelFStr; }
- inline AnimChannel<float> getCpsVelFRad() const { return mcVelFRad; }
-
- /****************************************/
-
- /*! Init channels from float arrays (for elbeem API) */
- void initChannels(
- int nTrans, float *trans, int nRot, float *rot, int nScale, float *scale,
- int nAct, float *act, int nIvel, float *ivel,
- int nAttrFStr, float *attrFStr,
- int nAttrFRad, float *attrFRad,
- int nVelFStr, float *velFStr,
- int nVelFRad, float *velFRad
- );
-
- /*! is the object animated? */
- inline bool getIsAnimated() const { return mIsAnimated; }
- /*! init object anim flag */
- bool checkIsAnimated();
- /*! is the mesh animated? */
- virtual bool getMeshAnimated();
- /*! init triangle divisions */
- virtual void calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTriangle> &tris, gfxReal fsTri);
-
- /*! apply object translation at time t*/
- void applyTransformation(double t, vector<ntlVec3Gfx> *verts, vector<ntlVec3Gfx> *norms, int vstart, int vend, int forceTrafo);
-
- /*! Prepare points for moving objects */
- void initMovingPoints(double time, gfxReal featureSize);
- /*! Prepare points for animated objects */
- void initMovingPointsAnim(
- double srctime, vector<ntlVec3Gfx> &srcpoints,
- double dsttime, vector<ntlVec3Gfx> &dstpoints,
- vector<ntlVec3Gfx> *dstnormals,
- gfxReal featureSize, ntlVec3Gfx geostart, ntlVec3Gfx geoend );
- /*! Prepare points for moving objects (copy into ret) */
- void getMovingPoints(vector<ntlVec3Gfx> &ret, vector<ntlVec3Gfx> *norms = NULL);
- /*! Calculate max. velocity on object from t1 to t2 */
- ntlVec3Gfx calculateMaxVel(double t1, double t2);
- /*! get translation at time t*/
- ntlVec3Gfx getTranslation(double t);
- /*! get active flag time t*/
- float getGeoActive(double t);
-
- /*! add triangle to scene and init flags */
- // helper function for getTriangles
- void sceneAddTriangle(
- ntlVec3Gfx p1,ntlVec3Gfx p2,ntlVec3Gfx p3,
- ntlVec3Gfx pn1,ntlVec3Gfx pn2,ntlVec3Gfx pn3,
- ntlVec3Gfx trin, bool smooth,
- vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *vertNormals);
- void sceneAddTriangleNoVert(int *trips,
- ntlVec3Gfx trin, bool smooth,
- vector<ntlTriangle> *triangles);
-
- protected:
-
- /* initialized for scene? */
- bool mIsInitialized;
-
- /*! Point to a property object describing the surface of this object */
- ntlMaterial *mpMaterial;
-
- /*! Name of the surcace property */
- string mMaterialName;
-
- /*! Cast shadows on/off */
- int mCastShadows;
- /*! REceive shadows on/off */
- int mReceiveShadows;
-
- /* fluid init data */
- /*! fluid object type (fluid, obstacle, accelerator etc.) */
- int mGeoInitType;
- /*! initial velocity for fluid objects */
- ntlVec3Gfx mInitialVelocity;
- AnimChannel<ntlVec3Gfx> mcInitialVelocity;
- /*! use object local inflow? */
- bool mLocalCoordInivel;
- /*! perform more accurate intersecting geo init for this object? */
- bool mGeoInitIntersect;
- /*! part slip bc value */
- float mGeoPartSlipValue;
- /*! obstacle impact correction factor */
- AnimChannel<float> mcGeoImpactFactor;
- /*! only init as thin object, dont fill? */
- int mVolumeInit;
-
- /*! initial offset for rot/scale */
- ntlVec3Gfx mInitialPos;
- /*! animated channels for postition, rotation and scale */
- AnimChannel<ntlVec3Gfx> mcTrans, mcRot, mcScale;
- /*! easy check for animation */
- bool mIsAnimated;
-
- /*! moving point/normal storage */
- vector<ntlVec3Gfx> mMovPoints;
- vector<ntlVec3Gfx> mMovNormals;
- /*! cached points for non moving objects/timeslots */
- bool mHaveCachedMov;
- vector<ntlVec3Gfx> mCachedMovPoints;
- vector<ntlVec3Gfx> mCachedMovNormals;
- /*! precomputed triangle divisions */
- vector<int> mTriangleDivs1,mTriangleDivs2;
- /*! inited? */
- float mMovPntsInited;
- /*! point with max. distance from center */
- int mMaxMovPnt;
-
- /*! animated channels for in/outflow on/off */
- AnimChannel<float> mcGeoActive;
-
- /* fluid control settings */
- float mCpsTimeStart;
- float mCpsTimeEnd;
- float mCpsQuality;
- AnimChannel<float> mcAttrFStr, mcAttrFRad, mcVelFStr, mcVelFRad;
-
- public:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlGeometryObject")
-#endif
-};
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_geometryshader.h b/intern/elbeem/intern/ntl_geometryshader.h
deleted file mode 100644
index 5400e05a27a..00000000000
--- a/intern/elbeem/intern/ntl_geometryshader.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Interface for a geometry shader
- *
- *****************************************************************************/
-#ifndef NTL_GEOMETRYSHADER_H
-#define NTL_GEOMETRYSHADER_H
-
-#include "ntl_geometryclass.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlGeometryObject;
-class ntlRenderGlobals;
-
-class ntlGeometryShader :
- public ntlGeometryClass
-{
-
- public:
-
- //! Default constructor
- inline ntlGeometryShader() :
- ntlGeometryClass(), mOutFilename("")
- {};
- //! Default destructor
- virtual ~ntlGeometryShader() {};
-
- //! Return type id
- virtual int getTypeId() { return GEOCLASSTID_SHADER; }
-
- /*! Initialize object, should return !=0 upon error */
- virtual int initializeShader() = 0;
-
- /*! Do further object initialization after all geometry has been constructed, should return !=0 upon error */
- virtual int postGeoConstrInit(ntlRenderGlobals *glob) { glob=NULL; /*unused*/ return 0; };
-
- /*! Get start iterator for all objects */
- virtual vector<ntlGeometryObject *>::iterator getObjectsBegin() { return mObjects.begin(); }
- /*! Get end iterator for all objects */
- virtual vector<ntlGeometryObject *>::iterator getObjectsEnd() { return mObjects.end(); }
-
- /*! notify object that dump is in progress (e.g. for field dump) */
- virtual void notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) = 0;
-
- /*! get output filename, returns global render outfile if empty */
- string getOutFilename( void ) { return mOutFilename; }
-
- protected:
-
- //! vector for the objects
- vector<ntlGeometryObject *> mObjects;
-
-
- /*! surface output name for this simulation */
- string mOutFilename;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlGeometryShader")
-#endif
-};
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_lighting.cpp b/intern/elbeem/intern/ntl_lighting.cpp
deleted file mode 100644
index aef06f8f490..00000000000
--- a/intern/elbeem/intern/ntl_lighting.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * a light object
- *
- *****************************************************************************/
-
-
-#include "ntl_lighting.h"
-#include "ntl_ray.h"
-#include "ntl_world.h"
-
-
-/******************************************************************************
- * Default Constructor
- *****************************************************************************/
-ntlLightObject::ntlLightObject(ntlRenderGlobals *glob) :
- mpGlob( glob ),
- mActive( 1 ),
- mCastShadows( 1 ),
- mcColor( ntlColor(1.0) ),
- mvPosition( ntlVec3Gfx(0.0) )
-{
- // nothing to do...
-}
-
-
-/******************************************************************************
- * Constructor with parameters
- *****************************************************************************/
-ntlLightObject::ntlLightObject(ntlRenderGlobals *glob, const ntlColor& col) :
- mpGlob( glob ),
- mActive( 1 ),
- mCastShadows( 1 ),
- mcColor( col )
-{
- // nothing to do...
-}
-
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlLightObject::~ntlLightObject()
-{
- // nothing to do...
-}
-
-
-
-/******************************************************************************
- * Determine color contribution of a lightsource (Phong model)
- * Specular part is returned in seperate parameter and added later
- *****************************************************************************/
-const ntlColor
-ntlLightObject::getShadedColor(const ntlRay &reflectedRay, const ntlVec3Gfx lightDir,
- ntlMaterial *surf, ntlColor &highlight) const
-{
- gfxReal ldot = dot(lightDir, reflectedRay.getNormal()); /* equals cos( angle(L,N) ) */
- ntlColor reflected_color = ntlColor(0.0); /* adds up to total reflected color */
- if(mpGlob->getDebugOut() > 5) errorOut("Lighting dir:"<<lightDir<<" norm:"<<reflectedRay.getNormal()<<" "<<ldot );
-
- /* lambertian reflection model */
- if (ldot > 0.0) {
- //ldot *= -1.0;
- reflected_color += surf->getDiffuseRefl() * (getColor() * ldot );
-
- /* specular part */
- /* specular reflection only makes sense, when the light is facing the surface,
- as the highlight is supposed to be a reflection of the lightsource, it cannot
- be reflected on surfaces with ldot<=0, as this means the arc between light
- and normal is more than 90 degrees. If this isn't done, ugly moiree patterns appear
- in the highlights, and refractions have strange patterns due to highlights on the
- inside of the surface */
- gfxReal spec = dot(reflectedRay.getDirection(), lightDir); // equals cos( angle(R,L) )
- if((spec > 0.0) && (surf->getSpecular()>0)) {
- spec = pow( spec, surf->getSpecExponent() ); /* phong exponent */
- highlight += getColor() * surf->getSpecular() * spec;
- //errorOut( " "<< surf->getName() <<" S "<<highlight<<" "<<spec<<" "<<surf->getSpecular()<<" "<<surf->getSpecExponent() );
- }
-
- }
-
- return ntlColor(reflected_color);
-}
-
-
-// omni light implementation
-
-
-/******************************************************************************
- *! prepare shadow maps if necessary
- *****************************************************************************/
-void ntlLightObject::prepare( bool doCaustics )
-{
- doCaustics = false; // unused
- if(!mActive) { return; }
-}
-
-
-/******************************************************************************
- * Illuminate the given point on an object
- *****************************************************************************/
-ntlColor ntlLightObject::illuminatePoint(ntlRay &reflectedRay, ntlGeometryObject *closest,
- ntlColor &highlight )
-{
- /* is this light active? */
- if(!mActive) { return ntlColor(0.0); }
-
- gfxReal visibility = 1.0; // how much of light is visible
- ntlVec3Gfx intersectionPos = reflectedRay.getOrigin();
- ntlColor current_color = ntlColor(0.0);
- ntlMaterial *clossurf = closest->getMaterial();
-
- ntlVec3Gfx lightDir = (mvPosition - intersectionPos);
- gfxReal lightDirNorm = normalize(lightDir);
-
- // where is the lightsource ?
- ntlRay rayOfLight(intersectionPos, lightDir, 0, 1.0, mpGlob );
-
- if( (1) && (mCastShadows)&&(closest->getReceiveShadows()) ) {
- ntlTriangle *tri;
- ntlVec3Gfx triNormal;
- gfxReal trit;
- mpGlob->getRenderScene()->intersectScene(rayOfLight, trit, triNormal, tri, TRI_CASTSHADOWS);
- if(( trit>0 )&&( trit<lightDirNorm )) visibility = 0.0;
- if(mpGlob->getDebugOut() > 5) errorOut("Omni lighting with "<<visibility );
- }
-
- /* is light partly visible ? */
-//? visibility=1.;
- if (visibility>0.0) {
- ntlColor highTemp(0.0); // temporary highlight color to multiply highTemp with offFac
- current_color = getShadedColor(reflectedRay, lightDir, clossurf, highTemp) * visibility;
- highlight += highTemp * visibility;
- if(mpGlob->getDebugOut() > 5) errorOut("Omni lighting color "<<current_color );
- }
- return current_color;
-}
-
-
-
-/******************************************************************************
- * Default constructor
- *****************************************************************************/
-ntlMaterial::ntlMaterial( void ) :
- mName( "default" ),
- mDiffuseRefl(0.5,0.5,0.5), mAmbientRefl(0.0,0.0,0.0),
- mSpecular(0.0), mSpecExponent(0.0), mMirror(0.0),
- mTransparence(0.0), mRefracIndex(1.05), mTransAdditive(0.0), mTransAttCol(0.0),
- mFresnel( 0 ) {
- // just do default init...
-}
-
-
-
-/******************************************************************************
- * Init constructor
- *****************************************************************************/
-ntlMaterial::ntlMaterial( string name,
- const ntlColor& Ref, const ntlColor& Amb,
- gfxReal Spec, gfxReal SpecEx, gfxReal Mirr,
- gfxReal Trans, gfxReal Refrac, gfxReal TAdd,
- const ntlColor& Att, int fres)
-{
- mName = name;
- mDiffuseRefl = Ref;
- mAmbientRefl = Amb;
- mSpecular = Spec;
- mSpecExponent = SpecEx;
- mMirror = Mirr;
- mTransparence = Trans;
- mRefracIndex = Refrac;
- mTransAdditive = TAdd;
- mTransAttCol = Att;
- mFresnel = fres;
-}
-
diff --git a/intern/elbeem/intern/ntl_lighting.h b/intern/elbeem/intern/ntl_lighting.h
deleted file mode 100644
index b046ccfae57..00000000000
--- a/intern/elbeem/intern/ntl_lighting.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * a light object
- * default omni light implementation
- *
- *****************************************************************************/
-#ifndef NTL_LIGHTING_H
-#define NTL_LIGHTING_H
-
-#include "ntl_vector3dim.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlMaterial;
-class ntlRay;
-class ntlRenderGlobals;
-class ntlGeometryObject;
-
-
-
-/* shadow map directions */
-#define LSM_RIGHT 0
-#define LSM_LEFT 1
-#define LSM_UP 2
-#define LSM_DOWN 3
-#define LSM_FRONT 4
-#define LSM_BACK 5
-
-/*! Basic object for lights, all other light are derived from this one */
-class ntlLightObject
-{
-public:
- /* CONSTRUCTORS */
- /*! Default constructor */
- ntlLightObject(ntlRenderGlobals *glob);
- /*! Constructor with parameters */
- ntlLightObject(ntlRenderGlobals *glob, const ntlColor& col);
- /*! Destructor */
- virtual ~ntlLightObject();
-
- /*! prepare light for rendering (for example shadow maps) */
- virtual void prepare( bool );
-
- /*! do the illumination... */
- virtual ntlColor illuminatePoint(ntlRay &reflectedRay,
- ntlGeometryObject *closest,
- ntlColor &highlight);
- /*! shade the point */
- const ntlColor
- getShadedColor(const ntlRay &reflectedray, ntlVec3Gfx lightDir,
- ntlMaterial *surf, ntlColor &highlight) const;
-
-
- /* access methods */
- /*! Access the active flag */
- inline void setActive(bool set) { mActive = set; }
- inline bool getActive() const { return mActive; }
- /*! Access the shadow flag */
- inline void setCastShadows(bool set) { mCastShadows = set; }
- inline bool getCastShadows() const { return mCastShadows; }
- /*! Access the light color */
- inline void setColor(ntlColor set) { mcColor = set; }
- inline ntlColor getColor() const { return mcColor; }
-
- /*! Access the omni light position */
- void setPosition(ntlVec3Gfx set) { mvPosition = set; }
- ntlVec3Gfx getPosition() const { return mvPosition; }
-
-
-protected:
- /*! render globals */
- ntlRenderGlobals *mpGlob;
-
- /*! is this light acitve? */
- bool mActive;
-
- /*! does it cast shadows? */
- bool mCastShadows;
-
- /*! color of this light */
- ntlColor mcColor;
-
- /*! light position */
- ntlVec3Gfx mvPosition;
-
-private:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlLightObject")
-#endif
-};
-
-
-//! Properties of an geo object, describing the reflection properties of the surface
-class ntlMaterial
-{
-public:
- // CONSTRUCTORS
- //! Default constructor
- ntlMaterial( void );
- //! Constructor with parameters
- /*! Sets reflectance, ambient reflection, specular intensity
- * specular exponent, mirror intensity
- * transparency, refraction index */
- ntlMaterial( string name,
- const ntlColor& Ref, const ntlColor& Amb,
- gfxReal Spec, gfxReal Exp, gfxReal Mirror,
- gfxReal Trans, gfxReal Refrac, gfxReal TAdd,
- const ntlColor& Att, int fres);
- //! Desctructor
- ~ntlMaterial() {};
-
- //! Calculate reflectance and refratance from Fresnel's law
- inline void calculateFresnel(const ntlVec3Gfx &dir, const ntlVec3Gfx &normal, gfxReal refIndex,
- gfxReal &refl, gfxReal &trans );
-
-protected:
-
- /* name of the material */
- string mName;
-
- //! Vector for reflectance of each color component (used in shade() of ray object)
- ntlColor mDiffuseRefl;
- //! Ambient reflectance
- ntlColor mAmbientRefl;
- //! Specular reflection intensity
- gfxReal mSpecular;
- //! Specular phong exponent
- gfxReal mSpecExponent;
- //! Mirror intensity
- gfxReal mMirror;
-
- //! Transparence
- gfxReal mTransparence;
- //! Refraction index, nu(Air) is assumed 1
- gfxReal mRefracIndex;
- //! Should transparence be additive?
- gfxReal mTransAdditive;
- //! Color dependent transparency attentuation factors (negative logarithm stored)
- ntlColor mTransAttCol;
- //! Should the transparence and reflectivity be determined by fresnel?
- int mFresnel;
-
-
-public:
- // access methods
-
- //! Returns the material name
- inline string getName() { return mName; }
- //! Returns the reflectance
- inline ntlColor getDiffuseRefl() const { return ntlColor(mDiffuseRefl); }
- //! Returns the ambience
- inline ntlColor getAmbientRefl() const { return ntlColor(mAmbientRefl); }
- //! Returns the specular component
- inline gfxReal getSpecular() const { return mSpecular; }
- //! Returns the specular exponent component
- inline gfxReal getSpecExponent() const { return mSpecExponent; }
- //! Returns the mirror component
- inline gfxReal getMirror() const { return mMirror; }
- //! Returns the transparence component
- inline gfxReal getTransparence() const { return mTransparence; }
- //! Returns the refraction index component
- inline gfxReal getRefracIndex() const { return mRefracIndex; }
- //! Returns the transparency additive factor component
- inline gfxReal getTransAdditive() const { return mTransAdditive; }
- //! Returns the transparency attentuation
- inline ntlColor getTransAttCol() const { return mTransAttCol; }
- //! Get Fresnel flag
- inline int getFresnel( void ) { return mFresnel; }
-
-
-
- //! Returns the mat name
- inline void setName(string set) { mName = set; }
- //! Returns the reflectance
- inline void setDiffuseRefl(ntlColor set) { mDiffuseRefl=set; }
- //! Returns the ambience
- inline void setAmbientRefl(ntlColor set) { mAmbientRefl=set; }
- //! Returns the specular component
- inline void setSpecular(gfxReal set) { mSpecular=set; }
- //! Returns the specular exponent component
- inline void setSpecExponent(gfxReal set) { mSpecExponent=set; }
- //! Returns the mirror component
- inline void setMirror(gfxReal set) { mMirror=set; }
- //! Returns the transparence component
- inline void setTransparence(gfxReal set) { mTransparence=set; }
- //! Returns the refraction index component
- inline void setRefracIndex(gfxReal set) { mRefracIndex=set; }
- //! Returns the transparency additive factor component
- inline void setTransAdditive(gfxReal set) { mTransAdditive=set; }
- //! Returns the transparency attentuation
- inline void setTransAttCol(ntlColor set) {
- ntlColor setlog = ntlColor( -log(set[0]), -log(set[1]), -log(set[2]) );
- mTransAttCol=setlog; }
- //! Set Fresnel on/off
- inline void setFresnel(int set) { mFresnel = set; }
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlMaterial")
-#endif
-};
-
-
-/******************************************************************************
- * Macro to define the default surface properties for a newly created object
- *****************************************************************************/
-#define GET_GLOBAL_DEFAULT_MATERIAL new ntlMaterial( "default",\
- ntlColor( 0.5 ), ntlColor(0.0), \
- 1.0, 5.0, 0.0, \
- /*0.0 test:*/ 0.5 , 1.0, 0.0, \
- ntlColor( 0.0 ), 0 );
-
-
-
-/******************************************************************************
- * Calculate reflectance and refratance from Fresnel's law
- * cf. Glassner p. 46
- *****************************************************************************/
-inline void
-ntlMaterial::calculateFresnel(const ntlVec3Gfx &dir, const ntlVec3Gfx &normal, gfxReal refIndex,
- gfxReal &refl, gfxReal &trans)
-{
- gfxReal c = -dot(dir, normal);
- if(c<0) {
- refl = 0.0; trans = 0.0; return;
- //c = 0.0;
- }
-
- gfxReal r0 = ((refIndex-1.0)*(refIndex-1.0)) /
- ((refIndex+1.0)*(refIndex+1.0));
- gfxReal omc = (1.0-c);
- gfxReal r =r0 + (1.0 - r0) * omc*omc*omc*omc*omc;
-
- //mMirror = r;
- //mTransparence = (1.0 - r);
- refl = r;
- trans = (1.0 - r);
- //errorOut(" fres ");
-}
-
-
-#endif
-
-
diff --git a/intern/elbeem/intern/ntl_matrices.h b/intern/elbeem/intern/ntl_matrices.h
deleted file mode 100644
index d3551f1a682..00000000000
--- a/intern/elbeem/intern/ntl_matrices.h
+++ /dev/null
@@ -1,790 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Basic matrix utility include file
- *
- *****************************************************************************/
-#ifndef NTL_MATRICES_H
-
-#include "ntl_vector3dim.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-// The basic vector class
-template<class Scalar>
-class ntlMatrix4x4
-{
-public:
- // Constructor
- inline ntlMatrix4x4(void );
- // Copy-Constructor
- inline ntlMatrix4x4(const ntlMatrix4x4<Scalar> &v );
- // construct a vector from one Scalar
- inline ntlMatrix4x4(Scalar);
- // construct a vector from three Scalars
- inline ntlMatrix4x4(Scalar, Scalar, Scalar);
-
- // Assignment operator
- inline const ntlMatrix4x4<Scalar>& operator= (const ntlMatrix4x4<Scalar>& v);
- // Assignment operator
- inline const ntlMatrix4x4<Scalar>& operator= (Scalar s);
- // Assign and add operator
- inline const ntlMatrix4x4<Scalar>& operator+= (const ntlMatrix4x4<Scalar>& v);
- // Assign and add operator
- inline const ntlMatrix4x4<Scalar>& operator+= (Scalar s);
- // Assign and sub operator
- inline const ntlMatrix4x4<Scalar>& operator-= (const ntlMatrix4x4<Scalar>& v);
- // Assign and sub operator
- inline const ntlMatrix4x4<Scalar>& operator-= (Scalar s);
- // Assign and mult operator
- inline const ntlMatrix4x4<Scalar>& operator*= (const ntlMatrix4x4<Scalar>& v);
- // Assign and mult operator
- inline const ntlMatrix4x4<Scalar>& operator*= (Scalar s);
- // Assign and div operator
- inline const ntlMatrix4x4<Scalar>& operator/= (const ntlMatrix4x4<Scalar>& v);
- // Assign and div operator
- inline const ntlMatrix4x4<Scalar>& operator/= (Scalar s);
-
-
- // unary operator
- inline ntlMatrix4x4<Scalar> operator- () const;
-
- // binary operator add
- inline ntlMatrix4x4<Scalar> operator+ (const ntlMatrix4x4<Scalar>&) const;
- // binary operator add
- inline ntlMatrix4x4<Scalar> operator+ (Scalar) const;
- // binary operator sub
- inline ntlMatrix4x4<Scalar> operator- (const ntlMatrix4x4<Scalar>&) const;
- // binary operator sub
- inline ntlMatrix4x4<Scalar> operator- (Scalar) const;
- // binary operator mult
- inline ntlMatrix4x4<Scalar> operator* (const ntlMatrix4x4<Scalar>&) const;
- // binary operator mult
- inline ntlVector3Dim<Scalar> operator* (const ntlVector3Dim<Scalar>&) const;
- // binary operator mult
- inline ntlMatrix4x4<Scalar> operator* (Scalar) const;
- // binary operator div
- inline ntlMatrix4x4<Scalar> operator/ (Scalar) const;
-
- // init function
- //! init identity matrix
- inline void initId();
- //! init rotation matrix
- inline void initTranslation(Scalar x, Scalar y, Scalar z);
- //! init rotation matrix
- inline void initRotationX(Scalar rot);
- inline void initRotationY(Scalar rot);
- inline void initRotationZ(Scalar rot);
- inline void initRotationXYZ(Scalar rotx,Scalar roty, Scalar rotz);
- //! init scaling matrix
- inline void initScaling(Scalar scale);
- inline void initScaling(Scalar x, Scalar y, Scalar z);
- //! from 16 value array (init id if all 0)
- inline void initArrayCheck(Scalar *array);
-
- //! decompose matrix
- void decompose(ntlVector3Dim<Scalar> &trans,ntlVector3Dim<Scalar> &scale,ntlVector3Dim<Scalar> &rot,ntlVector3Dim<Scalar> &shear);
-
- //! public to avoid [][] operators
- Scalar value[4][4]; //< Storage of vector values
-
-
-protected:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlMatrix4x4")
-#endif
-};
-
-
-
-//------------------------------------------------------------------------------
-// TYPEDEFS
-//------------------------------------------------------------------------------
-
-// a 3D vector for graphics output, typically float?
-//typedef ntlMatrix4x4<float> ntlVec3Gfx;
-
-//typedef ntlMatrix4x4<double> ntlMat4d;
-typedef ntlMatrix4x4<double> ntlMat4d;
-
-// a 3D vector with single precision
-typedef ntlMatrix4x4<float> ntlMat4f;
-
-// a 3D vector with grafix precision
-typedef ntlMatrix4x4<gfxReal> ntlMat4Gfx;
-
-// a 3D integer vector
-typedef ntlMatrix4x4<int> ntlMat4i;
-
-
-
-
-
-//------------------------------------------------------------------------------
-// STREAM FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Outputs the object in human readable form using the format
- [x,y,z]
- */
-template<class Scalar>
-std::ostream&
-operator<<( std::ostream& os, const ntlMatrix4x4<Scalar>& m )
-{
- for(int i=0; i<4; i++) {
- os << '|' << m.value[i][0] << ", " << m.value[i][1] << ", " << m.value[i][2] << ", " << m.value[i][3] << '|';
- }
- return os;
-}
-
-
-
-/*************************************************************************
- Reads the contents of the object from a stream using the same format
- as the output operator.
- */
-template<class Scalar>
-std::istream&
-operator>>( std::istream& is, ntlMatrix4x4<Scalar>& m )
-{
- char c;
- char dummy[3];
-
- for(int i=0; i<4; i++) {
- is >> c >> m.value[i][0] >> dummy >> m.value[i][1] >> dummy >> m.value[i][2] >> dummy >> m.value[i][3] >> c;
- }
- return is;
-}
-
-
-//------------------------------------------------------------------------------
-// VECTOR inline FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Constructor.
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>::ntlMatrix4x4( void )
-{
-#ifdef MATRIX_INIT_ZERO
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] = 0.0;
- }
- }
-#endif
-}
-
-
-
-/*************************************************************************
- Copy-Constructor.
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>::ntlMatrix4x4( const ntlMatrix4x4<Scalar> &v )
-{
- value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3];
- value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3];
- value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3];
- value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3];
-}
-
-
-
-/*************************************************************************
- Constructor for a vector from a single Scalar. All components of
- the vector get the same value.
- \param s The value to set
- \return The new vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>::ntlMatrix4x4(Scalar s )
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] = s;
- }
- }
-}
-
-
-
-/*************************************************************************
- Copy a ntlMatrix4x4 componentwise.
- \param v vector with values to be copied
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator=( const ntlMatrix4x4<Scalar> &v )
-{
- value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3];
- value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3];
- value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3];
- value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3];
- return *this;
-}
-
-
-/*************************************************************************
- Copy a Scalar to each component.
- \param s The value to copy
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator=(Scalar s)
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] = s;
- }
- }
- return *this;
-}
-
-
-/*************************************************************************
- Add another ntlMatrix4x4 componentwise.
- \param v vector with values to be added
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator+=( const ntlMatrix4x4<Scalar> &v )
-{
- value[0][0] += v.value[0][0]; value[0][1] += v.value[0][1]; value[0][2] += v.value[0][2]; value[0][3] += v.value[0][3];
- value[1][0] += v.value[1][0]; value[1][1] += v.value[1][1]; value[1][2] += v.value[1][2]; value[1][3] += v.value[1][3];
- value[2][0] += v.value[2][0]; value[2][1] += v.value[2][1]; value[2][2] += v.value[2][2]; value[2][3] += v.value[2][3];
- value[3][0] += v.value[3][0]; value[3][1] += v.value[3][1]; value[3][2] += v.value[3][2]; value[3][3] += v.value[3][3];
- return *this;
-}
-
-
-/*************************************************************************
- Add a Scalar value to each component.
- \param s Value to add
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator+=(Scalar s)
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] += s;
- }
- }
- return *this;
-}
-
-
-/*************************************************************************
- Subtract another vector componentwise.
- \param v vector of values to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator-=( const ntlMatrix4x4<Scalar> &v )
-{
- value[0][0] -= v.value[0][0]; value[0][1] -= v.value[0][1]; value[0][2] -= v.value[0][2]; value[0][3] -= v.value[0][3];
- value[1][0] -= v.value[1][0]; value[1][1] -= v.value[1][1]; value[1][2] -= v.value[1][2]; value[1][3] -= v.value[1][3];
- value[2][0] -= v.value[2][0]; value[2][1] -= v.value[2][1]; value[2][2] -= v.value[2][2]; value[2][3] -= v.value[2][3];
- value[3][0] -= v.value[3][0]; value[3][1] -= v.value[3][1]; value[3][2] -= v.value[3][2]; value[3][3] -= v.value[3][3];
- return *this;
-}
-
-
-/*************************************************************************
- Subtract a Scalar value from each component.
- \param s Value to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator-=(Scalar s)
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] -= s;
- }
- }
- return *this;
-}
-
-
-/*************************************************************************
- Multiply with another vector componentwise.
- \param v vector of values to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator*=( const ntlMatrix4x4<Scalar> &v )
-{
- ntlMatrix4x4<Scalar> nv(0.0);
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
-
- for(int k=0;k<4;k++)
- nv.value[i][j] += (value[i][k] * v.value[k][j]);
- }
- }
- *this = nv;
- return *this;
-}
-
-
-/*************************************************************************
- Multiply each component with a Scalar value.
- \param s Value to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator*=(Scalar s)
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] *= s;
- }
- }
- return *this;
-}
-
-
-
-/*************************************************************************
- Divide each component by a Scalar value.
- \param s Value to divide by
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator/=(Scalar s)
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] /= s;
- }
- }
- return *this;
-}
-
-
-//------------------------------------------------------------------------------
-// unary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build componentwise the negative this vector.
- \return The new (negative) vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator-() const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = -value[i][j];
- }
- }
- return nv;
-}
-
-
-
-//------------------------------------------------------------------------------
-// binary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build a vector with another vector added componentwise.
- \param v The second vector to add
- \return The sum vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator+( const ntlMatrix4x4<Scalar> &v ) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] + v.value[i][j];
- }
- }
- return nv;
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value added to each component.
- \param s The Scalar value to add
- \return The sum vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator+(Scalar s) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] + s;
- }
- }
- return nv;
-}
-
-
-/*************************************************************************
- Build a vector with another vector subtracted componentwise.
- \param v The second vector to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator-( const ntlMatrix4x4<Scalar> &v ) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] - v.value[i][j];
- }
- }
- return nv;
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value subtracted componentwise.
- \param s The Scalar value to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator-(Scalar s ) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] - s;
- }
- }
- return nv;
-}
-
-
-
-/*************************************************************************
- Build a ntlMatrix4x4 with a Scalar value multiplied to each component.
- \param s The Scalar value to multiply with
- \return The product vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator*(Scalar s) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] * s;
- }
- }
- return nv;
-}
-
-
-
-
-/*************************************************************************
- Build a vector divided componentwise by a Scalar value.
- \param s The Scalar value to divide by
- \return The ratio vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator/(Scalar s) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] / s;
- }
- }
- return nv;
-}
-
-
-
-
-
-/*************************************************************************
- Build a vector with another vector multiplied by componentwise.
- \param v The second vector to muliply with
- \return The product vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator*( const ntlMatrix4x4<Scalar>& v) const
-{
- ntlMatrix4x4<Scalar> nv(0.0);
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
-
- for(int k=0;k<4;k++)
- nv.value[i][j] += (value[i][k] * v.value[k][j]);
- }
- }
- return nv;
-}
-
-
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlMatrix4x4<Scalar>::operator*( const ntlVector3Dim<Scalar>& v) const
-{
- ntlVector3Dim<Scalar> nvec(0.0);
- for(int i=0; i<3; i++) {
- for(int j=0; j<3; j++) {
- nvec[i] += (v[j] * value[i][j]);
- }
- }
- // assume normalized w coord
- for(int i=0; i<3; i++) {
- nvec[i] += (1.0 * value[i][3]);
- }
- return nvec;
-}
-
-
-
-//------------------------------------------------------------------------------
-// Other helper functions
-//------------------------------------------------------------------------------
-
-//! init identity matrix
-template<class Scalar>
-inline void ntlMatrix4x4<Scalar>::initId()
-{
- (*this) = (Scalar)(0.0);
- value[0][0] =
- value[1][1] =
- value[2][2] =
- value[3][3] = (Scalar)(1.0);
-}
-
-//! init rotation matrix
-template<class Scalar>
-inline void ntlMatrix4x4<Scalar>::initTranslation(Scalar x, Scalar y, Scalar z)
-{
- //(*this) = (Scalar)(0.0);
- this->initId();
- value[0][3] = x;
- value[1][3] = y;
- value[2][3] = z;
-}
-
-//! init rotation matrix
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initRotationX(Scalar rot)
-{
- double drot = (double)(rot/360.0*2.0*M_PI);
- //? while(drot < 0.0) drot += (M_PI*2.0);
-
- this->initId();
- value[1][1] = (Scalar) cos(drot);
- value[1][2] = (Scalar) sin(drot);
- value[2][1] = (Scalar)(-sin(drot));
- value[2][2] = (Scalar) cos(drot);
-}
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initRotationY(Scalar rot)
-{
- double drot = (double)(rot/360.0*2.0*M_PI);
- //? while(drot < 0.0) drot += (M_PI*2.0);
-
- this->initId();
- value[0][0] = (Scalar) cos(drot);
- value[0][2] = (Scalar)(-sin(drot));
- value[2][0] = (Scalar) sin(drot);
- value[2][2] = (Scalar) cos(drot);
-}
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initRotationZ(Scalar rot)
-{
- double drot = (double)(rot/360.0*2.0*M_PI);
- //? while(drot < 0.0) drot += (M_PI*2.0);
-
- this->initId();
- value[0][0] = (Scalar) cos(drot);
- value[0][1] = (Scalar) sin(drot);
- value[1][0] = (Scalar)(-sin(drot));
- value[1][1] = (Scalar) cos(drot);
-}
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initRotationXYZ( Scalar rotx, Scalar roty, Scalar rotz)
-{
- ntlMatrix4x4<Scalar> val;
- ntlMatrix4x4<Scalar> rot;
- this->initId();
-
- // org
- /*rot.initRotationX(rotx);
- (*this) *= rot;
- rot.initRotationY(roty);
- (*this) *= rot;
- rot.initRotationZ(rotz);
- (*this) *= rot;
- // org */
-
- // blender
- rot.initRotationZ(rotz);
- (*this) *= rot;
- rot.initRotationY(roty);
- (*this) *= rot;
- rot.initRotationX(rotx);
- (*this) *= rot;
- // blender */
-}
-
-//! init scaling matrix
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initScaling(Scalar scale)
-{
- this->initId();
- value[0][0] = scale;
- value[1][1] = scale;
- value[2][2] = scale;
-}
-//! init scaling matrix
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initScaling(Scalar x, Scalar y, Scalar z)
-{
- this->initId();
- value[0][0] = x;
- value[1][1] = y;
- value[2][2] = z;
-}
-
-
-//! from 16 value array (init id if all 0)
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initArrayCheck(Scalar *array)
-{
- bool allZero = true;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] = array[i*4+j];
- if(array[i*4+j]!=0.0) allZero=false;
- }
- }
- if(allZero) this->initId();
-}
-
-//! decompose matrix
-template<class Scalar>
-void
-ntlMatrix4x4<Scalar>::decompose(ntlVector3Dim<Scalar> &trans,ntlVector3Dim<Scalar> &scale,ntlVector3Dim<Scalar> &rot,ntlVector3Dim<Scalar> &shear) {
- ntlVec3Gfx row[3],temp;
-
- for(int i = 0; i < 3; i++) {
- trans[i] = this->value[3][i];
- }
-
- for(int i = 0; i < 3; i++) {
- row[i][0] = this->value[i][0];
- row[i][1] = this->value[i][1];
- row[i][2] = this->value[i][2];
- }
-
- scale[0] = norm(row[0]);
- normalize (row[0]);
-
- shear[0] = dot(row[0], row[1]);
- row[1][0] = row[1][0] - shear[0]*row[0][0];
- row[1][1] = row[1][1] - shear[0]*row[0][1];
- row[1][2] = row[1][2] - shear[0]*row[0][2];
-
- scale[1] = norm(row[1]);
- normalize (row[1]);
-
- if(scale[1] != 0.0)
- shear[0] /= scale[1];
-
- shear[1] = dot(row[0], row[2]);
- row[2][0] = row[2][0] - shear[1]*row[0][0];
- row[2][1] = row[2][1] - shear[1]*row[0][1];
- row[2][2] = row[2][2] - shear[1]*row[0][2];
-
- shear[2] = dot(row[1], row[2]);
- row[2][0] = row[2][0] - shear[2]*row[1][0];
- row[2][1] = row[2][1] - shear[2]*row[1][1];
- row[2][2] = row[2][2] - shear[2]*row[1][2];
-
- scale[2] = norm(row[2]);
- normalize (row[2]);
-
- if(scale[2] != 0.0) {
- shear[1] /= scale[2];
- shear[2] /= scale[2];
- }
-
- temp = cross(row[1], row[2]);
- if(dot(row[0], temp) < 0.0) {
- for(int i = 0; i < 3; i++) {
- scale[i] *= -1.0;
- row[i][0] *= -1.0;
- row[i][1] *= -1.0;
- row[i][2] *= -1.0;
- }
- }
-
- if(row[0][2] < -1.0) row[0][2] = -1.0;
- if(row[0][2] > +1.0) row[0][2] = +1.0;
-
- rot[1] = asin(-row[0][2]);
-
- if(fabs(cos(rot[1])) > VECTOR_EPSILON) {
- rot[0] = atan2 (row[1][2], row[2][2]);
- rot[2] = atan2 (row[0][1], row[0][0]);
- }
- else {
- rot[0] = atan2 (row[1][0], row[1][1]);
- rot[2] = 0.0;
- }
-
- rot[0] = (180.0/M_PI)*rot[0];
- rot[1] = (180.0/M_PI)*rot[1];
- rot[2] = (180.0/M_PI)*rot[2];
-}
-
-#define NTL_MATRICES_H
-#endif
-
diff --git a/intern/elbeem/intern/ntl_ray.cpp b/intern/elbeem/intern/ntl_ray.cpp
deleted file mode 100644
index 1acc8cdca12..00000000000
--- a/intern/elbeem/intern/ntl_ray.cpp
+++ /dev/null
@@ -1,915 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * main renderer class
- *
- *****************************************************************************/
-
-
-#include "utilities.h"
-#include "ntl_ray.h"
-#include "ntl_world.h"
-#include "ntl_geometryobject.h"
-#include "ntl_geometryshader.h"
-
-
-/* Minimum value for refl/refr to be traced */
-#define RAY_THRESHOLD 0.001
-
-#if GFX_PRECISION==1
-// float values
-//! Minimal contribution for rays to be traced on
-#define RAY_MINCONTRIB (1e-04)
-
-#else
-// double values
-//! Minimal contribution for rays to be traced on
-#define RAY_MINCONTRIB (1e-05)
-
-#endif
-
-
-
-
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-ntlRay::ntlRay( void )
- : mOrigin(0.0)
- , mDirection(0.0)
- , mvNormal(0.0)
- , mDepth(0)
- , mpGlob(NULL)
- , mIsRefracted(0)
-{
- errFatal("ntlRay::ntlRay()","Don't use uninitialized rays !", SIMWORLD_GENERICERROR);
- return;
-}
-
-
-/******************************************************************************
- * Copy - Constructor
- *****************************************************************************/
-ntlRay::ntlRay( const ntlRay &r )
-{
- // copy it! initialization is not enough!
- mOrigin = r.mOrigin;
- mDirection = r.mDirection;
- mvNormal = r.mvNormal;
- mDepth = r.mDepth;
- mIsRefracted = r.mIsRefracted;
- mIsReflected = r.mIsReflected;
- mContribution = r.mContribution;
- mpGlob = r.mpGlob;
-
- // get new ID
- if(mpGlob) {
- mID = mpGlob->getCounterRays()+1;
- mpGlob->setCounterRays( mpGlob->getCounterRays()+1 );
- } else {
- mID = 0;
- }
-}
-
-
-/******************************************************************************
- * Constructor with explicit parameters and global render object
- *****************************************************************************/
-ntlRay::ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob)
- : mOrigin( o )
- , mDirection( d )
- , mvNormal(0.0)
- , mDepth( i )
- , mContribution( contrib )
- , mpGlob( glob )
- , mIsRefracted( 0 )
- , mIsReflected( 0 )
-{
- // get new ID
- if(mpGlob) {
- mID = mpGlob->getCounterRays()+1;
- mpGlob->setCounterRays( mpGlob->getCounterRays()+1 );
- } else {
- mID = 0;
- }
-}
-
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlRay::~ntlRay()
-{
- /* nothing to do... */
-}
-
-
-
-/******************************************************************************
- * AABB
- *****************************************************************************/
-/* for AABB intersect */
-#define NUMDIM 3
-#define RIGHT 0
-#define LEFT 1
-#define MIDDLE 2
-
-//! intersect ray with AABB
-#ifndef ELBEEM_PLUGIN
-void ntlRay::intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const
-{
- char inside = true; /* inside box? */
- char hit = false; /* ray hits box? */
- int whichPlane; /* intersection plane */
- gfxReal candPlane[NUMDIM]; /* candidate plane */
- gfxReal quadrant[NUMDIM]; /* quadrants */
- gfxReal maxT[NUMDIM]; /* max intersection T for planes */
- ntlVec3Gfx coord; /* intersection point */
- ntlVec3Gfx dir = mDirection;
- ntlVec3Gfx origin = mOrigin;
- ntlVec3Gfx normal(0.0, 0.0, 0.0);
-
- t = GFX_REAL_MAX;
-
- /* check intersection planes for AABB */
- for(int i=0;i<NUMDIM;i++) {
- if(origin[i] < mStart[i]) {
- quadrant[i] = LEFT;
- candPlane [i] = mStart[i];
- inside = false;
- } else if(origin[i] > mEnd[i]) {
- quadrant[i] = RIGHT;
- candPlane[i] = mEnd[i];
- inside = false;
- } else {
- quadrant[i] = MIDDLE;
- }
- }
-
- /* inside AABB? */
- if(!inside) {
- /* get t distances to planes */
- /* treat too small direction components as paralell */
- for(int i=0;i<NUMDIM;i++) {
- if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
- maxT[i] = (candPlane[i] - origin[i]) / dir[i];
- } else {
- maxT[i] = -1;
- }
- }
-
- /* largest max t */
- whichPlane = 0;
- for(int i=1;i<NUMDIM;i++) {
- if(maxT[whichPlane] < maxT[i]) whichPlane = i;
- }
-
- /* check final candidate */
- hit = true;
- if(maxT[whichPlane] >= 0.0) {
-
- for(int i=0;i<NUMDIM;i++) {
- if(whichPlane != i) {
- coord[i] = origin[i] + maxT[whichPlane] * dir[i];
- if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
- (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
- /* no hit... */
- hit = false;
- }
- }
- else {
- coord[i] = candPlane[i];
- }
- }
-
- /* AABB hit... */
- if( hit ) {
- t = maxT[whichPlane];
- if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0;
- else normal[whichPlane] = -1.0;
- }
- }
-
-
- } else {
- /* inside AABB... */
- t = 0.0;
- coord = origin;
- return;
- }
-
- if(t == GFX_REAL_MAX) t = -1.0;
- retnormal = normal;
- retcoord = coord;
-}
-
-//! intersect ray with AABB
-void ntlRay::intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const
-{
- char hit = false; /* ray hits box? */
- int whichPlane; /* intersection plane */
- gfxReal candPlane[NUMDIM]; /* candidate plane */
- gfxReal quadrant[NUMDIM]; /* quadrants */
- gfxReal maxT[NUMDIM]; /* max intersection T for planes */
- ntlVec3Gfx coord; /* intersection point */
- ntlVec3Gfx dir = mDirection;
- ntlVec3Gfx origin = mOrigin;
- ntlVec3Gfx normal(0.0, 0.0, 0.0);
-
- t = GFX_REAL_MAX;
- for(int i=0;i<NUMDIM;i++) {
- if(origin[i] < mStart[i]) {
- quadrant[i] = LEFT;
- candPlane [i] = mEnd[i];
- } else if(origin[i] > mEnd[i]) {
- quadrant[i] = RIGHT;
- candPlane[i] = mStart[i];
- } else {
- if(dir[i] > 0) {
- quadrant[i] = LEFT;
- candPlane [i] = mEnd[i];
- } else
- if(dir[i] < 0) {
- quadrant[i] = RIGHT;
- candPlane[i] = mStart[i];
- } else {
- quadrant[i] = MIDDLE;
- }
- }
- }
-
-
- /* get t distances to planes */
- /* treat too small direction components as paralell */
- for(int i=0;i<NUMDIM;i++) {
- if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
- maxT[i] = (candPlane[i] - origin[i]) / dir[i];
- } else {
- maxT[i] = GFX_REAL_MAX;
- }
- }
-
- /* largest max t */
- whichPlane = 0;
- for(int i=1;i<NUMDIM;i++) {
- if(maxT[whichPlane] > maxT[i]) whichPlane = i;
- }
-
- /* check final candidate */
- hit = true;
- if(maxT[whichPlane] != GFX_REAL_MAX) {
-
- for(int i=0;i<NUMDIM;i++) {
- if(whichPlane != i) {
- coord[i] = origin[i] + maxT[whichPlane] * dir[i];
- if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
- (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
- /* no hit... */
- hit = false;
- }
- }
- else {
- coord[i] = candPlane[i];
- }
- }
-
- /* AABB hit... */
- if( hit ) {
- t = maxT[whichPlane];
-
- if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0;
- else normal[whichPlane] = -1.0;
- }
- }
-
-
- if(t == GFX_REAL_MAX) t = -1.0;
- retnormal = normal;
- retcoord = coord;
-}
-#endif // ELBEEM_PLUGIN
-
-//! intersect ray with AABB
-void ntlRay::intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const
-{
- // char inside = true; /* inside box? */ /* UNUSED */
- char hit = false; /* ray hits box? */
- int whichPlane; /* intersection plane */
- gfxReal candPlane[NUMDIM]; /* candidate plane */
- gfxReal quadrant[NUMDIM]; /* quadrants */
- gfxReal maxT[NUMDIM]; /* max intersection T for planes */
- ntlVec3Gfx coord; /* intersection point */
- ntlVec3Gfx dir = mDirection;
- ntlVec3Gfx origin = mOrigin;
- gfxReal t = GFX_REAL_MAX;
-
- /* check intersection planes for AABB */
- for(int i=0;i<NUMDIM;i++) {
- if(origin[i] < mStart[i]) {
- quadrant[i] = LEFT;
- candPlane [i] = mStart[i];
- // inside = false;
- } else if(origin[i] > mEnd[i]) {
- quadrant[i] = RIGHT;
- candPlane[i] = mEnd[i];
- // inside = false;
- } else {
- /* intersect with backside */
- if(dir[i] > 0) {
- quadrant[i] = LEFT;
- candPlane [i] = mStart[i];
- } else
- if(dir[i] < 0) {
- quadrant[i] = RIGHT;
- candPlane[i] = mEnd[i];
- } else {
- quadrant[i] = MIDDLE;
- }
- }
- }
-
- /* get t distances to planes */
- for(int i=0;i<NUMDIM;i++) {
- if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
- maxT[i] = (candPlane[i] - origin[i]) / dir[i];
- } else {
- maxT[i] = GFX_REAL_MAX;
- }
- }
-
- /* largest max t */
- whichPlane = 0;
- for(int i=1;i<NUMDIM;i++) {
- if( ((maxT[whichPlane] < maxT[i])&&(maxT[i]!=GFX_REAL_MAX)) ||
- (maxT[whichPlane]==GFX_REAL_MAX) )
- whichPlane = i;
- }
-
- /* check final candidate */
- hit = true;
- if(maxT[whichPlane]<GFX_REAL_MAX) {
- for(int i=0;i<NUMDIM;i++) {
- if(whichPlane != i) {
- coord[i] = origin[i] + maxT[whichPlane] * dir[i];
- if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
- (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
- /* no hit... */
- hit = false;
- }
- }
- else { coord[i] = candPlane[i]; }
- }
-
- /* AABB hit... */
- if( hit ) {
- t = maxT[whichPlane];
- }
- }
- tmin = t;
-
- /* now the backside */
- t = GFX_REAL_MAX;
- for(int i=0;i<NUMDIM;i++) {
- if(origin[i] < mStart[i]) {
- quadrant[i] = LEFT;
- candPlane [i] = mEnd[i];
- } else if(origin[i] > mEnd[i]) {
- quadrant[i] = RIGHT;
- candPlane[i] = mStart[i];
- } else {
- if(dir[i] > 0) {
- quadrant[i] = LEFT;
- candPlane [i] = mEnd[i];
- } else
- if(dir[i] < 0) {
- quadrant[i] = RIGHT;
- candPlane[i] = mStart[i];
- } else {
- quadrant[i] = MIDDLE;
- }
- }
- }
-
-
- /* get t distances to planes */
- for(int i=0;i<NUMDIM;i++) {
- if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
- maxT[i] = (candPlane[i] - origin[i]) / dir[i];
- } else {
- maxT[i] = GFX_REAL_MAX;
- }
- }
-
- /* smallest max t */
- whichPlane = 0;
- for(int i=1;i<NUMDIM;i++) {
- if(maxT[whichPlane] > maxT[i]) whichPlane = i;
- }
-
- /* check final candidate */
- hit = true;
- if(maxT[whichPlane] != GFX_REAL_MAX) {
-
- for(int i=0;i<NUMDIM;i++) {
- if(whichPlane != i) {
- coord[i] = origin[i] + maxT[whichPlane] * dir[i];
- if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
- (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
- /* no hit... */
- hit = false;
- }
- }
- else {
- coord[i] = candPlane[i];
- }
- }
-
- /* AABB hit... */
- if( hit ) {
- t = maxT[whichPlane];
- }
- }
-
- tmax = t;
-}
-
-
-
-/******************************************************************************
- * Determine color of this ray by tracing through the scene
- *****************************************************************************/
-const ntlColor ntlRay::shade() //const
-{
-#ifndef ELBEEM_PLUGIN
- ntlGeometryObject *closest = NULL;
- gfxReal minT = GFX_REAL_MAX;
- vector<ntlLightObject*> *lightlist = mpGlob->getLightList();
- mpGlob->setCounterShades( mpGlob->getCounterShades()+1 );
- bool intersectionInside = 0;
- if(mpGlob->getDebugOut() > 5) errorOut(std::endl<<"New Ray: depth "<<mDepth<<", org "<<mOrigin<<", dir "<<mDirection );
-
- /* check if this ray contributes enough */
- if(mContribution <= RAY_MINCONTRIB) {
- //return ntlColor(0.0);
- }
-
- /* find closes object that intersects */
- ntlTriangle *tri = NULL;
- ntlVec3Gfx normal;
- mpGlob->getRenderScene()->intersectScene(*this, minT, normal, tri, 0);
- if(minT>0) {
- closest = mpGlob->getRenderScene()->getObject( tri->getObjectId() );
- }
-
- /* object hit... */
- if (closest != NULL) {
-
- ntlVec3Gfx triangleNormal = tri->getNormal();
- if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) errorOut("ntlRay warning: trinagle normal= 0 "); // DEBUG
- /* intersection on inside faces? if yes invert normal afterwards */
- gfxReal valDN; // = mDirection | normal;
- valDN = dot(mDirection, triangleNormal);
- if( valDN > 0.0) {
- intersectionInside = 1;
- normal = normal * -1.0;
- triangleNormal = triangleNormal * -1.0;
- }
-
- /* ... -> do reflection */
- ntlVec3Gfx intersectionPosition(mOrigin + (mDirection * (minT)) );
- ntlMaterial *clossurf = closest->getMaterial();
- /*if(mpGlob->getDebugOut() > 5) {
- errorOut("Ray hit: at "<<intersectionPosition<<" n:"<<normal<<" dn:"<<valDN<<" ins:"<<intersectionInside<<" cl:"<<((unsigned int)closest) );
- errorOut(" t1:"<<mpGlob->getRenderScene()->getVertex(tri->getPoints()[0])<<" t2:"<<mpGlob->getRenderScene()->getVertex(tri->getPoints()[1])<<" t3:"<<mpGlob->getScene()->getVertex(tri->getPoints()[2]) );
- errorOut(" trin:"<<tri->getNormal() );
- } // debug */
-
- /* current transparence and reflectivity */
- gfxReal currTrans = clossurf->getTransparence();
- gfxReal currRefl = clossurf->getMirror();
-
- /* correct intersectopm position */
- intersectionPosition += ( triangleNormal*getVecEpsilon() );
- /* reflection at normal */
- ntlVec3Gfx reflectedDir = getNormalized( reflectVector(mDirection, normal) );
- int badRefl = 0;
- if(dot(reflectedDir, triangleNormal)<0.0 ) {
- badRefl = 1;
- if(mpGlob->getDebugOut() > 5) { errorOut("Ray Bad reflection...!"); }
- }
-
- /* refraction direction, depending on in/outside hit */
- ntlVec3Gfx refractedDir;
- int refRefl = 0;
- /* refraction at normal is handled by inverting normal before */
- gfxReal myRefIndex = 1.0;
- if((currTrans>RAY_THRESHOLD)||(clossurf->getFresnel())) {
- if(intersectionInside) {
- myRefIndex = 1.0/clossurf->getRefracIndex();
- } else {
- myRefIndex = clossurf->getRefracIndex();
- }
-
- refractedDir = refractVector(mDirection, normal, myRefIndex , (gfxReal)(1.0) /* global ref index */, refRefl);
- }
-
- /* calculate fresnel? */
- if(clossurf->getFresnel()) {
- // for total reflection, just set trans to 0
- if(refRefl) {
- currRefl = 1.0; currTrans = 0.0;
- } else {
- // calculate fresnel coefficients
- clossurf->calculateFresnel( mDirection, normal, myRefIndex, currRefl,currTrans );
- }
- }
-
- ntlRay reflectedRay(intersectionPosition, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
- reflectedRay.setNormal( normal );
- ntlColor currentColor(0.0);
- ntlColor highlightColor(0.0);
-
- /* first add reflected ambient color */
- currentColor += (clossurf->getAmbientRefl() * mpGlob->getAmbientLight() );
-
- /* calculate lighting, not on the insides of objects... */
- if(!intersectionInside) {
- for (vector<ntlLightObject*>::iterator iter = lightlist->begin();
- iter != lightlist->end();
- iter++) {
-
- /* let light illuminate point */
- currentColor += (*iter)->illuminatePoint( reflectedRay, closest, highlightColor );
-
- } // for all lights
- }
-
- // recurse ?
- if ((mDepth < mpGlob->getRayMaxDepth() )&&(currRefl>RAY_THRESHOLD)) {
-
- if(badRefl) {
- ntlVec3Gfx intersectionPosition2;
- ntlGeometryObject *closest2 = NULL;
- gfxReal minT2 = GFX_REAL_MAX;
- ntlTriangle *tri2 = NULL;
- ntlVec3Gfx normal2;
-
- ntlVec3Gfx refractionPosition2(mOrigin + (mDirection * minT) );
- refractionPosition2 -= (triangleNormal*getVecEpsilon() );
-
- ntlRay reflectedRay2 = ntlRay(refractionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
- mpGlob->getRenderScene()->intersectScene(reflectedRay2, minT2, normal2, tri2, 0);
- if(minT2>0) {
- closest2 = mpGlob->getRenderScene()->getObject( tri2->getObjectId() );
- }
-
- /* object hit... */
- if (closest2 != NULL) {
- ntlVec3Gfx triangleNormal2 = tri2->getNormal();
- gfxReal valDN2;
- valDN2 = dot(reflectedDir, triangleNormal2);
- if( valDN2 > 0.0) {
- triangleNormal2 = triangleNormal2 * -1.0;
- intersectionPosition2 = ntlVec3Gfx(intersectionPosition + (reflectedDir * (minT2)) );
- /* correct intersection position and create new reflected ray */
- intersectionPosition2 += ( triangleNormal2*getVecEpsilon() );
- reflectedRay = ntlRay(intersectionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
- } else {
- // ray seems to work, continue normally ?
- }
-
- }
-
- }
-
- // add mirror color multiplied by mirror factor of surface
- if(mpGlob->getDebugOut() > 5) errorOut("Reflected ray from depth "<<mDepth<<", dir "<<reflectedDir );
- ntlColor reflectedColor = reflectedRay.shade() * currRefl;
- currentColor += reflectedColor;
- }
-
- /* Trace another ray on for transparent objects */
- if(currTrans > RAY_THRESHOLD) {
- /* position at the other side of the surface, along ray */
- ntlVec3Gfx refraction_position(mOrigin + (mDirection * minT) );
- refraction_position += (mDirection * getVecEpsilon());
- refraction_position -= (triangleNormal*getVecEpsilon() );
- ntlColor refracCol(0.0); /* refracted color */
-
- /* trace refracted ray */
- ntlRay transRay(refraction_position, refractedDir, mDepth+1, mContribution*currTrans, mpGlob);
- transRay.setRefracted(1);
- transRay.setNormal( normal );
- if(mDepth < mpGlob->getRayMaxDepth() ) {
- // full reflection should make sure refracindex&fresnel are on...
- if((0)||(!refRefl)) {
- if(mpGlob->getDebugOut() > 5) errorOut("Refracted ray from depth "<<mDepth<<", dir "<<refractedDir );
- refracCol = transRay.shade();
- } else {
- //we shouldnt reach this!
- if(mpGlob->getDebugOut() > 5) errorOut("Fully reflected ray from depth "<<mDepth<<", dir "<<reflectedDir );
- refracCol = reflectedRay.shade();
- }
- }
- //errMsg("REFMIR","t"<<currTrans<<" thres"<<RAY_THRESHOLD<<" mirr"<<currRefl<<" refRefl"<<refRefl<<" md"<<mDepth);
-
- /* calculate color */
- // use transadditive setting!?
- /* additive transparency "light amplification" */
- //? ntlColor add_col = currentColor + refracCol * currTrans;
- /* mix additive and subtractive */
- //? add_col += sub_col;
- //? currentColor += (refracCol * currTrans);
-
- /* subtractive transparency, more realistic */
- ntlColor sub_col = (refracCol * currTrans) + ( currentColor * (1.0-currTrans) );
- currentColor = sub_col;
-
- }
-
- /* add highlights (should not be affected by transparence as the diffuse reflections */
- currentColor += highlightColor;
-
- /* attentuate as a last step*/
- /* check if we're on the inside or outside */
- if(intersectionInside) {
- gfxReal kr,kg,kb; /* attentuation */
- /* calculate attentuation */
- ntlColor attCol = clossurf->getTransAttCol();
- kr = exp( attCol[0] * minT );
- kg = exp( attCol[1] * minT );
- kb = exp( attCol[2] * minT );
- currentColor = currentColor * ntlColor(kr,kg,kb);
- }
-
- /* done... */
- if(mpGlob->getDebugOut() > 5) { errorOut("Ray "<<mDepth<<" color "<<currentColor ); }
- return ntlColor(currentColor);
- }
-
-#endif // ELBEEM_PLUGIN
- /* no object hit -> ray goes to infinity */
- return mpGlob->getBackgroundCol();
-}
-
-
-
-/******************************************************************************
- ******************************************************************************
- ******************************************************************************
- * scene implementation
- ******************************************************************************
- ******************************************************************************
- *****************************************************************************/
-
-
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-ntlScene::ntlScene( ntlRenderGlobals *glob, bool del ) :
- mpGlob( glob ), mSceneDel(del),
- mpTree( NULL ),
- mSceneBuilt( false ), mFirstInitDone( false )
-{
-}
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlScene::~ntlScene()
-{
- if(mpTree != NULL) delete mpTree;
-
- // cleanup lists, only if this is the rendering cleanup scene
- if(mSceneDel)
- {
- for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
- iter != mGeos.end(); iter++) {
- //errMsg("ntlScene::~ntlScene","Deleting obj "<<(*iter)->getName() );
- delete (*iter);
- }
- for (vector<ntlLightObject*>::iterator iter = mpGlob->getLightList()->begin();
- iter != mpGlob->getLightList()->end(); iter++) {
- delete (*iter);
- }
- for (vector<ntlMaterial*>::iterator iter = mpGlob->getMaterials()->begin();
- iter != mpGlob->getMaterials()->end(); iter++) {
- delete (*iter);
- }
- }
- errMsg("ntlScene::~ntlScene","Deleted, ObjFree:"<<mSceneDel);
-}
-
-
-/******************************************************************************
- * Build the scene arrays (obj, tris etc.)
- *****************************************************************************/
-void ntlScene::buildScene(double time,bool firstInit)
-{
- const bool buildInfo=true;
-
- if(firstInit) {
- mObjects.clear();
- /* init geometry array, first all standard objects */
- for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
- iter != mGeos.end(); iter++) {
- bool geoinit = false;
- int tid = (*iter)->getTypeId();
- if(tid & GEOCLASSTID_OBJECT) {
- ntlGeometryObject *geoobj = (ntlGeometryObject*)(*iter);
- geoinit = true;
- mObjects.push_back( geoobj );
- if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added GeoObj "<<geoobj->getName()<<" Id:"<<geoobj->getObjectId(), 5 );
- }
- //if(geoshad) {
- if(tid & GEOCLASSTID_SHADER) {
- ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter);
- geoinit = true;
- if(!mFirstInitDone) {
- // only on first init
- geoshad->initializeShader();
- }
- for (vector<ntlGeometryObject*>::iterator siter = geoshad->getObjectsBegin();
- siter != geoshad->getObjectsEnd();
- siter++) {
- if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName()<<" Id:"<<(*siter)->getObjectId(), 5 );
- mObjects.push_back( (*siter) );
- }
- }
-
- if(!geoinit) {
- errFatal("ntlScene::BuildScene","Invalid geometry class!", SIMWORLD_INITERROR);
- return;
- }
- }
- }
-
- // collect triangles
- mTriangles.clear();
- mVertices.clear();
- mVertNormals.clear();
-
- /* for test mode deactivate transparencies etc. */
- if( mpGlob->getTestMode() ) {
- debugOut("ntlScene::buildScene : Test Mode activated!", 2);
- // assign random colors to dark materials
- int matCounter = 0;
- ntlColor stdCols[] = { ntlColor(0,0,1.0), ntlColor(0,1.0,0), ntlColor(1.0,0.7,0) , ntlColor(0.7,0,0.6) };
- int stdColNum = 4;
- for (vector<ntlMaterial*>::iterator iter = mpGlob->getMaterials()->begin();
- iter != mpGlob->getMaterials()->end(); iter++) {
- (*iter)->setTransparence(0.0);
- (*iter)->setMirror(0.0);
- (*iter)->setFresnel(false);
- // too dark?
- if( norm((*iter)->getDiffuseRefl()) <0.01) {
- (*iter)->setDiffuseRefl( stdCols[matCounter] );
- matCounter ++;
- matCounter = matCounter%stdColNum;
- }
- }
-
- // restrict output file size to 400
- float downscale = 1.0;
- if(mpGlob->getResX() > 400){ downscale = 400.0/(float)mpGlob->getResX(); }
- if(mpGlob->getResY() > 400){
- float downscale2 = 400.0/(float)mpGlob->getResY();
- if(downscale2<downscale) downscale=downscale2;
- }
- mpGlob->setResX( (int)(mpGlob->getResX() * downscale) );
- mpGlob->setResY( (int)(mpGlob->getResY() * downscale) );
-
- }
-
- /* collect triangles from objects */
- int idCnt = 0; // give IDs to objects
- bool debugTriCollect = false;
- if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Start...",5);
- for (vector<ntlGeometryObject*>::iterator iter = mObjects.begin();
- iter != mObjects.end();
- iter++) {
- /* only add visible objects */
- if(firstInit) {
- if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collect init of "<<(*iter)->getName()<<" idCnt:"<<idCnt, 4 );
- (*iter)->initialize( mpGlob ); }
- if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collecting tris from "<<(*iter)->getName(), 4 );
-
- int vstart = mVertNormals.size();
- (*iter)->setObjectId(idCnt);
- (*iter)->getTriangles(time, &mTriangles, &mVertices, &mVertNormals, idCnt);
- (*iter)->applyTransformation(time, &mVertices, &mVertNormals, vstart, mVertices.size(), false );
-
- if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Done with "<<(*iter)->getName()<<" totTris:"<<mTriangles.size()<<" totVerts:"<<mVertices.size()<<" totNorms:"<<mVertNormals.size(), 4 );
- idCnt ++;
- }
- if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"End",5);
-
-
- /* calculate triangle normals, and initialize flags */
- for (vector<ntlTriangle>::iterator iter = mTriangles.begin();
- iter != mTriangles.end();
- iter++) {
-
- // calculate normal from triangle points
- ntlVec3Gfx normal =
- cross( (ntlVec3Gfx)( (mVertices[(*iter).getPoints()[2]] - mVertices[(*iter).getPoints()[0]]) *-1.0), // BLITZ minus sign right??
- (ntlVec3Gfx)(mVertices[(*iter).getPoints()[1]] - mVertices[(*iter).getPoints()[0]]) );
- normalize(normal);
- (*iter).setNormal( normal );
- }
-
-
-
- // scene geometry built
- mSceneBuilt = true;
-
- // init shaders that require complete geometry
- if(!mFirstInitDone) {
- // only on first init
- for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
- iter != mGeos.end(); iter++) {
- if( (*iter)->getTypeId() & GEOCLASSTID_SHADER ) {
- ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter);
- if(geoshad->postGeoConstrInit( mpGlob )) {
- errFatal("ntlScene::buildScene","Init failed for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
- return;
- }
- }
- }
- mFirstInitDone = true;
- }
-
- // check unused attributes (for classes and objects!)
- for (vector<ntlGeometryObject*>::iterator iter = mObjects.begin(); iter != mObjects.end(); iter++) {
- if((*iter)->getAttributeList()->checkUnusedParams()) {
- (*iter)->getAttributeList()->print(); // DEBUG
- errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
- return;
- }
- }
- for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin(); iter != mGeos.end(); iter++) {
- if((*iter)->getAttributeList()->checkUnusedParams()) {
- (*iter)->getAttributeList()->print(); // DEBUG
- errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
- return;
- }
- }
-
-}
-
-/******************************************************************************
- * Prepare the scene triangles and maps for raytracing
- *****************************************************************************/
-void ntlScene::prepareScene(double time)
-{
- /* init triangles... */
- buildScene(time, false);
- // what for currently not used ???
- if(mpTree != NULL) delete mpTree;
- mpTree = new ntlTree(
-# if FSGR_STRICT_DEBUG!=1
- mpGlob->getTreeMaxDepth(), mpGlob->getTreeMaxTriangles(),
-# else
- mpGlob->getTreeMaxDepth()/3*2, mpGlob->getTreeMaxTriangles()*2,
-# endif
- this, TRI_GEOMETRY );
-
- //debMsgStd("ntlScene::prepareScene",DM_MSG,"Stats - tris:"<< (int)mTriangles.size()<<" verts:"<<mVertices.size()<<" vnorms:"<<mVertNormals.size(), 5 );
-}
-/******************************************************************************
- * Do some memory cleaning, when frame is finished
- *****************************************************************************/
-void ntlScene::cleanupScene( void )
-{
- mTriangles.clear();
- mVertices.clear();
- mVertNormals.clear();
-
- if(mpTree != NULL) delete mpTree;
- mpTree = NULL;
-}
-
-
-/******************************************************************************
- * Intersect a ray with the scene triangles
- *****************************************************************************/
-void ntlScene::intersectScene(const ntlRay &r, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri,int flags) const
-{
- distance = -1.0;
- mpGlob->setCounterSceneInter( mpGlob->getCounterSceneInter()+1 );
- mpTree->intersect(r, distance, normal, tri, flags, false);
-}
-
-
-
-
-
diff --git a/intern/elbeem/intern/ntl_ray.h b/intern/elbeem/intern/ntl_ray.h
deleted file mode 100644
index 064fce27059..00000000000
--- a/intern/elbeem/intern/ntl_ray.h
+++ /dev/null
@@ -1,438 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * ray class
- *
- *****************************************************************************/
-#ifndef NTL_RAY_H
-#define NTL_RAY_H
-
-#include <sstream>
-#include "ntl_vector3dim.h"
-#include "ntl_lighting.h"
-#include "ntl_geometryobject.h"
-#include "ntl_bsptree.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlTriangle;
-class ntlRay;
-class ntlTree;
-class ntlScene;
-class ntlRenderGlobals;
-class ntlGeometryObject;
-
-//! store data for an intersection of a ray and a triangle
-// NOT YET USED
-class ntlIntersection {
- public:
-
- ntlIntersection() :
- distance(-1.0), normal(0.0),
- ray(NULL), tri(NULL), flags(0) { };
-
- gfxReal distance;
- ntlVec3Gfx normal;
- ntlRay *ray;
- ntlTriangle *tri;
- char flags;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlIntersection")
-#endif
-};
-
-//! the main ray class
-class ntlRay
-{
-public:
- // CONSTRUCTORS
- //! Initialize ray memebers, prints error message
- ntlRay();
- //! Copy constructor, copy all members
- ntlRay(const ntlRay &r);
- //! Explicitly init member variables with global render object
- ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob);
- //! Destructor
- ~ntlRay();
-
- //! Set the refraction flag for refracted rays
- inline void setRefracted(unsigned char set) { mIsRefracted = set; }
- inline void setReflected(unsigned char set) { mIsReflected = set; }
-
- //! main ray recursion function
- /*!
- * First get closest object intersection, return background color if nothing
- * was hit, else calculate shading and reflection components
- * and return mixed color */
- const ntlColor shade() /*const*/;
-
- /*! Trace a photon through the scene */
- void tracePhoton(ntlColor) const;
-
- //! intersect ray with AABB
- void intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &normal, ntlVec3Gfx &retcoord) const;
- void intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &normal, ntlVec3Gfx &retcoord) const;
- void intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const;
- // intersection routines in bsptree.cpp
- //! optimized intersect ray with triangle
- inline void intersectTriangle(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
- //! optimized intersect ray with triangle along +X axis dir
- inline void intersectTriangleX(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
- //! intersect only with front side
- inline void intersectTriangleFront(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
- //! intersect ray only with backsides
- inline void intersectTriangleBack(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
-
- // access methods
- //! Returns the ray origin
- inline ntlVec3Gfx getOrigin() const { return ntlVec3Gfx(mOrigin); }
- //! Returns the ray direction
- inline ntlVec3Gfx getDirection() const { return ntlVec3Gfx(mDirection); }
- /*! Returns the ray relfection normal */
- inline ntlVec3Gfx getNormal() const { return ntlVec3Gfx(mvNormal); }
- //! Is this ray refracted?
- inline unsigned char getRefracted() const { return mIsRefracted; }
- inline unsigned char getReflected() const { return mIsReflected; }
- /*! Get position along ray */
- inline ntlVec3Gfx getPositionAt(gfxReal t) const { return (mOrigin+(mDirection*t)); }
- /*! Get render globals pointer of this ray */
- inline ntlRenderGlobals *getRenderglobals( void ) const { return mpGlob; }
- /*! get this ray's ID */
- inline int getID( void ) const { return mID; }
-
- /*! Set origin of this ray */
- inline void setOrigin(ntlVec3Gfx set) { mOrigin = set; }
- /*! Set direction of this ray */
- inline void setDirection(ntlVec3Gfx set) { mDirection = set; }
- /*! Set normal of this ray */
- inline void setNormal(ntlVec3Gfx set) { mvNormal = set; }
-
-protected:
- /* Calulates the Lambertian and Specular color for
- * the given reflection and returns it */
- const ntlColor getShadedColor(ntlLightObject *light, const ntlRay &reflectedray,
- const ntlVec3Gfx &normal, ntlMaterial *surf) const;
-
-private:
- /*! Origin of ray */
- ntlVec3Gfx mOrigin;
- /*! Normalized direction vector of ray */
- ntlVec3Gfx mDirection;
- /*! For reflected/refracted rays, the normal is stored here */
- ntlVec3Gfx mvNormal;
- /*! recursion depth */
- unsigned int mDepth;
- /*! How much does this ray contribute to the surface color? abort if too small */
- gfxReal mContribution;
-
- /*! Global rendering settings */
- ntlRenderGlobals *mpGlob;
-
- /*! If this ray is a refracted one, this flag has to be set
- * This is necessary to for example also give the background color
- * to refracted rays. Otherwise things may look strange...
- */
- unsigned char mIsRefracted;
- unsigned char mIsReflected;
-
- /*! ID of this ray (from renderglobals */
- int mID;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlRay")
-#endif
-};
-
-
-/******************************************************************************
- *
- * a single triangle
- *
- *****************************************************************************/
-
-// triangle intersection code in bsptree.cpp
-// intersectTriangle(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v);
-
-/*! Triangle flag defines */
-#define TRI_GEOMETRY (1<<0)
-#define TRI_CASTSHADOWS (1<<1)
-
-
-class ntlTriangle
-{
-public:
- /* CONSTRUCTORS */
- /*! Default constructor */
- inline ntlTriangle( void );
- /*! Constructor with parameters */
- inline ntlTriangle(int *p, bool smooth, int obj, ntlVec3Gfx norm, int setflags);
- /*! Copy - Constructor */
- inline ntlTriangle(const ntlTriangle &tri);
- /*! Destructor */
- inline ~ntlTriangle() {}
-
- /* Access methods */
-
- /*! Acces to points of triangle */
- inline int *getPoints( void ) { return mPoints; }
- /*! Acces normal smoothing */
- inline bool getSmoothNormals( void ) const { return mSmoothNormals; }
- inline void setSmoothNormals( bool set){ mSmoothNormals = set; }
- /*! Access object */
- inline int getObjectId( void ) const { return mObjectId; }
- inline void setObjectId( int set) { mObjectId = set; }
- /*! Acces normal index */
- inline ntlVec3Gfx getNormal( void ) const { return mNormal; }
- inline void setNormal( ntlVec3Gfx set ) { mNormal = set; }
- /*! Acces flags */
- inline int getFlags( void ) const { return mFlags; }
- inline void setFlags( int set ) { mFlags = set; }
- /*! Access last intersection ray ID */
- inline int getLastRay( void ) const { return mLastRay; }
- inline void setLastRay( int set ) { mLastRay = set; }
- /*! Acces bbox id */
- inline int getBBoxId( void ) const { return mBBoxId; }
- inline void setBBoxId( int set ) { mBBoxId = set; }
-
- /*! Get average of the three points for this axis */
- inline gfxReal getAverage( int axis ) const;
-
- /*! operator < for sorting, uses global sorting axis */
- inline friend bool operator<(const ntlTriangle &lhs, const ntlTriangle &rhs);
- /*! operator > for sorting, uses global sorting axis */
- inline friend bool operator>(const ntlTriangle &lhs, const ntlTriangle &rhs);
-
-protected:
-
-private:
-
- /*! indices to the three points of the triangle */
- int mPoints[3];
-
- /*! bounding box id (for tree generation), -1 if invalid */
- int mBBoxId;
-
- /*! Should the normals of this triangle get smoothed? */
- bool mSmoothNormals;
-
- /*! Id of parent object */
- int mObjectId;
-
- /*! Index to normal (for not smooth triangles) */
- //int mNormalIndex; ??
- ntlVec3Gfx mNormal;
-
- /*! Flags for object attributes cast shadows */
- int mFlags;
-
- /*! ID of last ray that an intersection was calculated for */
- int mLastRay;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlTriangle")
-#endif
-};
-
-
-
-
-/******************************************************************************
- * Default Constructor
- *****************************************************************************/
-ntlTriangle::ntlTriangle( void ) :
- mBBoxId(-1),
- mLastRay( 0 )
-{
- mPoints[0] = mPoints[1] = mPoints[2] = 0;
- mSmoothNormals = 0;
- mObjectId = 0;
- mNormal = ntlVec3Gfx(0.0);
- mFlags = 0;
-}
-
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-ntlTriangle::ntlTriangle(int *p, bool smooth, int obj, ntlVec3Gfx norm, int setflags) :
- mBBoxId(-1),
- mLastRay( 0 )
-{
- mPoints[0] = p[0];
- mPoints[1] = p[1];
- mPoints[2] = p[2];
- mSmoothNormals = smooth;
- mObjectId = obj;
- mNormal = norm;
- mFlags = setflags;
-}
-
-
-/******************************************************************************
- * Copy Constructor
- *****************************************************************************/
-ntlTriangle::ntlTriangle(const ntlTriangle &tri) :
- mBBoxId(-1),
- mLastRay( 0 )
-{
- mPoints[0] = tri.mPoints[0];
- mPoints[1] = tri.mPoints[1];
- mPoints[2] = tri.mPoints[2];
- mSmoothNormals = tri.mSmoothNormals;
- mObjectId = tri.mObjectId;
- mNormal = tri.mNormal;
- mFlags = tri.mFlags;
-}
-
-
-
-
-/******************************************************************************
- * Triangle sorting functions
- *****************************************************************************/
-
-/* variables imported from ntl_bsptree.cc, necessary for using the stl sort funtion */
-/* Static global variable for sorting direction */
-extern int globalSortingAxis;
-/* Access to points array for sorting */
-extern vector<ntlVec3Gfx> *globalSortingPoints;
-
-
-gfxReal ntlTriangle::getAverage( int axis ) const
-{
- return ( ( (*globalSortingPoints)[ mPoints[0] ][axis] +
- (*globalSortingPoints)[ mPoints[1] ][axis] +
- (*globalSortingPoints)[ mPoints[2] ][axis] )/3.0);
-}
-
-bool operator<(const ntlTriangle &lhs,const ntlTriangle &rhs)
-{
- return ( lhs.getAverage(globalSortingAxis) <
- rhs.getAverage(globalSortingAxis) );
-}
-
-bool operator>(const ntlTriangle &lhs,const ntlTriangle &rhs)
-{
- return ( lhs.getAverage(globalSortingAxis) >
- rhs.getAverage(globalSortingAxis) );
-}
-
-
-
-/******************************************************************************
- *
- * Scene object, that contains and manages all geometry objects
- *
- *****************************************************************************/
-
-
-
-class ntlScene
-{
-public:
- /* CONSTRUCTORS */
- /*! Default constructor */
- ntlScene( ntlRenderGlobals *glob, bool del=true );
- /*! Default destructor */
- ~ntlScene();
-
- /*! Add an object to the scene */
- inline void addGeoClass(ntlGeometryClass *geo) {
- mGeos.push_back( geo );
- geo->setObjectId(mGeos.size());
- }
- /*! Add a geo object to the scene, warning - only needed for hand init */
- inline void addGeoObject(ntlGeometryObject *geo) { mObjects.push_back( geo ); }
-
- /*! Acces a certain object */
- inline ntlGeometryObject *getObject(int id) {
- if(!mSceneBuilt) { errFatal("ntlScene::getObject","Scene not inited!", SIMWORLD_INITERROR); }
- return mObjects[id]; }
-
- /*! Acces object array */
- inline vector<ntlGeometryObject*> *getObjects() {
- if(!mSceneBuilt) { errFatal("ntlScene::getObjects[]","Scene not inited!", SIMWORLD_INITERROR); }
- return &mObjects; }
-
- /*! Acces geo class array */
- inline vector<ntlGeometryClass*> *getGeoClasses() {
- if(!mSceneBuilt) { errFatal("ntlScene::getGeoClasses[]","Scene not inited!", SIMWORLD_INITERROR); }
- return &mGeos; }
-
- /*! draw scene with opengl */
- //void draw();
-
- /*! Build/first init the scene arrays */
- void buildScene(double time, bool firstInit);
-
- //! Prepare the scene triangles and maps for raytracing
- void prepareScene(double time);
- //! Do some memory cleaning, when frame is finished
- void cleanupScene( void );
-
- /*! Intersect a ray with the scene triangles */
- void intersectScene(const ntlRay &r, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags) const;
-
- /*! return a vertex */
- ntlVec3Gfx getVertex(int index) { return mVertices[index]; }
-
- // for tree generation
- /*! return pointer to vertices vector */
- vector<ntlVec3Gfx> *getVertexPointer( void ) { return &mVertices; }
- /*! return pointer to vertices vector */
- vector<ntlVec3Gfx> *getVertexNormalPointer( void ) { return &mVertNormals; }
- /*! return pointer to vertices vector */
- vector<ntlTriangle> *getTrianglePointer( void ) { return &mTriangles; }
-
-private:
-
- /*! Global settings */
- ntlRenderGlobals *mpGlob;
-
- /*! free objects? (only necessary for render scene, which contains all) */
- bool mSceneDel;
-
- /*! List of geometry classes */
- vector<ntlGeometryClass *> mGeos;
-
- /*! List of geometry objects */
- vector<ntlGeometryObject *> mObjects;
-
- /*! List of triangles */
- vector<ntlTriangle> mTriangles;
- /*! List of vertices */
- vector<ntlVec3Gfx> mVertices;
- /*! List of normals */
- vector<ntlVec3Gfx> mVertNormals;
- /*! List of triangle normals */
- vector<ntlVec3Gfx> mTriangleNormals;
-
- /*! Tree to store quickly intersect triangles */
- ntlTree *mpTree;
-
- /*! was the scene successfully built? only then getObject(i) requests are valid */
- bool mSceneBuilt;
-
- /*! shader/obj initializations are only done on first init */
- bool mFirstInitDone;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlScene")
-#endif
-};
-
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_vector3dim.h b/intern/elbeem/intern/ntl_vector3dim.h
deleted file mode 100644
index 51e03e30dc8..00000000000
--- a/intern/elbeem/intern/ntl_vector3dim.h
+++ /dev/null
@@ -1,1105 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Basic vector class used everywhere, either blitz or inlined GRAPA class
- *
- *****************************************************************************/
-#ifndef NTL_VECTOR3DIM_H
-#define NTL_VECTOR3DIM_H
-
-// this serves as the main include file
-// for all kinds of stuff that might be required
-// under windows there seem to be strange
-// errors when including the STL header too
-// late...
-
-#ifdef _MSC_VER
-#define _USE_MATH_DEFINES 1
-#endif
-
-#include <iostream>
-#include <map>
-#include <vector>
-#include <string>
-#include <sstream>
-#include <math.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-/* absolute value */
-template < class T >
-inline T
-ABS( T a )
-{ return (0 < a) ? a : -a ; }
-
-// hack for MSVC6.0 compiler
-#ifdef _MSC_VER
-#if _MSC_VER < 1300
-#define for if(false); else for
-#define map std::map
-#define vector std::vector
-#define string std::string
-// use this define for MSVC6 stuff hereafter
-#define USE_MSVC6FIXES
-#else // _MSC_VER < 1300 , 7.0 or higher
-using std::map;
-using std::vector;
-using std::string;
-#endif
-#else // not MSVC6
-// for proper compilers...
-using std::map;
-using std::vector;
-using std::string;
-#endif // MSVC6
-
-#ifdef __APPLE_CC__
-// apple
-#else
-#ifdef WIN32
-
-// windows values missing, see below
-#ifndef snprintf
-#define snprintf _snprintf
-#endif
-
-#ifdef _MSC_VER
-#if _MSC_VER >= 1300
-#include <float.h>
-#endif
-#endif
-
-#else // WIN32
-
-// floating point limits for linux,*bsd etc...
-#include <float.h>
-
-#endif // WIN32
-#endif // __APPLE_CC__
-
-// windows, hardcoded limits for now...
-// for e.g. MSVC compiler...
-// some of these defines can be needed
-// for linux systems as well (e.g. FLT_MAX)
-#ifndef __FLT_MAX__
-# ifdef FLT_MAX // try to use it instead
-# define __FLT_MAX__ FLT_MAX
-# else // FLT_MAX
-# define __FLT_MAX__ 3.402823466e+38f
-# endif // FLT_MAX
-#endif // __FLT_MAX__
-#ifndef __DBL_MAX__
-# ifdef DBL_MAX // try to use it instead
-# define __DBL_MAX__ DBL_MAX
-# else // DBL_MAX
-# define __DBL_MAX__ 1.7976931348623158e+308
-# endif // DBL_MAX
-#endif // __DBL_MAX__
-
-#ifndef M_PI
-#define M_PI 3.1415926536
-#endif
-
-#ifndef M_E
-#define M_E 2.7182818284
-#endif
-
-// make sure elbeem plugin def is valid
-#if ELBEEM_BLENDER==1
-#ifndef ELBEEM_PLUGIN
-#define ELBEEM_PLUGIN 1
-#endif // !ELBEEM_PLUGIN
-#endif // ELBEEM_BLENDER==1
-
-// make sure GUI support is disabled for plugin use
-#if ELBEEM_PLUGIN==1
-#ifndef NOGUI
-#define NOGUI 1
-#endif // !NOGUI
-#endif // ELBEEM_PLUGIN==1
-
-
-// basic inlined vector class
-template<class Scalar>
-class ntlVector3Dim
-{
-public:
- // Constructor
- inline ntlVector3Dim(void );
- // Copy-Constructor
- inline ntlVector3Dim(const ntlVector3Dim<Scalar> &v );
- inline ntlVector3Dim(const float *);
- inline ntlVector3Dim(const double *);
- // construct a vector from one Scalar
- inline ntlVector3Dim(Scalar);
- // construct a vector from three Scalars
- inline ntlVector3Dim(Scalar, Scalar, Scalar);
-
- // get address of array for OpenGL
- Scalar *getAddress() { return value; }
-
- // Assignment operator
- inline const ntlVector3Dim<Scalar>& operator= (const ntlVector3Dim<Scalar>& v);
- // Assignment operator
- inline const ntlVector3Dim<Scalar>& operator= (Scalar s);
- // Assign and add operator
- inline const ntlVector3Dim<Scalar>& operator+= (const ntlVector3Dim<Scalar>& v);
- // Assign and add operator
- inline const ntlVector3Dim<Scalar>& operator+= (Scalar s);
- // Assign and sub operator
- inline const ntlVector3Dim<Scalar>& operator-= (const ntlVector3Dim<Scalar>& v);
- // Assign and sub operator
- inline const ntlVector3Dim<Scalar>& operator-= (Scalar s);
- // Assign and mult operator
- inline const ntlVector3Dim<Scalar>& operator*= (const ntlVector3Dim<Scalar>& v);
- // Assign and mult operator
- inline const ntlVector3Dim<Scalar>& operator*= (Scalar s);
- // Assign and div operator
- inline const ntlVector3Dim<Scalar>& operator/= (const ntlVector3Dim<Scalar>& v);
- // Assign and div operator
- inline const ntlVector3Dim<Scalar>& operator/= (Scalar s);
-
-
- // unary operator
- inline ntlVector3Dim<Scalar> operator- () const;
-
- // binary operator add
- inline ntlVector3Dim<Scalar> operator+ (const ntlVector3Dim<Scalar>&) const;
- // binary operator add
- inline ntlVector3Dim<Scalar> operator+ (Scalar) const;
- // binary operator sub
- inline ntlVector3Dim<Scalar> operator- (const ntlVector3Dim<Scalar>&) const;
- // binary operator sub
- inline ntlVector3Dim<Scalar> operator- (Scalar) const;
- // binary operator mult
- inline ntlVector3Dim<Scalar> operator* (const ntlVector3Dim<Scalar>&) const;
- // binary operator mult
- inline ntlVector3Dim<Scalar> operator* (Scalar) const;
- // binary operator div
- inline ntlVector3Dim<Scalar> operator/ (const ntlVector3Dim<Scalar>&) const;
- // binary operator div
- inline ntlVector3Dim<Scalar> operator/ (Scalar) const;
-
- // Projection normal to a vector
- inline ntlVector3Dim<Scalar> getOrthogonalntlVector3Dim() const;
- // Project into a plane
- inline const ntlVector3Dim<Scalar>& projectNormalTo(const ntlVector3Dim<Scalar> &v);
-
- // minimize
- inline const ntlVector3Dim<Scalar> &minimize(const ntlVector3Dim<Scalar> &);
- // maximize
- inline const ntlVector3Dim<Scalar> &maximize(const ntlVector3Dim<Scalar> &);
-
- // access operator
- inline Scalar& operator[](unsigned int i);
- // access operator
- inline const Scalar& operator[](unsigned int i) const;
-
-protected:
-
-private:
- Scalar value[3]; //< Storage of vector values
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlVector3Dim")
-#endif
-};
-
-
-
-
-//------------------------------------------------------------------------------
-// STREAM FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-//! global string for formatting vector output in utilities.cpp
-extern const char *globVecFormatStr;
-
-/*************************************************************************
- Outputs the object in human readable form using the format
- [x,y,z]
- */
-template<class Scalar>
-std::ostream&
-operator<<( std::ostream& os, const ntlVector3Dim<Scalar>& i )
-{
- char buf[256];
- snprintf(buf,256,globVecFormatStr,i[0],i[1],i[2]);
- os << string(buf);
- //os << '[' << i[0] << ", " << i[1] << ", " << i[2] << ']';
- return os;
-}
-
-
-
-/*************************************************************************
- Reads the contents of the object from a stream using the same format
- as the output operator.
- */
-template<class Scalar>
-std::istream&
-operator>>( std::istream& is, ntlVector3Dim<Scalar>& i )
-{
- char c;
- char dummy[3];
- is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c;
- return is;
-}
-
-
-//------------------------------------------------------------------------------
-// VECTOR inline FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Constructor.
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim( void )
-{
- value[0] = value[1] = value[2] = 0;
-}
-
-
-
-/*************************************************************************
- Copy-Constructor.
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim( const ntlVector3Dim<Scalar> &v )
-{
- value[0] = v.value[0];
- value[1] = v.value[1];
- value[2] = v.value[2];
-}
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim( const float *fvalue)
-{
- value[0] = (Scalar)fvalue[0];
- value[1] = (Scalar)fvalue[1];
- value[2] = (Scalar)fvalue[2];
-}
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim( const double *fvalue)
-{
- value[0] = (Scalar)fvalue[0];
- value[1] = (Scalar)fvalue[1];
- value[2] = (Scalar)fvalue[2];
-}
-
-
-
-/*************************************************************************
- Constructor for a vector from a single Scalar. All components of
- the vector get the same value.
- \param s The value to set
- \return The new vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim(Scalar s )
-{
- value[0]= s;
- value[1]= s;
- value[2]= s;
-}
-
-
-/*************************************************************************
- Constructor for a vector from three Scalars.
- \param s1 The value for the first vector component
- \param s2 The value for the second vector component
- \param s3 The value for the third vector component
- \return The new vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim(Scalar s1, Scalar s2, Scalar s3)
-{
- value[0]= s1;
- value[1]= s2;
- value[2]= s3;
-}
-
-
-/*************************************************************************
- Compute the vector product of two 3D vectors
- \param v Second vector to compute the product with
- \return A new vector with the product values
- */
-/*template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator^( const ntlVector3Dim<Scalar> &v ) const
-{
- return ntlVector3Dim<Scalar>(value[1]*v.value[2] - value[2]*v.value[1],
- value[2]*v.value[0] - value[0]*v.value[2],
- value[0]*v.value[1] - value[1]*v.value[0]);
-}*/
-
-
-/*************************************************************************
- Copy a ntlVector3Dim componentwise.
- \param v vector with values to be copied
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator=( const ntlVector3Dim<Scalar> &v )
-{
- value[0] = v.value[0];
- value[1] = v.value[1];
- value[2] = v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Copy a Scalar to each component.
- \param s The value to copy
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator=(Scalar s)
-{
- value[0] = s;
- value[1] = s;
- value[2] = s;
- return *this;
-}
-
-
-/*************************************************************************
- Add another ntlVector3Dim componentwise.
- \param v vector with values to be added
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator+=( const ntlVector3Dim<Scalar> &v )
-{
- value[0] += v.value[0];
- value[1] += v.value[1];
- value[2] += v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Add a Scalar value to each component.
- \param s Value to add
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator+=(Scalar s)
-{
- value[0] += s;
- value[1] += s;
- value[2] += s;
- return *this;
-}
-
-
-/*************************************************************************
- Subtract another vector componentwise.
- \param v vector of values to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator-=( const ntlVector3Dim<Scalar> &v )
-{
- value[0] -= v.value[0];
- value[1] -= v.value[1];
- value[2] -= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Subtract a Scalar value from each component.
- \param s Value to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator-=(Scalar s)
-{
- value[0]-= s;
- value[1]-= s;
- value[2]-= s;
- return *this;
-}
-
-
-/*************************************************************************
- Multiply with another vector componentwise.
- \param v vector of values to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator*=( const ntlVector3Dim<Scalar> &v )
-{
- value[0] *= v.value[0];
- value[1] *= v.value[1];
- value[2] *= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Multiply each component with a Scalar value.
- \param s Value to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator*=(Scalar s)
-{
- value[0] *= s;
- value[1] *= s;
- value[2] *= s;
- return *this;
-}
-
-
-/*************************************************************************
- Divide by another ntlVector3Dim componentwise.
- \param v vector of values to divide by
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator/=( const ntlVector3Dim<Scalar> &v )
-{
- value[0] /= v.value[0];
- value[1] /= v.value[1];
- value[2] /= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Divide each component by a Scalar value.
- \param s Value to divide by
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator/=(Scalar s)
-{
- value[0] /= s;
- value[1] /= s;
- value[2] /= s;
- return *this;
-}
-
-
-//------------------------------------------------------------------------------
-// unary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build componentwise the negative this vector.
- \return The new (negative) vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator-() const
-{
- return ntlVector3Dim<Scalar>(-value[0], -value[1], -value[2]);
-}
-
-
-
-//------------------------------------------------------------------------------
-// binary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build a vector with another vector added componentwise.
- \param v The second vector to add
- \return The sum vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator+( const ntlVector3Dim<Scalar> &v ) const
-{
- return ntlVector3Dim<Scalar>(value[0]+v.value[0],
- value[1]+v.value[1],
- value[2]+v.value[2]);
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value added to each component.
- \param s The Scalar value to add
- \return The sum vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator+(Scalar s) const
-{
- return ntlVector3Dim<Scalar>(value[0]+s,
- value[1]+s,
- value[2]+s);
-}
-
-
-/*************************************************************************
- Build a vector with another vector subtracted componentwise.
- \param v The second vector to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator-( const ntlVector3Dim<Scalar> &v ) const
-{
- return ntlVector3Dim<Scalar>(value[0]-v.value[0],
- value[1]-v.value[1],
- value[2]-v.value[2]);
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value subtracted componentwise.
- \param s The Scalar value to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator-(Scalar s ) const
-{
- return ntlVector3Dim<Scalar>(value[0]-s,
- value[1]-s,
- value[2]-s);
-}
-
-
-
-/*************************************************************************
- Build a vector with another vector multiplied by componentwise.
- \param v The second vector to muliply with
- \return The product vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator*( const ntlVector3Dim<Scalar>& v) const
-{
- return ntlVector3Dim<Scalar>(value[0]*v.value[0],
- value[1]*v.value[1],
- value[2]*v.value[2]);
-}
-
-
-/*************************************************************************
- Build a ntlVector3Dim with a Scalar value multiplied to each component.
- \param s The Scalar value to multiply with
- \return The product vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator*(Scalar s) const
-{
- return ntlVector3Dim<Scalar>(value[0]*s, value[1]*s, value[2]*s);
-}
-
-
-/*************************************************************************
- Build a vector divided componentwise by another vector.
- \param v The second vector to divide by
- \return The ratio vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator/(const ntlVector3Dim<Scalar>& v) const
-{
- return ntlVector3Dim<Scalar>(value[0]/v.value[0],
- value[1]/v.value[1],
- value[2]/v.value[2]);
-}
-
-
-
-/*************************************************************************
- Build a vector divided componentwise by a Scalar value.
- \param s The Scalar value to divide by
- \return The ratio vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator/(Scalar s) const
-{
- return ntlVector3Dim<Scalar>(value[0]/s,
- value[1]/s,
- value[2]/s);
-}
-
-
-
-
-
-/*************************************************************************
- Get a particular component of the vector.
- \param i Number of Scalar to get
- \return Reference to the component
- */
-template<class Scalar>
-inline Scalar&
-ntlVector3Dim<Scalar>::operator[]( unsigned int i )
-{
- return value[i];
-}
-
-
-/*************************************************************************
- Get a particular component of a constant vector.
- \param i Number of Scalar to get
- \return Reference to the component
- */
-template<class Scalar>
-inline const Scalar&
-ntlVector3Dim<Scalar>::operator[]( unsigned int i ) const
-{
- return value[i];
-}
-
-
-
-//------------------------------------------------------------------------------
-// BLITZ compatibility functions
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Compute the scalar product with another vector.
- \param v The second vector to work with
- \return The value of the scalar product
- */
-template<class Scalar>
-inline Scalar dot(const ntlVector3Dim<Scalar> &t, const ntlVector3Dim<Scalar> &v )
-{
- //return t.value[0]*v.value[0] + t.value[1]*v.value[1] + t.value[2]*v.value[2];
- return ((t[0]*v[0]) + (t[1]*v[1]) + (t[2]*v[2]));
-}
-
-
-/*************************************************************************
- Calculate the cross product of this and another vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar> cross(const ntlVector3Dim<Scalar> &t, const ntlVector3Dim<Scalar> &v)
-{
- ntlVector3Dim<Scalar> cp(
- ((t[1]*v[2]) - (t[2]*v[1])),
- ((t[2]*v[0]) - (t[0]*v[2])),
- ((t[0]*v[1]) - (t[1]*v[0])) );
- return cp;
-}
-
-
-
-
-/*************************************************************************
- Compute a vector that is orthonormal to self. Nothing else can be assumed
- for the direction of the new vector.
- \return The orthonormal vector
- */
-template<class Scalar>
-ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::getOrthogonalntlVector3Dim() const
-{
- // Determine the component with max. absolute value
- int max= (fabs(value[0]) > fabs(value[1])) ? 0 : 1;
- max= (fabs(value[max]) > fabs(value[2])) ? max : 2;
-
- /*************************************************************************
- Choose another axis than the one with max. component and project
- orthogonal to self
- */
- ntlVector3Dim<Scalar> vec(0.0);
- vec[(max+1)%3]= 1;
- vec.normalize();
- vec.projectNormalTo(this->getNormalized());
- return vec;
-}
-
-
-/*************************************************************************
- Projects the vector into a plane normal to the given vector, which must
- have unit length. Self is modified.
- \param v The plane normal
- \return The projected vector
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::projectNormalTo(const ntlVector3Dim<Scalar> &v)
-{
- Scalar sprod = dot(*this,v);
- value[0]= value[0] - v.value[0] * sprod;
- value[1]= value[1] - v.value[1] * sprod;
- value[2]= value[2] - v.value[2] * sprod;
- return *this;
-}
-
-
-
-//------------------------------------------------------------------------------
-// Other helper functions
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Minimize the vector, i.e. set each entry of the vector to the minimum
- of both values.
- \param pnt The second vector to compare with
- \return Reference to the modified self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar> &
-ntlVector3Dim<Scalar>::minimize(const ntlVector3Dim<Scalar> &pnt)
-{
- for (unsigned int i = 0; i < 3; i++)
- value[i] = MIN(value[i],pnt[i]);
- return *this;
-}
-
-
-
-/*************************************************************************
- Maximize the vector, i.e. set each entry of the vector to the maximum
- of both values.
- \param pnt The second vector to compare with
- \return Reference to the modified self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar> &
-ntlVector3Dim<Scalar>::maximize(const ntlVector3Dim<Scalar> &pnt)
-{
- for (unsigned int i = 0; i < 3; i++)
- value[i] = MAX(value[i],pnt[i]);
- return *this;
-}
-
-
-
-
-// ----
-
-// a 3D vector with double precision
-typedef ntlVector3Dim<double> ntlVec3d;
-
-// a 3D vector with single precision
-typedef ntlVector3Dim<float> ntlVec3f;
-
-// a 3D integer vector
-typedef ntlVector3Dim<int> ntlVec3i;
-
-// Color uses single precision fp values
-typedef ntlVec3f ntlColor;
-
-/* convert a float to double vector */
-template<class T> inline ntlVec3d vec2D(T v) { return ntlVec3d(v[0],v[1],v[2]); }
-template<class T> inline ntlVec3f vec2F(T v) { return ntlVec3f(v[0],v[1],v[2]); }
-template<class T> inline ntlColor vec2Col(T v) { return ntlColor(v[0],v[1],v[2]); }
-
-
-
-/************************************************************************/
-// graphics vector typing
-
-
-// use which fp-precision for raytracing? 1=float, 2=double
-
-/* VECTOR_EPSILON is the minimal vector length
- In order to be able to discriminate floating point values near zero, and
- to be sure not to fail a comparison because of roundoff errors, use this
- value as a threshold. */
-
-// use which fp-precision for graphics? 1=float, 2=double
-#ifdef PRECISION_GFX_SINGLE
-#define GFX_PRECISION 1
-#else
-#ifdef PRECISION_GFX_DOUBLE
-#define GFX_PRECISION 2
-#else
-// standard precision for graphics
-#ifndef GFX_PRECISION
-#define GFX_PRECISION 1
-#endif
-#endif
-#endif
-
-#if GFX_PRECISION==1
-typedef float gfxReal;
-#define GFX_REAL_MAX __FLT_MAX__
-//#define vecF2Gfx(x) (x)
-//#define vecGfx2F(x) (x)
-//#define vecD2Gfx(x) vecD2F(x)
-//#define vecGfx2D(x) vecF2D(x)
-#define VECTOR_EPSILON (1e-5f)
-#else
-typedef double gfxReal;
-#define GFX_REAL_MAX __DBL_MAX__
-//#define vecF2Gfx(x) vecD2F(x)
-//#define vecGfx2F(x) vecF2D(x)
-//#define vecD2Gfx(x) (x)
-//#define vecGfx2D(x) (x)
-#define VECTOR_EPSILON (1e-10)
-#endif
-
-/* fixed double prec. type, for epxlicitly double values */
-typedef double gfxDouble;
-
-// a 3D vector for graphics output, typically float?
-typedef ntlVector3Dim<gfxReal> ntlVec3Gfx;
-
-template<class T> inline ntlVec3Gfx vec2G(T v) { return ntlVec3Gfx(v[0],v[1],v[2]); }
-
-/* get minimal vector length value that can be discriminated. */
-//inline double getVecEpsilon() { return (double)VECTOR_EPSILON; }
-inline gfxReal getVecEpsilon() { return (gfxReal)VECTOR_EPSILON; }
-
-#define HAVE_GFXTYPES
-
-
-
-
-/************************************************************************/
-// HELPER FUNCTIONS, independent of implementation
-/************************************************************************/
-
-#define VECTOR_TYPE ntlVector3Dim<Scalar>
-
-
-/*************************************************************************
- Compute the length (norm) of the vector.
- \return The value of the norm
- */
-template<class Scalar>
-inline Scalar norm( const VECTOR_TYPE &v)
-{
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- return (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) ? 1. : sqrt(l);
-}
-
-
-/*************************************************************************
- Same as getNorm but doesnt sqrt
- */
-template<class Scalar>
-inline Scalar normNoSqrt( const VECTOR_TYPE &v)
-{
- return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
-}
-
-
-/*************************************************************************
- Compute a normalized vector based on this vector.
- \return The new normalized vector
- */
-template<class Scalar>
-inline VECTOR_TYPE getNormalized( const VECTOR_TYPE &v)
-{
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON)
- return v; /* normalized "enough"... */
- else if (l > VECTOR_EPSILON*VECTOR_EPSILON)
- {
- Scalar fac = 1./sqrt(l);
- return VECTOR_TYPE(v[0]*fac, v[1]*fac, v[2]*fac);
- }
- else
- return VECTOR_TYPE((Scalar)0);
-}
-
-
-/*************************************************************************
- Compute the norm of the vector and normalize it.
- \return The value of the norm
- */
-template<class Scalar>
-inline Scalar normalize( VECTOR_TYPE &v)
-{
- Scalar norm;
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) {
- norm = 1.;
- } else if (l > VECTOR_EPSILON*VECTOR_EPSILON) {
- norm = sqrt(l);
- Scalar fac = 1./norm;
- v[0] *= fac;
- v[1] *= fac;
- v[2] *= fac;
- } else {
- v[0]= v[1]= v[2]= 0;
- norm = 0.;
- }
- return (Scalar)norm;
-}
-
-
-/*************************************************************************
- Compute a vector, that is self (as an incoming
- vector) reflected at a surface with a distinct normal vector. Note
- that the normal is reversed, if the scalar product with it is positive.
- \param n The surface normal
- \return The new reflected vector
- */
-template<class Scalar>
-inline VECTOR_TYPE reflectVector(const VECTOR_TYPE &t, const VECTOR_TYPE &n)
-{
- VECTOR_TYPE nn= (dot(t, n) > 0.0) ? (n*-1.0) : n;
- return ( t - nn * (2.0 * dot(nn, t)) );
-}
-
-
-
-/*************************************************************************
- * My own refraction calculation
- * Taken from Glassner's book, section 5.2 (Heckberts method)
- */
-template<class Scalar>
-inline VECTOR_TYPE refractVector(const VECTOR_TYPE &t, const VECTOR_TYPE &normal, Scalar nt, Scalar nair, int &refRefl)
-{
- Scalar eta = nair / nt;
- Scalar n = -dot(t, normal);
- Scalar tt = 1.0 + eta*eta* (n*n-1.0);
- if(tt<0.0) {
- // we have total reflection!
- refRefl = 1;
- } else {
- // normal reflection
- tt = eta*n - sqrt(tt);
- return( t*eta + normal*tt );
- }
- return t;
-}
- /*double eta = nair / nt;
- double n = -((*this) | normal);
- double t = 1.0 + eta*eta* (n*n-1.0);
- if(t<0.0) {
- // we have total reflection!
- refRefl = 1;
- } else {
- // normal reflection
- t = eta*n - sqrt(t);
- return( (*this)*eta + normal*t );
- }
- return (*this);*/
-
-
-/*************************************************************************
- Test two ntlVector3Dims for equality based on the equality of their
- values within a small threshold.
- \param c The second vector to compare
- \return TRUE if both are equal
- \sa getEpsilon()
- */
-template<class Scalar>
-inline bool equal(const VECTOR_TYPE &v, const VECTOR_TYPE &c)
-{
- return (ABS(v[0]-c[0]) +
- ABS(v[1]-c[1]) +
- ABS(v[2]-c[2]) < VECTOR_EPSILON);
-}
-
-
-/*************************************************************************
- * Assume this vector is an RGB color, and convert it to HSV
- */
-template<class Scalar>
-inline void rgbToHsv( VECTOR_TYPE &V )
-{
- Scalar h=0,s=0,v=0;
- Scalar maxrgb, minrgb, delta;
- // convert to hsv...
- maxrgb = V[0];
- int maxindex = 1;
- if(V[2] > maxrgb){ maxrgb = V[2]; maxindex = 2; }
- if(V[1] > maxrgb){ maxrgb = V[1]; maxindex = 3; }
- minrgb = V[0];
- if(V[2] < minrgb) minrgb = V[2];
- if(V[1] < minrgb) minrgb = V[1];
-
- v = maxrgb;
- delta = maxrgb-minrgb;
-
- if(maxrgb > 0) s = delta/maxrgb;
- else s = 0;
-
- h = 0;
- if(s > 0) {
- if(maxindex == 1) {
- h = ((V[1]-V[2])/delta) + 0.0; }
- if(maxindex == 2) {
- h = ((V[2]-V[0])/delta) + 2.0; }
- if(maxindex == 3) {
- h = ((V[0]-V[1])/delta) + 4.0; }
- h *= 60.0;
- if(h < 0.0) h += 360.0;
- }
-
- V[0] = h;
- V[1] = s;
- V[2] = v;
-}
-
-/*************************************************************************
- * Assume this vector is HSV and convert to RGB
- */
-template<class Scalar>
-inline void hsvToRgb( VECTOR_TYPE &V )
-{
- Scalar h = V[0], s = V[1], v = V[2];
- Scalar r=0,g=0,b=0;
- Scalar p,q,t, fracth;
- int floorh;
- // ...and back to rgb
- if(s == 0) {
- r = g = b = v; }
- else {
- h /= 60.0;
- floorh = (int)h;
- fracth = h - floorh;
- p = v * (1.0 - s);
- q = v * (1.0 - (s * fracth));
- t = v * (1.0 - (s * (1.0 - fracth)));
- switch (floorh) {
- case 0: r = v; g = t; b = p; break;
- case 1: r = q; g = v; b = p; break;
- case 2: r = p; g = v; b = t; break;
- case 3: r = p; g = q; b = v; break;
- case 4: r = t; g = p; b = v; break;
- case 5: r = v; g = p; b = q; break;
- }
- }
-
- V[0] = r;
- V[1] = g;
- V[2] = b;
-}
-
-
-
-
-#endif /* NTL_VECTOR3DIM_HH */
diff --git a/intern/elbeem/intern/ntl_world.cpp b/intern/elbeem/intern/ntl_world.cpp
deleted file mode 100644
index 5f3d6e36b3b..00000000000
--- a/intern/elbeem/intern/ntl_world.cpp
+++ /dev/null
@@ -1,934 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Main renderer class
- *
- *****************************************************************************/
-
-
-#include <sys/stat.h>
-#include <sstream>
-#include "utilities.h"
-#include "ntl_world.h"
-#include "parametrizer.h"
-
-// for non-threaded renderViz
-#ifndef NOGUI
-#include "../gui/ntl_openglrenderer.h"
-#include "../gui/guifuncs.h"
-#include "../gui/frame.h"
-#endif
-
-
-/* external parser functions from cfgparser.cxx */
-#ifndef ELBEEM_PLUGIN
-/* parse given file as config file */
-void parseFile(string filename);
-/* set pointers for parsing */
-void setPointers( ntlRenderGlobals *setglob);
-#endif // ELBEEM_PLUGIN
-
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-
-ntlWorld::ntlWorld() {
- initDefaults();
-}
-
-ntlWorld::ntlWorld(string filename, bool commandlineMode)
-{
-#ifndef ELBEEM_PLUGIN
-
- initDefaults();
-# ifdef NOGUI
- commandlineMode = true; // remove warning...
-# endif // NOGUI
-
- // load config
- setPointers( getRenderGlobals() );
- parseFile( filename.c_str() );
-# ifndef NOGUI
- // setup opengl display, save first animation step for start time
- // init after parsing file...
- if(!commandlineMode) {
- mpOpenGLRenderer = new ntlOpenGLRenderer( mpGlob );
- }
-# endif // NOGUI
- finishWorldInit();
-
-#else // ELBEEM_PLUGIN
- errFatal("ntlWorld::init","Cfg file parsing not supported for API version! "<<filename<<" "<<commandlineMode, SIMWORLD_INITERROR);
-#endif // ELBEEM_PLUGIN
-}
-
-
-int globalDomainCounter = 1;
-int ntlWorld::addDomain(elbeemSimulationSettings *settings)
-{
- // create domain obj
- SimulationObject *sim = new SimulationObject();
- char simname[100];
- snprintf(simname,100,"domain%04d",globalDomainCounter);
- globalDomainCounter++;
- sim->setName(string(simname));
- mpGlob->getSims()->push_back( sim );
-
- // important - add to both, only render scene objects are free'd
- mpGlob->getRenderScene()->addGeoClass( sim );
- mpGlob->getSimScene()->addGeoClass( sim );
- sim->setGeoStart(ntlVec3Gfx(settings->geoStart[0],settings->geoStart[1],settings->geoStart[2]));
- sim->setGeoEnd(ntlVec3Gfx(
- settings->geoStart[0]+settings->geoSize[0],
- settings->geoStart[1]+settings->geoSize[1],
- settings->geoStart[2]+settings->geoSize[2] ));
- // further init in postGeoConstrInit/initializeLbmSimulation of SimulationObject
- sim->copyElbeemSettings(settings);
-
- Parametrizer *param = sim->getParametrizer();
- param->setSize( settings->resolutionxyz );
- param->setDomainSize( settings->realsize );
- param->setAniStart( settings->animStart );
- param->setNormalizedGStar( settings->gstar );
-
- // init domain channels
- vector<ParamFloat> valf;
- vector<ParamVec> valv;
- vector<double> time;
-
-#define INIT_CHANNEL_FLOAT(channel,size) \
- valf.clear(); time.clear(); elbeemSimplifyChannelFloat(channel,&size); \
- for(int i=0; i<size; i++) { valf.push_back( channel[2*i+0] ); time.push_back( channel[2*i+1] ); }
-#define INIT_CHANNEL_VEC(channel,size) \
- valv.clear(); time.clear(); elbeemSimplifyChannelVec3(channel,&size); \
- for(int i=0; i<size; i++) { valv.push_back( ParamVec(channel[4*i+0],channel[4*i+1],channel[4*i+2]) ); time.push_back( channel[4*i+3] ); }
-
- param->setViscosity( settings->viscosity );
- if((settings->channelViscosity)&&(settings->channelSizeViscosity>0)) {
- INIT_CHANNEL_FLOAT(settings->channelViscosity, settings->channelSizeViscosity);
- param->initViscosityChannel(valf,time); }
-
- param->setGravity( ParamVec(settings->gravity[0], settings->gravity[1], settings->gravity[2]) );
- if((settings->channelGravity)&&(settings->channelSizeGravity>0)) {
- INIT_CHANNEL_VEC(settings->channelGravity, settings->channelSizeGravity);
- param->initGravityChannel(valv,time); }
-
- param->setAniFrameTimeChannel( settings->aniFrameTime );
- if((settings->channelFrameTime)&&(settings->channelSizeFrameTime>0)) {
- INIT_CHANNEL_FLOAT(settings->channelFrameTime, settings->channelSizeFrameTime);
- param->initAniFrameTimeChannel(valf,time); }
-
-#undef INIT_CHANNEL_FLOAT
-#undef INIT_CHANNEL_VEC
-
- // might be set by previous domain
- if(mpGlob->getAniFrames() < settings->noOfFrames) mpGlob->setAniFrames( settings->noOfFrames );
- // set additionally to SimulationObject->mOutFilename
- mpGlob->setOutFilename( settings->outputPath );
-
- return 0;
-}
-
-void ntlWorld::initDefaults()
-{
- mStopRenderVisualization = false;
- mThreadRunning = false;
- mSimulationTime = 0.0;
- mFirstSim = 1;
- mSingleStepDebug = false;
- mFrameCnt = 0;
- mSimFrameCnt = 0;
- mpOpenGLRenderer = NULL;
-
- /* create scene storage */
- mpGlob = new ntlRenderGlobals();
- mpLightList = new vector<ntlLightObject*>;
- mpPropList = new vector<ntlMaterial*>;
- mpSims = new vector<SimulationObject*>;
-
- mpGlob->setLightList(mpLightList);
- mpGlob->setMaterials(mpPropList);
- mpGlob->setSims(mpSims);
-
- /* init default material */
- ntlMaterial *def = GET_GLOBAL_DEFAULT_MATERIAL;
- mpPropList->push_back( def );
-
- /* init the scene object */
- ntlScene *renderscene = new ntlScene( mpGlob, true );
- mpGlob->setRenderScene( renderscene );
- // sim scene shouldnt delete objs, may only contain subset
- ntlScene *simscene = new ntlScene( mpGlob, false );
- mpGlob->setSimScene( simscene );
-}
-
-void ntlWorld::finishWorldInit()
-{
- if(! isSimworldOk() ) return;
-
- // init the scene for the first time
- long sstartTime = getTime();
-
- // first init sim scene for geo setup
- mpGlob->getSimScene()->buildScene(0.0, true);
- if(! isSimworldOk() ) return;
- mpGlob->getRenderScene()->buildScene(0.0, true);
- if(! isSimworldOk() ) return;
- long sstopTime = getTime();
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Scene build time: "<< getTimeString(sstopTime-sstartTime) <<" ", 10);
-
- // TODO check simulations, run first steps
- mFirstSim = -1;
- if(mpSims->size() > 0) {
-
- // use values from first simulation as master time scale
- long startTime = getTime();
-
- // remember first active sim
- for(size_t i=0;i<mpSims->size();i++) {
- if(!(*mpSims)[i]->getVisible()) continue;
- if((*mpSims)[i]->getPanic()) continue;
-
- // check largest timestep
- if(mFirstSim>=0) {
- if( (*mpSims)[i]->getTimestep() > (*mpSims)[mFirstSim]->getTimestep() ) {
- mFirstSim = i;
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"First Sim changed: "<<i ,10);
- }
- }
- // check any valid sim
- if(mFirstSim<0) {
- mFirstSim = i;
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"First Sim: "<<i ,10);
- }
- }
-
- if(mFirstSim>=0) {
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime() ,10);
- while(mSimulationTime < (*mpSims)[mFirstSim]->getStartTime() ) {
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime()<<" simtime:"<<mSimulationTime ,10);
- advanceSims(-1);
- }
- long stopTime = getTime();
-
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Time for start-sims:"<< getTimeString(stopTime-startTime) , 1);
-#ifndef NOGUI
- guiResetSimulationTimeRange( mSimulationTime );
-#endif
- } else {
- if(!mpGlob->getSingleFrameMode()) debMsgStd("ntlWorld::ntlWorld",DM_WARNING,"No active simulations!", 1);
- }
- }
-
- if(! isSimworldOk() ) return;
- setElbeemState( SIMWORLD_INITED );
-}
-
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlWorld::~ntlWorld()
-{
- delete mpGlob->getRenderScene();
- delete mpGlob->getSimScene();
-
- delete mpGlob;
-
-
- // these get assigned to mpGlob but not freed there
- delete mpLightList;
- delete mpPropList; // materials
- delete mpSims;
-
-#ifndef NOGUI
- if(mpOpenGLRenderer) delete mpOpenGLRenderer;
-#endif // NOGUI
- debMsgStd("ntlWorld",DM_NOTIFY, "ntlWorld done", 10);
-}
-
-/******************************************************************************/
-/*! set single frame rendering to filename */
-void ntlWorld::setSingleFrameOut(string singleframeFilename) {
- mpGlob->setSingleFrameMode(true);
- mpGlob->setSingleFrameFilename(singleframeFilename);
-}
-
-/******************************************************************************
- * render a whole animation (command line mode)
- *****************************************************************************/
-
-int ntlWorld::renderAnimation( void )
-{
- // only single pic currently
- //debMsgStd("ntlWorld::renderAnimation : Warning only simulating...",1);
- if(mpGlob->getAniFrames() < 0) {
- debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No frames to render... ",1);
- return 1;
- }
-
- if(mFirstSim<0) {
- debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No reference animation found...",1);
- return 1;
- }
-
- mThreadRunning = true; // not threaded, but still use the same flags
- if(getElbeemState() == SIMWORLD_INITED) {
- renderScene();
- } else if(getElbeemState() == SIMWORLD_STOP) {
- // dont render now, just continue
- setElbeemState( SIMWORLD_INITED );
- mFrameCnt--; // counted one too many from last abort...
- } else {
- debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"Not properly inited, stopping...",1);
- return 1;
- }
-
- if(mpSims->size() <= 0) {
- debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No simulations found, stopping...",1);
- return 1;
- }
-
- bool simok = true;
- for( ; ((mFrameCnt<mpGlob->getAniFrames()) && (!getStopRenderVisualization() ) && (simok)); mFrameCnt++) {
- if(!advanceSims(mFrameCnt)) {
- renderScene();
- } // else means sim panicked, so dont render...
- else { simok=false; }
- }
- mThreadRunning = false;
- return 0;
-}
-
-/******************************************************************************
- * render a whole animation (visualization mode)
- * this function is run in another thread, and communicates
- * with the parent thread via a mutex
- *****************************************************************************/
-int ntlWorld::renderVisualization( bool multiThreaded )
-{
-#ifndef NOGUI
- if(getElbeemState() != SIMWORLD_INITED) { return 0; }
-
- if(multiThreaded) mThreadRunning = true;
- // TODO, check global state?
- while(!getStopRenderVisualization()) {
-
- if(mpSims->size() <= 0) {
- debMsgStd("ntlWorld::renderVisualization",DM_NOTIFY,"No simulations found, stopping...",1);
- stopSimulationThread();
- break;
- }
-
- // determine stepsize
- if(!mSingleStepDebug) {
- long startTime = getTime();
- advanceSims(mFrameCnt);
- mFrameCnt++;
- long stopTime = getTime();
- debMsgStd("ntlWorld::renderVisualization",DM_MSG,"Time for t="<<mSimulationTime<<": "<< getTimeString(stopTime-startTime) <<" ", 10);
- } else {
- double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
- singleStepSims(targetTime);
-
- // check paniced sims (normally done by advanceSims
- bool allPanic = true;
- for(size_t i=0;i<mpSims->size();i++) {
- if(!(*mpSims)[i]->getPanic()) allPanic = false;
- }
- if(allPanic) {
- warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" );
- setStopRenderVisualization( true );
- }
- if(! isSimworldOk() ) {
- warnMsg("ntlWorld::advanceSims","World state error... stopping" );
- setStopRenderVisualization( true );
- }
- }
-
- // save frame
- if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
-
- // for non-threaded check events
- if(!multiThreaded) {
- Fl::check();
- gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
- }
-
- }
- mThreadRunning = false;
- stopSimulationRestoreGui();
-#else
- multiThreaded = false; // remove warning
-#endif
- return 0;
-}
-/*! render a single step for viz mode */
-int ntlWorld::singleStepVisualization( void )
-{
- mThreadRunning = true;
- double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
- singleStepSims(targetTime);
- mSimulationTime = (*mpSims)[0]->getCurrentTime();
-
-#ifndef NOGUI
- if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
- Fl::check();
- gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
- mThreadRunning = false;
- stopSimulationRestoreGui();
-#else
- mThreadRunning = false;
-#endif // NOGUI
- return 0;
-}
-
-// dont use LBM_EPSILON here, time is always double-precision!
-#define LBM_TIME_EPSILON 1e-10
-
-/******************************************************************************
- * advance simulations by time t
- *****************************************************************************/
-int ntlWorld::advanceSims(int framenum)
-{
- bool done = false;
- bool allPanic = true;
-
- // stop/quit (abort), dont display/render
- if(!isSimworldOk()) {
- return 1;
- }
-
- for(size_t i=0;i<mpSims->size();i++) { (*mpSims)[i]->setFrameNum(framenum); }
-
- // time stopped? nothing else to do...
- if( (*mpSims)[mFirstSim]->getFrameTime(framenum) <= 0.0 ){
- done=true; allPanic=false;
-
- /* DG: Need to check for user cancel here (fix for [#30298]) */
- (*mpSims)[mFirstSim]->checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0);
- }
-
- // Prevent bug [#29186] Object contribute to fluid sim animation start earlier than keyframe
- // Was: double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getFrameTime(framenum); - DG
- double totalTime = 0.0, targetTime = 0.0;
- for(size_t i = 0; i < mSimFrameCnt; i++)
- {
- /* We need an intermediate array "mSimFrameValue" because
- otherwise if we don't start with starttime = 0,
- the sim gets out of sync - DG */
- totalTime += (*mpSims)[mFirstSim]->getFrameTime(mSimFrameValue[i]);
- }
- targetTime = totalTime + (*mpSims)[mFirstSim]->getFrameTime(framenum);
-
- int gstate = 0;
- myTime_t advsstart = getTime();
-
- // step all the sims, and check for panic
- debMsgStd("ntlWorld::advanceSims",DM_MSG, " sims "<<mpSims->size()<<" t"<<targetTime<<" done:"<<done<<" panic:"<<allPanic<<" gstate:"<<gstate, 10); // debug // timedebug
- while(!done) {
- double nextTargetTime = (*mpSims)[mFirstSim]->getCurrentTime() + (*mpSims)[mFirstSim]->getTimestep();
- singleStepSims(nextTargetTime);
-
- // check target times
- done = true;
- allPanic = false;
-
- if((*mpSims)[mFirstSim]->getTimestep() <1e-9 ) {
- // safety check, avoid timesteps that are too small
- errMsg("ntlWorld::advanceSims","Invalid time step, causing panic! curr:"<<(*mpSims)[mFirstSim]->getCurrentTime()<<" next:"<<nextTargetTime<<", stept:"<< (*mpSims)[mFirstSim]->getTimestep() );
- allPanic = true;
- } else {
- for(size_t i=0;i<mpSims->size();i++) {
- if(!(*mpSims)[i]->getVisible()) continue;
- if((*mpSims)[i]->getPanic()) allPanic = true; // do any panic now!?
- debMsgStd("ntlWorld::advanceSims",DM_MSG, "Sim "<<i<<", currt:"<<(*mpSims)[i]->getCurrentTime()<<", nt:"<<nextTargetTime<<", panic:"<<(*mpSims)[i]->getPanic()<<", targett:"<<targetTime, 10); // debug // timedebug
- }
- }
- if( (targetTime - (*mpSims)[mFirstSim]->getCurrentTime()) > LBM_TIME_EPSILON) done=false;
- if(allPanic) done = true;
- }
-
- if(allPanic) {
- warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" );
- setStopRenderVisualization( true );
- return 1;
- }
-
- myTime_t advsend = getTime();
- debMsgStd("ntlWorld::advanceSims",DM_MSG,"Overall steps so far took:"<< getTimeString(advsend-advsstart)<<" for sim time "<<targetTime, 4);
-
- // finish step
- for(size_t i=0;i<mpSims->size();i++) {
- SimulationObject *sim = (*mpSims)[i];
- if(!sim->getVisible()) continue;
- if(sim->getPanic()) continue;
- sim->prepareVisualization();
- }
-
- mSimFrameValue.push_back(framenum);
- mSimFrameCnt++;
-
- return 0;
-}
-
-/* advance simulations by a single step */
-/* dont check target time, if *targetTime==NULL */
-void ntlWorld::singleStepSims(double targetTime) {
- const bool debugTime = false;
- //double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
- if(debugTime) errMsg("ntlWorld::singleStepSims","Target time: "<<targetTime);
-
- for(size_t i=0;i<mpSims->size();i++) {
- SimulationObject *sim = (*mpSims)[i];
- if(!sim->getVisible()) continue;
- if(sim->getPanic()) continue;
- bool done = false;
- while(!done) {
- // try to prevent round off errs
- if(debugTime) errMsg("ntlWorld::singleStepSims","Test sim "<<i<<" curt:"<< sim->getCurrentTime()<<" target:"<<targetTime<<" delta:"<<(targetTime - sim->getCurrentTime())<<" stept:"<<sim->getTimestep()<<" leps:"<<LBM_TIME_EPSILON ); // timedebug
- if( (targetTime - sim->getCurrentTime()) > LBM_TIME_EPSILON) {
- if(debugTime) errMsg("ntlWorld::singleStepSims","Stepping sim "<<i<<" t:"<< sim->getCurrentTime()); // timedebug
- sim->step();
- } else {
- done = true;
- }
- }
- }
-
- mSimulationTime = (*mpSims)[mFirstSim]->getCurrentTime();
-#ifndef NOGUI
- if(mpOpenGLRenderer) mpOpenGLRenderer->notifyOfNextStep(mSimulationTime);
-#endif // NOGUI
-}
-
-
-
-/******************************************************************************
- * Render the current scene
- * uses the global variables from the parser
- *****************************************************************************/
-int ntlWorld::renderScene( void )
-{
-#ifndef ELBEEM_PLUGIN
- char nrStr[5]; // nr conversion
- std::ostringstream outfn_conv(""); // converted ppm with other suffix
- ntlRenderGlobals *glob; // storage for global rendering parameters
- myTime_t timeStart,totalStart,timeEnd; // measure user running time
- myTime_t rendStart,rendEnd; // measure user rendering time
- glob = mpGlob;
-
- // deactivate for all with index!=0
- if((glob_mpactive)&&(glob_mpindex>0)) return(0);
-
- /* check if picture already exists... */
- if(!glob->getSingleFrameMode() ) {
- snprintf(nrStr, 5, "%04d", glob->getAniCount() );
-
- if(glob_mpactive) {
- outfn_conv << glob->getOutFilename() <<"_"<<glob_mpindex<<"_" << nrStr << ".png"; /// DEBUG!
- } else {
- // ORG
- outfn_conv << glob->getOutFilename() <<"_" << nrStr << ".png";
- }
-
- //if((mpGlob->getDisplayMode() == DM_RAY)&&(mpGlob->getFrameSkip())) {
- if(mpGlob->getFrameSkip()) {
- struct stat statBuf;
- if(stat(outfn_conv.str().c_str(),&statBuf) == 0) {
- errorOut("ntlWorld::renderscene Warning: file "<<outfn_conv.str()<<" already exists - skipping frame...");
- glob->setAniCount( glob->getAniCount() +1 );
- return(2);
- }
- } // RAY mode
- } else {
- // single frame rendering, overwrite if necessary...
- outfn_conv << glob->getSingleFrameFilename();
- }
-
- /* start program */
- timeStart = getTime();
-
- /* build scene geometry, calls buildScene(t,false) */
- glob->getRenderScene()->prepareScene(mSimulationTime);
-
- /* start program */
- totalStart = getTime();
-
-
- /* view parameters are currently not animated */
- /* calculate rays through projection plane */
- ntlVec3Gfx direction = glob->getLookat() - glob->getEye();
- /* calculate width of screen using perpendicular triangle diven by
- * viewing direction and screen plane */
- gfxReal screenWidth = norm(direction)*tan( (glob->getFovy()*0.5/180.0)*M_PI );
-
- /* calculate vector orthogonal to up and viewing direction */
- ntlVec3Gfx upVec = glob->getUpVec();
- ntlVec3Gfx rightVec( cross(upVec,direction) );
- normalize(rightVec);
-
- /* calculate screen plane up vector, perpendicular to viewdir and right vec */
- upVec = ntlVec3Gfx( cross(rightVec,direction) );
- normalize(upVec);
-
- /* check if vectors are valid */
- if( (equal(upVec,ntlVec3Gfx(0.0))) || (equal(rightVec,ntlVec3Gfx(0.0))) ) {
- errMsg("ntlWorld::renderScene","Invalid viewpoint vectors! up="<<upVec<<" right="<<rightVec);
- return(1);
- }
-
- /* length from center to border of screen plane */
- rightVec *= (screenWidth*glob->getAspect() * -1.0);
- upVec *= (screenWidth * -1.0);
-
- /* screen traversal variables */
- ntlVec3Gfx screenPos; /* current position on virtual screen */
- int Xres = glob->getResX(); /* X resolution */
- int Yres = glob->getResY(); /* Y resolution */
- ntlVec3Gfx rightStep = (rightVec/(Xres/2.0)); /* one step right for a pixel */
- ntlVec3Gfx upStep = (upVec/(Yres/2.0)); /* one step up for a pixel */
-
-
- /* anti alias init */
- char showAAPic = 0;
- int aaDepth = glob->getAADepth();
- int aaLength;
- if(aaDepth>=0) aaLength = (2<<aaDepth);
- else aaLength = 0;
- float aaSensRed = 0.1;
- float aaSensGreen = 0.1;
- float aaSensBlue = 0.1;
- int aaArrayX = aaLength*Xres+1;
- int aaArrayY = ( aaLength+1 );
- ntlColor *aaCol = new ntlColor[ aaArrayX*aaArrayY ];
- char *aaUse = new char[ aaArrayX*aaArrayY ];
-
- /* picture storage */
- int picX = Xres;
- int picY = Yres;
- if(showAAPic) {
- picX = Xres *aaLength+1;
- picY = Yres *aaLength+1;
- }
- ntlColor *finalPic = new ntlColor[picX * picY];
-
-
- /* reset picture vars */
- for(int j=0;j<aaArrayY;j++) {
- for(int i=0;i<aaArrayX;i++) {
- aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
- aaUse[j*aaArrayX+i] = 0;
- }
- }
- for(int j=0;j<picY;j++) {
- for(int i=0;i<picX;i++) {
- finalPic[j*picX+i] = ntlColor(0.0, 0.0, 0.0);
- }
- }
-
- /* loop over all y lines in screen, from bottom to top because
- * ppm format wants 0,0 top left */
- rendStart = getTime();
- glob->setCounterShades(0);
- glob->setCounterSceneInter(0);
- for (int scanline=Yres ; scanline > 0 ; --scanline) {
-
- debugOutInter( "ntlWorld::renderScene: Line "<<scanline<<
- " ("<< ((Yres-scanline)*100/Yres) <<"%) ", 2, 2000 );
- screenPos = glob->getLookat() + upVec*((2.0*scanline-Yres)/Yres)
- - rightVec;
-
- /* loop over all pixels in line */
- for (int sx=0 ; sx < Xres ; ++sx) {
-
- if((sx==glob->getDebugPixelX())&&(scanline==(Yres-glob->getDebugPixelY()) )) {
- // DEBUG!!!
- glob->setDebugOut(10);
- } else glob->setDebugOut(0);
-
- /* compute ray from eye through current pixel into scene... */
- ntlColor col;
- if(aaDepth<0) {
- ntlVec3Gfx dir(screenPos - glob->getEye());
- ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
-
- /* ...and trace it */
- col = the_ray.shade();
- } else {
- /* anti alias */
- int ai,aj; /* position in grid */
- int aOrg = sx*aaLength; /* grid offset x */
- int currStep = aaLength; /* step size */
- char colDiff = 1; /* do colors still differ too much? */
- ntlColor minCol,maxCol; /* minimum and maximum Color Values */
- minCol = ntlColor(1.0,1.0,1.0);
- maxCol = ntlColor(0.0,0.0,0.0);
-
- while((colDiff) && (currStep>0)) {
- colDiff = 0;
-
- for(aj = 0;aj<=aaLength;aj+= currStep) {
- for(ai = 0;ai<=aaLength;ai+= currStep) {
-
- /* shade pixel if not done */
- if(aaUse[aj*aaArrayX +ai +aOrg] == 0) {
- aaUse[aj*aaArrayX +ai +aOrg] = 1;
- ntlVec3Gfx aaPos( screenPos +
- (rightStep * (ai- aaLength/2)/(gfxReal)aaLength ) +
- (upStep * (aj- aaLength/2)/(gfxReal)aaLength ) );
-
- ntlVec3Gfx dir(aaPos - glob->getEye());
- ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
-
- /* ...and trace it */
- ntlColor newCol= the_ray.shade();
- aaCol[aj*aaArrayX +ai +aOrg]= newCol;
- } /* not used? */
-
- }
- }
-
- /* check color differences */
- for(aj = 0;aj<aaLength;aj+= currStep) {
- for(ai = 0;ai<aaLength;ai+= currStep) {
-
- char thisColDiff = 0;
- if(
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] -
- aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] -
- aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] -
- aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
- thisColDiff = 1;
- } else
- if(
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] -
- aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][0])> aaSensRed ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] -
- aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][1])> aaSensGreen ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] -
- aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][2])> aaSensBlue ) ) {
- thisColDiff = 1;
- } else
- if(
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] -
- aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] -
- aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] -
- aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
- thisColDiff = 1;
- }
-
- //colDiff =1;
- if(thisColDiff) {
- /* set diff flag */
- colDiff = thisColDiff;
- for(int bj=aj;bj<=aj+currStep;bj++) {
- for(int bi=ai;bi<=ai+currStep;bi++) {
- if(aaUse[bj*aaArrayX +bi +aOrg]==2) {
- //if(showAAPic)
- aaUse[bj*aaArrayX +bi +aOrg] = 0;
- }
- }
- }
- } else {
- /* set all values */
- ntlColor avgCol = (
- aaCol[(aj+0 )*aaArrayX +(ai+0 ) +aOrg] +
- aaCol[(aj+0 )*aaArrayX +(ai+currStep) +aOrg] +
- aaCol[(aj+currStep)*aaArrayX +(ai+0 ) +aOrg] +
- aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg] ) *0.25;
- for(int bj=aj;bj<=aj+currStep;bj++) {
- for(int bi=ai;bi<=ai+currStep;bi++) {
- if(aaUse[bj*aaArrayX +bi +aOrg]==0) {
- aaCol[bj*aaArrayX +bi +aOrg] = avgCol;
- aaUse[bj*aaArrayX +bi +aOrg] = 2;
- }
- }
- }
- } /* smaller values set */
-
- }
- }
-
- /* half step size */
- currStep /= 2;
-
- } /* repeat until diff not too big */
-
- /* get average color */
- gfxReal colNum = 0.0;
- col = ntlColor(0.0, 0.0, 0.0);
- for(aj = 0;aj<=aaLength;aj++) {
- for(ai = 0;ai<=aaLength;ai++) {
- col += aaCol[aj*aaArrayX +ai +aOrg];
- colNum += 1.0;
- }
- }
- col /= colNum;
-
- }
-
- /* mark pixels with debugging */
- if( glob->getDebugOut() > 0) col = ntlColor(0,1,0);
-
- /* store pixel */
- if(!showAAPic) {
- finalPic[(scanline-1)*picX+sx] = col;
- }
- screenPos += rightStep;
-
- } /* foreach x */
-
- /* init aa array */
- if(showAAPic) {
- for(int j=0;j<=aaArrayY-1;j++) {
- for(int i=0;i<=aaArrayX-1;i++) {
- if(aaUse[j*aaArrayX +i]==1) finalPic[((scanline-1)*aaLength +j)*picX+i][0] = 1.0;
- }
- }
- }
-
- for(int i=0;i<aaArrayX;i++) {
- aaCol[(aaArrayY-1)*aaArrayX+i] = aaCol[0*aaArrayX+i];
- aaUse[(aaArrayY-1)*aaArrayX+i] = aaUse[0*aaArrayX+i];
- }
- for(int j=0;j<aaArrayY-1;j++) {
- for(int i=0;i<aaArrayX;i++) {
- aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
- aaUse[j*aaArrayX+i] = 0;
- }
- }
-
- } /* foreach y */
- rendEnd = getTime();
-
-
- /* write png file */
- {
- int w = picX;
- int h = picY;
-
- unsigned rowbytes = w*4;
- unsigned char *screenbuf, **rows;
- screenbuf = (unsigned char*)malloc( h*rowbytes );
- rows = (unsigned char**)malloc( h*sizeof(unsigned char*) );
- unsigned char *filler = screenbuf;
-
- // cutoff color values 0..1
- for(int j=0;j<h;j++) {
- for(int i=0;i<w;i++) {
- ntlColor col = finalPic[j*w+i];
- for (unsigned int cc=0; cc<3; cc++) {
- if(col[cc] <= 0.0) col[cc] = 0.0;
- if(col[cc] >= 1.0) col[cc] = 1.0;
- }
- *filler = (unsigned char)( col[0]*255.0 );
- filler++;
- *filler = (unsigned char)( col[1]*255.0 );
- filler++;
- *filler = (unsigned char)( col[2]*255.0 );
- filler++;
- *filler = (unsigned char)( 255.0 );
- filler++; // alpha channel
- }
- }
-
- for(int i = 0; i < h; i++) rows[i] = &screenbuf[ (h - i - 1)*rowbytes ];
- writePng(outfn_conv.str().c_str(), rows, w, h);
- }
-
-
- // next frame
- glob->setAniCount( glob->getAniCount() +1 );
-
- // done
- timeEnd = getTime();
-
- char resout[1024];
- snprintf(resout,1024, "NTL Done %s, frame %d/%d (took %s scene, %s raytracing, %s total, %d shades, %d i.s.'s)!\n",
- outfn_conv.str().c_str(), (glob->getAniCount()), (glob->getAniFrames()+1),
- getTimeString(totalStart-timeStart).c_str(), getTimeString(rendEnd-rendStart).c_str(), getTimeString(timeEnd-timeStart).c_str(),
- glob->getCounterShades(),
- glob->getCounterSceneInter() );
- debMsgStd("ntlWorld::renderScene",DM_MSG, resout, 1 );
-
- /* clean stuff up */
- delete [] aaCol;
- delete [] aaUse;
- delete [] finalPic;
- glob->getRenderScene()->cleanupScene();
-
- if(mpGlob->getSingleFrameMode() ) {
- debMsgStd("ntlWorld::renderScene",DM_NOTIFY, "Single frame mode done...", 1 );
- return 1;
- }
-#endif // ELBEEM_PLUGIN
- return 0;
-}
-
-
-/******************************************************************************
- * renderglobals
- *****************************************************************************/
-
-
-/*****************************************************************************/
-/* Constructor with standard value init */
-ntlRenderGlobals::ntlRenderGlobals() :
- mpRenderScene(NULL), mpSimScene(NULL),
- mpLightList( NULL ), mpMaterials( NULL ), mpSims( NULL ),
- mResX(320), mResY(200), mAADepth(-1), mMaxColVal(255),
- mRayMaxDepth( 5 ),
- mvEye(0.0,0.0,5.0), mvLookat(0.0,0.0,0.0), mvUpvec(0.0,1.0,0.0),
- mAspect(320.0/200.0),
- mFovy(45), mcBackgr(0.0,0.0,0.0), mcAmbientLight(0.0,0.0,0.0),
- mDebugOut( 0 ),
- mAniStart(0), mAniFrames( -1 ), mAniCount( 0 ),
- mFrameSkip( 0 ),
- mCounterRays( 0 ), mCounterShades( 0 ), mCounterSceneInter( 0 ),
- mOutFilename( "pic" ),
- mTreeMaxDepth( 30 ), mTreeMaxTriangles( 30 ),
- mpOpenGlAttr(NULL),
- mpBlenderAttr(NULL),
- mTestSphereEnabled( false ),
- mDebugPixelX( -1 ), mDebugPixelY( -1 ), mTestMode(false),
- mSingleFrameMode(false), mSingleFrameFilename("")
- //,mpRndDirections( NULL ), mpRndRoulette( NULL )
-{
- // create internal attribute list for opengl renderer
- mpOpenGlAttr = new AttributeList("__ntlOpenGLRenderer");
- mpBlenderAttr = new AttributeList("__ntlBlenderAttr");
-};
-
-
-/*****************************************************************************/
-/* Destructor */
-ntlRenderGlobals::~ntlRenderGlobals() {
- if(mpOpenGlAttr) delete mpOpenGlAttr;
- if(mpBlenderAttr) delete mpBlenderAttr;
-
-
-}
-
-
-/*****************************************************************************/
-//! get the next random photon direction
-//ntlVec3Gfx ntlRenderGlobals::getRandomDirection( void ) {
- //return ntlVec3Gfx(
- //(mpRndDirections->getGfxReal()-0.5),
- //(mpRndDirections->getGfxReal()-0.5),
- //(mpRndDirections->getGfxReal()-0.5) );
-//}
-
-
diff --git a/intern/elbeem/intern/ntl_world.h b/intern/elbeem/intern/ntl_world.h
deleted file mode 100644
index 7851b783225..00000000000
--- a/intern/elbeem/intern/ntl_world.h
+++ /dev/null
@@ -1,411 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Main renderer class
- *
- *****************************************************************************/
-#ifndef NTL_RAYTRACER_HH
-#define NTL_RAYTRACER_HH
-
-#include "ntl_vector3dim.h"
-#include "ntl_ray.h"
-#include "ntl_lighting.h"
-#include "ntl_geometryobject.h"
-#include "simulation_object.h"
-#include "elbeem.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlOpenGLRenderer;
-class ntlScene;
-class SimulationObject;
-class ntlRandomStream;
-
-class ntlWorld
-{
- public:
- /*! Constructor for API init */
- ntlWorld();
- /*! Constructor */
- ntlWorld(string filename, bool commandlineMode);
- /*! Destructor */
- virtual ~ntlWorld( void );
- /*! default init for all contructors */
- void initDefaults();
- /*! common world contruction stuff once the scene is set up */
- void finishWorldInit();
- /*! add domain for API init */
- int addDomain(elbeemSimulationSettings *simSettings);
-
- /*! render a whole animation (command line mode) */
- int renderAnimation( void );
- /*! render a whole animation (visualization mode) */
- int renderVisualization( bool );
- /*! render a single step for viz mode */
- int singleStepVisualization( void );
- /*! advance simulations by time frame time */
- int advanceSims(int framenum);
- /*! advance simulations by a single step */
- void singleStepSims(double targetTime);
-
- /*! set stop rend viz flag */
- void setStopRenderVisualization(bool set) { mStopRenderVisualization = set; }
- /*! should the rendering viz thread be stopped? */
- bool getStopRenderVisualization() { return mStopRenderVisualization; }
-
- /*! render scene (a single pictures) */
- virtual int renderScene( void );
-
- /*! set single frame rendering to filename */
- void setSingleFrameOut( string singleframeFilename );
-
- /* access functions */
-
- /*! set&get render globals */
- inline void setRenderGlobals( ntlRenderGlobals *set) { mpGlob = set; }
- inline ntlRenderGlobals *getRenderGlobals( void ) { return mpGlob; }
-
- /*! set&get render globals */
- inline void setSimulationTime( double set) { mSimulationTime = set; }
- inline double getSimulationTime( void ) { return mSimulationTime; }
-
- /*! set&get single step debug mode */
- inline void setSingleStepDebug( bool set) { mSingleStepDebug = set; }
- inline bool getSingleStepDebug( void ) { return mSingleStepDebug; }
-
- /*! &get simulation object vector (debugging) */
- inline vector<SimulationObject*> *getSimulations( void ) { return mpSims; }
-
- /*! get opengl renderer */
- inline ntlOpenGLRenderer *getOpenGLRenderer() { return mpOpenGLRenderer; }
-
- private:
-
- protected:
-
- /*! global render settings needed almost everywhere */
- ntlRenderGlobals *mpGlob;
-
- /*! a list of lights in the scene (geometry is store in ntl_scene) */
- vector<ntlLightObject*> *mpLightList;
- /*! surface materials */
- vector<ntlMaterial*> *mpPropList;
- /*! sims list */
- vector<SimulationObject*> *mpSims;
-
- /*! opengl display */
- ntlOpenGLRenderer *mpOpenGLRenderer;
-
- /*! stop rend viz? */
- bool mStopRenderVisualization;
-
- /*! rend viz thread currently running? */
- bool mThreadRunning;
-
- /*! remember the current simulation time */
- double mSimulationTime;
-
- /*! first simulation that is valid */
- int mFirstSim;
-
- /*! single step mode for debugging */
- bool mSingleStepDebug;
-
- /*! count no. of frame for viz render */
- int mFrameCnt;
-
- /*! count no. of frame for correct sim time */
- int mSimFrameCnt;
- vector<int> mSimFrameValue;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlWorld")
-#endif
-};
-
-
-//! Class that handles global rendering parameters
-class ntlRenderGlobals
-{
- public:
- //! Standard constructor
- ntlRenderGlobals();
- //! Destructor
- ~ntlRenderGlobals();
-
- //! Returns the renderscene manager (scene changes for each frame)
- inline ntlScene *getRenderScene(void) { return mpRenderScene; }
- //! Set the renderscene manager
- inline void setRenderScene(ntlScene *set) { mpRenderScene = set;}
-
- //! Returns the simulation scene manager (static scene with sim objects)
- inline ntlScene *getSimScene(void) { return mpSimScene; }
- //! Set the simulation scene manager
- inline void setSimScene(ntlScene *set) { mpSimScene = set;}
-
- //! Returns the light object list
- inline vector<ntlLightObject*> *getLightList(void) { return mpLightList; }
- //! Set the light list
- inline void setLightList(vector<ntlLightObject*> *set) { mpLightList = set;}
-
- //! Returns the property object list
- inline vector<ntlMaterial*> *getMaterials(void) { return mpMaterials; }
- //! Set the property list
- inline void setMaterials(vector<ntlMaterial*> *set) { mpMaterials = set;}
-
- //! Returns the list of simulations
- inline vector<SimulationObject*> *getSims(void) { return mpSims; }
- //! Set the pointer to the list of simulations
- inline void setSims(vector<SimulationObject*> *set) { mpSims = set;}
-
- //! Set the x resolution
- inline void setResX(unsigned int set) { mResX = set; }
- //! Set the y resolution
- inline void setResY(unsigned int set) { mResY = set; }
- //! Set the anti-aliasing depth
- inline void setAADepth(int set) { mAADepth = set; }
- //! Set the max color value
- inline void setMaxColVal(unsigned int set) { mMaxColVal = set; }
- //! Set the maximum ray recursion
- inline void setRayMaxDepth(unsigned int set) { mRayMaxDepth = set; }
- //! Set the eye point
- inline void setEye(ntlVec3Gfx set) { mvEye = set; }
- //! Set the look at vector
- inline void setLookat(ntlVec3Gfx set) { mvLookat = set; }
- //! Set the up vector
- inline void setUpVec(ntlVec3Gfx set) { mvUpvec = set; }
- //! Set the image aspect
- inline void setAspect(float set) { mAspect = set; }
- //! Set the field of view
- inline void setFovy(float set) { mFovy = set; }
- //! Set the background color
- inline void setBackgroundCol(ntlColor set) { mcBackgr = set; }
- //! Set the ambient lighting color
- inline void setAmbientLight(ntlColor set) { mcAmbientLight = set; }
- //! Set the debug output var
- inline void setDebugOut(int set) { mDebugOut = set; }
-
- //! Set the animation start time
- inline void setAniStart(int set) { mAniStart = set; }
- //! Set the animation number of frames
- inline void setAniFrames(int set) { mAniFrames = set; }
- //! Set the animation
- inline void setAniCount(int set) { mAniCount = set; }
- //! Set the ray counter
- inline void setCounterRays(int set) { mCounterRays = set; }
- //! Set the ray shades counter
- inline void setCounterShades(int set) { mCounterShades = set; }
- //! Set the scenen intersection counter
- inline void setCounterSceneInter(int set) { mCounterSceneInter = set; }
- //! Set if existing frames should be skipped
- inline void setFrameSkip(int set) { mFrameSkip = set; }
-
- //! Set the outfilename
- inline void setOutFilename(string set) { mOutFilename = set; }
-
- //! get Maximum depth for BSP tree
- inline void setTreeMaxDepth( int set ) { mTreeMaxDepth = set; }
- //! get Maxmimum nr of triangles per BSP tree node
- inline void setTreeMaxTriangles( int set ) { mTreeMaxTriangles = set; }
-
- //! set the enable flag of the test sphere
- inline void setTestSphereEnabled( bool set ) { mTestSphereEnabled = set; }
- //! set the center of the test sphere
- inline void setTestSphereCenter( ntlVec3Gfx set ) { mTestSphereCenter = set; }
- //! set the radius of the test sphere
- inline void setTestSphereRadius( gfxReal set ) { mTestSphereRadius = set; }
- //! set the material name of the test sphere
- inline void setTestSphereMaterialName( char* set ) { mTestSphereMaterialName = set; }
- //! set debugging pixel coordinates
- inline void setDebugPixel( int setx, int sety ) { mDebugPixelX = setx; mDebugPixelY = sety; }
- //! set test mode flag
- inline void setTestMode( bool set ) { mTestMode = set; }
- //! set single frame mode flag
- inline void setSingleFrameMode(bool set) {mSingleFrameMode = set; };
- //! set single frame mode filename
- inline void setSingleFrameFilename(string set) {mSingleFrameFilename = set; };
-
-
- //! Return the x resolution
- inline unsigned int getResX(void) { return mResX; }
- //! Return the y resolution
- inline unsigned int getResY(void) { return mResY; }
- //! Return the anti-aliasing depth
- inline int getAADepth(void) { return mAADepth; }
- //! Return the max color value for ppm
- inline unsigned int getMaxColVal(void) { return mMaxColVal; }
- //! Return the maximum ray recursion
- inline unsigned int getRayMaxDepth(void) { return mRayMaxDepth; }
- //! Return the eye point
- inline ntlVec3Gfx getEye(void) { return mvEye; }
- //! Return the look at vector
- inline ntlVec3Gfx getLookat(void) { return mvLookat; }
- //! Return the up vector
- inline ntlVec3Gfx getUpVec(void) { return mvUpvec; }
- //! Return the image aspect
- inline float getAspect(void) { return mAspect; }
- //! Return the field of view
- inline float getFovy(void) { return mFovy; }
- //! Return the background color
- inline ntlColor getBackgroundCol(void) { return mcBackgr; }
- //! Return the ambient color
- inline ntlColor getAmbientLight(void) { return mcAmbientLight; }
- //! Return the debug mode setting
- inline int getDebugOut(void) { return mDebugOut; }
-
- //! Return the animation start time
- inline int getAniStart(void) { return mAniStart; }
- //! Return the animation frame number
- inline int getAniFrames(void) { return mAniFrames; }
- //! Return the animation counter
- inline int getAniCount(void) { return mAniCount; }
- //! Return the ray counter
- inline int getCounterRays(void) { return mCounterRays; }
- //! Return the ray shades counter
- inline int getCounterShades(void) { return mCounterShades; }
- //! Return the scene intersection counter
- inline int getCounterSceneInter(void) { return mCounterSceneInter; }
- //! Check if existing frames should be skipped
- inline int getFrameSkip( void ) { return mFrameSkip; }
-
-
- //! Return the outfilename
- inline string getOutFilename(void) { return mOutFilename; }
-
- //! get Maximum depth for BSP tree
- inline int getTreeMaxDepth( void ) { return mTreeMaxDepth; }
- //! get Maxmimum nr of triangles per BSP tree node
- inline int getTreeMaxTriangles( void ) { return mTreeMaxTriangles; }
-
- //! get open gl attribute list
- inline AttributeList* getOpenGlAttributes( void ) { return mpOpenGlAttr; }
- //! get blender output attribute list
- inline AttributeList* getBlenderAttributes( void ) { return mpBlenderAttr; }
-
- //! is the test sphere enabled?
- inline bool getTestSphereEnabled( void ) { return mTestSphereEnabled; }
- //! get the center of the test sphere
- inline ntlVec3Gfx getTestSphereCenter( void ) { return mTestSphereCenter; }
- //! get the radius of the test sphere
- inline gfxReal getTestSphereRadius( void) { return mTestSphereRadius; }
- //! get the materialname of the test sphere
- inline char *getTestSphereMaterialName( void) { return mTestSphereMaterialName; }
- //! get the debug pixel coordinate
- inline int getDebugPixelX( void ) { return mDebugPixelX; }
- //! get the debug pixel coordinate
- inline int getDebugPixelY( void ) { return mDebugPixelY; }
- //! get test mode flag
- inline bool getTestMode( void ) { return mTestMode; }
- //! set single frame mode flag
- inline bool getSingleFrameMode() { return mSingleFrameMode; };
- //! set single frame mode filename
- inline string getSingleFrameFilename() { return mSingleFrameFilename; };
-
-
-private:
-
- /*! Scene storage (dynamic rendering scene) */
- ntlScene *mpRenderScene;
- /*! Scene storage (static sim scene, inited only once) */
- ntlScene *mpSimScene;
-
- //! List of light objects
- vector<ntlLightObject*> *mpLightList;
- //! List of surface properties
- vector<ntlMaterial*> *mpMaterials;
- /*! storage for simulations */
- vector<SimulationObject*> *mpSims;
-
- //! resolution of the picture
- unsigned int mResX, mResY;
- //! Anti-Aliasing depth
- int mAADepth;
- //! max color value for ppm
- unsigned int mMaxColVal;
- /* Maximal ray recursion depth */
- int mRayMaxDepth;
- //! The eye point
- ntlVec3Gfx mvEye;
- //! The look at point
- ntlVec3Gfx mvLookat;
- //! The up vector
- ntlVec3Gfx mvUpvec;
- //! The image aspect = Xres/Yres
- float mAspect;
- //! The horizontal field of view
- float mFovy;
- //! The background color
- ntlColor mcBackgr;
- //! The ambient color
- ntlColor mcAmbientLight;
- //! how much debug output is needed? off by default
- char mDebugOut;
-
-
- //! animation properties, start time
- int mAniStart;
- //! animation properties, number of frames to render
- int mAniFrames;
- //! animation status, current frame number
- int mAniCount;
- /*! Should existing picture frames be skipped? */
- int mFrameSkip;
-
-
- //! count the total number of rays created (also used for ray ID's)
- int mCounterRays;
- //! count the total number of rays shaded
- int mCounterShades;
- //! count the total number of scene intersections
- int mCounterSceneInter;
-
- /*! filename of output pictures (without suffix or numbers) */
- string mOutFilename;
-
- //! get Maximum depth for BSP tree
- int mTreeMaxDepth;
- //! get Maxmimum nr of triangles per BSP tree node
- int mTreeMaxTriangles;
-
- //! attribute list for opengl renderer
- AttributeList *mpOpenGlAttr;
- //! attribute list for blender output
- AttributeList *mpBlenderAttr;
-
-
- //! Enable test sphere?
- bool mTestSphereEnabled;
- //! Center of the test sphere
- ntlVec3Gfx mTestSphereCenter;
- //! Radius of the test sphere
- gfxReal mTestSphereRadius;
- //! Materialname of the test sphere
- char *mTestSphereMaterialName;
- //! coordinates of the debugging pixel
- int mDebugPixelX, mDebugPixelY;
-
- //! test mode for quick rendering activated?, inited in ntl_scene::buildScene
- bool mTestMode;
-
- //! single frame flag
- bool mSingleFrameMode;
- //! filename for single frame mode
- string mSingleFrameFilename;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlRenderGlobals")
-#endif
-};
-
-
-
-#endif
diff --git a/intern/elbeem/intern/paraloopend.h b/intern/elbeem/intern/paraloopend.h
deleted file mode 100644
index 6f321cd68b1..00000000000
--- a/intern/elbeem/intern/paraloopend.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-
-// same as grid loop_end + barrier
-
- } // i
- int i=0; //dummy
- ADVANCE_POINTERS(2*gridLoopBound);
- } // j
-
-# if COMPRESSGRIDS==1
-# if PARALLEL==1
- //frintf(stderr," (id=%d k=%d) ",id,k);
-#pragma omp barrier
-# endif // PARALLEL==1
-# else // COMPRESSGRIDS==1
- int i=0; //dummy
- ADVANCE_POINTERS(mLevel[lev].lSizex*2);
-# endif // COMPRESSGRIDS==1
-
-} // all cell loop k,j,i
-
-#pragma omp critical
-{
- if(doReduce) {
- // synchronize global vars
- for(size_t j=0; j<calcListFull.size() ; j++) mListFull.push_back( calcListFull[j] );
- for(size_t j=0; j<calcListEmpty.size(); j++) mListEmpty.push_back( calcListEmpty[j] );
- for(size_t j=0; j<calcListParts.size(); j++) mpParticles->addFullParticle( calcListParts[j] );
- if(calcMaxVlen>mMaxVlen) {
- mMxvx = calcMxvx;
- mMxvy = calcMxvy;
- mMxvz = calcMxvz;
- mMaxVlen = calcMaxVlen;
- }
- if(0) {debMsgStd("OMP_CRIT",DM_MSG, "reduce id"<<id<<" curr: "<<mMaxVlen<<"|"<<mMxvx<<","<<mMxvy<<","<<mMxvz<<
- " calc[ "<<calcMaxVlen<<"|"<<calcMxvx<<","<<calcMxvy<<","<<calcMxvz<<"] " ,4 ); }
- }
-} // critical
-
-
-} /* main_region */
- //?lobOutstrForce = true;
-
diff --git a/intern/elbeem/intern/parametrizer.cpp b/intern/elbeem/intern/parametrizer.cpp
deleted file mode 100644
index 889b8b85c4d..00000000000
--- a/intern/elbeem/intern/parametrizer.cpp
+++ /dev/null
@@ -1,597 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Parameter calculator for the LBM Solver class
- *
- *****************************************************************************/
-
-#include <sstream>
-#include "parametrizer.h"
-
-// debug output flag, has to be off for win32 for some reason...
-#define DEBUG_PARAMCHANNELS 0
-
-/*! param seen debug string array */
-const char *ParamStrings[] = {
- "RelaxTime",
- "Reynolds",
- "Viscosity",
- "SoundSpeed",
- "DomainSize",
- "GravityForce",
- "TimeLength",
- "Timestep",
- "Size",
- "TimeFactor",
- "AniFrames",
- "AniFrameTime",
- "AniStart",
- "SurfaceTension",
- "Density",
- "CellSize",
- "GStar",
- "MaxSpeed",
- "SimMaxSpeed",
- "FluidVolHeight",
- "NormalizedGStar",
- "PSERR", "PSERR", "PSERR", "PSERR"
-};
-
-
-
-/******************************************************************************
- * Default constructor
- *****************************************************************************/
-Parametrizer::Parametrizer( void ) :
- mcViscosity( 8.94e-7 ),
- mSoundSpeed( 1500 ),
- mDomainSize( 0.1 ), mCellSize( 0.01 ),
- mcGravity( ParamVec(0.0) ),
- mTimestep(0.0001), mDesiredTimestep(-1.0),
- mMaxTimestep(-1.0),
- mMinTimestep(-1.0),
- mSizex(50), mSizey(50), mSizez(50),
- mTimeFactor( 1.0 ),
- mcAniFrameTime(0.0001),
- mTimeStepScale(1.0),
- mAniStart(0.0),
- //mExtent(1.0, 1.0, 1.0), //mSurfaceTension( 0.0 ),
- mDensity(1000.0), mGStar(0.0001), mFluidVolumeHeight(0.0),
- mSimulationMaxSpeed(0.0),
- mTadapMaxOmega(2.0), mTadapMaxSpeed(0.1), mTadapLevels(1),
- mFrameNum(0),
- mSeenValues( 0 ), mCalculatedValues( 0 )
-{
-}
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-Parametrizer::~Parametrizer()
-{
- /* not much to do... */
-}
-
-/******************************************************************************
- * Init from attr list
- *****************************************************************************/
-void Parametrizer::parseAttrList()
-{
- if(!mpAttrs) {
- errFatal("Parametrizer::parseAttrList", "mpAttrs pointer not initialized!", SIMWORLD_INITERROR);
- return;
- }
-
- // unused
- string mSetupType = "";
- mSetupType = mpAttrs->readString("p_setup",mSetupType, "Parametrizer","mSetupType", false);
-
- // real params
- if(getAttributeList()->exists("p_viscosity")) {
- mcViscosity = mpAttrs->readChannelFloat("p_viscosity"); seenThis( PARAM_VISCOSITY ); }
-
- mSoundSpeed = mpAttrs->readFloat("p_soundspeed",mSoundSpeed, "Parametrizer","mSoundSpeed", false);
- if(getAttributeList()->exists("p_soundspeed")) seenThis( PARAM_SOUNDSPEED );
-
- mDomainSize = mpAttrs->readFloat("p_domainsize",mDomainSize, "Parametrizer","mDomainSize", false);
- if(getAttributeList()->exists("p_domainsize")) seenThis( PARAM_DOMAINSIZE );
- if(mDomainSize<=0.0) {
- errMsg("Parametrizer::parseAttrList","Invalid real world domain size:"<<mDomainSize<<", resetting to 0.1");
- mDomainSize = 0.1;
- }
-
- if(getAttributeList()->exists("p_gravity")) { // || (!mcGravity.isInited()) ) {
- mcGravity = mpAttrs->readChannelVec3d("p_gravity"); seenThis( PARAM_GRAVITY );
- }
-
- mTimestep = mpAttrs->readFloat("p_steptime",mTimestep, "Parametrizer","mTimestep", false);
- if(getAttributeList()->exists("p_steptime")) seenThis( PARAM_STEPTIME );
-
- mTimeFactor = mpAttrs->readFloat("p_timefactor",mTimeFactor, "Parametrizer","mTimeFactor", false);
- if(getAttributeList()->exists("p_timefactor")) seenThis( PARAM_TIMEFACTOR );
-
- if(getAttributeList()->exists("p_aniframetime")) { //|| (!mcAniFrameTime.isInited()) ) {
- mcAniFrameTime = mpAttrs->readChannelFloat("p_aniframetime");seenThis( PARAM_ANIFRAMETIME );
- }
- mTimeStepScale = mpAttrs->readFloat("p_timestepscale",mTimeStepScale, "Parametrizer","mTimeStepScale", false);
-
- mAniStart = mpAttrs->readFloat("p_anistart",mAniStart, "Parametrizer","mAniStart", false);
- if(getAttributeList()->exists("p_anistart")) seenThis( PARAM_ANISTART );
- if(mAniStart<0.0) {
- errMsg("Parametrizer::parseAttrList","Invalid start time:"<<mAniStart<<", resetting to 0.0");
- mAniStart = 0.0;
- }
-
- //mSurfaceTension = mpAttrs->readFloat("p_surfacetension",mSurfaceTension, "Parametrizer","mSurfaceTension", false);
- //if(getAttributeList()->exists("p_surfacetension")) seenThis( PARAM_SURFACETENSION );
-
- mDensity = mpAttrs->readFloat("p_density",mDensity, "Parametrizer","mDensity", false);
- if(getAttributeList()->exists("p_density")) seenThis( PARAM_DENSITY );
-
- ParamFloat cellSize = 0.0; // unused, deprecated
- cellSize = mpAttrs->readFloat("p_cellsize",cellSize, "Parametrizer","cellSize", false);
-
- mGStar = mpAttrs->readFloat("p_gstar",mGStar, "Parametrizer","mGStar", false);
- if(getAttributeList()->exists("p_gstar")) seenThis( PARAM_GSTAR );
-
- mNormalizedGStar = mpAttrs->readFloat("p_normgstar",mNormalizedGStar, "Parametrizer","mNormalizedGStar", false);
- if(getAttributeList()->exists("p_normgstar")) seenThis( PARAM_NORMALIZEDGSTAR );
-
- mTadapMaxOmega = mpAttrs->readFloat("p_tadapmaxomega",mTadapMaxOmega, "Parametrizer","mTadapMaxOmega", false);
- mTadapMaxSpeed = mpAttrs->readFloat("p_tadapmaxspeed",mTadapMaxSpeed, "Parametrizer","mTadapMaxSpeed", false);
-}
-
-/******************************************************************************
- *! advance to next render/output frame
- *****************************************************************************/
-void Parametrizer::setFrameNum(int frame) {
- mFrameNum = frame;
-#if DEBUG_PARAMCHANNELS>0
- errMsg("DEBUG_PARAMCHANNELS","setFrameNum frame-num="<<mFrameNum);
-#endif // DEBUG_PARAMCHANNELS>0
-}
-/*! get time of an animation frame (renderer) */
-// also used by: mpParam->getCurrentAniFrameTime() , e.g. for velocity dump
-ParamFloat Parametrizer::getAniFrameTime( int frame ) {
- double frametime = (double)frame;
- ParamFloat anift = mcAniFrameTime.get(frametime);
- if(anift<0.0) {
- ParamFloat resetv = 0.;
- errMsg("Parametrizer::setFrameNum","Invalid frame time:"<<anift<<" at frame "<<frame<<", resetting to "<<resetv);
- anift = resetv;
- }
-#if DEBUG_PARAMCHANNELS>0
- if((0)|| (DEBUG_PARAMCHANNELS)) errMsg("DEBUG_PARAMCHANNELS","getAniFrameTime frame="<<frame<<", frametime="<<anift<<" ");
-#endif // DEBUG_PARAMCHANNELS>0
- return anift;
-}
-
-/******************************************************************************
- * scale a given speed vector in m/s to lattice values
- *****************************************************************************/
-ParamVec Parametrizer::calculateAddForce(ParamVec vec, string usage)
-{
- ParamVec ret = vec * (mTimestep*mTimestep) /mCellSize;
- debMsgStd("Parametrizer::calculateVector", DM_MSG, "scaled vector = "<<ret<<" for '"<<usage<<"', org = "<<vec<<" dt="<<mTimestep ,10);
- return ret;
-}
-
-
-/******************************************************************************
- * calculate size of a single cell
- *****************************************************************************/
-ParamFloat Parametrizer::calculateCellSize(void)
-{
- int maxsize = mSizex; // get max size
- if(mSizey>maxsize) maxsize = mSizey;
- if(mSizez>maxsize) maxsize = mSizez;
- maxsize = mSizez; // take along gravity dir for now!
- ParamFloat cellSize = 1.0 / (ParamFloat)maxsize;
- return cellSize;
-}
-
-
-/*****************************************************************************/
-/* simple calulation functions */
-/*****************************************************************************/
-
-/*! get omega for LBM from channel */
-ParamFloat Parametrizer::calculateOmega( double time ) {
- ParamFloat viscStar = calculateLatticeViscosity(time);
- ParamFloat relaxTime = (6.0 * viscStar + 1) * 0.5;
-#if DEBUG_PARAMCHANNELS>0
- errMsg("DEBUG_PARAMCHANNELS","calculateOmega viscStar="<<viscStar<<" relaxtime="<<relaxTime);
-#endif // DEBUG_PARAMCHANNELS>0
- return (1.0/relaxTime);
-}
-
-/*! get external force x component */
-ParamVec Parametrizer::calculateGravity( double time ) {
- ParamVec grav = mcGravity.get(time);
- ParamFloat forceFactor = (mTimestep *mTimestep)/mCellSize;
- ParamVec latticeGravity = grav * forceFactor;
-#if DEBUG_PARAMCHANNELS>0
- errMsg("DEBUG_PARAMCHANNELS","calculateGravity grav="<<grav<<" ff"<<forceFactor<<" lattGrav="<<latticeGravity);
-#endif // DEBUG_PARAMCHANNELS>0
- return latticeGravity;
-}
-
-/*! calculate the lattice viscosity */
-ParamFloat Parametrizer::calculateLatticeViscosity( double time ) {
- // check seen values
- int reqValues = PARAM_VISCOSITY | PARAM_STEPTIME;
- if(!checkSeenValues( reqValues ) ){
- errMsg("Parametrizer::calculateLatticeViscosity"," Missing arguments!");
- }
- ParamFloat viscStar = mcViscosity.get(time) * mTimestep / (mCellSize*mCellSize);
-#if DEBUG_PARAMCHANNELS>0
- errMsg("DEBUG_PARAMCHANNELS","calculateLatticeViscosity viscStar="<<viscStar);
-#endif // DEBUG_PARAMCHANNELS>0
- return viscStar;
-}
-
-/*! get no of steps for the given length in seconds */
-int Parametrizer::calculateStepsForSecs( ParamFloat s ) {
- return (int)(s/mTimestep);
-}
-
-/*! get start time of animation */
-int Parametrizer::calculateAniStart( void ) {
- return (int)(mAniStart/mTimestep);
-}
-
-/*! get no of steps for a single animation frame */
-int Parametrizer::calculateAniStepsPerFrame(int frame) {
- if(!checkSeenValues(PARAM_ANIFRAMETIME)) {
- errFatal("Parametrizer::calculateAniStepsPerFrame", "Missing ani frame time argument!", SIMWORLD_INITERROR);
- return 1;
- }
- int value = (int)(getAniFrameTime(frame)/mTimestep);
- if((value<0) || (value>1000000)) {
- errFatal("Parametrizer::calculateAniStepsPerFrame", "Invalid step-time (="<<value<<") <> ani-frame-time ("<<mTimestep<<") settings, aborting...", SIMWORLD_INITERROR);
- return 1;
- }
- return value;
-}
-
-/*! get no. of timesteps for LBM */
-int Parametrizer::calculateNoOfSteps( ParamFloat timelen ) {
- return (int)(timelen/mTimestep);
-}
-
-/*! get extent of the domain = (1,1,1) if parametrizer not used, (x,y,z) [m] otherwise */
-//ParamVec Parametrizer::calculateExtent( void ) {
- //return mExtent;
-//}
-
-/*! get (scaled) surface tension */
-//ParamFloat Parametrizer::calculateSurfaceTension( void ) { return mSurfaceTension; }
-
-/*! get the length of a single time step */
-// explicity scaled by time factor for refinement
-ParamFloat Parametrizer::getTimestep( void ) {
- return mTimestep;
-}
-
-/*! calculate lattice velocity from real world value [m/s] */
-ParamVec Parametrizer::calculateLattVelocityFromRw( ParamVec ivel ) {
- ParamVec velvec = ivel;
- velvec /= mCellSize;
- velvec *= mTimestep;
- return velvec;
-}
-/*! calculate real world [m/s] velocity from lattice value */
-ParamVec Parametrizer::calculateRwVelocityFromLatt( ParamVec ivel ) {
- ParamVec velvec = ivel;
- velvec *= mCellSize;
- velvec /= mTimestep;
- return velvec;
-}
-
-
-/*! get g star value with fhvol calculations */
-ParamFloat Parametrizer::getCurrentGStar( void ) {
- ParamFloat gStar = mGStar; // check? TODO get from mNormalizedGStar?
- if(mFluidVolumeHeight>0.0) { gStar = mGStar/mFluidVolumeHeight; }
- return gStar;
-}
-
-/******************************************************************************
- * function that tries to calculate all the missing values from the given ones
- * prints errors and returns false if thats not possible
- *****************************************************************************/
-bool Parametrizer::calculateAllMissingValues( double time, bool silent )
-{
- bool init = false; // did we init correctly?
- int valuesChecked = 0;
- int reqValues;
-
- // we always need the sizes
- reqValues = PARAM_SIZE;
- valuesChecked |= reqValues;
- if(!checkSeenValues(reqValues)) {
- errMsg("Parametrizer::calculateAllMissingValues"," Missing size argument!");
- return false;
- }
-
- if(!checkSeenValues(PARAM_DOMAINSIZE)) {
- errMsg("Parametrizer::calculateAllMissingValues"," Missing domain size argument!");
- return false;
- }
- int maxsize = mSizex; // get max size
- if(mSizey>maxsize) maxsize = mSizey;
- if(mSizez>maxsize) maxsize = mSizez;
- maxsize = mSizez; // take along gravity dir for now!
- mCellSize = ( mDomainSize * calculateCellSize() ); // sets mCellSize
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," max domain resolution="<<(maxsize)<<" cells , cellsize="<<mCellSize ,10);
-
-
- /* Carolin init , see DA for details */
- ParamFloat maxDeltaT = 0.0;
-
- /* normalized gstar init */
- reqValues = PARAM_NORMALIZEDGSTAR;
- valuesChecked |= reqValues;
- if(checkSeenValues( reqValues ) ){
- //if(checkSeenValues( PARAM_GSTAR ) ){ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_WARNING," g star value override by normalizedGStar!",1); }
- const ParamFloat normgstarReset = 0.005;
- if(mNormalizedGStar<=1e-6) {
- errMsg("Parametrizer::calculateAllMissingValues","Invalid NormGstar: "<<mNormalizedGStar<<"... resetting to "<<normgstarReset);
- mNormalizedGStar = normgstarReset;
- }
-
- mGStar = mNormalizedGStar/maxsize;
-
-// TODO FIXME add use testdata check!
-mGStar = mNormalizedGStar/mSizez;
-errMsg("Warning","Used z-dir for gstar!");
-
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," g star set to "<<mGStar<<" from normalizedGStar="<<mNormalizedGStar ,1);
- seenThis(PARAM_GSTAR);
- }
-
- reqValues = PARAM_GSTAR | PARAM_VISCOSITY;
- if((checkSeenValues(PARAM_SURFACETENSION))) reqValues |= PARAM_DENSITY; // surface tension optional now...
- valuesChecked |= reqValues;
- if(checkSeenValues( reqValues ) ){
- const ParamFloat gstarReset = 0.0005;
- if(getCurrentGStar()<=1e-6) {
- errMsg("Parametrizer::calculateAllMissingValues","Invalid Gstar: "<<getCurrentGStar()<<" (set to "<<mGStar<<") ... resetting to "<<gstarReset);
- mGStar = gstarReset;
- }
-
- ParamFloat gStar = getCurrentGStar(); // mGStar
- if(mFluidVolumeHeight>0.0) {
- debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," height"<<mFluidVolumeHeight<<" resGStar = "<<gStar, 10);
- }
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," g star = "<<gStar, 10);
-
- ParamFloat forceStrength = 0.0;
- //if(checkSeenValues(PARAM_GRAVITY)) { forceStrength = norm( calculateGravity(time) ); }
- if(checkSeenValues(PARAM_GRAVITY)) { forceStrength = norm( mcGravity.get(time) ); }
-
- // determine max. delta density per timestep trough gravity force
- if(forceStrength>0.0) {
- maxDeltaT = sqrt( gStar*mCellSize *mTimeStepScale /forceStrength );
- } else {
- // use 1 lbm setp = 1 anim step as max
- maxDeltaT = getAniFrameTime(0);
- }
-
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," targeted step time = "<<maxDeltaT, 10);
-
- //ParamFloat viscStarFac = mViscosity/(mCellSize*mCellSize);
- //if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," viscStarFac = "<<viscStarFac<<" viscosity:"<<mViscosity, 10);
-
- // time step adaptivty, only for caro with max sim speed
- ParamFloat setDeltaT = maxDeltaT;
- if(mDesiredTimestep>0.0) {
- // explicitly set step time according to max velocity in sim
- setDeltaT = mDesiredTimestep;
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," desired step time = "<<setDeltaT, 10);
- mDesiredTimestep = -1.0;
- } else {
- // just use max delta t as current
- }
-
- // and once for init determine minimal delta t by omega max.
- if((mMinTimestep<0.0) || (mMaxTimestep<0.0)) {
- ParamFloat minDeltaT;
- ParamFloat maxOmega = mTadapMaxOmega;
- ParamFloat minRelaxTime = 1.0/maxOmega;
- for(int lev=1; lev<mTadapLevels; lev++) {
- // make minRelaxTime larger for each level that exists...
- minRelaxTime = 2.0 * (minRelaxTime-0.5) + 0.5;
- }
- maxOmega = 1.0/minRelaxTime;
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," maxOmega="<<maxOmega<<" minRelaxTime="<<minRelaxTime<<" levels="<<mTadapLevels, 1);
- // visc-star for min relax time to calculate min delta ta
- if(mcViscosity.get(time)>0.0) {
- minDeltaT = ((2.0*minRelaxTime-1.0)/6.0) * mCellSize * mCellSize / mcViscosity.get(time);
- } else {
- // visc=0, this is not physical, but might happen
- minDeltaT = 0.0;
- }
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," min delta t = "<<minDeltaT<<" , range = " << (maxDeltaT/minDeltaT) ,1);
-
- // sim speed + accel shouldnt exceed 0.1?
- mMaxTimestep = maxDeltaT;
- mMinTimestep = minDeltaT;
- // only use once...
- }
-
- setTimestep( setDeltaT ); // set mTimestep to new value
- init = true;
- }
-
- // finish init
- if(init) {
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," omega = "<<calculateOmega(0.0)<<", delt="<<mTimestep,1);
-
- if(checkSeenValues(PARAM_GRAVITY)) {
- ParamFloat forceFactor = (mTimestep *mTimestep)/mCellSize; // only used for printing...
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," gravity force = "<<PRINT_NTLVEC(mcGravity.get(time))<<", scaled with "<<forceFactor<<" to "<<calculateGravity(time),1);
- }
-
- //mExtent = ParamVec( mCellSize*mSizex, mCellSize*mSizey, mCellSize*mSizez );
- //if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," domain extent = "<<PRINT_NTLVEC(mExtent)<<"m , gs:"<<PRINT_VEC(mSizex,mSizey,mSizez)<<" cs:"<<mCellSize,1);
-
- if(!checkSeenValues(PARAM_ANIFRAMETIME)) {
- errFatal("Parametrizer::calculateAllMissingValues"," Warning no ani frame time given!", SIMWORLD_INITERROR);
- setAniFrameTimeChannel( mTimestep );
- }
-
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," ani frame steps = "<<calculateAniStepsPerFrame(mFrameNum)<<" for frame "<<mFrameNum, 1);
-
- if((checkSeenValues(PARAM_ANISTART))&&(calculateAniStart()>0)) {
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," ani start steps = "<<calculateAniStart()<<" ",1);
- }
-
- if(! isSimworldOk() ) return false;
- // everything ok
- return true;
- }
-
- // init failed ... failure:
- errMsg("Parametrizer::calculateAllMissingValues "," invalid configuration!");
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues ",DM_WARNING, " values seen:", 1);
- for(int i=0;i<PARAM_NUMIDS;i++) {
- if(checkSeenValues( 1<<i )) {
- if(!silent) debMsgStd(" ",DM_NOTIFY, ParamStrings[i], 1);
- }
- }
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues ",DM_WARNING, "values checked but missing:", 1);
- for(int i=0;i<PARAM_NUMIDS;i++) {
- if((!checkSeenValues( 1<<i ))&&
- ( (valuesChecked&(1<<i))==(1<<i)) ) {
- debMsgStd(" ",DM_IMPORTANT, ParamStrings[i], 1);
- }
- }
-
- // print values?
- return false;
-}
-
-
-/******************************************************************************
- * init debug functions
- *****************************************************************************/
-
-
-/*! set kinematic viscosity */
-void Parametrizer::setViscosity(ParamFloat set) {
- mcViscosity = AnimChannel<ParamFloat>(set);
- seenThis( PARAM_VISCOSITY );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcViscosity set = "<< mcViscosity.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-void Parametrizer::initViscosityChannel(vector<ParamFloat> val, vector<double> time) {
- mcViscosity = AnimChannel<ParamFloat>(val,time);
- seenThis( PARAM_VISCOSITY );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcViscosity initc = "<< mcViscosity.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-
-/*! set the external force */
-void Parametrizer::setGravity(ParamFloat setx, ParamFloat sety, ParamFloat setz) {
- mcGravity = AnimChannel<ParamVec>(ParamVec(setx,sety,setz));
- seenThis( PARAM_GRAVITY );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcGravity set = "<< mcGravity.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-void Parametrizer::setGravity(ParamVec set) {
- mcGravity = AnimChannel<ParamVec>(set);
- seenThis( PARAM_GRAVITY );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcGravity set = "<< mcGravity.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-void Parametrizer::initGravityChannel(vector<ParamVec> val, vector<double> time) {
- mcGravity = AnimChannel<ParamVec>(val,time);
- seenThis( PARAM_GRAVITY );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcGravity initc = "<< mcGravity.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-
-/*! set time of an animation frame (renderer) */
-void Parametrizer::setAniFrameTimeChannel(ParamFloat set) {
- mcAniFrameTime = AnimChannel<ParamFloat>(set);
- seenThis( PARAM_ANIFRAMETIME );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcAniFrameTime set = "<< mcAniFrameTime.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-void Parametrizer::initAniFrameTimeChannel(vector<ParamFloat> val, vector<double> time) {
- mcAniFrameTime = AnimChannel<ParamFloat>(val,time);
- seenThis( PARAM_ANIFRAMETIME );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcAniFrameTime initc = "<< mcAniFrameTime.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-
-// OLD interface stuff
-// reactivate at some point?
-
- /*! surface tension, [kg/s^2] */
- //ParamFloat mSurfaceTension;
- /*! set starting time of the animation (renderer) */
- //void setSurfaceTension(ParamFloat set) { mSurfaceTension = set; seenThis( PARAM_SURFACETENSION ); }
- /*! get starting time of the animation (renderer) */
- //ParamFloat getSurfaceTension( void ) { return mSurfaceTension; }
- /*if((checkSeenValues(PARAM_SURFACETENSION))&&(mSurfaceTension>0.0)) {
- ParamFloat massDelta = 1.0;
- ParamFloat densityStar = 1.0;
- massDelta = mDensity / densityStar *mCellSize*mCellSize*mCellSize;
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," massDelta = "<<massDelta, 10);
-
- mSurfaceTension = mSurfaceTension*mTimestep*mTimestep/massDelta;
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," surface tension = "<<mSurfaceTension<<" ",1);
- } // */
-
-// probably just delete:
-
- /*! reynolds number (calculated from domain length and max. speed [dimensionless] */
- //ParamFloat mReynolds;
-
- /*! set relaxation time */
- //void setRelaxTime(ParamFloat set) { mRelaxTime = set; seenThis( PARAM_RELAXTIME ); }
- /*! get relaxation time */
- //ParamFloat getRelaxTime( void ) { return mRelaxTime; }
- /*! set reynolds number */
- //void setReynolds(ParamFloat set) { mReynolds = set; seenThis( PARAM_REYNOLDS ); }
- /*! get reynolds number */
- //ParamFloat getReynolds( void ) { return mReynolds; }
-
- // calculate reynolds number
- /*if(mViscosity>0.0) {
- ParamFloat maxSpeed = 1.0/6.0; // for rough reynolds approx
- ParamFloat reynoldsApprox = -1.0;
- ParamFloat gridSpeed = (maxSpeed*mCellSize/mTimestep);
- reynoldsApprox = (mDomainSize*gridSpeed) / mViscosity;
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," reynolds number (D="<<mDomainSize<<", assuming V="<<gridSpeed<<")= "<<reynoldsApprox<<" ", 1);
- } // */
-
- //? mRelaxTime = mpAttrs->readFloat("p_relaxtime",mRelaxTime, "Parametrizer","mRelaxTime", false);
- //if(getAttributeList()->exists("p_relaxtime")) seenThis( PARAM_RELAXTIME );
- //? mReynolds = mpAttrs->readFloat("p_reynolds",mReynolds, "Parametrizer","mReynolds", false);
- //if(getAttributeList()->exists("p_reynolds")) seenThis( PARAM_REYNOLDS );
-
- //mViscosity = mpAttrs->readFloat("p_viscosity",mViscosity, "Parametrizer","mViscosity", false);
- //if(getAttributeList()->exists("p_viscosity") || (!mcViscosity.isInited()) ) { }
- //if(getAttributeList()->exists("p_viscosity"))
-
-
- //ParamFloat viscStar = calculateLatticeViscosity(time);
- //RelaxTime = (6.0 * viscStar + 1) * 0.5;
-
-
diff --git a/intern/elbeem/intern/parametrizer.h b/intern/elbeem/intern/parametrizer.h
deleted file mode 100644
index bd7377b9fbd..00000000000
--- a/intern/elbeem/intern/parametrizer.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Parameter calculator for the LBM Solver class
- *
- *****************************************************************************/
-#ifndef MFFSLBM_PARAMETRIZER
-#define MFFSLBM_PARAMETRIZER
-
-
-/* LBM Files */
-#include "utilities.h"
-#include "attributes.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-/* parametrizer accuracy */
-typedef double ParamFloat;
-typedef ntlVec3d ParamVec;
-
-/*! flags to check which values are known */
-#define PARAM_RELAXTIME (1<< 0)
-#define PARAM_REYNOLDS (1<< 1)
-#define PARAM_VISCOSITY (1<< 2)
-#define PARAM_SOUNDSPEED (1<< 3)
-#define PARAM_DOMAINSIZE (1<< 4)
-#define PARAM_GRAVITY (1<< 5)
-#define PARAM_STEPTIME (1<< 7)
-#define PARAM_SIZE (1<< 8)
-#define PARAM_TIMEFACTOR (1<< 9)
-#define PARAM_ANIFRAMETIME (1<<11)
-#define PARAM_ANISTART (1<<12)
-#define PARAM_SURFACETENSION (1<<13)
-#define PARAM_DENSITY (1<<14)
-#define PARAM_GSTAR (1<<16)
-#define PARAM_SIMMAXSPEED (1<<18)
-#define PARAM_FLUIDVOLHEIGHT (1<<19)
-#define PARAM_NORMALIZEDGSTAR (1<<20)
-#define PARAM_NUMIDS 21
-
-//! output parameter debug message?
-//#define PARAM_DEBUG 1
-
-
-
-/*! Parameter calculator for the LBM Solver class */
-class Parametrizer {
-
- public:
- /*! default contructor */
- Parametrizer();
-
- /*! destructor */
- ~Parametrizer();
-
- /*! Initilize variables fom attribute list */
- void parseAttrList( void );
-
- /*! function that tries to calculate all the missing values from the given ones
- * prints errors and returns false if thats not possible
- * currently needs time value as well */
- bool calculateAllMissingValues( double time, bool silent );
- /*! is the parametrizer used at all? */
- bool isUsed() { return true; }
-
- /*! add this flag to the seen values */
- void seenThis(int seen) { mSeenValues = (mSeenValues | seen);
-#ifdef PARAM_DEBUG
- errorOut(" seen "<<seen<<endl);
-#endif
- }
-
- /*! set the flags integer */
- void setSeenValues(int set) { mSeenValues = set; }
- /*! check if the flags are set in the values int */
- bool checkSeenValues(int check) { /*errorOut( " b"<<((mSeenValues&check)==check) );*/ return ((mSeenValues&check)==check); }
-
- /*! add this flag to the calculated values */
- void calculatedThis(int cac) { mCalculatedValues = (mCalculatedValues | cac); /*errorOut(" a "<<seen);*/ }
- /*! set the calculated flags integer */
- void setCalculatedValues(int set) { mCalculatedValues = set; }
- /*! check if the calculated flags are set in the values int */
- bool checkCalculatedValues(int check) { /*errorOut( " b"<<((mSeenValues&check)==check) );*/ return ((mCalculatedValues&check)==check); }
- /*! advance to next render/output frame */
- void setFrameNum(int frame);
- ParamFloat getAniFrameTime(int frame);
- ParamFloat getCurrentAniFrameTime(){ return getAniFrameTime(mFrameNum); };
-
- /*! scale a given speed vector in m/s to lattice values
- * usage string is only needed for debugging */
- ParamVec calculateAddForce(ParamVec vec, string usage);
-
- /* simple calulation functions */
- /*! get omega for LBM */
- ParamFloat calculateOmega( double time );
- /*! get no. of timesteps for LBM */
- int calculateNoOfSteps( ParamFloat timelen );
- /*! get external force x component */
- ParamVec calculateGravity( double time );
- /*! get no of steps for the given length in seconds */
- int calculateStepsForSecs( ParamFloat s );
- /*! get no of steps for a singel animation frame */
- int calculateAniStepsPerFrame(int frame);
- /*! get start time of animation */
- int calculateAniStart( void );
- /*! get extent of the domain = (1,1,1) if parametrizer not used, (x,y,z) [m] otherwise */
- //ParamVec calculateExtent( void );
- /*! get (scaled) surface tension */
- ParamFloat calculateSurfaceTension( void );
- /*! get time step size for lbm (equals mTimeFactor) */
- // unused ParamFloat calculateTimestep( void );
- /*! calculate size of a single cell */
- ParamFloat calculateCellSize(void);
- /*! calculate the lattice viscosity */
- ParamFloat calculateLatticeViscosity( double time );
-
- /*! calculate lattice velocity from real world value [m/s] */
- ParamVec calculateLattVelocityFromRw( ParamVec ivel );
- /*! calculate real world [m/s] velocity from lattice value */
- ParamVec calculateRwVelocityFromLatt( ParamVec ivel );
-
- /*! set speed of sound */
- void setSoundSpeed(ParamFloat set) { mSoundSpeed = set; seenThis( PARAM_SOUNDSPEED ); }
- /*! get speed of sound */
- ParamFloat getSoundSpeed( void ) { return mSoundSpeed; }
-
- /*! set kinematic viscosity */
- void setViscosity(ParamFloat set);
- void initViscosityChannel(vector<ParamFloat> val, vector<double> time);
-
- /*! set the external force */
- void setGravity(ParamFloat setx, ParamFloat sety, ParamFloat setz);
- void setGravity(ParamVec set);
- void initGravityChannel(vector<ParamVec> val, vector<double> time);
- ParamVec getGravity(double time) { return mcGravity.get( time ); }
-
- /*! set time of an animation frame (renderer) */
- void setAniFrameTimeChannel(ParamFloat set);
- void initAniFrameTimeChannel(vector<ParamFloat> val, vector<double> time);
-
- /*! set the length of a single time step */
- void setTimestep(ParamFloat set) { mTimestep = set; seenThis( PARAM_STEPTIME ); }
- /*! get the length of a single time step */
- ParamFloat getTimestep( void);
- /*! set a desired step time for rescaling/adaptive timestepping */
- void setDesiredTimestep(ParamFloat set) { mDesiredTimestep = set; }
- /*! get the length of a single time step */
- ParamFloat getMaxTimestep( void ) { return mMaxTimestep; }
- /*! get the length of a single time step */
- ParamFloat getMinTimestep( void ) { return mMinTimestep; }
-
- /*! set the time scaling factor */
- void setTimeFactor(ParamFloat set) { mTimeFactor = set; seenThis( PARAM_TIMEFACTOR ); }
- /*! get the time scaling factor */
- ParamFloat getTimeFactor( void ) { return mTimeFactor; }
-
- /*! init domain resoultion */
- void setSize(int ijk) { mSizex = ijk; mSizey = ijk; mSizez = ijk; seenThis( PARAM_SIZE ); }
- void setSize(int i,int j, int k) { mSizex = i; mSizey = j; mSizez = k; seenThis( PARAM_SIZE ); }
-
- /*! set starting time of the animation (renderer) */
- void setAniStart(ParamFloat set) { mAniStart = set; seenThis( PARAM_ANISTART ); }
- /*! get starting time of the animation (renderer) */
- ParamFloat getAniStart( void ) { return mAniStart; }
-
- /*! set fluid density */
- void setDensity(ParamFloat set) { mDensity = set; seenThis( PARAM_DENSITY ); }
- /*! get fluid density */
- ParamFloat getDensity( void ) { return mDensity; }
-
- /*! set g star value */
- void setGStar(ParamFloat set) { mGStar = set; seenThis( PARAM_GSTAR ); }
- /*! get g star value */
- ParamFloat getGStar( void ) { return mGStar; }
- /*! get g star value with fhvol calculations */
- ParamFloat getCurrentGStar( void );
- /*! set normalized g star value */
- void setNormalizedGStar(ParamFloat set) { mNormalizedGStar = set; seenThis( PARAM_NORMALIZEDGSTAR ); }
- /*! get normalized g star value */
- ParamFloat getNormalizedGStar( void ) { return mNormalizedGStar; }
-
- /*! set g star value */
- void setFluidVolumeHeight(ParamFloat set) { mFluidVolumeHeight = set; seenThis( PARAM_FLUIDVOLHEIGHT ); }
- /*! get g star value */
- ParamFloat getFluidVolumeHeight( void ) { return mFluidVolumeHeight; }
-
- /*! set the size of a single lbm cell */
- void setDomainSize(ParamFloat set) { mDomainSize = set; seenThis( PARAM_DOMAINSIZE ); }
- /*! get the size of a single lbm cell */
- ParamFloat getDomainSize( void ) { return mDomainSize; }
-
- /*! set the size of a single lbm cell (dont use, normally set by domainsize and resolution) */
- void setCellSize(ParamFloat set) { mCellSize = set; }
- /*! get the size of a single lbm cell */
- ParamFloat getCellSize( void ) { return mCellSize; }
-
- /*! set active flag for parametrizer */
- //void setActive(bool set) { mActive = set; }
-
- /*! set attr list pointer */
- void setAttrList(AttributeList *set) { mpAttrs = set; }
- /*! Returns the attribute list pointer */
- inline AttributeList *getAttributeList() { return mpAttrs; }
-
- /*! set maximum allowed speed for maxspeed setup */
- void setSimulationMaxSpeed(ParamFloat set) { mSimulationMaxSpeed = set; seenThis( PARAM_SIMMAXSPEED ); }
- /*! get maximum allowed speed for maxspeed setup */
- ParamFloat getSimulationMaxSpeed( void ) { return mSimulationMaxSpeed; }
-
- /*! set maximum allowed omega for time adaptivity */
- void setTadapMaxOmega(ParamFloat set) { mTadapMaxOmega = set; }
- /*! get maximum allowed omega for time adaptivity */
- ParamFloat getTadapMaxOmega( void ) { return mTadapMaxOmega; }
-
- /*! set maximum allowed speed for time adaptivity */
- void setTadapMaxSpeed(ParamFloat set) { mTadapMaxSpeed = set; }
- /*! get maximum allowed speed for time adaptivity */
- ParamFloat getTadapMaxSpeed( void ) { return mTadapMaxSpeed; }
-
- /*! set maximum allowed omega for time adaptivity */
- void setTadapLevels(int set) { mTadapLevels = set; }
- /*! get maximum allowed omega for time adaptivity */
- int getTadapLevels( void ) { return mTadapLevels; }
-
- /*! set */
- // void set(ParamFloat set) { m = set; seenThis( PARAM_ ); }
- /*! get */
- // ParamFloat get( void ) { return m; }
-
-
-
- private:
-
- /*! kinematic viscosity of the fluid [m^2/s] */
- AnimChannel<ParamFloat> mcViscosity;
-
- /*! speed of sound of the fluid [m/s] */
- ParamFloat mSoundSpeed;
-
- /*! size of the domain [m] */
- ParamFloat mDomainSize;
-
- /*! size of a single cell in the grid [m] */
- ParamFloat mCellSize;
-
- /*! time step length [s] */
- ParamFloat mTimeStep;
-
- /*! external force as acceleration [m/s^2] */
- AnimChannel<ParamVec> mcGravity;
-
- /*! length of one time step in the simulation */
- ParamFloat mTimestep;
- /*! desired step time for rescaling/adaptive timestepping, only regarded if >0.0, reset after usage */
- ParamFloat mDesiredTimestep;
- /*! minimal and maximal step times for current setup */
- ParamFloat mMaxTimestep, mMinTimestep;
-
- /*! domain resoultion, the same values as in lbmsolver */
- int mSizex, mSizey, mSizez;
-
- /*! time scaling factor (auto calc from accel, or set), equals the delta t in LBM */
- ParamFloat mTimeFactor;
-
- /*! for renderer - length of an animation step [s] */
- AnimChannel<ParamFloat> mcAniFrameTime;
- /*! time step scaling factor for testing/debugging */
- ParamFloat mTimeStepScale;
-
- /*! for renderer - start time of the animation [s] */
- ParamFloat mAniStart;
-
- /*! extent of the domain in meters */
- //ParamVec mExtent;
-
- /*! fluid density [kg/m^3], default 1.0 g/cm^3 */
- ParamFloat mDensity;
-
- /*! max difference due to gravity (for caro setup) */
- ParamFloat mGStar;
- /*! set gstar normalized! */
- ParamFloat mNormalizedGStar;
- /*! fluid volume/height multiplier for GStar */
- ParamFloat mFluidVolumeHeight;
-
- /*! current max speed of the simulation (for adaptive time steps) */
- ParamFloat mSimulationMaxSpeed;
- /*! maximum omega (for adaptive time steps) */
- ParamFloat mTadapMaxOmega;
- /*! maximum allowed speed in lattice units e.g. 0.1 (for adaptive time steps, not directly used in parametrizer) */
- ParamFloat mTadapMaxSpeed;
- /*! no. of levels for max omega (set by fsgr, not in cfg file) */
- int mTadapLevels;
-
- /*! remember current frame number */
- int mFrameNum;
-
- /*! values that are seen for this simulation */
- int mSeenValues;
-
- /*! values that are calculated from the seen ones for this simulation */
- int mCalculatedValues;
-
- /*! pointer to the attribute list */
- AttributeList *mpAttrs;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:Parametrizer")
-#endif
-};
-
-
-#endif
-
diff --git a/intern/elbeem/intern/particletracer.cpp b/intern/elbeem/intern/particletracer.cpp
deleted file mode 100644
index 7a0005f67ce..00000000000
--- a/intern/elbeem/intern/particletracer.cpp
+++ /dev/null
@@ -1,470 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Particle Viewer/Tracer
- *
- *****************************************************************************/
-
-#include <stdio.h>
-//#include "../libs/my_gl.h"
-//#include "../libs/my_glu.h"
-
-/* own lib's */
-#include "particletracer.h"
-#include "ntl_matrices.h"
-#include "ntl_ray.h"
-#include "ntl_matrices.h"
-#include "globals.h"
-
-#include <zlib.h>
-
-
-// particle object id counter
-int ParticleObjectIdCnt = 1;
-
-/******************************************************************************
- * Standard constructor
- *****************************************************************************/
-ParticleTracer::ParticleTracer() :
- ntlGeometryObject(),
- mParts(),
- //mTrailLength(1), mTrailInterval(1),mTrailIntervalCounter(0),
- mPartSize(0.01),
- mStart(-1.0), mEnd(1.0),
- mSimStart(-1.0), mSimEnd(1.0),
- mPartScale(0.1) , mPartHeadDist( 0.1 ), mPartTailDist( -0.1 ), mPartSegments( 4 ),
- mValueScale(0),
- mValueCutoffTop(0.0), mValueCutoffBottom(0.0),
- mDumpParts(0), //mDumpText(0),
- mDumpTextFile(""),
- mDumpTextInterval(0.), mDumpTextLastTime(0.), mDumpTextCount(0),
- mShowOnly(0),
- mNumInitialParts(0), mpTrafo(NULL),
- mInitStart(-1.), mInitEnd(-1.),
- mPrevs(), mTrailTimeLast(0.), mTrailInterval(-1.), mTrailLength(0)
-{
- debMsgStd("ParticleTracer::ParticleTracer",DM_MSG,"inited",10);
-};
-
-ParticleTracer::~ParticleTracer() {
- debMsgStd("ParticleTracer::~ParticleTracer",DM_MSG,"destroyed",10);
- if(mpTrafo) delete mpTrafo;
-}
-
-/*****************************************************************************/
-//! parse settings from attributes (dont use own list!)
-/*****************************************************************************/
-void ParticleTracer::parseAttrList(AttributeList *att)
-{
- AttributeList *tempAtt = mpAttrs;
- mpAttrs = att;
-
- mNumInitialParts = mpAttrs->readInt("particles",mNumInitialParts, "ParticleTracer","mNumInitialParts", false);
- //errMsg(" NUMP"," "<<mNumInitialParts);
- mPartScale = mpAttrs->readFloat("part_scale",mPartScale, "ParticleTracer","mPartScale", false);
- mPartHeadDist = mpAttrs->readFloat("part_headdist",mPartHeadDist, "ParticleTracer","mPartHeadDist", false);
- mPartTailDist = mpAttrs->readFloat("part_taildist",mPartTailDist, "ParticleTracer","mPartTailDist", false);
- mPartSegments = mpAttrs->readInt ("part_segments",mPartSegments, "ParticleTracer","mPartSegments", false);
- mValueScale = mpAttrs->readInt ("part_valscale",mValueScale, "ParticleTracer","mValueScale", false);
- mValueCutoffTop = mpAttrs->readFloat("part_valcutofftop",mValueCutoffTop, "ParticleTracer","mValueCutoffTop", false);
- mValueCutoffBottom = mpAttrs->readFloat("part_valcutoffbottom",mValueCutoffBottom, "ParticleTracer","mValueCutoffBottom", false);
-
- mDumpParts = mpAttrs->readInt ("part_dump",mDumpParts, "ParticleTracer","mDumpParts", false);
- // mDumpText deprecatd, use mDumpTextInterval>0. instead
- mShowOnly = mpAttrs->readInt ("part_showonly",mShowOnly, "ParticleTracer","mShowOnly", false);
- mDumpTextFile= mpAttrs->readString("part_textdumpfile",mDumpTextFile, "ParticleTracer","mDumpTextFile", false);
- mDumpTextInterval= mpAttrs->readFloat("part_textdumpinterval",mDumpTextInterval, "ParticleTracer","mDumpTextInterval", false);
-
- string matPart;
- matPart = mpAttrs->readString("material_part", "default", "ParticleTracer","material", false);
- setMaterialName( matPart );
-
- mInitStart = mpAttrs->readFloat("part_initstart",mInitStart, "ParticleTracer","mInitStart", false);
- mInitEnd = mpAttrs->readFloat("part_initend", mInitEnd, "ParticleTracer","mInitEnd", false);
-
- // unused...
- //int mTrailLength = 0; // UNUSED
- //int mTrailInterval= 0; // UNUSED
- mTrailLength = mpAttrs->readInt("traillength",mTrailLength, "ParticleTracer","mTrailLength", false);
- mTrailInterval= mpAttrs->readFloat("trailinterval",mTrailInterval, "ParticleTracer","mTrailInterval", false);
-
- // restore old list
- mpAttrs = tempAtt;
-}
-
-/******************************************************************************
- * draw the particle array
- *****************************************************************************/
-void ParticleTracer::draw()
-{
-}
-
-/******************************************************************************
- * init trafo matrix
- *****************************************************************************/
-void ParticleTracer::initTrafoMatrix() {
- ntlVec3Gfx scale = ntlVec3Gfx(
- (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]),
- (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]),
- (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2])
- );
- ntlVec3Gfx trans = mStart;
- if(!mpTrafo) mpTrafo = new ntlMat4Gfx(0.0);
- mpTrafo->initId();
- for(int i=0; i<3; i++) { mpTrafo->value[i][i] = scale[i]; }
- for(int i=0; i<3; i++) { mpTrafo->value[i][3] = trans[i]; }
-}
-
-/******************************************************************************
- * adapt time step by rescaling velocities
- *****************************************************************************/
-void ParticleTracer::adaptPartTimestep(float factor) {
- for(size_t i=0; i<mParts.size(); i++) {
- mParts[i].setVel( mParts[i].getVel() * factor );
- }
-}
-
-
-/******************************************************************************
- * add a particle at this position
- *****************************************************************************/
-void ParticleTracer::addParticle(float x, float y, float z) {
- ntlVec3Gfx p(x,y,z);
- ParticleObject part( p );
- mParts.push_back( part );
-}
-void ParticleTracer::addFullParticle(ParticleObject &np) {
- mParts.push_back( np );
-}
-
-
-void ParticleTracer::cleanup() {
- // cleanup
- int last = (int)mParts.size()-1;
- if(mDumpTextInterval>0.) { errMsg("ParticleTracer::cleanup","Skipping cleanup due to text dump..."); return; }
-
- for(int i=0; i<=last; i++) {
- if( mParts[i].getActive()==false ) {
- ParticleObject *p = &mParts[i];
- ParticleObject *p2 = &mParts[last];
- *p = *p2; last--; mParts.pop_back();
- }
- }
-}
-
-/******************************************************************************
- *! dump particles if desired
- *****************************************************************************/
-void ParticleTracer::notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime) {
- debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"obj:"<<this->getName()<<" frame:"<<frameNrStr<<" dumpp"<<mDumpParts<<" t"<<simtime, 10); // DEBUG
-
- if(
- (dumptype==DUMP_FULLGEOMETRY)&&
- (mDumpParts>0)) {
- // dump to binary file
- std::ostringstream boutfilename("");
- boutfilename << outfilename <<"_particles_" << frameNrStr;
- if(glob_mpactive) {
- if(glob_mpindex>0) { boutfilename << "mp"<<glob_mpindex; }
- }
- boutfilename << ".gz";
- debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"B-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" #"<<frameNr , 7);
- //debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"B-Dumping: partgeodeb sim:"<<mSimStart<<","<<mSimEnd<<" geosize:"<<mStart<<","<<mEnd,2 );
-
- // output to zipped file
- gzFile gzf;
- gzf = gzopen(boutfilename.str().c_str(), "wb1");
- if(gzf) {
- int numParts;
- if(sizeof(numParts)!=4) { errMsg("ParticleTracer::notifyOfDump","Invalid int size"); return; }
- // only dump active particles
- numParts = 0;
- for(size_t i=0; i<mParts.size(); i++) {
- if(!mParts[i].getActive()) continue;
- numParts++;
- }
- gzwrite(gzf, &numParts, sizeof(numParts));
- for(size_t i=0; i<mParts.size(); i++) {
- if(!mParts[i].getActive()) { continue; }
- ParticleObject *p = &mParts[i];
- //int type = p->getType(); // export whole type info
- int type = p->getFlags(); // debug export whole type & status info
- ntlVec3Gfx pos = p->getPos();
- float size = p->getSize();
-
- if(type&PART_FLOAT) { // WARNING same handling for dump!
- // add one gridcell offset
- //pos[2] += 1.0;
- }
- // display as drop for now externally
- //else if(type&PART_TRACER) { type |= PART_DROP; }
-
- pos = (*mpTrafo) * pos;
-
- ntlVec3Gfx v = p->getVel();
- v[0] *= mpTrafo->value[0][0];
- v[1] *= mpTrafo->value[1][1];
- v[2] *= mpTrafo->value[2][2];
- // FIXME check: pos = (*mpTrafo) * pos;
- gzwrite(gzf, &type, sizeof(type));
- gzwrite(gzf, &size, sizeof(size));
- for(int j=0; j<3; j++) { gzwrite(gzf, &pos[j], sizeof(float)); }
- for(int j=0; j<3; j++) { gzwrite(gzf, &v[j], sizeof(float)); }
- }
- gzclose( gzf );
- }
- } // dump?
-}
-
-void ParticleTracer::checkDumpTextPositions(double simtime) {
- // dfor partial & full dump
- if(mDumpTextInterval>0.) {
- debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"t="<<simtime<<" last:"<<mDumpTextLastTime<<" inter:"<<mDumpTextInterval,7);
- }
-
- if((mDumpTextInterval>0.) && (simtime>mDumpTextLastTime+mDumpTextInterval)) {
- // dump to binary file
- std::ostringstream boutfilename("");
- if(mDumpTextFile.length()>1) {
- boutfilename << mDumpTextFile << ".cpart2";
- } else {
- boutfilename << "_particles" << ".cpart2";
- }
- debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"T-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" " , 7);
-
- int numParts = 0;
- // only dump bubble particles
- for(size_t i=0; i<mParts.size(); i++) {
- //if(!mParts[i].getActive()) continue;
- //if(!(mParts[i].getType()&PART_BUBBLE)) continue;
- numParts++;
- }
-
- // output to text file
- //gzFile gzf;
- FILE *stf;
- if(mDumpTextCount==0) {
- //gzf = gzopen(boutfilename.str().c_str(), "w0");
- stf = fopen(boutfilename.str().c_str(), "w");
-
- fprintf( stf, "\n\n# cparts generated by elbeem \n# no. of parts \nN %d \n\n",numParts);
- // fixed time scale for now
- fprintf( stf, "T %f \n\n", 1.0);
- } else {
- //gzf = gzopen(boutfilename.str().c_str(), "a+0");
- stf = fopen(boutfilename.str().c_str(), "a+");
- }
-
- // add current set
- if(stf) {
- fprintf( stf, "\n\n# new set at frame %d,t%f,p%d --------------------------------- \n\n", mDumpTextCount, simtime, numParts );
- fprintf( stf, "S %f \n\n", simtime );
-
- for(size_t i=0; i<mParts.size(); i++) {
- ParticleObject *p = &mParts[i];
- ntlVec3Gfx pos = p->getPos();
- float size = p->getSize();
- float infl = 1.;
- //if(!mParts[i].getActive()) { size=0.; } // switch "off"
- if(!mParts[i].getActive()) { infl=0.; } // switch "off"
- if(!mParts[i].getInFluid()) { infl=0.; } // switch "off"
- if(mParts[i].getLifeTime()<0.) { infl=0.; } // not yet active...
-
- pos = (*mpTrafo) * pos;
- ntlVec3Gfx v = p->getVel();
- v[0] *= mpTrafo->value[0][0];
- v[1] *= mpTrafo->value[1][1];
- v[2] *= mpTrafo->value[2][2];
-
- fprintf( stf, "P %f %f %f \n", pos[0],pos[1],pos[2] );
- if(size!=1.0) fprintf( stf, "s %f \n", size );
- if(infl!=1.0) fprintf( stf, "i %f \n", infl );
- fprintf( stf, "\n" );
- }
-
- fprintf( stf, "# %d end ", mDumpTextCount );
- //gzclose( gzf );
- fclose( stf );
-
- mDumpTextCount++;
- }
-
- mDumpTextLastTime += mDumpTextInterval;
- }
-
-}
-
-
-void ParticleTracer::checkTrails(double time) {
- if(mTrailLength<1) return;
- if(time-mTrailTimeLast > mTrailInterval) {
-
- if( (int)mPrevs.size() < mTrailLength) mPrevs.resize( mTrailLength );
- for(int i=mPrevs.size()-1; i>0; i--) {
- mPrevs[i] = mPrevs[i-1];
- //errMsg("TRAIL"," from "<<i<<" to "<<(i-1) );
- }
- mPrevs[0] = mParts;
-
- mTrailTimeLast += mTrailInterval;
- }
-}
-
-
-/******************************************************************************
- * Get triangles for rendering
- *****************************************************************************/
-void ParticleTracer::getTriangles(double time, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId )
-{
-#ifdef ELBEEM_PLUGIN
- // suppress warnings...
- vertices = NULL; triangles = NULL;
- normals = NULL; objectId = 0;
- time = 0.;
-#else // ELBEEM_PLUGIN
- int pcnt = 0;
- // currently not used in blender
- objectId = 0; // remove, deprecated
- if(mDumpParts>1) {
- return; // only dump, no tri-gen
- }
-
- const bool debugParts = false;
- int tris = 0;
- int segments = mPartSegments;
- ntlVec3Gfx scale = ntlVec3Gfx( (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]), (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]), (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2]));
- ntlVec3Gfx trans = mStart;
- time = 0.; // doesnt matter
-
- for(size_t t=0; t<mPrevs.size()+1; t++) {
- vector<ParticleObject> *dparts;
- if(t==0) {
- dparts = &mParts;
- } else {
- dparts = &mPrevs[t-1];
- }
- //errMsg("TRAILT","prevs"<<t<<"/"<<mPrevs.size()<<" parts:"<<dparts->size() );
-
- gfxReal partscale = mPartScale;
- if(t>1) {
- partscale *= (gfxReal)(mPrevs.size()+1-t) / (gfxReal)(mPrevs.size()+1);
- }
- gfxReal partNormSize = 0.01 * partscale;
- //for(size_t i=0; i<mParts.size(); i++) {
- for(size_t i=0; i<dparts->size(); i++) {
- ParticleObject *p = &( (*dparts)[i] ); // mParts[i];
-
- if(mShowOnly!=10) {
- // 10=show only deleted
- if( p->getActive()==false ) continue;
- } else {
- if( p->getActive()==true ) continue;
- }
- int type = p->getType();
- if(mShowOnly>0) {
- switch(mShowOnly) {
- case 1: if(!(type&PART_BUBBLE)) continue; break;
- case 2: if(!(type&PART_DROP)) continue; break;
- case 3: if(!(type&PART_INTER)) continue; break;
- case 4: if(!(type&PART_FLOAT)) continue; break;
- case 5: if(!(type&PART_TRACER)) continue; break;
- }
- } else {
- // by default dont display inter
- if(type&PART_INTER) continue;
- }
-
- pcnt++;
- ntlVec3Gfx pnew = p->getPos();
- if(type&PART_FLOAT) { // WARNING same handling for dump!
- if(p->getStatus()&PART_IN) { pnew[2] += 0.8; } // offset for display
- // add one gridcell offset
- //pnew[2] += 1.0;
- }
-#if LBMDIM==2
- pnew[2] += 0.001; // DEBUG
- pnew[2] += 0.009; // DEBUG
-#endif
-
- ntlVec3Gfx pdir = p->getVel();
- gfxReal plen = normalize( pdir );
- if( plen < 1e-05) pdir = ntlVec3Gfx(-1.0 ,0.0 ,0.0);
- ntlVec3Gfx pos = (*mpTrafo) * pnew;
- gfxReal partsize = 0.0;
- if(debugParts) errMsg("DebugParts"," i"<<i<<" new"<<pnew<<" vel"<<pdir<<" pos="<<pos );
- //if(i==0 &&(debugParts)) errMsg("DebugParts"," i"<<i<<" new"<<pnew[0]<<" pos="<<pos[0]<<" scale="<<scale[0]<<" t="<<trans[0] );
-
- // value length scaling?
- if(mValueScale==1) {
- partsize = partscale * plen;
- } else if(mValueScale==2) {
- // cut off scaling
- if(plen > mValueCutoffTop) continue;
- if(plen < mValueCutoffBottom) continue;
- partsize = partscale * plen;
- } else {
- partsize = partscale; // no length scaling
- }
- //if(type&(PART_DROP|PART_BUBBLE))
- partsize *= p->getSize()/5.0;
-
- ntlVec3Gfx pstart( mPartHeadDist *partsize, 0.0, 0.0 );
- ntlVec3Gfx pend ( mPartTailDist *partsize, 0.0, 0.0 );
- gfxReal phi = 0.0;
- gfxReal phiD = 2.0*M_PI / (gfxReal)segments;
-
- ntlMat4Gfx cvmat;
- cvmat.initId();
- pdir *= -1.0;
- ntlVec3Gfx cv1 = pdir;
- ntlVec3Gfx cv2 = ntlVec3Gfx(pdir[1], -pdir[0], 0.0);
- ntlVec3Gfx cv3 = cross( cv1, cv2);
- //? for(int l=0; l<3; l++) { cvmat.value[l][0] = cv1[l]; cvmat.value[l][1] = cv2[l]; cvmat.value[l][2] = cv3[l]; }
- pstart = (cvmat * pstart);
- pend = (cvmat * pend);
-
- for(int s=0; s<segments; s++) {
- ntlVec3Gfx p1( 0.0 );
- ntlVec3Gfx p2( 0.0 );
-
- gfxReal radscale = partNormSize;
- radscale = (partsize+partNormSize)*0.5;
- p1[1] += cos(phi) * radscale;
- p1[2] += sin(phi) * radscale;
- p2[1] += cos(phi + phiD) * radscale;
- p2[2] += sin(phi + phiD) * radscale;
- ntlVec3Gfx n1 = ntlVec3Gfx( 0.0, cos(phi), sin(phi) );
- ntlVec3Gfx n2 = ntlVec3Gfx( 0.0, cos(phi + phiD), sin(phi + phiD) );
- ntlVec3Gfx ns = n1*0.5 + n2*0.5;
-
- p1 = (cvmat * p1);
- p2 = (cvmat * p2);
-
- sceneAddTriangle( pos+pstart, pos+p1, pos+p2,
- ns,n1,n2, ntlVec3Gfx(0.0), 1, triangles,vertices,normals );
- sceneAddTriangle( pos+pend , pos+p2, pos+p1,
- ns,n2,n1, ntlVec3Gfx(0.0), 1, triangles,vertices,normals );
-
- phi += phiD;
- tris += 2;
- }
- }
-
- } // t
-
- debMsgStd("ParticleTracer::getTriangles",DM_MSG,"Dumped "<<pcnt<<"/"<<mParts.size()<<" parts, tris:"<<tris<<", showonly:"<<mShowOnly,10);
- return; // DEBUG
-
-#endif // ELBEEM_PLUGIN
-}
-
-
-
-
diff --git a/intern/elbeem/intern/particletracer.h b/intern/elbeem/intern/particletracer.h
deleted file mode 100644
index 10b37406f8c..00000000000
--- a/intern/elbeem/intern/particletracer.h
+++ /dev/null
@@ -1,296 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Particle Viewer/Tracer
- *
- *****************************************************************************/
-#ifndef NTL_PARTICLETRACER_H
-
-#include "ntl_geometryobject.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-template<class Scalar> class ntlMatrix4x4;
-
-// particle types
-#define PART_BUBBLE (1<< 1)
-#define PART_DROP (1<< 2)
-#define PART_INTER (1<< 3)
-#define PART_FLOAT (1<< 4)
-#define PART_TRACER (1<< 5)
-
-// particle state
-#define PART_IN (1<< 8)
-#define PART_OUT (1<< 9)
-#define PART_INACTIVE (1<<10)
-#define PART_OUTFLUID (1<<11)
-
-// defines for particle movement
-#define MOVE_FLOATS 1
-#define FLOAT_JITTER 0.03
-//#define FLOAT_JITTER 0.0
-
-extern int ParticleObjectIdCnt;
-
-//! A single particle
-class ParticleObject
-{
- public:
- //! Standard constructor
- inline ParticleObject(ntlVec3Gfx mp) :
- mPos(mp),mVel(0.0), mSize(1.0), mStatus(0),mLifeTime(0),mpNext(NULL)
- { mId = ParticleObjectIdCnt++; };
- //! Copy constructor
- inline ParticleObject(const ParticleObject &a) :
- mPos(a.mPos), mVel(a.mVel), mSize(a.mSize),
- mStatus(a.mStatus),
- mLifeTime(a.mLifeTime), mpNext(NULL)
- { mId = ParticleObjectIdCnt++; };
- //! Destructor
- inline ~ParticleObject() { /* empty */ };
-
- //! add vector to position
- inline void advance(float vx, float vy, float vz) {
- mPos[0] += vx; mPos[1] += vy; mPos[2] += vz; }
- inline void advanceVec(ntlVec3Gfx v) {
- mPos[0] += v[0]; mPos[1] += v[1]; mPos[2] += v[2]; }
- //! advance with own velocity
- inline void advanceVel() { mPos += mVel; }
- //! add acceleration to velocity
- inline void addToVel(ntlVec3Gfx acc) { mVel += acc; }
-
- //! get/set vector to position
- inline ntlVec3Gfx getPos() { return mPos; }
- inline void setPos(ntlVec3Gfx set) { mPos=set; }
- //! set velocity
- inline void setVel(ntlVec3Gfx set) { mVel = set; }
- //! set velocity
- inline void setVel(gfxReal x, gfxReal y, gfxReal z) { mVel = ntlVec3Gfx(x,y,z); }
- //! get velocity
- inline ntlVec3Gfx getVel() { return mVel; }
-
- //! get/set size value
- inline gfxReal getSize() { return mSize; }
- inline void setSize(gfxReal set) { mSize=set; }
-
- //! get/set next pointer
- inline ParticleObject* getNext() { return mpNext; }
- inline void setNext(ParticleObject* set) { mpNext=set; }
-
- //! get whole flags
- inline int getFlags() const { return mStatus; }
- //! get status (higher byte)
- inline int getStatus() const { return (mStatus&0xFF00); }
- //! set status (higher byte)
- inline void setStatus(int set) { mStatus = set|(mStatus&0x00FF); }
- //! get type (lower byte)
- inline int getType() const { return (mStatus&0x00FF); }
- //! set type (lower byte)
- inline void setType(int set) { mStatus = set|(mStatus&0xFF00); }
- //! get active flag
- inline bool getActive() const { return ((mStatus&PART_INACTIVE)==0); }
- //! set active flag
- inline void setActive(bool set) {
- if(set) mStatus &= (~PART_INACTIVE);
- else mStatus |= PART_INACTIVE;
- }
- //! get influid flag
- inline bool getInFluid() const { return ((mStatus&PART_OUTFLUID)==0); }
- //! set influid flag
- inline void setInFluid(bool set) {
- if(set) mStatus &= (~PART_OUTFLUID);
- else mStatus |= PART_OUTFLUID;
- }
- //! get/set lifetime
- inline float getLifeTime() const { return mLifeTime; }
- //! set type (lower byte)
- inline void setLifeTime(float set) { mLifeTime = set; }
-
- inline int getId() const { return mId; }
-
- static inline float getMass(float size) {
- return 4.0/3.0 * M_PI* (size)*(size)*(size); // mass: 4/3 pi r^3 rho
- }
-
- protected:
-
- /*! only for debugging */
- int mId;
- /*! the particle position */
- ntlVec3Gfx mPos;
- /*! the particle velocity */
- ntlVec3Gfx mVel;
- /*! size / mass of particle */
- gfxReal mSize;
- /*! particle status */
- int mStatus;
- /*! count survived time steps */
- float mLifeTime;
-
- /* for list constructions */
- ParticleObject *mpNext;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ParticleObject")
-#endif
-};
-
-
-//! A whole particle array
-class ParticleTracer :
- public ntlGeometryObject
-{
- public:
- //! Standard constructor
- ParticleTracer();
- //! Destructor
- ~ParticleTracer();
-
- //! add a particle at this position
- void addParticle(float x, float y, float z);
- //! add/copy a particle from inited struct
- void addFullParticle(ParticleObject &np);
-
- //! draw the particle array
- void draw();
-
- //! parse settings from attributes (dont use own list!)
- void parseAttrList( AttributeList *att );
-
- //! adapt time step by rescaling velocities
- void adaptPartTimestep(float factor);
-
- // access funcs
-
- //! get the number of particles
- inline int getNumParticles() { return mParts.size(); }
- //! set/get the number of particles
- inline void setNumInitialParticles(int set) { mNumInitialParts=set; }
- inline int getNumInitialParticles() { return mNumInitialParts; }
-
- //! iterate over all newest particles (for advancing positions)
- inline vector<ParticleObject>::iterator getParticlesBegin() { return mParts.begin(); }
- //! end iterator for newest particles
- inline vector<ParticleObject>::iterator getParticlesEnd() { return mParts.end(); }
- //! end iterator for newest particles
- inline ParticleObject* getLast() { return &(mParts[ mParts.size()-1 ]); }
-
- /*! set geometry start (for renderer) */
- inline void setStart(ntlVec3Gfx set) { mStart = set; initTrafoMatrix(); }
- /*! set geometry end (for renderer) */
- inline void setEnd(ntlVec3Gfx set) { mEnd = set; initTrafoMatrix(); }
- /*! get values */
- inline ntlVec3Gfx getStart() { return mStart; }
- /*! set geometry end (for renderer) */
- inline ntlVec3Gfx getEnd() { return mEnd; }
-
- /*! set simulation domain start */
- inline void setSimStart(ntlVec3Gfx set) { mSimStart = set; initTrafoMatrix(); }
- /*! set simulation domain end */
- inline void setSimEnd(ntlVec3Gfx set) { mSimEnd = set; initTrafoMatrix(); }
-
- /*! set/get dump flag */
- inline void setDumpParts(bool set) { mDumpParts = set; }
- inline bool getDumpParts() { return mDumpParts; }
- /*! set/get dump text file */
- inline void setDumpTextFile(string set) { mDumpTextFile = set; }
- inline string getDumpTextFile() { return mDumpTextFile; }
- /*! set/get dump text interval */
- inline void setDumpTextInterval(float set) { mDumpTextInterval = set; }
- inline float getDumpTextInterval() { return mDumpTextInterval; }
- /*! set/get init times */
- inline void setInitStart(float set) { mInitStart = set; }
- inline float getInitStart() { return mInitStart; }
- inline void setInitEnd(float set) { mInitEnd = set; }
- inline float getInitEnd() { return mInitEnd; }
-
- //! set the particle scaling factor
- inline void setPartScale(float set) { mPartScale = set; }
-
- //! called after each frame to check if positions should be dumped
- void checkDumpTextPositions(double simtime);
-
- // NTL geometry implementation
- /*! Get the triangles from this object */
- virtual void getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId );
-
- virtual void notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename,double simtime);
-
- // notify of next step for trails
- void checkTrails(double time);
- // free deleted particles
- void cleanup();
-
- protected:
-
- /*! the particle array (for multiple timesteps) */
- vector<ParticleObject> mParts;
-
- /*! size of the particles to display */
- float mPartSize;
-
- /*! start and end vectors for the triangulation region to create particles in */
- ntlVec3Gfx mStart, mEnd;
-
- /*! start and end vectors of the simulation domain */
- ntlVec3Gfx mSimStart, mSimEnd;
-
- /*! scaling param for particles */
- float mPartScale;
- /*! head and tail distance for particle shapes */
- float mPartHeadDist, mPartTailDist;
- /*! no of segments for particle cone */
- int mPartSegments;
- /*! use length/absval of values to scale particles? */
- int mValueScale;
- /*! value length maximal cutoff value, for mValueScale==2 */
- float mValueCutoffTop;
- /*! value length minimal cutoff value, for mValueScale==2 */
- float mValueCutoffBottom;
-
- /*! dump particles (or certain types of) to disk? */
- int mDumpParts;
- /*! text dump output file */
- string mDumpTextFile;
- /*! text dump interval, start at t=0, dumping active if >0 */
- float mDumpTextInterval;
- float mDumpTextLastTime;
- int mDumpTextCount;
- /*! show only a certain type (debugging) */
- int mShowOnly;
- /*! no. of particles to init */
- int mNumInitialParts;
-
- //! transform matrix
- ntlMatrix4x4<gfxReal> *mpTrafo;
- /*! init sim/pos transformation */
- void initTrafoMatrix();
-
- //! init time distribution start/end
- float mInitStart, mInitEnd;
-
- /*! the particle array (for multiple timesteps) */
- vector< vector<ParticleObject> > mPrevs;
- /* prev pos save interval */
- float mTrailTimeLast, mTrailInterval;
- int mTrailLength;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ParticleTracer")
-#endif
-};
-
-#define NTL_PARTICLETRACER_H
-#endif
-
diff --git a/intern/elbeem/intern/simulation_object.cpp b/intern/elbeem/intern/simulation_object.cpp
deleted file mode 100644
index bba202300e9..00000000000
--- a/intern/elbeem/intern/simulation_object.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Basic interface for all simulation modules
- *
- *****************************************************************************/
-
-#include "simulation_object.h"
-#include "solver_interface.h"
-#include "ntl_bsptree.h"
-#include "ntl_ray.h"
-#include "ntl_world.h"
-#include "solver_interface.h"
-#include "particletracer.h"
-#include "elbeem.h"
-
-#if PARALLEL==1
-#include <omp.h>
-#endif
-
-#ifdef _WIN32
-#else
-#include <sys/time.h>
-#endif
-
-
-//! lbm factory functions
-LbmSolverInterface* createSolver();
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-SimulationObject::SimulationObject() :
- ntlGeometryShader(),
- mGeoStart(-100.0), mGeoEnd(100.0),
- mpGiTree(NULL), mpGiObjects(NULL),
- mpGlob(NULL),
- mPanic( false ),
- mDebugType( 1 /* =FLUIDDISPNothing*/ ),
- mpLbm(NULL), mpParam( NULL ),
- mShowSurface(true), mShowParticles(false),
- mSelectedCid( NULL ),
- mpElbeemSettings( NULL )
-
-{
- mpParam = new Parametrizer();
- //for(int i=0; i<MAX_DEBDISPSET; i++) { mDebDispSet[i].type = (i); mDebDispSet[i].on = false; mDebDispSet[i].scale = 1.0; }
-
- // reset time
- mTime = 0.0;
-}
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-SimulationObject::~SimulationObject()
-{
- if(mpGiTree) delete mpGiTree;
- if(mpElbeemSettings) delete mpElbeemSettings;
- if(mpLbm) delete mpLbm;
- if(mpParam) delete mpParam;
- if(mpParts) delete mpParts;
- debMsgStd("SimulationObject",DM_MSG,"El'Beem Done!\n",10);
-}
-
-
-
-/*****************************************************************************/
-/*! init tree for certain geometry init */
-/*****************************************************************************/
-void SimulationObject::initGeoTree() {
- // unused!! overriden by solver interface
- if(mpGlob == NULL) {
- errFatal("SimulationObject::initGeoTree error","Requires globals!", SIMWORLD_INITERROR);
- return;
- }
- ntlScene *scene = mpGlob->getSimScene();
- mpGiObjects = scene->getObjects();
-
- if(mpGiTree != NULL) delete mpGiTree;
- char treeFlag = (1<<(mGeoInitId+4));
- mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here...
- scene, treeFlag );
- // unused!! overriden by solver interface
-}
-
-/*****************************************************************************/
-/*! destroy tree etc. when geometry init done */
-/*****************************************************************************/
-void SimulationObject::freeGeoTree() {
- if(mpGiTree != NULL) delete mpGiTree;
-}
-
-
-
-// copy & remember settings for later use
-void SimulationObject::copyElbeemSettings(elbeemSimulationSettings *settings) {
- mpElbeemSettings = new elbeemSimulationSettings;
- *mpElbeemSettings = *settings;
-
- mGeoInitId = settings->domainId+1;
- debMsgStd("SimulationObject",DM_MSG,"mGeoInitId="<<mGeoInitId<<", domainId="<<settings->domainId, 8);
-}
-
-/******************************************************************************
- * simluation interface: initialize simulation using the given configuration file
- *****************************************************************************/
-extern int glob_mpnum;
-int SimulationObject::initializeLbmSimulation(ntlRenderGlobals *glob)
-{
- if(! isSimworldOk() ) return 1;
-
- // already inited?
- if(mpLbm) return 0;
-
- mpGlob = glob;
- if(!getVisible()) {
- mpAttrs->setAllUsed();
- return 0;
- }
-
-
- mGeoInitId = mpAttrs->readInt("geoinitid", mGeoInitId,"LbmSolverInterface", "mGeoInitId", false);
- //mDimension, mSolverType are deprecated
- string mSolverType("");
- mSolverType = mpAttrs->readString("solver", mSolverType, "SimulationObject","mSolverType", false );
-
- mpLbm = createSolver();
- /* check lbm pointer */
- if(mpLbm == NULL) {
- errFatal("SimulationObject::initializeLbmSimulation","Unable to init LBM solver! ", SIMWORLD_INITERROR);
- return 2;
- }
- debMsgStd("SimulationObject::initialized",DM_MSG,"IdStr:"<<mpLbm->getIdString() <<" LBM solver! ", 2);
-
- mpParts = new ParticleTracer();
-
- // for non-param simulations
- mpLbm->setParametrizer( mpParam );
- mpParam->setAttrList( getAttributeList() );
- // not needed.. done in solver_init: mpParam->setSize ... in solver_interface
- mpParam->parseAttrList();
-
- mpLbm->setAttrList( getAttributeList() );
- mpLbm->setSwsAttrList( getSwsAttributeList() );
- mpLbm->parseAttrList();
- mpParts->parseAttrList( getAttributeList() );
-
- if(! isSimworldOk() ) return 3;
- mpParts->setName( getName() + "_part" );
- mpParts->initialize( glob );
- if(! isSimworldOk() ) return 4;
-
- // init material settings
- string matMc("default");
- matMc = mpAttrs->readString("material_surf", matMc, "SimulationObject","matMc", false );
- mShowSurface = mpAttrs->readInt("showsurface", mShowSurface, "SimulationObject","mShowSurface", false );
- mShowParticles = mpAttrs->readInt("showparticles", mShowParticles, "SimulationObject","mShowParticles", false );
-
- checkBoundingBox( mGeoStart, mGeoEnd, "SimulationObject::initializeSimulation" );
- mpLbm->setLbmInitId( mGeoInitId );
- mpLbm->setGeoStart( mGeoStart );
- mpLbm->setGeoEnd( mGeoEnd );
- mpLbm->setRenderGlobals( mpGlob );
- mpLbm->setName( getName() + "_lbm" );
- mpLbm->setParticleTracer( mpParts );
- if(mpElbeemSettings) {
- // set further settings from API struct init
- this->mOutFilename = string(mpElbeemSettings->outputPath);
- mpLbm->initDomainTrafo( mpElbeemSettings->surfaceTrafo );
- mpLbm->setSmoothing(1.0 * mpElbeemSettings->surfaceSmoothing, 1.0 * mpElbeemSettings->surfaceSmoothing);
- mpLbm->setIsoSubdivs(mpElbeemSettings->surfaceSubdivs);
-#if PARALLEL==1
- mpLbm->setNumOMPThreads(mpElbeemSettings->threads);
-#endif
- mpLbm->setSizeX(mpElbeemSettings->resolutionxyz);
- mpLbm->setSizeY(mpElbeemSettings->resolutionxyz);
- mpLbm->setSizeZ(mpElbeemSettings->resolutionxyz);
- mpLbm->setPreviewSize(mpElbeemSettings->previewresxyz);
- mpLbm->setRefinementDesired(mpElbeemSettings->maxRefine);
- mpLbm->setGenerateParticles(mpElbeemSettings->generateParticles);
- // set initial particles
- mpParts->setNumInitialParticles(mpElbeemSettings->numTracerParticles);
-
- // surface generation flag
- mpLbm->setSurfGenSettings(mpElbeemSettings->mFsSurfGenSetting);
-
- string dinitType = string("no");
- if (mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_PARTSLIP) dinitType = string("part");
- else if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_FREESLIP) dinitType = string("free");
- else /*if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_NOSLIP)*/ dinitType = string("no");
- mpLbm->setDomainBound(dinitType);
- mpLbm->setDomainPartSlip(mpElbeemSettings->domainobsPartslip);
- mpLbm->setDumpVelocities(mpElbeemSettings->generateVertexVectors);
- mpLbm->setFarFieldSize(mpElbeemSettings->farFieldSize);
- debMsgStd("SimulationObject::initialize",DM_MSG,"Added domain bound: "<<dinitType<<" ps="<<mpElbeemSettings->domainobsPartslip<<" vv"<<mpElbeemSettings->generateVertexVectors<<","<<mpLbm->getDumpVelocities(), 9 );
-
- debMsgStd("SimulationObject::initialize",DM_MSG,"Set ElbeemSettings values "<<mpLbm->getGenerateParticles(),10);
- }
-
- if(! mpLbm->initializeSolverMemory() ) { errMsg("SimulationObject::initialize","initializeSolverMemory failed"); mPanic=true; return 10; }
- if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverMemory status"); mPanic=true; return 11; }
- if(! mpLbm->initializeSolverGrids() ) { errMsg("SimulationObject::initialize","initializeSolverGrids failed"); mPanic=true; return 12; }
- if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverGrids status"); mPanic=true; return 13; }
- if(! mpLbm->initializeSolverPostinit() ) { errMsg("SimulationObject::initialize","initializeSolverPostin failed"); mPanic=true; return 14; }
- if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverPostin status"); mPanic=true; return 15; }
-
- // print cell type stats
- bool printStats = true;
- if(glob_mpnum>0) printStats=false; // skip in this case
- if(printStats) {
- const int jmax = sizeof(CellFlagType)*8;
- int totalCells = 0;
- int flagCount[jmax];
- for(int j=0; j<jmax ; j++) flagCount[j] = 0;
- int diffInits = 0;
- LbmSolverInterface::CellIdentifier cid = mpLbm->getFirstCell();
- for(; mpLbm->noEndCell( cid );
- mpLbm->advanceCell( cid ) ) {
- int flag = mpLbm->getCellFlag(cid,0);
- int flag2 = mpLbm->getCellFlag(cid,1);
- if(flag != flag2) {
- diffInits++;
- }
- for(int j=0; j<jmax ; j++) {
- if( flag&(1<<j) ) flagCount[j]++;
- }
- totalCells++;
- }
- mpLbm->deleteCellIterator( &cid );
-
- char charNl = '\n';
- debugOutNnl("SimulationObject::initializeLbmSimulation celltype stats: " <<charNl, 5);
- debugOutNnl("no. of cells = "<<totalCells<<", "<<charNl ,5);
- for(int j=0; j<jmax ; j++) {
- std::ostringstream out;
- if(flagCount[j]>0) {
- out<<"\t" << flagCount[j] <<" x "<< convertCellFlagType2String( (CellFlagType)(1<<j) ) <<", " << charNl;
- debugOutNnl(out.str(), 5);
- }
- }
- // compute dist. of empty/bnd - fluid - if
- // cfEmpty = (1<<0), cfBnd = (1<< 2), cfFluid = (1<<10), cfInter = (1<<11),
- if(1){
- std::ostringstream out;
- out.precision(2); out.width(4);
- int totNum = flagCount[1]+flagCount[2]+flagCount[7]+flagCount[8];
- double ebFrac = (double)(flagCount[1]+flagCount[2]) / totNum;
- double flFrac = (double)(flagCount[7]) / totNum;
- double ifFrac = (double)(flagCount[8]) / totNum;
- //???
- out<<"\tFractions: [empty/bnd - fluid - interface - ext. if] = [" << ebFrac<<" - " << flFrac<<" - " << ifFrac<<"] "<< charNl;
-
- if(diffInits > 0) {
- debMsgStd("SimulationObject::initializeLbmSimulation",DM_MSG,"celltype Warning: Diffinits="<<diffInits<<"!" , 5);
- }
- debugOutNnl(out.str(), 5);
- }
- } // cellstats
-
- // might be modified by mpLbm
- //mpParts->setStart( mGeoStart );? mpParts->setEnd( mGeoEnd );?
- mpParts->setStart( mpLbm->getGeoStart() );
- mpParts->setEnd( mpLbm->getGeoEnd() );
- mpParts->setCastShadows( false );
- mpParts->setReceiveShadows( false );
- mpParts->searchMaterial( glob->getMaterials() );
-
- // this has to be inited here - before, the values might be unknown
- IsoSurface *surf = mpLbm->getSurfaceGeoObj();
- if(surf) {
- surf->setName( "final" ); // final surface mesh
- // warning - this might cause overwriting effects for multiple sims and geom dump...
- surf->setCastShadows( true );
- surf->setReceiveShadows( false );
- surf->searchMaterial( glob->getMaterials() );
- if(mShowSurface) mObjects.push_back( surf );
- }
-
-#ifdef ELBEEM_PLUGIN
- mShowParticles=1; // for e.g. dumping
-#endif // ELBEEM_PLUGIN
- if((mpLbm->getGenerateParticles()>0.0)||(mpParts->getNumInitialParticles()>0)) {
- mShowParticles=1;
- mpParts->setDumpParts(true);
- }
- //debMsgStd("SimulationObject::init",DM_NOTIFY,"Using envvar ELBEEM_DUMPPARTICLE to set mShowParticles, DEBUG!",1);
- //} // DEBUG ENABLE!!!!!!!!!!
- if(mShowParticles) {
- mObjects.push_back(mpParts);
- }
-
- // add objects to display for debugging (e.g. levelset particles)
- vector<ntlGeometryObject *> debugObjs = mpLbm->getDebugObjects();
- for(size_t i=0;i<debugObjs.size(); i++) {
- debugObjs[i]->setCastShadows( false );
- debugObjs[i]->setReceiveShadows( false );
- debugObjs[i]->searchMaterial( glob->getMaterials() );
- mObjects.push_back( debugObjs[i] );
- debMsgStd("SimulationObject::init",DM_NOTIFY,"Added debug obj "<<debugObjs[i]->getName(), 10 );
- }
- return 0;
-}
-
-/*! set current frame */
-void SimulationObject::setFrameNum(int num) {
- // advance parametrizer
- mpParam->setFrameNum(num);
-}
-
-/******************************************************************************
- * simluation interface: advance simulation another step (whatever delta time that might be)
- *****************************************************************************/
-void SimulationObject::step( void )
-{
- if(mpParam->getCurrentAniFrameTime()>0.0) {
- // dont advance for stopped time
- mpLbm->step();
- mTime += mpParam->getTimestep();
- //if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); xit(1); } // PROFILE DEBUG TEST!
- }
- if(mpLbm->getPanic()) mPanic = true;
-
- checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0);
- //if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) {
- //int ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, FLUIDSIM_CBSTATUS_STEP, 0);
- //errMsg("runSimulationCallback cbtest1"," "<<this->getName()<<" ret="<<ret);
- //}
- //debMsgStd("SimulationObject::step",DM_MSG," Sim '"<<mName<<"' stepped to "<<mTime<<" (stept="<<(mpParam->getTimestep())<<", framet="<<getFrameTime()<<") ", 10);
-}
-/*! prepare visualization of simulation for e.g. raytracing */
-void SimulationObject::prepareVisualization( void ) {
- if(mPanic) return;
- mpLbm->prepareVisualization();
-}
-
-
-/******************************************************************************/
-/* get current start simulation time */
-double SimulationObject::getStartTime( void ) {
- //return mpParam->calculateAniStart();
- return mpParam->getAniStart();
-}
-/* get time for a single animation frame */
-double SimulationObject::getFrameTime( int frame ) {
- return mpParam->getAniFrameTime(frame);
-}
-/* get time for a single time step */
-double SimulationObject::getTimestep( void ) {
- return mpParam->getTimestep();
-}
-
-
-/******************************************************************************
- * return a pointer to the geometry object of this simulation
- *****************************************************************************/
-//ntlGeometryObject *SimulationObject::getGeometry() { return mpMC; }
-vector<ntlGeometryObject *>::iterator
-SimulationObject::getObjectsBegin()
-{
- return mObjects.begin();
-}
-vector<ntlGeometryObject *>::iterator
-SimulationObject::getObjectsEnd()
-{
- return mObjects.end();
-}
-
-
-
-
-
-/******************************************************************************
- * GUI - display debug info
- *****************************************************************************/
-
-void SimulationObject::drawDebugDisplay() {
-#ifndef NOGUI
- if(!getVisible()) return;
-
- //if( mDebugType > (MAX_DEBDISPSET-1) ){ errFatal("SimulationObject::drawDebugDisplay","Invalid debug type!", SIMWORLD_GENERICERROR); return; }
- //mDebDispSet[ mDebugType ].on = true;
- //errorOut( mDebugType <<"//"<< mDebDispSet[mDebugType].type );
- mpLbm->debugDisplay( mDebugType );
-
- //::lbmMarkedCellDisplay<>( mpLbm );
- mpLbm->lbmMarkedCellDisplay();
-#endif
-}
-
-/* GUI - display interactive info */
-void SimulationObject::drawInteractiveDisplay()
-{
-#ifndef NOGUI
- if(!getVisible()) return;
- if(mSelectedCid) {
- // in debugDisplayNode if dispset is on is ignored...
- mpLbm->debugDisplayNode( FLUIDDISPGrid, mSelectedCid );
- }
-#endif
-}
-
-
-/*******************************************************************************/
-// GUI - handle mouse movement for selection
-/*******************************************************************************/
-void SimulationObject::setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir)
-{
- normalize( dir );
- // assume 2D sim is in XY plane...
-
- double zplane = (mGeoEnd[2]-mGeoStart[2])*0.5;
- double zt = (zplane-org[2]) / dir[2];
- ntlVec3Gfx pos(
- org[0]+ dir[0] * zt,
- org[1]+ dir[1] * zt, 0.0);
-
- mSelectedCid = mpLbm->getCellAt( pos );
- //errMsg("SMP ", mName<< x<<" "<<y<<" - "<<dir );
- x = y = 0; // remove warning
-}
-
-
-void SimulationObject::setMouseClick()
-{
- if(mSelectedCid) {
- //::debugPrintNodeInfo<>( mpLbm, mSelectedCid, mpLbm->getNodeInfoString() );
- mpLbm->debugPrintNodeInfo( mSelectedCid );
- }
-}
-
-/*! notify object that dump is in progress (e.g. for field dump) */
-void SimulationObject::notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) {
- if(!mpLbm) return;
-
- mpLbm->notifySolverOfDump(dumptype, frameNr,frameNrStr,outfilename);
- checkCallerStatus(FLUIDSIM_CBSTATUS_NEWFRAME, frameNr);
-}
-
-/*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */
-int SimulationObject::checkCallerStatus(int status, int frame) {
- //return 0; // DEBUG
- int ret = 0;
- if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) {
- ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, status,frame);
- if(ret!=FLUIDSIM_CBRET_CONTINUE) {
- if(ret==FLUIDSIM_CBRET_STOP) {
- debMsgStd("SimulationObject::notifySolverOfDump",DM_NOTIFY,"Got stop signal from caller",1);
- setElbeemState( SIMWORLD_STOP );
- }
- else if(ret==FLUIDSIM_CBRET_ABORT) {
- errFatal("SimulationObject::notifySolverOfDump","Got abort signal from caller, aborting...", SIMWORLD_GENERICERROR );
- mPanic = 1;
- }
- else {
- errMsg("SimulationObject::notifySolverOfDump","Invalid callback return value: "<<ret<<", ignoring... ");
- }
- }
- }
-
- //debMsgStd("SimulationObject::checkCallerStatus",DM_MSG, "s="<<status<<",f="<<frame<<" "<<this->getName()<<" ret="<<ret);
- if(isSimworldOk()) return 0;
- return 1;
-}
-
diff --git a/intern/elbeem/intern/simulation_object.h b/intern/elbeem/intern/simulation_object.h
deleted file mode 100644
index b35482f2098..00000000000
--- a/intern/elbeem/intern/simulation_object.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Basic interface for all simulation modules
- *
- *****************************************************************************/
-
-#ifndef SIMULATION_OBJECT_H
-#define SIMULATION_OBJECT_H
-
-
-#define USE_GLUTILITIES
-#include "ntl_geometryshader.h"
-#include "parametrizer.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class LbmSolverInterface;
-class CellIdentifierInterface;
-class ntlTree;
-class ntlRenderGlobals;
-class ntlRenderGlobals;
-class ParticleTracer;
-struct elbeemSimulationSettings;
-
-
-//! type fluid geometry init
-// warning : should match typeslbm.h values!
-const int cFgiFlagstart = 16;
-typedef enum {
- fgiFluid = (1<<(cFgiFlagstart+0)),
- fgiNoFluid = (1<<(cFgiFlagstart+1)),
- fgiSlipNo = (1<<(cFgiFlagstart+2)),
- fgiSlipFree = (1<<(cFgiFlagstart+3)),
- fgiNoBnd = (1<<(cFgiFlagstart+4)),
- fgiAcc = (1<<(cFgiFlagstart+5)),
- fgiNoAcc = (1<<(cFgiFlagstart+6)),
-
- fgiBndAll = (fgiSlipNo | fgiSlipFree)
-} FgiFlagType;
-
-
-/*! interface for different simluation models to visualize */
-class SimulationObject :
- public ntlGeometryShader {
-
- public:
-
- /*! Constructor */
- SimulationObject();
- /*! Destructor */
- virtual ~SimulationObject();
- /*! for init from API */
- void copyElbeemSettings(elbeemSimulationSettings *settings);
-
-
- /*! init tree for certain geometry init */
- void initGeoTree();
- /*! destroy tree etc. when geometry init done */
- void freeGeoTree();
- /*! get fluid init type at certain position */
- int geoInitGetPointType(ntlVec3Gfx org, int &OId);
- /*! check for a certain flag type at position org */
- bool geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId);
-
- // access functions
-
- /*! get current (max) simulation time */
- double getCurrentTime( void ) { return mTime; }
- /*! set geometry generation start point */
- virtual void setGeoStart(ntlVec3Gfx set) { mGeoStart = set; }
- /*! set geometry generation end point */
- virtual void setGeoEnd(ntlVec3Gfx set) { mGeoEnd = set; }
-
- /*! set sim panic flag */
- void setPanic(bool set) { mPanic = set; }
- /*! get sim panic flag */
- bool getPanic( void ) { return mPanic; }
-
- /*! simluation interface: initialize simulation */
- int initializeLbmSimulation(ntlRenderGlobals *glob);
-
- /*! set current frame */
- void setFrameNum(int num);
-
- /*! Do geo etc. init */
- virtual int postGeoConstrInit(ntlRenderGlobals *glob) { return initializeLbmSimulation(glob); };
- virtual int initializeShader() { /* ... */ return true; };
- /*! notify object that dump is in progress (e.g. for field dump) */
- virtual void notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename);
- /*! simluation interface: draw the simulation with OpenGL */
- virtual void draw( void ) {};
- virtual vector<ntlGeometryObject *>::iterator getObjectsBegin();
- virtual vector<ntlGeometryObject *>::iterator getObjectsEnd();
-
-
- /*! simluation interface: advance simulation another step (whatever delta time that might be) */
- virtual void step( void );
- /*! prepare visualization of simulation for e.g. raytracing */
- virtual void prepareVisualization( void );
-
- /*! GUI - display debug info */
- virtual void drawDebugDisplay();
- /*! GUI - display interactive info */
- virtual void drawInteractiveDisplay();
- /*! GUI - handle mouse movement for selection */
- virtual void setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir);
- virtual void setMouseClick();
-
- /*! get current start simulation time */
- double getStartTime( void );
- /*! get time for a single animation frame */
- double getFrameTime( int frame );
- /*! get time for a single time step in the simulation */
- double getTimestep( void );
-
- //! access solver
- LbmSolverInterface *getSolver(){ return mpLbm; }
-
- protected:
-
- /*! current time in the simulation */
- double mTime;
-
- /*! for display - start and end vectors for geometry */
- ntlVec3Gfx mGeoStart, mGeoEnd;
-
- /*! geometry init id */
- //? int mGeoInitId;
- /*! tree object for geomerty initialization */
- ntlTree *mpGiTree;
- /*! object vector for geo init */
- vector<ntlGeometryObject*> *mpGiObjects;
- /*! remember globals */
- ntlRenderGlobals *mpGlob;
-
- /*! simulation panic on/off */
- bool mPanic;
-
- /*! debug info to display */
- int mDebugType;
-
- /*! pointer to the lbm solver */
- LbmSolverInterface *mpLbm;
-
- /*! parametrizer for lbm solver */
- Parametrizer *mpParam;
-
- /*! particle tracing object */
- ParticleTracer *mpParts;
-
- /*! show parts of the simulation toggles */
- bool mShowSurface;
- bool mShowParticles;
-
- /*! debug display settings */
- int mDebDispSetting;
-
- /*! pointer to identifier of selected node */
- CellIdentifierInterface *mSelectedCid;
-
- /*! storage of API settings */
- elbeemSimulationSettings *mpElbeemSettings;
-
- public:
-
- // debug display setting funtions
-
- /*! set type of info to display */
- inline void setDebugDisplay(int disp) { mDebugType = disp; }
- inline int getDebugDisplay() { return mDebugType; }
-
- /* miscelleanous access functions */
-
- /*! init parametrizer for anim step length */
- void initParametrizer(Parametrizer *set) { mpParam = set; }
- /*! init parametrizer for anim step length */
- Parametrizer *getParametrizer() { return mpParam; }
-
- /*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */
- // parameters same as elbeem runsimCallback
- int checkCallerStatus(int status, int frame);
-
- /*! get bounding box of fluid for GUI */
- virtual inline ntlVec3Gfx *getBBStart() { return &mGeoStart; }
- virtual inline ntlVec3Gfx *getBBEnd() { return &mGeoEnd; }
-
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:SimulationObject")
-#endif
-};
-
-
-#endif
-
-
-
diff --git a/intern/elbeem/intern/solver_adap.cpp b/intern/elbeem/intern/solver_adap.cpp
deleted file mode 100644
index 9e5619ca4a5..00000000000
--- a/intern/elbeem/intern/solver_adap.cpp
+++ /dev/null
@@ -1,1281 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Adaptivity functions
- *
- *****************************************************************************/
-
-#include "solver_class.h"
-#include "solver_relax.h"
-#include "particletracer.h"
-
-#include <cmath>
-
-using std::isfinite;
-
-/*****************************************************************************/
-//! coarse step functions
-/*****************************************************************************/
-
-
-
-void LbmFsgrSolver::coarseCalculateFluxareas(int lev)
-{
- FSGR_FORIJK_BOUNDS(lev) {
- if( RFLAG(lev, i,j,k,mLevel[lev].setCurr) & CFFluid) {
- if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & CFGrFromCoarse) {
- LbmFloat totArea = mFsgrCellArea[0]; // for l=0
- for(int l=1; l<this->cDirNum; l++) {
- int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l];
- if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&
- (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
- ) {
- totArea += mFsgrCellArea[l];
- }
- } // l
- QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = totArea;
- //continue;
- } else
- if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & (CFEmpty|CFUnused)) {
- QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 1.0;
- //continue;
- } else {
- QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 0.0;
- }
- //errMsg("DFINI"," at l"<<lev<<" "<<PRINT_IJK<<" v:"<<QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) );
- }
- } // } TEST DEBUG
- if(!this->mSilent){ debMsgStd("coarseCalculateFluxareas",DM_MSG,"level "<<lev<<" calculated", 7); }
-}
-
-void LbmFsgrSolver::coarseAdvance(int lev)
-{
- LbmFloat calcCurrentMass = 0.0;
- LbmFloat calcCurrentVolume = 0.0;
-
- LbmFloat *ccel = NULL;
- LbmFloat *tcel = NULL;
- LbmFloat m[LBM_DFNUM];
- LbmFloat rho, ux, uy, uz, tmp, usqr, lcsmqo;
-#if OPT3D==1
- LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega;
-#endif // OPT3D==true
- m[0] = tmp = usqr = 0.0;
-
- coarseCalculateFluxareas(lev);
- // copied from fineAdv.
- CellFlagType *pFlagSrc = &RFLAG(lev, 1,1,getForZMin1(),SRCS(lev));
- CellFlagType *pFlagDst = &RFLAG(lev, 1,1,getForZMin1(),TSET(lev));
- pFlagSrc -= 1;
- pFlagDst -= 1;
- ccel = RACPNT(lev, 1,1,getForZMin1() ,SRCS(lev)); // QTEST
- ccel -= QCELLSTEP;
- tcel = RACPNT(lev, 1,1,getForZMin1() ,TSET(lev)); // QTEST
- tcel -= QCELLSTEP;
- //if(strstr(this->getName().c_str(),"Debug")){ errMsg("DEBUG","DEBUG!!!!!!!!!!!!!!!!!!!!!!!"); }
-
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
-#if FSGR_STRICT_DEBUG==1
- rho = ux = uy = uz = tmp = usqr = -100.0; // DEBUG
-#endif
- pFlagSrc++;
- pFlagDst++;
- ccel += QCELLSTEP;
- tcel += QCELLSTEP;
-
- // from coarse cells without unused nbs are not necessary...! -> remove
- if( ((*pFlagSrc) & (CFGrFromCoarse)) ) {
- bool invNb = false;
- FORDF1 { if(RFLAG_NB(lev, i, j, k, SRCS(lev), l) & CFUnused) { invNb = true; } }
- if(!invNb) {
- // WARNING - this modifies source flag array...
- *pFlagSrc = CFFluid|CFGrNorm;
-#if ELBEEM_PLUGIN!=1
- errMsg("coarseAdvance","FC2NRM_CHECK Converted CFGrFromCoarse to Norm at "<<lev<<" "<<PRINT_IJK);
-#endif // ELBEEM_PLUGIN!=1
- // move to perform coarsening?
- }
- } // */
-
-#if FSGR_STRICT_DEBUG==1
- *pFlagDst = *pFlagSrc; // always set other set...
-#else
- *pFlagDst = (*pFlagSrc & (~CFGrCoarseInited)); // always set other set... , remove coarse inited flag
-#endif
-
- // old INTCFCOARSETEST==1
- if((*pFlagSrc) & CFGrFromCoarse) { // interpolateFineFromCoarse test!
- if(( this->mStepCnt & (1<<(mMaxRefine-lev)) ) ==1) {
- FORDF0 { RAC(tcel,l) = RAC(ccel,l); }
- } else {
- interpolateCellFromCoarse( lev, i,j,k, TSET(lev), 0.0, CFFluid|CFGrFromCoarse, false);
- this->mNumUsedCells++;
- }
- continue; // interpolateFineFromCoarse test!
- } // interpolateFineFromCoarse test! old INTCFCOARSETEST==1
-
- if( ((*pFlagSrc) & (CFFluid)) ) {
- ccel = RACPNT(lev, i,j,k ,SRCS(lev));
- tcel = RACPNT(lev, i,j,k ,TSET(lev));
-
- if( ((*pFlagSrc) & (CFGrFromFine)) ) {
- FORDF0 { RAC(tcel,l) = RAC(ccel,l); } // always copy...?
- continue; // comes from fine grid
- }
- // also ignore CFGrFromCoarse
- else if( ((*pFlagSrc) & (CFGrFromCoarse)) ) {
- FORDF0 { RAC(tcel,l) = RAC(ccel,l); } // always copy...?
- continue;
- }
-
- OPTIMIZED_STREAMCOLLIDE;
- *pFlagDst |= CFNoBndFluid; // test?
- calcCurrentVolume += RAC(ccel,dFlux);
- calcCurrentMass += RAC(ccel,dFlux)*rho;
- //ebugMarkCell(lev+1, 2*i+1,2*j+1,2*k );
-#if FSGR_STRICT_DEBUG==1
- if(rho<-1.0){ debugMarkCell(lev, i,j,k );
- errMsg("INVRHOCELL_CHECK"," l"<<lev<<" "<< PRINT_IJK<<" rho:"<<rho );
- CAUSE_PANIC;
- }
-#endif // FSGR_STRICT_DEBUG==1
- this->mNumUsedCells++;
-
- }
- }
- pFlagSrc+=2; // after x
- pFlagDst+=2; // after x
- ccel += (QCELLSTEP*2);
- tcel += (QCELLSTEP*2);
- }
- pFlagSrc+= mLevel[lev].lSizex*2; // after y
- pFlagDst+= mLevel[lev].lSizex*2; // after y
- ccel += (QCELLSTEP*mLevel[lev].lSizex*2);
- tcel += (QCELLSTEP*mLevel[lev].lSizex*2);
- } // all cell loop k,j,i
-
-
- //errMsg("coarseAdvance","level "<<lev<<" stepped from "<<mLevel[lev].setCurr<<" to "<<mLevel[lev].setOther);
- if(!this->mSilent){ errMsg("coarseAdvance","level "<<lev<<" stepped from "<<SRCS(lev)<<" to "<<TSET(lev)); }
- // */
-
- // update other set
- mLevel[lev].setOther = mLevel[lev].setCurr;
- mLevel[lev].setCurr ^= 1;
- mLevel[lev].lsteps++;
- mLevel[lev].lmass = calcCurrentMass * mLevel[lev].lcellfactor;
- mLevel[lev].lvolume = calcCurrentVolume * mLevel[lev].lcellfactor;
-#if ELBEEM_PLUGIN!=1
- debMsgStd("LbmFsgrSolver::coarseAdvance",DM_NOTIFY, "mass: lev="<<lev<<" m="<<mLevel[lev].lmass<<" c="<<calcCurrentMass<<" lcf="<< mLevel[lev].lcellfactor, 8 );
- debMsgStd("LbmFsgrSolver::coarseAdvance",DM_NOTIFY, "volume: lev="<<lev<<" v="<<mLevel[lev].lvolume<<" c="<<calcCurrentVolume<<" lcf="<< mLevel[lev].lcellfactor, 8 );
-#endif // ELBEEM_PLUGIN
-}
-
-/*****************************************************************************/
-//! multi level functions
-/*****************************************************************************/
-
-
-// get dfs from level (lev+1) to (lev) coarse border nodes
-void LbmFsgrSolver::coarseRestrictFromFine(int lev)
-{
- if((lev<0) || ((lev+1)>mMaxRefine)) return;
-#if FSGR_STRICT_DEBUG==1
- // reset all unused cell values to invalid
- int unuCnt = 0;
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
- CellFlagType *pFlagSrc = &RFLAG(lev, i,j,k,mLevel[lev].setCurr);
- if( ((*pFlagSrc) & (CFFluid|CFGrFromFine)) == (CFFluid|CFGrFromFine) ) {
- FORDF0{ QCELL(lev, i,j,k,mLevel[lev].setCurr, l) = -10000.0; }
- unuCnt++;
- // set here
- } else if( ((*pFlagSrc) & (CFFluid|CFGrNorm)) == (CFFluid|CFGrNorm) ) {
- // simulated...
- } else {
- // reset in interpolation
- //errMsg("coarseRestrictFromFine"," reset l"<<lev<<" "<<PRINT_IJK);
- }
- if( ((*pFlagSrc) & (CFEmpty|CFUnused)) ) { // test, also reset?
- FORDF0{ QCELL(lev, i,j,k,mLevel[lev].setCurr, l) = -10000.0; }
- } // test
- } } }
- errMsg("coarseRestrictFromFine"," reset l"<<lev<<" fluid|coarseBorder cells: "<<unuCnt);
-#endif // FSGR_STRICT_DEBUG==1
- const int srcSet = mLevel[lev+1].setCurr;
- const int dstSet = mLevel[lev].setCurr;
-
- //restrict
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
- CellFlagType *pFlagSrc = &RFLAG(lev, i,j,k,dstSet);
- if((*pFlagSrc) & (CFFluid)) {
- if( ((*pFlagSrc) & (CFFluid|CFGrFromFine)) == (CFFluid|CFGrFromFine) ) {
- // do resctriction
- mNumInterdCells++;
- coarseRestrictCell(lev, i,j,k,srcSet,dstSet);
-
- this->mNumUsedCells++;
- } // from fine & fluid
- else {
- if(RFLAG(lev+1, 2*i,2*j,2*k,srcSet) & CFGrFromCoarse) {
- RFLAG(lev, i,j,k,dstSet) |= CFGrToFine;
- } else {
- RFLAG(lev, i,j,k,dstSet) &= (~CFGrToFine);
- }
- }
- } // & fluid
- }}}
- if(!this->mSilent){ errMsg("coarseRestrictFromFine"," from l"<<(lev+1)<<",s"<<mLevel[lev+1].setCurr<<" to l"<<lev<<",s"<<mLevel[lev].setCurr); }
-}
-
-bool LbmFsgrSolver::adaptGrid(int lev) {
- if((lev<0) || ((lev+1)>mMaxRefine)) return false;
- bool change = false;
- { // refinement, PASS 1-3
-
- //bool nbsok;
- // FIXME remove TIMEINTORDER ?
- LbmFloat interTime = 0.0;
- // update curr from other, as streaming afterwards works on curr
- // thus read only from srcSet, modify other
- const int srcSet = mLevel[lev].setOther;
- const int dstSet = mLevel[lev].setCurr;
- const int srcFineSet = mLevel[lev+1].setCurr;
- const bool debugRefinement = false;
-
- // use //template functions for 2D/3D
- /*if(strstr(this->getName().c_str(),"Debug"))
- if(lev+1==mMaxRefine) { // mixborder
- for(int l=0;((l<this->cDirNum) && (!removeFromFine)); l++) { // FARBORD
- int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l];
- if(RFLAG(lev+1, ni,nj,nk, srcFineSet)&CFBnd) { // NEWREFT
- removeFromFine=true;
- }
- }
- } // FARBORD */
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
-
- if(RFLAG(lev, i,j,k, srcSet) & CFGrFromFine) {
- bool removeFromFine = false;
- const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine);
- CellFlagType reqType = CFGrNorm;
- if(lev+1==mMaxRefine) reqType = CFNoBndFluid;
-
- if( (RFLAG(lev+1, (2*i),(2*j),(2*k), srcFineSet) & reqType) &&
- (!(RFLAG(lev+1, (2*i),(2*j),(2*k), srcFineSet) & (notAllowed)) ) ){ // ok
- } else {
- removeFromFine=true;
- }
-
- if(removeFromFine) {
- // dont turn CFGrFromFine above interface cells into CFGrNorm
- //errMsg("performRefinement","Removing CFGrFromFine on lev"<<lev<<" " <<PRINT_IJK<<" srcflag:"<<convertCellFlagType2String(RFLAG(lev+1, (2*i),(2*j),(2*k), srcFineSet)) <<" set:"<<dstSet );
- RFLAG(lev, i,j,k, dstSet) = CFEmpty;
-#if FSGR_STRICT_DEBUG==1
- // for interpolation later on during fine grid fixing
- // these cells are still correctly inited
- RFLAG(lev, i,j,k, dstSet) |= CFGrCoarseInited; // remove later on? FIXME?
-#endif // FSGR_STRICT_DEBUG==1
- //RFLAG(lev, i,j,k, mLevel[lev].setOther) = CFEmpty; // FLAGTEST
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,i,j,k);
- change=true;
- mNumFsgrChanges++;
- for(int l=1; l<this->cDirNum; l++) {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- //errMsg("performRefinement","On lev:"<<lev<<" check: "<<PRINT_VEC(ni,nj,nk)<<" set:"<<dstSet<<" = "<<convertCellFlagType2String(RFLAG(lev, ni,nj,nk, srcSet)) );
- if( ( RFLAG(lev, ni,nj,nk, srcSet)&CFFluid ) &&
- (!(RFLAG(lev, ni,nj,nk, srcSet)&CFGrFromFine)) ) { // dont change status of nb. from fine cells
- // tag as inited for debugging, cell contains fluid DFs anyway
- RFLAG(lev, ni,nj,nk, dstSet) = CFFluid|CFGrFromFine|CFGrCoarseInited;
- //errMsg("performRefinement","On lev:"<<lev<<" set to from fine: "<<PRINT_VEC(ni,nj,nk)<<" set:"<<dstSet);
- //if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,ni,nj,nk);
- }
- } // l
-
- // FIXME fix fine level?
- }
-
- // recheck from fine flag
- }
- }}} // TEST
- // PASS 1 */
-
-
- /*if( ((*pFlagSrc) & (CFGrFromCoarse)) ) {
- bool invNb = false;
- FORDF1 {
- if(RFLAG_NB(lev, i, j, k, SRCS(lev), l) & CFUnused) { invNb = true; }
- }
- if(!invNb) {
- *pFlagSrc = CFFluid|CFGrNorm;
- errMsg("coarseAdvance","FC2NRM_CHECK Converted CFGrFromCoarse to Norm at "<<lev<<" "<<PRINT_IJK);
- }
- } // */
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { // TEST
- for(int j=1;j<mLevel[lev].lSizey-1;++j) { // TEST
- for(int i=1;i<mLevel[lev].lSizex-1;++i) { // TEST
-
- // test from coarseAdvance
- // from coarse cells without unused nbs are not necessary...! -> remove
-
- if(RFLAG(lev, i,j,k, srcSet) & CFGrFromCoarse) {
-
- // from coarse cells without unused nbs are not necessary...! -> remove
- bool invNb = false;
- bool fluidNb = false;
- for(int l=1; l<this->cDirNum; l++) {
- if(RFLAG_NB(lev, i, j, k, srcSet, l) & CFUnused) { invNb = true; }
- if(RFLAG_NB(lev, i, j, k, srcSet, l) & (CFGrNorm)) { fluidNb = true; }
- }
- if(!invNb) {
- // no unused cells around -> calculate normally from now on
- RFLAG(lev, i,j,k, dstSet) = CFFluid|CFGrNorm;
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k);
- change=true;
- mNumFsgrChanges++;
- } // from advance
- if(!fluidNb) {
- // no fluid cells near -> no transfer necessary
- RFLAG(lev, i,j,k, dstSet) = CFUnused;
- //RFLAG(lev, i,j,k, mLevel[lev].setOther) = CFUnused; // FLAGTEST
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k);
- change=true;
- mNumFsgrChanges++;
- } // from advance
-
-
- // dont allow double transfer
- // this might require fixing the neighborhood
- if(RFLAG(lev+1, 2*i,2*j,2*k, srcFineSet)&(CFGrFromCoarse)) {
- // dont turn CFGrFromFine above interface cells into CFGrNorm
- //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<lev<<" " <<PRINT_IJK<<" due to finer from coarse cell " );
- RFLAG(lev, i,j,k, dstSet) = CFFluid|CFGrNorm;
- if(lev>0) RFLAG(lev-1, i/2,j/2,k/2, mLevel[lev-1].setCurr) &= (~CFGrToFine); // TODO add more of these?
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k);
- change=true;
- mNumFsgrChanges++;
- for(int l=1; l<this->cDirNum; l++) {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if(RFLAG(lev, ni,nj,nk, srcSet)&(CFGrNorm)) { //ok
- for(int m=1; m<this->cDirNum; m++) {
- int mi= ni +this->dfVecX[m], mj= nj +this->dfVecY[m], mk= nk +this->dfVecZ[m];
- if(RFLAG(lev, mi, mj, mk, srcSet)&CFUnused) {
- // norm cells in neighborhood with unused nbs have to be new border...
- RFLAG(lev, ni,nj,nk, dstSet) = CFFluid|CFGrFromCoarse;
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,ni,nj,nk);
- }
- }
- // these alreay have valid values...
- }
- else if(RFLAG(lev, ni,nj,nk, srcSet)&(CFUnused)) { //ok
- // this should work because we have a valid neighborhood here for now
- interpolateCellFromCoarse(lev, ni, nj, nk, dstSet, interTime, CFFluid|CFGrFromCoarse, false);
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,ni,nj,nk);
- mNumFsgrChanges++;
- }
- } // l
- } // double transer
-
- } // from coarse
-
- } } }
- // PASS 2 */
-
-
- // fix dstSet from fine cells here
- // warning - checks CFGrFromFine on dstset changed before!
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { // TEST
- for(int j=1;j<mLevel[lev].lSizey-1;++j) { // TEST
- for(int i=1;i<mLevel[lev].lSizex-1;++i) { // TEST
-
- //if(RFLAG(lev, i,j,k, srcSet) & CFGrFromFine) {
- if(RFLAG(lev, i,j,k, dstSet) & CFGrFromFine) {
- // modify finer level border
- if((RFLAG(lev+1, 2*i,2*j,2*k, srcFineSet)&(CFGrFromCoarse))) {
- //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<(lev+1)<<" from l"<<lev<<" " <<PRINT_IJK );
- CellFlagType setf = CFFluid;
- if(lev+1 < mMaxRefine) setf = CFFluid|CFGrNorm;
- RFLAG(lev+1, 2*i,2*j,2*k, srcFineSet)=setf;
- change=true;
- mNumFsgrChanges++;
- for(int l=1; l<this->cDirNum; l++) {
- int bi=(2*i)+this->dfVecX[l], bj=(2*j)+this->dfVecY[l], bk=(2*k)+this->dfVecZ[l];
- if(RFLAG(lev+1, bi, bj, bk, srcFineSet)&(CFGrFromCoarse)) {
- //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<(lev+1)<<" "<<PRINT_VEC(bi,bj,bk) );
- RFLAG(lev+1, bi, bj, bk, srcFineSet) = setf;
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev+1,bi,bj,bk);
- }
- else if(RFLAG(lev+1, bi, bj, bk, srcFineSet)&(CFUnused )) {
- //errMsg("performRefinement","Removing CFUnused on lev"<<(lev+1)<<" "<<PRINT_VEC(bi,bj,bk) );
- interpolateCellFromCoarse(lev+1, bi, bj, bk, srcFineSet, interTime, setf, false);
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev+1,bi,bj,bk);
- mNumFsgrChanges++;
- }
- }
- for(int l=1; l<this->cDirNum; l++) {
- int bi=(2*i)+this->dfVecX[l], bj=(2*j)+this->dfVecY[l], bk=(2*k)+this->dfVecZ[l];
- if( (RFLAG(lev+1, bi, bj, bk, srcFineSet)&CFFluid ) &&
- (!(RFLAG(lev+1, bi, bj, bk, srcFineSet)&CFGrFromCoarse)) ) {
- // all unused nbs now of coarse have to be from coarse
- for(int m=1; m<this->cDirNum; m++) {
- int mi= bi +this->dfVecX[m], mj= bj +this->dfVecY[m], mk= bk +this->dfVecZ[m];
- if(RFLAG(lev+1, mi, mj, mk, srcFineSet)&CFUnused) {
- //errMsg("performRefinement","Changing CFUnused on lev"<<(lev+1)<<" "<<PRINT_VEC(mi,mj,mk) );
- interpolateCellFromCoarse(lev+1, mi, mj, mk, srcFineSet, interTime, CFFluid|CFGrFromCoarse, false);
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev+1,mi,mj,mk);
- mNumFsgrChanges++;
- }
- }
- // nbs prepared...
- }
- }
- }
-
- } // convert regions of from fine
- }}} // TEST
- // PASS 3 */
-
- if(!this->mSilent){ errMsg("performRefinement"," for l"<<lev<<" done ("<<change<<") " ); }
- } // PASS 1-3
- // refinement done
-
- //LbmFsgrSolver::performCoarsening(int lev) {
- { // PASS 4,5
- bool nbsok;
- // WARNING
- // now work on modified curr set
- const int srcSet = mLevel[lev].setCurr;
- const int dstlev = lev+1;
- const int dstFineSet = mLevel[dstlev].setCurr;
- const bool debugCoarsening = false;
-
- // PASS 5 test DEBUG
- /*if(this->mInitDone) {
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
- if(RFLAG(lev, i,j,k, srcSet) & CFEmpty) {
- // check empty -> from fine conversion
- bool changeToFromFine = false;
- const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine);
- CellFlagType reqType = CFGrNorm;
- if(lev+1==mMaxRefine) reqType = CFNoBndFluid;
- if( (RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & reqType) &&
- (!(RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & (notAllowed)) ) ){
- changeToFromFine=true; }
- if(changeToFromFine) {
- change = true;
- mNumFsgrChanges++;
- RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrFromFine;
- if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(lev,i,j,k);
- // same as restr from fine func! not necessary ?!
- // coarseRestrictFromFine part
- coarseRestrictCell(lev, i,j,k,srcSet, dstFineSet);
- }
- } // only check empty cells
- }}} // TEST!
- } // PASS 5 */
-
- // use //template functions for 2D/3D
- /*if(strstr(this->getName().c_str(),"Debug"))
- if((nbsok)&&(lev+1==mMaxRefine)) { // mixborder
- for(int l=0;((l<this->cDirNum) && (nbsok)); l++) { // FARBORD
- int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l];
- if(RFLAG(lev+1, ni,nj,nk, dstFineSet)&CFBnd) { // NEWREFT
- nbsok=false;
- }
- }
- } // FARBORD */
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
-
- // from coarse cells without unused nbs are not necessary...! -> remove
- // perform check from coarseAdvance here?
- if(RFLAG(lev, i,j,k, srcSet) & CFGrFromFine) {
- // remove from fine cells now that are completely in fluid
- // FIXME? check that new from fine in performRefinement never get deleted here afterwards?
- // or more general, one cell never changed more than once?
- const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine);
- //const CellFlagType notNbAllowed = (CFInter|CFBnd|CFGrFromFine); unused
- CellFlagType reqType = CFGrNorm;
- if(lev+1==mMaxRefine) reqType = CFNoBndFluid;
-
- nbsok = true;
- for(int l=0; l<this->cDirNum && nbsok; l++) {
- int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l];
- if( (RFLAG(lev+1, ni,nj,nk, dstFineSet) & reqType) &&
- (!(RFLAG(lev+1, ni,nj,nk, dstFineSet) & (notAllowed)) ) ){
- // ok
- } else {
- nbsok=false;
- }
- // FARBORD
- }
- // dont turn CFGrFromFine above interface cells into CFGrNorm
- // now check nbs on same level
- for(int l=1; l<this->cDirNum && nbsok; l++) {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if(RFLAG(lev, ni,nj,nk, srcSet)&(CFFluid)) { //ok
- } else {
- nbsok = false;
- }
- } // l
-
- if(nbsok) {
- // conversion to coarse fluid cell
- change = true;
- mNumFsgrChanges++;
- RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrNorm;
- // dfs are already ok...
- //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine changed to CFGrNorm at lev"<<lev<<" " <<PRINT_IJK );
- if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(lev,i,j,k);
-
- // only check complete cubes
- for(int dx=-1;dx<=1;dx+=2) {
- for(int dy=-1;dy<=1;dy+=2) {
- for(int dz=-1*(LBMDIM&1);dz<=1*(LBMDIM&1);dz+=2) { // 2d/3d
- // check for norm and from coarse, as the coarse level might just have been refined...
- if(
- // we now the flag of the current cell! ( RFLAG(lev, i , j , k , srcSet)&(CFGrNorm)) &&
- ( RFLAG(lev, i+dx, j , k , srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
- ( RFLAG(lev, i , j+dy, k , srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
- ( RFLAG(lev, i , j , k+dz, srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
-
- ( RFLAG(lev, i+dx, j+dy, k , srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
- ( RFLAG(lev, i+dx, j , k+dz, srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
- ( RFLAG(lev, i , j+dy, k+dz, srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
- ( RFLAG(lev, i+dx, j+dy, k+dz, srcSet)&(CFGrNorm|CFGrFromCoarse))
- ) {
- // middle source node on higher level
- int dstx = (2*i)+dx;
- int dsty = (2*j)+dy;
- int dstz = (2*k)+dz;
-
- mNumFsgrChanges++;
- RFLAG(dstlev, dstx,dsty,dstz, dstFineSet) = CFUnused;
- RFLAG(dstlev, dstx,dsty,dstz, mLevel[dstlev].setOther) = CFUnused; // FLAGTEST
- //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init center unused set l"<<dstlev<<" at "<<PRINT_VEC(dstx,dsty,dstz) );
-
- for(int l=1; l<this->cDirNum; l++) {
- int dstni=dstx+this->dfVecX[l], dstnj=dsty+this->dfVecY[l], dstnk=dstz+this->dfVecZ[l];
- if(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)&(CFFluid)) {
- RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet) = CFFluid|CFGrFromCoarse;
- }
- if(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)&(CFInter)) {
- //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init CHECK Warning - deleting interface cell...");
- this->mFixMass += QCELL( dstlev, dstni,dstnj,dstnk, dstFineSet, dMass);
- RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet) = CFFluid|CFGrFromCoarse;
- }
- } // l
-
- // again check nb flags of all surrounding cells to see if any from coarse
- // can be convted to unused
- for(int l=1; l<this->cDirNum; l++) {
- int dstni=dstx+this->dfVecX[l], dstnj=dsty+this->dfVecY[l], dstnk=dstz+this->dfVecZ[l];
- // have to be at least from coarse here...
- //errMsg("performCoarsening","CFGrFromFine subcube init unused check l"<<dstlev<<" at "<<PRINT_VEC(dstni,dstnj,dstnk)<<" "<< convertCellFlagType2String(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)) );
- if(!(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)&(CFUnused) )) {
- bool delok = true;
- // careful long range here... check domain bounds?
- for(int m=1; m<this->cDirNum; m++) {
- int chkni=dstni+this->dfVecX[m], chknj=dstnj+this->dfVecY[m], chknk=dstnk+this->dfVecZ[m];
- if(RFLAG(dstlev, chkni,chknj,chknk, dstFineSet)&(CFUnused|CFGrFromCoarse)) {
- // this nb cell is ok for deletion
- } else {
- delok=false; // keep it!
- }
- //errMsg("performCoarsening"," CHECK "<<PRINT_VEC(dstni,dstnj,dstnk)<<" to "<<PRINT_VEC( chkni,chknj,chknk )<<" f:"<< convertCellFlagType2String( RFLAG(dstlev, chkni,chknj,chknk, dstFineSet))<<" nbsok"<<delok );
- }
- //errMsg("performCoarsening","CFGrFromFine subcube init unused check l"<<dstlev<<" at "<<PRINT_VEC(dstni,dstnj,dstnk)<<" ok"<<delok );
- if(delok) {
- mNumFsgrChanges++;
- RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet) = CFUnused;
- RFLAG(dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setOther) = CFUnused; // FLAGTEST
- if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(dstlev,dstni,dstnj,dstnk);
- }
- }
- } // l
- // treat subcube
- //ebugMarkCell(lev,i+dx,j+dy,k+dz);
- //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init, dir:"<<PRINT_VEC(dx,dy,dz) );
- }
- } } }
-
- } // ?
- } // convert regions of from fine
- }}} // TEST!
- // PASS 4 */
-
- // reinit cell area value
- /*if( RFLAG(lev, i,j,k,srcSet) & CFFluid) {
- if( RFLAG(lev+1, i*2,j*2,k*2,dstFineSet) & CFGrFromCoarse) {
- LbmFloat totArea = mFsgrCellArea[0]; // for l=0
- for(int l=1; l<this->cDirNum; l++) {
- int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l];
- if(RFLAG(lev+1, ni,nj,nk, dstFineSet)&
- (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
- //(CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
- ) {
- //LbmFloat area = 0.25; if(this->dfVecX[l]!=0) area *= 0.5; if(this->dfVecY[l]!=0) area *= 0.5; if(this->dfVecZ[l]!=0) area *= 0.5;
- totArea += mFsgrCellArea[l];
- }
- } // l
- QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) =
- QCELL(lev, i,j,k,srcSet, dFlux) = totArea;
- } else {
- QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) =
- QCELL(lev, i,j,k,srcSet, dFlux) = 1.0;
- }
- //errMsg("DFINI"," at l"<<lev<<" "<<PRINT_IJK<<" v:"<<QCELL(lev, i,j,k,srcSet, dFlux) );
- }
- // */
-
-
- // PASS 5 org
- /*if(strstr(this->getName().c_str(),"Debug"))
- if((changeToFromFine)&&(lev+1==mMaxRefine)) { // mixborder
- for(int l=0;((l<this->cDirNum) && (changeToFromFine)); l++) { // FARBORD
- int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l];
- if(RFLAG(lev+1, ni,nj,nk, dstFineSet)&CFBnd) { // NEWREFT
- changeToFromFine=false; }
- }
- }// FARBORD */
- //if(!this->mInitDone) {
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
-
-
- if(RFLAG(lev, i,j,k, srcSet) & CFEmpty) {
- // check empty -> from fine conversion
- bool changeToFromFine = false;
- const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine);
- CellFlagType reqType = CFGrNorm;
- if(lev+1==mMaxRefine) reqType = CFNoBndFluid;
-
- if( (RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & reqType) &&
- (!(RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & (notAllowed)) ) ){
- // DEBUG
- changeToFromFine=true;
- }
-
- // FARBORD
-
- if(changeToFromFine) {
- change = true;
- mNumFsgrChanges++;
- RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrFromFine;
- if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(lev,i,j,k);
- // same as restr from fine func! not necessary ?!
- // coarseRestrictFromFine part
- }
- } // only check empty cells
-
- }}} // TEST!
- //} // init done
- // PASS 5 */
- } // coarsening, PASS 4,5
-
- if(!this->mSilent){ errMsg("adaptGrid"," for l"<<lev<<" done " ); }
- return change;
-}
-
-/*****************************************************************************/
-//! cell restriction and prolongation
-/*****************************************************************************/
-
-void LbmFsgrSolver::coarseRestrictCell(int lev, int i,int j,int k, int srcSet, int dstSet)
-{
- LbmFloat *ccel = RACPNT(lev+1, 2*i,2*j,2*k,srcSet);
- LbmFloat *tcel = RACPNT(lev , i,j,k ,dstSet);
-
- LbmFloat rho=0.0, ux=0.0, uy=0.0, uz=0.0;
- //LbmFloat *ccel = NULL;
- //LbmFloat *tcel = NULL;
-#if OPT3D==1
- LbmFloat m[LBM_DFNUM];
- // for macro add
- LbmFloat usqr;
- //LbmFloat *addfcel, *dstcell;
- LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM];
- LbmFloat lcsmDstOmega, lcsmSrcOmega, lcsmdfscale;
-#else // OPT3D==true
- LbmFloat df[LBM_DFNUM];
- LbmFloat omegaDst, omegaSrc;
- LbmFloat feq[LBM_DFNUM];
- LbmFloat dfScale = mDfScaleUp;
-#endif // OPT3D==true
-
-# if OPT3D==0
- // add up weighted dfs
- FORDF0{ df[l] = 0.0;}
- for(int n=0;(n<this->cDirNum); n++) {
- int ni=2*i+1*this->dfVecX[n], nj=2*j+1*this->dfVecY[n], nk=2*k+1*this->dfVecZ[n];
- ccel = RACPNT(lev+1, ni,nj,nk,srcSet);// CFINTTEST
- const LbmFloat weight = mGaussw[n];
- FORDF0{
- LbmFloat cdf = weight * RAC(ccel,l);
-# if FSGR_STRICT_DEBUG==1
- if( cdf<-1.0 ){ errMsg("INVDFCREST_DFCHECK", PRINT_IJK<<" s"<<dstSet<<" from "<<PRINT_VEC(2*i,2*j,2*k)<<" s"<<srcSet<<" df"<<l<<":"<< df[l]); }
-# endif
- //errMsg("INVDFCREST_DFCHECK", PRINT_IJK<<" s"<<dstSet<<" from "<<PRINT_VEC(2*i,2*j,2*k)<<" s"<<srcSet<<" df"<<l<<":"<< df[l]<<" = "<<cdf<<" , w"<<weight);
- df[l] += cdf;
- }
- }
-
- // calc rho etc. from weighted dfs
- rho = ux = uy = uz = 0.0;
- FORDF0{
- LbmFloat cdf = df[l];
- rho += cdf;
- ux += (this->dfDvecX[l]*cdf);
- uy += (this->dfDvecY[l]*cdf);
- uz += (this->dfDvecZ[l]*cdf);
- }
-
- FORDF0{ feq[l] = this->getCollideEq(l, rho,ux,uy,uz); }
- if(mLevel[lev ].lcsmago>0.0) {
- const LbmFloat Qo = this->getLesNoneqTensorCoeff(df,feq);
- omegaDst = this->getLesOmega(mLevel[lev ].omega,mLevel[lev ].lcsmago,Qo);
- omegaSrc = this->getLesOmega(mLevel[lev+1].omega,mLevel[lev+1].lcsmago,Qo);
- } else {
- omegaDst = mLevel[lev+0].omega; /* NEWSMAGOT*/
- omegaSrc = mLevel[lev+1].omega;
- }
- dfScale = (mLevel[lev ].timestep/mLevel[lev+1].timestep)* (1.0/omegaDst-1.0)/ (1.0/omegaSrc-1.0); // yu
- FORDF0{
- RAC(tcel, l) = feq[l]+ (df[l]-feq[l])*dfScale;
- }
-# else // OPT3D
- // similar to OPTIMIZED_STREAMCOLLIDE_UNUSED
-
- //rho = ux = uy = uz = 0.0;
- MSRC_C = CCELG_C(0) ;
- MSRC_N = CCELG_N(0) ;
- MSRC_S = CCELG_S(0) ;
- MSRC_E = CCELG_E(0) ;
- MSRC_W = CCELG_W(0) ;
- MSRC_T = CCELG_T(0) ;
- MSRC_B = CCELG_B(0) ;
- MSRC_NE = CCELG_NE(0);
- MSRC_NW = CCELG_NW(0);
- MSRC_SE = CCELG_SE(0);
- MSRC_SW = CCELG_SW(0);
- MSRC_NT = CCELG_NT(0);
- MSRC_NB = CCELG_NB(0);
- MSRC_ST = CCELG_ST(0);
- MSRC_SB = CCELG_SB(0);
- MSRC_ET = CCELG_ET(0);
- MSRC_EB = CCELG_EB(0);
- MSRC_WT = CCELG_WT(0);
- MSRC_WB = CCELG_WB(0);
- for(int n=1;(n<this->cDirNum); n++) {
- ccel = RACPNT(lev+1, 2*i+1*this->dfVecX[n], 2*j+1*this->dfVecY[n], 2*k+1*this->dfVecZ[n] ,srcSet);
- MSRC_C += CCELG_C(n) ;
- MSRC_N += CCELG_N(n) ;
- MSRC_S += CCELG_S(n) ;
- MSRC_E += CCELG_E(n) ;
- MSRC_W += CCELG_W(n) ;
- MSRC_T += CCELG_T(n) ;
- MSRC_B += CCELG_B(n) ;
- MSRC_NE += CCELG_NE(n);
- MSRC_NW += CCELG_NW(n);
- MSRC_SE += CCELG_SE(n);
- MSRC_SW += CCELG_SW(n);
- MSRC_NT += CCELG_NT(n);
- MSRC_NB += CCELG_NB(n);
- MSRC_ST += CCELG_ST(n);
- MSRC_SB += CCELG_SB(n);
- MSRC_ET += CCELG_ET(n);
- MSRC_EB += CCELG_EB(n);
- MSRC_WT += CCELG_WT(n);
- MSRC_WB += CCELG_WB(n);
- }
- rho = MSRC_C + MSRC_N + MSRC_S + MSRC_E + MSRC_W + MSRC_T
- + MSRC_B + MSRC_NE + MSRC_NW + MSRC_SE + MSRC_SW + MSRC_NT
- + MSRC_NB + MSRC_ST + MSRC_SB + MSRC_ET + MSRC_EB + MSRC_WT + MSRC_WB;
- ux = MSRC_E - MSRC_W + MSRC_NE - MSRC_NW + MSRC_SE - MSRC_SW
- + MSRC_ET + MSRC_EB - MSRC_WT - MSRC_WB;
- uy = MSRC_N - MSRC_S + MSRC_NE + MSRC_NW - MSRC_SE - MSRC_SW
- + MSRC_NT + MSRC_NB - MSRC_ST - MSRC_SB;
- uz = MSRC_T - MSRC_B + MSRC_NT - MSRC_NB + MSRC_ST - MSRC_SB
- + MSRC_ET - MSRC_EB + MSRC_WT - MSRC_WB;
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- \
- lcsmeq[dC] = EQC ; \
- COLL_CALCULATE_DFEQ(lcsmeq); \
- COLL_CALCULATE_NONEQTENSOR(lev+0, MSRC_ )\
- COLL_CALCULATE_CSMOMEGAVAL(lev+0, lcsmDstOmega); \
- COLL_CALCULATE_CSMOMEGAVAL(lev+1, lcsmSrcOmega); \
- \
- lcsmdfscale = (mLevel[lev+0].timestep/mLevel[lev+1].timestep)* (1.0/lcsmDstOmega-1.0)/ (1.0/lcsmSrcOmega-1.0); \
- RAC(tcel, dC ) = (lcsmeq[dC ] + (MSRC_C -lcsmeq[dC ] )*lcsmdfscale);
- RAC(tcel, dN ) = (lcsmeq[dN ] + (MSRC_N -lcsmeq[dN ] )*lcsmdfscale);
- RAC(tcel, dS ) = (lcsmeq[dS ] + (MSRC_S -lcsmeq[dS ] )*lcsmdfscale);
- RAC(tcel, dE ) = (lcsmeq[dE ] + (MSRC_E -lcsmeq[dE ] )*lcsmdfscale);
- RAC(tcel, dW ) = (lcsmeq[dW ] + (MSRC_W -lcsmeq[dW ] )*lcsmdfscale);
- RAC(tcel, dT ) = (lcsmeq[dT ] + (MSRC_T -lcsmeq[dT ] )*lcsmdfscale);
- RAC(tcel, dB ) = (lcsmeq[dB ] + (MSRC_B -lcsmeq[dB ] )*lcsmdfscale);
- RAC(tcel, dNE) = (lcsmeq[dNE] + (MSRC_NE-lcsmeq[dNE] )*lcsmdfscale);
- RAC(tcel, dNW) = (lcsmeq[dNW] + (MSRC_NW-lcsmeq[dNW] )*lcsmdfscale);
- RAC(tcel, dSE) = (lcsmeq[dSE] + (MSRC_SE-lcsmeq[dSE] )*lcsmdfscale);
- RAC(tcel, dSW) = (lcsmeq[dSW] + (MSRC_SW-lcsmeq[dSW] )*lcsmdfscale);
- RAC(tcel, dNT) = (lcsmeq[dNT] + (MSRC_NT-lcsmeq[dNT] )*lcsmdfscale);
- RAC(tcel, dNB) = (lcsmeq[dNB] + (MSRC_NB-lcsmeq[dNB] )*lcsmdfscale);
- RAC(tcel, dST) = (lcsmeq[dST] + (MSRC_ST-lcsmeq[dST] )*lcsmdfscale);
- RAC(tcel, dSB) = (lcsmeq[dSB] + (MSRC_SB-lcsmeq[dSB] )*lcsmdfscale);
- RAC(tcel, dET) = (lcsmeq[dET] + (MSRC_ET-lcsmeq[dET] )*lcsmdfscale);
- RAC(tcel, dEB) = (lcsmeq[dEB] + (MSRC_EB-lcsmeq[dEB] )*lcsmdfscale);
- RAC(tcel, dWT) = (lcsmeq[dWT] + (MSRC_WT-lcsmeq[dWT] )*lcsmdfscale);
- RAC(tcel, dWB) = (lcsmeq[dWB] + (MSRC_WB-lcsmeq[dWB] )*lcsmdfscale);
-# endif // OPT3D==0
-}
-
-void LbmFsgrSolver::interpolateCellFromCoarse(int lev, int i, int j,int k, int dstSet, LbmFloat t, CellFlagType flagSet, bool markNbs) {
- LbmFloat rho=0.0, ux=0.0, uy=0.0, uz=0.0;
- LbmFloat intDf[19] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
-
-#if OPT3D==1
- // for macro add
- LbmFloat addDfFacT, addVal, usqr;
- LbmFloat *addfcel, *dstcell;
- LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM];
- LbmFloat lcsmDstOmega, lcsmSrcOmega, lcsmdfscale;
-#endif // OPT3D==true
-
- // SET required nbs to from coarse (this might overwrite flag several times)
- // this is not necessary for interpolateFineFromCoarse
- if(markNbs) {
- FORDF1{
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if(RFLAG(lev,ni,nj,nk,dstSet)&CFUnused) {
- // parents have to be inited!
- interpolateCellFromCoarse(lev, ni, nj, nk, dstSet, t, CFFluid|CFGrFromCoarse, false);
- }
- } }
-
- // change flag of cell to be interpolated
- RFLAG(lev,i,j,k, dstSet) = flagSet;
- mNumInterdCells++;
-
- // interpolation lines...
- int betx = i&1;
- int bety = j&1;
- int betz = k&1;
-
- if((!betx) && (!bety) && (!betz)) {
- ADD_INT_DFS(lev-1, i/2 ,j/2 ,k/2 , 0.0, 1.0);
- }
- else if(( betx) && (!bety) && (!betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D1);
- }
- else if((!betx) && ( bety) && (!betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D1);
- }
- else if((!betx) && (!bety) && ( betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D1);
- }
- else if(( betx) && ( bety) && (!betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2) , t, WO1D2);
- }
- else if((!betx) && ( bety) && ( betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2)+1, t, WO1D2);
- }
- else if(( betx) && (!bety) && ( betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2)+1, t, WO1D2);
- }
- else if(( betx) && ( bety) && ( betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2)+1, t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2) , t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2)+1, t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2)+1, t, WO1D3);
- }
- else {
- CAUSE_PANIC;
- errFatal("interpolateCellFromCoarse","Invalid!?", SIMWORLD_GENERICERROR);
- }
-
- IDF_WRITEBACK;
- return;
-}
-
-
-
-#define MPTADAP_INTERV 4
-
-/*****************************************************************************/
-/*! change the size of the LBM time step */
-/*****************************************************************************/
-void LbmFsgrSolver::adaptTimestep() {
- LbmFloat massTOld=0.0, massTNew=0.0;
- LbmFloat volTOld=0.0, volTNew=0.0;
-
- bool rescale = false; // do any rescale at all?
- LbmFloat scaleFac = -1.0; // timestep scaling
- if(mPanic) return;
-
- LbmFloat levOldOmega[FSGR_MAXNOOFLEVELS];
- LbmFloat levOldStepsize[FSGR_MAXNOOFLEVELS];
- for(int lev=mMaxRefine; lev>=0 ; lev--) {
- levOldOmega[lev] = mLevel[lev].omega;
- levOldStepsize[lev] = mLevel[lev].timestep;
- }
-
- const LbmFloat reduceFac = 0.8; // modify time step by 20%, TODO? do multiple times for large changes?
- LbmFloat diffPercent = 0.05; // dont scale if less than 5%
- LbmFloat allowMax = mpParam->getTadapMaxSpeed(); // maximum allowed velocity
- LbmFloat nextmax = mpParam->getSimulationMaxSpeed() + norm(mLevel[mMaxRefine].gravity);
-
- // sync nextmax
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(glob_mpactive) {
- if(mLevel[mMaxRefine].lsteps % MPTADAP_INTERV != MPTADAP_INTERV-1) {
- debMsgStd("LbmFsgrSolver::TAdp",DM_MSG, "mpact:"<<glob_mpactive<<","<<glob_mpindex<<"/"<<glob_mpnum<<" step:"<<mLevel[mMaxRefine].lsteps<<" skipping tadap...",8);
- return;
- }
- nextmax = mrInitTadap(nextmax);
- }
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
- LbmFloat newdt = mpParam->getTimestep(); // newtr
- if(nextmax > allowMax/reduceFac) {
- mTimeMaxvelStepCnt++; }
- else { mTimeMaxvelStepCnt=0; }
-
- // emergency, or 10 steps with high vel
- if((mTimeMaxvelStepCnt>5) || (nextmax> (1.0/3.0)) || (mForceTimeStepReduce) ) {
- newdt = mpParam->getTimestep() * reduceFac;
- } else {
- if(nextmax<allowMax*reduceFac) {
- newdt = mpParam->getTimestep() / reduceFac;
- }
- } // newtr
- //errMsg("LbmFsgrSolver::adaptTimestep","nextmax="<<nextmax<<" allowMax="<<allowMax<<" fac="<<reduceFac<<" simmaxv="<< mpParam->getSimulationMaxSpeed() );
-
- bool minCutoff = false;
- LbmFloat desireddt = newdt;
- if(newdt>mpParam->getMaxTimestep()){ newdt = mpParam->getMaxTimestep(); }
- if(newdt<mpParam->getMinTimestep()){
- newdt = mpParam->getMinTimestep();
- if(nextmax>allowMax/reduceFac){ minCutoff=true; } // only if really large vels...
- }
-
- LbmFloat dtdiff = fabs(newdt - mpParam->getTimestep());
- if(!mSilent) {
- debMsgStd("LbmFsgrSolver::TAdp",DM_MSG, "new"<<newdt
- <<" max"<<mpParam->getMaxTimestep()<<" min"<<mpParam->getMinTimestep()<<" diff"<<dtdiff
- <<" simt:"<<mSimulationTime<<" minsteps:"<<(mSimulationTime/mMaxTimestep)<<" maxsteps:"<<(mSimulationTime/mMinTimestep)<<
- " olddt"<<levOldStepsize[mMaxRefine]<<" redlock"<<mTimestepReduceLock
- , 10); }
-
- // in range, and more than X% change?
- //if( newdt < mpParam->getTimestep() ) // DEBUG
- LbmFloat rhoAvg = mCurrentMass/mCurrentVolume;
- if( (newdt<=mpParam->getMaxTimestep()) && (newdt>=mpParam->getMinTimestep())
- && (dtdiff>(mpParam->getTimestep()*diffPercent)) ) {
- if((newdt>levOldStepsize[mMaxRefine])&&(mTimestepReduceLock)) {
- // wait some more...
- //debMsgNnl("LbmFsgrSolver::TAdp",DM_NOTIFY," Delayed... "<<mTimestepReduceLock<<" ",10);
- debMsgDirect("D");
- } else {
- mpParam->setDesiredTimestep( newdt );
- rescale = true;
- if(!mSilent) {
- debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"\n\n\n\n",10);
- debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Timestep changing: new="<<newdt<<" old="<<mpParam->getTimestep()
- <<" maxSpeed:"<<mpParam->getSimulationMaxSpeed()<<" next:"<<nextmax<<" step:"<<mStepCnt, 10 );
- //debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Timestep changing: "<< "rhoAvg="<<rhoAvg<<" cMass="<<mCurrentMass<<" cVol="<<mCurrentVolume,10);
- }
- } // really change dt
- }
-
- if(mTimestepReduceLock>0) mTimestepReduceLock--;
-
-
- // forced back and forth switchting (for testing)
- /*const int tadtogInter = 100;
- const double tadtogSwitch = 0.66;
- errMsg("TIMESWITCHTOGGLETEST","warning enabled "<< tadtogSwitch<<","<<tadtogSwitch<<" !!!!!!!!!!!!!!!!!!!");
- if( ((mStepCnt% tadtogInter)== (tadtogInter/4*1)-1) ||
- ((mStepCnt% tadtogInter)== (tadtogInter/4*2)-1) ){
- rescale = true; minCutoff = false;
- newdt = tadtogSwitch * mpParam->getTimestep();
- mpParam->setDesiredTimestep( newdt );
- } else
- if( ((mStepCnt% tadtogInter)== (tadtogInter/4*3)-1) ||
- ((mStepCnt% tadtogInter)== (tadtogInter/4*4)-1) ){
- rescale = true; minCutoff = false;
- newdt = mpParam->getTimestep()/tadtogSwitch ;
- mpParam->setDesiredTimestep( newdt );
- } else {
- rescale = false; minCutoff = false;
- }
- // */
-
- // test mass rescale
-
- scaleFac = newdt/mpParam->getTimestep();
- if(rescale) {
- // perform acutal rescaling...
- mTimeMaxvelStepCnt=0;
- mForceTimeStepReduce = false;
-
- // FIXME - approximate by averaging, take gravity direction here?
- //mTimestepReduceLock = 4*(mLevel[mMaxRefine].lSizey+mLevel[mMaxRefine].lSizez+mLevel[mMaxRefine].lSizex)/3;
- // use z as gravity direction
- mTimestepReduceLock = 4*mLevel[mMaxRefine].lSizez;
-
- mTimeSwitchCounts++;
- mpParam->calculateAllMissingValues( mSimulationTime, mSilent );
- recalculateObjectSpeeds();
- // calc omega, force for all levels
- mLastOmega=1e10; mLastGravity=1e10;
- initLevelOmegas();
- if(mpParam->getTimestep()<mMinTimestep) mMinTimestep = mpParam->getTimestep();
- if(mpParam->getTimestep()>mMaxTimestep) mMaxTimestep = mpParam->getTimestep();
-
- // this might be called during init, before we have any particles
- if(mpParticles) { mpParticles->adaptPartTimestep(scaleFac); }
-#if LBM_INCLUDE_TESTSOLVERS==1
- if((mUseTestdata)&&(mpTest)) {
- mpTest->adaptTimestep(scaleFac, mLevel[mMaxRefine].omega, mLevel[mMaxRefine].timestep, vec2L( mpParam->calculateGravity(mSimulationTime)) );
- mpTest->mGrav3d = mLevel[mMaxRefine].gravity;
- }
-#endif // LBM_INCLUDE_TESTSOLVERS!=1
-
- for(int lev=mMaxRefine; lev>=0 ; lev--) {
- LbmFloat newSteptime = mLevel[lev].timestep;
- LbmFloat dfScaleFac = (newSteptime/1.0)/(levOldStepsize[lev]/levOldOmega[lev]);
-
- if(!mSilent) {
- debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Level: "<<lev<<" Timestep chlevel: "<<
- " scaleFac="<<dfScaleFac<<" newDt="<<newSteptime<<" newOmega="<<mLevel[lev].omega,10);
- }
- if(lev!=mMaxRefine) coarseCalculateFluxareas(lev);
-
- int wss = 0, wse = 1;
- // only change currset (necessary for compressed grids, better for non-compr.gr.)
- wss = wse = mLevel[lev].setCurr;
- for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT
- // warning - check sets for higher levels...?
- FSGR_FORIJK1(lev) {
- if( (RFLAG(lev,i,j,k, workSet) & CFBndMoving) ) {
- /*
- // paranoid check - shouldnt be necessary!
- if(QCELL(lev, i, j, k, workSet, dFlux)!=mSimulationTime) {
- errMsg("TTTT","found invalid bnd cell.... removing at "<<PRINT_IJK);
- RFLAG(lev,i,j,k, workSet) = CFInter;
- // init empty zero vel interface cell...
- initVelocityCell(lev, i,j,k, CFInter, 1.0, 0.01, LbmVec(0.) );
- } else {// */
- for(int l=0; l<cDfNum; l++) {
- QCELL(lev, i, j, k, workSet, l) = QCELL(lev, i, j, k, workSet, l)* scaleFac;
- }
- //} // ok
- continue;
- }
- if(
- (RFLAG(lev,i,j,k, workSet) & CFFluid) ||
- (RFLAG(lev,i,j,k, workSet) & CFInter) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrFromCoarse) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrFromFine) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrNorm)
- ) {
- // these cells have to be scaled...
- } else {
- continue;
- }
-
- // collide on current set
- LbmFloat rhoOld;
- LbmVec velOld;
- LbmFloat rho, ux,uy,uz;
- rho=0.0; ux = uy = uz = 0.0;
- for(int l=0; l<cDfNum; l++) {
- LbmFloat m = QCELL(lev, i, j, k, workSet, l);
- rho += m;
- ux += (dfDvecX[l]*m);
- uy += (dfDvecY[l]*m);
- uz += (dfDvecZ[l]*m);
- }
- rhoOld = rho;
- velOld = LbmVec(ux,uy,uz);
-
- LbmFloat rhoNew = (rhoOld-rhoAvg)*scaleFac +rhoAvg;
- LbmVec velNew = velOld * scaleFac;
-
- LbmFloat df[LBM_DFNUM];
- LbmFloat feqOld[LBM_DFNUM];
- LbmFloat feqNew[LBM_DFNUM];
- for(int l=0; l<cDfNum; l++) {
- feqOld[l] = getCollideEq(l,rhoOld, velOld[0],velOld[1],velOld[2] );
- feqNew[l] = getCollideEq(l,rhoNew, velNew[0],velNew[1],velNew[2] );
- df[l] = QCELL(lev, i,j,k,workSet, l);
- }
- const LbmFloat Qo = getLesNoneqTensorCoeff(df,feqOld);
- const LbmFloat oldOmega = getLesOmega(levOldOmega[lev], mLevel[lev].lcsmago,Qo);
- const LbmFloat newOmega = getLesOmega(mLevel[lev].omega,mLevel[lev].lcsmago,Qo);
- //newOmega = mLevel[lev].omega; // FIXME debug test
-
- //LbmFloat dfScaleFac = (newSteptime/1.0)/(levOldStepsize[lev]/levOldOmega[lev]);
- const LbmFloat dfScale = (newSteptime/newOmega)/(levOldStepsize[lev]/oldOmega);
- //dfScale = dfScaleFac/newOmega;
-
- for(int l=0; l<cDfNum; l++) {
- // org scaling
- //df = eqOld + (df-eqOld)*dfScale; df *= (eqNew/eqOld); // non-eq. scaling, important
- // new scaling
- LbmFloat dfn = feqNew[l] + (df[l]-feqOld[l])*dfScale*feqNew[l]/feqOld[l]; // non-eq. scaling, important
- //df = eqNew + (df-eqOld)*dfScale; // modified ig scaling, no real difference?
- QCELL(lev, i,j,k,workSet, l) = dfn;
- }
-
- if(RFLAG(lev,i,j,k, workSet) & CFInter) {
- //if(workSet==mLevel[lev].setCurr)
- LbmFloat area = 1.0;
- if(lev!=mMaxRefine) area = QCELL(lev, i,j,k,workSet, dFlux);
- massTOld += QCELL(lev, i,j,k,workSet, dMass) * area;
- volTOld += QCELL(lev, i,j,k,workSet, dFfrac);
-
- // wrong... QCELL(i,j,k,workSet, dMass] = (QCELL(i,j,k,workSet, dFfrac]*rhoNew);
- QCELL(lev, i,j,k,workSet, dMass) = (QCELL(lev, i,j,k,workSet, dMass)/rhoOld*rhoNew);
- QCELL(lev, i,j,k,workSet, dFfrac) = (QCELL(lev, i,j,k,workSet, dMass)/rhoNew);
-
- //if(workSet==mLevel[lev].setCurr)
- massTNew += QCELL(lev, i,j,k,workSet, dMass);
- volTNew += QCELL(lev, i,j,k,workSet, dFfrac);
- }
- if(RFLAG(lev,i,j,k, workSet) & CFFluid) { // DEBUG
- if(RFLAG(lev,i,j,k, workSet) & (CFGrFromFine|CFGrFromCoarse)) { // DEBUG
- // dont include
- } else {
- LbmFloat area = 1.0;
- if(lev!=mMaxRefine) area = QCELL(lev, i,j,k,workSet, dFlux) * mLevel[lev].lcellfactor;
- //if(workSet==mLevel[lev].setCurr)
- massTOld += rhoOld*area;
- //if(workSet==mLevel[lev].setCurr)
- massTNew += rhoNew*area;
- volTOld += area;
- volTNew += area;
- }
- }
-
- } // IJK
- } // workSet
-
- } // lev
-
- if(!mSilent) {
- debMsgStd("LbmFsgrSolver::step",DM_MSG,"REINIT DONE "<<mStepCnt<<
- " no"<<mTimeSwitchCounts<<" maxdt"<<mMaxTimestep<<
- " mindt"<<mMinTimestep<<" currdt"<<mLevel[mMaxRefine].timestep, 10);
- debMsgStd("LbmFsgrSolver::step",DM_MSG,"REINIT DONE masst:"<<massTNew<<","<<massTOld<<" org:"<<mCurrentMass<<"; "<<
- " volt:"<<volTNew<<","<<volTOld<<" org:"<<mCurrentVolume, 10);
- } else {
- debMsgStd("\nLbmOptSolver::step",DM_MSG,"Timestep changed by "<< (newdt/levOldStepsize[mMaxRefine]) <<" newDt:"<<newdt
- <<", oldDt:"<<levOldStepsize[mMaxRefine]<<" newOmega:"<<mOmega<<" gStar:"<<mpParam->getCurrentGStar()<<", step:"<<mStepCnt , 10);
- }
- } // rescale?
- //NEWDEBCHECK("tt2");
-
- //errMsg("adaptTimestep","Warning - brute force rescale off!"); minCutoff = false; // DEBUG
- if(minCutoff) {
- errMsg("adaptTimestep","Warning - performing Brute-Force rescale... (sim:"<<mName<<" step:"<<mStepCnt<<" newdt="<<desireddt<<" mindt="<<mpParam->getMinTimestep()<<") " );
- //brute force resacle all the time?
-
- for(int lev=mMaxRefine; lev>=0 ; lev--) {
- int rescs=0;
- int wss = 0, wse = 1;
-#if COMPRESSGRIDS==1
- if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr;
-#endif // COMPRESSGRIDS==1
- for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT
- //for(int workSet = 0; workSet<=1; workSet++) {
- FSGR_FORIJK1(lev) {
-
- //if( (RFLAG(lev, i,j,k, workSet) & CFFluid) || (RFLAG(lev, i,j,k, workSet) & CFInter) ) {
- if(
- (RFLAG(lev,i,j,k, workSet) & CFFluid) ||
- (RFLAG(lev,i,j,k, workSet) & CFInter) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrFromCoarse) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrFromFine) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrNorm)
- ) {
- // these cells have to be scaled...
- } else {
- continue;
- }
-
- // collide on current set
- LbmFloat rho, ux,uy,uz;
- rho=0.0; ux = uy = uz = 0.0;
- for(int l=0; l<cDfNum; l++) {
- LbmFloat m = QCELL(lev, i, j, k, workSet, l);
- rho += m;
- ux += (dfDvecX[l]*m);
- uy += (dfDvecY[l]*m);
- uz += (dfDvecZ[l]*m);
- }
-#ifndef WIN32
- if (!isfinite(rho)) {
- errMsg("adaptTimestep","Brute force non-finite rho at"<<PRINT_IJK); // DEBUG!
- rho = 1.0;
- ux = uy = uz = 0.0;
- QCELL(lev, i, j, k, workSet, dMass) = 1.0;
- QCELL(lev, i, j, k, workSet, dFfrac) = 1.0;
- }
-#endif // WIN32
-
- if( (ux*ux+uy*uy+uz*uz)> (allowMax*allowMax) ) {
- LbmFloat cfac = allowMax/sqrt(ux*ux+uy*uy+uz*uz);
- ux *= cfac;
- uy *= cfac;
- uz *= cfac;
- for(int l=0; l<cDfNum; l++) {
- QCELL(lev, i, j, k, workSet, l) = getCollideEq(l, rho, ux,uy,uz); }
- rescs++;
- debMsgDirect("B");
- }
-
- } }
- //if(rescs>0) { errMsg("adaptTimestep","!!!!! Brute force rescaling was necessary !!!!!!!"); }
- debMsgStd("adaptTimestep",DM_MSG,"Brute force rescale done. level:"<<lev<<" rescs:"<<rescs, 1);
- //TTT mNumProblems += rescs; // add to problem display...
- } // lev,set,ijk
-
- } // try brute force rescale?
-
- // time adap done...
-}
-
-
-
diff --git a/intern/elbeem/intern/solver_class.h b/intern/elbeem/intern/solver_class.h
deleted file mode 100644
index ac02f2cc85a..00000000000
--- a/intern/elbeem/intern/solver_class.h
+++ /dev/null
@@ -1,1036 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - the visual lattice boltzmann freesurface simulator
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Combined 2D/3D Lattice Boltzmann standard solver classes
- *
- *****************************************************************************/
-
-
-#ifndef LBM_SOLVERCLASS_H
-#define LBM_SOLVERCLASS_H
-
-#include "utilities.h"
-#include "solver_interface.h"
-#include "ntl_ray.h"
-#include <stdio.h>
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-#if PARALLEL==1
-#include <omp.h>
-#endif // PARALLEL=1
-#ifndef PARALLEL
-#define PARALLEL 0
-#endif // PARALLEL
-
-
-// general solver setting defines
-
-//! debug coordinate accesses and the like? (much slower)
-// might be enabled by compilation
-#ifndef FSGR_STRICT_DEBUG
-#define FSGR_STRICT_DEBUG 0
-#endif // FSGR_STRICT_DEBUG
-
-//! debug coordinate accesses and the like? (much slower)
-#define FSGR_OMEGA_DEBUG 0
-
-//! OPT3D quick LES on/off, only debug/benchmarking
-#define USE_LES 1
-
-//! order of interpolation (0=always current/1=interpolate/2=always other)
-//#define TIMEINTORDER 0
-// TODO remove interpol t param, also interTime
-
-// use optimized 3D code?
-#if LBMDIM==2
-#define OPT3D 0
-#else
-// determine with debugging...
-# if FSGR_STRICT_DEBUG==1
-# define OPT3D 0
-# else // FSGR_STRICT_DEBUG==1
-// usually switch optimizations for 3d on, when not debugging
-# define OPT3D 1
-// COMPRT
-//# define OPT3D 0
-# endif // FSGR_STRICT_DEBUG==1
-#endif
-
-//! invalid mass value for unused mass data
-#define MASS_INVALID -1000.0
-
-// empty/fill cells without fluid/empty NB's by inserting them into the full/empty lists?
-#define FSGR_LISTTRICK 1
-#define FSGR_LISTTTHRESHEMPTY 0.10
-#define FSGR_LISTTTHRESHFULL 0.90
-#define FSGR_MAGICNR 0.025
-//0.04
-
-//! maxmimum no. of grid levels
-#define FSGR_MAXNOOFLEVELS 5
-
-// enable/disable fine grid compression for finest level
-// make sure this is same as useGridComp in calculateMemreqEstimate
-#if LBMDIM==3
-#define COMPRESSGRIDS 1
-#else
-#define COMPRESSGRIDS 0
-#endif
-
-// helper for comparing floats with epsilon
-#define GFX_FLOATNEQ(x,y) ( ABS((x)-(y)) > (VECTOR_EPSILON) )
-#define LBM_FLOATNEQ(x,y) ( ABS((x)-(y)) > (10.0*LBM_EPSILON) )
-
-
-// macros for loops over all DFs
-#define FORDF0 for(int l= 0; l< LBM_DFNUM; ++l)
-#define FORDF1 for(int l= 1; l< LBM_DFNUM; ++l)
-// and with different loop var to prevent shadowing
-#define FORDF0M for(int m= 0; m< LBM_DFNUM; ++m)
-#define FORDF1M for(int m= 1; m< LBM_DFNUM; ++m)
-
-// iso value defines
-// border for marching cubes
-#define ISOCORR 3
-
-#define LBM_INLINED inline
-
-// sirdude fix for solaris
-#if !defined(linux) && defined(sun)
-#include "ieeefp.h"
-#ifndef expf
-#define expf(x) exp((double)(x))
-#endif
-#endif
-
-#include "solver_control.h"
-
-#if LBM_INCLUDE_TESTSOLVERS==1
-#include "solver_test.h"
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
-/*****************************************************************************/
-/*! cell access classes */
-class UniformFsgrCellIdentifier :
- public CellIdentifierInterface , public LbmCellContents
-{
- public:
- //! which grid level?
- int level;
- //! location in grid
- int x,y,z;
-
- //! reset constructor
- UniformFsgrCellIdentifier() :
- x(0), y(0), z(0) { };
-
- // implement CellIdentifierInterface
- virtual string getAsString() {
- std::ostringstream ret;
- ret <<"{ i"<<x<<",j"<<y;
- if(LBMDIM>2) ret<<",k"<<z;
- ret <<" }";
- return ret.str();
- }
-
- virtual bool equal(CellIdentifierInterface* other) {
- UniformFsgrCellIdentifier *cid = (UniformFsgrCellIdentifier *)( other );
- if(!cid) return false;
- if( x==cid->x && y==cid->y && z==cid->z && level==cid->level ) return true;
- return false;
- }
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:UniformFsgrCellIdentifier")
-#endif
-};
-
-//! information needed for each level in the simulation
-class FsgrLevelData {
-public:
- int id; // level number
-
- //! node size on this level (geometric, in world coordinates, not simulation units!)
- LbmFloat nodeSize;
- //! node size on this level in simulation units
- LbmFloat simCellSize;
- //! quadtree node relaxation parameter
- LbmFloat omega;
- //! size this level was advanced to
- LbmFloat time;
- //! size of a single lbm step in time units on this level
- LbmFloat timestep;
- //! step count
- int lsteps;
- //! gravity force for this level
- LbmVec gravity;
- //! level array
- LbmFloat *mprsCells[2];
- CellFlagType *mprsFlags[2];
-
- //! smago params and precalculated values
- LbmFloat lcsmago;
- LbmFloat lcsmago_sqr;
- LbmFloat lcnu;
-
- // LES statistics per level
- double avgOmega;
- double avgOmegaCnt;
-
- //! current set of dist funcs
- int setCurr;
- //! target/other set of dist funcs
- int setOther;
-
- //! mass&volume for this level
- LbmFloat lmass;
- LbmFloat lvolume;
- LbmFloat lcellfactor;
-
- //! local storage of mSizes
- int lSizex, lSizey, lSizez;
- int lOffsx, lOffsy, lOffsz;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:FsgrLevelData")
-#endif
-};
-
-
-
-/*****************************************************************************/
-/*! class for solving a LBM problem */
-class LbmFsgrSolver :
- public LbmSolverInterface // this means, the solver is a lbmData object and implements the lbmInterface
-{
-
- public:
- //! Constructor
- LbmFsgrSolver();
- //! Destructor
- virtual ~LbmFsgrSolver();
-
- //! initilize variables fom attribute list
- virtual void parseAttrList();
- //! Initialize omegas and forces on all levels (for init/timestep change)
- void initLevelOmegas();
-
- // multi step solver init
- /*! finish the init with config file values (allocate arrays...) */
- virtual bool initializeSolverMemory();
- /*! init solver arrays */
- virtual bool initializeSolverGrids();
- /*! prepare actual simulation start, setup viz etc */
- virtual bool initializeSolverPostinit();
-
- //! notify object that dump is in progress (e.g. for field dump)
- virtual void notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename);
-
-# if LBM_USE_GUI==1
- //! show simulation info (implement LbmSolverInterface pure virtual func)
- virtual void debugDisplay(int set);
-# endif
-
- // implement CellIterator<UniformFsgrCellIdentifier> interface
- typedef UniformFsgrCellIdentifier stdCellId;
- virtual CellIdentifierInterface* getFirstCell( );
- virtual void advanceCell( CellIdentifierInterface* );
- virtual bool noEndCell( CellIdentifierInterface* );
- virtual void deleteCellIterator( CellIdentifierInterface** );
- virtual CellIdentifierInterface* getCellAt( ntlVec3Gfx pos );
- virtual int getCellSet ( CellIdentifierInterface* );
- virtual ntlVec3Gfx getCellOrigin ( CellIdentifierInterface* );
- virtual ntlVec3Gfx getCellSize ( CellIdentifierInterface* );
- virtual int getCellLevel ( CellIdentifierInterface* );
- virtual LbmFloat getCellDensity ( CellIdentifierInterface* ,int set);
- virtual LbmVec getCellVelocity ( CellIdentifierInterface* ,int set);
- virtual LbmFloat getCellDf ( CellIdentifierInterface* ,int set, int dir);
- virtual LbmFloat getCellMass ( CellIdentifierInterface* ,int set);
- virtual LbmFloat getCellFill ( CellIdentifierInterface* ,int set);
- virtual CellFlagType getCellFlag ( CellIdentifierInterface* ,int set);
- virtual LbmFloat getEquilDf ( int );
- virtual ntlVec3Gfx getVelocityAt (float x, float y, float z);
- // convert pointers
- stdCellId* convertBaseCidToStdCid( CellIdentifierInterface* basecid);
-
- //! perform geometry init (if switched on)
- bool initGeometryFlags();
- //! init part for all freesurface testcases
- void initFreeSurfaces();
- //! init density gradient if enabled
- void initStandingFluidGradient();
-
- /*! init a given cell with flag, density, mass and equilibrium dist. funcs */
- LBM_INLINED void initEmptyCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass);
- LBM_INLINED void initVelocityCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass, LbmVec vel);
- LBM_INLINED void changeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag);
- LBM_INLINED void forceChangeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag);
- LBM_INLINED void initInterfaceVars(int level, int i,int j,int k,int workSet, bool initMass);
- //! interpolate velocity and density at a given position
- void interpolateCellValues(int level,int ei,int ej,int ek,int workSet, LbmFloat &retrho, LbmFloat &retux, LbmFloat &retuy, LbmFloat &retuz);
-
- /*! perform a single LBM step */
- void stepMain();
- //! advance fine grid
- void fineAdvance();
- //! advance coarse grid
- void coarseAdvance(int lev);
- //! update flux area values on coarse grids
- void coarseCalculateFluxareas(int lev);
- // adaptively coarsen grid
- bool adaptGrid(int lev);
- // restrict fine grid DFs to coarse grid
- void coarseRestrictFromFine(int lev);
-
- /* simulation object interface, just calls stepMain */
- virtual void step();
- /*! init particle positions */
- virtual int initParticles();
- /*! move all particles */
- virtual void advanceParticles();
- /*! move a particle at a boundary */
- void handleObstacleParticle(ParticleObject *p);
- /*! check whether to add particle
- bool checkAddParticle();
- void performAddParticle();*/
-
-
- /*! debug object display (used e.g. for preview surface) */
- virtual vector<ntlGeometryObject*> getDebugObjects();
-
- // gui/output debugging functions
-# if LBM_USE_GUI==1
- virtual void debugDisplayNode(int dispset, CellIdentifierInterface* cell );
- virtual void lbmDebugDisplay(int dispset);
- virtual void lbmMarkedCellDisplay();
-# endif // LBM_USE_GUI==1
- virtual void debugPrintNodeInfo(CellIdentifierInterface* cell, int forceSet=-1);
-
- //! for raytracing, preprocess
- void prepareVisualization( void );
-
- /* surface generation settings */
- virtual void setSurfGenSettings(short value);
-
- protected:
-
- //! internal quick print function (for debugging)
- void printLbmCell(int level, int i, int j, int k,int set);
- // debugging use CellIterator interface to mark cell
- void debugMarkCellCall(int level, int vi,int vj,int vk);
-
- // loop over grid, stream&collide update
- void mainLoop(const int lev);
- // change time step size
- void adaptTimestep();
- //! init mObjectSpeeds for current parametrization
- void recalculateObjectSpeeds();
- //! init moving obstacles for next sim step sim
- void initMovingObstacles(bool staticInit);
- //! flag reinit step - always works on finest grid!
- void reinitFlags( int workSet );
- //! mass dist weights
- LbmFloat getMassdWeight(bool dirForw, int i,int j,int k,int workSet, int l);
- //! compute surface normals: fluid, fluid more accurate, and for obstacles
- void computeFluidSurfaceNormal(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret);
- void computeFluidSurfaceNormalAcc(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret);
- void computeObstacleSurfaceNormal(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret);
- void computeObstacleSurfaceNormalAcc(int i,int j,int k, LbmFloat *snret);
- //! add point to mListNewInter list
- LBM_INLINED void addToNewInterList( int ni, int nj, int nk );
- //! cell is interpolated from coarse level (inited into set, source sets are determined by t)
- void interpolateCellFromCoarse(int lev, int i, int j,int k, int dstSet, LbmFloat t, CellFlagType flagSet,bool markNbs);
- void coarseRestrictCell(int lev, int i,int j,int k, int srcSet, int dstSet);
-
- //! minimal and maximal z-coords (for 2D/3D loops)
- LBM_INLINED int getForZMinBnd();
- LBM_INLINED int getForZMin1();
- LBM_INLINED int getForZMaxBnd(int lev);
- LBM_INLINED int getForZMax1(int lev);
- LBM_INLINED bool checkDomainBounds(int lev,int i,int j,int k);
- LBM_INLINED bool checkDomainBoundsPos(int lev,LbmVec pos);
-
- // touch grid and flags once
- void preinitGrids();
- // one relaxation step for standing fluid
- void standingFluidPreinit();
-
-
- // member vars
-
- //! mass calculated during streaming step
- LbmFloat mCurrentMass;
- LbmFloat mCurrentVolume;
- LbmFloat mInitialMass;
-
- //! count problematic cases, that occured so far...
- int mNumProblems;
-
- // average mlsups, count how many so far...
- double mAvgMLSUPS;
- double mAvgMLSUPSCnt;
-
- //! Mcubes object for surface reconstruction
- IsoSurface *mpPreviewSurface;
-
- //! use time adaptivity?
- bool mTimeAdap;
- //! force smaller timestep for next LBM step? (eg for mov obj)
- bool mForceTimeStepReduce;
-
- //! fluid vol height
- LbmFloat mFVHeight;
- LbmFloat mFVArea;
- bool mUpdateFVHeight;
-
- //! force quit for gfx
- LbmFloat mGfxEndTime;
- //! smoother surface initialization?
- int mInitSurfaceSmoothing;
- //! surface generation settings, default is all off (=0)
- // each flag switches side on off, fssgNoObs is for obstacle sides
- // -1 equals all on
- typedef enum {
- fssgNormal = 0,
- fssgNoNorth = 1,
- fssgNoSouth = 2,
- fssgNoEast = 4,
- fssgNoWest = 8,
- fssgNoTop = 16,
- fssgNoBottom = 32,
- fssgNoObs = 64
- } fsSurfaceGen;
- int mFsSurfGenSetting;
-
- //! lock time step down switching
- int mTimestepReduceLock;
- //! count no. of switches
- int mTimeSwitchCounts;
- // only switch of maxvel is higher for several steps...
- int mTimeMaxvelStepCnt;
-
- //! total simulation time so far
- LbmFloat mSimulationTime, mLastSimTime;
- //! smallest and largest step size so far
- LbmFloat mMinTimestep, mMaxTimestep;
- //! track max. velocity
- LbmFloat mMxvx, mMxvy, mMxvz, mMaxVlen;
-
- //! list of the cells to empty at the end of the step
- vector<LbmPoint> mListEmpty;
- //! list of the cells to make fluid at the end of the step
- vector<LbmPoint> mListFull;
- //! list of new interface cells to init
- vector<LbmPoint> mListNewInter;
- //! class for handling redist weights in reinit flag function
- class lbmFloatSet {
- public:
- LbmFloat val[dTotalNum];
- LbmFloat numNbs;
- };
- //! normalized vectors for all neighboring cell directions (for e.g. massdweight calc)
- LbmVec mDvecNrm[27];
-
-
- //! debugging
- bool checkSymmetry(string idstring);
- //! kepp track of max/min no. of filled cells
- int mMaxNoCells, mMinNoCells;
- LONGINT mAvgNumUsedCells;
-
- //! precalculated objects speeds for current parametrization
- vector<LbmVec> mObjectSpeeds;
- //! partslip bc. values for obstacle boundary conditions
- vector<LbmFloat> mObjectPartslips;
- //! moving object mass boundary condition values
- vector<LbmFloat> mObjectMassMovnd;
-
- //! permanent movobj vert storage
- vector<ntlVec3Gfx> mMOIVertices;
- vector<ntlVec3Gfx> mMOIVerticesOld;
- vector<ntlVec3Gfx> mMOINormals;
-
- //! get isofield weights
- int mIsoWeightMethod;
- float mIsoWeight[27];
-
- // grid coarsening vars
-
- /*! vector for the data for each level */
- FsgrLevelData mLevel[FSGR_MAXNOOFLEVELS];
-
- /*! minimal and maximal refinement levels */
- int mMaxRefine;
-
- /*! df scale factors for level up/down */
- LbmFloat mDfScaleUp, mDfScaleDown;
-
- /*! precomputed cell area values */
- LbmFloat mFsgrCellArea[27];
- /*! restriction interpolation weights */
- LbmFloat mGaussw[27];
-
- /*! LES C_smago paramter for finest grid */
- float mInitialCsmago;
- /*! LES stats for non OPT3D */
- LbmFloat mDebugOmegaRet;
- /*! remember last init for animated params */
- LbmFloat mLastOmega;
- LbmVec mLastGravity;
-
- //! fluid stats
- int mNumInterdCells;
- int mNumInvIfCells;
- int mNumInvIfTotal;
- int mNumFsgrChanges;
-
- //! debug function to disable standing f init
- int mDisableStandingFluidInit;
- //! init 2d with skipped Y/Z coords
- bool mInit2dYZ;
- //! debug function to force tadap syncing
- int mForceTadapRefine;
- //! border cutoff value
- int mCutoff;
-
- // strict debug interface
-# if FSGR_STRICT_DEBUG==1
- int debLBMGI(int level, int ii,int ij,int ik, int is);
- CellFlagType& debRFLAG(int level, int xx,int yy,int zz,int set);
- CellFlagType& debRFLAG_NB(int level, int xx,int yy,int zz,int set, int dir);
- CellFlagType& debRFLAG_NBINV(int level, int xx,int yy,int zz,int set, int dir);
- int debLBMQI(int level, int ii,int ij,int ik, int is, int l);
- LbmFloat& debQCELL(int level, int xx,int yy,int zz,int set,int l);
- LbmFloat& debQCELL_NB(int level, int xx,int yy,int zz,int set, int dir,int l);
- LbmFloat& debQCELL_NBINV(int level, int xx,int yy,int zz,int set, int dir,int l);
- LbmFloat* debRACPNT(int level, int ii,int ij,int ik, int is );
- LbmFloat& debRAC(LbmFloat* s,int l);
-# endif // FSGR_STRICT_DEBUG==1
-
- LbmControlData *mpControl;
-
- void initCpdata();
- void handleCpdata();
- void cpDebugDisplay(int dispset);
-
- bool mUseTestdata;
-# if LBM_INCLUDE_TESTSOLVERS==1
- // test functions
- LbmTestdata *mpTest;
- void initTestdata();
- void destroyTestdata();
- void handleTestdata();
- void set3dHeight(int ,int );
-
- int mMpNum,mMpIndex;
- int mOrgSizeX;
- LbmFloat mOrgStartX;
- LbmFloat mOrgEndX;
- void mrSetup();
- void mrExchange();
- void mrIsoExchange();
- LbmFloat mrInitTadap(LbmFloat max);
- void gcFillBuffer( LbmGridConnector *gc, int *retSizeCnt, const int *bdfs);
- void gcUnpackBuffer(LbmGridConnector *gc, int *retSizeCnt, const int *bdfs);
- public:
- // needed for testdata
- void find3dHeight(int i,int j, LbmFloat prev, LbmFloat &ret, LbmFloat *retux, LbmFloat *retuy, LbmFloat *retuz);
- // mptest
- int getMpIndex() { return mMpIndex; };
-# endif // LBM_INCLUDE_TESTSOLVERS==1
-
- // former LbmModelLBGK functions
- // relaxation funtions - implemented together with relax macros
- static inline LbmFloat getVelVecLen(int l, LbmFloat ux,LbmFloat uy,LbmFloat uz);
- static inline LbmFloat getCollideEq(int l, LbmFloat rho, LbmFloat ux, LbmFloat uy, LbmFloat uz);
- inline LbmFloat getLesNoneqTensorCoeff( LbmFloat df[], LbmFloat feq[] );
- inline LbmFloat getLesOmega(LbmFloat omega, LbmFloat csmago, LbmFloat Qo);
- inline void collideArrays( int lev, int i, int j, int k, // position - more for debugging
- LbmFloat df[], LbmFloat &outrho, // out only!
- // velocity modifiers (returns actual velocity!)
- LbmFloat &mux, LbmFloat &muy, LbmFloat &muz,
- LbmFloat omega, LbmVec gravity, LbmFloat csmago,
- LbmFloat *newOmegaRet, LbmFloat *newQoRet);
-
-
- // former LBM models
- //! shorten static const definitions
-# define STCON static const
-
-# if LBMDIM==3
-
- //! id string of solver
- virtual string getIdString() { return string("FreeSurfaceFsgrSolver[BGK_D3Q19]"); }
-
- //! how many dimensions? UNUSED? replace by LBMDIM?
- STCON int cDimension;
-
- // Wi factors for collide step
- STCON LbmFloat cCollenZero;
- STCON LbmFloat cCollenOne;
- STCON LbmFloat cCollenSqrtTwo;
-
- //! threshold value for filled/emptied cells
- STCON LbmFloat cMagicNr2;
- STCON LbmFloat cMagicNr2Neg;
- STCON LbmFloat cMagicNr;
- STCON LbmFloat cMagicNrNeg;
-
- //! size of a single set of distribution functions
- STCON int cDfNum;
- //! direction vector contain vecs for all spatial dirs, even if not used for LBM model
- STCON int cDirNum;
-
- //! distribution functions directions
- typedef enum {
- cDirInv= -1,
- cDirC = 0,
- cDirN = 1,
- cDirS = 2,
- cDirE = 3,
- cDirW = 4,
- cDirT = 5,
- cDirB = 6,
- cDirNE = 7,
- cDirNW = 8,
- cDirSE = 9,
- cDirSW = 10,
- cDirNT = 11,
- cDirNB = 12,
- cDirST = 13,
- cDirSB = 14,
- cDirET = 15,
- cDirEB = 16,
- cDirWT = 17,
- cDirWB = 18
- } dfDir;
-
- /* Vector Order 3D:
- * 0 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
- * 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1
- * 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1
- * 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1
- */
-
- /*! name of the dist. function
- only for nicer output */
- STCON char* dfString[ 19 ];
-
- /*! index of normal dist func, not used so far?... */
- STCON int dfNorm[ 19 ];
-
- /*! index of inverse dist func, not fast, but useful... */
- STCON int dfInv[ 19 ];
-
- /*! index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefX[ 19 ];
- /*! index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefY[ 19 ];
- /*! index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefZ[ 19 ];
-
- /*! dist func vectors */
- STCON int dfVecX[ 27 ];
- STCON int dfVecY[ 27 ];
- STCON int dfVecZ[ 27 ];
-
- /*! arrays as before with doubles */
- STCON LbmFloat dfDvecX[ 27 ];
- STCON LbmFloat dfDvecY[ 27 ];
- STCON LbmFloat dfDvecZ[ 27 ];
-
- /*! principal directions */
- STCON int princDirX[ 2*3 ];
- STCON int princDirY[ 2*3 ];
- STCON int princDirZ[ 2*3 ];
-
- /*! vector lengths */
- STCON LbmFloat dfLength[ 19 ];
-
- /*! equilibrium distribution functions, precalculated = getCollideEq(i, 0,0,0,0) */
- static LbmFloat dfEquil[ dTotalNum ];
-
- /*! arrays for les model coefficients */
- static LbmFloat lesCoeffDiag[ (3-1)*(3-1) ][ 27 ];
- static LbmFloat lesCoeffOffdiag[ 3 ][ 27 ];
-
-# else // end LBMDIM==3 , LBMDIM==2
-
- //! id string of solver
- virtual string getIdString() { return string("FreeSurfaceFsgrSolver[BGK_D2Q9]"); }
-
- //! how many dimensions?
- STCON int cDimension;
-
- //! Wi factors for collide step
- STCON LbmFloat cCollenZero;
- STCON LbmFloat cCollenOne;
- STCON LbmFloat cCollenSqrtTwo;
-
- //! threshold value for filled/emptied cells
- STCON LbmFloat cMagicNr2;
- STCON LbmFloat cMagicNr2Neg;
- STCON LbmFloat cMagicNr;
- STCON LbmFloat cMagicNrNeg;
-
- //! size of a single set of distribution functions
- STCON int cDfNum;
- STCON int cDirNum;
-
- //! distribution functions directions
- typedef enum {
- cDirInv= -1,
- cDirC = 0,
- cDirN = 1,
- cDirS = 2,
- cDirE = 3,
- cDirW = 4,
- cDirNE = 5,
- cDirNW = 6,
- cDirSE = 7,
- cDirSW = 8
- } dfDir;
-
- /* Vector Order 2D:
- * 0 1 2 3 4 5 6 7 8
- * 0, 0,0, 1,-1, 1,-1,1,-1
- * 0, 1,-1, 0,0, 1,1,-1,-1 */
-
- /* name of the dist. function
- only for nicer output */
- STCON char* dfString[ 9 ];
-
- /* index of normal dist func, not used so far?... */
- STCON int dfNorm[ 9 ];
-
- /* index of inverse dist func, not fast, but useful... */
- STCON int dfInv[ 9 ];
-
- /* index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefX[ 9 ];
- /* index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefY[ 9 ];
- /* index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefZ[ 9 ];
-
- /* dist func vectors */
- STCON int dfVecX[ 9 ];
- STCON int dfVecY[ 9 ];
- /* Z, 2D values are all 0! */
- STCON int dfVecZ[ 9 ];
-
- /* arrays as before with doubles */
- STCON LbmFloat dfDvecX[ 9 ];
- STCON LbmFloat dfDvecY[ 9 ];
- /* Z, 2D values are all 0! */
- STCON LbmFloat dfDvecZ[ 9 ];
-
- /*! principal directions */
- STCON int princDirX[ 2*2 ];
- STCON int princDirY[ 2*2 ];
- STCON int princDirZ[ 2*2 ];
-
- /* vector lengths */
- STCON LbmFloat dfLength[ 9 ];
-
- /* equilibrium distribution functions, precalculated = getCollideEq(i, 0,0,0,0) */
- static LbmFloat dfEquil[ dTotalNum ];
-
- /*! arrays for les model coefficients */
- static LbmFloat lesCoeffDiag[ (2-1)*(2-1) ][ 9 ];
- static LbmFloat lesCoeffOffdiag[ 2 ][ 9 ];
-
-# endif // LBMDIM==2
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:LbmFsgrSolver")
-#endif
-};
-
-#undef STCON
-
-
-/*****************************************************************************/
-// relaxation_macros
-
-
-
-// cell mark debugging
-#if FSGR_STRICT_DEBUG==10
-#define debugMarkCell(lev,x,y,z) \
- errMsg("debugMarkCell",this->mName<<" step: "<<this->mStepCnt<<" lev:"<<(lev)<<" marking "<<PRINT_VEC((x),(y),(z))<<" line "<< __LINE__ ); \
- debugMarkCellCall((lev),(x),(y),(z));
-#else // FSGR_STRICT_DEBUG==1
-#define debugMarkCell(lev,x,y,z) \
- debugMarkCellCall((lev),(x),(y),(z));
-#endif // FSGR_STRICT_DEBUG==1
-
-
-// flag array defines -----------------------------------------------------------------------------------------------
-
-// lbm testsolver get index define, note - ignores is (set) as flag
-// array is only a single entry
-#define _LBMGI(level, ii,ij,ik, is) ( (LONGINT)((LONGINT)mLevel[level].lOffsy*(LONGINT)(ik)) + ((LONGINT)mLevel[level].lOffsx*(LONGINT)(ij)) + (LONGINT)(ii) )
-
-//! flag array acces macro
-#define _RFLAG(level,xx,yy,zz,set) mLevel[level].mprsFlags[set][ (LONGINT)LBMGI((level),(xx),(yy),(zz),(set)) ]
-#define _RFLAG_NB(level,xx,yy,zz,set, dir) mLevel[level].mprsFlags[set][ (LONGINT)LBMGI((level),(xx)+this->dfVecX[dir],(yy)+this->dfVecY[dir],(zz)+this->dfVecZ[dir],set) ]
-#define _RFLAG_NBINV(level,xx,yy,zz,set, dir) mLevel[level].mprsFlags[set][ (LONGINT)LBMGI((level),(xx)+this->dfVecX[this->dfInv[dir]],(yy)+this->dfVecY[this->dfInv[dir]],(zz)+this->dfVecZ[this->dfInv[dir]],set) ]
-
-// array handling -----------------------------------------------------------------------------------------------
-
-#define _LBMQI(level, ii,ij,ik, is, lunused) ( (LONGINT)((LONGINT)mLevel[level].lOffsy*(LONGINT)(ik)) + (LONGINT)((LONGINT)mLevel[level].lOffsx*(LONGINT)(ij)) + (LONGINT)(ii) )
-#define _QCELL(level,xx,yy,zz,set,l) (mLevel[level].mprsCells[(set)][ (LONGINT)LBMQI((level),(xx),(yy),(zz),(set), l)*(LONGINT)dTotalNum +(LONGINT)(l)])
-#define _QCELL_NB(level,xx,yy,zz,set, dir,l) (mLevel[level].mprsCells[(set)][ (LONGINT)LBMQI((level),(xx)+this->dfVecX[dir],(yy)+this->dfVecY[dir],(zz)+this->dfVecZ[dir],set, l)*dTotalNum +(l)])
-#define _QCELL_NBINV(level,xx,yy,zz,set, dir,l) (mLevel[level].mprsCells[(set)][ (LONGINT)LBMQI((level),(xx)+this->dfVecX[this->dfInv[dir]],(yy)+this->dfVecY[this->dfInv[dir]],(zz)+this->dfVecZ[this->dfInv[dir]],set, l)*dTotalNum +(l)])
-
-#define QCELLSTEP dTotalNum
-#define _RACPNT(level, ii,ij,ik, is ) &QCELL(level,ii,ij,ik,is,0)
-#define _RAC(s,l) (s)[(l)]
-
-
-#if FSGR_STRICT_DEBUG==1
-
-#define LBMGI(level,ii,ij,ik, is) debLBMGI(level,ii,ij,ik, is)
-#define RFLAG(level,xx,yy,zz,set) debRFLAG(level,xx,yy,zz,set)
-#define RFLAG_NB(level,xx,yy,zz,set, dir) debRFLAG_NB(level,xx,yy,zz,set, dir)
-#define RFLAG_NBINV(level,xx,yy,zz,set, dir) debRFLAG_NBINV(level,xx,yy,zz,set, dir)
-
-#define LBMQI(level,ii,ij,ik, is, l) debLBMQI(level,ii,ij,ik, is, l)
-#define QCELL(level,xx,yy,zz,set,l) debQCELL(level,xx,yy,zz,set,l)
-#define QCELL_NB(level,xx,yy,zz,set, dir,l) debQCELL_NB(level,xx,yy,zz,set, dir,l)
-#define QCELL_NBINV(level,xx,yy,zz,set, dir,l) debQCELL_NBINV(level,xx,yy,zz,set, dir,l)
-#define RACPNT(level, ii,ij,ik, is ) debRACPNT(level, ii,ij,ik, is )
-#define RAC(s,l) debRAC(s,l)
-
-#else // FSGR_STRICT_DEBUG==1
-
-#define LBMGI(level,ii,ij,ik, is) _LBMGI(level,ii,ij,ik, is)
-#define RFLAG(level,xx,yy,zz,set) _RFLAG(level,xx,yy,zz,set)
-#define RFLAG_NB(level,xx,yy,zz,set, dir) _RFLAG_NB(level,xx,yy,zz,set, dir)
-#define RFLAG_NBINV(level,xx,yy,zz,set, dir) _RFLAG_NBINV(level,xx,yy,zz,set, dir)
-
-#define LBMQI(level,ii,ij,ik, is, l) _LBMQI(level,ii,ij,ik, is, l)
-#define QCELL(level,xx,yy,zz,set,l) _QCELL(level,xx,yy,zz,set,l)
-#define QCELL_NB(level,xx,yy,zz,set, dir,l) _QCELL_NB(level,xx,yy,zz,set, dir, l)
-#define QCELL_NBINV(level,xx,yy,zz,set, dir,l) _QCELL_NBINV(level,xx,yy,zz,set, dir,l)
-#define RACPNT(level, ii,ij,ik, is ) _RACPNT(level, ii,ij,ik, is )
-#define RAC(s,l) _RAC(s,l)
-
-#endif // FSGR_STRICT_DEBUG==1
-
-// general defines -----------------------------------------------------------------------------------------------
-
-// replace TESTFLAG
-#define FLAGISEXACT(flag, compflag) ((flag & compflag)==compflag)
-
-#if LBMDIM==2
-#define dC 0
-#define dN 1
-#define dS 2
-#define dE 3
-#define dW 4
-#define dNE 5
-#define dNW 6
-#define dSE 7
-#define dSW 8
-#else
-// direction indices
-#define dC 0
-#define dN 1
-#define dS 2
-#define dE 3
-#define dW 4
-#define dT 5
-#define dB 6
-#define dNE 7
-#define dNW 8
-#define dSE 9
-#define dSW 10
-#define dNT 11
-#define dNB 12
-#define dST 13
-#define dSB 14
-#define dET 15
-#define dEB 16
-#define dWT 17
-#define dWB 18
-#endif
-//? #define dWB 18
-
-// default init for dFlux values
-#define FLUX_INIT 0.5f * (float)(this->cDfNum)
-
-// only for non DF dir handling!
-#define dNET 19
-#define dNWT 20
-#define dSET 21
-#define dSWT 22
-#define dNEB 23
-#define dNWB 24
-#define dSEB 25
-#define dSWB 26
-
-//! fill value for boundary cells
-#define BND_FILL 0.0
-
-#define DFL1 (1.0/ 3.0)
-#define DFL2 (1.0/18.0)
-#define DFL3 (1.0/36.0)
-
-// loops over _all_ cells (including boundary layer)
-#define FSGR_FORIJK_BOUNDS(leveli) \
- for(int k= getForZMinBnd(); k< getForZMaxBnd(leveli); ++k) \
- for(int j=0;j<mLevel[leveli].lSizey-0;++j) \
- for(int i=0;i<mLevel[leveli].lSizex-0;++i) \
-
-// loops over _only inner_ cells
-#define FSGR_FORIJK1(leveli) \
- for(int k= getForZMin1(); k< getForZMax1(leveli); ++k) \
- for(int j=1;j<mLevel[leveli].lSizey-1;++j) \
- for(int i=1;i<mLevel[leveli].lSizex-1;++i) \
-
-// relaxation_macros end
-
-
-
-/******************************************************************************/
-/*! equilibrium functions */
-/******************************************************************************/
-
-/*! calculate length of velocity vector */
-inline LbmFloat LbmFsgrSolver::getVelVecLen(int l, LbmFloat ux,LbmFloat uy,LbmFloat uz) {
- return ((ux)*dfDvecX[l]+(uy)*dfDvecY[l]+(uz)*dfDvecZ[l]);
-};
-
-/*! calculate equilibrium DF for given values */
-inline LbmFloat LbmFsgrSolver::getCollideEq(int l, LbmFloat rho, LbmFloat ux, LbmFloat uy, LbmFloat uz) {
-#if FSGR_STRICT_DEBUG==1
- if((l<0)||(l>LBM_DFNUM)) { errFatal("LbmFsgrSolver::getCollideEq","Invalid DFEQ call "<<l, SIMWORLD_PANIC ); /* no access to mPanic here */ }
-#endif // FSGR_STRICT_DEBUG==1
- LbmFloat tmp = getVelVecLen(l,ux,uy,uz);
- return( dfLength[l] *(
- + rho - (3.0/2.0*(ux*ux + uy*uy + uz*uz))
- + 3.0 *tmp
- + 9.0/2.0 *(tmp*tmp) )
- ); // */
-};
-
-/*****************************************************************************/
-/* init a given cell with flag, density, mass and equilibrium dist. funcs */
-
-void LbmFsgrSolver::forceChangeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag) {
- // also overwrite persisting flags
- // function is useful for tracking accesses...
- RFLAG(level,xx,yy,zz,set) = newflag;
-}
-void LbmFsgrSolver::changeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag) {
- CellFlagType pers = RFLAG(level,xx,yy,zz,set) & CFPersistMask;
- RFLAG(level,xx,yy,zz,set) = newflag | pers;
-}
-
-void
-LbmFsgrSolver::initEmptyCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass) {
- /* init eq. dist funcs */
- LbmFloat *ecel;
- int workSet = mLevel[level].setCurr;
-
- ecel = RACPNT(level, i,j,k, workSet);
- FORDF0 { RAC(ecel, l) = this->dfEquil[l] * rho; }
- RAC(ecel, dMass) = mass;
- RAC(ecel, dFfrac) = mass/rho;
- RAC(ecel, dFlux) = FLUX_INIT;
- changeFlag(level, i,j,k, workSet, flag);
-
- workSet ^= 1;
- changeFlag(level, i,j,k, workSet, flag);
- return;
-}
-
-void
-LbmFsgrSolver::initVelocityCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass, LbmVec vel) {
- LbmFloat *ecel;
- int workSet = mLevel[level].setCurr;
-
- ecel = RACPNT(level, i,j,k, workSet);
- FORDF0 { RAC(ecel, l) = getCollideEq(l, rho,vel[0],vel[1],vel[2]); }
- RAC(ecel, dMass) = mass;
- RAC(ecel, dFfrac) = mass/rho;
- RAC(ecel, dFlux) = FLUX_INIT;
- changeFlag(level, i,j,k, workSet, flag);
-
- workSet ^= 1;
- changeFlag(level, i,j,k, workSet, flag);
- return;
-}
-
-int LbmFsgrSolver::getForZMinBnd() {
- return 0;
-}
-int LbmFsgrSolver::getForZMin1() {
- if(LBMDIM==2) return 0;
- return 1;
-}
-
-int LbmFsgrSolver::getForZMaxBnd(int lev) {
- if(LBMDIM==2) return 1;
- return mLevel[lev].lSizez -0;
-}
-int LbmFsgrSolver::getForZMax1(int lev) {
- if(LBMDIM==2) return 1;
- return mLevel[lev].lSizez -1;
-}
-
-bool LbmFsgrSolver::checkDomainBounds(int lev,int i,int j,int k) {
- if(i<0) return false;
- if(j<0) return false;
- if(k<0) return false;
- if(i>mLevel[lev].lSizex-1) return false;
- if(j>mLevel[lev].lSizey-1) return false;
- if(k>mLevel[lev].lSizez-1) return false;
- return true;
-}
-bool LbmFsgrSolver::checkDomainBoundsPos(int lev,LbmVec pos) {
- const int i= (int)pos[0];
- if(i<0) return false;
- if(i>mLevel[lev].lSizex-1) return false;
- const int j= (int)pos[1];
- if(j<0) return false;
- if(j>mLevel[lev].lSizey-1) return false;
- const int k= (int)pos[2];
- if(k<0) return false;
- if(k>mLevel[lev].lSizez-1) return false;
- return true;
-}
-
-void LbmFsgrSolver::initInterfaceVars(int level, int i,int j,int k,int workSet, bool initMass) {
- LbmFloat *ccel = &QCELL(level ,i,j,k, workSet,0);
- LbmFloat nrho = 0.0;
- FORDF0 { nrho += RAC(ccel,l); }
- if(initMass) {
- RAC(ccel,dMass) = nrho;
- RAC(ccel, dFfrac) = 1.;
- } else {
- // preinited, e.g. from reinitFlags
- RAC(ccel, dFfrac) = RAC(ccel, dMass)/nrho;
- RAC(ccel, dFlux) = FLUX_INIT;
- }
-}
-
-
-#endif
-
-
diff --git a/intern/elbeem/intern/solver_control.cpp b/intern/elbeem/intern/solver_control.cpp
deleted file mode 100644
index 7064dba8e22..00000000000
--- a/intern/elbeem/intern/solver_control.cpp
+++ /dev/null
@@ -1,876 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - the visual lattice boltzmann freesurface simulator
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- *
- * Copyright 2003-2008 Nils Thuerey
- *
- * control extensions
- *
- *****************************************************************************/
-#include "solver_class.h"
-#include "solver_relax.h"
-#include "particletracer.h"
-
-#include "solver_control.h"
-
-#include "controlparticles.h"
-
-#include "elbeem.h"
-
-#include "ntl_geometrymodel.h"
-
-/******************************************************************************
- * LbmControlData control set
- *****************************************************************************/
-
-LbmControlSet::LbmControlSet() :
- mCparts(NULL), mCpmotion(NULL), mContrPartFile(""), mCpmotionFile(""),
- mcForceAtt(0.), mcForceVel(0.), mcForceMaxd(0.),
- mcRadiusAtt(0.), mcRadiusVel(0.), mcRadiusMind(0.), mcRadiusMaxd(0.),
- mcCpScale(1.), mcCpOffset(0.)
-{
-}
-LbmControlSet::~LbmControlSet() {
- if(mCparts) delete mCparts;
- if(mCpmotion) delete mCpmotion;
-}
-void LbmControlSet::initCparts() {
- mCparts = new ControlParticles();
- mCpmotion = new ControlParticles();
-}
-
-
-
-/******************************************************************************
- * LbmControlData control
- *****************************************************************************/
-
-LbmControlData::LbmControlData() :
- mSetForceStrength(0.),
- mCons(),
- mCpUpdateInterval(8), // DG: was 16 --> causes problems (big sphere after some time), unstable
- mCpOutfile(""),
- mCpForces(), mCpKernel(), mMdKernel(),
- mDiffVelCon(1.),
- mDebugCpscale(0.),
- mDebugVelScale(0.),
- mDebugCompavScale(0.),
- mDebugAttScale(0.),
- mDebugMaxdScale(0.),
- mDebugAvgVelScale(0.)
-{
-}
-
-LbmControlData::~LbmControlData()
-{
- while (!mCons.empty()) {
- delete mCons.back(); mCons.pop_back();
- }
-}
-
-
-void LbmControlData::parseControldataAttrList(AttributeList *attr) {
- // controlpart vars
- mSetForceStrength = attr->readFloat("tforcestrength", mSetForceStrength,"LbmControlData", "mSetForceStrength", false);
- //errMsg("tforcestrength set to "," "<<mSetForceStrength);
- mCpUpdateInterval = attr->readInt("controlparticle_updateinterval", mCpUpdateInterval,"LbmControlData","mCpUpdateInterval", false);
- // tracer output file
- mCpOutfile = attr->readString("controlparticle_outfile",mCpOutfile,"LbmControlData","mCpOutfile", false);
- if(getenv("ELBEEM_CPOUTFILE")) {
- string outfile(getenv("ELBEEM_CPOUTFILE"));
- mCpOutfile = outfile;
- debMsgStd("LbmControlData::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_CPOUTFILE to set mCpOutfile to "<<outfile<<","<<mCpOutfile,7);
- }
-
- for(int cpii=0; cpii<10; cpii++) {
- string suffix("");
- //if(cpii>0)
- { suffix = string("0"); suffix[0]+=cpii; }
- LbmControlSet *cset;
- cset = new LbmControlSet();
- cset->initCparts();
-
- cset->mContrPartFile = attr->readString("controlparticle"+suffix+"_file",cset->mContrPartFile,"LbmControlData","cset->mContrPartFile", false);
- if((cpii==0) && (getenv("ELBEEM_CPINFILE")) ) {
- string infile(getenv("ELBEEM_CPINFILE"));
- cset->mContrPartFile = infile;
- debMsgStd("LbmControlData::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_CPINFILE to set mContrPartFile to "<<infile<<","<<cset->mContrPartFile,7);
- }
-
- LbmFloat cpvort=0.;
- cset->mcRadiusAtt = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusatt", 0., "LbmControlData","mcRadiusAtt" );
- cset->mcRadiusVel = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusvel", 0., "LbmControlData","mcRadiusVel" );
- cset->mcRadiusVel = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusvel", 0., "LbmControlData","mcRadiusVel" );
- cset->mCparts->setRadiusAtt(cset->mcRadiusAtt.get(0.));
- cset->mCparts->setRadiusVel(cset->mcRadiusVel.get(0.));
-
- // WARNING currently only for first set
- //if(cpii==0) {
- cset->mcForceAtt = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_attraction", 0. , "LbmControlData","cset->mcForceAtt", false);
- cset->mcForceVel = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_velocity", 0. , "LbmControlData","mcForceVel", false);
- cset->mcForceMaxd = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_maxdist", 0. , "LbmControlData","mcForceMaxd", false);
- cset->mCparts->setInfluenceAttraction(cset->mcForceAtt.get(0.) );
- // warning - stores temprorarily, value converted to dt dep. factor
- cset->mCparts->setInfluenceVelocity(cset->mcForceVel.get(0.) , 0.01 ); // dummy dt
- cset->mCparts->setInfluenceMaxdist(cset->mcForceMaxd.get(0.) );
- cpvort = attr->readFloat("controlparticle"+suffix+"_vorticity", cpvort, "LbmControlData","cpvort", false);
- cset->mCparts->setInfluenceTangential(cpvort);
-
- cset->mcRadiusMind = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusmin", cset->mcRadiusMind.get(0.), "LbmControlData","mcRadiusMind", false);
- cset->mcRadiusMaxd = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusmax", cset->mcRadiusMind.get(0.), "LbmControlData","mcRadiusMaxd", false);
- cset->mCparts->setRadiusMinMaxd(cset->mcRadiusMind.get(0.));
- cset->mCparts->setRadiusMaxd(cset->mcRadiusMaxd.get(0.));
- //}
-
- // now local...
- //LbmVec cpOffset(0.), cpScale(1.);
- LbmFloat cpTimescale = 1.;
- string cpMirroring("");
-
- //cset->mcCpOffset = attr->readChannelVec3f("controlparticle"+suffix+"_offset", ntlVec3f(0.),"LbmControlData","mcCpOffset", false);
- //cset->mcCpScale = attr->readChannelVec3f("controlparticle"+suffix+"_scale", ntlVec3f(1.), "LbmControlData","mcCpScale", false);
- cset->mcCpOffset = attr->readChannelVec3f("controlparticle"+suffix+"_offset", ntlVec3f(0.),"LbmControlData","mcCpOffset", false);
- cset->mcCpScale = attr->readChannelVec3f("controlparticle"+suffix+"_scale", ntlVec3f(1.), "LbmControlData","mcCpScale", false);
- cpTimescale = attr->readFloat("controlparticle"+suffix+"_timescale", cpTimescale, "LbmControlData","cpTimescale", false);
- cpMirroring = attr->readString("controlparticle"+suffix+"_mirror", cpMirroring, "LbmControlData","cpMirroring", false);
-
- LbmFloat cpsWidth = cset->mCparts->getCPSWith();
- cpsWidth = attr->readFloat("controlparticle"+suffix+"_cpswidth", cpsWidth, "LbmControlData","cpsWidth", false);
- LbmFloat cpsDt = cset->mCparts->getCPSTimestep();
- cpsDt = attr->readFloat("controlparticle"+suffix+"_cpstimestep", cpsDt, "LbmControlData","cpsDt", false);
- LbmFloat cpsTstart = cset->mCparts->getCPSTimeStart();
- cpsTstart = attr->readFloat("controlparticle"+suffix+"_cpststart", cpsTstart, "LbmControlData","cpsTstart", false);
- LbmFloat cpsTend = cset->mCparts->getCPSTimeEnd();
- cpsTend = attr->readFloat("controlparticle"+suffix+"_cpstend", cpsTend, "LbmControlData","cpsTend", false);
- LbmFloat cpsMvmfac = cset->mCparts->getCPSMvmWeightFac();
- cpsMvmfac = attr->readFloat("controlparticle"+suffix+"_cpsmvmfac", cpsMvmfac, "LbmControlData","cpsMvmfac", false);
- cset->mCparts->setCPSWith(cpsWidth);
- cset->mCparts->setCPSTimestep(cpsDt);
- cset->mCparts->setCPSTimeStart(cpsTstart);
- cset->mCparts->setCPSTimeEnd(cpsTend);
- cset->mCparts->setCPSMvmWeightFac(cpsMvmfac);
-
- cset->mCparts->setOffset( vec2L(cset->mcCpOffset.get(0.)) );
- cset->mCparts->setScale( vec2L(cset->mcCpScale.get(0.)) );
- cset->mCparts->setInitTimeScale( cpTimescale );
- cset->mCparts->setInitMirror( cpMirroring );
-
- int mDebugInit = 0;
- mDebugInit = attr->readInt("controlparticle"+suffix+"_debuginit", mDebugInit,"LbmControlData","mDebugInit", false);
- cset->mCparts->setDebugInit(mDebugInit);
-
- // motion particle settings
- LbmVec mcpOffset(0.), mcpScale(1.);
- LbmFloat mcpTimescale = 1.;
- string mcpMirroring("");
-
- cset->mCpmotionFile = attr->readString("cpmotion"+suffix+"_file",cset->mCpmotionFile,"LbmControlData","mCpmotionFile", false);
- mcpTimescale = attr->readFloat("cpmotion"+suffix+"_timescale", mcpTimescale, "LbmControlData","mcpTimescale", false);
- mcpMirroring = attr->readString("cpmotion"+suffix+"_mirror", mcpMirroring, "LbmControlData","mcpMirroring", false);
- mcpOffset = vec2L( attr->readVec3d("cpmotion"+suffix+"_offset", vec2P(mcpOffset),"LbmControlData","cpOffset", false) );
- mcpScale = vec2L( attr->readVec3d("cpmotion"+suffix+"_scale", vec2P(mcpScale), "LbmControlData","cpScale", false) );
-
- cset->mCpmotion->setOffset( vec2L(mcpOffset) );
- cset->mCpmotion->setScale( vec2L(mcpScale) );
- cset->mCpmotion->setInitTimeScale( mcpTimescale );
- cset->mCpmotion->setInitMirror( mcpMirroring );
-
- if(cset->mContrPartFile.length()>1) {
- errMsg("LbmControlData","Using control particle set "<<cpii<<" file:"<<cset->mContrPartFile<<" cpmfile:"<<cset->mCpmotionFile<<" mirr:'"<<cset->mCpmotion->getInitMirror()<<"' " );
- mCons.push_back( cset );
- } else {
- delete cset;
- }
- }
-
- // debug, testing - make sure theres at least an empty set
- if(mCons.size()<1) {
- mCons.push_back( new LbmControlSet() );
- mCons[0]->initCparts();
- }
-
- // take from first set
- for(int cpii=1; cpii<(int)mCons.size(); cpii++) {
- mCons[cpii]->mCparts->setRadiusMinMaxd( mCons[0]->mCparts->getRadiusMinMaxd() );
- mCons[cpii]->mCparts->setRadiusMaxd( mCons[0]->mCparts->getRadiusMaxd() );
- mCons[cpii]->mCparts->setInfluenceAttraction( mCons[0]->mCparts->getInfluenceAttraction() );
- mCons[cpii]->mCparts->setInfluenceTangential( mCons[0]->mCparts->getInfluenceTangential() );
- mCons[cpii]->mCparts->setInfluenceVelocity( mCons[0]->mCparts->getInfluenceVelocity() , 0.01 ); // dummy dt
- mCons[cpii]->mCparts->setInfluenceMaxdist( mCons[0]->mCparts->getInfluenceMaxdist() );
- }
-
- // invert for usage in relax macro
- mDiffVelCon = 1.-attr->readFloat("cpdiffvelcon", mDiffVelCon, "LbmControlData","mDiffVelCon", false);
-
- mDebugCpscale = attr->readFloat("cpdebug_cpscale", mDebugCpscale, "LbmControlData","mDebugCpscale", false);
- mDebugMaxdScale = attr->readFloat("cpdebug_maxdscale", mDebugMaxdScale, "LbmControlData","mDebugMaxdScale", false);
- mDebugAttScale = attr->readFloat("cpdebug_attscale", mDebugAttScale, "LbmControlData","mDebugAttScale", false);
- mDebugVelScale = attr->readFloat("cpdebug_velscale", mDebugVelScale, "LbmControlData","mDebugVelScale", false);
- mDebugCompavScale = attr->readFloat("cpdebug_compavscale", mDebugCompavScale, "LbmControlData","mDebugCompavScale", false);
- mDebugAvgVelScale = attr->readFloat("cpdebug_avgvelsc", mDebugAvgVelScale, "LbmControlData","mDebugAvgVelScale", false);
-}
-
-
-void
-LbmFsgrSolver::initCpdata()
-{
- // enable for cps via env. vars
- //if( (getenv("ELBEEM_CPINFILE")) || (getenv("ELBEEM_CPOUTFILE")) ){ mUseTestdata=1; }
-
-
- // manually switch on! if this is zero, nothing is done...
- mpControl->mSetForceStrength = this->mTForceStrength = 1.;
- while (!mpControl->mCons.empty()) {
- delete mpControl->mCons.back(); mpControl->mCons.pop_back();
- }
-
-
- // init all control fluid objects
- int numobjs = (int)(mpGiObjects->size());
- for(int o=0; o<numobjs; o++) {
- ntlGeometryObjModel *obj = (ntlGeometryObjModel *)(*mpGiObjects)[o];
- if(obj->getGeoInitType() & FGI_CONTROL) {
- // add new control set per object
- LbmControlSet *cset;
-
- cset = new LbmControlSet();
- cset->initCparts();
-
- // dont load any file
- cset->mContrPartFile = string("");
-
- cset->mcForceAtt = obj->getCpsAttrFStr();
- cset->mcRadiusAtt = obj->getCpsAttrFRad();
- cset->mcForceVel = obj->getCpsVelFStr();
- cset->mcRadiusVel = obj->getCpsVelFRad();
-
- cset->mCparts->setCPSTimeStart(obj->getCpsTimeStart());
- cset->mCparts->setCPSTimeEnd(obj->getCpsTimeEnd());
-
- if(obj->getCpsQuality() > LBM_EPSILON)
- cset->mCparts->setCPSWith(1.0 / obj->getCpsQuality());
-
- // this value can be left at 0.5:
- cset->mCparts->setCPSMvmWeightFac(0.5);
-
- mpControl->mCons.push_back( cset );
- mpControl->mCons[mpControl->mCons.size()-1]->mCparts->initFromObject(obj);
- }
- }
-
- // NT blender integration manual test setup
- if(0) {
- // manually switch on! if this is zero, nothing is done...
- mpControl->mSetForceStrength = this->mTForceStrength = 1.;
- while (!mpControl->mCons.empty()) {
- delete mpControl->mCons.back(); mpControl->mCons.pop_back();
- }
-
- // add new set
- LbmControlSet *cset;
-
- cset = new LbmControlSet();
- cset->initCparts();
- // dont load any file
- cset->mContrPartFile = string("");
-
- // set radii for attraction & velocity forces
- // set strength of the forces
- // don't set directly! but use channels:
- // mcForceAtt, mcForceVel, mcForceMaxd, mcRadiusAtt, mcRadiusVel, mcRadiusMind, mcRadiusMaxd etc.
-
- // wrong: cset->mCparts->setInfluenceAttraction(1.15); cset->mCparts->setRadiusAtt(1.5);
- // right, e.g., to init some constant values:
- cset->mcForceAtt = AnimChannel<float>(0.2);
- cset->mcRadiusAtt = AnimChannel<float>(0.75);
- cset->mcForceVel = AnimChannel<float>(0.2);
- cset->mcRadiusVel = AnimChannel<float>(0.75);
-
- // this value can be left at 0.5:
- cset->mCparts->setCPSMvmWeightFac(0.5);
-
- mpControl->mCons.push_back( cset );
-
- // instead of reading from file (cset->mContrPartFile), manually init some particles
- mpControl->mCons[0]->mCparts->initBlenderTest();
-
- // other values that might be interesting to change:
- //cset->mCparts->setCPSTimestep(0.02);
- //cset->mCparts->setCPSTimeStart(0.);
- //cset->mCparts->setCPSTimeEnd(1.);
-
- //mpControl->mDiffVelCon = 1.; // more rigid velocity control, 0 (default) allows more turbulence
- }
-
- // control particle -------------------------------------------------------------------------------------
-
- // init cppf stage, use set 0!
- if(mCppfStage>0) {
- if(mpControl->mCpOutfile.length()<1) mpControl->mCpOutfile = string("cpout"); // use getOutFilename !?
- char strbuf[100];
- const char *cpFormat = "_d%dcppf%d";
-
- // initial coarse stage, no input
- if(mCppfStage==1) {
- mpControl->mCons[0]->mContrPartFile = "";
- } else {
- // read from prev stage
- snprintf(strbuf,100, cpFormat ,LBMDIM,mCppfStage-1);
- mpControl->mCons[0]->mContrPartFile = mpControl->mCpOutfile;
- mpControl->mCons[0]->mContrPartFile += strbuf;
- mpControl->mCons[0]->mContrPartFile += ".cpart2";
- }
-
- snprintf(strbuf,100, cpFormat ,LBMDIM,mCppfStage);
- mpControl->mCpOutfile += strbuf;
- } // */
-
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
- ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
-
- // now set with real dt
- cparts->setInfluenceVelocity( mpControl->mCons[cpssi]->mcForceVel.get(0.), mLevel[mMaxRefine].timestep);
- cparts->setCharLength( mLevel[mMaxRefine].nodeSize );
- cparts->setCharLength( mLevel[mMaxRefine].nodeSize );
- errMsg("LbmControlData","CppfStage "<<mCppfStage<<" in:"<<mpControl->mCons[cpssi]->mContrPartFile<<
- " out:"<<mpControl->mCpOutfile<<" cl:"<< cparts->getCharLength() );
-
- // control particle test init
- if(mpControl->mCons[cpssi]->mCpmotionFile.length()>=1) cpmotion->initFromTextFile(mpControl->mCons[cpssi]->mCpmotionFile);
- // not really necessary...
- //? cparts->setFluidSpacing( mLevel[mMaxRefine].nodeSize ); // use grid coords!?
- //? cparts->calculateKernelWeight();
- //? debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - motion inited: "<<cparts->getSize() ,10);
-
- // ensure both are on for env. var settings
- // when no particles, but outfile enabled, initialize
- const int lev = mMaxRefine;
- if((mpParticles) && (mpControl->mCpOutfile.length()>=1) && (cpssi==0)) {
- // check if auto num
- if( (mpParticles->getNumInitialParticles()<=1) &&
- (mpParticles->getNumParticles()<=1) ) { // initParticles done afterwards anyway
- int tracers = 0;
- const int workSet = mLevel[lev].setCurr;
- FSGR_FORIJK_BOUNDS(lev) {
- if(RFLAG(lev,i,j,k, workSet)&(CFFluid)) tracers++;
- }
- if(LBMDIM==3) tracers /= 8;
- else tracers /= 4;
- mpParticles->setNumInitialParticles(tracers);
- mpParticles->setDumpTextFile(mpControl->mCpOutfile);
- debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - set tracers #"<<tracers<<", actual #"<<mpParticles->getNumParticles() ,10);
- }
- if(mpParticles->getDumpTextInterval()<=0.) {
- mpParticles->setDumpTextInterval(mLevel[lev].timestep * mLevel[lev].lSizex);
- debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - dump delta t not set, using dti="<< mpParticles->getDumpTextInterval()<<", sim dt="<<mLevel[lev].timestep, 5 );
- }
- mpParticles->setDumpParts(true); // DEBUG? also dump as particle system
- }
-
- if(mpControl->mCons[cpssi]->mContrPartFile.length()>=1) cparts->initFromTextFile(mpControl->mCons[cpssi]->mContrPartFile);
- cparts->setFluidSpacing( mLevel[lev].nodeSize ); // use grid coords!?
- cparts->calculateKernelWeight();
- debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles mCons"<<cpssi<<" - inited, parts:"<<cparts->getTotalSize()<<","<<cparts->getSize()<<" dt:"<<mpParam->getTimestep()<<" control time:"<<cparts->getControlTimStart()<<" to "<<cparts->getControlTimEnd() ,10);
- } // cpssi
-
- if(getenv("ELBEEM_CPINFILE")) {
- this->mTForceStrength = 1.0;
- }
- this->mTForceStrength = mpControl->mSetForceStrength;
- if(mpControl->mCpOutfile.length()>=1) mpParticles->setDumpTextFile(mpControl->mCpOutfile);
-
- // control particle init end -------------------------------------------------------------------------------------
-
- // make sure equiv to solver init
- if(this->mTForceStrength>0.) { \
- mpControl->mCpForces.resize( mMaxRefine+1 );
- for(int lev = 0; lev<=mMaxRefine; lev++) {
- LONGINT rcellSize = (mLevel[lev].lSizex*mLevel[lev].lSizey*mLevel[lev].lSizez);
- debMsgStd("LbmFsgrSolver::initControl",DM_MSG,"mCpForces init, lev="<<lev<<" rcs:"<<(int)(rcellSize+4)<<","<<(rcellSize*sizeof(ControlForces)/(1024*1024)), 9 );
- mpControl->mCpForces[lev].resize( (int)(rcellSize+4) );
- //for(int i=0 ;i<rcellSize; i++) mpControl->mCpForces.push_back( ControlForces() );
- for(int i=0 ;i<rcellSize; i++) mpControl->mCpForces[lev][i].resetForces();
- }
- } // on?
-
- debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles #mCons "<<mpControl->mCons.size()<<" done", 6);
-}
-
-
-#define CPODEBUG 0
-//define CPINTER ((int)(mpControl->mCpUpdateInterval))
-
-#define KERN(x,y,z) mpControl->mCpKernel[ (((z)*cpkarWidth + (y))*cpkarWidth + (x)) ]
-#define MDKERN(x,y,z) mpControl->mMdKernel[ (((z)*mdkarWidth + (y))*mdkarWidth + (x)) ]
-
-#define BOUNDCHECK(x,low,high) ( ((x)<low) ? low : (((x)>high) ? high : (x) ) )
-#define BOUNDSKIP(x,low,high) ( ((x)<low) || ((x)>high) )
-
-void
-LbmFsgrSolver::handleCpdata()
-{
- myTime_t cpstart = getTime();
- int cpChecks=0;
- int cpInfs=0;
- //debMsgStd("ControlData::handleCpdata",DM_MSG,"called... "<<this->mTForceStrength,1);
-
- // add cp influence
- if((true) && (this->mTForceStrength>0.)) {
- // ok continue...
- } // on off
- else {
- return;
- }
-
- // check if we have control objects
- if(mpControl->mCons.size()==0)
- return;
-
- if((mpControl->mCpUpdateInterval<1) || (this->mStepCnt%mpControl->mCpUpdateInterval==0)) {
- // do full reinit later on...
- }
- else if(this->mStepCnt>mpControl->mCpUpdateInterval) {
- // only reinit new cells
- // TODO !? remove loop dependance!?
-#define NOFORCEENTRY(lev, i,j,k) (LBMGET_FORCE(lev, i,j,k).maxDistance==CPF_MAXDINIT)
- // interpolate missing
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- if( (RFLAG(lev,i,j,k, mLevel[lev].setCurr)) & (CFFluid|CFInter) )
- //if( (RFLAG(lev,i,j,k, mLevel[lev].setCurr)) & (CFInter) )
- //if(0)
- { // only check new inter? RFLAG?check
- if(NOFORCEENTRY(lev, i,j,k)) {
- //errMsg("CP","FE_MISSING at "<<PRINT_IJK<<" f"<<LBMGET_FORCE(lev, i,j,k).weightAtt<<" md"<<LBMGET_FORCE(lev, i,j,k).maxDistance );
-
- LbmFloat nbs=0.;
- ControlForces vals;
- vals.resetForces(); vals.maxDistance = 0.;
- for(int l=1; l<this->cDirNum; l++) {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- //errMsg("CP","FE_MISSING check "<<PRINT_VEC(ni,nj,nk)<<" f"<<LBMGET_FORCE(lev, ni,nj,nk).weightAtt<<" md"<<LBMGET_FORCE(lev, ni,nj,nk).maxDistance );
- if(!NOFORCEENTRY(lev, ni,nj,nk)) {
- //? vals.weightAtt += LBMGET_FORCE(lev, ni,nj,nk).weightAtt;
- //? vals.forceAtt += LBMGET_FORCE(lev, ni,nj,nk).forceAtt;
- vals.maxDistance += LBMGET_FORCE(lev, ni,nj,nk).maxDistance;
- vals.forceMaxd += LBMGET_FORCE(lev, ni,nj,nk).forceMaxd;
- vals.weightVel += LBMGET_FORCE(lev, ni,nj,nk).weightVel;
- vals.forceVel += LBMGET_FORCE(lev, ni,nj,nk).forceVel;
- // ignore att/compAv/avgVel here for now
- nbs += 1.;
- }
- }
- if(nbs>0.) {
- nbs = 1./nbs;
- //? LBMGET_FORCE(lev, i,j,k).weightAtt = vals.weightAtt*nbs;
- //? LBMGET_FORCE(lev, i,j,k).forceAtt = vals.forceAtt*nbs;
- LBMGET_FORCE(lev, i,j,k).maxDistance = vals.maxDistance*nbs;
- LBMGET_FORCE(lev, i,j,k).forceMaxd = vals.forceMaxd*nbs;
- LBMGET_FORCE(lev, i,j,k).weightVel = vals.weightVel*nbs;
- LBMGET_FORCE(lev, i,j,k).forceVel = vals.forceVel*nbs;
- }
- /*ControlForces *ff = &LBMGET_FORCE(lev, i,j,k); // DEBUG
- errMsg("CP","FE_MISSING rec at "<<PRINT_IJK // DEBUG
- <<" w:"<<ff->weightAtt<<" wa:" <<PRINT_VEC( ff->forceAtt[0],ff->forceAtt[1],ff->forceAtt[2] )
- <<" v:"<<ff->weightVel<<" wv:" <<PRINT_VEC( ff->forceVel[0],ff->forceVel[1],ff->forceVel[2] )
- <<" v:"<<ff->maxDistance<<" wv:" <<PRINT_VEC( ff->forceMaxd[0],ff->forceMaxd[1],ff->forceMaxd[2] ) ); // DEBUG */
- // else errMsg("CP","FE_MISSING rec at "<<PRINT_IJK<<" failed!"); // DEBUG
-
- }
- }
- }} // ijk, lev
-
- // mStepCnt > mpControl->mCpUpdateInterval
- return;
- } else {
- // nothing to do ...
- return;
- }
-
- // reset
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) { LBMGET_FORCE(lev,i,j,k).resetForces(); }
- }
- // do setup for coarsest level
- const int coarseLev = 0;
- const int fineLev = mMaxRefine;
-
- // init for current time
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
- LbmControlSet *cset = mpControl->mCons[cpssi];
-
- cparts->setRadiusAtt(cset->mcRadiusAtt.get(mSimulationTime));
- cparts->setRadiusVel(cset->mcRadiusVel.get(mSimulationTime));
- cparts->setInfluenceAttraction(cset->mcForceAtt.get(mSimulationTime) );
- cparts->setInfluenceMaxdist(cset->mcForceMaxd.get(mSimulationTime) );
- cparts->setRadiusMinMaxd(cset->mcRadiusMind.get(mSimulationTime));
- cparts->setRadiusMaxd(cset->mcRadiusMaxd.get(mSimulationTime));
- cparts->calculateKernelWeight(); // always necessary!?
- cparts->setOffset( vec2L(cset->mcCpOffset.get(mSimulationTime)) );
- cparts->setScale( vec2L(cset->mcCpScale.get(mSimulationTime)) );
-
- cparts->setInfluenceVelocity( cset->mcForceVel.get(mSimulationTime), mLevel[fineLev].timestep );
- cparts->setLastOffset( vec2L(cset->mcCpOffset.get(mSimulationTime-mLevel[fineLev].timestep)) );
- cparts->setLastScale( vec2L(cset->mcCpScale.get(mSimulationTime-mLevel[fineLev].timestep)) );
-
- }
-
- // check actual values
- LbmFloat iatt = ABS(mpControl->mCons[0]->mCparts->getInfluenceAttraction());
- LbmFloat ivel = mpControl->mCons[0]->mCparts->getInfluenceVelocity();
- LbmFloat imaxd = mpControl->mCons[0]->mCparts->getInfluenceMaxdist();
- //errMsg("FINCIT","iatt="<<iatt<<" ivel="<<ivel<<" imaxd="<<imaxd);
- for(int cpssi=1; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- LbmFloat iatt2 = ABS(mpControl->mCons[cpssi]->mCparts->getInfluenceAttraction());
- LbmFloat ivel2 = mpControl->mCons[cpssi]->mCparts->getInfluenceVelocity();
- LbmFloat imaxd2 = mpControl->mCons[cpssi]->mCparts->getInfluenceMaxdist();
-
- // we allow negative attraction force here!
- if(iatt2 > iatt) iatt = iatt2;
-
- if(ivel2 >ivel) ivel = ivel2;
- if(imaxd2>imaxd) imaxd= imaxd2;
- //errMsg("FINCIT"," "<<cpssi<<" iatt2="<<iatt2<<" ivel2="<<ivel2<<" imaxd2="<<imaxd<<" NEW "<<" iatt="<<iatt<<" ivel="<<ivel<<" imaxd="<<imaxd);
- }
-
- if(iatt==0. && ivel==0. && imaxd==0.) {
- debMsgStd("ControlData::initControl",DM_MSG,"Skipped, all zero...",4);
- return;
- }
- //iatt = mpControl->mCons[1]->mCparts->getInfluenceAttraction(); //ivel = mpControl->mCons[1]->mCparts->getInfluenceVelocity(); //imaxd = mpControl->mCons[1]->mCparts->getInfluenceMaxdist(); // TTTTTT
-
- // do control setup
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
- ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
-
- // TEST!?
- bool radmod = false;
- const LbmFloat minRadSize = mLevel[coarseLev].nodeSize * 1.5;
- if((cparts->getRadiusAtt()>0.) && (cparts->getRadiusAtt()<minRadSize) && (!radmod) ) {
- LbmFloat radfac = minRadSize / cparts->getRadiusAtt(); radmod=true;
- debMsgStd("ControlData::initControl",DM_MSG,"Modified radii att, fac="<<radfac, 7);
- cparts->setRadiusAtt(cparts->getRadiusAtt()*radfac);
- cparts->setRadiusVel(cparts->getRadiusVel()*radfac);
- cparts->setRadiusMaxd(cparts->getRadiusMaxd()*radfac);
- cparts->setRadiusMinMaxd(cparts->getRadiusMinMaxd()*radfac);
- } else if((cparts->getRadiusVel()>0.) && (cparts->getRadiusVel()<minRadSize) && (!radmod) ) {
- LbmFloat radfac = minRadSize / cparts->getRadiusVel();
- debMsgStd("ControlData::initControl",DM_MSG,"Modified radii vel, fac="<<radfac, 7);
- cparts->setRadiusVel(cparts->getRadiusVel()*radfac);
- cparts->setRadiusMaxd(cparts->getRadiusMaxd()*radfac);
- cparts->setRadiusMinMaxd(cparts->getRadiusMinMaxd()*radfac);
- } else if((cparts->getRadiusMaxd()>0.) && (cparts->getRadiusMaxd()<minRadSize) && (!radmod) ) {
- LbmFloat radfac = minRadSize / cparts->getRadiusMaxd();
- debMsgStd("ControlData::initControl",DM_MSG,"Modified radii maxd, fac="<<radfac, 7);
- cparts->setRadiusMaxd(cparts->getRadiusMaxd()*radfac);
- cparts->setRadiusMinMaxd(cparts->getRadiusMinMaxd()*radfac);
- }
- if(radmod) {
- debMsgStd("ControlData::initControl",DM_MSG,"Modified radii: att="<<
- cparts->getRadiusAtt()<<", vel=" << cparts->getRadiusVel()<<", maxd=" <<
- cparts->getRadiusMaxd()<<", mind=" << cparts->getRadiusMinMaxd() ,5);
- }
-
- cpmotion->prepareControl( mSimulationTime+((LbmFloat)mpControl->mCpUpdateInterval)*(mpParam->getTimestep()), mpParam->getTimestep(), NULL );
- cparts->prepareControl( mSimulationTime+((LbmFloat)mpControl->mCpUpdateInterval)*(mpParam->getTimestep()), mpParam->getTimestep(), cpmotion );
- }
-
- // do control...
- for(int lev=0; lev<=mMaxRefine; lev++) {
- LbmFloat levVolume = 1.;
- LbmFloat levForceScale = 1.;
- for(int ll=lev; ll<mMaxRefine; ll++) {
- if(LBMDIM==3) levVolume *= 8.;
- else levVolume *= 4.;
- levForceScale *= 2.;
- }
- errMsg("LbmFsgrSolver::handleCpdata","levVolume="<<levVolume<<" levForceScale="<<levForceScale );
- //todo: scale velocity, att by level timestep!?
-
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
- // ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
-
- // if control set is not active skip it
- if((cparts->getControlTimStart() > mSimulationTime) || (cparts->getControlTimEnd() < mLastSimTime))
- {
- continue;
- }
-
- const LbmFloat velLatticeScale = mLevel[lev].timestep/mLevel[lev].nodeSize;
- LbmFloat gsx = ((mvGeoEnd[0]-mvGeoStart[0])/(LbmFloat)mLevel[lev].lSizex);
- LbmFloat gsy = ((mvGeoEnd[1]-mvGeoStart[1])/(LbmFloat)mLevel[lev].lSizey);
- LbmFloat gsz = ((mvGeoEnd[2]-mvGeoStart[2])/(LbmFloat)mLevel[lev].lSizez);
-#if LBMDIM==2
- gsz = gsx;
-#endif
- LbmFloat goffx = mvGeoStart[0];
- LbmFloat goffy = mvGeoStart[1];
- LbmFloat goffz = mvGeoStart[2];
-
- //const LbmFloat cpwIncFac = 2.0;
- // max to two thirds of domain size
- const int cpw = MIN( mLevel[lev].lSizex/3, MAX( (int)( cparts->getRadiusAtt() /gsx) +1 , 2) ); // normal kernel, att,vel
- const int cpkarWidth = 2*cpw+1;
- mpControl->mCpKernel.resize(cpkarWidth* cpkarWidth* cpkarWidth);
- ControlParticle cpt; cpt.reset();
- cpt.pos = LbmVec( (gsx*(LbmFloat)cpw)+goffx, (gsy*(LbmFloat)cpw)+goffy, (gsz*(LbmFloat)cpw)+goffz ); // optimize?
- cpt.density = 0.5; cpt.densityWeight = 0.5;
-#if LBMDIM==3
- for(int k= 0; k<cpkarWidth; ++k) {
-#else // LBMDIM==3
- { int k = cpw;
-#endif
- for(int j= 0; j<cpkarWidth; ++j)
- for(int i= 0; i<cpkarWidth; ++i) {
- KERN(i,j,k).resetForces();
- //LbmFloat dx = i-cpw; LbmFloat dy = j-cpw; LbmFloat dz = k-cpw;
- //LbmVec dv = ( LbmVec(dx,dy,dz) );
- //LbmFloat dl = norm( dv ); //LbmVec dir = dv / dl;
- LbmVec pos = LbmVec( (gsx*(LbmFloat)i)+goffx, (gsy*(LbmFloat)j)+goffy, (gsz*(LbmFloat)k)+goffz ); // optimize?
- cparts->calculateCpInfluenceOpt( &cpt, pos, LbmVec(0,0,0), &KERN(i,j,k) ,1. );
- /*if((CPODEBUG)&&(k==cpw)) errMsg("kern"," at "<<PRINT_IJK<<" pos"<<pos<<" cpp"<<cpt.pos
- <<" wf:"<<KERN(i,j,k).weightAtt<<" wa:"<< PRINT_VEC( KERN(i,j,k).forceAtt[0],KERN(i,j,k).forceAtt[1],KERN(i,j,k).forceAtt[2] )
- <<" wf:"<<KERN(i,j,k).weightVel<<" wa:"<< PRINT_VEC( KERN(i,j,k).forceVel[0],KERN(i,j,k).forceVel[1],KERN(i,j,k).forceVel[2] )
- <<" wf:"<<KERN(i,j,k).maxDistance<<" wa:"<< PRINT_VEC( KERN(i,j,k).forceMaxd[0],KERN(i,j,k).forceMaxd[1],KERN(i,j,k).forceMaxd[2] ) ); // */
- KERN(i,j,k).weightAtt *= 2.;
- KERN(i,j,k).forceAtt *= 2.;
- //KERN(i,j,k).forceAtt[1] *= 2.; KERN(i,j,k).forceAtt[2] *= 2.;
- KERN(i,j,k).weightVel *= 2.;
- KERN(i,j,k).forceVel *= 2.;
- //KERN(i,j,k).forceVel[1] *= 2.; KERN(i,j,k).forceVel[2] *= 2.;
- }
- }
-
- if(CPODEBUG) errMsg("cpw"," = "<<cpw<<" f"<< cparts->getRadiusAtt()<<" gsx"<<gsx<<" kpw"<<cpkarWidth); // DEBUG
- // first cp loop - add att and vel forces
- for(int cppi=0; cppi<cparts->getSize(); cppi++) {
- ControlParticle *cp = cparts->getParticle(cppi);
- if(cp->influence<=0.) continue;
- const int cpi = (int)( (cp->pos[0]-goffx)/gsx );
- const int cpj = (int)( (cp->pos[1]-goffy)/gsy );
- int cpk = (int)( (cp->pos[2]-goffz)/gsz );
- /*if( ((LBMDIM==3)&&(BOUNDSKIP(cpk - cpwsm, getForZMinBnd(), getForZMaxBnd(lev) ))) ||
- ((LBMDIM==3)&&(BOUNDSKIP(cpk + cpwsm, getForZMinBnd(), getForZMaxBnd(lev) ))) ||
- BOUNDSKIP(cpj - cpwsm, 0, mLevel[lev].lSizey ) ||
- BOUNDSKIP(cpj + cpwsm, 0, mLevel[lev].lSizey ) ||
- BOUNDSKIP(cpi - cpwsm, 0, mLevel[lev].lSizex ) ||
- BOUNDSKIP(cpi + cpwsm, 0, mLevel[lev].lSizex ) ) {
- continue;
- } // */
- int is,ie,js,je,ks,ke;
- ks = BOUNDCHECK(cpk - cpw, getForZMinBnd(), getForZMaxBnd(lev) );
- ke = BOUNDCHECK(cpk + cpw, getForZMinBnd(), getForZMaxBnd(lev) );
- js = BOUNDCHECK(cpj - cpw, 0, mLevel[lev].lSizey );
- je = BOUNDCHECK(cpj + cpw, 0, mLevel[lev].lSizey );
- is = BOUNDCHECK(cpi - cpw, 0, mLevel[lev].lSizex );
- ie = BOUNDCHECK(cpi + cpw, 0, mLevel[lev].lSizex );
- if(LBMDIM==2) { cpk = 0; ks = 0; ke = 1; }
- if(CPODEBUG) errMsg("cppft","i"<<cppi<<" cpw"<<cpw<<" gpos"<<PRINT_VEC(cpi,cpj,cpk)<<" i:"<<is<<","<<ie<<" j:"<<js<<","<<je<<" k:"<<ks<<","<<ke<<" "); // DEBUG
- cpInfs++;
-
- for(int k= ks; k<ke; ++k) {
- for(int j= js; j<je; ++j) {
-
- CellFlagType *pflag = &RFLAG(lev,is,j,k, mLevel[lev].setCurr);
- ControlForces *kk = &KERN( is-cpi+cpw, j-cpj+cpw, k-cpk+cpw);
- ControlForces *ff = &LBMGET_FORCE(lev,is,j,k);
- pflag--; kk--; ff--;
-
- for(int i= is; i<ie; ++i) {
- // first cp loop (att,vel)
- pflag++; kk++; ff++;
-
- //add weight for bnd cells
- const LbmFloat pwforce = kk->weightAtt;
- // control particle mod,
- // dont add multiple CFFluid fsgr boundaries
- if(lev==mMaxRefine) {
- //if( ( ((*pflag)&(CFFluid )) && (lev==mMaxRefine) ) ||
- //( ((*pflag)&(CFGrNorm)) && (lev <mMaxRefine) ) ) {
- if((*pflag)&(CFFluid|CFUnused)) {
- // check not fromcoarse?
- cp->density += levVolume* kk->weightAtt; // old CFFluid
- } else if( (*pflag) & (CFEmpty) ) {
- cp->density -= levVolume* 0.5;
- } else { //if( ((*pflag) & (CFBnd)) ) {
- cp->density -= levVolume* 0.2; // penalty
- }
- } else {
- //if((*pflag)&(CFGrNorm)) {
- //cp->density += levVolume* kk->weightAtt; // old CFFluid
- //}
- }
- //else if(!((*pflag) & (CFUnused)) ) { cp->density -= levVolume* 0.2; } // penalty
-
- if( (*pflag) & (CFFluid|CFInter) ) // RFLAG_check
- {
-
- cpChecks++;
- //const LbmFloat pwforce = kk->weightAtt;
- LbmFloat pwvel = kk->weightVel;
- if((pwforce==0.)&&(pwvel==0.)) { continue; }
- ff->weightAtt += 1e-6; // for distance
-
- if(pwforce>0.) {
- ff->weightAtt += pwforce *cp->densityWeight *cp->influence;
- ff->forceAtt += kk->forceAtt *levForceScale *cp->densityWeight *cp->influence;
-
- // old fill handling here
- const int workSet =mLevel[lev].setCurr;
- LbmFloat ux=0., uy=0., uz=0.;
- FORDF1{
- const LbmFloat dfn = QCELL(lev, i,j,k, workSet, l);
- ux += (this->dfDvecX[l]*dfn);
- uy += (this->dfDvecY[l]*dfn);
- uz += (this->dfDvecZ[l]*dfn);
- }
- // control particle mod
- cp->avgVelWeight += levVolume*pwforce;
- cp->avgVelAcc += LbmVec(ux,uy,uz) * levVolume*pwforce;
- }
-
- if(pwvel>0.) {
- // TODO make switch? vel.influence depends on density weight...
- // (reduced lowering with 0.75 factor)
- pwvel *= cp->influence *(1.-0.75*cp->densityWeight);
- // control particle mod
- // todo use Omega instead!?
- ff->forceVel += cp->vel*levVolume*pwvel * velLatticeScale; // levVolume?
- ff->weightVel += levVolume*pwvel; // levVolume?
- ff->compAv += cp->avgVel*levVolume*pwvel; // levVolume?
- ff->compAvWeight += levVolume*pwvel; // levVolume?
- }
-
- if(CPODEBUG) errMsg("cppft","i"<<cppi<<" at "<<PRINT_IJK<<" kern:"<<
- PRINT_VEC(i-cpi+cpw, j-cpj+cpw, k-cpk+cpw )
- //<<" w:"<<ff->weightAtt<<" wa:"
- //<<PRINT_VEC( ff->forceAtt[0],ff->forceAtt[1],ff->forceAtt[2] )
- //<<" v:"<<ff->weightVel<<" wv:"
- //<<PRINT_VEC( ff->forceVel[0],ff->forceVel[1],ff->forceVel[2] )
- //<<" v:"<<ff->maxDistance<<" wv:"
- //<<PRINT_VEC( ff->forceMaxd[0],ff->forceMaxd[1],ff->forceMaxd[2] )
- );
- } // celltype
-
- } // ijk
- } // ijk
- } // ijk
- } // cpi, end first cp loop (att,vel)
- debMsgStd("LbmFsgrSolver::handleCpdata",DM_MSG,"Force cpgrid "<<cpssi<<" generated checks:"<<cpChecks<<" infs:"<<cpInfs ,9);
- } //cpssi
- } // lev
-
- // second loop
- for(int lev=0; lev<=mMaxRefine; lev++) {
- LbmFloat levVolume = 1.;
- LbmFloat levForceScale = 1.;
- for(int ll=lev; ll<mMaxRefine; ll++) {
- if(LBMDIM==3) levVolume *= 8.;
- else levVolume *= 4.;
- levForceScale *= 2.;
- }
- // prepare maxd forces
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
-
- // WARNING copied from above!
- const LbmFloat velLatticeScale = mLevel[lev].timestep/mLevel[lev].nodeSize;
- LbmFloat gsx = ((mvGeoEnd[0]-mvGeoStart[0])/(LbmFloat)mLevel[lev].lSizex);
- LbmFloat gsy = ((mvGeoEnd[1]-mvGeoStart[1])/(LbmFloat)mLevel[lev].lSizey);
- LbmFloat gsz = ((mvGeoEnd[2]-mvGeoStart[2])/(LbmFloat)mLevel[lev].lSizez);
-#if LBMDIM==2
- gsz = gsx;
-#endif
- LbmFloat goffx = mvGeoStart[0];
- LbmFloat goffy = mvGeoStart[1];
- LbmFloat goffz = mvGeoStart[2];
-
- //const LbmFloat cpwIncFac = 2.0;
- const int mdw = MIN( mLevel[lev].lSizex/2, MAX( (int)( cparts->getRadiusMaxd() /gsx) +1 , 2) ); // wide kernel, md
- const int mdkarWidth = 2*mdw+1;
- mpControl->mMdKernel.resize(mdkarWidth* mdkarWidth* mdkarWidth);
- ControlParticle cpt; cpt.reset();
- cpt.density = 0.5; cpt.densityWeight = 0.5;
- cpt.pos = LbmVec( (gsx*(LbmFloat)mdw)+goffx, (gsy*(LbmFloat)mdw)+goffy, (gsz*(LbmFloat)mdw)+goffz ); // optimize?
-#if LBMDIM==3
- for(int k= 0; k<mdkarWidth; ++k) {
-#else // LBMDIM==3
- { int k = mdw;
-#endif
- for(int j= 0; j<mdkarWidth; ++j)
- for(int i= 0; i<mdkarWidth; ++i) {
- MDKERN(i,j,k).resetForces();
- LbmVec pos = LbmVec( (gsx*(LbmFloat)i)+goffx, (gsy*(LbmFloat)j)+goffy, (gsz*(LbmFloat)k)+goffz ); // optimize?
- cparts->calculateMaxdForce( &cpt, pos, &MDKERN(i,j,k) );
- }
- }
-
- // second cpi loop, maxd forces
- if(cparts->getInfluenceMaxdist()>0.) {
- for(int cppi=0; cppi<cparts->getSize(); cppi++) {
- ControlParticle *cp = cparts->getParticle(cppi);
- if(cp->influence<=0.) continue;
- const int cpi = (int)( (cp->pos[0]-goffx)/gsx );
- const int cpj = (int)( (cp->pos[1]-goffy)/gsy );
- int cpk = (int)( (cp->pos[2]-goffz)/gsz );
-
- int is,ie,js,je,ks,ke;
- ks = BOUNDCHECK(cpk - mdw, getForZMinBnd(), getForZMaxBnd(lev) );
- ke = BOUNDCHECK(cpk + mdw, getForZMinBnd(), getForZMaxBnd(lev) );
- js = BOUNDCHECK(cpj - mdw, 0, mLevel[lev].lSizey );
- je = BOUNDCHECK(cpj + mdw, 0, mLevel[lev].lSizey );
- is = BOUNDCHECK(cpi - mdw, 0, mLevel[lev].lSizex );
- ie = BOUNDCHECK(cpi + mdw, 0, mLevel[lev].lSizex );
- if(LBMDIM==2) { cpk = 0; ks = 0; ke = 1; }
- if(CPODEBUG) errMsg("cppft","i"<<cppi<<" mdw"<<mdw<<" gpos"<<PRINT_VEC(cpi,cpj,cpk)<<" i:"<<is<<","<<ie<<" j:"<<js<<","<<je<<" k:"<<ks<<","<<ke<<" "); // DEBUG
- cpInfs++;
-
- for(int k= ks; k<ke; ++k)
- for(int j= js; j<je; ++j) {
- CellFlagType *pflag = &RFLAG(lev,is-1,j,k, mLevel[lev].setCurr);
- for(int i= is; i<ie; ++i) {
- // second cpi loop, maxd forces
- pflag++;
- if( (*pflag) & (CFFluid|CFInter) ) // RFLAG_check
- {
- cpChecks++;
- ControlForces *ff = &LBMGET_FORCE(lev,i,j,k);
- if(ff->weightAtt == 0.) {
- ControlForces *kk = &MDKERN( i-cpi+mdw, j-cpj+mdw, k-cpk+mdw);
- const LbmFloat pmdf = kk->maxDistance;
- if((ff->maxDistance > pmdf) || (ff->maxDistance<0.))
- ff->maxDistance = pmdf;
- ff->forceMaxd = kk->forceMaxd;
- // todo use Omega instead!?
- ff->forceVel = cp->vel* velLatticeScale;
- }
- } // celltype
- } } // ijk
- } // cpi, md loop
- } // maxd inf>0 */
-
-
- debMsgStd("ControlData::initControl",DM_MSG,"Maxd cpgrid "<<cpssi<<" generated checks:"<<cpChecks<<" infs:"<<cpInfs ,9);
- } //cpssi
-
- // normalize, only done once for the whole array
- mpControl->mCons[0]->mCparts->finishControl( mpControl->mCpForces[lev], iatt,ivel,imaxd );
-
- } // lev loop
-
- myTime_t cpend = getTime();
- debMsgStd("ControlData::handleCpdata",DM_MSG,"Time for cpgrid generation:"<< getTimeString(cpend-cpstart)<<", checks:"<<cpChecks<<" infs:"<<cpInfs<<" " ,8);
-
- // warning, may return before
-}
-
-void LbmFsgrSolver::cpDebugDisplay(int dispset) { }
diff --git a/intern/elbeem/intern/solver_control.h b/intern/elbeem/intern/solver_control.h
deleted file mode 100644
index 809cac17297..00000000000
--- a/intern/elbeem/intern/solver_control.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - the visual lattice boltzmann freesurface simulator
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * testing extensions
- *
- *****************************************************************************/
-
-
-#ifndef LBM_TESTCLASS_H
-#define LBM_TESTCLASS_H
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-//class IsoSurface;
-class ParticleObject;
-class ControlParticles;
-class ControlForces;
-
-//#define NUMGRIDS 2
-//#define MAXNUMSWS 10
-
-// farfield modes
-#define FARF_3DONLY -1
-#define FARF_BOTH 0
-#define FARF_SWEONLY 1
-// dont reuse 3d vars/init
-#define FARF_SEPSWE 2
-
-// relaxation macros for solver_relax.h
-
-// WARNING has to match controlparts.h
-#define CPF_ENTRIES 12
-#define CPF_FORCE 0
-#define CPF_VELWEIGHT 3
-#define CPF_VELOCITY 4
-#define CPF_FORCEWEIGHT 7
-#define CPF_MINCPDIST 8
-#define CPF_MINCPDIR 9
-
-#include "controlparticles.h"
-
-#include "ntl_geometrymodel.h"
-
-// get force entry, set=0 is unused anyway
-#define LBMGET_FORCE(lev, i,j,k) mpControl->mCpForces[lev][ (LBMGI(lev,i,j,k,0)) ]
-
-// debug mods off...
-// same as in src/solver_relax.h!
-#define __PRECOLLIDE_MODS(rho,ux,uy,uz, grav) \
- ux += (grav)[0]; \
- uy += (grav)[1]; \
- uz += (grav)[2];
-
-//void testMaxdmod(int i, int j,int k, LbmFloat &ux,LbmFloat &uy,LbmFloat &uz,ControlForces &ff);
-#if LBMDIM==3
-#define MAXDGRAV \
- if(myforce->forceMaxd[0]*ux+myforce->forceMaxd[1]*uy<LBM_EPSILON) { \
- ux = v2w*myforce->forceVel[0]+ v2wi*ux; \
- uy = v2w*myforce->forceVel[1]+ v2wi*uy; } \
- /* movement inverse to g? */ \
- if((uz>LBM_EPSILON)&&(uz>myforce->forceVel[2])) { \
- uz = v2w*myforce->forceVel[2]+ v2wi*uz; }
-#else // LBMDIM==3
-#define MAXDGRAV \
- if(myforce->forceMaxd[0]*ux<LBM_EPSILON) { \
- ux = v2w*myforce->forceVel[0]+ v2wi*ux; } \
- /* movement inverse to g? */ \
- if((uy>LBM_EPSILON)&&(uy>myforce->forceVel[1])) { \
- uy = v2w*myforce->forceVel[1]+ v2wi*uy; }
-#endif // LBMDIM==3
-
-// debug modifications of collide vars (testing)
-// requires: lev,i,j,k
-#define PRECOLLIDE_MODS(rho,ux,uy,uz, grav) \
- LbmFloat attforce = 1.; \
- if(this->mTForceStrength>0.) { \
- ControlForces* myforce = &LBMGET_FORCE(lev,i,j,k); \
- const LbmFloat vf = myforce->weightAtt;\
- const LbmFloat vw = myforce->weightVel;\
- if(vf!=0.) { attforce = MAX(0., 1.-vf); /* TODO FIXME? use ABS(vf) for repulsion force? */ \
- ux += myforce->forceAtt[0]; \
- uy += myforce->forceAtt[1]; \
- uz += myforce->forceAtt[2]; \
- \
- } else if(( myforce->maxDistance>0.) && ( myforce->maxDistance<CPF_MAXDINIT)) {\
- const LbmFloat v2w = mpControl->mCons[0]->mCparts->getInfluenceMaxdist() * \
- (myforce->maxDistance-mpControl->mCons[0]->mCparts->getRadiusMinMaxd()) / (mpControl->mCons[0]->mCparts->getRadiusMaxd()-mpControl->mCons[0]->mCparts->getRadiusMinMaxd()); \
- const LbmFloat v2wi = 1.-v2w; \
- if(v2w>0.){ MAXDGRAV; \
- /* errMsg("ERRMDTT","at "<<PRINT_IJK<<" maxd="<<myforce->maxDistance<<", newu"<<PRINT_VEC(ux,uy,uz)<<", org"<<PRINT_VEC(oux,ouy,ouz)<<", fv"<<myforce->forceVel<<" " ); */ \
- }\
- } \
- if(vw>0.) { \
- const LbmFloat vwi = 1.-vw;\
- const LbmFloat vwd = mpControl->mDiffVelCon;\
- ux += vw*(myforce->forceVel[0]-myforce->compAv[0] + vwd*(myforce->compAv[0]-ux) ); \
- uy += vw*(myforce->forceVel[1]-myforce->compAv[1] + vwd*(myforce->compAv[1]-uy) ); \
- uz += vw*(myforce->forceVel[2]-myforce->compAv[2] + vwd*(myforce->compAv[2]-uz) ); \
- /* TODO test!? modify smooth vel by influence of force for each lbm step, to account for force update only each N steps */ \
- myforce->compAv = (myforce->forceVel*vw+ myforce->compAv*vwi); \
- } \
- } \
- ux += (grav)[0]*attforce; \
- uy += (grav)[1]*attforce; \
- uz += (grav)[2]*attforce; \
- /* end PRECOLLIDE_MODS */
-
-#define TEST_IF_CHECK \
- if((!iffilled)&&(LBMGET_FORCE(lev,i,j,k).weightAtt!=0.)) { \
- errMsg("TESTIFFILL"," at "<<PRINT_IJK<<" "<<mass<<" "<<rho); \
- iffilled = true; \
- if(mass<rho*1.0) mass = rho*1.0; myfrac = 1.0; \
- }
-
-
-// a single set of control particles and params
-class LbmControlSet {
- public:
- LbmControlSet();
- ~LbmControlSet();
- void initCparts();
-
- // control particles
- ControlParticles *mCparts;
- // control particle overall motion (for easier manual generation)
- ControlParticles *mCpmotion;
- // cp data file
- string mContrPartFile;
- string mCpmotionFile;
- // cp debug displau
- LbmFloat mDebugCpscale, mDebugVelScale, mDebugCompavScale, mDebugAttScale, mDebugMaxdScale, mDebugAvgVelScale;
-
- // params
- AnimChannel<float> mcForceAtt;
- AnimChannel<float> mcForceVel;
- AnimChannel<float> mcForceMaxd;
-
- AnimChannel<float> mcRadiusAtt;
- AnimChannel<float> mcRadiusVel;
- AnimChannel<float> mcRadiusMind;
- AnimChannel<float> mcRadiusMaxd;
-
- AnimChannel<ntlVec3f> mcCpScale;
- AnimChannel<ntlVec3f> mcCpOffset;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:LbmControlSet")
-#endif
-};
-
-
-
-// main control data storage
-class LbmControlData
-{
- public:
- LbmControlData();
- virtual ~LbmControlData();
-
- // control data
-
- // contorl params
- void parseControldataAttrList(AttributeList *attr);
-
- // control strength, set for solver interface
- LbmFloat mSetForceStrength;
- // cp vars
- std::vector<LbmControlSet*> mCons;
- // update interval
- int mCpUpdateInterval;
- // output
- string mCpOutfile;
- // control particle precomputed influence
- std::vector< std::vector<ControlForces> > mCpForces;
- std::vector<ControlForces> mCpKernel;
- std::vector<ControlForces> mMdKernel;
- // activate differential velcon
- LbmFloat mDiffVelCon;
-
- // cp debug displau
- LbmFloat mDebugCpscale, mDebugVelScale, mDebugCompavScale, mDebugAttScale, mDebugMaxdScale, mDebugAvgVelScale;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:LbmControlData ")
-#endif
-};
-
-#endif // LBM_TESTCLASS_H
diff --git a/intern/elbeem/intern/solver_init.cpp b/intern/elbeem/intern/solver_init.cpp
deleted file mode 100644
index 5f28b4da41a..00000000000
--- a/intern/elbeem/intern/solver_init.cpp
+++ /dev/null
@@ -1,2396 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Standard LBM Factory implementation
- *
- *****************************************************************************/
-
-
-#include "solver_class.h"
-#include "solver_relax.h"
-// for geo init FGI_ defines
-#include "elbeem.h"
-#include "globals.h"
-
-
-// helper for 2d init
-#define SWAPYZ(vec) { \
- const LbmFloat tmp = (vec)[2]; \
- (vec)[2] = (vec)[1]; (vec)[1] = tmp; }
-
-
-/*****************************************************************************/
-//! common variables
-
-/*****************************************************************************/
-/*! 3D implementation D3Q19 */
-#if LBMDIM==3
-
- //! how many dimensions?
- const int LbmFsgrSolver::cDimension = 3;
-
- // Wi factors for collide step
- const LbmFloat LbmFsgrSolver::cCollenZero = (1.0/3.0);
- const LbmFloat LbmFsgrSolver::cCollenOne = (1.0/18.0);
- const LbmFloat LbmFsgrSolver::cCollenSqrtTwo = (1.0/36.0);
-
- //! threshold value for filled/emptied cells
- const LbmFloat LbmFsgrSolver::cMagicNr2 = 1.0005;
- const LbmFloat LbmFsgrSolver::cMagicNr2Neg = -0.0005;
- const LbmFloat LbmFsgrSolver::cMagicNr = 1.010001;
- const LbmFloat LbmFsgrSolver::cMagicNrNeg = -0.010001;
-
- //! size of a single set of distribution functions
- const int LbmFsgrSolver::cDfNum = 19;
- //! direction vector contain vecs for all spatial dirs, even if not used for LBM model
- const int LbmFsgrSolver::cDirNum = 27;
-
- //const string LbmFsgrSolver::dfString[ cDfNum ] = {
- const char* LbmFsgrSolver::dfString[ cDfNum ] = {
- " C", " N"," S"," E"," W"," T"," B",
- "NE","NW","SE","SW",
- "NT","NB","ST","SB",
- "ET","EB","WT","WB"
- };
-
- const int LbmFsgrSolver::dfNorm[ cDfNum ] = {
- cDirC, cDirN, cDirS, cDirE, cDirW, cDirT, cDirB,
- cDirNE, cDirNW, cDirSE, cDirSW,
- cDirNT, cDirNB, cDirST, cDirSB,
- cDirET, cDirEB, cDirWT, cDirWB
- };
-
- const int LbmFsgrSolver::dfInv[ cDfNum ] = {
- cDirC, cDirS, cDirN, cDirW, cDirE, cDirB, cDirT,
- cDirSW, cDirSE, cDirNW, cDirNE,
- cDirSB, cDirST, cDirNB, cDirNT,
- cDirWB, cDirWT, cDirEB, cDirET
- };
-
- const int LbmFsgrSolver::dfRefX[ cDfNum ] = {
- 0, 0, 0, 0, 0, 0, 0,
- cDirSE, cDirSW, cDirNE, cDirNW,
- 0, 0, 0, 0,
- cDirEB, cDirET, cDirWB, cDirWT
- };
-
- const int LbmFsgrSolver::dfRefY[ cDfNum ] = {
- 0, 0, 0, 0, 0, 0, 0,
- cDirNW, cDirNE, cDirSW, cDirSE,
- cDirNB, cDirNT, cDirSB, cDirST,
- 0, 0, 0, 0
- };
-
- const int LbmFsgrSolver::dfRefZ[ cDfNum ] = {
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- cDirST, cDirSB, cDirNT, cDirNB,
- cDirWT, cDirWB, cDirET, cDirEB
- };
-
- // Vector Order 3D:
- // 0 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
- // 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1
- // 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1
- // 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1
-
- const int LbmFsgrSolver::dfVecX[ cDirNum ] = {
- 0, 0,0, 1,-1, 0,0,
- 1,-1,1,-1,
- 0,0,0,0,
- 1,1,-1,-1,
- 1,-1, 1,-1,
- 1,-1, 1,-1,
- };
- const int LbmFsgrSolver::dfVecY[ cDirNum ] = {
- 0, 1,-1, 0,0,0,0,
- 1,1,-1,-1,
- 1,1,-1,-1,
- 0,0,0,0,
- 1, 1,-1,-1,
- 1, 1,-1,-1
- };
- const int LbmFsgrSolver::dfVecZ[ cDirNum ] = {
- 0, 0,0,0,0,1,-1,
- 0,0,0,0,
- 1,-1,1,-1,
- 1,-1,1,-1,
- 1, 1, 1, 1,
- -1,-1,-1,-1
- };
-
- const LbmFloat LbmFsgrSolver::dfDvecX[ cDirNum ] = {
- 0, 0,0, 1,-1, 0,0,
- 1,-1,1,-1,
- 0,0,0,0,
- 1,1,-1,-1,
- 1,-1, 1,-1,
- 1,-1, 1,-1
- };
- const LbmFloat LbmFsgrSolver::dfDvecY[ cDirNum ] = {
- 0, 1,-1, 0,0,0,0,
- 1,1,-1,-1,
- 1,1,-1,-1,
- 0,0,0,0,
- 1, 1,-1,-1,
- 1, 1,-1,-1
- };
- const LbmFloat LbmFsgrSolver::dfDvecZ[ cDirNum ] = {
- 0, 0,0,0,0,1,-1,
- 0,0,0,0,
- 1,-1,1,-1,
- 1,-1,1,-1,
- 1, 1, 1, 1,
- -1,-1,-1,-1
- };
-
- /* principal directions */
- const int LbmFsgrSolver::princDirX[ 2*LbmFsgrSolver::cDimension ] = {
- 1,-1, 0,0, 0,0
- };
- const int LbmFsgrSolver::princDirY[ 2*LbmFsgrSolver::cDimension ] = {
- 0,0, 1,-1, 0,0
- };
- const int LbmFsgrSolver::princDirZ[ 2*LbmFsgrSolver::cDimension ] = {
- 0,0, 0,0, 1,-1
- };
-
- /*! arrays for les model coefficients, inited in lbmsolver constructor */
- LbmFloat LbmFsgrSolver::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ];
- LbmFloat LbmFsgrSolver::lesCoeffOffdiag[ cDimension ][ cDirNum ];
-
-
- const LbmFloat LbmFsgrSolver::dfLength[ cDfNum ]= {
- cCollenZero,
- cCollenOne, cCollenOne, cCollenOne,
- cCollenOne, cCollenOne, cCollenOne,
- cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo,
- cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo,
- cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo
- };
-
- /* precalculated equilibrium dfs, inited in lbmsolver constructor */
- LbmFloat LbmFsgrSolver::dfEquil[ dTotalNum ];
-
-#else // end LBMDIM==3 , LBMDIM==2
-
-/*****************************************************************************/
-/*! 2D implementation D2Q9 */
-
- //! how many dimensions?
- const int LbmFsgrSolver::cDimension = 2;
-
- //! Wi factors for collide step
- const LbmFloat LbmFsgrSolver::cCollenZero = (4.0/9.0);
- const LbmFloat LbmFsgrSolver::cCollenOne = (1.0/9.0);
- const LbmFloat LbmFsgrSolver::cCollenSqrtTwo = (1.0/36.0);
-
- //! threshold value for filled/emptied cells
- const LbmFloat LbmFsgrSolver::cMagicNr2 = 1.0005;
- const LbmFloat LbmFsgrSolver::cMagicNr2Neg = -0.0005;
- const LbmFloat LbmFsgrSolver::cMagicNr = 1.010001;
- const LbmFloat LbmFsgrSolver::cMagicNrNeg = -0.010001;
-
- //! size of a single set of distribution functions
- const int LbmFsgrSolver::cDfNum = 9;
- const int LbmFsgrSolver::cDirNum = 9;
-
- //const string LbmFsgrSolver::dfString[ cDfNum ] = {
- const char* LbmFsgrSolver::dfString[ cDfNum ] = {
- " C",
- " N", " S", " E", " W",
- "NE", "NW", "SE","SW"
- };
-
- const int LbmFsgrSolver::dfNorm[ cDfNum ] = {
- cDirC,
- cDirN, cDirS, cDirE, cDirW,
- cDirNE, cDirNW, cDirSE, cDirSW
- };
-
- const int LbmFsgrSolver::dfInv[ cDfNum ] = {
- cDirC,
- cDirS, cDirN, cDirW, cDirE,
- cDirSW, cDirSE, cDirNW, cDirNE
- };
-
- const int LbmFsgrSolver::dfRefX[ cDfNum ] = {
- 0,
- 0, 0, 0, 0,
- cDirSE, cDirSW, cDirNE, cDirNW
- };
-
- const int LbmFsgrSolver::dfRefY[ cDfNum ] = {
- 0,
- 0, 0, 0, 0,
- cDirNW, cDirNE, cDirSW, cDirSE
- };
-
- const int LbmFsgrSolver::dfRefZ[ cDfNum ] = {
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0
- };
-
- // Vector Order 2D:
- // 0 1 2 3 4 5 6 7 8
- // 0, 0,0, 1,-1, 1,-1,1,-1
- // 0, 1,-1, 0,0, 1,1,-1,-1
-
- const int LbmFsgrSolver::dfVecX[ cDirNum ] = {
- 0,
- 0,0, 1,-1,
- 1,-1,1,-1
- };
- const int LbmFsgrSolver::dfVecY[ cDirNum ] = {
- 0,
- 1,-1, 0,0,
- 1,1,-1,-1
- };
- const int LbmFsgrSolver::dfVecZ[ cDirNum ] = {
- 0, 0,0,0,0, 0,0,0,0
- };
-
- const LbmFloat LbmFsgrSolver::dfDvecX[ cDirNum ] = {
- 0,
- 0,0, 1,-1,
- 1,-1,1,-1
- };
- const LbmFloat LbmFsgrSolver::dfDvecY[ cDirNum ] = {
- 0,
- 1,-1, 0,0,
- 1,1,-1,-1
- };
- const LbmFloat LbmFsgrSolver::dfDvecZ[ cDirNum ] = {
- 0, 0,0,0,0, 0,0,0,0
- };
-
- const int LbmFsgrSolver::princDirX[ 2*LbmFsgrSolver::cDimension ] = {
- 1,-1, 0,0
- };
- const int LbmFsgrSolver::princDirY[ 2*LbmFsgrSolver::cDimension ] = {
- 0,0, 1,-1
- };
- const int LbmFsgrSolver::princDirZ[ 2*LbmFsgrSolver::cDimension ] = {
- 0,0, 0,0
- };
-
-
- /*! arrays for les model coefficients, inited in lbmsolver constructor */
- LbmFloat LbmFsgrSolver::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ];
- LbmFloat LbmFsgrSolver::lesCoeffOffdiag[ cDimension ][ cDirNum ];
-
-
- const LbmFloat LbmFsgrSolver::dfLength[ cDfNum ]= {
- cCollenZero,
- cCollenOne, cCollenOne, cCollenOne, cCollenOne,
- cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo
- };
-
- /* precalculated equilibrium dfs, inited in lbmsolver constructor */
- LbmFloat LbmFsgrSolver::dfEquil[ dTotalNum ];
-
-// D2Q9 end
-#endif // LBMDIM==2
-
-
-
-
-/******************************************************************************
- * Lbm Constructor
- *****************************************************************************/
-LbmFsgrSolver::LbmFsgrSolver() :
- //D(),
- mCurrentMass(0.0), mCurrentVolume(0.0),
- mNumProblems(0),
- mAvgMLSUPS(0.0), mAvgMLSUPSCnt(0.0),
- mpPreviewSurface(NULL),
- mTimeAdap(true), mForceTimeStepReduce(false),
- mFVHeight(0.0), mFVArea(1.0), mUpdateFVHeight(false),
- mInitSurfaceSmoothing(0), mFsSurfGenSetting(0),
- mTimestepReduceLock(0),
- mTimeSwitchCounts(0), mTimeMaxvelStepCnt(0),
- mSimulationTime(0.0), mLastSimTime(0.0),
- mMinTimestep(0.0), mMaxTimestep(0.0),
- mMaxNoCells(0), mMinNoCells(0), mAvgNumUsedCells(0),
- mObjectSpeeds(), mObjectPartslips(), mObjectMassMovnd(),
- mMOIVertices(), mMOIVerticesOld(), mMOINormals(),
- mIsoWeightMethod(1),
- mMaxRefine(1),
- mDfScaleUp(-1.0), mDfScaleDown(-1.0),
- mInitialCsmago(0.02), // set to 0.02 for mMaxRefine==0 below and default for fine level, coarser ones are 0.03
- mDebugOmegaRet(0.0),
- mLastOmega(1e10), mLastGravity(1e10),
- mNumInvIfTotal(0), mNumFsgrChanges(0),
- mDisableStandingFluidInit(0),
- mInit2dYZ(false),
- mForceTadapRefine(-1), mCutoff(-1)
-{
- mpControl = new LbmControlData();
-
-#if LBM_INCLUDE_TESTSOLVERS==1
- mpTest = new LbmTestdata();
- mMpNum = mMpIndex = 0;
- mOrgSizeX = 0;
- mOrgStartX = 0.;
- mOrgEndX = 0.;
-#endif // LBM_INCLUDE_TESTSOLVERS!=1
- mpIso = new IsoSurface( mIsoValue );
-
- // init equilibrium dist. func
- LbmFloat rho=1.0;
- FORDF0 {
- dfEquil[l] = this->getCollideEq( l,rho, 0.0, 0.0, 0.0);
- }
- dfEquil[dMass] = 1.;
- dfEquil[dFfrac] = 1.;
- dfEquil[dFlux] = FLUX_INIT;
-
- // init LES
- int odm = 0;
- for(int m=0; m<LBMDIM; m++) {
- for(int l=0; l<cDfNum; l++) {
- this->lesCoeffDiag[m][l] =
- this->lesCoeffOffdiag[m][l] = 0.0;
- }
- }
- for(int m=0; m<LBMDIM; m++) {
- for(int n=0; n<LBMDIM; n++) {
- for(int l=1; l<cDfNum; l++) {
- LbmFloat em;
- switch(m) {
- case 0: em = dfDvecX[l]; break;
- case 1: em = dfDvecY[l]; break;
- case 2: em = dfDvecZ[l]; break;
- default: em = -1.0; errFatal("SMAGO1","err m="<<m, SIMWORLD_GENERICERROR);
- }
- LbmFloat en;
- switch(n) {
- case 0: en = dfDvecX[l]; break;
- case 1: en = dfDvecY[l]; break;
- case 2: en = dfDvecZ[l]; break;
- default: en = -1.0; errFatal("SMAGO2","err n="<<n, SIMWORLD_GENERICERROR);
- }
- const LbmFloat coeff = em*en;
- if(m==n) {
- this->lesCoeffDiag[m][l] = coeff;
- } else {
- if(m>n) {
- this->lesCoeffOffdiag[odm][l] = coeff;
- }
- }
- }
-
- if(m==n) {
- } else {
- if(m>n) odm++;
- }
- }
- }
-
- mDvecNrm[0] = LbmVec(0.0);
- FORDF1 {
- mDvecNrm[l] = getNormalized(
- LbmVec(dfDvecX[dfInv[l]], dfDvecY[dfInv[l]], dfDvecZ[dfInv[l]] )
- ) * -1.0;
- }
-
- // calculate gauss weights for restriction
- //LbmFloat mGaussw[27];
- LbmFloat totGaussw = 0.0;
- const LbmFloat alpha = 1.0;
- const LbmFloat gw = sqrt(2.0*LBMDIM);
-#if ELBEEM_PLUGIN!=1
- errMsg("coarseRestrictFromFine", "TCRFF_DFDEBUG2 test df/dir num!");
-#endif
- for(int n=0;(n<cDirNum); n++) { mGaussw[n] = 0.0; }
- //for(int n=0;(n<cDirNum); n++) {
- for(int n=0;(n<cDfNum); n++) {
- const LbmFloat d = norm(LbmVec(dfVecX[n], dfVecY[n], dfVecZ[n]));
- LbmFloat w = expf( -alpha*d*d ) - expf( -alpha*gw*gw );
- mGaussw[n] = w;
- totGaussw += w;
- }
- for(int n=0;(n<cDirNum); n++) {
- mGaussw[n] = mGaussw[n]/totGaussw;
- }
-
-}
-
-/*****************************************************************************/
-/* Destructor */
-/*****************************************************************************/
-LbmFsgrSolver::~LbmFsgrSolver()
-{
- if(!mInitDone){ debMsgStd("LbmFsgrSolver::LbmFsgrSolver",DM_MSG,"not inited...",0); return; }
-#if COMPRESSGRIDS==1
- delete [] mLevel[mMaxRefine].mprsCells[1];
- mLevel[mMaxRefine].mprsCells[0] = mLevel[mMaxRefine].mprsCells[1] = NULL;
-#endif // COMPRESSGRIDS==1
-
- for(int i=0; i<=mMaxRefine; i++) {
- for(int s=0; s<2; s++) {
- if(mLevel[i].mprsCells[s]) delete [] mLevel[i].mprsCells[s];
- if(mLevel[i].mprsFlags[s]) delete [] mLevel[i].mprsFlags[s];
- }
- }
- delete mpIso;
- if(mpPreviewSurface) delete mpPreviewSurface;
- // cleanup done during scene deletion...
-
- if(mpControl) delete mpControl;
-
- // always output performance estimate
- debMsgStd("LbmFsgrSolver::~LbmFsgrSolver",DM_MSG," Avg. MLSUPS:"<<(mAvgMLSUPS/mAvgMLSUPSCnt), 5);
- if(!mSilent) debMsgStd("LbmFsgrSolver::~LbmFsgrSolver",DM_MSG,"Deleted...",10);
-}
-
-
-
-
-/******************************************************************************
- * initilize variables fom attribute list
- *****************************************************************************/
-void LbmFsgrSolver::parseAttrList()
-{
- LbmSolverInterface::parseStdAttrList();
-
- string matIso("default");
- matIso = mpSifAttrs->readString("material_surf", matIso, "SimulationLbm","mpIso->material", false );
- mpIso->setMaterialName( matIso );
- mOutputSurfacePreview = mpSifAttrs->readInt("surfacepreview", mOutputSurfacePreview, "SimulationLbm","mOutputSurfacePreview", false );
- mTimeAdap = mpSifAttrs->readBool("timeadap", mTimeAdap, "SimulationLbm","mTimeAdap", false );
- mDomainBound = mpSifAttrs->readString("domainbound", mDomainBound, "SimulationLbm","mDomainBound", false );
- mDomainPartSlipValue = mpSifAttrs->readFloat("domainpartslip", mDomainPartSlipValue, "SimulationLbm","mDomainPartSlipValue", false );
-
- mIsoWeightMethod= mpSifAttrs->readInt("isoweightmethod", mIsoWeightMethod, "SimulationLbm","mIsoWeightMethod", false );
- mInitSurfaceSmoothing = mpSifAttrs->readInt("initsurfsmooth", mInitSurfaceSmoothing, "SimulationLbm","mInitSurfaceSmoothing", false );
- mSmoothSurface = mpSifAttrs->readFloat("smoothsurface", mSmoothSurface, "SimulationLbm","mSmoothSurface", false );
- mSmoothNormals = mpSifAttrs->readFloat("smoothnormals", mSmoothNormals, "SimulationLbm","mSmoothNormals", false );
- mFsSurfGenSetting = mpSifAttrs->readInt("fssurfgen", mFsSurfGenSetting, "SimulationLbm","mFsSurfGenSetting", false );
-
- // refinement
- mMaxRefine = mRefinementDesired;
- mMaxRefine = mpSifAttrs->readInt("maxrefine", mMaxRefine ,"LbmFsgrSolver", "mMaxRefine", false);
- if(mMaxRefine<0) mMaxRefine=0;
- if(mMaxRefine>FSGR_MAXNOOFLEVELS) mMaxRefine=FSGR_MAXNOOFLEVELS-1;
- mDisableStandingFluidInit = mpSifAttrs->readInt("disable_stfluidinit", mDisableStandingFluidInit,"LbmFsgrSolver", "mDisableStandingFluidInit", false);
- mInit2dYZ = mpSifAttrs->readBool("init2dyz", mInit2dYZ,"LbmFsgrSolver", "mInit2dYZ", false);
- mForceTadapRefine = mpSifAttrs->readInt("forcetadaprefine", mForceTadapRefine,"LbmFsgrSolver", "mForceTadapRefine", false);
-
- // demo mode settings
- mFVHeight = mpSifAttrs->readFloat("fvolheight", mFVHeight, "LbmFsgrSolver","mFVHeight", false );
- // FIXME check needed?
- mFVArea = mpSifAttrs->readFloat("fvolarea", mFVArea, "LbmFsgrSolver","mFArea", false );
-
- // debugging - skip some time...
- double starttimeskip = 0.;
- starttimeskip = mpSifAttrs->readFloat("forcestarttimeskip", starttimeskip, "LbmFsgrSolver","starttimeskip", false );
- mSimulationTime += starttimeskip;
- if(starttimeskip>0.) debMsgStd("LbmFsgrSolver::parseStdAttrList",DM_NOTIFY,"Used starttimeskip="<<starttimeskip<<", t="<<mSimulationTime, 1);
-
- mpControl->parseControldataAttrList(mpSifAttrs);
-
-#if LBM_INCLUDE_TESTSOLVERS==1
- mUseTestdata = 0;
- mUseTestdata = mpSifAttrs->readBool("use_testdata", mUseTestdata,"LbmFsgrSolver", "mUseTestdata", false);
- mpTest->parseTestdataAttrList(mpSifAttrs);
-#ifdef ELBEEM_PLUGIN
- mUseTestdata=1; // DEBUG
-#endif // ELBEEM_PLUGIN
-
- mMpNum = mpSifAttrs->readInt("mpnum", mMpNum ,"LbmFsgrSolver", "mMpNum", false);
- mMpIndex = mpSifAttrs->readInt("mpindex", mMpIndex ,"LbmFsgrSolver", "mMpIndex", false);
- if(glob_mpactive) {
- // used instead...
- mMpNum = glob_mpnum;
- mMpIndex = glob_mpindex;
- } else {
- glob_mpnum = mMpNum;
- glob_mpindex = 0;
- }
- errMsg("LbmFsgrSolver::parseAttrList"," mpactive:"<<glob_mpactive<<", "<<glob_mpindex<<"/"<<glob_mpnum);
- if(mMpNum>0) {
- mUseTestdata=1; // needed in this case...
- }
-
- errMsg("LbmFsgrSolver::LBM_INCLUDE_TESTSOLVERS","Active, mUseTestdata:"<<mUseTestdata<<" ");
-#else // LBM_INCLUDE_TESTSOLVERS!=1
- // not testsolvers, off by default
- mUseTestdata = 0;
- if(mFarFieldSize>=2.) mUseTestdata=1; // equiv. to test solver check
-#endif // LBM_INCLUDE_TESTSOLVERS!=1
-
- mInitialCsmago = mpSifAttrs->readFloat("csmago", mInitialCsmago, "SimulationLbm","mInitialCsmago", false );
- // deprecated!
- float mInitialCsmagoCoarse = 0.0;
- mInitialCsmagoCoarse = mpSifAttrs->readFloat("csmago_coarse", mInitialCsmagoCoarse, "SimulationLbm","mInitialCsmagoCoarse", false );
-#if USE_LES==1
-#else // USE_LES==1
- debMsgStd("LbmFsgrSolver", DM_WARNING, "LES model switched off!",2);
- mInitialCsmago = 0.0;
-#endif // USE_LES==1
-}
-
-
-/******************************************************************************
- * (part of enabling chapter 6 of "Free Surface Flows with Moving and Deforming Objects for LBM")
- *****************************************************************************/
-void LbmFsgrSolver::setSurfGenSettings(short value)
-{
- mFsSurfGenSetting = value;
-}
-
-
-/******************************************************************************
- * Initialize omegas and forces on all levels (for init/timestep change)
- *****************************************************************************/
-void LbmFsgrSolver::initLevelOmegas()
-{
- // no explicit settings
- mOmega = mpParam->calculateOmega(mSimulationTime);
- mGravity = vec2L( mpParam->calculateGravity(mSimulationTime) );
- mSurfaceTension = 0.; //mpParam->calculateSurfaceTension(); // unused
- if(mInit2dYZ) { SWAPYZ(mGravity); }
-
- // check if last init was ok
- LbmFloat gravDelta = norm(mGravity-mLastGravity);
- //errMsg("ChannelAnimDebug","t:"<<mSimulationTime<<" om:"<<mOmega<<" - lom:"<<mLastOmega<<" gv:"<<mGravity<<" - "<<mLastGravity<<" , "<<gravDelta );
- if((mOmega == mLastOmega) && (gravDelta<=0.0)) return;
-
- if(mInitialCsmago<=0.0) {
- if(OPT3D==1) {
- errFatal("LbmFsgrSolver::initLevelOmegas","Csmago-LES = 0 not supported for optimized 3D version...",SIMWORLD_INITERROR);
- return;
- }
- }
-
- LbmFloat fineCsmago = mInitialCsmago;
- LbmFloat coarseCsmago = mInitialCsmago;
- LbmFloat maxFineCsmago1 = 0.026;
- LbmFloat maxCoarseCsmago1 = 0.029; // try stabilizing
- LbmFloat maxFineCsmago2 = 0.028;
- LbmFloat maxCoarseCsmago2 = 0.032; // try stabilizing some more
- if((mMaxRefine==1)&&(mInitialCsmago<maxFineCsmago1)) {
- fineCsmago = maxFineCsmago1;
- coarseCsmago = maxCoarseCsmago1;
- }
- if((mMaxRefine>1)&&(mInitialCsmago<maxFineCsmago2)) {
- fineCsmago = maxFineCsmago2;
- coarseCsmago = maxCoarseCsmago2;
- }
-
-
- // use Tau instead of Omega for calculations
- { // init base level
- int i = mMaxRefine;
- mLevel[i].omega = mOmega;
- mLevel[i].timestep = mpParam->getTimestep();
- mLevel[i].lcsmago = fineCsmago; //CSMAGO_INITIAL;
- mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago;
- mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0);
- }
-
- // init all sub levels
- for(int i=mMaxRefine-1; i>=0; i--) {
- //mLevel[i].omega = 2.0 * (mLevel[i+1].omega-0.5) + 0.5;
- double nomega = 0.5 * ( (1.0/(double)mLevel[i+1].omega) -0.5) + 0.5;
- nomega = 1.0/nomega;
- mLevel[i].omega = (LbmFloat)nomega;
- mLevel[i].timestep = 2.0 * mLevel[i+1].timestep;
- mLevel[i].lcsmago = coarseCsmago;
- mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago;
- mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0);
- }
-
- // for lbgk
- mLevel[ mMaxRefine ].gravity = mGravity / mLevel[ mMaxRefine ].omega;
- for(int i=mMaxRefine-1; i>=0; i--) {
- // should be the same on all levels...
- // for lbgk
- mLevel[i].gravity = (mLevel[i+1].gravity * mLevel[i+1].omega) * 2.0 / mLevel[i].omega;
- }
-
- mLastOmega = mOmega;
- mLastGravity = mGravity;
- // debug? invalidate old values...
- mGravity = -100.0;
- mOmega = -100.0;
-
- for(int i=0; i<=mMaxRefine; i++) {
- if(!mSilent) {
- errMsg("LbmFsgrSolver", "Level init "<<i<<" - sizes:"<<mLevel[i].lSizex<<","<<mLevel[i].lSizey<<","<<mLevel[i].lSizez<<" offs:"<<mLevel[i].lOffsx<<","<<mLevel[i].lOffsy<<","<<mLevel[i].lOffsz
- <<" omega:"<<mLevel[i].omega<<" grav:"<<mLevel[i].gravity<< ", "
- <<" cmsagp:"<<mLevel[i].lcsmago<<", "
- << " ss"<<mLevel[i].timestep<<" ns"<<mLevel[i].nodeSize<<" cs"<<mLevel[i].simCellSize );
- } else {
- if(!mInitDone) {
- debMsgStd("LbmFsgrSolver", DM_MSG, "Level init "<<i<<" - sizes:"<<mLevel[i].lSizex<<","<<mLevel[i].lSizey<<","<<mLevel[i].lSizez<<" "
- <<"omega:"<<mLevel[i].omega<<" grav:"<<mLevel[i].gravity , 5);
- }
- }
- }
- if(mMaxRefine>0) {
- mDfScaleUp = (mLevel[0 ].timestep/mLevel[0+1].timestep)* (1.0/mLevel[0 ].omega-1.0)/ (1.0/mLevel[0+1].omega-1.0); // yu
- mDfScaleDown = (mLevel[0+1].timestep/mLevel[0 ].timestep)* (1.0/mLevel[0+1].omega-1.0)/ (1.0/mLevel[0 ].omega-1.0); // yu
- }
-}
-
-
-/******************************************************************************
- * Init Solver (values should be read from config file)
- *****************************************************************************/
-
-/*! finish the init with config file values (allocate arrays...) */
-bool LbmFsgrSolver::initializeSolverMemory()
-{
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init start... "<<mInitDone<<" "<<(void*)this,1);
-
- // init cppf stage
- if(mCppfStage>0) {
- mSizex *= mCppfStage;
- mSizey *= mCppfStage;
- mSizez *= mCppfStage;
- }
- if(mFsSurfGenSetting==-1) {
- // all on
- mFsSurfGenSetting =
- fssgNormal | fssgNoNorth | fssgNoSouth | fssgNoEast |
- fssgNoWest | fssgNoTop | fssgNoBottom | fssgNoObs ;
- }
-
- // size inits to force cubic cells and mult4 level dimensions
- // and make sure we dont allocate too much...
- bool memOk = false;
- int orgSx = mSizex;
- int orgSy = mSizey;
- int orgSz = mSizez;
- double sizeReduction = 1.0;
- double memEstFromFunc = -1.0;
- double memEstFine = -1.0;
- string memreqStr("");
- bool firstMInit = true;
- int minitTries=0;
- while(!memOk) {
- minitTries++;
- initGridSizes( mSizex, mSizey, mSizez,
- mvGeoStart, mvGeoEnd, mMaxRefine, PARALLEL);
-
- // MPT
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(firstMInit) {
- mrSetup();
- }
-#else
- (void)firstMInit;
-#endif // LBM_INCLUDE_TESTSOLVERS==1
- firstMInit=false;
-
- calculateMemreqEstimate( mSizex, mSizey, mSizez,
- mMaxRefine, mFarFieldSize, &memEstFromFunc, &memEstFine, &memreqStr );
-
- bool noLimit = false;
- double memLimit = 0.;
- string memLimStr("-");
- if(sizeof(void*)==4) {
- // 32bit system, limit to 2GB
- memLimit = 2.0* 1024.0*1024.0*1024.0;
- memLimStr = string("2GB");
- } else {
- // 64bit, just take 16GB as limit for now...
- // memLimit = 16.0* 1024.0*1024.0*1024.0;
- // memLimStr = string("16GB");
- noLimit = true;
- }
-
- // restrict max. chunk of 1 mem block to 1GB for windows
- bool memBlockAllocProblem = false;
- double maxDefaultMemChunk = 2.*1024.*1024.*1024.;
- //std::cerr<<" memEstFine "<< memEstFine <<" maxWin:" <<maxWinMemChunk <<" maxMac:" <<maxMacMemChunk ; // DEBUG
-#ifdef WIN32
- double maxWinMemChunk = 1100.*1024.*1024.;
- if(sizeof(void *)==4 && memEstFine>maxWinMemChunk) {
- memBlockAllocProblem = true;
- }
-#endif // WIN32
-#ifdef __APPLE__
- double maxMacMemChunk = 1200.*1024.*1024.;
- if(memEstFine> maxMacMemChunk) {
- memBlockAllocProblem = true;
- }
-#endif // Mac
- if(sizeof(void*)==4 && memEstFine>maxDefaultMemChunk) {
- // max memory chunk for 32bit systems 2gig
- memBlockAllocProblem = true;
- }
-
- if(!noLimit && (memEstFromFunc>memLimit || memBlockAllocProblem)) {
- sizeReduction *= 0.9;
- mSizex = (int)(orgSx * sizeReduction);
- mSizey = (int)(orgSy * sizeReduction);
- mSizez = (int)(orgSz * sizeReduction);
- debMsgStd("LbmFsgrSolver::initialize",DM_WARNING,"initGridSizes: memory limit exceeded "<<
- //memEstFromFunc<<"/"<<memLimit<<", "<<
- //memEstFine<<"/"<<maxWinMemChunk<<", "<<
- memreqStr<<"/"<<memLimStr<<", "<<
- "retrying: "<<PRINT_VEC(mSizex,mSizey,mSizez)<<" org:"<<PRINT_VEC(orgSx,orgSy,orgSz)
- , 3 );
- } else {
- memOk = true;
- }
- }
-
- mPreviewFactor = (LbmFloat)mOutputSurfacePreview / (LbmFloat)mSizex;
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"initGridSizes: Final domain size X:"<<mSizex<<" Y:"<<mSizey<<" Z:"<<mSizez<<
- ", Domain: "<<mvGeoStart<<":"<<mvGeoEnd<<", "<<(mvGeoEnd-mvGeoStart)<<
- ", PointerSize: "<< sizeof(void*) << ", IntSize: "<< sizeof(int) <<
- ", est. Mem.Req.: "<<memreqStr ,2);
- mpParam->setSize(mSizex, mSizey, mSizez);
- if((minitTries>1)&&(glob_mpnum)) { errMsg("LbmFsgrSolver::initialize","Warning!!!!!!!!!!!!!!! Original gridsize changed........."); }
-
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Definitions: "
- <<"LBM_EPSILON="<<LBM_EPSILON <<" "
- <<"FSGR_STRICT_DEBUG="<<FSGR_STRICT_DEBUG <<" "
- <<"OPT3D="<<OPT3D <<" "
- <<"COMPRESSGRIDS="<<COMPRESSGRIDS<<" "
- <<"MASS_INVALID="<<MASS_INVALID <<" "
- <<"FSGR_LISTTRICK="<<FSGR_LISTTRICK <<" "
- <<"FSGR_LISTTTHRESHEMPTY="<<FSGR_LISTTTHRESHEMPTY <<" "
- <<"FSGR_LISTTTHRESHFULL="<<FSGR_LISTTTHRESHFULL <<" "
- <<"FSGR_MAGICNR="<<FSGR_MAGICNR <<" "
- <<"USE_LES="<<USE_LES <<" "
- ,10);
-
- // perform 2D corrections...
- if(LBMDIM == 2) mSizez = 1;
-
- mpParam->setSimulationMaxSpeed(0.0);
- if(mFVHeight>0.0) mpParam->setFluidVolumeHeight(mFVHeight);
- mpParam->setTadapLevels( mMaxRefine+1 );
-
- if(mForceTadapRefine>mMaxRefine) {
- mpParam->setTadapLevels( mForceTadapRefine+1 );
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Forcing a t-adap refine level of "<<mForceTadapRefine, 6);
- }
-
- if(!mpParam->calculateAllMissingValues(mSimulationTime, false)) {
- errFatal("LbmFsgrSolver::initialize","Fatal: failed to init parameters! Aborting...",SIMWORLD_INITERROR);
- return false;
- }
-
-
- // init vectors
- for(int i=0; i<=mMaxRefine; i++) {
- mLevel[i].id = i;
- mLevel[i].nodeSize = 0.0;
- mLevel[i].simCellSize = 0.0;
- mLevel[i].omega = 0.0;
- mLevel[i].time = 0.0;
- mLevel[i].timestep = 1.0;
- mLevel[i].gravity = LbmVec(0.0);
- mLevel[i].mprsCells[0] = NULL;
- mLevel[i].mprsCells[1] = NULL;
- mLevel[i].mprsFlags[0] = NULL;
- mLevel[i].mprsFlags[1] = NULL;
-
- mLevel[i].avgOmega = 0.0;
- mLevel[i].avgOmegaCnt = 0.0;
- }
-
-#if PARALLEL == 1
- /*
- // DG: this would be the correct sanity check, not the "hack below" */
- // if(( mSizey / mNumOMPThreads) * mNumOMPThreads != mSizey) {
- // setNumOMPThreads();
- //}
- if( mSizey < mNumOMPThreads ) {
- setNumOMPThreads(mSizey);
- }
-#endif
-
- // init sizes
- mLevel[mMaxRefine].lSizex = mSizex;
- mLevel[mMaxRefine].lSizey = mSizey;
- mLevel[mMaxRefine].lSizez = mSizez;
- for(int i=mMaxRefine-1; i>=0; i--) {
- mLevel[i].lSizex = mLevel[i+1].lSizex/2;
- mLevel[i].lSizey = mLevel[i+1].lSizey/2;
- mLevel[i].lSizez = mLevel[i+1].lSizez/2;
- }
-
- // safety check
- if(sizeof(CellFlagType) != CellFlagTypeSize) {
- errFatal("LbmFsgrSolver::initialize","Fatal Error: CellFlagType has wrong size! Is:"<<sizeof(CellFlagType)<<", should be:"<<CellFlagTypeSize, SIMWORLD_GENERICERROR);
- return false;
- }
-
- double ownMemCheck = 0.0;
- mLevel[ mMaxRefine ].nodeSize = ((mvGeoEnd[0]-mvGeoStart[0]) / (LbmFloat)(mSizex));
- mLevel[ mMaxRefine ].simCellSize = mpParam->getCellSize();
- mLevel[ mMaxRefine ].lcellfactor = 1.0;
- LONGINT rcellSize = (LONGINT)((LONGINT)((LONGINT)mLevel[mMaxRefine].lSizex*(LONGINT)mLevel[mMaxRefine].lSizey*(LONGINT)mLevel[mMaxRefine].lSizez) * (LONGINT)dTotalNum);
-
-#if COMPRESSGRIDS==0
- mLevel[ mMaxRefine ].mprsCells[0] = new LbmFloat[ rcellSize +4 ];
- mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +4 ];
- ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4);
-#else // COMPRESSGRIDS==0
- LONGINT compressOffset = (LONGINT)((LONGINT)mLevel[mMaxRefine].lSizex * (LONGINT)mLevel[mMaxRefine].lSizey * (LONGINT)dTotalNum * 2);
- // LONGINT tmp = ( (rcellSize +compressOffset +4)/(1024*1024) )*sizeof(LbmFloat);
- // printf("Debug MEMMMM excee: %I64d, %I64d, %I64d, %d, %d\n", tmp, compressOffset, rcellSize, mLevel[mMaxRefine].lSizex, mLevel[mMaxRefine].lSizey );
- mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +compressOffset +4 ];
- mLevel[ mMaxRefine ].mprsCells[0] = mLevel[ mMaxRefine ].mprsCells[1]+compressOffset;
- ownMemCheck += sizeof(LbmFloat) * (rcellSize +compressOffset +4);
-#endif // COMPRESSGRIDS==0
-
- if(!mLevel[ mMaxRefine ].mprsCells[1] || !mLevel[ mMaxRefine ].mprsCells[0]) {
- errFatal("LbmFsgrSolver::initialize","Fatal: Couldnt allocate memory (1)! Aborting...",SIMWORLD_INITERROR);
- return false;
- }
-
- // +4 for safety ?
- mLevel[ mMaxRefine ].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ];
- mLevel[ mMaxRefine ].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ];
- ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4);
- if(!mLevel[ mMaxRefine ].mprsFlags[1] || !mLevel[ mMaxRefine ].mprsFlags[0]) {
- errFatal("LbmFsgrSolver::initialize","Fatal: Couldnt allocate memory (2)! Aborting...",SIMWORLD_INITERROR);
-
-#if COMPRESSGRIDS==0
- delete[] mLevel[ mMaxRefine ].mprsCells[0];
- delete[] mLevel[ mMaxRefine ].mprsCells[1];
-#else // COMPRESSGRIDS==0
- delete[] mLevel[ mMaxRefine ].mprsCells[1];
-#endif // COMPRESSGRIDS==0
- return false;
- }
-
- LbmFloat lcfdimFac = 8.0;
- if(LBMDIM==2) lcfdimFac = 4.0;
- for(int i=mMaxRefine-1; i>=0; i--) {
- mLevel[i].nodeSize = 2.0 * mLevel[i+1].nodeSize;
- mLevel[i].simCellSize = 2.0 * mLevel[i+1].simCellSize;
- mLevel[i].lcellfactor = mLevel[i+1].lcellfactor * lcfdimFac;
-
- if(LBMDIM==2){ mLevel[i].lSizez = 1; } // 2D
- rcellSize = ((mLevel[i].lSizex*mLevel[i].lSizey*mLevel[i].lSizez) *dTotalNum);
- mLevel[i].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ];
- mLevel[i].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ];
- ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4);
- mLevel[i].mprsCells[0] = new LbmFloat[ rcellSize +4 ];
- mLevel[i].mprsCells[1] = new LbmFloat[ rcellSize +4 ];
- ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4);
- }
-
- // isosurface memory, use orig res values
- if(mFarFieldSize>0.) {
- ownMemCheck += (double)( (3*sizeof(int)+sizeof(float)) * ((mSizex+2)*(mSizey+2)*(mSizez+2)) );
- } else {
- // ignore 3 int slices...
- ownMemCheck += (double)( ( sizeof(float)) * ((mSizex+2)*(mSizey+2)*(mSizez+2)) );
- }
-
- // sanity check
-#if ELBEEM_PLUGIN!=1
- if(ABS(1.0-ownMemCheck/memEstFromFunc)>0.01) {
- errMsg("LbmFsgrSolver::initialize","Sanity Error - memory estimate is off! real:"<<ownMemCheck<<" vs. estimate:"<<memEstFromFunc );
- }
-#endif // ELBEEM_PLUGIN!=1
-
- // init sizes for _all_ levels
- for(int i=mMaxRefine; i>=0; i--) {
- mLevel[i].lOffsx = mLevel[i].lSizex;
- mLevel[i].lOffsy = mLevel[i].lOffsx*mLevel[i].lSizey;
- mLevel[i].lOffsz = mLevel[i].lOffsy*mLevel[i].lSizez;
- mLevel[i].setCurr = 0;
- mLevel[i].setOther = 1;
- mLevel[i].lsteps = 0;
- mLevel[i].lmass = 0.0;
- mLevel[i].lvolume = 0.0;
- }
-
- // calc omega, force for all levels
- initLevelOmegas();
- mMinTimestep = mpParam->getTimestep();
- mMaxTimestep = mpParam->getTimestep();
-
- // init isosurf
- mpIso->setIsolevel( mIsoValue );
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(mUseTestdata) {
- mpTest->setMaterialName( mpIso->getMaterialName() );
- delete mpIso;
- mpIso = mpTest;
- if(mpTest->mFarfMode>0) { // 3d off
- mpTest->setIsolevel(-100.0);
- } else {
- mpTest->setIsolevel( mIsoValue );
- }
- }
-#endif // LBM_INCLUDE_TESTSOLVERS!=1
- // approximate feature size with mesh resolution
- float featureSize = mLevel[ mMaxRefine ].nodeSize*0.5;
- // smooth vars defined in solver_interface, set by simulation object
- // reset for invalid values...
- if((mSmoothSurface<0.)||(mSmoothSurface>50.)) mSmoothSurface = 1.;
- if((mSmoothNormals<0.)||(mSmoothNormals>50.)) mSmoothNormals = 1.;
- mpIso->setSmoothSurface( mSmoothSurface * featureSize );
- mpIso->setSmoothNormals( mSmoothNormals * featureSize );
-
- // init iso weight values mIsoWeightMethod
- int wcnt = 0;
- float totw = 0.0;
- for(int ak=-1;ak<=1;ak++)
- for(int aj=-1;aj<=1;aj++)
- for(int ai=-1;ai<=1;ai++) {
- switch(mIsoWeightMethod) {
- case 1: // light smoothing
- mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) );
- break;
- case 2: // very light smoothing
- mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) );
- mIsoWeight[wcnt] *= mIsoWeight[wcnt];
- break;
- case 3: // no smoothing
- if(ai==0 && aj==0 && ak==0) mIsoWeight[wcnt] = 1.0;
- else mIsoWeight[wcnt] = 0.0;
- break;
- default: // strong smoothing (=0)
- mIsoWeight[wcnt] = 1.0;
- break;
- }
- totw += mIsoWeight[wcnt];
- wcnt++;
- }
- for(int i=0; i<27; i++) mIsoWeight[i] /= totw;
-
- LbmVec isostart = vec2L(mvGeoStart);
- LbmVec isoend = vec2L(mvGeoEnd);
- int twodOff = 0; // 2d slices
- if(LBMDIM==2) {
- LbmFloat sn,se;
- sn = isostart[2]+(isoend[2]-isostart[2])*0.5 - ((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5;
- se = isostart[2]+(isoend[2]-isostart[2])*0.5 + ((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5;
- isostart[2] = sn;
- isoend[2] = se;
- twodOff = 2;
- }
- int isosx = mSizex+2;
- int isosy = mSizey+2;
- int isosz = mSizez+2+twodOff;
-
- // MPT
-#if LBM_INCLUDE_TESTSOLVERS==1
- //if( strstr( this->getName().c_str(), "mpfluid1" ) != NULL) {
- if( (mMpNum>0) && (mMpIndex==0) ) {
- //? mpindex==0
- // restore original value for node0
- isosx = mOrgSizeX + 2;
- isostart[0] = mOrgStartX;
- isoend[0] = mOrgEndX;
- }
- errMsg("LbmFsgrSolver::initialize", "MPT: gcon "<<mMpNum<<","<<mMpIndex<<" src"<< PRINT_VEC(mpTest->mGCMin.mSrcx,mpTest->mGCMin.mSrcy,mpTest->mGCMin.mSrcz)<<" dst"
- << PRINT_VEC(mpTest->mGCMin.mDstx,mpTest->mGCMin.mDsty,mpTest->mGCMin.mDstz)<<" consize"
- << PRINT_VEC(mpTest->mGCMin.mConSizex,mpTest->mGCMin.mConSizey,mpTest->mGCMin.mConSizez)<<" ");
- errMsg("LbmFsgrSolver::initialize", "MPT: gcon "<<mMpNum<<","<<mMpIndex<<" src"<< PRINT_VEC(mpTest->mGCMax.mSrcx,mpTest->mGCMax.mSrcy,mpTest->mGCMax.mSrcz)<<" dst"
- << PRINT_VEC(mpTest->mGCMax.mDstx,mpTest->mGCMax.mDsty,mpTest->mGCMax.mDstz)<<" consize"
- << PRINT_VEC(mpTest->mGCMax.mConSizex,mpTest->mGCMax.mConSizey,mpTest->mGCMax.mConSizez)<<" ");
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
- errMsg(" SETISO ", "iso "<<isostart<<" - "<<isoend<<" "<<(((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5)<<" "<<(LbmFloat)(mSizex+1.0) );
- errMsg("LbmFsgrSolver::initialize", "MPT: geo "<< mvGeoStart<<","<<mvGeoEnd<<
- " grid:"<<PRINT_VEC(mSizex,mSizey,mSizez)<<",iso:"<< PRINT_VEC(isosx,isosy,isosz) );
- mpIso->setStart( vec2G(isostart) );
- mpIso->setEnd( vec2G(isoend) );
- LbmVec isodist = isoend-isostart;
-
- int isosubs = mIsoSubdivs;
- if(mFarFieldSize>1.) {
- errMsg("LbmFsgrSolver::initialize","Warning - resetting isosubdivs, using fulledge!");
- isosubs = 1;
- mpIso->setUseFulledgeArrays(true);
- }
- mpIso->setSubdivs(isosubs);
-
- mpIso->initializeIsosurface( isosx,isosy,isosz, vec2G(isodist) );
-
- // reset iso field
- for(int ak=0;ak<isosz;ak++)
- for(int aj=0;aj<isosy;aj++)
- for(int ai=0;ai<isosx;ai++) { *mpIso->getData(ai,aj,ak) = 0.0; }
-
-
- /* init array (set all invalid first) */
- preinitGrids();
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- RFLAG(lev,i,j,k,0) = 0, RFLAG(lev,i,j,k,0) = 0; // reset for changeFlag usage
- if(!mAllfluid) {
- initEmptyCell(lev, i,j,k, CFEmpty, -1.0, -1.0);
- } else {
- initEmptyCell(lev, i,j,k, CFFluid, 1.0, 1.0);
- }
- }
- }
-
-
- if(LBMDIM==2) {
- if(mOutputSurfacePreview) {
- errMsg("LbmFsgrSolver::init","No preview in 2D allowed!");
- mOutputSurfacePreview = 0; }
- }
- if((glob_mpactive) && (glob_mpindex>0)) {
- mOutputSurfacePreview = 0;
- }
-
-#if LBM_USE_GUI==1
- if(mOutputSurfacePreview) {
- errMsg("LbmFsgrSolver::init","No preview in GUI mode... mOutputSurfacePreview=0");
- mOutputSurfacePreview = 0; }
-#endif // LBM_USE_GUI==1
- if(mOutputSurfacePreview) {
- // same as normal one, but use reduced size
- mpPreviewSurface = new IsoSurface( mIsoValue );
- mpPreviewSurface->setMaterialName( mpPreviewSurface->getMaterialName() );
- mpPreviewSurface->setIsolevel( mIsoValue );
- // usually dont display for rendering
- mpPreviewSurface->setVisible( false );
-
- mpPreviewSurface->setStart( vec2G(isostart) );
- mpPreviewSurface->setEnd( vec2G(isoend) );
- LbmVec pisodist = isoend-isostart;
- LbmFloat pfac = mPreviewFactor;
- mpPreviewSurface->initializeIsosurface( (int)(pfac*mSizex)+2, (int)(pfac*mSizey)+2, (int)(pfac*mSizez)+2, vec2G(pisodist) );
- //mpPreviewSurface->setName( getName() + "preview" );
- mpPreviewSurface->setName( "preview" );
-
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Preview with sizes "<<(pfac*mSizex)<<","<<(pfac*mSizey)<<","<<(pfac*mSizez)<<" enabled",10);
- }
-
- // init defaults
- mAvgNumUsedCells = 0;
- mFixMass= 0.0;
- return true;
-}
-
-/*! init solver arrays */
-bool LbmFsgrSolver::initializeSolverGrids() {
- /* init boundaries */
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Boundary init...",10);
- // init obstacles, and reinit time step size
- initGeometryFlags();
- mLastSimTime = -1.0;
- // TODO check for invalid cells? nitGenericTestCases();
-
- // new - init noslip 1 everywhere...
- // half fill boundary cells?
-
- CellFlagType domainBoundType = CFInvalid;
- // TODO use normal object types instad...
- if(mDomainBound.find(string("free")) != string::npos) {
- domainBoundType = CFBnd | CFBndFreeslip;
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: FreeSlip, value:"<<mDomainBound,10);
- } else if(mDomainBound.find(string("part")) != string::npos) {
- domainBoundType = CFBnd | CFBndPartslip; // part slip type
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: PartSlip ("<<mDomainPartSlipValue<<"), value:"<<mDomainBound,10);
- } else {
- domainBoundType = CFBnd | CFBndNoslip;
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: NoSlip, value:"<<mDomainBound,10);
- }
-
- // use ar[numobjs] as entry for domain (used e.g. for mDomainPartSlipValue in mObjectPartslips)
- int domainobj = (int)(mpGiObjects->size());
- domainBoundType |= (domainobj<<24);
- //for(int i=0; i<(int)(domainobj+0); i++) {
- //errMsg("GEOIN","i"<<i<<" "<<(*mpGiObjects)[i]->getName());
- //if((*mpGiObjects)[i] == mpIso) { //check...
- //}
- //}
- //errMsg("GEOIN"," dm "<<(domainBoundType>>24));
-
- for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
- for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
- initEmptyCell(mMaxRefine, i,0,k, domainBoundType, 0.0, BND_FILL);
- initEmptyCell(mMaxRefine, i,mLevel[mMaxRefine].lSizey-1,k, domainBoundType, 0.0, BND_FILL);
- }
-
- for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
- initEmptyCell(mMaxRefine, 0,j,k, domainBoundType, 0.0, BND_FILL);
- initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-1,j,k, domainBoundType, 0.0, BND_FILL);
- // DEBUG BORDER!
- //initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-2,j,k, domainBoundType, 0.0, BND_FILL);
- }
-
- if(LBMDIM == 3) {
- // only for 3D
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++)
- for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
- initEmptyCell(mMaxRefine, i,j,0, domainBoundType, 0.0, BND_FILL);
- initEmptyCell(mMaxRefine, i,j,mLevel[mMaxRefine].lSizez-1, domainBoundType, 0.0, BND_FILL);
- }
- }
-
- // TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11
- /*for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
- initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-2,j,k, domainBoundType, 0.0, BND_FILL);
- }
- for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
- for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
- initEmptyCell(mMaxRefine, i,1,k, domainBoundType, 0.0, BND_FILL);
- }
- // */
-
- /*for(int ii=0; ii<(int)po w_change?(2.0,mMaxRefine)-1; ii++) {
- errMsg("BNDTESTSYMM","set "<<mLevel[mMaxRefine].lSizex-2-ii );
- for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
- initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-2-ii,j,k, domainBoundType, 0.0, BND_FILL); // SYMM!? 2D?
- }
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++)
- for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
- initEmptyCell(mMaxRefine, i,j,mLevel[mMaxRefine].lSizez-2-ii, domainBoundType, 0.0, BND_FILL); // SYMM!? 3D?
- }
- }
- // Symmetry tests */
- // vortt
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(( strstr( this->getName().c_str(), "vorttfluid" ) != NULL) && (LBMDIM==2)) {
- errMsg("VORTT","init");
- int level=mMaxRefine;
- int cx = mLevel[level].lSizex/2;
- int cyo = mLevel[level].lSizey/2;
- int sx = mLevel[level].lSizex/8;
- int sy = mLevel[level].lSizey/8;
- LbmFloat rho = 1.;
- LbmFloat rhomass = 1.;
- LbmFloat uFactor = 0.15;
- LbmFloat vdist = 1.0;
-
- int cy1=cyo-(int)(vdist*sy);
- int cy2=cyo+(int)(vdist*sy);
-
- //for(int j=cy-sy;j<cy+sy;j++) for(int i=cx-sx;i<cx+sx;i++) {
- for(int j=1;j<mLevel[level].lSizey-1;j++)
- for(int i=1;i<mLevel[level].lSizex-1;i++) {
- LbmFloat d1 = norm(LbmVec(cx,cy1,0.)-LbmVec(i,j,0));
- LbmFloat d2 = norm(LbmVec(cx,cy2,0.)-LbmVec(i,j,0));
- bool in1 = (d1<=(LbmFloat)(sx));
- bool in2 = (d2<=(LbmFloat)(sx));
- LbmVec uvec(0.);
- LbmVec v1 = getNormalized( cross( LbmVec(cx,cy1,0.)-LbmVec(i,j,0), LbmVec(0.,0.,1.)) )* uFactor;
- LbmVec v2 = getNormalized( cross( LbmVec(cx,cy2,0.)-LbmVec(i,j,0), LbmVec(0.,0.,1.)) )* uFactor;
- LbmFloat w1=1., w2=1.;
- if(!in1) w1=(LbmFloat)(sx)/(1.5*d1);
- if(!in2) w2=(LbmFloat)(sx)/(1.5*d2);
- if(!in1) w1=0.; if(!in2) w2=0.; // sharp falloff
- uvec += v1*w1;
- uvec += v2*w2;
- initVelocityCell(level, i,j,0, CFFluid, rho, rhomass, uvec );
- //errMsg("VORTT","init uvec"<<uvec);
- }
-
- }
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
- //if(getGlobalBakeState()<0) { CAUSE_PANIC; errMsg("LbmFsgrSolver::initialize","Got abort signal1, causing panic, aborting..."); return false; }
-
- // prepare interface cells
- initFreeSurfaces();
- initStandingFluidGradient();
-
- // perform first step to init initial mass
- mInitialMass = 0.0;
- int inmCellCnt = 0;
- FSGR_FORIJK1(mMaxRefine) {
- if( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFFluid) {
- LbmFloat fluidRho = QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, 0);
- FORDF1 { fluidRho += QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, l); }
- mInitialMass += fluidRho;
- inmCellCnt ++;
- } else if( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFInter) {
- mInitialMass += QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, dMass);
- inmCellCnt ++;
- }
- }
- mCurrentVolume = mCurrentMass = mInitialMass;
-
- ParamVec cspv = mpParam->calculateCellSize();
- if(LBMDIM==2) cspv[2] = 1.0;
- inmCellCnt = 1;
- double nrmMass = (double)mInitialMass / (double)(inmCellCnt) *cspv[0]*cspv[1]*cspv[2] * 1000.0;
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Initial Mass:"<<mInitialMass<<" normalized:"<<nrmMass, 3);
- mInitialMass = 0.0; // reset, and use actual value after first step
-
- //mStartSymm = false;
-#if ELBEEM_PLUGIN!=1
- if((LBMDIM==2)&&(mSizex<200)) {
- if(!checkSymmetry("init")) {
- errMsg("LbmFsgrSolver::initialize","Unsymmetric init...");
- } else {
- errMsg("LbmFsgrSolver::initialize","Symmetric init!");
- }
- }
-#endif // ELBEEM_PLUGIN!=1
- return true;
-}
-
-
-/*! prepare actual simulation start, setup viz etc */
-bool LbmFsgrSolver::initializeSolverPostinit() {
- // coarsen region
- myTime_t fsgrtstart = getTime();
- for(int lev=mMaxRefine-1; lev>=0; lev--) {
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Coarsening level "<<lev<<".",8);
- adaptGrid(lev);
- coarseRestrictFromFine(lev);
- adaptGrid(lev);
- coarseRestrictFromFine(lev);
- }
- markedClearList();
- myTime_t fsgrtend = getTime();
- if(!mSilent){ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"FSGR init done ("<< getTimeString(fsgrtend-fsgrtstart)<<"), changes:"<<mNumFsgrChanges , 10 ); }
- mNumFsgrChanges = 0;
-
- for(int l=0; l<cDirNum; l++) {
- LbmFloat area = 0.5 * 0.5 *0.5;
- if(LBMDIM==2) area = 0.5 * 0.5;
-
- if(dfVecX[l]!=0) area *= 0.5;
- if(dfVecY[l]!=0) area *= 0.5;
- if(dfVecZ[l]!=0) area *= 0.5;
- mFsgrCellArea[l] = area;
- } // l
-
- // make sure both sets are ok
- // copy from other to curr
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- RFLAG(lev, i,j,k,mLevel[lev].setOther) = RFLAG(lev, i,j,k,mLevel[lev].setCurr);
- } } // first copy flags */
-
-
- // old mpPreviewSurface init
- //if(getGlobalBakeState()<0) { CAUSE_PANIC; errMsg("LbmFsgrSolver::initialize","Got abort signal2, causing panic, aborting..."); return false; }
- // make sure fill fracs are right for first surface generation
- stepMain();
-
- // prepare once...
- mpIso->setParticles(mpParticles, mPartDropMassSub);
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Iso Settings, subdivs="<<mpIso->getSubdivs()<<", partsize="<<mPartDropMassSub, 9);
- prepareVisualization();
- // copy again for stats counting
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- RFLAG(lev, i,j,k,mLevel[lev].setOther) = RFLAG(lev, i,j,k,mLevel[lev].setCurr);
- } } // first copy flags */
-
-
- // now really done...
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"SurfaceGen: SmsOrg("<<mSmoothSurface<<","<<mSmoothNormals<< /*","<<featureSize<<*/ "), Iso("<<mpIso->getSmoothSurface()<<","<<mpIso->getSmoothNormals()<<") ",10);
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init done ... ",10);
- mInitDone = 1;
-
- // init fluid control
- initCpdata();
-
-#if LBM_INCLUDE_TESTSOLVERS==1
- initTestdata();
-#endif // ELBEEM_PLUGIN!=1
- // not inited? dont use...
- if(mCutoff<0) mCutoff=0;
-
- initParticles();
- return true;
-}
-
-
-
-// macros for mov obj init
-#if LBMDIM==2
-
-#define POS2GRID_CHECK(vec,n) \
- monTotal++;\
- int k=(int)( ((vec)[n][2]-iniPos[2])/dvec[2] +0.0); \
- if(k!=0) continue; \
- const int i=(int)( ((vec)[n][0]-iniPos[0])/dvec[0] +0.0); \
- if(i<=0) continue; \
- if(i>=mLevel[level].lSizex-1) continue; \
- const int j=(int)( ((vec)[n][1]-iniPos[1])/dvec[1] +0.0); \
- if(j<=0) continue; \
- if(j>=mLevel[level].lSizey-1) continue; \
-
-#else // LBMDIM -> 3
-#define POS2GRID_CHECK(vec,n) \
- monTotal++;\
- const int i=(int)( ((vec)[n][0]-iniPos[0])/dvec[0] +0.0); \
- if(i<=0) continue; \
- if(i>=mLevel[level].lSizex-1) continue; \
- const int j=(int)( ((vec)[n][1]-iniPos[1])/dvec[1] +0.0); \
- if(j<=0) continue; \
- if(j>=mLevel[level].lSizey-1) continue; \
- const int k=(int)( ((vec)[n][2]-iniPos[2])/dvec[2] +0.0); \
- if(k<=0) continue; \
- if(k>=mLevel[level].lSizez-1) continue; \
-
-#endif // LBMDIM
-
-// calculate object velocity from vert arrays in objvel vec
-#define OBJVEL_CALC \
- LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { \
- const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; \
- USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); \
- if(usqr>maxusqr) { \
- /* cutoff at maxVelVal */ \
- for(int jj=0; jj<3; jj++) { \
- if(objvel[jj]>0.) objvel[jj] = maxVelVal; \
- if(objvel[jj]<0.) objvel[jj] = -maxVelVal; \
- } \
- } } \
- if(ntype&(CFBndFreeslip)) { \
- const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); \
- /* const LbmVec oldov=objvel; */ /*DEBUG*/ \
- objvel = vec2L((*pNormals)[n]) *dp; \
- /* if((j==24)&&(n%5==2)) errMsg("FSBT","n"<<n<<" v"<<objvel<<" nn"<<(*pNormals)[n]<<" dp"<<dp<<" oldov"<<oldov ); */ \
- } \
- else if(ntype&(CFBndPartslip)) { \
- const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); \
- /* const LbmVec oldov=objvel; */ /*DEBUG*/ \
- /* if((j==24)&&(n%5==2)) errMsg("FSBT","n"<<n<<" v"<<objvel<<" nn"<<(*pNormals)[n]<<" dp"<<dp<<" oldov"<<oldov ); */ \
- const LbmFloat partv = mObjectPartslips[OId]; \
- /*errMsg("PARTSLIP_DEBUG","l="<<l<<" ccel="<<RAC(ccel, dfInv[l] )<<" partv="<<partv<<",id="<<(int)(mnbf>>24)<<" newval="<<newval ); / part slip debug */ \
- /* m[l] = (RAC(ccel, dfInv[l] ) ) * partv + newval * (1.-partv); part slip */ \
- objvel = objvel*partv + vec2L((*pNormals)[n]) *dp*(1.-partv); \
- }
-
-#define TTT \
-
-
-/*****************************************************************************/
-//! init moving obstacles for next sim step sim
-/*****************************************************************************/
-void LbmFsgrSolver::initMovingObstacles(bool staticInit) {
- myTime_t monstart = getTime();
-
- // movobj init
- const int level = mMaxRefine;
- const int workSet = mLevel[level].setCurr;
- const int otherSet = mLevel[level].setOther;
- LbmFloat sourceTime = mSimulationTime; // should be equal to mLastSimTime!
- // for debugging - check targetTime check during DEFAULT STREAM
- LbmFloat targetTime = mSimulationTime + mpParam->getTimestep();
- if(mLastSimTime == targetTime) {
- debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_WARNING,"Called for same time! (t="<<mSimulationTime<<" , targett="<<targetTime<<")", 1);
- return;
- }
- //debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_WARNING,"time: "<<mSimulationTime<<" lasttt:"<<mLastSimTime,10);
- //if(mSimulationTime!=mLastSimTime) errMsg("LbmFsgrSolver::initMovingObstacles","time: "<<mSimulationTime<<" lasttt:"<<mLastSimTime);
-
- const LbmFloat maxVelVal = 0.1666;
- const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5;
-
- LbmFloat rhomass = 0.0;
- CellFlagType otype = CFInvalid; // verify type of last step, might be non moving obs!
- CellFlagType ntype = CFInvalid;
- // WARNING - copied from geo init!
- int numobjs = (int)(mpGiObjects->size());
- ntlVec3Gfx dvec = ntlVec3Gfx(mLevel[level].nodeSize); //dvec*1.0;
- // 2d display as rectangles
- ntlVec3Gfx iniPos(0.0);
- if(LBMDIM==2) {
- dvec[2] = 1.0;
- iniPos = (mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (mvGeoEnd[2]-mvGeoStart[2])*0.5 ))-(dvec*0.0);
- } else {
- iniPos = (mvGeoStart + ntlVec3Gfx( 0.0 ))-(dvec*0.0);
- }
-
- if( (int)mObjectMassMovnd.size() < numobjs) {
- for(int i=mObjectMassMovnd.size(); i<numobjs; i++) {
- mObjectMassMovnd.push_back(0.);
- }
- }
-
- // stats
- int monPoints=0, monObsts=0, monFluids=0, monTotal=0, monTrafo=0;
- int nbored;
- for(int OId=0; OId<numobjs; OId++) {
- ntlGeometryObject *obj = (*mpGiObjects)[OId];
- bool skip = false;
- if(obj->getGeoInitId() != mLbmInitId) skip=true;
- if( (!staticInit) && (!obj->getIsAnimated()) ) skip=true;
- if( ( staticInit) && ( obj->getIsAnimated()) ) skip=true;
- if(skip) continue;
- debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" skip:"<<skip<<", static:"<<staticInit<<" anim:"<<obj->getIsAnimated()<<" gid:"<<obj->getGeoInitId()<<" simgid:"<<mLbmInitId, 10);
-
- if( (obj->getGeoInitType()&FGI_ALLBOUNDS) ||
- ((obj->getGeoInitType()&FGI_FLUID) && staticInit) ) {
-
- otype = ntype = CFInvalid;
- switch(obj->getGeoInitType()) {
- /* case FGI_BNDPART: // old, use noslip for moving part/free objs
- case FGI_BNDFREE:
- if(!staticInit) {
- errMsg("LbmFsgrSolver::initMovingObstacles","Warning - moving free/part slip objects NYI "<<obj->getName() );
- otype = ntype = CFBnd|CFBndNoslip;
- } else {
- if(obj->getGeoInitType()==FGI_BNDPART) otype = ntype = CFBnd|CFBndPartslip;
- if(obj->getGeoInitType()==FGI_BNDFREE) otype = ntype = CFBnd|CFBndFreeslip;
- }
- break;
- // off */
- case FGI_BNDPART: rhomass = BND_FILL;
- otype = ntype = CFBnd|CFBndPartslip|(OId<<24);
- break;
- case FGI_BNDFREE: rhomass = BND_FILL;
- otype = ntype = CFBnd|CFBndFreeslip|(OId<<24);
- break;
- // off */
- case FGI_BNDNO: rhomass = BND_FILL;
- otype = ntype = CFBnd|CFBndNoslip|(OId<<24);
- break;
- case FGI_FLUID:
- otype = ntype = CFFluid;
- break;
- case FGI_MBNDINFLOW:
- otype = ntype = CFMbndInflow;
- break;
- case FGI_MBNDOUTFLOW:
- otype = ntype = CFMbndOutflow;
- break;
- }
- int wasActive = ((obj->getGeoActive(sourceTime)>0.)? 1:0);
- int active = ((obj->getGeoActive(targetTime)>0.)? 1:0);
- //errMsg("GEOACTT"," obj "<<obj->getName()<<" a:"<<active<<","<<wasActive<<" s"<<sourceTime<<" t"<<targetTime <<" v"<<mObjectSpeeds[OId] );
- // skip inactive in/out flows
- if(ntype==CFInvalid){ errMsg("LbmFsgrSolver::initMovingObstacles","Invalid obj type "<<obj->getGeoInitType()); continue; }
- if((!active) && (otype&(CFMbndOutflow|CFMbndInflow)) ) continue;
-
- // copied from recalculateObjectSpeeds
- mObjectSpeeds[OId] = vec2L(mpParam->calculateLattVelocityFromRw( vec2P( (*mpGiObjects)[OId]->getInitialVelocity(mSimulationTime) )));
- debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG,"id"<<OId<<" "<<obj->getName()<<" inivel set to "<< mObjectSpeeds[OId]<<", unscaled:"<< (*mpGiObjects)[OId]->getInitialVelocity(mSimulationTime) ,10 );
-
- //vector<ntlVec3Gfx> tNormals;
- vector<ntlVec3Gfx> *pNormals = NULL;
- mMOINormals.clear();
- if(ntype&(CFBndFreeslip|CFBndPartslip)) { pNormals = &mMOINormals; }
-
- mMOIVertices.clear();
- if(obj->getMeshAnimated()) {
- // do two full update
- // TODO tNormals handling!?
- mMOIVerticesOld.clear();
- obj->initMovingPointsAnim(sourceTime,mMOIVerticesOld, targetTime, mMOIVertices, pNormals, mLevel[mMaxRefine].nodeSize, mvGeoStart, mvGeoEnd);
- monTrafo += mMOIVerticesOld.size();
- obj->applyTransformation(sourceTime, &mMOIVerticesOld,pNormals, 0, mMOIVerticesOld.size(), false );
- monTrafo += mMOIVertices.size();
- obj->applyTransformation(targetTime, &mMOIVertices,NULL /* no old normals needed */, 0, mMOIVertices.size(), false );
- } else {
- // only do transform update
- obj->getMovingPoints(mMOIVertices,pNormals); // mMOIVertices = mCachedMovPoints
- mMOIVerticesOld = mMOIVertices;
- // WARNING - assumes mSimulationTime is global!?
- obj->applyTransformation(targetTime, &mMOIVertices,pNormals, 0, mMOIVertices.size(), false );
- monTrafo += mMOIVertices.size();
-
- // correct flags from last position, but extrapolate
- // velocity to next timestep
- obj->applyTransformation(sourceTime, &mMOIVerticesOld, NULL /* no old normals needed */, 0, mMOIVerticesOld.size(), false );
- monTrafo += mMOIVerticesOld.size();
- }
-
- // object types
- if(ntype&CFBnd){
-
- // check if object is moving at all
- if(obj->getIsAnimated()) {
- ntlVec3Gfx objMaxVel = obj->calculateMaxVel(sourceTime,targetTime);
- // FIXME?
- if(normNoSqrt(objMaxVel)>0.0) { ntype |= CFBndMoving; }
- // get old type - CHECK FIXME , timestep could have changed - cause trouble?
- ntlVec3Gfx oldobjMaxVel = obj->calculateMaxVel(sourceTime - mpParam->getTimestep(),sourceTime);
- if(normNoSqrt(oldobjMaxVel)>0.0) { otype |= CFBndMoving; }
- }
- if(obj->getMeshAnimated()) { ntype |= CFBndMoving; otype |= CFBndMoving; }
- CellFlagType rflagnb[27];
- LbmFloat massCheck = 0.;
- int massReinits=0;
- bool fillCells = (mObjectMassMovnd[OId]<=-1.);
- LbmFloat impactCorrFactor = obj->getGeoImpactFactor(targetTime);
-
-
- // first pass - set new obs. cells
- if(active) {
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- //errMsg("initMovingObstacles_Debug","OId"<<OId<<" n"<<n<<" -> "<<PRINT_IJK);
- POS2GRID_CHECK(mMOIVertices,n);
- //{ errMsg("initMovingObstacles_Debug","OId"<<OId<<" n"<<n<<" -> "<<PRINT_IJK<<", t="<<targetTime); }
- if(QCELL(level, i,j,k, workSet, dFlux)==targetTime) continue;
- monPoints++;
-
- // check mass
- if(RFLAG(level, i,j,k, workSet)&(CFFluid)) {
- FORDF0 { massCheck -= QCELL(level, i,j,k, workSet, l); }
- massReinits++;
- }
- else if(RFLAG(level, i,j,k, workSet)&(CFInter)) {
- massCheck -= QCELL(level, i,j,k, workSet, dMass);
- massReinits++;
- }
-
- RFLAG(level, i,j,k, workSet) = ntype;
- FORDF1 {
- //CellFlagType flag = RFLAG_NB(level, i,j,k,workSet,l);
- rflagnb[l] = RFLAG_NB(level, i,j,k,workSet,l);
- if(rflagnb[l]&(CFFluid|CFInter)) {
- rflagnb[l] &= (~CFNoBndFluid); // remove CFNoBndFluid flag
- RFLAG_NB(level, i,j,k,workSet,l) &= rflagnb[l];
- }
- }
- LbmFloat *dstCell = RACPNT(level, i,j,k,workSet);
- RAC(dstCell,0) = 0.0;
- if(ntype&CFBndMoving) {
- OBJVEL_CALC;
-
- // compute fluid acceleration
- FORDF1 {
- if(rflagnb[l]&(CFFluid|CFInter)) {
- const LbmFloat ux = dfDvecX[l]*objvel[0];
- const LbmFloat uy = dfDvecY[l]*objvel[1];
- const LbmFloat uz = dfDvecZ[l]*objvel[2];
-
- LbmFloat factor = 2. * dfLength[l] * 3.0 * (ux+uy+uz); //
- if(ntype&(CFBndFreeslip|CFBndPartslip)) {
- // missing, diag mass checks...
- //if(l<=LBMDIM*2) factor *= 1.4142;
- factor *= 2.0; // TODO, optimize
- } else {
- factor *= 1.2; // TODO, optimize
- }
- factor *= impactCorrFactor; // use manual tweaking channel
- RAC(dstCell,l) = factor;
- massCheck += factor;
- } else {
- RAC(dstCell,l) = 0.;
- }
- }
-
-#if NEWDIRVELMOTEST==1
- FORDF1 { RAC(dstCell,l) = 0.; }
- RAC(dstCell,dMass) = objvel[0];
- RAC(dstCell,dFfrac) = objvel[1];
- RAC(dstCell,dC) = objvel[2];
-#endif // NEWDIRVELMOTEST==1
- } else {
- FORDF1 { RAC(dstCell,l) = 0.0; }
- }
- RAC(dstCell, dFlux) = targetTime;
- //errMsg("initMovingObstacles_Debug","OId"<<OId<<" n"<<n<<" -> "<<PRINT_IJK" dflt="<<RAC(dstCell, dFlux) );
- monObsts++;
- } // points
- } // bnd, is active?
-
- // second pass, remove old ones
- // warning - initEmptyCell et. al dont overwrite OId or persist flags...
- if(wasActive) {
- for(size_t n=0; n<mMOIVerticesOld.size(); n++) {
- POS2GRID_CHECK(mMOIVerticesOld,n);
- monPoints++;
- if((RFLAG(level, i,j,k, workSet) == otype) &&
- (QCELL(level, i,j,k, workSet, dFlux) != targetTime)) {
- // from mainloop
- nbored = 0;
- // TODO: optimize for OPT3D==0
- FORDF1 {
- //rflagnb[l] = RFLAG_NB(level, i,j,k,workSet,l);
- rflagnb[l] = RFLAG_NB(level, i,j,k,otherSet,l); // test use other set to not have loop dependance
- nbored |= rflagnb[l];
- }
- CellFlagType settype = CFInvalid;
- if(nbored&CFFluid) {
- settype = CFInter|CFNoInterpolSrc;
- rhomass = 1.5;
- if(!fillCells) rhomass = 0.;
-
- OBJVEL_CALC;
- if(!(nbored&CFEmpty)) { settype=CFFluid|CFNoInterpolSrc; rhomass=1.; }
-
- // new interpolate values
- LbmFloat avgrho = 0.0;
- LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0;
- interpolateCellValues(level,i,j,k,workSet, avgrho,avgux,avguy,avguz);
- initVelocityCell(level, i,j,k, settype, avgrho, rhomass, LbmVec(avgux,avguy,avguz) );
- //errMsg("NMOCIT"," at "<<PRINT_IJK<<" "<<avgrho<<" "<<norm(LbmVec(avgux,avguy,avguz))<<" "<<LbmVec(avgux,avguy,avguz) );
- massCheck += rhomass;
- } else {
- settype = CFEmpty; rhomass = 0.0;
- initEmptyCell(level, i,j,k, settype, 1., rhomass );
- }
- monFluids++;
- massReinits++;
- } // flag & simtime
- }
- } // wasactive
-
- // only compute mass transfer when init is done
- if(mInitDone) {
- errMsg("initMov","dccd\n\nMassd test "<<obj->getName()<<" dccd massCheck="<<massCheck<<" massReinits"<<massReinits<<
- " fillCells"<<fillCells<<" massmovbnd:"<<mObjectMassMovnd[OId]<<" inim:"<<mInitialMass );
- mObjectMassMovnd[OId] += massCheck;
- }
- } // bnd, active
-
- else if(ntype&CFFluid){
- // second static init pass
- if(staticInit) {
- //debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" verts"<<mMOIVertices.size() ,9);
- CellFlagType setflflag = CFFluid; //|(OId<<24);
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- POS2GRID_CHECK(mMOIVertices,n);
- if(RFLAG(level, i,j,k, workSet)&(CFMbndInflow|CFMbndOutflow)){ continue; }
- if(RFLAG(level, i,j,k, workSet)&(CFEmpty)) {
- //changeFlag(level, i,j,k, workSet, setflflag);
- initVelocityCell(level, i,j,k, setflflag, 1., 1., mObjectSpeeds[OId] );
- }
- //else if(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter)) { changeFlag(level, i,j,k, workSet, RFLAG(level, i,j,k, workSet)|set2Flag); }
- }
- } // second static inflow pass
- } // fluid
-
- else if(ntype&CFMbndInflow){
- // inflow pass - add new fluid cells
- // this is slightly different for standing inflows,
- // as the fluid is forced to the desired velocity inside as
- // well...
- const LbmFloat iniRho = 1.0;
- const LbmVec vel(mObjectSpeeds[OId]);
- const LbmFloat usqr = (vel[0]*vel[0]+vel[1]*vel[1]+vel[2]*vel[2])*1.5;
- USQRMAXCHECK(usqr,vel[0],vel[1],vel[2], mMaxVlen, mMxvx,mMxvy,mMxvz);
- //errMsg("LbmFsgrSolver::initMovingObstacles","id"<<OId<<" "<<obj->getName()<<" inflow "<<staticInit<<" "<<mMOIVertices.size() );
-
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- POS2GRID_CHECK(mMOIVertices,n);
- // TODO - also reinit interface cells !?
- if(RFLAG(level, i,j,k, workSet)!=CFEmpty) {
- // test prevent particle gen for inflow inter cells
- if(RFLAG(level, i,j,k, workSet)&(CFInter)) { RFLAG(level, i,j,k, workSet) &= (~CFNoBndFluid); } // remove CFNoBndFluid flag
- continue; }
- monFluids++;
-
- // TODO add OPT3D treatment
- LbmFloat *tcel = RACPNT(level, i,j,k,workSet);
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, iniRho,vel[0],vel[1],vel[2]); }
- RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
- RAC(tcel, dFlux) = FLUX_INIT;
- CellFlagType setFlag = CFInter;
- changeFlag(level, i,j,k, workSet, setFlag);
- mInitialMass += iniRho;
- }
- // second static init pass
- if(staticInit) {
- CellFlagType set2Flag = CFMbndInflow|(OId<<24);
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- POS2GRID_CHECK(mMOIVertices,n);
- if(RFLAG(level, i,j,k, workSet)&(CFMbndInflow|CFMbndOutflow)){ continue; }
- if(RFLAG(level, i,j,k, workSet)&(CFEmpty)) {
- forceChangeFlag(level, i,j,k, workSet, set2Flag);
- } else if(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter)) {
- forceChangeFlag(level, i,j,k, workSet,
- (RFLAG(level, i,j,k, workSet)&CFNoPersistMask)|set2Flag);
- }
- }
- } // second static inflow pass
-
- } // inflow
-
- else if(ntype&CFMbndOutflow){
- const LbmFloat iniRho = 0.0;
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- POS2GRID_CHECK(mMOIVertices,n);
- // FIXME check fluid/inter cells for non-static!?
- if(!(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter))) {
- if((staticInit)&&(RFLAG(level, i,j,k, workSet)==CFEmpty)) {
- forceChangeFlag(level, i,j,k, workSet, CFMbndOutflow); }
- continue;
- }
- monFluids++;
- // interface cell - might be double empty? FIXME check?
-
- // remove fluid cells, shouldnt be here anyway
- LbmFloat *tcel = RACPNT(level, i,j,k,workSet);
- LbmFloat fluidRho = RAC(tcel,0); FORDF1 { fluidRho += RAC(tcel,l); }
- mInitialMass -= fluidRho;
- RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
- RAC(tcel, dFlux) = FLUX_INIT;
- CellFlagType setFlag = CFInter;
- changeFlag(level, i,j,k, workSet, setFlag);
-
- // same as ifemptied for if below
- LbmPoint emptyp;
- emptyp.x = i; emptyp.y = j; emptyp.z = k;
- mListEmpty.push_back( emptyp );
- //calcCellsEmptied++;
- } // points
- // second static init pass
- if(staticInit) {
- CellFlagType set2Flag = CFMbndOutflow|(OId<<24);
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- POS2GRID_CHECK(mMOIVertices,n);
- if(RFLAG(level, i,j,k, workSet)&(CFMbndInflow|CFMbndOutflow)){ continue; }
- if(RFLAG(level, i,j,k, workSet)&(CFEmpty)) {
- forceChangeFlag(level, i,j,k, workSet, set2Flag);
- } else if(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter)) {
- forceChangeFlag(level, i,j,k, workSet,
- (RFLAG(level, i,j,k, workSet)&CFNoPersistMask)|set2Flag);
- }
- }
- } // second static outflow pass
- } // outflow
-
- } // allbound check
- } // OId
-
-
- /* { // DEBUG check
- int workSet = mLevel[level].setCurr;
- FSGR_FORIJK1(level) {
- if( (RFLAG(level,i,j,k, workSet) & CFBndMoving) ) {
- if(QCELL(level, i,j,k, workSet, dFlux)!=targetTime) {
- errMsg("lastt"," old val!? at "<<PRINT_IJK<<" t="<<QCELL(level, i,j,k, workSet, dFlux)<<" target="<<targetTime);
- }
- }
- }
- } // DEBUG */
-
-#undef POS2GRID_CHECK
- myTime_t monend = getTime();
- if(monend-monstart>0) debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG,"Total: "<<monTotal<<" Points :"<<monPoints<<" ObstInits:"<<monObsts<<" FlInits:"<<monFluids<<" Trafos:"<<monTotal<<", took "<<getTimeString(monend-monstart), 7);
- mLastSimTime = targetTime;
-}
-
-
-// geoinit position
-
-#define GETPOS(i,j,k) \
- ntlVec3Gfx ggpos = \
- ntlVec3Gfx( iniPos[0]+ dvec[0]*(gfxReal)(i), \
- iniPos[1]+ dvec[1]*(gfxReal)(j), \
- iniPos[2]+ dvec[2]*(gfxReal)(k) ); \
- if((LBMDIM==2)&&(mInit2dYZ)) { SWAPYZ(ggpos); }
-
-/*****************************************************************************/
-/*! perform geometry init (if switched on) */
-/*****************************************************************************/
-extern int globGeoInitDebug; //solver_interface
-bool LbmFsgrSolver::initGeometryFlags() {
- int level = mMaxRefine;
- myTime_t geotimestart = getTime();
- ntlGeometryObject *pObj;
- ntlVec3Gfx dvec = ntlVec3Gfx(mLevel[level].nodeSize); //dvec*1.0;
- debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Performing geometry init ("<< mLbmInitId <<") v"<<dvec,3);
- // WARNING - copied to movobj init!
-
- /* init object velocities, this has always to be called for init */
- initGeoTree();
- if(mAllfluid) {
- freeGeoTree();
- return true; }
-
- // make sure moving obstacles are inited correctly
- // preinit moving obj points
- int numobjs = (int)(mpGiObjects->size());
- for(int o=0; o<numobjs; o++) {
- ntlGeometryObject *obj = (*mpGiObjects)[o];
- //debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" type "<<obj->getGeoInitType()<<" anim"<<obj->getIsAnimated()<<" "<<obj->getVolumeInit() ,9);
- if(
- ((obj->getGeoInitType()&FGI_ALLBOUNDS) && (obj->getIsAnimated())) ||
- (obj->getVolumeInit()&VOLUMEINIT_SHELL) ) {
- if(!obj->getMeshAnimated()) {
- debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" type "<<obj->getGeoInitType()<<" anim"<<obj->getIsAnimated()<<" "<<obj->getVolumeInit() ,9);
- obj->initMovingPoints(mSimulationTime, mLevel[mMaxRefine].nodeSize);
- }
- }
- }
-
- // max speed init
- ntlVec3Gfx maxMovobjVelRw = getGeoMaxMovementVelocity( mSimulationTime, mpParam->getTimestep() );
- ntlVec3Gfx maxMovobjVel = vec2G( mpParam->calculateLattVelocityFromRw( vec2P( maxMovobjVelRw )) );
- mpParam->setSimulationMaxSpeed( norm(maxMovobjVel) + norm(mLevel[level].gravity) );
- LbmFloat allowMax = mpParam->getTadapMaxSpeed(); // maximum allowed velocity
- debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Maximum Velocity from geo init="<< maxMovobjVel <<" from mov. obj.="<<maxMovobjVelRw<<" , allowed Max="<<allowMax ,5);
- if(mpParam->getSimulationMaxSpeed() > allowMax) {
- // similar to adaptTimestep();
- LbmFloat nextmax = mpParam->getSimulationMaxSpeed();
- LbmFloat newdt = mpParam->getTimestep() * (allowMax / nextmax); // newtr
- debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Performing reparametrization, newdt="<< newdt<<" prevdt="<< mpParam->getTimestep() <<" ",5);
- mpParam->setDesiredTimestep( newdt );
- mpParam->calculateAllMissingValues( mSimulationTime, mSilent );
- maxMovobjVel = vec2G( mpParam->calculateLattVelocityFromRw( vec2P(getGeoMaxMovementVelocity(
- mSimulationTime, mpParam->getTimestep() )) ));
- debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"New maximum Velocity from geo init="<< maxMovobjVel,5);
- }
- recalculateObjectSpeeds();
- // */
-
- // init obstacles for first time step (requires obj speeds)
- initMovingObstacles(true);
-
- /* set interface cells */
- ntlVec3Gfx pos,iniPos; // position of current cell
- LbmFloat rhomass = 0.0;
- CellFlagType ntype = CFInvalid;
- int savedNodes = 0;
- int OId = -1;
- gfxReal distance;
-
- // 2d display as rectangles
- if(LBMDIM==2) {
- dvec[2] = 0.0;
- iniPos =(mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (mvGeoEnd[2]-mvGeoStart[2])*0.5 ))+(dvec*0.5);
- //if(mInit2dYZ) { SWAPYZ(mGravity); for(int lev=0; lev<=mMaxRefine; lev++){ SWAPYZ( mLevel[lev].gravity ); } }
- } else {
- iniPos =(mvGeoStart + ntlVec3Gfx( 0.0 ))+(dvec*0.5);
- }
-
-
- // first init boundary conditions
- // invalid cells are set to empty afterwards
- // TODO use floop macros!?
- for(int k= getForZMin1(); k< getForZMax1(level); ++k) {
- for(int j=1;j<mLevel[level].lSizey-1;j++) {
- for(int i=1;i<mLevel[level].lSizex-1;i++) {
- ntype = CFInvalid;
-
- GETPOS(i,j,k);
- const bool inside = geoInitCheckPointInside( ggpos, FGI_ALLBOUNDS, OId, distance);
- if(inside) {
- pObj = (*mpGiObjects)[OId];
- switch( pObj->getGeoInitType() ){
- case FGI_MBNDINFLOW:
- if(! pObj->getIsAnimated() ) {
- rhomass = 1.0;
- ntype = CFFluid | CFMbndInflow;
- } else {
- ntype = CFInvalid;
- }
- break;
- case FGI_MBNDOUTFLOW:
- if(! pObj->getIsAnimated() ) {
- rhomass = 0.0;
- ntype = CFEmpty|CFMbndOutflow;
- } else {
- ntype = CFInvalid;
- }
- break;
- case FGI_BNDNO:
- rhomass = BND_FILL;
- ntype = CFBnd|CFBndNoslip;
- break;
- case FGI_BNDPART:
- rhomass = BND_FILL;
- ntype = CFBnd|CFBndPartslip; break;
- case FGI_BNDFREE:
- rhomass = BND_FILL;
- ntype = CFBnd|CFBndFreeslip; break;
- default: // warn here?
- rhomass = BND_FILL;
- ntype = CFBnd|CFBndNoslip; break;
- }
- }
- if(ntype != CFInvalid) {
- // initDefaultCell
- if((ntype & CFMbndInflow) || (ntype & CFMbndOutflow) ) { }
- ntype |= (OId<<24); // NEWTEST2
- initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
- }
-
- // walk along x until hit for following inits
- if(distance<=-1.0) { distance = 100.0; } // FIXME dangerous
- if(distance>=0.0) {
- gfxReal dcnt=dvec[0];
- while(( dcnt< distance-dvec[0] )&&(i+1<mLevel[level].lSizex-1)) {
- dcnt += dvec[0]; i++;
- savedNodes++;
- if(ntype != CFInvalid) {
- // rho,mass,OId are still inited from above
- initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
- }
- }
- }
- // */
-
- }
- }
- } // zmax
- // */
-
- // now init fluid layer
- for(int k= getForZMin1(); k< getForZMax1(level); ++k) {
- for(int j=1;j<mLevel[level].lSizey-1;j++) {
- for(int i=1;i<mLevel[level].lSizex-1;i++) {
- if(!(RFLAG(level, i,j,k, mLevel[level].setCurr)==CFEmpty)) continue;
- ntype = CFInvalid;
- int inits = 0;
- GETPOS(i,j,k);
- const bool inside = geoInitCheckPointInside( ggpos, FGI_FLUID, OId, distance);
- if(inside) {
- ntype = CFFluid;
- }
- if(ntype != CFInvalid) {
- // initDefaultCell
- rhomass = 1.0;
- initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
- inits++;
- }
-
- // walk along x until hit for following inits
- if(distance<=-1.0) { distance = 100.0; }
- if(distance>=0.0) {
- gfxReal dcnt=dvec[0];
- while((dcnt< distance )&&(i+1<mLevel[level].lSizex-1)) {
- dcnt += dvec[0]; i++;
- savedNodes++;
- if(!(RFLAG(level, i,j,k, mLevel[level].setCurr)==CFEmpty)) continue;
- if(ntype != CFInvalid) {
- // rhomass are still inited from above
- initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
- inits++;
- }
- }
- } // distance>0
-
- }
- }
- } // zmax
-
- // reset invalid to empty again
- for(int k= getForZMin1(); k< getForZMax1(level); ++k) {
- for(int j=1;j<mLevel[level].lSizey-1;j++) {
- for(int i=1;i<mLevel[level].lSizex-1;i++) {
- if(RFLAG(level, i,j,k, mLevel[level].setCurr)==CFInvalid) {
- RFLAG(level, i,j,k, mLevel[level].setOther) =
- RFLAG(level, i,j,k, mLevel[level].setCurr) = CFEmpty;
- }
- }
- }
- }
-
- freeGeoTree();
- myTime_t geotimeend = getTime();
- debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Geometry init done ("<< getTimeString(geotimeend-geotimestart)<<","<<savedNodes<<") " , 10 );
- //errMsg(" SAVED "," "<<savedNodes<<" of "<<(mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez));
- return true;
-}
-
-#undef GETPOS
-
-/*****************************************************************************/
-/* init part for all freesurface testcases */
-void LbmFsgrSolver::initFreeSurfaces() {
- double interfaceFill = 0.45; // filling level of interface cells
- //interfaceFill = 1.0; // DEUG!! GEOMTEST!!!!!!!!!!!!
-
- // set interface cells
- FSGR_FORIJK1(mMaxRefine) {
- if( ( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFFluid )) {
- FORDF1 {
- int ni=i+dfVecX[l], nj=j+dfVecY[l], nk=k+dfVecZ[l];
- if( ( RFLAG(mMaxRefine, ni, nj, nk, mLevel[mMaxRefine].setCurr)& CFEmpty ) ) {
- LbmFloat arho=0., aux=0., auy=0., auz=0.;
- interpolateCellValues(mMaxRefine, ni,nj,nk, mLevel[mMaxRefine].setCurr, arho,aux,auy,auz);
- //errMsg("TINI"," "<<PRINT_VEC(ni,nj,nk)<<" v"<<LbmVec(aux,auy,auz) );
- // unnecessary? initEmptyCell(mMaxRefine, ni,nj,nk, CFInter, arho, interfaceFill);
- initVelocityCell(mMaxRefine, ni,nj,nk, CFInter, arho, interfaceFill, LbmVec(aux,auy,auz) );
- }
- }
- }
- }
-
- // remove invalid interface cells
- FSGR_FORIJK1(mMaxRefine) {
- // remove invalid interface cells
- if( ( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFInter) ) {
- int delit = 0;
- int NBs = 0; // neighbor flags or'ed
- int noEmptyNB = 1;
-
- FORDF1 {
- if( ( RFLAG_NBINV(mMaxRefine, i, j, k, mLevel[mMaxRefine].setCurr,l )& CFEmpty ) ) {
- noEmptyNB = 0;
- }
- NBs |= RFLAG_NBINV(mMaxRefine, i, j, k, mLevel[mMaxRefine].setCurr, l);
- }
- // remove cells with no fluid or interface neighbors
- if((NBs & CFFluid)==0) { delit = 1; }
- if((NBs & CFInter)==0) { delit = 1; }
- // remove cells with no empty neighbors
- if(noEmptyNB) { delit = 2; }
-
- // now we can remove the cell
- if(delit==1) {
- initEmptyCell(mMaxRefine, i,j,k, CFEmpty, 1.0, 0.0);
- }
- if(delit==2) {
- //initEmptyCell(mMaxRefine, i,j,k, CFFluid, 1.0, 1.0);
- LbmFloat arho=0., aux=0., auy=0., auz=0.;
- interpolateCellValues(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, arho,aux,auy,auz);
- initVelocityCell(mMaxRefine, i,j,k, CFFluid, arho,1., LbmVec(aux,auy,auz) );
- }
- } // interface
- } // */
-
- // another brute force init, make sure the fill values are right...
- // and make sure both sets are equal
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- if( (RFLAG(lev, i,j,k,0) & (CFBnd)) ) {
- QCELL(lev, i,j,k,mLevel[mMaxRefine].setCurr, dFfrac) = BND_FILL;
- continue;
- }
- if( (RFLAG(lev, i,j,k,0) & (CFEmpty)) ) {
- QCELL(lev, i,j,k,mLevel[mMaxRefine].setCurr, dFfrac) = 0.0;
- continue;
- }
- } }
-
- // ----------------------------------------------------------------------
- // smoother surface...
- if(mInitSurfaceSmoothing>0) {
- debMsgStd("Surface Smoothing init", DM_MSG, "Performing "<<(mInitSurfaceSmoothing)<<" smoothing timestep ",10);
-#if COMPRESSGRIDS==1
- //errFatal("NYI","COMPRESSGRIDS mInitSurfaceSmoothing",SIMWORLD_INITERROR); return;
-#endif // COMPRESSGRIDS==0
- }
- for(int s=0; s<mInitSurfaceSmoothing; s++) {
- //SGR_FORIJK1(mMaxRefine) {
-
- int kstart=getForZMin1(), kend=getForZMax1(mMaxRefine);
- int lev = mMaxRefine;
-#if COMPRESSGRIDS==0
- for(int k=kstart;k<kend;++k) {
-#else // COMPRESSGRIDS==0
- int kdir = 1; // COMPRT ON
- if(mLevel[lev].setCurr==1) {
- kdir = -1;
- int temp = kend;
- kend = kstart-1;
- kstart = temp-1;
- } // COMPRT
- for(int k=kstart;k!=kend;k+=kdir) {
-#endif // COMPRESSGRIDS==0
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
- if( ( RFLAG(lev, i,j,k, mLevel[lev].setCurr)& CFInter) ) {
- LbmFloat mass = 0.0;
- //LbmFloat nbdiv;
- //FORDF0 {
- for(int l=0;(l<cDirNum); l++) {
- int ni=i+dfVecX[l], nj=j+dfVecY[l], nk=k+dfVecZ[l];
- if( RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr) & CFFluid ){
- mass += 1.0;
- }
- if( RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr) & CFInter ){
- mass += QCELL(lev, ni,nj,nk, mLevel[lev].setCurr, dMass);
- }
- //nbdiv+=1.0;
- }
-
- //errMsg(" I ", PRINT_IJK<<" m"<<mass );
- QCELL(lev, i,j,k, mLevel[lev].setOther, dMass) = (mass/ ((LbmFloat)cDirNum) );
- QCELL(lev, i,j,k, mLevel[lev].setOther, dFfrac) = QCELL(lev, i,j,k, mLevel[lev].setOther, dMass);
- }
- }}}
-
- mLevel[lev].setOther = mLevel[lev].setCurr;
- mLevel[lev].setCurr ^= 1;
- }
- // copy back...?
-}
-
-/*****************************************************************************/
-/* init part for all freesurface testcases */
-void LbmFsgrSolver::initStandingFluidGradient() {
- // ----------------------------------------------------------------------
- // standing fluid preinit
- const int debugStandingPreinit = 0;
- int haveStandingFluid = 0;
-
-#define STANDFLAGCHECK(iindex) \
- if( ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFInter)) ) || \
- ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFEmpty)) ) ){ \
- if((iindex)>1) { haveStandingFluid=(iindex); } \
- j = mLevel[mMaxRefine].lSizey; i=mLevel[mMaxRefine].lSizex; k=getForZMaxBnd(); \
- continue; \
- }
- int gravIndex[3] = {0,0,0};
- int gravDir[3] = {1,1,1};
- int maxGravComp = 1; // by default y
- int gravComp1 = 0; // by default y
- int gravComp2 = 2; // by default y
- if( ABS(mLevel[mMaxRefine].gravity[0]) > ABS(mLevel[mMaxRefine].gravity[1]) ){ maxGravComp = 0; gravComp1=1; gravComp2=2; }
- if( ABS(mLevel[mMaxRefine].gravity[2]) > ABS(mLevel[mMaxRefine].gravity[0]) ){ maxGravComp = 2; gravComp1=0; gravComp2=1; }
-
- int gravIMin[3] = { 0 , 0 , 0 };
- int gravIMax[3] = {
- mLevel[mMaxRefine].lSizex + 0,
- mLevel[mMaxRefine].lSizey + 0,
- mLevel[mMaxRefine].lSizez + 0 };
- if(LBMDIM==2) gravIMax[2] = 1;
-
- //int gravDir = 1;
- if( mLevel[mMaxRefine].gravity[maxGravComp] > 0.0 ) {
- // swap directions
- int i=maxGravComp;
- int tmp = gravIMin[i];
- gravIMin[i] = gravIMax[i] - 1;
- gravIMax[i] = tmp - 1;
- gravDir[i] = -1;
- }
-#define PRINTGDIRS \
- errMsg("Standing fp","X start="<<gravIMin[0]<<" end="<<gravIMax[0]<<" dir="<<gravDir[0] ); \
- errMsg("Standing fp","Y start="<<gravIMin[1]<<" end="<<gravIMax[1]<<" dir="<<gravDir[1] ); \
- errMsg("Standing fp","Z start="<<gravIMin[2]<<" end="<<gravIMax[2]<<" dir="<<gravDir[2] );
- // _PRINTGDIRS;
-
- bool gravAbort = false;
-#define GRAVLOOP \
- gravAbort=false; \
- for(gravIndex[2]= gravIMin[2]; (gravIndex[2]!=gravIMax[2])&&(!gravAbort); gravIndex[2] += gravDir[2]) \
- for(gravIndex[1]= gravIMin[1]; (gravIndex[1]!=gravIMax[1])&&(!gravAbort); gravIndex[1] += gravDir[1]) \
- for(gravIndex[0]= gravIMin[0]; (gravIndex[0]!=gravIMax[0])&&(!gravAbort); gravIndex[0] += gravDir[0])
-
- GRAVLOOP {
- int i = gravIndex[0], j = gravIndex[1], k = gravIndex[2];
- if( ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFInter)) ) ||
- ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFBndMoving)) ) ||
- ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFEmpty)) ) ) {
- int fluidHeight = (ABS(gravIndex[maxGravComp] - gravIMin[maxGravComp]));
- if(debugStandingPreinit) errMsg("Standing fp","fh="<<fluidHeight<<" gmax="<<gravIMax[maxGravComp]<<" gi="<<gravIndex[maxGravComp] );
- if(fluidHeight>1) {
- haveStandingFluid = fluidHeight; //gravIndex[maxGravComp];
- gravIMax[maxGravComp] = gravIndex[maxGravComp] + gravDir[maxGravComp];
- }
- gravAbort = true; continue;
- }
- } // GRAVLOOP
- // _PRINTGDIRS;
-
- LbmFloat fluidHeight;
- fluidHeight = (LbmFloat)(ABS(gravIMax[maxGravComp]-gravIMin[maxGravComp]));
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(mUseTestdata) mpTest->mFluidHeight = (int)fluidHeight;
-#endif // ELBEEM_PLUGIN!=1
- if(debugStandingPreinit) debMsgStd("Standing fluid preinit", DM_MSG, "fheight="<<fluidHeight<<" min="<<PRINT_VEC(gravIMin[0],gravIMin[1], gravIMin[2])<<" max="<<PRINT_VEC(gravIMax[0], gravIMax[1],gravIMax[2])<<
- " mgc="<<maxGravComp<<" mc1="<<gravComp1<<" mc2="<<gravComp2<<" dir="<<gravDir[maxGravComp]<<" have="<<haveStandingFluid ,10);
-
- if(mDisableStandingFluidInit) {
- debMsgStd("Standing fluid preinit", DM_MSG, "Should be performed - but skipped due to mDisableStandingFluidInit flag set!", 2);
- haveStandingFluid=0;
- }
-
- // copy flags and init , as no flags will be changed during grav init
- // also important for corasening later on
- const int lev = mMaxRefine;
- CellFlagType nbflag[LBM_DFNUM], nbored;
- for(int k=getForZMinBnd();k<getForZMaxBnd(mMaxRefine);++k) {
- for(int j=0;j<mLevel[lev].lSizey-0;++j) {
- for(int i=0;i<mLevel[lev].lSizex-0;++i) {
- if( (RFLAG(lev, i,j,k,SRCS(lev)) & (CFFluid)) ) {
- nbored = 0;
- FORDF1 {
- nbflag[l] = RFLAG_NB(lev, i,j,k, SRCS(lev),l);
- nbored |= nbflag[l];
- }
- if(nbored&CFBnd) {
- RFLAG(lev, i,j,k,SRCS(lev)) &= (~CFNoBndFluid);
- } else {
- RFLAG(lev, i,j,k,SRCS(lev)) |= CFNoBndFluid;
- }
- }
- RFLAG(lev, i,j,k,TSET(lev)) = RFLAG(lev, i,j,k,SRCS(lev));
- } } }
-
- if(haveStandingFluid) {
- int rhoworkSet = mLevel[lev].setCurr;
- myTime_t timestart = getTime(); // FIXME use user time here?
-
- GRAVLOOP {
- int i = gravIndex[0], j = gravIndex[1], k = gravIndex[2];
- //debMsgStd("Standing fluid preinit", DM_MSG, " init check "<<PRINT_IJK<<" "<< haveStandingFluid, 1 );
- if( ( (RFLAG(lev, i,j,k,rhoworkSet) & (CFInter)) ) ||
- ( (RFLAG(lev, i,j,k,rhoworkSet) & (CFEmpty)) ) ){
- //gravAbort = true;
- continue;
- }
-
- LbmFloat rho = 1.0;
- // 1/6 velocity from denisty gradient, 1/2 for delta of two cells
- rho += 1.0* (fluidHeight-gravIndex[maxGravComp]) *
- (mLevel[lev].gravity[maxGravComp])* (-3.0/1.0)*(mLevel[lev].omega);
- if(debugStandingPreinit)
- if((gravIndex[gravComp1]==gravIMin[gravComp1]) && (gravIndex[gravComp2]==gravIMin[gravComp2])) {
- errMsg("Standing fp","gi="<<gravIndex[maxGravComp]<<" rho="<<rho<<" at "<<PRINT_IJK);
- }
-
- if( (RFLAG(lev, i,j,k, rhoworkSet) & CFFluid) ||
- (RFLAG(lev, i,j,k, rhoworkSet) & CFInter) ) {
- FORDF0 { QCELL(lev, i,j,k, rhoworkSet, l) *= rho; }
- QCELL(lev, i,j,k, rhoworkSet, dMass) *= rho;
- }
-
- } // GRAVLOOP
-
- debMsgStd("Standing fluid preinit", DM_MSG, "Density gradient inited (max-rho:"<<
- (1.0+ (fluidHeight) * (mLevel[lev].gravity[maxGravComp])* (-3.0/1.0)*(mLevel[lev].omega)) <<", h:"<< fluidHeight<<") ", 8);
-
- int preinitSteps = (haveStandingFluid* ((mLevel[lev].lSizey+mLevel[lev].lSizez+mLevel[lev].lSizex)/3) );
- preinitSteps = (haveStandingFluid>>2); // not much use...?
- //preinitSteps = 0;
- debMsgStd("Standing fluid preinit", DM_MSG, "Performing "<<preinitSteps<<" prerelaxations ",10);
- for(int s=0; s<preinitSteps; s++) {
- // in solver main cpp
- standingFluidPreinit();
- }
-
- myTime_t timeend = getTime();
- debMsgStd("Standing fluid preinit", DM_MSG, " done, "<<getTimeString(timeend-timestart), 9);
-#undef NBFLAG
- }
-}
-
-
-
-bool LbmFsgrSolver::checkSymmetry(string idstring)
-{
- bool erro = false;
- bool symm = true;
- int msgs = 0;
- const int maxMsgs = 10;
- const bool markCells = false;
-
- //for(int lev=0; lev<=mMaxRefine; lev++) {
- { int lev = mMaxRefine;
-
- // no point if not symm.
- if( (mLevel[lev].lSizex==mLevel[lev].lSizey) && (mLevel[lev].lSizex==mLevel[lev].lSizez)) {
- // ok
- } else {
- return false;
- }
-
- for(int s=0; s<2; s++) {
- FSGR_FORIJK1(lev) {
- if(i<(mLevel[lev].lSizex/2)) {
- int inb = (mLevel[lev].lSizey-1-i);
-
- if(lev==mMaxRefine) inb -= 1; // FSGR_SYMM_T
-
- if( RFLAG(lev, i,j,k,s) != RFLAG(lev, inb,j,k,s) ) { erro = true;
- if(LBMDIM==2) {
- if(msgs<maxMsgs) { msgs++;
- errMsg("EFLAG", PRINT_IJK<<"s"<<s<<" flag "<<RFLAG(lev, i,j,k,s)<<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" flag "<<RFLAG(lev, inb,j,k,s) );
- }
- }
- if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
- symm = false;
- }
- if( LBM_FLOATNEQ(QCELL(lev, i,j,k,s, dMass), QCELL(lev, inb,j,k,s, dMass)) ) { erro = true;
- if(LBMDIM==2) {
- if(msgs<maxMsgs) { msgs++;
- //debMsgDirect(" mass1 "<<QCELL(lev, i,j,k,s, dMass)<<" mass2 "<<QCELL(lev, inb,j,k,s, dMass) <<std::endl);
- errMsg("EMASS", PRINT_IJK<<"s"<<s<<" mass "<<QCELL(lev, i,j,k,s, dMass)<<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" mass "<<QCELL(lev, inb,j,k,s, dMass) );
- }
- }
- if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
- symm = false;
- }
-
- LbmFloat nbrho = QCELL(lev, i,j,k, s, dC);
- FORDF1 { nbrho += QCELL(lev, i,j,k, s, l); }
- LbmFloat otrho = QCELL(lev, inb,j,k, s, dC);
- FORDF1 { otrho += QCELL(lev, inb,j,k, s, l); }
- if( LBM_FLOATNEQ(nbrho, otrho) ) { erro = true;
- if(LBMDIM==2) {
- if(msgs<maxMsgs) { msgs++;
- //debMsgDirect(" rho 1 "<<nbrho <<" rho 2 "<<otrho <<std::endl);
- errMsg("ERHO ", PRINT_IJK<<"s"<<s<<" rho "<<nbrho <<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" rho "<<otrho );
- }
- }
- if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
- symm = false;
- }
- }
- } }
- } // lev
- LbmFloat maxdiv =0.0;
- if(erro) {
- errMsg("SymCheck Failed!", idstring<<" rho maxdiv:"<< maxdiv );
- //if(LBMDIM==2) mPanic = true;
- //return false;
- } else {
- errMsg("SymCheck OK!", idstring<<" rho maxdiv:"<< maxdiv );
- }
- // all ok...
- return symm;
-}// */
-
-
-void
-LbmFsgrSolver::interpolateCellValues(
- int level,int ei,int ej,int ek,int workSet,
- LbmFloat &retrho, LbmFloat &retux, LbmFloat &retuy, LbmFloat &retuz)
-{
- LbmFloat avgrho = 0.0;
- LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0;
- LbmFloat cellcnt = 0.0;
-
- for(int nbl=1; nbl< cDfNum ; ++nbl) {
- if(RFLAG_NB(level,ei,ej,ek,workSet,nbl) & CFNoInterpolSrc) continue;
- if( (RFLAG_NB(level,ei,ej,ek,workSet,nbl) & (CFFluid|CFInter)) ){
- //((!(RFLAG_NB(level,ei,ej,ek,workSet,nbl) & CFNoInterpolSrc) ) &&
- //(RFLAG_NB(level,ei,ej,ek,workSet,nbl) & CFInter) ) {
- cellcnt += 1.0;
- for(int rl=0; rl< cDfNum ; ++rl) {
- LbmFloat nbdf = QCELL_NB(level,ei,ej,ek, workSet,nbl, rl);
- avgux += (dfDvecX[rl]*nbdf);
- avguy += (dfDvecY[rl]*nbdf);
- avguz += (dfDvecZ[rl]*nbdf);
- avgrho += nbdf;
- }
- }
- }
-
- if(cellcnt<=0.0) {
- // no nbs? just use eq.
- avgrho = 1.0;
- avgux = avguy = avguz = 0.0;
- //TTT mNumProblems++;
-#if ELBEEM_PLUGIN!=1
- //mPanic=1;
- // this can happen for worst case moving obj scenarios...
- errMsg("LbmFsgrSolver::interpolateCellValues","Cellcnt<=0.0 at "<<PRINT_VEC(ei,ej,ek));
-#endif // ELBEEM_PLUGIN
- } else {
- // init speed
- avgux /= cellcnt; avguy /= cellcnt; avguz /= cellcnt;
- avgrho /= cellcnt;
- }
-
- retrho = avgrho;
- retux = avgux;
- retuy = avguy;
- retuz = avguz;
-} // interpolateCellValues
-
-
-/******************************************************************************
- * instantiation
- *****************************************************************************/
-
-//! lbm factory functions
-LbmSolverInterface* createSolver() { return new LbmFsgrSolver(); }
-
-
diff --git a/intern/elbeem/intern/solver_interface.cpp b/intern/elbeem/intern/solver_interface.cpp
deleted file mode 100644
index 7f8fe9256e1..00000000000
--- a/intern/elbeem/intern/solver_interface.cpp
+++ /dev/null
@@ -1,753 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Combined 2D/3D Lattice Boltzmann Interface Class
- * contains stuff to be statically compiled
- *
- *****************************************************************************/
-
-/* LBM Files */
-#include "ntl_matrices.h"
-#include "solver_interface.h"
-#include "ntl_ray.h"
-#include "ntl_world.h"
-#include "elbeem.h"
-
-
-
-
-/******************************************************************************
- * Interface Constructor
- *****************************************************************************/
-LbmSolverInterface::LbmSolverInterface() :
- mPanic( false ),
- mSizex(10), mSizey(10), mSizez(10),
- mAllfluid(false), mStepCnt( 0 ),
- mFixMass( 0.0 ),
- mOmega( 1.0 ),
- mGravity(0.0),
- mSurfaceTension( 0.0 ),
- mBoundaryEast( (CellFlagType)(CFBnd) ),mBoundaryWest( (CellFlagType)(CFBnd) ),mBoundaryNorth( (CellFlagType)(CFBnd) ),
- mBoundarySouth( (CellFlagType)(CFBnd) ),mBoundaryTop( (CellFlagType)(CFBnd) ),mBoundaryBottom( (CellFlagType)(CFBnd) ),
- mInitDone( false ),
- mInitDensityGradient( false ),
- mpSifAttrs( NULL ), mpSifSwsAttrs(NULL), mpParam( NULL ), mpParticles(NULL),
- mNumParticlesLost(0),
- mNumInvalidDfs(0), mNumFilledCells(0), mNumEmptiedCells(0), mNumUsedCells(0), mMLSUPS(0),
- mDebugVelScale( 0.01 ), mNodeInfoString("+"),
- mvGeoStart(-1.0), mvGeoEnd(1.0), mpSimTrafo(NULL),
- mAccurateGeoinit(0),
- mName("lbm_default") ,
- mpIso( NULL ), mIsoValue(0.499),
- mSilent(false) ,
- mLbmInitId(1) ,
- mpGiTree( NULL ),
- mpGiObjects( NULL ), mGiObjInside(), mpGlob( NULL ),
- mRefinementDesired(0),
- mOutputSurfacePreview(0), mPreviewFactor(0.25),
- mSmoothSurface(1.0), mSmoothNormals(1.0),
- mIsoSubdivs(1), mPartGenProb(0.),
- mDumpVelocities(false),
- mMarkedCells(), mMarkedCellIndex(0),
- mDomainBound("noslip"), mDomainPartSlipValue(0.1),
- mFarFieldSize(0.),
- mPartDropMassSub(0.1), // good default
- mPartUsePhysModel(false),
- mTForceStrength(0.0),
- mCppfStage(0),
- mDumpRawText(false),
- mDumpRawBinary(false),
- mDumpRawBinaryZip(true)
-#if PARALLEL==1
- , mNumOMPThreads(1)
-#endif // PARALLEL==1
-{
-#if ELBEEM_PLUGIN==1
- if(gDebugLevel<=1) setSilent(true);
-#endif
- mpSimTrafo = new ntlMat4Gfx(0.0);
- mpSimTrafo->initId();
-
- if(getenv("ELBEEM_RAWDEBUGDUMP")) {
- debMsgStd("LbmSolverInterface",DM_MSG,"Using env var ELBEEM_RAWDEBUGDUMP, mDumpRawText on",2);
- mDumpRawText = true;
- }
-
- if(getenv("ELBEEM_BINDEBUGDUMP")) {
- debMsgStd("LbmSolverInterface",DM_MSG,"Using env var ELBEEM_RAWDEBUGDUMP, mDumpRawText on",2);
- mDumpRawBinary = true;
- }
-}
-
-LbmSolverInterface::~LbmSolverInterface()
-{
- if(mpSimTrafo) delete mpSimTrafo;
-}
-
-
-/******************************************************************************
- * initialize correct grid sizes given a geometric bounding box
- * and desired grid resolutions, all params except maxrefine
- * will be modified
- *****************************************************************************/
-void initGridSizes(int &sizex, int &sizey, int &sizez,
- ntlVec3Gfx &geoStart, ntlVec3Gfx &geoEnd,
- int mMaxRefine, bool parallel)
-{
- // fix size inits to force cubic cells and mult4 level dimensions
- const int debugGridsizeInit = 1;
- if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Called - size X:"<<sizex<<" Y:"<<sizey<<" Z:"<<sizez<<" "<<geoStart<<","<<geoEnd ,10);
-
- int maxGridSize = sizex; // get max size
- if(sizey>maxGridSize) maxGridSize = sizey;
- if(sizez>maxGridSize) maxGridSize = sizez;
- LbmFloat maxGeoSize = (geoEnd[0]-geoStart[0]); // get max size
- if((geoEnd[1]-geoStart[1])>maxGeoSize) maxGeoSize = (geoEnd[1]-geoStart[1]);
- if((geoEnd[2]-geoStart[2])>maxGeoSize) maxGeoSize = (geoEnd[2]-geoStart[2]);
- // FIXME better divide max geo size by corresponding resolution rather than max? no prob for rx==ry==rz though
- LbmFloat cellSize = (maxGeoSize / (LbmFloat)maxGridSize);
- if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Start:"<<geoStart<<" End:"<<geoEnd<<" maxS:"<<maxGeoSize<<" maxG:"<<maxGridSize<<" cs:"<<cellSize, 10);
- // force grid sizes according to geom. size, rounded
- sizex = (int) ((geoEnd[0]-geoStart[0]) / cellSize +0.5);
- sizey = (int) ((geoEnd[1]-geoStart[1]) / cellSize +0.5);
- sizez = (int) ((geoEnd[2]-geoStart[2]) / cellSize +0.5);
- // match refinement sizes, round downwards to multiple of 4
- int sizeMask = 0;
- int maskBits = mMaxRefine;
- if(parallel==1) maskBits+=2;
- for(int i=0; i<maskBits; i++) { sizeMask |= (1<<i); }
-
- // at least size 4 on coarsest level
- int minSize = 4<<mMaxRefine; //(maskBits+2);
- if(sizex<minSize) sizex = minSize;
- if(sizey<minSize) sizey = minSize;
- if(sizez<minSize) sizez = minSize;
-
- sizeMask = ~sizeMask;
- if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Size X:"<<sizex<<" Y:"<<sizey<<" Z:"<<sizez<<" m"<<convertFlags2String(sizeMask)<<", maskBits:"<<maskBits<<",minSize:"<<minSize ,10);
- sizex &= sizeMask;
- sizey &= sizeMask;
- sizez &= sizeMask;
- // debug
- int nextinc = (~sizeMask)+1;
- debMsgStd("initGridSizes",DM_MSG,"MPTeffMLtest, curr size:"<<PRINT_VEC(sizex,sizey,sizez)<<", next size:"<<PRINT_VEC(sizex+nextinc,sizey+nextinc,sizez+nextinc) ,10);
-
- // force geom size to match rounded/modified grid sizes
- geoEnd[0] = geoStart[0] + cellSize*(LbmFloat)sizex;
- geoEnd[1] = geoStart[1] + cellSize*(LbmFloat)sizey;
- geoEnd[2] = geoStart[2] + cellSize*(LbmFloat)sizez;
-}
-
-void calculateMemreqEstimate( int resx,int resy,int resz,
- int refine, float farfield,
- double *reqret, double *reqretFine, string *reqstr) {
- // debug estimation?
- const bool debugMemEst = true;
- // COMPRESSGRIDS define is not available here, make sure it matches
- const bool useGridComp = true;
- // make sure we can handle bid numbers here... all double
- double memCnt = 0.0;
- double ddTotalNum = (double)dTotalNum;
- if(reqretFine) *reqretFine = -1.;
-
- double currResx = (double)resx;
- double currResy = (double)resy;
- double currResz = (double)resz;
- double rcellSize = ((currResx*currResy*currResz) *ddTotalNum);
- memCnt += (double)(sizeof(CellFlagType) * (rcellSize/ddTotalNum +4.0) *2.0);
- if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"res:"<<PRINT_VEC(currResx,currResy,currResz)<<" rcellSize:"<<rcellSize<<" mc:"<<memCnt, 10);
- if(!useGridComp) {
- memCnt += (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
- if(reqretFine) *reqretFine = (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
- if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG," no-comp, mc:"<<memCnt, 10);
- } else {
- double compressOffset = (double)(currResx*currResy*ddTotalNum*2.0);
- memCnt += (double)(sizeof(LbmFloat) * (rcellSize+compressOffset +4.0));
- if(reqretFine) *reqretFine = (double)(sizeof(LbmFloat) * (rcellSize+compressOffset +4.0));
- if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG," w-comp, mc:"<<memCnt, 10);
- }
- for(int i=refine-1; i>=0; i--) {
- currResx /= 2.0;
- currResy /= 2.0;
- currResz /= 2.0;
- rcellSize = ((currResz*currResy*currResx) *ddTotalNum);
- memCnt += (double)(sizeof(CellFlagType) * (rcellSize/ddTotalNum +4.0) *2.0);
- memCnt += (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
- if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"refine "<<i<<", mc:"<<memCnt, 10);
- }
-
- // isosurface memory, use orig res values
- if(farfield>0.) {
- memCnt += (double)( (3*sizeof(int)+sizeof(float)) * ((resx+2)*(resy+2)*(resz+2)) );
- } else {
- // ignore 3 int slices...
- memCnt += (double)( ( sizeof(float)) * ((resx+2)*(resy+2)*(resz+2)) );
- }
- if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"iso, mc:"<<memCnt, 10);
-
- // cpdata init check missing...
-
- double memd = memCnt;
- const char *sizeStr = "";
- const double sfac = 1024.0;
- if(memd>sfac){ memd /= sfac; sizeStr="KB"; }
- if(memd>sfac){ memd /= sfac; sizeStr="MB"; }
- if(memd>sfac){ memd /= sfac; sizeStr="GB"; }
- if(memd>sfac){ memd /= sfac; sizeStr="TB"; }
-
- // return values
- std::ostringstream ret;
- if(memCnt< 1024.0*1024.0) {
- // show full MBs
- ret << (ceil(memd));
- } else {
- // two digits for anything larger than MB
- ret << (ceil(memd*100.0)/100.0);
- }
- ret << " "<< sizeStr;
- *reqret = memCnt;
- *reqstr = ret.str();
- //debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Required Grid memory: "<< memd <<" "<< sizeStr<<" ",4);
-}
-
-void LbmSolverInterface::initDomainTrafo(float *mat) {
- mpSimTrafo->initArrayCheck(mat);
-}
-
-/*******************************************************************************/
-/*! parse a boundary flag string */
-CellFlagType LbmSolverInterface::readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed) {
- string val = mpSifAttrs->readString(name, "", source, target, needed);
- if(!strcmp(val.c_str(),"")) {
- // no value given...
- return CFEmpty;
- }
- if(!strcmp(val.c_str(),"bnd_no")) {
- return (CellFlagType)( CFBnd );
- }
- if(!strcmp(val.c_str(),"bnd_free")) {
- return (CellFlagType)( CFBnd );
- }
- if(!strcmp(val.c_str(),"fluid")) {
- /* might be used for some in/out flow cases */
- return (CellFlagType)( CFFluid );
- }
- errMsg("LbmSolverInterface::readBoundaryFlagInt","Invalid value '"<<val<<"' " );
-# if FSGR_STRICT_DEBUG==1
- errFatal("readBoundaryFlagInt","Strict abort..."<<val, SIMWORLD_INITERROR);
-# endif
- return defaultValue;
-}
-
-/*******************************************************************************/
-/*! parse standard attributes */
-void LbmSolverInterface::parseStdAttrList() {
- if(!mpSifAttrs) {
- errFatal("LbmSolverInterface::parseAttrList","mpSifAttrs pointer not initialized!",SIMWORLD_INITERROR);
- return; }
-
- // st currently unused
- mBoundaryEast = readBoundaryFlagInt("boundary_east", mBoundaryEast, "LbmSolverInterface", "mBoundaryEast", false);
- mBoundaryWest = readBoundaryFlagInt("boundary_west", mBoundaryWest, "LbmSolverInterface", "mBoundaryWest", false);
- mBoundaryNorth = readBoundaryFlagInt("boundary_north", mBoundaryNorth,"LbmSolverInterface", "mBoundaryNorth", false);
- mBoundarySouth = readBoundaryFlagInt("boundary_south", mBoundarySouth,"LbmSolverInterface", "mBoundarySouth", false);
- mBoundaryTop = readBoundaryFlagInt("boundary_top", mBoundaryTop,"LbmSolverInterface", "mBoundaryTop", false);
- mBoundaryBottom= readBoundaryFlagInt("boundary_bottom", mBoundaryBottom,"LbmSolverInterface", "mBoundaryBottom", false);
-
- mpSifAttrs->readMat4Gfx("domain_trafo" , (*mpSimTrafo), "ntlBlenderDumper","mpSimTrafo", false, mpSimTrafo );
-
- LbmVec sizeVec(mSizex,mSizey,mSizez);
- sizeVec = vec2L( mpSifAttrs->readVec3d("size", vec2P(sizeVec), "LbmSolverInterface", "sizeVec", false) );
- mSizex = (int)sizeVec[0];
- mSizey = (int)sizeVec[1];
- mSizez = (int)sizeVec[2];
- // param needs size in any case
- // test solvers might not have mpPara, though
- if(mpParam) mpParam->setSize(mSizex, mSizey, mSizez );
-
- mInitDensityGradient = mpSifAttrs->readBool("initdensitygradient", mInitDensityGradient,"LbmSolverInterface", "mInitDensityGradient", false);
- mIsoValue = mpSifAttrs->readFloat("isovalue", mIsoValue, "LbmOptSolver","mIsoValue", false );
-
- mDebugVelScale = mpSifAttrs->readFloat("debugvelscale", mDebugVelScale,"LbmSolverInterface", "mDebugVelScale", false);
- mNodeInfoString = mpSifAttrs->readString("nodeinfo", mNodeInfoString, "SimulationLbm","mNodeInfoString", false );
-
- mDumpVelocities = mpSifAttrs->readBool("dump_velocities", mDumpVelocities, "SimulationLbm","mDumpVelocities", false );
- if(getenv("ELBEEM_DUMPVELOCITIES")) {
- int get = atoi(getenv("ELBEEM_DUMPVELOCITIES"));
- if((get==0)||(get==1)) {
- mDumpVelocities = get;
- debMsgStd("LbmSolverInterface::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_DUMPVELOCITIES to set mDumpVelocities to "<<get<<","<<mDumpVelocities,8);
- }
- }
-
- // new test vars
- // mTForceStrength set from test solver
- mFarFieldSize = mpSifAttrs->readFloat("farfieldsize", mFarFieldSize,"LbmSolverInterface", "mFarFieldSize", false);
- // old compat
- float sizeScale = mpSifAttrs->readFloat("test_scale", 0.,"LbmTestdata", "mSizeScale", false);
- if((mFarFieldSize<=0.)&&(sizeScale>0.)) { mFarFieldSize=sizeScale; errMsg("LbmTestdata","Warning - using mSizeScale..."); }
-
- mPartDropMassSub = mpSifAttrs->readFloat("part_dropmass", mPartDropMassSub,"LbmSolverInterface", "mPartDropMassSub", false);
-
- mCppfStage = mpSifAttrs->readInt("cppfstage", mCppfStage,"LbmSolverInterface", "mCppfStage", false);
- mPartGenProb = mpSifAttrs->readFloat("partgenprob", mPartGenProb,"LbmFsgrSolver", "mPartGenProb", false);
- mPartUsePhysModel = mpSifAttrs->readBool("partusephysmodel", mPartUsePhysModel,"LbmFsgrSolver", "mPartUsePhysModel", false);
- mIsoSubdivs = mpSifAttrs->readInt("isosubdivs", mIsoSubdivs,"LbmFsgrSolver", "mIsoSubdivs", false);
-}
-
-
-/*******************************************************************************/
-/*! geometry initialization */
-/*******************************************************************************/
-
-/*****************************************************************************/
-/*! init tree for certain geometry init */
-void LbmSolverInterface::initGeoTree() {
- if(mpGlob == NULL) { errFatal("LbmSolverInterface::initGeoTree","Requires globals!",SIMWORLD_INITERROR); return; }
- ntlScene *scene = mpGlob->getSimScene();
- mpGiObjects = scene->getObjects();
- mGiObjInside.resize( mpGiObjects->size() );
- mGiObjDistance.resize( mpGiObjects->size() );
- mGiObjSecondDist.resize( mpGiObjects->size() );
- for(size_t i=0; i<mpGiObjects->size(); i++) {
- if((*mpGiObjects)[i]->getGeoInitIntersect()) mAccurateGeoinit=true;
- //debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"id:"<<mLbmInitId<<" obj:"<< (*mpGiObjects)[i]->getName() <<" gid:"<<(*mpGiObjects)[i]->getGeoInitId(), 9 );
- }
- debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"Accurate geo init: "<<mAccurateGeoinit, 9)
- debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"Objects: "<<mpGiObjects->size() ,10);
-
- if(mpGiTree != NULL) delete mpGiTree;
- char treeFlag = (1<<(this->mLbmInitId+4));
- mpGiTree = new ntlTree(
-# if FSGR_STRICT_DEBUG!=1
- 15, 8, // TREEwarning - fixed values for depth & maxtriangles here...
-# else // FSGR_STRICT_DEBUG==1
- 10, 20, // reduced/slower debugging values
-# endif // FSGR_STRICT_DEBUG==1
- scene, treeFlag );
-}
-
-/*****************************************************************************/
-/*! destroy tree etc. when geometry init done */
-void LbmSolverInterface::freeGeoTree() {
- if(mpGiTree != NULL) {
- delete mpGiTree;
- mpGiTree = NULL;
- }
-}
-
-
-int globGeoInitDebug = 0;
-int globGICPIProblems = 0;
-/*****************************************************************************/
-/*! check for a certain flag type at position org */
-bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance, int shootDir) {
- // shift ve ctors to avoid rounding errors
- org += ntlVec3Gfx(0.0001);
- OId = -1;
-
- // select shooting direction
- ntlVec3Gfx dir = ntlVec3Gfx(1., 0., 0.);
- if(shootDir==1) dir = ntlVec3Gfx(0., 1., 0.);
- else if(shootDir==2) dir = ntlVec3Gfx(0., 0., 1.);
- else if(shootDir==-2) dir = ntlVec3Gfx(0., 0., -1.);
- else if(shootDir==-1) dir = ntlVec3Gfx(0., -1., 0.);
-
- ntlRay ray(org, dir, 0, 1.0, mpGlob);
- bool done = false;
- bool inside = false;
-
- vector<int> giObjFirstHistSide;
- giObjFirstHistSide.resize( mpGiObjects->size() );
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- mGiObjInside[i] = 0;
- mGiObjDistance[i] = -1.0;
- mGiObjSecondDist[i] = -1.0;
- giObjFirstHistSide[i] = 0;
- }
- // if not inside, return distance to first hit
- gfxReal firstHit=-1.0;
- int firstOId = -1;
- if(globGeoInitDebug) errMsg("IIIstart"," isect "<<org<<" f"<<flags<<" acc"<<mAccurateGeoinit);
-
- if(mAccurateGeoinit) {
- while(!done) {
- // find first inside intersection
- ntlTriangle *triIns = NULL;
- distance = -1.0;
- ntlVec3Gfx normal(0.0);
- if(shootDir==0) mpGiTree->intersectX(ray,distance,normal, triIns, flags, true);
- else mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
- if(triIns) {
- ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
- LbmFloat orientation = dot(normal, dir);
- OId = triIns->getObjectId();
- if(orientation<=0.0) {
- // outside hit
- normal *= -1.0;
- mGiObjInside[OId]++;
- if(giObjFirstHistSide[OId]==0) giObjFirstHistSide[OId] = 1;
- if(globGeoInitDebug) errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation);
- } else {
- // inside hit
- mGiObjInside[OId]++;
- if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
- if(globGeoInitDebug) errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation);
- if(giObjFirstHistSide[OId]==0) giObjFirstHistSide[OId] = -1;
- }
- norg += normal * getVecEpsilon();
- ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
- // remember first hit distance, in case we're not
- // inside anything
- if(firstHit<0.0) {
- firstHit = distance;
- firstOId = OId;
- }
- } else {
- // no more intersections... return false
- done = true;
- }
- }
-
- distance = -1.0;
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- if(mGiObjInside[i]>0) {
- bool mess = false;
- if((mGiObjInside[i]%2)==1) {
- if(giObjFirstHistSide[i] != -1) mess=true;
- } else {
- if(giObjFirstHistSide[i] != 1) mess=true;
- }
- if(mess) {
- //errMsg("IIIproblem","At "<<org<<" obj "<<i<<" inside:"<<mGiObjInside[i]<<" firstside:"<<giObjFirstHistSide[i] );
- globGICPIProblems++;
- mGiObjInside[i]++; // believe first hit side...
- }
- }
- }
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- if(globGeoInitDebug) errMsg("CHIII","i"<<i<<" ins="<<mGiObjInside[i]<<" t"<<mGiObjDistance[i]<<" d"<<distance);
- if(((mGiObjInside[i]%2)==1)&&(mGiObjDistance[i]>0.0)) {
- if( (distance<0.0) || // first intersection -> good
- ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
- ) {
- distance = mGiObjDistance[i];
- OId = i;
- inside = true;
- }
- }
- }
- if(!inside) {
- distance = firstHit;
- OId = firstOId;
- }
- if(globGeoInitDebug) errMsg("CHIII","i"<<inside<<" fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId);
-
- return inside;
- } else {
-
- // find first inside intersection
- ntlTriangle *triIns = NULL;
- distance = -1.0;
- ntlVec3Gfx normal(0.0);
- if(shootDir==0) mpGiTree->intersectX(ray,distance,normal, triIns, flags, true);
- else mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
- if(triIns) {
- // check outside intersect
- LbmFloat orientation = dot(normal, dir);
- if(orientation<=0.0) return false;
-
- OId = triIns->getObjectId();
- return true;
- }
- return false;
- }
-}
-bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, ntlVec3Gfx dir, int flags, int &OId, gfxReal &distance, const gfxReal halfCellsize, bool &thinHit, bool recurse) {
- // shift ve ctors to avoid rounding errors
- org += ntlVec3Gfx(0.0001); //?
- OId = -1;
- ntlRay ray(org, dir, 0, 1.0, mpGlob);
- //int insCnt = 0;
- bool done = false;
- bool inside = false;
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- mGiObjInside[i] = 0;
- mGiObjDistance[i] = -1.0;
- mGiObjSecondDist[i] = -1.0;
- }
- // if not inside, return distance to first hit
- gfxReal firstHit=-1.0;
- int firstOId = -1;
- thinHit = false;
-
- if(mAccurateGeoinit) {
- while(!done) {
- // find first inside intersection
- ntlTriangle *triIns = NULL;
- distance = -1.0;
- ntlVec3Gfx normal(0.0);
- mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
- if(triIns) {
- ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
- LbmFloat orientation = dot(normal, dir);
- OId = triIns->getObjectId();
- if(orientation<=0.0) {
- // outside hit
- normal *= -1.0;
- //mGiObjDistance[OId] = -1.0;
- //errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
- } else {
- // inside hit
- //if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
- //errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
- if(mGiObjInside[OId]==1) {
- // second inside hit
- if(mGiObjSecondDist[OId]<0.0) mGiObjSecondDist[OId] = distance;
- }
- }
- mGiObjInside[OId]++;
- // always store first hit for thin obj init
- if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
-
- norg += normal * getVecEpsilon();
- ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
- // remember first hit distance, in case we're not
- // inside anything
- if(firstHit<0.0) {
- firstHit = distance;
- firstOId = OId;
- }
- } else {
- // no more intersections... return false
- done = true;
- //if(insCnt%2) inside=true;
- }
- }
-
- distance = -1.0;
- // standard inside check
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- if(((mGiObjInside[i]%2)==1)&&(mGiObjDistance[i]>0.0)) {
- if( (distance<0.0) || // first intersection -> good
- ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
- ) {
- distance = mGiObjDistance[i];
- OId = i;
- inside = true;
- }
- }
- }
- // now check for thin hits
- if(!inside) {
- distance = -1.0;
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- if((mGiObjInside[i]>=2)&&(mGiObjDistance[i]>0.0)&&(mGiObjSecondDist[i]>0.0)&&
- (mGiObjDistance[i]<1.0*halfCellsize)&&(mGiObjSecondDist[i]<2.0*halfCellsize) ) {
- if( (distance<0.0) || // first intersection -> good
- ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
- ) {
- distance = mGiObjDistance[i];
- OId = i;
- inside = true;
- thinHit = true;
- }
- }
- }
- }
- if(!inside) {
- // check for hit in this cell, opposite to current dir (only recurse once)
- if(recurse) {
- gfxReal r_distance;
- int r_OId;
- bool ret = geoInitCheckPointInside(org, dir*-1.0, flags, r_OId, r_distance, halfCellsize, thinHit, false);
- if((ret)&&(thinHit)) {
- OId = r_OId;
- distance = 0.0;
- return true;
- }
- }
- }
- // really no hit...
- if(!inside) {
- distance = firstHit;
- OId = firstOId;
- /*if((mGiObjDistance[OId]>0.0)&&(mGiObjSecondDist[OId]>0.0)) {
- const gfxReal thisdist = mGiObjSecondDist[OId]-mGiObjDistance[OId];
- // dont walk over this cell...
- if(thisdist<halfCellsize) distance-=2.0*halfCellsize;
- } // ? */
- }
- //errMsg("CHIII","i"<<inside<<" fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId);
-
- return inside;
- } else {
-
- // find first inside intersection
- ntlTriangle *triIns = NULL;
- distance = -1.0;
- ntlVec3Gfx normal(0.0);
- mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
- if(triIns) {
- // check outside intersect
- LbmFloat orientation = dot(normal, dir);
- if(orientation<=0.0) return false;
-
- OId = triIns->getObjectId();
- return true;
- }
- return false;
- }
-}
-
-
-/*****************************************************************************/
-ntlVec3Gfx LbmSolverInterface::getGeoMaxMovementVelocity(LbmFloat simtime, LbmFloat stepsize) {
- ntlVec3Gfx max(0.0);
- if(mpGlob == NULL) return max;
- // mpGiObjects has to be inited here...
-
- for(int i=0; i< (int)mpGiObjects->size(); i++) {
- //errMsg("LbmSolverInterface::getGeoMaxMovementVelocity","i="<<i<<" "<< (*mpGiObjects)[i]->getName() ); // DEBUG
- if( (*mpGiObjects)[i]->getGeoInitType() & (FGI_FLUID|FGI_MBNDINFLOW) ){
- //ntlVec3Gfx objMaxVel = obj->calculateMaxVel(sourceTime,targetTime);
- ntlVec3Gfx orgvel = (*mpGiObjects)[i]->calculateMaxVel( simtime, simtime+stepsize );
- if( normNoSqrt(orgvel) > normNoSqrt(max) ) { max = orgvel; }
- //errMsg("MVT","i"<<i<<" a"<< (*mpGiObjects)[i]->getInitialVelocity(simtime)<<" o"<<orgvel ); // DEBUG
- // TODO check if inflow and simtime
- ntlVec3Gfx inivel = (*mpGiObjects)[i]->getInitialVelocity(simtime);
- if( normNoSqrt(inivel) > normNoSqrt(max) ) { max = inivel; }
- }
- }
- errMsg("LbmSolverInterface::getGeoMaxMovementVelocity", "max="<< max ); // DEBUG
- return max;
-}
-
-
-
-
-/*******************************************************************************/
-/*! cell iteration functions */
-/*******************************************************************************/
-
-
-
-
-/*****************************************************************************/
-//! add cell to mMarkedCells list
-void
-LbmSolverInterface::addCellToMarkedList( CellIdentifierInterface *cid ) {
- for(size_t i=0; i<mMarkedCells.size(); i++) {
- // check if cids alreay in
- if( mMarkedCells[i]->equal(cid) ) return;
- //mMarkedCells[i]->setEnd(false);
- }
- mMarkedCells.push_back( cid );
- //cid->setEnd(true);
-}
-
-/*****************************************************************************/
-//! marked cell iteration methods
-CellIdentifierInterface*
-LbmSolverInterface::markedGetFirstCell( ) {
- if(mMarkedCells.size() > 0){ return mMarkedCells[0]; }
- return NULL;
-}
-
-CellIdentifierInterface*
-LbmSolverInterface::markedAdvanceCell() {
- mMarkedCellIndex++;
- if(mMarkedCellIndex>=(int)mMarkedCells.size()) return NULL;
- return mMarkedCells[mMarkedCellIndex];
-}
-
-void LbmSolverInterface::markedClearList() {
- // FIXME free cids?
- mMarkedCells.clear();
-}
-
-#if PARALLEL==1
-void LbmSolverInterface::setNumOMPThreads(int num_threads) {
- mNumOMPThreads = num_threads;
-}
-#endif // PARALLEL==1
-
-/*******************************************************************************/
-/*! string helper functions */
-/*******************************************************************************/
-
-
-
-// 32k
-string convertSingleFlag2String(CellFlagType cflag) {
- CellFlagType flag = cflag;
- if(flag == CFUnused ) return string("cCFUnused");
- if(flag == CFEmpty ) return string("cCFEmpty");
- if(flag == CFBnd ) return string("cCFBnd");
- if(flag == CFBndNoslip ) return string("cCFBndNoSlip");
- if(flag == CFBndFreeslip ) return string("cCFBndFreeSlip");
- if(flag == CFBndPartslip ) return string("cCFBndPartSlip");
- if(flag == CFNoInterpolSrc ) return string("cCFNoInterpolSrc");
- if(flag == CFFluid ) return string("cCFFluid");
- if(flag == CFInter ) return string("cCFInter");
- if(flag == CFNoNbFluid ) return string("cCFNoNbFluid");
- if(flag == CFNoNbEmpty ) return string("cCFNoNbEmpty");
- if(flag == CFNoDelete ) return string("cCFNoDelete");
- if(flag == CFNoBndFluid ) return string("cCFNoBndFluid");
- if(flag == CFGrNorm ) return string("cCFGrNorm");
- if(flag == CFGrFromFine ) return string("cCFGrFromFine");
- if(flag == CFGrFromCoarse ) return string("cCFGrFromCoarse");
- if(flag == CFGrCoarseInited ) return string("cCFGrCoarseInited");
- if(flag == CFMbndInflow ) return string("cCFMbndInflow");
- if(flag == CFMbndOutflow ) return string("cCFMbndOutflow");
- if(flag == CFInvalid ) return string("cfINVALID");
-
- std::ostringstream mult;
- int val = 0;
- if(flag != 0) {
- while(! (flag&1) ) {
- flag = flag>>1;
- val++;
- }
- } else {
- val = -1;
- }
- if(val>=24) {
- mult << "cfOID_" << (flag>>24) <<"_TYPE";
- } else {
- mult << "cfUNKNOWN_" << val <<"_TYPE";
- }
- return mult.str();
-}
-
-//! helper function to convert flag to string (for debuggin)
-string convertCellFlagType2String( CellFlagType cflag ) {
- int flag = cflag;
-
- const int jmax = sizeof(CellFlagType)*8;
- bool somefound = false;
- std::ostringstream mult;
- mult << "[";
- for(int j=0; j<jmax ; j++) {
- if(flag& (1<<j)) {
- if(somefound) mult << "|";
- mult << j<<"<"<< convertSingleFlag2String( (CellFlagType)(1<<j) ); // this call should always be _non_-recursive
- somefound = true;
- }
- };
- mult << "]";
-
- // return concatenated string
- if(somefound) return mult.str();
-
- // empty?
- return string("[emptyCFT]");
-}
-
diff --git a/intern/elbeem/intern/solver_interface.h b/intern/elbeem/intern/solver_interface.h
deleted file mode 100644
index 1301e0f6ebb..00000000000
--- a/intern/elbeem/intern/solver_interface.h
+++ /dev/null
@@ -1,639 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Header for Combined 2D/3D Lattice Boltzmann Interface Class
- *
- *****************************************************************************/
-#ifndef LBMINTERFACE_H
-#define LBMINTERFACE_H
-
-//! include gui support?
-#ifndef NOGUI
-#define LBM_USE_GUI 1
-#else
-#define LBM_USE_GUI 0
-#endif
-
-#if LBM_USE_GUI==1
-#define USE_GLUTILITIES
-// for debug display
-//#include <GL/gl.h>
-#include "../gui/guifuncs.h"
-#endif
-
-#include <sstream>
-#include "utilities.h"
-#include "ntl_bsptree.h"
-#include "ntl_geometryobject.h"
-#include "parametrizer.h"
-#include "attributes.h"
-#include "isosurface.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ParticleTracer;
-class ParticleObject;
-
-// use which fp-precision for LBM? 1=float, 2=double
-#ifdef PRECISION_LBM_SINGLE
-#define LBM_PRECISION 1
-#else
-#ifdef PRECISION_LBM_DOUBLE
-#define LBM_PRECISION 2
-#else
-// default to floats
-#define LBM_PRECISION 1
-#endif
-#endif
-
-#if LBM_PRECISION==1
-/* low precision for LBM solver */
-typedef float LbmFloat;
-typedef ntlVec3f LbmVec;
-#define LBM_EPSILON (1e-5)
-#else
-/* standard precision for LBM solver */
-typedef double LbmFloat;
-typedef ntlVec3d LbmVec;
-#define LBM_EPSILON (1e-10)
-#endif
-
-// long integer, needed e.g. for memory calculations
-#ifndef USE_MSVC6FIXES
-#define LONGINT long long int
-#else
-#define LONGINT _int64
-#endif
-
-
-// default to 3dim
-#ifndef LBMDIM
-#define LBMDIM 3
-#endif // LBMDIM
-
-#if LBMDIM==2
-#define LBM_DFNUM 9
-#else
-#define LBM_DFNUM 19
-#endif
-
-// conversions (lbm and parametrizer)
-template<class T> inline LbmVec vec2L(T v) { return LbmVec(v[0],v[1],v[2]); }
-template<class T> inline ParamVec vec2P(T v) { return ParamVec(v[0],v[1],v[2]); }
-
-template<class Scalar> class ntlMatrix4x4;
-
-
-// bubble id type
-typedef int BubbleId;
-
-// basic cell type distinctions
-#define CFUnused (1<< 0)
-#define CFEmpty (1<< 1)
-#define CFBnd (1<< 2)
-#define CFMbndInflow (1<< 3)
-#define CFMbndOutflow (1<< 4)
-#define CFFluid (1<< 5)
-#define CFInter (1<< 6)
-// additional for fluid (needed separately for adaptive grids)
-#define CFNoBndFluid (1<< 7)
-#define CFNoDelete (1<< 8)
-
-// additional bnd add flags
-#define CFBndNoslip (1<< 9)
-#define CFBndFreeslip (1<<10)
-#define CFBndPartslip (1<<11)
-#define CFBndMoving (1<<12)
-
-// additional for fluid/interface
-// force symmetry for flag reinit
-#define CFNoInterpolSrc (1<<13)
-#define CFNoNbFluid (1<<14)
-#define CFNoNbEmpty (1<<15)
-
-// cell treated normally on coarser grids
-#define CFGrNorm (1<<16)
-#define CFGrCoarseInited (1<<17)
-
-// (the following values shouldnt overlap to ensure
-// proper coarsening)
-// border cells to be interpolated from finer grid
-#define CFGrFromFine (1<<18)
-// 32k aux border marker
-#define CFGrToFine (1<<19)
-// also needed on finest level
-#define CFGrFromCoarse (1<<20)
-// additional refinement tags (coarse grids only?)
-// */
-
-// above 24 is used to encode in/outflow object type
-#define CFPersistMask (0xFF000000 | CFMbndInflow | CFMbndOutflow)
-#define CFNoPersistMask (~CFPersistMask)
-
-
-// nk
-#define CFInvalid (CellFlagType)(1<<31)
-
-// use 32bit flag types
-//#ifdef __x86_64__
- //typedef int cfINT32;
-//#else
- //typedef long cfINT32;
-//#endif // defined (_IA64)
-//#define CellFlagType cfINT32
-#define CellFlagType int
-#define CellFlagTypeSize 4
-
-
-// aux. field indices (same for 2d)
-#define dFfrac 19
-#define dMass 20
-#define dFlux 21
-// max. no. of cell values for 3d
-#define dTotalNum 22
-
-
-/*****************************************************************************/
-/*! a single lbm cell */
-/* the template is only needed for
- * dimension dependend constants e.g.
- * number of df's in model */
-class LbmCellContents {
- public:
- LbmFloat df[ 27 ]; // be on the safe side here...
- LbmFloat rho;
- LbmVec vel;
- LbmFloat mass;
- CellFlagType flag;
- BubbleId bubble;
- LbmFloat ffrac;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:LbmCellContents")
-#endif
-};
-
-/* struct for the coordinates of a cell in the grid */
-typedef struct {
- int x,y,z;
- int flag; // special handling?
-} LbmPoint;
-
-/* struct for the coordinates of a cell in the grid */
-typedef struct {
- char active; // bubble in use, oder may be overwritten?
- LbmFloat volume; // volume of this bubble (0 vor atmosphere)
- LbmFloat mass; // "mass" of bubble
- int i,j,k; // index of a cell in the bubble
-} LbmBubble;
-
-
-
-
-//! choose which data to display
-#define FLUIDDISPINVALID 0
-#define FLUIDDISPNothing 1
-#define FLUIDDISPCelltypes 2
-#define FLUIDDISPVelocities 3
-#define FLUIDDISPCellfills 4
-#define FLUIDDISPDensity 5
-#define FLUIDDISPGrid 6
-#define FLUIDDISPSurface 7
-
-
-
-/*****************************************************************************/
-//! cell identifier interface
-class CellIdentifierInterface {
- public:
- //! reset constructor
- CellIdentifierInterface():mEnd(false) { };
- //! virtual destructor
- virtual ~CellIdentifierInterface() {};
-
- //! return node as string (with some basic info)
- virtual string getAsString() = 0;
-
- //! compare cids
- virtual bool equal(CellIdentifierInterface* other) = 0;
-
- //! set/get end flag for grid traversal (not needed for marked cells)
- inline void setEnd(bool set){ mEnd = set; }
- inline bool getEnd( ) { return mEnd; }
-
- //! has the grid been traversed?
- bool mEnd;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:CellIdentifierInterface")
-#endif
-};
-
-
-
-/*****************************************************************************/
-/*! class defining abstract function interface */
-/* has to provide iterating functionality */
-class LbmSolverInterface
-{
- public:
- //! Constructor
- LbmSolverInterface();
- //! Destructor
- virtual ~LbmSolverInterface();
- //! id string of solver
- virtual string getIdString() = 0;
-
- // multi step solver init
- /*! finish the init with config file values (allocate arrays...) */
- virtual bool initializeSolverMemory() =0;
- /*! init solver arrays */
- virtual bool initializeSolverGrids() =0;
- /*! prepare actual simulation start, setup viz etc */
- virtual bool initializeSolverPostinit() =0;
-
- /*! notify object that dump is in progress (e.g. for field dump) */
- virtual void notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) = 0;
-
- /*! parse a boundary flag string */
- CellFlagType readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed);
- /*! parse standard attributes */
- void parseStdAttrList();
- /*! initilize variables fom attribute list (should at least call std parse) */
- virtual void parseAttrList() = 0;
-
- virtual void step() = 0;
- virtual void prepareVisualization() { /* by default off */ };
-
- /*! particle handling */
- virtual int initParticles() = 0;
- virtual void advanceParticles() = 0;
- /*! get surface object (NULL if no surface) */
- IsoSurface* getSurfaceGeoObj() { return mpIso; }
-
- /*! debug object display */
- virtual vector<ntlGeometryObject*> getDebugObjects() { vector<ntlGeometryObject*> empty(0); return empty; }
-
- /* surface generation settings */
- virtual void setSurfGenSettings(short value) = 0;
-
-#if LBM_USE_GUI==1
- /*! show simulation info */
- virtual void debugDisplay(int) = 0;
-#endif
-
- /*! init tree for certain geometry init */
- void initGeoTree();
- /*! destroy tree etc. when geometry init done */
- void freeGeoTree();
- /*! check for a certain flag type at position org (needed for e.g. quadtree refinement) */
- bool geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance,int shootDir=0);
- bool geoInitCheckPointInside(ntlVec3Gfx org, ntlVec3Gfx dir, int flags, int &OId, gfxReal &distance,
- const gfxReal halfCellsize, bool &thinHit, bool recurse);
- /*! set render globals, for scene/tree access */
- void setRenderGlobals(ntlRenderGlobals *glob) { mpGlob = glob; };
- /*! get max. velocity of all objects to initialize as fluid regions, and of all moving objects */
- ntlVec3Gfx getGeoMaxMovementVelocity(LbmFloat simtime, LbmFloat stepsize);
-
- /* rt interface functions */
- unsigned int getIsoVertexCount() { return mpIso->getIsoVertexCount(); }
- unsigned int getIsoIndexCount() { return mpIso->getIsoIndexCount(); }
- char* getIsoVertexArray() { return mpIso->getIsoVertexArray(); }
- unsigned int *getIsoIndexArray() { return mpIso->getIsoIndexArray(); }
- void triangulateSurface() { mpIso->triangulate(); }
-
- /* access functions */
-
- /*! return grid sizes */
- int getSizeX( void ) { return mSizex; }
- int getSizeY( void ) { return mSizey; }
- int getSizeZ( void ) { return mSizez; }
- /*! return grid sizes */
- void setSizeX( int ns ) { mSizex = ns; }
- void setSizeY( int ns ) { mSizey = ns; }
- void setSizeZ( int ns ) { mSizez = ns; }
- /*! access fluid only simulation flag */
- void setAllfluid(bool set) { mAllfluid=set; }
- bool getAllfluid() { return mAllfluid; }
-
- /*! set attr list pointer */
- void setAttrList(AttributeList *set) { mpSifAttrs = set; }
- /*! Returns the attribute list pointer */
- inline AttributeList *getAttributeList() { return mpSifAttrs; }
- /*! set sws attr list pointer */
- void setSwsAttrList(AttributeList *set) { mpSifSwsAttrs = set; }
- inline AttributeList *getSwsAttributeList() { return mpSifSwsAttrs; }
-
- /*! set parametrizer pointer */
- inline void setParametrizer(Parametrizer *set) { mpParam = set; }
- /*! get parametrizer pointer */
- inline Parametrizer *getParametrizer() { return mpParam; }
- /*! get/set particle pointer */
- inline void setParticleTracer(ParticleTracer *set) { mpParticles = set; }
- inline ParticleTracer *getParticleTracer() { return mpParticles; }
-
- /*! set density gradient init from e.g. init test cases */
- inline void setInitDensityGradient(bool set) { mInitDensityGradient = set; }
-
- /*! access geometry start vector */
- inline void setGeoStart(ntlVec3Gfx set) { mvGeoStart = set; }
- inline ntlVec3Gfx getGeoStart() const { return mvGeoStart; }
-
- /*! access geometry end vector */
- inline void setGeoEnd(ntlVec3Gfx set) { mvGeoEnd = set; }
- inline ntlVec3Gfx getGeoEnd() const { return mvGeoEnd; }
-
- /*! access geo init vars */
- inline void setLbmInitId(int set) { mLbmInitId = set; }
- inline int getLbmInitId() const { return mLbmInitId; }
-
- /*! init domain transformation matrix from float array */
- void initDomainTrafo(float *mat);
- /*! get domain transformation matrix to have object centered fluid vertices */
- inline ntlMatrix4x4<gfxReal> *getDomainTrafo() { return mpSimTrafo; }
-
- /*! access name string */
- inline void setName(string set) { mName = set; }
- inline string getName() const { return mName; }
-
- /*! access string for node info debugging output */
- inline string getNodeInfoString() const { return mNodeInfoString; }
-
- /*! get panic flag */
- inline bool getPanic() { return mPanic; }
-
- //! set silent mode?
- inline void setSilent(bool set){ mSilent = set; }
-
- //! set amount of surface/normal smoothing
- inline void setSmoothing(float setss,float setns){ mSmoothSurface=setss; mSmoothNormals=setns; }
- //! set amount of iso subdivisions
- inline void setIsoSubdivs(int s){ mIsoSubdivs=s; }
- //! set desired refinement
- inline void setPreviewSize(int set){ mOutputSurfacePreview = set; }
- //! set desired refinement
- inline void setRefinementDesired(int set){ mRefinementDesired = set; }
-
- //! set/get dump velocities flag
- inline void setDumpVelocities(bool set) { mDumpVelocities = set; }
- inline bool getDumpVelocities() const { return mDumpVelocities; }
-
- //! set/get particle generation prob.
- inline void setGenerateParticles(LbmFloat set) { mPartGenProb = set; }
- inline LbmFloat getGenerateParticles() const { return mPartGenProb; }
-
- //! set/get dump velocities flag
- inline void setDomainBound(string set) { mDomainBound = set; }
- inline string getDomainBound() const { return mDomainBound; }
- //! set/get dump velocities flag
- inline void setDomainPartSlip(LbmFloat set) { mDomainPartSlipValue = set; }
- inline LbmFloat getDomainPartSlip() const { return mDomainPartSlipValue; }
- //! set/get far field size
- inline void setFarFieldSize(LbmFloat set) { mFarFieldSize = set; }
- inline LbmFloat getFarFieldSize() const { return mFarFieldSize; }
- //! set/get cp stage
- inline void setCpStage(int set) { mCppfStage = set; }
- inline int getCpStage() const { return mCppfStage; }
- //! set/get dump modes
- inline void setDumpRawText(bool set) { mDumpRawText = set; }
- inline bool getDumpRawText() const { return mDumpRawText; }
- inline void setDumpRawBinary(bool set) { mDumpRawBinary = set; }
- inline bool getDumpRawBinary() const { return mDumpRawBinary; }
- inline void setDumpRawBinaryZip(bool set) { mDumpRawBinaryZip = set; }
- inline bool getDumpRawBinaryZip() const { return mDumpRawBinaryZip; }
- //! set/get debug vel scale
- inline void setDebugVelScale(LbmFloat set) { mDebugVelScale = set; }
- inline LbmFloat getDebugVelScale() const { return mDebugVelScale; }
-
- // cell iterator interface
-
- // cell id type
- typedef CellIdentifierInterface* CellIdentifier;
-
- //! cell iteration methods
- virtual CellIdentifierInterface* getFirstCell( ) = 0;
- virtual void advanceCell( CellIdentifierInterface* ) = 0;
- virtual bool noEndCell( CellIdentifierInterface* ) = 0;
- //! clean up iteration, this should be called, when the iteration is not completely finished
- virtual void deleteCellIterator( CellIdentifierInterface** ) = 0;
-
- //! find cell at a given position (returns NULL if not in domain)
- virtual CellIdentifierInterface* getCellAt( ntlVec3Gfx pos ) = 0;
-
- //! return node information
- virtual int getCellSet ( CellIdentifierInterface* ) = 0;
- virtual ntlVec3Gfx getCellOrigin ( CellIdentifierInterface* ) = 0;
- virtual ntlVec3Gfx getCellSize ( CellIdentifierInterface* ) = 0;
- virtual int getCellLevel ( CellIdentifierInterface* ) = 0;
- virtual LbmFloat getCellDensity ( CellIdentifierInterface*,int ) = 0;
- virtual LbmVec getCellVelocity ( CellIdentifierInterface*,int ) = 0;
- /*! get equilibrium distribution functions */
- virtual LbmFloat getEquilDf ( int ) = 0;
- /*! redundant cell functions */
- virtual LbmFloat getCellDf ( CellIdentifierInterface* ,int set, int dir) = 0;
- virtual LbmFloat getCellMass ( CellIdentifierInterface* ,int set) = 0;
- virtual LbmFloat getCellFill ( CellIdentifierInterface* ,int set) = 0;
- virtual CellFlagType getCellFlag ( CellIdentifierInterface* ,int set) = 0;
-
- /*! get velocity directly from position */
- virtual ntlVec3Gfx getVelocityAt(float x, float y, float z) = 0;
-
- // gui/output debugging functions
-#if LBM_USE_GUI==1
- virtual void debugDisplayNode(int dispset, CellIdentifier cell ) = 0;
- virtual void lbmDebugDisplay(int dispset) = 0;
- virtual void lbmMarkedCellDisplay() = 0;
-#endif // LBM_USE_GUI==1
- virtual void debugPrintNodeInfo(CellIdentifier cell, int forceSet=-1) = 0;
-
- // debugging cell marker functions
-
- //! add cell to mMarkedCells list
- void addCellToMarkedList( CellIdentifierInterface *cid );
- //! marked cell iteration methods
- CellIdentifierInterface* markedGetFirstCell( );
- CellIdentifierInterface* markedAdvanceCell();
- void markedClearList();
-
-#if PARALLEL==1
- void setNumOMPThreads(int num_threads);
-#endif // PARALLEL==1
- protected:
-
- /*! abort simulation on error... */
- bool mPanic;
-
-
- /*! Size of the array in x,y,z direction */
- int mSizex, mSizey, mSizez;
- /*! only fluid in sim? */
- bool mAllfluid;
-
-
- /*! step counter */
- int mStepCnt;
-
- /*! mass change from one step to the next, for extreme cases fix globally */
- LbmFloat mFixMass;
-
- // deprecated param vars
- /*! omega for lbm */
- LbmFloat mOmega;
- /*! gravity strength in neg. z direction */
- LbmVec mGravity;
- /*! Surface tension of the fluid */
- LbmFloat mSurfaceTension;
-
-
- /* boundary inits */
- CellFlagType mBoundaryEast, mBoundaryWest,
- mBoundaryNorth, mBoundarySouth,
- mBoundaryTop, mBoundaryBottom;
-
- /*! initialization from config file done? */
- int mInitDone;
-
- /*! init density gradient? */
- bool mInitDensityGradient;
-
- /*! pointer to the attribute list, only pointer to obj attrs */
- AttributeList *mpSifAttrs;
- AttributeList *mpSifSwsAttrs;
-
- /*! get parameters from this parametrize in finishInit */
- Parametrizer *mpParam;
- //! store particle tracer
- ParticleTracer *mpParticles;
-
- /*! number of particles lost so far */
- int mNumParticlesLost;
- /*! number of particles lost so far */
- int mNumInvalidDfs;
- /*! no of filled/emptied cells per time step */
- int mNumFilledCells, mNumEmptiedCells;
- /*! counter number of used cells for performance */
- int mNumUsedCells;
- /*! MLSUPS counter */
- LbmFloat mMLSUPS;
- /*! debug - velocity output scaling factor */
- LbmFloat mDebugVelScale;
- /*! string for node info debugging output */
- string mNodeInfoString;
-
- // geo init vars
- // TODO deprecate SimulationObject vars
-
- /*! for display - start and end vectors for geometry */
- ntlVec3Gfx mvGeoStart, mvGeoEnd;
- //! domain vertex trafos
- ntlMatrix4x4<gfxReal> *mpSimTrafo;
-
- /*! perform accurate geometry init? */
- bool mAccurateGeoinit;
-
- /*! name of this lbm object (for debug output) */
- string mName;
-
- //! Mcubes object for surface reconstruction
- IsoSurface *mpIso;
- /*! isolevel value for marching cubes surface reconstruction */
- LbmFloat mIsoValue;
-
- //! debug output?
- bool mSilent;
-
- /*! geometry init id, passed from ntl_geomclass */
- int mLbmInitId;
- /*! tree object for geomerty initialization */
- ntlTree *mpGiTree;
- /*! object vector for geo init */
- vector<ntlGeometryObject*> *mpGiObjects;
- /*! inside which objects? */
- vector<int> mGiObjInside;
- /*! inside which objects? */
- vector<gfxReal> mGiObjDistance;
- vector<gfxReal> mGiObjSecondDist;
- /*! remember globals */
- ntlRenderGlobals *mpGlob;
-
- //! use refinement/coarsening?
- int mRefinementDesired;
-
- //! output surface preview? if >0 yes, and use as reduzed size
- int mOutputSurfacePreview;
- LbmFloat mPreviewFactor;
-
- /*! enable surface and normals smoothing? */
- float mSmoothSurface;
- float mSmoothNormals;
- /*! isosurface subdivisions */
- int mIsoSubdivs;
-
- //! particle generation probability
- LbmFloat mPartGenProb;
-
- //! dump velocities?
- bool mDumpVelocities;
-
- // list for marked cells
- vector<CellIdentifierInterface *> mMarkedCells;
- int mMarkedCellIndex;
-
- //! domain boundary free/no slip type
- string mDomainBound;
- //! part slip value for domain
- LbmFloat mDomainPartSlipValue;
-
- // size of far field area
- LbmFloat mFarFieldSize;
- // amount of drop mass to subtract
- LbmFloat mPartDropMassSub;
- // use physical drop model for particles?
- bool mPartUsePhysModel;
-
- //! test vars
- // strength of applied force
- LbmFloat mTForceStrength;
- int mCppfStage;
-
- //! dumping modes
- bool mDumpRawText;
- bool mDumpRawBinary;
- bool mDumpRawBinaryZip;
-
-#if PARALLEL==1
- int mNumOMPThreads;
-#endif // PARALLEL==1
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:LbmSolverInterface")
-#endif
-};
-
-
-// helper function to create consistent grid resolutions
-void initGridSizes(int &mSizex, int &mSizey, int &mSizez,
- ntlVec3Gfx &mvGeoStart, ntlVec3Gfx &mvGeoEnd,
- int mMaxRefine, bool parallel);
-// return the amount of memory required in total (reqret)
-// and for the finest grid only (reqretFine, can be NULL)
-void calculateMemreqEstimate(int resx,int resy,int resz, int refine,
- float farfieldsize, double *reqret, double *reqretFine, string *reqstr);
-
-//! helper function to convert flag to string (for debuggin)
-string convertCellFlagType2String( CellFlagType flag );
-string convertSingleFlag2String(CellFlagType cflag);
-
-#endif // LBMINTERFACE_H
diff --git a/intern/elbeem/intern/solver_main.cpp b/intern/elbeem/intern/solver_main.cpp
deleted file mode 100644
index 961bd44e08f..00000000000
--- a/intern/elbeem/intern/solver_main.cpp
+++ /dev/null
@@ -1,1723 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Standard LBM Factory implementation
- *
- *****************************************************************************/
-
-#include "solver_class.h"
-#include "solver_relax.h"
-#include "particletracer.h"
-#include "loop_tools.h"
-#include "globals.h"
-
-#include <stdlib.h>
-#include <cmath>
-
-using std::isfinite;
-
-/*****************************************************************************/
-/*! perform a single LBM step */
-/*****************************************************************************/
-
-double globdfcnt;
-double globdfavg[19];
-double globdfmax[19];
-double globdfmin[19];
-
-// simulation object interface
-void LbmFsgrSolver::step() {
- stepMain();
-}
-
-// lbm main step
-void messageOutputForce(string from);
-void LbmFsgrSolver::stepMain() {
- myTime_t timestart = getTime();
-
- initLevelOmegas();
- markedClearList(); // DMC clearMarkedCellsList
-
- // safety check, counter reset
- mNumUsedCells = 0;
- mNumInterdCells = 0;
- mNumInvIfCells = 0;
-
- //debugOutNnl("LbmFsgrSolver::step : "<<mStepCnt, 10);
- if(!mSilent){ debMsgStd("LbmFsgrSolver::step", DM_MSG, mName<<" cnt:"<<mStepCnt<<" t:"<<mSimulationTime, 10); }
- //debMsgDirect( "LbmFsgrSolver::step : "<<mStepCnt<<" ");
- //myTime_t timestart = 0;
- //if(mStartSymm) { checkSymmetry("step1"); } // DEBUG
-
- // time adapt
- mMaxVlen = mMxvz = mMxvy = mMxvx = 0.0;
-
- // init moving bc's, can change mMaxVlen
- initMovingObstacles(false);
-
- // handle fluid control
- handleCpdata();
-
- // important - keep for tadap
- LbmFloat lastMass = mCurrentMass;
- mCurrentMass = mFixMass; // reset here for next step
- mCurrentVolume = 0.0;
-
- //change to single step advance!
- int levsteps = 0;
- int dsbits = mStepCnt ^ (mStepCnt-1);
- //errMsg("S"," step:"<<mStepCnt<<" s-1:"<<(mStepCnt-1)<<" xf:"<<convertCellFlagType2String(dsbits));
- for(int lev=0; lev<=mMaxRefine; lev++) {
- //if(! (mStepCnt&(1<<lev)) ) {
- if( dsbits & (1<<(mMaxRefine-lev)) ) {
- //errMsg("S"," l"<<lev);
-
- if(lev==mMaxRefine) {
- // always advance fine level...
- fineAdvance();
- } else {
- adaptGrid(lev);
- coarseRestrictFromFine(lev);
- coarseAdvance(lev);
- }
-#if FSGR_OMEGA_DEBUG==1
- errMsg("LbmFsgrSolver::step","LES stats l="<<lev<<" omega="<<mLevel[lev].omega<<" avgOmega="<< (mLevel[lev].avgOmega/mLevel[lev].avgOmegaCnt) );
- mLevel[lev].avgOmega = 0.0; mLevel[lev].avgOmegaCnt = 0.0;
-#endif // FSGR_OMEGA_DEBUG==1
- levsteps++;
- }
- mCurrentMass += mLevel[lev].lmass;
- mCurrentVolume += mLevel[lev].lvolume;
- }
-
- // prepare next step
- mStepCnt++;
-
-
- // some dbugging output follows
- // calculate MLSUPS
- myTime_t timeend = getTime();
-
- mNumUsedCells += mNumInterdCells; // count both types for MLSUPS
- mAvgNumUsedCells += mNumUsedCells;
- mMLSUPS = ((double)mNumUsedCells / ((timeend-timestart)/(double)1000.0) ) / (1000000.0);
- if(mMLSUPS>10000){ mMLSUPS = -1; }
- //else { mAvgMLSUPS += mMLSUPS; mAvgMLSUPSCnt += 1.0; } // track average mlsups
-
- LbmFloat totMLSUPS = ( ((mLevel[mMaxRefine].lSizex-2)*(mLevel[mMaxRefine].lSizey-2)*(getForZMax1(mMaxRefine)-getForZMin1())) / ((timeend-timestart)/(double)1000.0) ) / (1000000);
- if(totMLSUPS>10000) totMLSUPS = -1;
- mNumInvIfTotal += mNumInvIfCells; // debug
-
- // do some formatting
- if(!mSilent){
- int avgcls = (int)(mAvgNumUsedCells/(LONGINT)mStepCnt);
- debMsgStd("LbmFsgrSolver::step", DM_MSG, mName<<" cnt:"<<mStepCnt<<" t:"<<mSimulationTime<<
- " cur-mlsups:"<<mMLSUPS<< //" avg:"<<(mAvgMLSUPS/mAvgMLSUPSCnt)<<"), "<<
- " totcls:"<<mNumUsedCells<< " avgcls:"<< avgcls<<
- " intd:"<<mNumInterdCells<< " invif:"<<mNumInvIfCells<<
- " invift:"<<mNumInvIfTotal<< " fsgrcs:"<<mNumFsgrChanges<<
- " filled:"<<mNumFilledCells<<", emptied:"<<mNumEmptiedCells<<
- " mMxv:"<<PRINT_VEC(mMxvx,mMxvy,mMxvz)<<", tscnts:"<<mTimeSwitchCounts<<
- //" RWmxv:"<<ntlVec3Gfx(mMxvx,mMxvy,mMxvz)*(mLevel[mMaxRefine].simCellSize / mLevel[mMaxRefine].timestep)<<" "<< /* realworld vel output */
- " probs:"<<mNumProblems<< " simt:"<<mSimulationTime<<
- " took:"<< getTimeString(timeend-timestart)<<
- " for '"<<mName<<"' " , 10);
- } else { debMsgDirect("."); }
-
- if(mStepCnt==1) {
- mMinNoCells = mMaxNoCells = mNumUsedCells;
- } else {
- if(mNumUsedCells>mMaxNoCells) mMaxNoCells = mNumUsedCells;
- if(mNumUsedCells<mMinNoCells) mMinNoCells = mNumUsedCells;
- }
-
- // mass scale test
- if((mMaxRefine>0)&&(mInitialMass>0.0)) {
- LbmFloat mscale = mInitialMass/mCurrentMass;
-
- mscale = 1.0;
- const LbmFloat dchh = 0.001;
- if(mCurrentMass<mInitialMass) mscale = 1.0+dchh;
- if(mCurrentMass>mInitialMass) mscale = 1.0-dchh;
-
- // use mass rescaling?
- // with float precision this seems to be nonsense...
- const bool MREnable = false;
-
- const int MSInter = 2;
- static int mscount = 0;
- if( (MREnable) && ((mLevel[0].lsteps%MSInter)== (MSInter-1)) && ( ABS( (mInitialMass/mCurrentMass)-1.0 ) > 0.01) && ( dsbits & (1<<(mMaxRefine-0)) ) ){
- // example: FORCE RESCALE MASS! ini:1843.5, cur:1817.6, f=1.01425 step:22153 levstep:5539 msc:37
- // mass rescale MASS RESCALE check
- errMsg("MDTDD","\n\n");
- errMsg("MDTDD","FORCE RESCALE MASS! "
- <<"ini:"<<mInitialMass<<", cur:"<<mCurrentMass<<", f="<<ABS(mInitialMass/mCurrentMass)
- <<" step:"<<mStepCnt<<" levstep:"<<mLevel[0].lsteps<<" msc:"<<mscount<<" "
- );
- errMsg("MDTDD","\n\n");
-
- mscount++;
- for(int lev=mMaxRefine; lev>=0 ; lev--) {
- //for(int workSet = 0; workSet<=1; workSet++) {
- int wss = 0;
- int wse = 1;
-#if COMPRESSGRIDS==1
- if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr;
-#endif // COMPRESSGRIDS==1
- for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT
-
- FSGR_FORIJK1(lev) {
- if( (RFLAG(lev,i,j,k, workSet) & (CFFluid| CFInter| CFGrFromCoarse| CFGrFromFine| CFGrNorm))
- ) {
-
- FORDF0 { QCELL(lev, i,j,k,workSet, l) *= mscale; }
- QCELL(lev, i,j,k,workSet, dMass) *= mscale;
- QCELL(lev, i,j,k,workSet, dFfrac) *= mscale;
-
- } else {
- continue;
- }
- }
- }
- mLevel[lev].lmass *= mscale;
- }
- }
-
- mCurrentMass *= mscale;
- }// if mass scale test */
- else {
- // use current mass after full step for initial setting
- if((mMaxRefine>0)&&(mInitialMass<=0.0) && (levsteps == (mMaxRefine+1))) {
- mInitialMass = mCurrentMass;
- debMsgStd("MDTDD",DM_NOTIFY,"Second Initial Mass Init: "<<mInitialMass, 2);
- }
- }
-
-#if LBM_INCLUDE_TESTSOLVERS==1
- if((mUseTestdata)&&(mInitDone)) { handleTestdata(); }
- mrExchange();
-#endif
-
- // advance positions with current grid
- advanceParticles();
- if(mpParticles) {
- mpParticles->checkDumpTextPositions(mSimulationTime);
- mpParticles->checkTrails(mSimulationTime);
- }
-
- // one of the last things to do - adapt timestep
- // was in fineAdvance before...
- if(mTimeAdap) {
- adaptTimestep();
- } // time adaptivity
-
-
-#ifndef WIN32
- // good indicator for instabilities
- if( (!isfinite(mMxvx)) || (!isfinite(mMxvy)) || (!isfinite(mMxvz)) ) { CAUSE_PANIC; }
- if( (!isfinite(mCurrentMass)) || (!isfinite(mCurrentVolume)) ) { CAUSE_PANIC; }
-#endif // WIN32
-
- // output total step time
- myTime_t timeend2 = getTime();
- double mdelta = (lastMass-mCurrentMass);
- if(ABS(mdelta)<1e-12) mdelta=0.;
- double effMLSUPS = ((double)mNumUsedCells / ((timeend2-timestart)/(double)1000.0) ) / (1000000.0);
- if(mInitDone) {
- if(effMLSUPS>10000){ effMLSUPS = -1; }
- else { mAvgMLSUPS += effMLSUPS; mAvgMLSUPSCnt += 1.0; } // track average mlsups
- }
-
- debMsgStd("LbmFsgrSolver::stepMain", DM_MSG, "mmpid:"<<glob_mpindex<<" step:"<<mStepCnt
- <<" dccd="<< mCurrentMass
- //<<",d"<<mdelta
- //<<",ds"<<(mCurrentMass-mObjectMassMovnd[1])
- //<<"/"<<mCurrentVolume<<"(fix="<<mFixMass<<",ini="<<mInitialMass<<"), "
- <<" effMLSUPS=("<< effMLSUPS
- <<",avg:"<<(mAvgMLSUPS/mAvgMLSUPSCnt)<<"), "
- <<" took totst:"<< getTimeString(timeend2-timestart), 3);
- // nicer output
- //debMsgDirect(std::endl);
- // */
-
- messageOutputForce("");
- //#endif // ELBEEM_PLUGIN!=1
-}
-
-#define NEWDEBCHECK(str) \
- if(!this->mPanic){ FSGR_FORIJK_BOUNDS(mMaxRefine) { \
- if(RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr)&(CFFluid|CFInter)) { \
- for(int l=0;l<dTotalNum;l++) { \
- if(!isfinite(QCELL(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr,l))) { errMsg("NNOFIN"," "<<str<<" at "<<PRINT_IJK<<" l"<<l<<" "); }\
- }/*for*/ \
- }/*if*/ \
- } }
-
-void LbmFsgrSolver::fineAdvance()
-{
- // do the real thing...
- //NEWDEBCHECK("t1");
- mainLoop( mMaxRefine );
- if(mUpdateFVHeight) {
- // warning assume -Y gravity...
- mFVHeight = mCurrentMass*mFVArea/((LbmFloat)(mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizez));
- if(mFVHeight<1.0) mFVHeight = 1.0;
- mpParam->setFluidVolumeHeight(mFVHeight);
- }
-
- // advance time before timestep change
- mSimulationTime += mpParam->getTimestep();
- // time adaptivity
- mpParam->setSimulationMaxSpeed( sqrt(mMaxVlen / 1.5) );
- //if(mStartSymm) { checkSymmetry("step2"); } // DEBUG
- if(!mSilent){ debMsgStd("fineAdvance",DM_NOTIFY," stepped from "<<mLevel[mMaxRefine].setCurr<<" to "<<mLevel[mMaxRefine].setOther<<" step"<< (mLevel[mMaxRefine].lsteps), 3 ); }
-
- // update other set
- mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr;
- mLevel[mMaxRefine].setCurr ^= 1;
- mLevel[mMaxRefine].lsteps++;
-
- // flag init... (work on current set, to simplify flag checks)
- reinitFlags( mLevel[mMaxRefine].setCurr );
- if(!mSilent){ debMsgStd("fineAdvance",DM_NOTIFY," flags reinit on set "<< mLevel[mMaxRefine].setCurr, 3 ); }
-
- // DEBUG VEL CHECK
- if(0) {
- int lev = mMaxRefine;
- int workSet = mLevel[lev].setCurr;
- int mi=0,mj=0,mk=0;
- LbmFloat compRho=0.;
- LbmFloat compUx=0.;
- LbmFloat compUy=0.;
- LbmFloat compUz=0.;
- LbmFloat maxUlen=0.;
- LbmVec maxU(0.);
- LbmFloat maxRho=-100.;
- int ri=0,rj=0,rk=0;
-
- FSGR_FORIJK1(lev) {
- if( (RFLAG(lev,i,j,k, workSet) & (CFFluid| CFInter| CFGrFromCoarse| CFGrFromFine| CFGrNorm)) ) {
- compRho=QCELL(lev, i,j,k,workSet, dC);
- compUx = compUy = compUz = 0.0;
- for(int l=1; l<this->cDfNum; l++) {
- LbmFloat df = QCELL(lev, i,j,k,workSet, l);
- compRho += df;
- compUx += (this->dfDvecX[l]*df);
- compUy += (this->dfDvecY[l]*df);
- compUz += (this->dfDvecZ[l]*df);
- }
- LbmVec u(compUx,compUy,compUz);
- LbmFloat nu = norm(u);
- if(nu>maxUlen) {
- maxU = u;
- maxUlen = nu;
- mi=i; mj=j; mk=k;
- }
- if(compRho>maxRho) {
- maxRho=compRho;
- ri=i; rj=j; rk=k;
- }
- } else {
- continue;
- }
- }
-
- errMsg("MAXVELCHECK"," at "<<PRINT_VEC(mi,mj,mk)<<" norm:"<<maxUlen<<" u:"<<maxU);
- errMsg("MAXRHOCHECK"," at "<<PRINT_VEC(ri,rj,rk)<<" rho:"<<maxRho);
- printLbmCell(lev, 30,36,23, -1);
- } // DEBUG VEL CHECK
-
-}
-
-
-
-// fine step defines
-
-// access to own dfs during step (may be changed to local array)
-#define MYDF(l) RAC(ccel, l)
-
-// drop model definitions
-#define RWVEL_THRESH 1.5
-#define RWVEL_WINDTHRESH (RWVEL_THRESH*0.5)
-
-#if LBMDIM==3
-// normal
-#define SLOWDOWNREGION (mSizez/4)
-#else // LBMDIM==2
-// off
-#define SLOWDOWNREGION 10
-#endif // LBMDIM==2
-#define P_LCSMQO 0.01
-
-/*****************************************************************************/
-//! fine step function
-/*****************************************************************************/
-void
-LbmFsgrSolver::mainLoop(const int lev)
-{
- // loops over _only inner_ cells -----------------------------------------------------------------------------------
-
- // slow surf regions smooth (if below)
- const LbmFloat smoothStrength = 0.0; //0.01;
- const LbmFloat sssUsqrLimit = 1.5 * 0.03*0.03;
- const LbmFloat sssUsqrLimitInv = 1.0/sssUsqrLimit;
-
- const int cutMin = 1;
- const int cutConst = mCutoff+2;
-
-
-# if LBM_INCLUDE_TESTSOLVERS==1
- // 3d region off... quit
- if((mUseTestdata)&&(mpTest->mFarfMode>0)) { return; }
-# endif // ELBEEM_PLUGIN!=1
-
- // main loop region
- const bool doReduce = true;
- const int gridLoopBound=1;
- int calcNumInvIfCells = 0;
- LbmFloat calcInitialMass = 0;
- GRID_REGION_INIT();
-#if PARALLEL==1
- const int gDebugLevel = ::gDebugLevel;
-#pragma omp parallel num_threads(mNumOMPThreads) \
- reduction(+: \
- calcCurrentMass,calcCurrentVolume, \
- calcCellsFilled,calcCellsEmptied, \
- calcNumUsedCells,calcNumInvIfCells,calcInitialMass)
- GRID_REGION_START();
-#else // PARALLEL==1
- GRID_REGION_START();
-#endif // PARALLEL==1
-
- // local to main
- CellFlagType nbflag[LBM_DFNUM];
- int oldFlag, newFlag, nbored;
- LbmFloat m[LBM_DFNUM];
- LbmFloat rho, ux, uy, uz, tmp, usqr;
-
- // smago vars
- LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega;
-
- // ifempty cell conversion flags
- bool iffilled, ifemptied;
- LbmFloat nbfracs[LBM_DFNUM]; // ffracs of neighbors
- int recons[LBM_DFNUM]; // reconstruct this DF?
- int numRecons; // how many are reconstructed?
-
- LbmFloat mass=0., change=0., lcsmqo=0.;
- rho= ux= uy= uz= usqr= tmp= 0.;
- lcsmqadd = lcsmomega = 0.;
- FORDF0{ lcsmeq[l] = 0.; }
-
- // ---
- // now stream etc.
- // use //template functions for 2D/3D
-
- GRID_LOOP_START();
- // loop start
- // stream from current set to other, then collide and store
- //errMsg("l2"," at "<<PRINT_IJK<<" id"<<id);
-
-# if FSGR_STRICT_DEBUG==1
- // safety pointer check
- rho = ux = uy = uz = tmp = usqr = -100.0; // DEBUG
- if( (&RFLAG(lev, i,j,k,mLevel[lev].setCurr) != pFlagSrc) ||
- (&RFLAG(lev, i,j,k,mLevel[lev].setOther) != pFlagDst) ) {
- errMsg("LbmFsgrSolver::mainLoop","Err flagp "<<PRINT_IJK<<"="<<
- RFLAG(lev, i,j,k,mLevel[lev].setCurr)<<","<<RFLAG(lev, i,j,k,mLevel[lev].setOther)<<" but is "<<
- (*pFlagSrc)<<","<<(*pFlagDst) <<", pointers "<<
- (long)(&RFLAG(lev, i,j,k,mLevel[lev].setCurr))<<","<<(long)(&RFLAG(lev, i,j,k,mLevel[lev].setOther))<<" but is "<<
- (long)(pFlagSrc)<<","<<(long)(pFlagDst)<<" "
- );
- CAUSE_PANIC;
- }
- if( (&QCELL(lev, i,j,k,mLevel[lev].setCurr,0) != ccel) ||
- (&QCELL(lev, i,j,k,mLevel[lev].setOther,0) != tcel) ) {
- errMsg("LbmFsgrSolver::mainLoop","Err cellp "<<PRINT_IJK<<"="<<
- (long)(&QCELL(lev, i,j,k,mLevel[lev].setCurr,0))<<","<<(long)(&QCELL(lev, i,j,k,mLevel[lev].setOther,0))<<" but is "<<
- (long)(ccel)<<","<<(long)(tcel)<<" "
- );
- CAUSE_PANIC;
- }
-# endif
- oldFlag = *pFlagSrc;
-
- // old INTCFCOARSETEST==1
- if( (oldFlag & (CFGrFromCoarse)) ) {
- if(( mStepCnt & (1<<(mMaxRefine-lev)) ) ==1) {
- FORDF0 { RAC(tcel,l) = RAC(ccel,l); }
- } else {
- interpolateCellFromCoarse( lev, i,j,k, TSET(lev), 0.0, CFFluid|CFGrFromCoarse, false);
- calcNumUsedCells++;
- }
- continue; // interpolateFineFromCoarse test!
- } // interpolateFineFromCoarse test!
-
- if(oldFlag & (CFMbndInflow)) {
- // fluid & if are ok, fill if later on
- int isValid = oldFlag & (CFFluid|CFInter);
- const LbmFloat iniRho = 1.0;
- const int OId = oldFlag>>24;
- if(!isValid) {
- // make new if cell
- const LbmVec vel(mObjectSpeeds[OId]);
- // TODO add OPT3D treatment
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, iniRho,vel[0],vel[1],vel[2]); }
- RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
- RAC(tcel, dFlux) = FLUX_INIT;
- changeFlag(lev, i,j,k, TSET(lev), CFInter);
- calcCurrentMass += iniRho;
- calcCurrentVolume += 1.0;
- calcNumUsedCells++;
- calcInitialMass += iniRho;
- // dont treat cell until next step
- continue;
- }
- }
- else // these are exclusive
- if(oldFlag & (CFMbndOutflow)) {
- int isnotValid = oldFlag & (CFFluid);
- if(isnotValid) {
- // remove fluid cells, shouldnt be here anyway
- LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; }
- calcInitialMass -= fluidRho;
- const LbmFloat iniRho = 0.0;
- RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
- RAC(tcel, dFlux) = FLUX_INIT;
- changeFlag(lev, i,j,k, TSET(lev), CFInter);
-
- // same as ifemptied for if below
- LbmPoint oemptyp; oemptyp.flag = 0;
- oemptyp.x = i; oemptyp.y = j; oemptyp.z = k;
- LIST_EMPTY(oemptyp);
- calcCellsEmptied++;
- continue;
- }
- }
-
- if(oldFlag & (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)) {
- *pFlagDst = oldFlag;
- continue;
- }
- /*if( oldFlag & CFNoBndFluid ) { // TEST ME FASTER?
- OPTIMIZED_STREAMCOLLIDE; PERFORM_USQRMAXCHECK;
- RAC(tcel,dFfrac) = 1.0;
- *pFlagDst = (CellFlagType)oldFlag; // newFlag;
- calcCurrentMass += rho; calcCurrentVolume += 1.0;
- calcNumUsedCells++;
- continue;
- }// TEST ME FASTER? */
-
- // only neighbor flags! not own flag
- nbored = 0;
-
-#if OPT3D==0
- FORDF1 {
- nbflag[l] = RFLAG_NB(lev, i,j,k,SRCS(lev),l);
- nbored |= nbflag[l];
- }
-#else
- nbflag[dSB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dSB];
- nbflag[dWB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWB];
- nbflag[ dB] = *(pFlagSrc + (-mLevel[lev].lOffsy)); nbored |= nbflag[dB];
- nbflag[dEB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dEB];
- nbflag[dNB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNB];
-
- nbflag[dSW] = *(pFlagSrc + (-mLevel[lev].lOffsx+-1)); nbored |= nbflag[dSW];
- nbflag[ dS] = *(pFlagSrc + (-mLevel[lev].lOffsx)); nbored |= nbflag[dS];
- nbflag[dSE] = *(pFlagSrc + (-mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dSE];
-
- nbflag[ dW] = *(pFlagSrc + (-1)); nbored |= nbflag[dW];
- nbflag[ dE] = *(pFlagSrc + ( 1)); nbored |= nbflag[dE];
-
- nbflag[dNW] = *(pFlagSrc + ( mLevel[lev].lOffsx+-1)); nbored |= nbflag[dNW];
- nbflag[ dN] = *(pFlagSrc + ( mLevel[lev].lOffsx)); nbored |= nbflag[dN];
- nbflag[dNE] = *(pFlagSrc + ( mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dNE];
-
- nbflag[dST] = *(pFlagSrc + ( mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dST];
- nbflag[dWT] = *(pFlagSrc + ( mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWT];
- nbflag[ dT] = *(pFlagSrc + ( mLevel[lev].lOffsy)); nbored |= nbflag[dT];
- nbflag[dET] = *(pFlagSrc + ( mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dET];
- nbflag[dNT] = *(pFlagSrc + ( mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNT];
- // */
-#endif
-
- // pointer to destination cell
- calcNumUsedCells++;
-
- // FLUID cells
- if( oldFlag & CFFluid ) {
- // only standard fluid cells (with nothing except fluid as nbs
-
- if(oldFlag&CFMbndInflow) {
- // force velocity for inflow, necessary to have constant direction of flow
- // FIXME , test also set interface cells?
- const int OId = oldFlag>>24;
- //? DEFAULT_STREAM;
- //const LbmFloat fluidRho = 1.0;
- // for submerged inflows, streaming would have to be performed...
- LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; }
- const LbmVec vel(mObjectSpeeds[OId]);
- ux=vel[0], uy=vel[1], uz=vel[2];
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz);
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, fluidRho,ux,uy,uz); }
- rho = fluidRho;
- //errMsg("INFLOW_DEBUG","std at "<<PRINT_IJK<<" v="<<vel<<" rho="<<rho);
- } else {
- if(nbored&CFBnd) {
- DEFAULT_STREAM;
- //ux = [0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2];
- DEFAULT_COLLIDEG(mLevel[lev].gravity);
- oldFlag &= (~CFNoBndFluid);
- } else {
- // do standard stream/collide
- OPTIMIZED_STREAMCOLLIDE;
- oldFlag |= CFNoBndFluid;
- }
- }
-
- PERFORM_USQRMAXCHECK;
- // "normal" fluid cells
- RAC(tcel,dFfrac) = 1.0;
- *pFlagDst = (CellFlagType)oldFlag; // newFlag;
- calcCurrentMass += rho;
- calcCurrentVolume += 1.0;
- continue;
- }
-
- newFlag = oldFlag;
- // make sure here: always check which flags to really unset...!
- newFlag = newFlag & (~(
- CFNoNbFluid|CFNoNbEmpty| CFNoDelete
- | CFNoInterpolSrc
- | CFNoBndFluid
- ));
- if(!(nbored&CFBndNoslip)) { //NEWSURFT NEWSURFTNOS
- newFlag |= CFNoBndFluid;
- }
- /*if(!(nbored&CFBnd)) { //NEWSURFT NEWSURFTNOS
- // explicitly check for noslip neighbors
- bool hasnoslipnb = false;
- FORDF1 { if((nbflag[l]&CFBnd)&&(nbflag[l]&CFBndNoslip)) hasnoslipnb=true; }
- if(!hasnoslipnb) newFlag |= CFNoBndFluid;
- } // */
-
- // store own dfs and mass
- mass = RAC(ccel,dMass);
-
- // WARNING - only interface cells arrive here!
- // read distribution funtions of adjacent cells = stream step
- DEFAULT_STREAM;
-
- if((nbored & CFFluid)==0) { newFlag |= CFNoNbFluid; calcNumInvIfCells++; }
- if((nbored & CFEmpty)==0) { newFlag |= CFNoNbEmpty; calcNumInvIfCells++; }
-
- // calculate mass exchange for interface cells
- LbmFloat myfrac = RAC(ccel,dFfrac);
- if(myfrac<0.) myfrac=0.; // NEWSURFT
-# define nbdf(l) m[ this->dfInv[(l)] ]
-
- // update mass
- // only do boundaries for fluid cells, and interface cells without
- // any fluid neighbors (assume that interface cells _with_ fluid
- // neighbors are affected enough by these)
- // which Df's have to be reconstructed?
- // for fluid cells - just the f_i difference from streaming to empty cells ----
- numRecons = 0;
- bool onlyBndnb = ((!(oldFlag&CFNoBndFluid))&&(oldFlag&CFNoNbFluid)&&(nbored&CFBndNoslip));
- //onlyBndnb = false; // DEBUG test off
-
- FORDF1 { // dfl loop
- recons[l] = 0;
- nbfracs[l] = 0.0;
- // finally, "normal" interface cells ----
- if( nbflag[l]&(CFFluid|CFBnd) ) { // NEWTEST! FIXME check!!!!!!!!!!!!!!!!!!
- change = nbdf(l) - MYDF(l);
- }
- // interface cells - distuingish cells that shouldn't fill/empty
- else if( nbflag[l] & CFInter ) {
-
- LbmFloat mynbfac,nbnbfac;
- // NEW TEST t1
- // t2 -> off
- if((oldFlag&CFNoBndFluid)&&(nbflag[l]&CFNoBndFluid)) {
- mynbfac = QCELL_NB(lev, i,j,k,SRCS(lev),l, dFlux) / QCELL(lev, i,j,k,SRCS(lev), dFlux);
- nbnbfac = 1.0/mynbfac;
- onlyBndnb = false;
- } else {
- mynbfac = nbnbfac = 1.0; // switch calc flux off
- goto changeDefault; // NEWSURFT
- //change = 0.; goto changeDone; // NEWSURFT
- }
- //mynbfac = nbnbfac = 1.0; // switch calc flux off t3
-
- // perform interface case handling
- if ((oldFlag|nbflag[l])&(CFNoNbFluid|CFNoNbEmpty)) {
- switch (oldFlag&(CFNoNbFluid|CFNoNbEmpty)) {
- case 0:
- // we are a normal cell so...
- switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) {
- case CFNoNbFluid:
- // just fill current cell = empty neighbor
- change = nbnbfac*nbdf(l) ; goto changeDone;
- case CFNoNbEmpty:
- // just empty current cell = fill neighbor
- change = - mynbfac*MYDF(l) ; goto changeDone;
- }
- break;
-
- case CFNoNbFluid:
- // we dont have fluid nb's so...
- switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) {
- case 0:
- case CFNoNbEmpty:
- // we have no fluid nb's -> just empty
- change = - mynbfac*MYDF(l) ; goto changeDone;
- }
- break;
-
- case CFNoNbEmpty:
- // we dont have empty nb's so...
- switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) {
- case 0:
- case CFNoNbFluid:
- // we have no empty nb's -> just fill
- change = nbnbfac*nbdf(l); goto changeDone;
- }
- break;
- }} // inter-inter exchange
-
- changeDefault: ;
- // just do normal mass exchange...
- change = ( nbnbfac*nbdf(l) - mynbfac*MYDF(l) ) ;
- changeDone: ;
- nbfracs[l] = QCELL_NB(lev, i,j,k, SRCS(lev),l, dFfrac);
- if(nbfracs[l]<0.) nbfracs[l] = 0.; // NEWSURFT
- change *= (myfrac + nbfracs[l]) * 0.5;
- } // the other cell is interface
-
- // last alternative - reconstruction in this direction
- else {
- // empty + bnd case
- recons[l] = 1;
- numRecons++;
- change = 0.0;
- }
-
- // modify mass at SRCS
- mass += change;
- } // l
- // normal interface, no if empty/fluid
-
- // computenormal
- LbmFloat surfaceNormal[3];
- computeFluidSurfaceNormal(ccel,pFlagSrc, surfaceNormal);
-
- if( (ABS(surfaceNormal[0])+ABS(surfaceNormal[1])+ABS(surfaceNormal[2])) > LBM_EPSILON) {
- // normal ok and usable...
- FORDF1 {
- if( (this->dfDvecX[l]*surfaceNormal[0] + this->dfDvecY[l]*surfaceNormal[1] + this->dfDvecZ[l]*surfaceNormal[2]) // dot Dvec,norml
- > LBM_EPSILON) {
- recons[l] = 2;
- numRecons++;
- }
- }
- }
-
- // calculate macroscopic cell values
- LbmFloat oldUx, oldUy, oldUz;
- LbmFloat oldRho; // OLD rho = ccel->rho;
-# define REFERENCE_PRESSURE 1.0 // always atmosphere...
-# if OPT3D==0
- oldRho=RAC(ccel,0);
- oldUx = oldUy = oldUz = 0.0;
- for(int l=1; l<this->cDfNum; l++) {
- oldRho += RAC(ccel,l);
- oldUx += (this->dfDvecX[l]*RAC(ccel,l));
- oldUy += (this->dfDvecY[l]*RAC(ccel,l));
- oldUz += (this->dfDvecZ[l]*RAC(ccel,l));
- }
- // reconstruct dist funcs from empty cells
- FORDF1 {
- if(recons[ l ]) {
- m[ this->dfInv[l] ] =
- this->getCollideEq(l, REFERENCE_PRESSURE, oldUx,oldUy,oldUz) +
- this->getCollideEq(this->dfInv[l], REFERENCE_PRESSURE, oldUx,oldUy,oldUz)
- - MYDF( l );
- }
- }
- ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); // needed later on
-# else // OPT3D==0
- oldRho = + RAC(ccel,dC) + RAC(ccel,dN )
- + RAC(ccel,dS ) + RAC(ccel,dE )
- + RAC(ccel,dW ) + RAC(ccel,dT )
- + RAC(ccel,dB ) + RAC(ccel,dNE)
- + RAC(ccel,dNW) + RAC(ccel,dSE)
- + RAC(ccel,dSW) + RAC(ccel,dNT)
- + RAC(ccel,dNB) + RAC(ccel,dST)
- + RAC(ccel,dSB) + RAC(ccel,dET)
- + RAC(ccel,dEB) + RAC(ccel,dWT)
- + RAC(ccel,dWB);
-
- oldUx = + RAC(ccel,dE) - RAC(ccel,dW)
- + RAC(ccel,dNE) - RAC(ccel,dNW)
- + RAC(ccel,dSE) - RAC(ccel,dSW)
- + RAC(ccel,dET) + RAC(ccel,dEB)
- - RAC(ccel,dWT) - RAC(ccel,dWB);
-
- oldUy = + RAC(ccel,dN) - RAC(ccel,dS)
- + RAC(ccel,dNE) + RAC(ccel,dNW)
- - RAC(ccel,dSE) - RAC(ccel,dSW)
- + RAC(ccel,dNT) + RAC(ccel,dNB)
- - RAC(ccel,dST) - RAC(ccel,dSB);
-
- oldUz = + RAC(ccel,dT) - RAC(ccel,dB)
- + RAC(ccel,dNT) - RAC(ccel,dNB)
- + RAC(ccel,dST) - RAC(ccel,dSB)
- + RAC(ccel,dET) - RAC(ccel,dEB)
- + RAC(ccel,dWT) - RAC(ccel,dWB);
-
- (void)oldRho;
-
- // now reconstruction
- ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr
- rho = REFERENCE_PRESSURE;
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); // needed later on
- if(recons[dN ]) { m[dS ] = EQN + EQS - MYDF(dN ); }
- if(recons[dS ]) { m[dN ] = EQS + EQN - MYDF(dS ); }
- if(recons[dE ]) { m[dW ] = EQE + EQW - MYDF(dE ); }
- if(recons[dW ]) { m[dE ] = EQW + EQE - MYDF(dW ); }
- if(recons[dT ]) { m[dB ] = EQT + EQB - MYDF(dT ); }
- if(recons[dB ]) { m[dT ] = EQB + EQT - MYDF(dB ); }
- if(recons[dNE]) { m[dSW] = EQNE + EQSW - MYDF(dNE); }
- if(recons[dNW]) { m[dSE] = EQNW + EQSE - MYDF(dNW); }
- if(recons[dSE]) { m[dNW] = EQSE + EQNW - MYDF(dSE); }
- if(recons[dSW]) { m[dNE] = EQSW + EQNE - MYDF(dSW); }
- if(recons[dNT]) { m[dSB] = EQNT + EQSB - MYDF(dNT); }
- if(recons[dNB]) { m[dST] = EQNB + EQST - MYDF(dNB); }
- if(recons[dST]) { m[dNB] = EQST + EQNB - MYDF(dST); }
- if(recons[dSB]) { m[dNT] = EQSB + EQNT - MYDF(dSB); }
- if(recons[dET]) { m[dWB] = EQET + EQWB - MYDF(dET); }
- if(recons[dEB]) { m[dWT] = EQEB + EQWT - MYDF(dEB); }
- if(recons[dWT]) { m[dEB] = EQWT + EQEB - MYDF(dWT); }
- if(recons[dWB]) { m[dET] = EQWB + EQET - MYDF(dWB); }
-# endif
-
-
- // inflow bc handling
- if(oldFlag & (CFMbndInflow)) {
- // fill if cells in inflow region
- if(myfrac<0.5) {
- mass += 0.25;
- calcInitialMass += 0.25;
- }
- const int OId = oldFlag>>24;
- const LbmVec vel(mObjectSpeeds[OId]);
- ux=vel[0], uy=vel[1], uz=vel[2];
- //? usqr = 1.5 * (ux*ux + uy*uy + uz*uz);
- //FORDF0 { RAC(tcel, l) = this->getCollideEq(l, fluidRho,ux,uy,uz); } rho = fluidRho;
- rho = REFERENCE_PRESSURE;
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,ux,uy,uz); }
- //errMsg("INFLOW_DEBUG","if at "<<PRINT_IJK<<" v="<<vel<<" rho="<<rho);
- } else {
- // NEWSURFT, todo optimize!
- if(onlyBndnb) { //if(usqr<0.001*0.001) {
- rho = ux = uy = uz = 0.;
- FORDF0{
- rho += m[l];
- ux += (this->dfDvecX[l]*m[l]);
- uy += (this->dfDvecY[l]*m[l]);
- uz += (this->dfDvecZ[l]*m[l]);
- }
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,ux,uy,uz); }
- } else {// NEWSURFT */
- if(usqr>0.3*0.3) {
- // force reset! , warning causes distortions...
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,0.,0.,0.); }
- } else {
- // normal collide
- // mass streaming done... do normal collide
- LbmVec grav = mLevel[lev].gravity*mass;
- DEFAULT_COLLIDEG(grav);
- PERFORM_USQRMAXCHECK; }
- // rho init from default collide necessary for fill/empty check below
- } // test
- }
-
- // testing..., particle generation
- // also check oldFlag for CFNoNbFluid, test
- // for inflow no pargen test // NOBUBBB!
- if((mInitDone)
- // dont allow new if cells, or submerged ones
- && (!((oldFlag|newFlag)& (CFNoDelete|CFNoNbEmpty) ))
- // dont try to subtract from empty cells
- && (mass>0.) && (mPartGenProb>0.0)) {
- bool doAdd = true;
- bool bndOk=true;
- if( (i<cutMin)||(i>mSizex-cutMin)||
- (j<cutMin)||(j>mSizey-cutMin)||
- (k<cutMin)||(k>mSizez-cutMin) ) { bndOk=false; }
- if(!bndOk) doAdd=false;
-
- LbmFloat prob = (rand()/(RAND_MAX+1.0));
- LbmFloat basethresh = mPartGenProb*lcsmqo*(LbmFloat)(mSizez+mSizey+mSizex)*0.5*0.333;
-
- // physical drop model
- if(mPartUsePhysModel) {
- LbmFloat realWorldFac = (mLevel[lev].simCellSize / mLevel[lev].timestep);
- LbmVec ru(ux * realWorldFac, uy * realWorldFac, uz * realWorldFac);
- LbmFloat rl = norm(ru);
- basethresh *= rl;
-
- // reduce probability in outer region?
- const int pibord = mLevel[mMaxRefine].lSizex/2-cutConst;
- const int pjbord = mLevel[mMaxRefine].lSizey/2-cutConst;
- LbmFloat pifac = 1.-(LbmFloat)(ABS(i-pibord)) / (LbmFloat)(pibord);
- LbmFloat pjfac = 1.-(LbmFloat)(ABS(j-pjbord)) / (LbmFloat)(pjbord);
- if(pifac<0.) pifac=0.;
- if(pjfac<0.) pjfac=0.;
-
- //if( (prob< (basethresh*rl)) && (lcsmqo>0.0095) && (rl>RWVEL_THRESH) ) {
- if( (prob< (basethresh*rl*pifac*pjfac)) && (lcsmqo>0.0095) && (rl>RWVEL_THRESH) ) {
- // add
- } else {
- doAdd = false; // dont...
- }
-
- // "wind" disturbance
- // use realworld relative velocity here instead?
- if( (doAdd &&
- ((rl>RWVEL_WINDTHRESH) && (lcsmqo<P_LCSMQO)) )// normal checks
- ||(k>mSizez-SLOWDOWNREGION) ) {
- LbmFloat nuz = uz;
- if(k>mSizez-SLOWDOWNREGION) {
- // special case
- LbmFloat zfac = (LbmFloat)( k-(mSizez-SLOWDOWNREGION) );
- zfac /= (LbmFloat)(SLOWDOWNREGION);
- nuz += (1.0) * zfac; // check max speed? OFF?
- //errMsg("TOPT"," at "<<PRINT_IJK<<" zfac"<<zfac);
- } else {
- // normal probability
- //? LbmFloat fac = P_LCSMQO-lcsmqo;
- //? jdf *= fac;
- }
- FORDF1 {
- const LbmFloat jdf = 0.05 * (rand()/(RAND_MAX+1.0));
- // TODO use wind velocity?
- if(jdf>0.025) {
- const LbmFloat add = this->dfLength[l]*(-ux*this->dfDvecX[l]-uy*this->dfDvecY[l]-nuz*this->dfDvecZ[l])*jdf;
- RAC(tcel,l) += add; }
- }
- //errMsg("TOPDOWNCORR"," jdf:"<<jdf<<" rl"<<rl<<" vel "<<norm(LbmVec(ux,uy,nuz))<<" rwv"<<norm(LbmVec(rux,ruy,ruz)) );
- } // wind disturbance
- } // mPartUsePhysModel
- else {
- // empirical model
- //if((prob<basethresh) && (lcsmqo>0.0095)) { // add
- if((prob<basethresh) && (lcsmqo>0.012)) { // add
- } else { doAdd = false; }// dont...
- }
-
-
- // remove noise
- if(usqr<0.0001) doAdd=false; // TODO check!?
-
- // dont try to subtract from empty cells
- // ensure cell has enough mass for new drop
- LbmFloat newPartsize = 1.0;
- if(mPartUsePhysModel) {
- // 1-10
- newPartsize += 9.0* (rand()/(RAND_MAX+1.0));
- } else {
- // 1-5, overall size has to be less than
- // .62 (ca. 0.5) to make drops significantly smaller
- // than a full cell!
- newPartsize += 4.0* (rand()/(RAND_MAX+1.0));
- }
- LbmFloat dropmass = ParticleObject::getMass(mPartDropMassSub*newPartsize); //PARTMASS(mPartDropMassSub*newPartsize); // mass: 4/3 pi r^3 rho
- while(dropmass>mass) {
- newPartsize -= 0.2;
- dropmass = ParticleObject::getMass(mPartDropMassSub*newPartsize);
- }
- if(newPartsize<=1.) doAdd=false;
-
- if( (doAdd) ) { // init new particle
- for(int s=0; s<1; s++) { // one part!
- const LbmFloat posjitter = 0.05;
- const LbmFloat posjitteroffs = posjitter*-0.5;
- LbmFloat jpx = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0));
- LbmFloat jpy = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0));
- LbmFloat jpz = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0));
-
- const LbmFloat jitterstr = 1.0;
- const LbmFloat jitteroffs = jitterstr*-0.5;
- LbmFloat jx = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0));
- LbmFloat jy = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0));
- LbmFloat jz = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0));
-
- // average normal & velocity
- // -> mostly along velocity dir, many into surface
- // fluid velocity (not normalized!)
- LbmVec flvelVel(ux,uy,uz);
- LbmFloat flvelLen = norm(flvelVel);
- // surface normal
- LbmVec normVel(surfaceNormal[0],surfaceNormal[1],surfaceNormal[2]);
- normalize(normVel);
- LbmFloat normScale = (0.01+flvelLen);
- // jitter vector, 0.2 * flvel
- LbmVec jittVel(jx,jy,jz);
- jittVel *= (0.05+flvelLen)*0.1;
- // weighten velocities
- const LbmFloat flvelWeight = 0.9;
- LbmVec newpartVel = normVel*normScale*(1.-flvelWeight) + flvelVel*(flvelWeight) + jittVel;
-
- // offset towards surface (hide popping)
- jpx += -normVel[0]*0.4;
- jpy += -normVel[1]*0.4;
- jpz += -normVel[2]*0.4;
-
- LbmFloat srci=i+0.5+jpx, srcj=j+0.5+jpy, srck=k+0.5+jpz;
- int type=0;
- type = PART_DROP;
-
-# if LBMDIM==2
- newpartVel[2]=0.; srck=0.5;
-# endif // LBMDIM==2
- // subtract drop mass
- mass -= dropmass;
- // init new particle
- {
- ParticleObject np( ntlVec3Gfx(srci,srcj,srck) );
- np.setVel(newpartVel[0],newpartVel[1],newpartVel[2]);
- np.setStatus(PART_IN);
- np.setType(type);
- //if((s%3)==2) np.setType(PART_FLOAT);
- np.setSize(newPartsize);
- //errMsg("NEWPART"," at "<<PRINT_IJK<<" u="<<norm(LbmVec(ux,uy,uz)) <<" add"<<doAdd<<" pvel="<<norm(newpartVel)<<" size="<<newPartsize );
- //errMsg("NEWPT","u="<<newpartVel<<" norm="<<normVel<<" flvel="<<flvelVel<<" jitt="<<jittVel );
- FSGR_ADDPART(np);
- } // new part
- //errMsg("PIT","NEW pit"<<np.getId()<<" pos:"<< np.getPos()<<" status:"<<convertFlags2String(np.getFlags())<<" vel:"<< np.getVel() );
- } // multiple parts
- } // doAdd
- } // */
-
-
- // interface cell filled or emptied?
- iffilled = ifemptied = 0;
- // interface cells empty/full?, WARNING: to mark these cells, better do it at the end of reinitCellFlags
- // interface cell if full?
- if( (mass) >= (rho * (1.0+FSGR_MAGICNR)) ) { iffilled = 1; }
- // interface cell if empty?
- if( (mass) <= (rho * ( -FSGR_MAGICNR)) ) { ifemptied = 1; }
-
- if(oldFlag & (CFMbndOutflow)) {
- calcInitialMass -= mass;
- mass = myfrac = 0.0;
- iffilled = 0; ifemptied = 1;
- }
-
- // looks much nicer... LISTTRICK
-# if FSGR_LISTTRICK==1
- //if((oldFlag&CFNoNbEmpty)&&(newFlag&CFNoNbEmpty)) { TEST_IF_CHECK; }
- if(newFlag&CFNoBndFluid) { // test NEW TEST
- if(!iffilled) {
- // remove cells independent from amount of change...
- if( (oldFlag & CFNoNbEmpty)&&(newFlag & CFNoNbEmpty)&&
- ( (mass>(rho*FSGR_LISTTTHRESHFULL)) || ((nbored&CFInter)==0) )) {
- //if((nbored&CFInter)==0){ errMsg("NBORED!CFINTER","filled "<<PRINT_IJK); };
- iffilled = 1;
- }
- }
- if(!ifemptied) {
- if( (oldFlag & CFNoNbFluid)&&(newFlag & CFNoNbFluid)&&
- ( (mass<(rho*FSGR_LISTTTHRESHEMPTY)) || ((nbored&CFInter)==0) )) {
- //if((nbored&CFInter)==0){ errMsg("NBORED!CFINTER","emptied "<<PRINT_IJK); };
- ifemptied = 1;
- }
- }
- } // nobndfluid only */
-# endif
- //iffilled = ifemptied = 0; // DEBUG!!!!!!!!!!!!!!!
-
-
- // now that all dfs are known, handle last changes
- if(iffilled) {
- LbmPoint filledp; filledp.flag=0;
- if(!(newFlag&CFNoBndFluid)) filledp.flag |= 1; // NEWSURFT
- filledp.x = i; filledp.y = j; filledp.z = k;
- LIST_FULL(filledp);
- //mNumFilledCells++; // DEBUG
- calcCellsFilled++;
- }
- else if(ifemptied) {
- LbmPoint emptyp; emptyp.flag=0;
- if(!(newFlag&CFNoBndFluid)) emptyp.flag |= 1; // NEWSURFT
- emptyp.x = i; emptyp.y = j; emptyp.z = k;
- LIST_EMPTY(emptyp);
- //mNumEmptiedCells++; // DEBUG
- calcCellsEmptied++;
- }
- // dont cutoff values -> better cell conversions
- RAC(tcel,dFfrac) = (mass/rho);
-
- // init new flux value
- float flux = FLUX_INIT; // dxqn on
- if(newFlag&CFNoBndFluid) {
- //flux = 50.0; // extreme on
- for(int nn=1; nn<this->cDfNum; nn++) {
- if(nbflag[nn] & (CFFluid|CFInter|CFBnd)) { flux += this->dfLength[nn]; }
- }
- // optical hack - smooth slow moving
- // surface regions
- if(usqr< sssUsqrLimit) {
- for(int nn=1; nn<this->cDfNum; nn++) {
- if(nbfracs[nn]!=0.0) {
- LbmFloat curSmooth = (sssUsqrLimit-usqr)*sssUsqrLimitInv;
- if(curSmooth>1.0) curSmooth=1.0;
- flux *= (1.0+ smoothStrength*curSmooth * (nbfracs[nn]-myfrac)) ;
- }
- } }
- // NEW TEST */
- }
- // flux = FLUX_INIT; // calc flux off
- QCELL(lev, i,j,k,TSET(lev), dFlux) = flux; // */
-
- // perform mass exchange with streamed values
- QCELL(lev, i,j,k,TSET(lev), dMass) = mass; // MASST
- // set new flag
- *pFlagDst = (CellFlagType)newFlag;
- calcCurrentMass += mass;
- calcCurrentVolume += RAC(tcel,dFfrac);
-
- // interface cell handling done...
-
-#if PARALLEL!=1
- GRID_LOOPREG_END();
-#else // PARALLEL==1
-#include "paraloopend.h" // = GRID_LOOPREG_END();
-#endif // PARALLEL==1
-
- // write vars from computations to class
- mLevel[lev].lmass = calcCurrentMass;
- mLevel[lev].lvolume = calcCurrentVolume;
- mNumFilledCells = calcCellsFilled;
- mNumEmptiedCells = calcCellsEmptied;
- mNumUsedCells = calcNumUsedCells;
- mNumInvIfCells += calcNumInvIfCells;
- mInitialMass += calcInitialMass;
-}
-
-
-
-void
-LbmFsgrSolver::preinitGrids()
-{
- const int lev = mMaxRefine;
- const bool doReduce = false;
- const int gridLoopBound=0;
-
- // preinit both grids
- for(int s=0; s<2; s++) {
-
- GRID_REGION_INIT();
-#if PARALLEL==1
- const int gDebugLevel = ::gDebugLevel;
-#pragma omp parallel num_threads(mNumOMPThreads) \
- reduction(+: \
- calcCurrentMass,calcCurrentVolume, \
- calcCellsFilled,calcCellsEmptied, \
- calcNumUsedCells )
-#endif // PARALLEL==1
- GRID_REGION_START();
- GRID_LOOP_START();
- for(int l=0; l<dTotalNum; l++) { RAC(ccel,l) = 0.; }
- *pFlagSrc =0;
- *pFlagDst =0;
- //errMsg("l1"," at "<<PRINT_IJK<<" id"<<id);
-#if PARALLEL!=1
- GRID_LOOPREG_END();
-#else // PARALLEL==1
-#include "paraloopend.h" // = GRID_LOOPREG_END();
-#endif // PARALLEL==1
-
- /* dummy, remove warnings */
- calcCurrentMass = calcCurrentVolume = 0.;
- calcCellsFilled = calcCellsEmptied = calcNumUsedCells = 0;
-
- // change grid
- mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr;
- mLevel[mMaxRefine].setCurr ^= 1;
- }
-}
-
-void
-LbmFsgrSolver::standingFluidPreinit()
-{
- const int lev = mMaxRefine;
- const bool doReduce = false;
- const int gridLoopBound=1;
-
- GRID_REGION_INIT();
-#if PARALLEL==1
- const int gDebugLevel = ::gDebugLevel;
-#pragma omp parallel num_threads(mNumOMPThreads) \
- reduction(+: \
- calcCurrentMass,calcCurrentVolume, \
- calcCellsFilled,calcCellsEmptied, \
- calcNumUsedCells )
-#endif // PARALLEL==1
- GRID_REGION_START();
-
- LbmFloat rho, ux,uy,uz, usqr;
- CellFlagType nbflag[LBM_DFNUM];
- LbmFloat m[LBM_DFNUM];
- LbmFloat lcsmqo;
-# if OPT3D==1
- LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega;
-# endif // OPT3D==true
-
- GRID_LOOP_START();
- //errMsg("l1"," at "<<PRINT_IJK<<" id"<<id);
- const CellFlagType currFlag = *pFlagSrc; //RFLAG(lev, i,j,k,workSet);
- if( (currFlag & (CFEmpty|CFBnd)) ) continue;
-
- if( (currFlag & (CFInter)) ) {
- // copy all values
- for(int l=0; l<dTotalNum;l++) { RAC(tcel,l) = RAC(ccel,l); }
- continue;
- }
-
- if( (currFlag & CFNoBndFluid)) {
- OPTIMIZED_STREAMCOLLIDE;
- } else {
- FORDF1 {
- nbflag[l] = RFLAG_NB(lev, i,j,k, SRCS(lev),l);
- }
- DEFAULT_STREAM;
- DEFAULT_COLLIDEG(mLevel[lev].gravity);
- }
- for(int l=LBM_DFNUM; l<dTotalNum;l++) { RAC(tcel,l) = RAC(ccel,l); }
-#if PARALLEL!=1
- GRID_LOOPREG_END();
-#else // PARALLEL==1
-#include "paraloopend.h" // = GRID_LOOPREG_END();
-#endif // PARALLEL==1
-
- /* dummy remove warnings */
- calcCurrentMass = calcCurrentVolume = 0.;
- calcCellsFilled = calcCellsEmptied = calcNumUsedCells = 0;
-
- // change grid
- mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr;
- mLevel[mMaxRefine].setCurr ^= 1;
-}
-
-
-/******************************************************************************
- * work on lists from updateCellMass to reinit cell flags
- *****************************************************************************/
-
-LbmFloat LbmFsgrSolver::getMassdWeight(bool dirForw, int i,int j,int k,int workSet, int l) {
- //return 0.0; // test
- int level = mMaxRefine;
- LbmFloat *ccel = RACPNT(level, i,j,k, workSet);
-
- // computenormal
- CellFlagType *cflag = &RFLAG(level, i,j,k, workSet);
- LbmFloat n[3];
- computeFluidSurfaceNormal(ccel,cflag, n);
- LbmFloat scal = mDvecNrm[l][0]*n[0] + mDvecNrm[l][1]*n[1] + mDvecNrm[l][2]*n[2];
-
- LbmFloat ret = 1.0;
- // forward direction, add mass (for filling cells):
- if(dirForw) {
- if(scal<LBM_EPSILON) ret = 0.0;
- else ret = scal;
- } else {
- // backward for emptying
- if(scal>-LBM_EPSILON) ret = 0.0;
- else ret = scal * -1.0;
- }
- //errMsg("massd", PRINT_IJK<<" nv"<<nvel<<" : ret="<<ret ); //xit(1); //VECDEB
- return ret;
-}
-
-// warning - normal compuations are without
-// boundary checks &
-// normalization
-void LbmFsgrSolver::computeFluidSurfaceNormal(LbmFloat *ccel, CellFlagType *cflagpnt,LbmFloat *snret) {
- const int level = mMaxRefine;
- LbmFloat nx,ny,nz, nv1,nv2;
- const CellFlagType flagE = *(cflagpnt+1);
- const CellFlagType flagW = *(cflagpnt-1);
- if(flagE &(CFFluid|CFInter)){ nv1 = RAC((ccel+QCELLSTEP ),dFfrac); }
- else if(flagE &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagW &(CFFluid|CFInter)){ nv2 = RAC((ccel-QCELLSTEP ),dFfrac); }
- else if(flagW &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- nx = 0.5* (nv2-nv1);
-
- const CellFlagType flagN = *(cflagpnt+mLevel[level].lOffsx);
- const CellFlagType flagS = *(cflagpnt-mLevel[level].lOffsx);
- if(flagN &(CFFluid|CFInter)){ nv1 = RAC((ccel+(mLevel[level].lOffsx*QCELLSTEP)),dFfrac); }
- else if(flagN &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagS &(CFFluid|CFInter)){ nv2 = RAC((ccel-(mLevel[level].lOffsx*QCELLSTEP)),dFfrac); }
- else if(flagS &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- ny = 0.5* (nv2-nv1);
-
-#if LBMDIM==3
- const CellFlagType flagT = *(cflagpnt+mLevel[level].lOffsy);
- const CellFlagType flagB = *(cflagpnt-mLevel[level].lOffsy);
- if(flagT &(CFFluid|CFInter)){ nv1 = RAC((ccel+(mLevel[level].lOffsy*QCELLSTEP)),dFfrac); }
- else if(flagT &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagB &(CFFluid|CFInter)){ nv2 = RAC((ccel-(mLevel[level].lOffsy*QCELLSTEP)),dFfrac); }
- else if(flagB &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- nz = 0.5* (nv2-nv1);
-#else //LBMDIM==3
- nz = 0.0;
-#endif //LBMDIM==3
-
- // return vals
- snret[0]=nx; snret[1]=ny; snret[2]=nz;
-}
-void LbmFsgrSolver::computeFluidSurfaceNormalAcc(LbmFloat *ccel, CellFlagType *cflagpnt, LbmFloat *snret) {
- LbmFloat nx=0.,ny=0.,nz=0.;
- ccel = NULL; cflagpnt=NULL; // remove warning
- snret[0]=nx; snret[1]=ny; snret[2]=nz;
-}
-void LbmFsgrSolver::computeObstacleSurfaceNormal(LbmFloat *ccel, CellFlagType *cflagpnt, LbmFloat *snret) {
- const int level = mMaxRefine;
- LbmFloat nx,ny,nz, nv1,nv2;
- ccel = NULL; // remove warning
-
- const CellFlagType flagE = *(cflagpnt+1);
- const CellFlagType flagW = *(cflagpnt-1);
- if(flagE &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagW &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- nx = 0.5* (nv2-nv1);
-
- const CellFlagType flagN = *(cflagpnt+mLevel[level].lOffsx);
- const CellFlagType flagS = *(cflagpnt-mLevel[level].lOffsx);
- if(flagN &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagS &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- ny = 0.5* (nv2-nv1);
-
-#if LBMDIM==3
- const CellFlagType flagT = *(cflagpnt+mLevel[level].lOffsy);
- const CellFlagType flagB = *(cflagpnt-mLevel[level].lOffsy);
- if(flagT &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagB &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- nz = 0.5* (nv2-nv1);
-#else //LBMDIM==3
- nz = 0.0;
-#endif //LBMDIM==3
-
- // return vals
- snret[0]=nx; snret[1]=ny; snret[2]=nz;
-}
-void LbmFsgrSolver::computeObstacleSurfaceNormalAcc(int i,int j,int k, LbmFloat *snret) {
- bool nonorm = false;
- LbmFloat nx=0.,ny=0.,nz=0.;
- if(i<=0) { nx = 1.; nonorm = true; }
- if(i>=mSizex-1) { nx = -1.; nonorm = true; }
- if(j<=0) { ny = 1.; nonorm = true; }
- if(j>=mSizey-1) { ny = -1.; nonorm = true; }
-# if LBMDIM==3
- if(k<=0) { nz = 1.; nonorm = true; }
- if(k>=mSizez-1) { nz = -1.; nonorm = true; }
-# endif // LBMDIM==3
- if(!nonorm) {
- // in domain, revert to helper, use setCurr&mMaxRefine
- LbmVec bnormal;
- CellFlagType *bflag = &RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr);
- LbmFloat *bcell = RACPNT(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr);
- computeObstacleSurfaceNormal(bcell,bflag, &bnormal[0]);
- // TODO check if there is a normal near here?
- // use wider range otherwise...
- snret[0]=bnormal[0]; snret[1]=bnormal[0]; snret[2]=bnormal[0];
- return;
- }
- snret[0]=nx; snret[1]=ny; snret[2]=nz;
-}
-
-void LbmFsgrSolver::addToNewInterList( int ni, int nj, int nk ) {
-#if FSGR_STRICT_DEBUG==10
- // dangerous, this can change the simulation...
- /*for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
- iter != mListNewInter.end(); iter++ ) {
- if(ni!=iter->x) continue;
- if(nj!=iter->y) continue;
- if(nk!=iter->z) continue;
- // all 3 values match... skip point
- return;
- } */
-#endif // FSGR_STRICT_DEBUG==1
- // store point
- LbmPoint newinter; newinter.flag = 0;
- newinter.x = ni; newinter.y = nj; newinter.z = nk;
- mListNewInter.push_back(newinter);
-}
-
-void LbmFsgrSolver::reinitFlags( int workSet ) {
- // reinitCellFlags OLD mods:
- // add all to intel list?
- // check ffrac for new cells
- // new if cell inits (last loop)
- // vweights handling
-
- const int debugFlagreinit = 0;
-
- // some things need to be read/modified on the other set
- int otherSet = (workSet^1);
- // fixed level on which to perform
- int workLev = mMaxRefine;
-
- /* modify interface cells from lists */
- /* mark filled interface cells as fluid, or emptied as empty */
- /* count neighbors and distribute excess mass to interface neighbor cells
- * problems arise when there are no interface neighbors anymore
- * then just distribute to any fluid neighbors...
- */
-
- // for symmetry, first init all neighbor cells */
- for( vector<LbmPoint>::iterator iter=mListFull.begin();
- iter != mListFull.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- if(debugFlagreinit) errMsg("FULL", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) ); // DEBUG SYMM
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- //if((LBMDIM>2)&&( (ni<=0) || (nj<=0) || (nk<=0) || (ni>=mLevel[workLev].lSizex-1) || (nj>=mLevel[workLev].lSizey-1) || (nk>=mLevel[workLev].lSizez-1) )) {
- if( (ni<=0) || (nj<=0) ||
- (ni>=mLevel[workLev].lSizex-1) ||
- (nj>=mLevel[workLev].lSizey-1)
-# if LBMDIM==3
- || (nk<=0) || (nk>=mLevel[workLev].lSizez-1)
-# endif // LBMDIM==1
- ) {
- continue; } // new bc, dont treat cells on boundary NEWBC
- if( RFLAG(workLev, ni,nj,nk, workSet) & CFEmpty ){
-
- // preinit speed, get from average surrounding cells
- // interpolate from non-workset to workset, sets are handled in function
-
- // new and empty interface cell, dont change old flag here!
- addToNewInterList(ni,nj,nk);
-
- LbmFloat avgrho = 0.0;
- LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0;
- interpolateCellValues(workLev,ni,nj,nk,workSet, avgrho,avgux,avguy,avguz);
-
- // careful with l's...
- FORDF0M {
- QCELL(workLev,ni,nj,nk, workSet, m) = this->getCollideEq( m,avgrho, avgux, avguy, avguz );
- //QCELL(workLev,ni,nj,nk, workSet, l) = avgnbdf[l]; // CHECK FIXME test?
- }
- //errMsg("FNEW", PRINT_VEC(ni,nj,nk)<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<<avgrho<<" vel"<<PRINT_VEC(avgux,avguy,avguz) ); // DEBUG SYMM
- QCELL(workLev,ni,nj,nk, workSet, dMass) = 0.0; //?? new
- QCELL(workLev,ni,nj,nk, workSet, dFfrac) = 0.0; //?? new
- //RFLAG(workLev,ni,nj,nk,workSet) = (CellFlagType)(CFInter|CFNoInterpolSrc);
- changeFlag(workLev,ni,nj,nk,workSet, (CFInter|CFNoInterpolSrc));
- if(debugFlagreinit) errMsg("NEWE", PRINT_IJK<<" newif "<<PRINT_VEC(ni,nj,nk)<<" rho"<<avgrho<<" vel("<<avgux<<","<<avguy<<","<<avguz<<") " );
- }
- /* prevent surrounding interface cells from getting removed as empty cells
- * (also cells that are not newly inited) */
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
- //RFLAG(workLev,ni,nj,nk, workSet) = (CellFlagType)(RFLAG(workLev,ni,nj,nk, workSet) | CFNoDelete);
- changeFlag(workLev,ni,nj,nk, workSet, (RFLAG(workLev,ni,nj,nk, workSet) | CFNoDelete));
- // also add to list...
- addToNewInterList(ni,nj,nk);
- } // NEW?
- }
-
- // NEW? no extra loop...
- //RFLAG(workLev,i,j,k, workSet) = CFFluid;
- changeFlag(workLev,i,j,k, workSet,CFFluid);
- }
-
- /* remove empty interface cells that are not allowed to be removed anyway
- * this is important, otherwise the dreaded cell-type-flickering can occur! */
- for(int n=0; n<(int)mListEmpty.size(); n++) {
- int i=mListEmpty[n].x, j=mListEmpty[n].y, k=mListEmpty[n].z;
- if((RFLAG(workLev,i,j,k, workSet)&(CFInter|CFNoDelete)) == (CFInter|CFNoDelete)) {
- // treat as "new inter"
- addToNewInterList(i,j,k);
- // remove entry
- if(debugFlagreinit) errMsg("EMPT REMOVED!!!", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) ); // DEBUG SYMM
- if(n<(int)mListEmpty.size()-1) mListEmpty[n] = mListEmpty[mListEmpty.size()-1];
- mListEmpty.pop_back();
- n--;
- }
- }
-
-
- /* problems arise when adjacent cells empty&fill ->
- let fill cells+surrounding interface cells have the higher importance */
- for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
- iter != mListEmpty.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- if((RFLAG(workLev,i,j,k, workSet)&(CFInter|CFNoDelete)) == (CFInter|CFNoDelete)){ errMsg("A"," ARGHARGRAG "); } // DEBUG
- if(debugFlagreinit) errMsg("EMPT", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) );
-
- /* set surrounding fluid cells to interface cells */
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFFluid){
- // init fluid->interface
- //RFLAG(workLev,ni,nj,nk, workSet) = (CellFlagType)(CFInter);
- changeFlag(workLev,ni,nj,nk, workSet, CFInter);
- /* new mass = current density */
- LbmFloat nbrho = QCELL(workLev,ni,nj,nk, workSet, dC);
- for(int rl=1; rl< this->cDfNum ; ++rl) { nbrho += QCELL(workLev,ni,nj,nk, workSet, rl); }
- QCELL(workLev,ni,nj,nk, workSet, dMass) = nbrho;
- QCELL(workLev,ni,nj,nk, workSet, dFfrac) = 1.0;
-
- // store point
- addToNewInterList(ni,nj,nk);
- }
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter){
- // test, also add to list...
- addToNewInterList(ni,nj,nk);
- } // NEW?
- }
-
- /* for symmetry, set our flag right now */
- changeFlag(workLev,i,j,k, workSet, CFEmpty);
- // mark cell not be changed mass... - not necessary, not in list anymore anyway!
- } // emptylist
-
-
-
- // precompute weights to get rid of order dependancies
- vector<lbmFloatSet> vWeights;
- vWeights.resize( mListFull.size() + mListEmpty.size() );
- int weightIndex = 0;
- int nbCount = 0;
- LbmFloat nbWeights[LBM_DFNUM];
- LbmFloat nbTotWeights = 0.0;
- for( vector<LbmPoint>::iterator iter=mListFull.begin();
- iter != mListFull.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- nbCount = 0; nbTotWeights = 0.0;
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
- nbCount++;
- if(iter->flag&1) nbWeights[l] = 1.; // NEWSURFT
- else nbWeights[l] = getMassdWeight(1,i,j,k,workSet,l); // NEWSURFT
- nbTotWeights += nbWeights[l];
- } else {
- nbWeights[l] = -100.0; // DEBUG;
- }
- }
- if(nbCount>0) {
- //errMsg("FF I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeights);
- vWeights[weightIndex].val[0] = nbTotWeights;
- FORDF1 { vWeights[weightIndex].val[l] = nbWeights[l]; }
- vWeights[weightIndex].numNbs = (LbmFloat)nbCount;
- } else {
- vWeights[weightIndex].numNbs = 0.0;
- }
- weightIndex++;
- }
- for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
- iter != mListEmpty.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- nbCount = 0; nbTotWeights = 0.0;
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
- nbCount++;
- if(iter->flag&1) nbWeights[l] = 1.; // NEWSURFT
- else nbWeights[l] = getMassdWeight(0,i,j,k,workSet,l); // NEWSURFT
- nbTotWeights += nbWeights[l];
- } else {
- nbWeights[l] = -100.0; // DEBUG;
- }
- }
- if(nbCount>0) {
- //errMsg("EE I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeights);
- vWeights[weightIndex].val[0] = nbTotWeights;
- FORDF1 { vWeights[weightIndex].val[l] = nbWeights[l]; }
- vWeights[weightIndex].numNbs = (LbmFloat)nbCount;
- } else {
- vWeights[weightIndex].numNbs = 0.0;
- }
- weightIndex++;
- }
- weightIndex = 0;
-
-
- /* process full list entries, filled cells are done after this loop */
- for( vector<LbmPoint>::iterator iter=mListFull.begin();
- iter != mListFull.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
-
- LbmFloat myrho = QCELL(workLev,i,j,k, workSet, dC);
- FORDF1 { myrho += QCELL(workLev,i,j,k, workSet, l); } // QCELL.rho
-
- LbmFloat massChange = QCELL(workLev,i,j,k, workSet, dMass) - myrho;
- if(vWeights[weightIndex].numNbs>0.0) {
- const LbmFloat nbTotWeightsp = vWeights[weightIndex].val[0];
- //errMsg("FF I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeightsp);
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
- LbmFloat change = -1.0;
- if(nbTotWeightsp>0.0) {
- //change = massChange * ( nbWeights[l]/nbTotWeightsp );
- change = massChange * ( vWeights[weightIndex].val[l]/nbTotWeightsp );
- } else {
- change = (LbmFloat)(massChange/vWeights[weightIndex].numNbs);
- }
- QCELL(workLev,ni,nj,nk, workSet, dMass) += change;
- }
- }
- massChange = 0.0;
- } else {
- // Problem! no interface neighbors
- mFixMass += massChange;
- //TTT mNumProblems++;
- //errMsg(" FULL PROBLEM ", PRINT_IJK<<" "<<mFixMass);
- }
- weightIndex++;
-
- // already done? RFLAG(workLev,i,j,k, workSet) = CFFluid;
- QCELL(workLev,i,j,k, workSet, dMass) = myrho; // should be rho... but unused?
- QCELL(workLev,i,j,k, workSet, dFfrac) = 1.0; // should be rho... but unused?
- } // fulllist
-
-
- /* now, finally handle the empty cells - order is important, has to be after
- * full cell handling */
- for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
- iter != mListEmpty.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
-
- LbmFloat massChange = QCELL(workLev, i,j,k, workSet, dMass);
- if(vWeights[weightIndex].numNbs>0.0) {
- const LbmFloat nbTotWeightsp = vWeights[weightIndex].val[0];
- //errMsg("EE I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeightsp);
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
- LbmFloat change = -1.0;
- if(nbTotWeightsp>0.0) {
- change = massChange * ( vWeights[weightIndex].val[l]/nbTotWeightsp );
- } else {
- change = (LbmFloat)(massChange/vWeights[weightIndex].numNbs);
- }
- QCELL(workLev, ni,nj,nk, workSet, dMass) += change;
- }
- }
- massChange = 0.0;
- } else {
- // Problem! no interface neighbors
- mFixMass += massChange;
- //TTT mNumProblems++;
- //errMsg(" EMPT PROBLEM ", PRINT_IJK<<" "<<mFixMass);
- }
- weightIndex++;
-
- // finally... make it empty
- // already done? RFLAG(workLev,i,j,k, workSet) = CFEmpty;
- QCELL(workLev,i,j,k, workSet, dMass) = 0.0;
- QCELL(workLev,i,j,k, workSet, dFfrac) = 0.0;
- }
- for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
- iter != mListEmpty.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- changeFlag(workLev,i,j,k, otherSet, CFEmpty);
- }
-
-
- // check if some of the new interface cells can be removed again
- // never happens !!! not necessary
- // calculate ffrac for new IF cells NEW
-
- // how many are really new interface cells?
- int numNewIf = 0;
- for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
- iter != mListNewInter.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) {
- continue;
- // FIXME remove from list?
- }
- numNewIf++;
- }
-
- // redistribute mass, reinit flags
- if(debugFlagreinit) errMsg("NEWIF", "total:"<<mListNewInter.size());
- float newIfFac = 1.0/(LbmFloat)numNewIf;
- for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
- iter != mListNewInter.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- if((i<=0) || (j<=0) ||
- (i>=mLevel[workLev].lSizex-1) ||
- (j>=mLevel[workLev].lSizey-1) ||
- ((LBMDIM==3) && ((k<=0) || (k>=mLevel[workLev].lSizez-1) ) )
- ) {
- continue; } // new bc, dont treat cells on boundary NEWBC
- if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) {
- //errMsg("???"," "<<PRINT_IJK);
- continue;
- } // */
-
- QCELL(workLev,i,j,k, workSet, dMass) += (mFixMass * newIfFac);
-
- int nbored = 0;
- FORDF1 { nbored |= RFLAG_NB(workLev, i,j,k, workSet,l); }
- if(!(nbored & CFBndNoslip)) { RFLAG(workLev,i,j,k, workSet) |= CFNoBndFluid; }
- if(!(nbored & CFFluid)) { RFLAG(workLev,i,j,k, workSet) |= CFNoNbFluid; }
- if(!(nbored & CFEmpty)) { RFLAG(workLev,i,j,k, workSet) |= CFNoNbEmpty; }
-
- if(!(RFLAG(workLev,i,j,k, otherSet)&CFInter)) {
- RFLAG(workLev,i,j,k, workSet) = (CellFlagType)(RFLAG(workLev,i,j,k, workSet) | CFNoDelete);
- }
- if(debugFlagreinit) errMsg("NEWIF", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" f"<< convertCellFlagType2String(RFLAG(workLev,i,j,k, workSet))<<" wl"<<workLev );
- }
-
- // reinit fill fraction
- for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
- iter != mListNewInter.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { continue; }
-
- initInterfaceVars(workLev, i,j,k, workSet, false); //int level, int i,int j,int k,int workSet, bool initMass) {
- //LbmFloat nrho = 0.0;
- //FORDF0 { nrho += QCELL(workLev, i,j,k, workSet, l); }
- //QCELL(workLev,i,j,k, workSet, dFfrac) = QCELL(workLev,i,j,k, workSet, dMass)/nrho;
- //QCELL(workLev,i,j,k, workSet, dFlux) = FLUX_INIT;
- }
-
- if(mListNewInter.size()>0){
- //errMsg("FixMassDisted"," fm:"<<mFixMass<<" nif:"<<mListNewInter.size() );
- mFixMass = 0.0;
- }
-
- // empty lists for next step
- mListFull.clear();
- mListEmpty.clear();
- mListNewInter.clear();
-} // reinitFlags
-
-
-
diff --git a/intern/elbeem/intern/solver_relax.h b/intern/elbeem/intern/solver_relax.h
deleted file mode 100644
index d665025ba33..00000000000
--- a/intern/elbeem/intern/solver_relax.h
+++ /dev/null
@@ -1,1169 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - the visual lattice boltzmann freesurface simulator
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Combined 2D/3D Lattice Boltzmann relaxation macros
- *
- *****************************************************************************/
-
-#if FSGR_STRICT_DEBUG==1
-#define CAUSE_PANIC { this->mPanic=1; /* *((int*)(0x0)) = 1; crash*/ }
-#else // FSGR_STRICT_DEBUG==1
-#define CAUSE_PANIC { this->mPanic=1; } /*set flag*/
-#endif // FSGR_STRICT_DEBUG==1
-
-/******************************************************************************
- * normal relaxation
- *****************************************************************************/
-
-// standard arrays
-#define CSRC_C RAC(ccel , dC )
-#define CSRC_E RAC(ccel + (-1) *(dTotalNum), dE )
-#define CSRC_W RAC(ccel + (+1) *(dTotalNum), dW )
-#define CSRC_N RAC(ccel + (-mLevel[lev].lOffsx) *(dTotalNum), dN )
-#define CSRC_S RAC(ccel + (+mLevel[lev].lOffsx) *(dTotalNum), dS )
-#define CSRC_NE RAC(ccel + (-mLevel[lev].lOffsx-1) *(dTotalNum), dNE)
-#define CSRC_NW RAC(ccel + (-mLevel[lev].lOffsx+1) *(dTotalNum), dNW)
-#define CSRC_SE RAC(ccel + (+mLevel[lev].lOffsx-1) *(dTotalNum), dSE)
-#define CSRC_SW RAC(ccel + (+mLevel[lev].lOffsx+1) *(dTotalNum), dSW)
-#define CSRC_T RAC(ccel + (-mLevel[lev].lOffsy) *(dTotalNum), dT )
-#define CSRC_B RAC(ccel + (+mLevel[lev].lOffsy) *(dTotalNum), dB )
-#define CSRC_ET RAC(ccel + (-mLevel[lev].lOffsy-1) *(dTotalNum), dET)
-#define CSRC_EB RAC(ccel + (+mLevel[lev].lOffsy-1) *(dTotalNum), dEB)
-#define CSRC_WT RAC(ccel + (-mLevel[lev].lOffsy+1) *(dTotalNum), dWT)
-#define CSRC_WB RAC(ccel + (+mLevel[lev].lOffsy+1) *(dTotalNum), dWB)
-#define CSRC_NT RAC(ccel + (-mLevel[lev].lOffsy-mLevel[lev].lOffsx) *(dTotalNum), dNT)
-#define CSRC_NB RAC(ccel + (+mLevel[lev].lOffsy-mLevel[lev].lOffsx) *(dTotalNum), dNB)
-#define CSRC_ST RAC(ccel + (-mLevel[lev].lOffsy+mLevel[lev].lOffsx) *(dTotalNum), dST)
-#define CSRC_SB RAC(ccel + (+mLevel[lev].lOffsy+mLevel[lev].lOffsx) *(dTotalNum), dSB)
-
-#define XSRC_C(x) RAC(ccel + (x) *dTotalNum, dC )
-#define XSRC_E(x) RAC(ccel + ((x)-1) *dTotalNum, dE )
-#define XSRC_W(x) RAC(ccel + ((x)+1) *dTotalNum, dW )
-#define XSRC_N(x) RAC(ccel + ((x)-mLevel[lev].lOffsx) *dTotalNum, dN )
-#define XSRC_S(x) RAC(ccel + ((x)+mLevel[lev].lOffsx) *dTotalNum, dS )
-#define XSRC_NE(x) RAC(ccel + ((x)-mLevel[lev].lOffsx-1) *dTotalNum, dNE)
-#define XSRC_NW(x) RAC(ccel + ((x)-mLevel[lev].lOffsx+1) *dTotalNum, dNW)
-#define XSRC_SE(x) RAC(ccel + ((x)+mLevel[lev].lOffsx-1) *dTotalNum, dSE)
-#define XSRC_SW(x) RAC(ccel + ((x)+mLevel[lev].lOffsx+1) *dTotalNum, dSW)
-#define XSRC_T(x) RAC(ccel + ((x)-mLevel[lev].lOffsy) *dTotalNum, dT )
-#define XSRC_B(x) RAC(ccel + ((x)+mLevel[lev].lOffsy) *dTotalNum, dB )
-#define XSRC_ET(x) RAC(ccel + ((x)-mLevel[lev].lOffsy-1) *dTotalNum, dET)
-#define XSRC_EB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy-1) *dTotalNum, dEB)
-#define XSRC_WT(x) RAC(ccel + ((x)-mLevel[lev].lOffsy+1) *dTotalNum, dWT)
-#define XSRC_WB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy+1) *dTotalNum, dWB)
-#define XSRC_NT(x) RAC(ccel + ((x)-mLevel[lev].lOffsy-mLevel[lev].lOffsx) *dTotalNum, dNT)
-#define XSRC_NB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy-mLevel[lev].lOffsx) *dTotalNum, dNB)
-#define XSRC_ST(x) RAC(ccel + ((x)-mLevel[lev].lOffsy+mLevel[lev].lOffsx) *dTotalNum, dST)
-#define XSRC_SB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy+mLevel[lev].lOffsx) *dTotalNum, dSB)
-
-
-
-#define OMEGA(l) mLevel[(l)].omega
-
-#define EQC ( DFL1*(rho - usqr))
-#define EQN ( DFL2*(rho + uy*(4.5*uy + 3.0) - usqr))
-#define EQS ( DFL2*(rho + uy*(4.5*uy - 3.0) - usqr))
-#define EQE ( DFL2*(rho + ux*(4.5*ux + 3.0) - usqr))
-#define EQW ( DFL2*(rho + ux*(4.5*ux - 3.0) - usqr))
-#define EQT ( DFL2*(rho + uz*(4.5*uz + 3.0) - usqr))
-#define EQB ( DFL2*(rho + uz*(4.5*uz - 3.0) - usqr))
-
-#define EQNE ( DFL3*(rho + (+ux+uy)*(4.5*(+ux+uy) + 3.0) - usqr))
-#define EQNW ( DFL3*(rho + (-ux+uy)*(4.5*(-ux+uy) + 3.0) - usqr))
-#define EQSE ( DFL3*(rho + (+ux-uy)*(4.5*(+ux-uy) + 3.0) - usqr))
-#define EQSW ( DFL3*(rho + (-ux-uy)*(4.5*(-ux-uy) + 3.0) - usqr))
-#define EQNT ( DFL3*(rho + (+uy+uz)*(4.5*(+uy+uz) + 3.0) - usqr))
-#define EQNB ( DFL3*(rho + (+uy-uz)*(4.5*(+uy-uz) + 3.0) - usqr))
-#define EQST ( DFL3*(rho + (-uy+uz)*(4.5*(-uy+uz) + 3.0) - usqr))
-#define EQSB ( DFL3*(rho + (-uy-uz)*(4.5*(-uy-uz) + 3.0) - usqr))
-#define EQET ( DFL3*(rho + (+ux+uz)*(4.5*(+ux+uz) + 3.0) - usqr))
-#define EQEB ( DFL3*(rho + (+ux-uz)*(4.5*(+ux-uz) + 3.0) - usqr))
-#define EQWT ( DFL3*(rho + (-ux+uz)*(4.5*(-ux+uz) + 3.0) - usqr))
-#define EQWB ( DFL3*(rho + (-ux-uz)*(4.5*(-ux-uz) + 3.0) - usqr))
-
-
-// this is a bit ugly, but necessary for the CSRC_ access...
-#define MSRC_C m[dC ]
-#define MSRC_N m[dN ]
-#define MSRC_S m[dS ]
-#define MSRC_E m[dE ]
-#define MSRC_W m[dW ]
-#define MSRC_T m[dT ]
-#define MSRC_B m[dB ]
-#define MSRC_NE m[dNE]
-#define MSRC_NW m[dNW]
-#define MSRC_SE m[dSE]
-#define MSRC_SW m[dSW]
-#define MSRC_NT m[dNT]
-#define MSRC_NB m[dNB]
-#define MSRC_ST m[dST]
-#define MSRC_SB m[dSB]
-#define MSRC_ET m[dET]
-#define MSRC_EB m[dEB]
-#define MSRC_WT m[dWT]
-#define MSRC_WB m[dWB]
-
-// this is a bit ugly, but necessary for the ccel local access...
-#define CCEL_C RAC(ccel, dC )
-#define CCEL_N RAC(ccel, dN )
-#define CCEL_S RAC(ccel, dS )
-#define CCEL_E RAC(ccel, dE )
-#define CCEL_W RAC(ccel, dW )
-#define CCEL_T RAC(ccel, dT )
-#define CCEL_B RAC(ccel, dB )
-#define CCEL_NE RAC(ccel, dNE)
-#define CCEL_NW RAC(ccel, dNW)
-#define CCEL_SE RAC(ccel, dSE)
-#define CCEL_SW RAC(ccel, dSW)
-#define CCEL_NT RAC(ccel, dNT)
-#define CCEL_NB RAC(ccel, dNB)
-#define CCEL_ST RAC(ccel, dST)
-#define CCEL_SB RAC(ccel, dSB)
-#define CCEL_ET RAC(ccel, dET)
-#define CCEL_EB RAC(ccel, dEB)
-#define CCEL_WT RAC(ccel, dWT)
-#define CCEL_WB RAC(ccel, dWB)
-// for coarse to fine interpol access
-#define CCELG_C(f) (RAC(ccel, dC )*mGaussw[(f)])
-#define CCELG_N(f) (RAC(ccel, dN )*mGaussw[(f)])
-#define CCELG_S(f) (RAC(ccel, dS )*mGaussw[(f)])
-#define CCELG_E(f) (RAC(ccel, dE )*mGaussw[(f)])
-#define CCELG_W(f) (RAC(ccel, dW )*mGaussw[(f)])
-#define CCELG_T(f) (RAC(ccel, dT )*mGaussw[(f)])
-#define CCELG_B(f) (RAC(ccel, dB )*mGaussw[(f)])
-#define CCELG_NE(f) (RAC(ccel, dNE)*mGaussw[(f)])
-#define CCELG_NW(f) (RAC(ccel, dNW)*mGaussw[(f)])
-#define CCELG_SE(f) (RAC(ccel, dSE)*mGaussw[(f)])
-#define CCELG_SW(f) (RAC(ccel, dSW)*mGaussw[(f)])
-#define CCELG_NT(f) (RAC(ccel, dNT)*mGaussw[(f)])
-#define CCELG_NB(f) (RAC(ccel, dNB)*mGaussw[(f)])
-#define CCELG_ST(f) (RAC(ccel, dST)*mGaussw[(f)])
-#define CCELG_SB(f) (RAC(ccel, dSB)*mGaussw[(f)])
-#define CCELG_ET(f) (RAC(ccel, dET)*mGaussw[(f)])
-#define CCELG_EB(f) (RAC(ccel, dEB)*mGaussw[(f)])
-#define CCELG_WT(f) (RAC(ccel, dWT)*mGaussw[(f)])
-#define CCELG_WB(f) (RAC(ccel, dWB)*mGaussw[(f)])
-
-
-#if PARALLEL==1
-#define CSMOMEGA_STATS(dlev, domega)
-#else // PARALLEL==1
-#if FSGR_OMEGA_DEBUG==1
-#define CSMOMEGA_STATS(dlev, domega) \
- mLevel[dlev].avgOmega += domega; mLevel[dlev].avgOmegaCnt+=1.0;
-#else // FSGR_OMEGA_DEBUG==1
-#define CSMOMEGA_STATS(dlev, domega)
-#endif // FSGR_OMEGA_DEBUG==1
-#endif // PARALLEL==1
-
-
-// used for main loops and grav init
-// source set
-#define SRCS(l) mLevel[(l)].setCurr
-// target set
-#define TSET(l) mLevel[(l)].setOther
-
-// handle mov. obj
-#if FSGR_STRICT_DEBUG==1
-
-#define LBMDS_ADDMOV(linv,l) \
- \
- if((nbflag[linv]&CFBndMoving)&&(!(nbflag[l]&CFBnd))){ \
- \
- LbmFloat dte=QCELL_NBINV(lev, i, j, k, SRCS(lev), l,dFlux)-(mSimulationTime+this->mpParam->getTimestep()); \
- if( ABS(dte)< 1e-15 ) { \
- m[l]+=QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \
- } else { \
- const int sdx = i+this->dfVecX[linv], sdy = j+this->dfVecY[linv], sdz = k+this->dfVecZ[linv]; \
- \
- errMsg("INVALID_MOV_OBJ_TIME"," at "<<PRINT_IJK<<" from l"<<l<<" "<<PRINT_VEC(sdx,sdy,sdz)<<" t="<<(mSimulationTime+this->mpParam->getTimestep())<<" ct="<<QCELL_NBINV(lev, i, j, k, SRCS(lev), l,dFlux)<<" dte="<<dte); \
- debugMarkCell(lev,sdx,sdy,sdz); \
- } \
- } \
-
-
-
-#else // FSGR_STRICT_DEBUG==1
-
-#define LBMDS_ADDMOV(linv,l) \
- \
- \
- if((nbflag[linv]&CFBndMoving)&&(!(nbflag[l]&CFBnd))){ \
- \
- m[l]+=QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \
- } \
-
-
-
-#endif // !FSGR_STRICT_DEBUG==1
-
-// treatment of freeslip reflection
-// used both for OPT and nonOPT
-#define DEFAULT_STREAM_FREESLIP(l,invl,mnbf) \
- \
- int nb1 = 0, nb2 = 0; \
- LbmFloat newval = 0.0; \
- const int dx = this->dfVecX[invl], dy = this->dfVecY[invl], dz = this->dfVecZ[invl]; \
- \
- \
- \
- const LbmFloat movadd = ( \
- ((nbflag[invl]&CFBndMoving)&&(!(nbflag[l]&CFBnd))) ? \
- (QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l)) : 0.); \
- \
- if(dz==0) { \
- nb1 = !(RFLAG(lev, i, j+dy,k, SRCS(lev))&(CFFluid|CFInter)); \
- nb2 = !(RFLAG(lev, i+dx,j, k, SRCS(lev))&(CFFluid|CFInter)); \
- if((nb1)&&(!nb2)) { \
- \
- newval = QCELL(lev, i+dx,j,k,SRCS(lev), this->dfRefX[l]); \
- } else \
- if((!nb1)&&(nb2)) { \
- \
- newval = QCELL(lev, i,j+dy,k,SRCS(lev), this->dfRefY[l]); \
- } else { \
- \
- newval = RAC(ccel, this->dfInv[l] ) +movadd /* */; \
- } \
- } else \
- if(dy==0) { \
- nb1 = !(RFLAG(lev, i,j,k+dz, SRCS(lev))&(CFFluid|CFInter)); \
- nb2 = !(RFLAG(lev, i+dx,j,k, SRCS(lev))&(CFFluid|CFInter)); \
- if((nb1)&&(!nb2)) { \
- \
- newval = QCELL(lev, i+dx,j,k,SRCS(lev), this->dfRefX[l]); \
- } else \
- if((!nb1)&&(nb2)) { \
- \
- newval = QCELL(lev, i,j,k+dz,SRCS(lev), this->dfRefZ[l]); \
- } else { \
- \
- newval = RAC(ccel, this->dfInv[l] ) +movadd /* */; \
- } \
- \
- } else \
- \
- { \
- \
- nb1 = !(RFLAG(lev, i,j,k+dz, SRCS(lev))&(CFFluid|CFInter)); \
- nb2 = !(RFLAG(lev, i,j+dy,k, SRCS(lev))&(CFFluid|CFInter)); \
- if((nb1)&&(!nb2)) { \
- \
- newval = QCELL(lev, i,j+dy,k,SRCS(lev), this->dfRefY[l]); \
- } else \
- if((!nb1)&&(nb2)) { \
- \
- newval = QCELL(lev, i,j,k+dz,SRCS(lev), this->dfRefZ[l]); \
- } else { \
- \
- newval = RAC(ccel, this->dfInv[l] ) +movadd /* */; \
- } \
- } \
- \
- if(mnbf & CFBndPartslip) { \
- const LbmFloat partv = mObjectPartslips[(int)(mnbf>>24)]; \
- \
- m[l] = (RAC(ccel, this->dfInv[l] ) +movadd /* d *(1./1.) */ ) * partv + newval * (1.0-partv); \
- } else { \
- m[l] = newval; \
- } \
- \
-
-
-
-
-// complete default stream&collide, 2d/3d
-/* read distribution funtions of adjacent cells = sweep step */
-#if OPT3D==0
-
-#if FSGR_STRICT_DEBUG==1
-#define MARKCELLCHECK \
- debugMarkCell(lev,i,j,k); CAUSE_PANIC;
-#define STREAMCHECK(id,ni,nj,nk,nl) \
- if((!(m[nl] > -1.0) && (m[nl]<1.0)) ) {\
- errMsg("STREAMCHECK","ID"<<id<<" Invalid streamed DF nl"<<nl<<" value:"<<m[nl]<<" at "<<PRINT_IJK<<" from "<<PRINT_VEC(ni,nj,nk)<<" nl"<<(nl)<<\
- " nfc"<< RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr)<<" nfo"<< RFLAG(lev, ni,nj,nk, mLevel[lev].setOther) ); \
- /*FORDF0{ errMsg("STREAMCHECK"," at "<<PRINT_IJK<<" df "<<l<<"="<<m[l] ); } */ \
- MARKCELLCHECK; \
- m[nl] = dfEquil[nl]; /* REPAIR */ \
- }
-#define COLLCHECK \
- if( (rho>2.0) || (rho<-1.0) || (ABS(ux)>1.0) || (ABS(uy)>1.0) |(ABS(uz)>1.0) ) {\
- errMsg("COLLCHECK","Invalid collision values r:"<<rho<<" u:"PRINT_VEC(ux,uy,uz)<<" at? "<<PRINT_IJK ); \
- /*FORDF0{ errMsg("COLLCHECK"," at? "<<PRINT_IJK<<" df "<<l<<"="<<m[l] ); }*/ \
- rho=ux=uy=uz= 0.; /* REPAIR */ \
- MARKCELLCHECK; \
- }
-#else
-#define STREAMCHECK(id, ni,nj,nk,nl)
-#define COLLCHECK
-#endif
-
-// careful ux,uy,uz need to be inited before!
-#define DEFAULT_STREAM \
- m[dC] = RAC(ccel,dC); \
- STREAMCHECK(1, i,j,k, dC); \
- FORDF1 { \
- CellFlagType nbf = nbflag[ this->dfInv[l] ]; \
- if(nbf & CFBnd) { \
- if(nbf & CFBndNoslip) { \
- \
- m[l] = RAC(ccel, this->dfInv[l] ); \
- LBMDS_ADDMOV(this->dfInv[l],l); \
- STREAMCHECK(2, i,j,k, l); \
- } else if(nbf & (CFBndFreeslip|CFBndPartslip)) { \
- \
- if(l<=LBMDIM*2) { \
- m[l] = RAC(ccel, this->dfInv[l] ); STREAMCHECK(3, i,j,k, l); \
- LBMDS_ADDMOV(this->dfInv[l],l); \
- } else { \
- const int inv_l = this->dfInv[l]; \
- DEFAULT_STREAM_FREESLIP(l,inv_l,nbf); \
- } \
- \
- } \
- else { \
- errMsg("LbmFsgrSolver","Invalid Bnd type at "<<PRINT_IJK<<" f"<<convertCellFlagType2String(nbf)<<",nbdir"<<this->dfInv[l] ); \
- } \
- } else { \
- m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \
- if(RFLAG(lev, i,j,k, mLevel[lev].setCurr)&CFFluid) { \
- if(!(nbf&(CFFluid|CFInter)) ) { \
- int ni=i+this->dfVecX[this->dfInv[l]], nj=j+this->dfVecY[this->dfInv[l]], nk=k+this->dfVecZ[this->dfInv[l]]; \
- errMsg("STREAMCHECK"," Invalid nbflag, streamed DF l"<<l<<" value:"<<m[l]<<" at "<<PRINT_IJK<<" from "<< \
- PRINT_VEC(ni,nj,nk) <<" l"<<(l)<< \
- " nfc"<< RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr)<<" nfo"<< RFLAG(lev, ni,nj,nk, mLevel[lev].setOther) ); \
- \
- \
- } } \
- STREAMCHECK(4, i+this->dfVecX[this->dfInv[l]], j+this->dfVecY[this->dfInv[l]],k+this->dfVecZ[this->dfInv[l]], l); \
- } \
- } \
-
-
-
-
-// careful ux,uy,uz need to be inited before!
-#define DEFAULT_COLLIDEG(grav) \
- this->collideArrays(lev, i,j,k, m, rho,ux,uy,uz, OMEGA(lev), grav, mLevel[lev].lcsmago, &mDebugOmegaRet, &lcsmqo ); \
- CSMOMEGA_STATS(lev,mDebugOmegaRet); \
- FORDF0 { RAC(tcel,l) = m[l]; } \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- COLLCHECK; \
-
-
-
-#define OPTIMIZED_STREAMCOLLIDE \
- m[0] = RAC(ccel,0); \
- FORDF1 { \
- \
- if(RFLAG_NBINV(lev, i,j,k,SRCS(lev),l)&CFBnd) { errMsg("???", "bnd-err-nobndfl"); CAUSE_PANIC; \
- } else { m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l, l); } \
- STREAMCHECK(8, i+this->dfVecX[this->dfInv[l]], j+this->dfVecY[this->dfInv[l]],k+this->dfVecZ[this->dfInv[l]], l); \
- } \
- rho=m[0]; \
- DEFAULT_COLLIDEG(mLevel[lev].gravity) \
-
-
-
-#define OPTIMIZED_STREAMCOLLIDE___UNUSED \
- \
- this->collideArrays(lev, i,j,k, m, rho,ux,uy,uz, OMEGA(lev), mLevel[lev].gravity, mLevel[lev].lcsmago , &mDebugOmegaRet, &lcsmqo ); \
- CSMOMEGA_STATS(lev,mDebugOmegaRet); \
- FORDF0 { RAC(tcel,l) = m[l]; } \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- COLLCHECK; \
-
-
-
-#else // 3D, opt OPT3D==true
-
-
-// default stream opt3d add moving bc val
-#define DEFAULT_STREAM \
- m[dC] = RAC(ccel,dC); \
- \
- if(0 /* ((!nbored) & CFBnd) */) { \
- \
- m[dN ] = CSRC_N ; m[dS ] = CSRC_S ; \
- m[dE ] = CSRC_E ; m[dW ] = CSRC_W ; \
- m[dT ] = CSRC_T ; m[dB ] = CSRC_B ; \
- m[dNE] = CSRC_NE; m[dNW] = CSRC_NW; m[dSE] = CSRC_SE; m[dSW] = CSRC_SW; \
- m[dNT] = CSRC_NT; m[dNB] = CSRC_NB; m[dST] = CSRC_ST; m[dSB] = CSRC_SB; \
- m[dET] = CSRC_ET; m[dEB] = CSRC_EB; m[dWT] = CSRC_WT; m[dWB] = CSRC_WB; \
- } else { \
- \
- if(nbflag[dS ]&CFBnd) { m[dN ] = RAC(ccel,dS ); LBMDS_ADDMOV(dS ,dN ); } else { m[dN ] = CSRC_N ; } \
- if(nbflag[dN ]&CFBnd) { m[dS ] = RAC(ccel,dN ); LBMDS_ADDMOV(dN ,dS ); } else { m[dS ] = CSRC_S ; } \
- if(nbflag[dW ]&CFBnd) { m[dE ] = RAC(ccel,dW ); LBMDS_ADDMOV(dW ,dE ); } else { m[dE ] = CSRC_E ; } \
- if(nbflag[dE ]&CFBnd) { m[dW ] = RAC(ccel,dE ); LBMDS_ADDMOV(dE ,dW ); } else { m[dW ] = CSRC_W ; } \
- if(nbflag[dB ]&CFBnd) { m[dT ] = RAC(ccel,dB ); LBMDS_ADDMOV(dB ,dT ); } else { m[dT ] = CSRC_T ; } \
- if(nbflag[dT ]&CFBnd) { m[dB ] = RAC(ccel,dT ); LBMDS_ADDMOV(dT ,dB ); } else { m[dB ] = CSRC_B ; } \
- \
- \
- if(nbflag[dSW]&CFBnd) { if(nbflag[dSW]&CFBndNoslip){ m[dNE] = RAC(ccel,dSW); LBMDS_ADDMOV(dSW,dNE); }else{ DEFAULT_STREAM_FREESLIP(dNE,dSW,nbflag[dSW]);} } else { m[dNE] = CSRC_NE; } \
- if(nbflag[dSE]&CFBnd) { if(nbflag[dSE]&CFBndNoslip){ m[dNW] = RAC(ccel,dSE); LBMDS_ADDMOV(dSE,dNW); }else{ DEFAULT_STREAM_FREESLIP(dNW,dSE,nbflag[dSE]);} } else { m[dNW] = CSRC_NW; } \
- if(nbflag[dNW]&CFBnd) { if(nbflag[dNW]&CFBndNoslip){ m[dSE] = RAC(ccel,dNW); LBMDS_ADDMOV(dNW,dSE); }else{ DEFAULT_STREAM_FREESLIP(dSE,dNW,nbflag[dNW]);} } else { m[dSE] = CSRC_SE; } \
- if(nbflag[dNE]&CFBnd) { if(nbflag[dNE]&CFBndNoslip){ m[dSW] = RAC(ccel,dNE); LBMDS_ADDMOV(dNE,dSW); }else{ DEFAULT_STREAM_FREESLIP(dSW,dNE,nbflag[dNE]);} } else { m[dSW] = CSRC_SW; } \
- if(nbflag[dSB]&CFBnd) { if(nbflag[dSB]&CFBndNoslip){ m[dNT] = RAC(ccel,dSB); LBMDS_ADDMOV(dSB,dNT); }else{ DEFAULT_STREAM_FREESLIP(dNT,dSB,nbflag[dSB]);} } else { m[dNT] = CSRC_NT; } \
- if(nbflag[dST]&CFBnd) { if(nbflag[dST]&CFBndNoslip){ m[dNB] = RAC(ccel,dST); LBMDS_ADDMOV(dST,dNB); }else{ DEFAULT_STREAM_FREESLIP(dNB,dST,nbflag[dST]);} } else { m[dNB] = CSRC_NB; } \
- if(nbflag[dNB]&CFBnd) { if(nbflag[dNB]&CFBndNoslip){ m[dST] = RAC(ccel,dNB); LBMDS_ADDMOV(dNB,dST); }else{ DEFAULT_STREAM_FREESLIP(dST,dNB,nbflag[dNB]);} } else { m[dST] = CSRC_ST; } \
- if(nbflag[dNT]&CFBnd) { if(nbflag[dNT]&CFBndNoslip){ m[dSB] = RAC(ccel,dNT); LBMDS_ADDMOV(dNT,dSB); }else{ DEFAULT_STREAM_FREESLIP(dSB,dNT,nbflag[dNT]);} } else { m[dSB] = CSRC_SB; } \
- if(nbflag[dWB]&CFBnd) { if(nbflag[dWB]&CFBndNoslip){ m[dET] = RAC(ccel,dWB); LBMDS_ADDMOV(dWB,dET); }else{ DEFAULT_STREAM_FREESLIP(dET,dWB,nbflag[dWB]);} } else { m[dET] = CSRC_ET; } \
- if(nbflag[dWT]&CFBnd) { if(nbflag[dWT]&CFBndNoslip){ m[dEB] = RAC(ccel,dWT); LBMDS_ADDMOV(dWT,dEB); }else{ DEFAULT_STREAM_FREESLIP(dEB,dWT,nbflag[dWT]);} } else { m[dEB] = CSRC_EB; } \
- if(nbflag[dEB]&CFBnd) { if(nbflag[dEB]&CFBndNoslip){ m[dWT] = RAC(ccel,dEB); LBMDS_ADDMOV(dEB,dWT); }else{ DEFAULT_STREAM_FREESLIP(dWT,dEB,nbflag[dEB]);} } else { m[dWT] = CSRC_WT; } \
- if(nbflag[dET]&CFBnd) { if(nbflag[dET]&CFBndNoslip){ m[dWB] = RAC(ccel,dET); LBMDS_ADDMOV(dET,dWB); }else{ DEFAULT_STREAM_FREESLIP(dWB,dET,nbflag[dET]);} } else { m[dWB] = CSRC_WB; } \
- } \
-
-
-
-
-
-#define COLL_CALCULATE_DFEQ(dstarray) \
- dstarray[dN ] = EQN ; dstarray[dS ] = EQS ; \
- dstarray[dE ] = EQE ; dstarray[dW ] = EQW ; \
- dstarray[dT ] = EQT ; dstarray[dB ] = EQB ; \
- dstarray[dNE] = EQNE; dstarray[dNW] = EQNW; dstarray[dSE] = EQSE; dstarray[dSW] = EQSW; \
- dstarray[dNT] = EQNT; dstarray[dNB] = EQNB; dstarray[dST] = EQST; dstarray[dSB] = EQSB; \
- dstarray[dET] = EQET; dstarray[dEB] = EQEB; dstarray[dWT] = EQWT; dstarray[dWB] = EQWB; \
-
-
-
-#define COLL_CALCULATE_NONEQTENSOR(csolev, srcArray ) \
- lcsmqadd = (srcArray##NE - lcsmeq[ dNE ]); \
- lcsmqadd -= (srcArray##NW - lcsmeq[ dNW ]); \
- lcsmqadd -= (srcArray##SE - lcsmeq[ dSE ]); \
- lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \
- lcsmqo = (lcsmqadd* lcsmqadd); \
- lcsmqadd = (srcArray##ET - lcsmeq[ dET ]); \
- lcsmqadd -= (srcArray##EB - lcsmeq[ dEB ]); \
- lcsmqadd -= (srcArray##WT - lcsmeq[ dWT ]); \
- lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \
- lcsmqo += (lcsmqadd* lcsmqadd); \
- lcsmqadd = (srcArray##NT - lcsmeq[ dNT ]); \
- lcsmqadd -= (srcArray##NB - lcsmeq[ dNB ]); \
- lcsmqadd -= (srcArray##ST - lcsmeq[ dST ]); \
- lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \
- lcsmqo += (lcsmqadd* lcsmqadd); \
- lcsmqo *= 2.0; \
- lcsmqadd = (srcArray##E - lcsmeq[ dE ]); \
- lcsmqadd += (srcArray##W - lcsmeq[ dW ]); \
- lcsmqadd += (srcArray##NE - lcsmeq[ dNE ]); \
- lcsmqadd += (srcArray##NW - lcsmeq[ dNW ]); \
- lcsmqadd += (srcArray##SE - lcsmeq[ dSE ]); \
- lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \
- lcsmqadd += (srcArray##ET - lcsmeq[ dET ]); \
- lcsmqadd += (srcArray##EB - lcsmeq[ dEB ]); \
- lcsmqadd += (srcArray##WT - lcsmeq[ dWT ]); \
- lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \
- lcsmqo += (lcsmqadd* lcsmqadd); \
- lcsmqadd = (srcArray##N - lcsmeq[ dN ]); \
- lcsmqadd += (srcArray##S - lcsmeq[ dS ]); \
- lcsmqadd += (srcArray##NE - lcsmeq[ dNE ]); \
- lcsmqadd += (srcArray##NW - lcsmeq[ dNW ]); \
- lcsmqadd += (srcArray##SE - lcsmeq[ dSE ]); \
- lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \
- lcsmqadd += (srcArray##NT - lcsmeq[ dNT ]); \
- lcsmqadd += (srcArray##NB - lcsmeq[ dNB ]); \
- lcsmqadd += (srcArray##ST - lcsmeq[ dST ]); \
- lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \
- lcsmqo += (lcsmqadd* lcsmqadd); \
- lcsmqadd = (srcArray##T - lcsmeq[ dT ]); \
- lcsmqadd += (srcArray##B - lcsmeq[ dB ]); \
- lcsmqadd += (srcArray##NT - lcsmeq[ dNT ]); \
- lcsmqadd += (srcArray##NB - lcsmeq[ dNB ]); \
- lcsmqadd += (srcArray##ST - lcsmeq[ dST ]); \
- lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \
- lcsmqadd += (srcArray##ET - lcsmeq[ dET ]); \
- lcsmqadd += (srcArray##EB - lcsmeq[ dEB ]); \
- lcsmqadd += (srcArray##WT - lcsmeq[ dWT ]); \
- lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \
- lcsmqo += (lcsmqadd* lcsmqadd); \
- lcsmqo = sqrt(lcsmqo); \
-
-
-
-// COLL_CALCULATE_CSMOMEGAVAL(csolev, lcsmomega);
-
-// careful - need lcsmqo
-#define COLL_CALCULATE_CSMOMEGAVAL(csolev, dstomega ) \
- dstomega = 1.0/ \
- ( 3.0*( mLevel[(csolev)].lcnu+mLevel[(csolev)].lcsmago_sqr*( \
- -mLevel[(csolev)].lcnu + sqrt( mLevel[(csolev)].lcnu*mLevel[(csolev)].lcnu + 18.0*mLevel[(csolev)].lcsmago_sqr* lcsmqo ) \
- / (6.0*mLevel[(csolev)].lcsmago_sqr)) \
- ) +0.5 ); \
-
-
-
-#define DEFAULT_COLLIDE_LES(grav) \
- rho = + MSRC_C + MSRC_N \
- + MSRC_S + MSRC_E \
- + MSRC_W + MSRC_T \
- + MSRC_B + MSRC_NE \
- + MSRC_NW + MSRC_SE \
- + MSRC_SW + MSRC_NT \
- + MSRC_NB + MSRC_ST \
- + MSRC_SB + MSRC_ET \
- + MSRC_EB + MSRC_WT \
- + MSRC_WB; \
- \
- ux = MSRC_E - MSRC_W \
- + MSRC_NE - MSRC_NW \
- + MSRC_SE - MSRC_SW \
- + MSRC_ET + MSRC_EB \
- - MSRC_WT - MSRC_WB ; \
- \
- uy = MSRC_N - MSRC_S \
- + MSRC_NE + MSRC_NW \
- - MSRC_SE - MSRC_SW \
- + MSRC_NT + MSRC_NB \
- - MSRC_ST - MSRC_SB ; \
- \
- uz = MSRC_T - MSRC_B \
- + MSRC_NT - MSRC_NB \
- + MSRC_ST - MSRC_SB \
- + MSRC_ET - MSRC_EB \
- + MSRC_WT - MSRC_WB ; \
- PRECOLLIDE_MODS(rho,ux,uy,uz, grav); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- COLL_CALCULATE_DFEQ(lcsmeq); \
- COLL_CALCULATE_NONEQTENSOR(lev, MSRC_); \
- COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \
- CSMOMEGA_STATS(lev,lcsmomega); \
- \
- RAC(tcel,dC ) = (1.0-lcsmomega)*MSRC_C + lcsmomega*EQC ; \
- \
- RAC(tcel,dN ) = (1.0-lcsmomega)*MSRC_N + lcsmomega*lcsmeq[ dN ]; \
- RAC(tcel,dS ) = (1.0-lcsmomega)*MSRC_S + lcsmomega*lcsmeq[ dS ]; \
- RAC(tcel,dE ) = (1.0-lcsmomega)*MSRC_E + lcsmomega*lcsmeq[ dE ]; \
- RAC(tcel,dW ) = (1.0-lcsmomega)*MSRC_W + lcsmomega*lcsmeq[ dW ]; \
- RAC(tcel,dT ) = (1.0-lcsmomega)*MSRC_T + lcsmomega*lcsmeq[ dT ]; \
- RAC(tcel,dB ) = (1.0-lcsmomega)*MSRC_B + lcsmomega*lcsmeq[ dB ]; \
- \
- RAC(tcel,dNE) = (1.0-lcsmomega)*MSRC_NE + lcsmomega*lcsmeq[ dNE]; \
- RAC(tcel,dNW) = (1.0-lcsmomega)*MSRC_NW + lcsmomega*lcsmeq[ dNW]; \
- RAC(tcel,dSE) = (1.0-lcsmomega)*MSRC_SE + lcsmomega*lcsmeq[ dSE]; \
- RAC(tcel,dSW) = (1.0-lcsmomega)*MSRC_SW + lcsmomega*lcsmeq[ dSW]; \
- RAC(tcel,dNT) = (1.0-lcsmomega)*MSRC_NT + lcsmomega*lcsmeq[ dNT]; \
- RAC(tcel,dNB) = (1.0-lcsmomega)*MSRC_NB + lcsmomega*lcsmeq[ dNB]; \
- RAC(tcel,dST) = (1.0-lcsmomega)*MSRC_ST + lcsmomega*lcsmeq[ dST]; \
- RAC(tcel,dSB) = (1.0-lcsmomega)*MSRC_SB + lcsmomega*lcsmeq[ dSB]; \
- RAC(tcel,dET) = (1.0-lcsmomega)*MSRC_ET + lcsmomega*lcsmeq[ dET]; \
- RAC(tcel,dEB) = (1.0-lcsmomega)*MSRC_EB + lcsmomega*lcsmeq[ dEB]; \
- RAC(tcel,dWT) = (1.0-lcsmomega)*MSRC_WT + lcsmomega*lcsmeq[ dWT]; \
- RAC(tcel,dWB) = (1.0-lcsmomega)*MSRC_WB + lcsmomega*lcsmeq[ dWB]; \
-
-
-
-#define DEFAULT_COLLIDE_NOLES(grav) \
- rho = + MSRC_C + MSRC_N \
- + MSRC_S + MSRC_E \
- + MSRC_W + MSRC_T \
- + MSRC_B + MSRC_NE \
- + MSRC_NW + MSRC_SE \
- + MSRC_SW + MSRC_NT \
- + MSRC_NB + MSRC_ST \
- + MSRC_SB + MSRC_ET \
- + MSRC_EB + MSRC_WT \
- + MSRC_WB; \
- \
- ux = MSRC_E - MSRC_W \
- + MSRC_NE - MSRC_NW \
- + MSRC_SE - MSRC_SW \
- + MSRC_ET + MSRC_EB \
- - MSRC_WT - MSRC_WB ; \
- \
- uy = MSRC_N - MSRC_S \
- + MSRC_NE + MSRC_NW \
- - MSRC_SE - MSRC_SW \
- + MSRC_NT + MSRC_NB \
- - MSRC_ST - MSRC_SB ; \
- \
- uz = MSRC_T - MSRC_B \
- + MSRC_NT - MSRC_NB \
- + MSRC_ST - MSRC_SB \
- + MSRC_ET - MSRC_EB \
- + MSRC_WT - MSRC_WB ; \
- PRECOLLIDE_MODS(rho, ux,uy,uz, grav); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- \
- RAC(tcel,dC ) = (1.0-OMEGA(lev))*MSRC_C + OMEGA(lev)*EQC ; \
- \
- RAC(tcel,dN ) = (1.0-OMEGA(lev))*MSRC_N + OMEGA(lev)*EQN ; \
- RAC(tcel,dS ) = (1.0-OMEGA(lev))*MSRC_S + OMEGA(lev)*EQS ; \
- RAC(tcel,dE ) = (1.0-OMEGA(lev))*MSRC_E + OMEGA(lev)*EQE ; \
- RAC(tcel,dW ) = (1.0-OMEGA(lev))*MSRC_W + OMEGA(lev)*EQW ; \
- RAC(tcel,dT ) = (1.0-OMEGA(lev))*MSRC_T + OMEGA(lev)*EQT ; \
- RAC(tcel,dB ) = (1.0-OMEGA(lev))*MSRC_B + OMEGA(lev)*EQB ; \
- \
- RAC(tcel,dNE) = (1.0-OMEGA(lev))*MSRC_NE + OMEGA(lev)*EQNE; \
- RAC(tcel,dNW) = (1.0-OMEGA(lev))*MSRC_NW + OMEGA(lev)*EQNW; \
- RAC(tcel,dSE) = (1.0-OMEGA(lev))*MSRC_SE + OMEGA(lev)*EQSE; \
- RAC(tcel,dSW) = (1.0-OMEGA(lev))*MSRC_SW + OMEGA(lev)*EQSW; \
- RAC(tcel,dNT) = (1.0-OMEGA(lev))*MSRC_NT + OMEGA(lev)*EQNT; \
- RAC(tcel,dNB) = (1.0-OMEGA(lev))*MSRC_NB + OMEGA(lev)*EQNB; \
- RAC(tcel,dST) = (1.0-OMEGA(lev))*MSRC_ST + OMEGA(lev)*EQST; \
- RAC(tcel,dSB) = (1.0-OMEGA(lev))*MSRC_SB + OMEGA(lev)*EQSB; \
- RAC(tcel,dET) = (1.0-OMEGA(lev))*MSRC_ET + OMEGA(lev)*EQET; \
- RAC(tcel,dEB) = (1.0-OMEGA(lev))*MSRC_EB + OMEGA(lev)*EQEB; \
- RAC(tcel,dWT) = (1.0-OMEGA(lev))*MSRC_WT + OMEGA(lev)*EQWT; \
- RAC(tcel,dWB) = (1.0-OMEGA(lev))*MSRC_WB + OMEGA(lev)*EQWB; \
-
-
-
-
-
-#define OPTIMIZED_STREAMCOLLIDE_LES \
- \
- m[dC ] = CSRC_C ; \
- m[dN ] = CSRC_N ; m[dS ] = CSRC_S ; \
- m[dE ] = CSRC_E ; m[dW ] = CSRC_W ; \
- m[dT ] = CSRC_T ; m[dB ] = CSRC_B ; \
- m[dNE] = CSRC_NE; m[dNW] = CSRC_NW; m[dSE] = CSRC_SE; m[dSW] = CSRC_SW; \
- m[dNT] = CSRC_NT; m[dNB] = CSRC_NB; m[dST] = CSRC_ST; m[dSB] = CSRC_SB; \
- m[dET] = CSRC_ET; m[dEB] = CSRC_EB; m[dWT] = CSRC_WT; m[dWB] = CSRC_WB; \
- \
- rho = MSRC_C + MSRC_N + MSRC_S + MSRC_E + MSRC_W + MSRC_T \
- + MSRC_B + MSRC_NE + MSRC_NW + MSRC_SE + MSRC_SW + MSRC_NT \
- + MSRC_NB + MSRC_ST + MSRC_SB + MSRC_ET + MSRC_EB + MSRC_WT + MSRC_WB; \
- ux = MSRC_E - MSRC_W + MSRC_NE - MSRC_NW + MSRC_SE - MSRC_SW \
- + MSRC_ET + MSRC_EB - MSRC_WT - MSRC_WB; \
- uy = MSRC_N - MSRC_S + MSRC_NE + MSRC_NW - MSRC_SE - MSRC_SW \
- + MSRC_NT + MSRC_NB - MSRC_ST - MSRC_SB; \
- uz = MSRC_T - MSRC_B + MSRC_NT - MSRC_NB + MSRC_ST - MSRC_SB \
- + MSRC_ET - MSRC_EB + MSRC_WT - MSRC_WB; \
- PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- COLL_CALCULATE_DFEQ(lcsmeq); \
- COLL_CALCULATE_NONEQTENSOR(lev, MSRC_) \
- COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \
- CSMOMEGA_STATS(lev,lcsmomega); \
- \
- RAC(tcel,dC ) = (1.0-lcsmomega)*MSRC_C + lcsmomega*EQC ; \
- RAC(tcel,dN ) = (1.0-lcsmomega)*MSRC_N + lcsmomega*lcsmeq[ dN ]; \
- RAC(tcel,dS ) = (1.0-lcsmomega)*MSRC_S + lcsmomega*lcsmeq[ dS ]; \
- RAC(tcel,dE ) = (1.0-lcsmomega)*MSRC_E + lcsmomega*lcsmeq[ dE ]; \
- RAC(tcel,dW ) = (1.0-lcsmomega)*MSRC_W + lcsmomega*lcsmeq[ dW ]; \
- RAC(tcel,dT ) = (1.0-lcsmomega)*MSRC_T + lcsmomega*lcsmeq[ dT ]; \
- RAC(tcel,dB ) = (1.0-lcsmomega)*MSRC_B + lcsmomega*lcsmeq[ dB ]; \
- \
- RAC(tcel,dNE) = (1.0-lcsmomega)*MSRC_NE + lcsmomega*lcsmeq[ dNE]; \
- RAC(tcel,dNW) = (1.0-lcsmomega)*MSRC_NW + lcsmomega*lcsmeq[ dNW]; \
- RAC(tcel,dSE) = (1.0-lcsmomega)*MSRC_SE + lcsmomega*lcsmeq[ dSE]; \
- RAC(tcel,dSW) = (1.0-lcsmomega)*MSRC_SW + lcsmomega*lcsmeq[ dSW]; \
- \
- RAC(tcel,dNT) = (1.0-lcsmomega)*MSRC_NT + lcsmomega*lcsmeq[ dNT]; \
- RAC(tcel,dNB) = (1.0-lcsmomega)*MSRC_NB + lcsmomega*lcsmeq[ dNB]; \
- RAC(tcel,dST) = (1.0-lcsmomega)*MSRC_ST + lcsmomega*lcsmeq[ dST]; \
- RAC(tcel,dSB) = (1.0-lcsmomega)*MSRC_SB + lcsmomega*lcsmeq[ dSB]; \
- \
- RAC(tcel,dET) = (1.0-lcsmomega)*MSRC_ET + lcsmomega*lcsmeq[ dET]; \
- RAC(tcel,dEB) = (1.0-lcsmomega)*MSRC_EB + lcsmomega*lcsmeq[ dEB]; \
- RAC(tcel,dWT) = (1.0-lcsmomega)*MSRC_WT + lcsmomega*lcsmeq[ dWT]; \
- RAC(tcel,dWB) = (1.0-lcsmomega)*MSRC_WB + lcsmomega*lcsmeq[ dWB]; \
-
-
-
-#define OPTIMIZED_STREAMCOLLIDE_UNUSED \
- \
- rho = CSRC_C + CSRC_N + CSRC_S + CSRC_E + CSRC_W + CSRC_T \
- + CSRC_B + CSRC_NE + CSRC_NW + CSRC_SE + CSRC_SW + CSRC_NT \
- + CSRC_NB + CSRC_ST + CSRC_SB + CSRC_ET + CSRC_EB + CSRC_WT + CSRC_WB; \
- ux = CSRC_E - CSRC_W + CSRC_NE - CSRC_NW + CSRC_SE - CSRC_SW \
- + CSRC_ET + CSRC_EB - CSRC_WT - CSRC_WB; \
- uy = CSRC_N - CSRC_S + CSRC_NE + CSRC_NW - CSRC_SE - CSRC_SW \
- + CSRC_NT + CSRC_NB - CSRC_ST - CSRC_SB; \
- uz = CSRC_T - CSRC_B + CSRC_NT - CSRC_NB + CSRC_ST - CSRC_SB \
- + CSRC_ET - CSRC_EB + CSRC_WT - CSRC_WB; \
- PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- COLL_CALCULATE_DFEQ(lcsmeq); \
- COLL_CALCULATE_NONEQTENSOR(lev, CSRC_) \
- COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \
- \
- RAC(tcel,dC ) = (1.0-lcsmomega)*CSRC_C + lcsmomega*EQC ; \
- RAC(tcel,dN ) = (1.0-lcsmomega)*CSRC_N + lcsmomega*lcsmeq[ dN ]; \
- RAC(tcel,dS ) = (1.0-lcsmomega)*CSRC_S + lcsmomega*lcsmeq[ dS ]; \
- RAC(tcel,dE ) = (1.0-lcsmomega)*CSRC_E + lcsmomega*lcsmeq[ dE ]; \
- RAC(tcel,dW ) = (1.0-lcsmomega)*CSRC_W + lcsmomega*lcsmeq[ dW ]; \
- RAC(tcel,dT ) = (1.0-lcsmomega)*CSRC_T + lcsmomega*lcsmeq[ dT ]; \
- RAC(tcel,dB ) = (1.0-lcsmomega)*CSRC_B + lcsmomega*lcsmeq[ dB ]; \
- \
- RAC(tcel,dNE) = (1.0-lcsmomega)*CSRC_NE + lcsmomega*lcsmeq[ dNE]; \
- RAC(tcel,dNW) = (1.0-lcsmomega)*CSRC_NW + lcsmomega*lcsmeq[ dNW]; \
- RAC(tcel,dSE) = (1.0-lcsmomega)*CSRC_SE + lcsmomega*lcsmeq[ dSE]; \
- RAC(tcel,dSW) = (1.0-lcsmomega)*CSRC_SW + lcsmomega*lcsmeq[ dSW]; \
- \
- RAC(tcel,dNT) = (1.0-lcsmomega)*CSRC_NT + lcsmomega*lcsmeq[ dNT]; \
- RAC(tcel,dNB) = (1.0-lcsmomega)*CSRC_NB + lcsmomega*lcsmeq[ dNB]; \
- RAC(tcel,dST) = (1.0-lcsmomega)*CSRC_ST + lcsmomega*lcsmeq[ dST]; \
- RAC(tcel,dSB) = (1.0-lcsmomega)*CSRC_SB + lcsmomega*lcsmeq[ dSB]; \
- \
- RAC(tcel,dET) = (1.0-lcsmomega)*CSRC_ET + lcsmomega*lcsmeq[ dET]; \
- RAC(tcel,dEB) = (1.0-lcsmomega)*CSRC_EB + lcsmomega*lcsmeq[ dEB]; \
- RAC(tcel,dWT) = (1.0-lcsmomega)*CSRC_WT + lcsmomega*lcsmeq[ dWT]; \
- RAC(tcel,dWB) = (1.0-lcsmomega)*CSRC_WB + lcsmomega*lcsmeq[ dWB]; \
-
-
-
-#define OPTIMIZED_STREAMCOLLIDE_NOLES \
- \
- rho = CSRC_C + CSRC_N + CSRC_S + CSRC_E + CSRC_W + CSRC_T \
- + CSRC_B + CSRC_NE + CSRC_NW + CSRC_SE + CSRC_SW + CSRC_NT \
- + CSRC_NB + CSRC_ST + CSRC_SB + CSRC_ET + CSRC_EB + CSRC_WT + CSRC_WB; \
- ux = CSRC_E - CSRC_W + CSRC_NE - CSRC_NW + CSRC_SE - CSRC_SW \
- + CSRC_ET + CSRC_EB - CSRC_WT - CSRC_WB; \
- uy = CSRC_N - CSRC_S + CSRC_NE + CSRC_NW - CSRC_SE - CSRC_SW \
- + CSRC_NT + CSRC_NB - CSRC_ST - CSRC_SB; \
- uz = CSRC_T - CSRC_B + CSRC_NT - CSRC_NB + CSRC_ST - CSRC_SB \
- + CSRC_ET - CSRC_EB + CSRC_WT - CSRC_WB; \
- PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- RAC(tcel,dC ) = (1.0-OMEGA(lev))*CSRC_C + OMEGA(lev)*EQC ; \
- RAC(tcel,dN ) = (1.0-OMEGA(lev))*CSRC_N + OMEGA(lev)*EQN ; \
- RAC(tcel,dS ) = (1.0-OMEGA(lev))*CSRC_S + OMEGA(lev)*EQS ; \
- RAC(tcel,dE ) = (1.0-OMEGA(lev))*CSRC_E + OMEGA(lev)*EQE ; \
- RAC(tcel,dW ) = (1.0-OMEGA(lev))*CSRC_W + OMEGA(lev)*EQW ; \
- RAC(tcel,dT ) = (1.0-OMEGA(lev))*CSRC_T + OMEGA(lev)*EQT ; \
- RAC(tcel,dB ) = (1.0-OMEGA(lev))*CSRC_B + OMEGA(lev)*EQB ; \
- \
- RAC(tcel,dNE) = (1.0-OMEGA(lev))*CSRC_NE + OMEGA(lev)*EQNE; \
- RAC(tcel,dNW) = (1.0-OMEGA(lev))*CSRC_NW + OMEGA(lev)*EQNW; \
- RAC(tcel,dSE) = (1.0-OMEGA(lev))*CSRC_SE + OMEGA(lev)*EQSE; \
- RAC(tcel,dSW) = (1.0-OMEGA(lev))*CSRC_SW + OMEGA(lev)*EQSW; \
- \
- RAC(tcel,dNT) = (1.0-OMEGA(lev))*CSRC_NT + OMEGA(lev)*EQNT; \
- RAC(tcel,dNB) = (1.0-OMEGA(lev))*CSRC_NB + OMEGA(lev)*EQNB; \
- RAC(tcel,dST) = (1.0-OMEGA(lev))*CSRC_ST + OMEGA(lev)*EQST; \
- RAC(tcel,dSB) = (1.0-OMEGA(lev))*CSRC_SB + OMEGA(lev)*EQSB; \
- \
- RAC(tcel,dET) = (1.0-OMEGA(lev))*CSRC_ET + OMEGA(lev)*EQET; \
- RAC(tcel,dEB) = (1.0-OMEGA(lev))*CSRC_EB + OMEGA(lev)*EQEB; \
- RAC(tcel,dWT) = (1.0-OMEGA(lev))*CSRC_WT + OMEGA(lev)*EQWT; \
- RAC(tcel,dWB) = (1.0-OMEGA(lev))*CSRC_WB + OMEGA(lev)*EQWB; \
-
-
-
-
-
-// LES switching for OPT3D
-#if USE_LES==1
-#define DEFAULT_COLLIDEG(grav) DEFAULT_COLLIDE_LES(grav)
-#define OPTIMIZED_STREAMCOLLIDE OPTIMIZED_STREAMCOLLIDE_LES
-#else
-#define DEFAULT_COLLIDEG(grav) DEFAULT_COLLIDE_NOLES(grav)
-#define OPTIMIZED_STREAMCOLLIDE OPTIMIZED_STREAMCOLLIDE_NOLES
-#endif
-
-#endif // 3D, opt OPT3D==true
-
-#define USQRMAXCHECK(Cusqr,Cux,Cuy,Cuz, CmMaxVlen,CmMxvx,CmMxvy,CmMxvz) \
- if(Cusqr>CmMaxVlen) { \
- CmMxvx = Cux; CmMxvy = Cuy; CmMxvz = Cuz; CmMaxVlen = Cusqr; \
- } /* stats */
-
-
-
-/******************************************************************************
- * interpolateCellFromCoarse macros
- *****************************************************************************/
-
-
-// WOXDY_N = Weight Order X Dimension Y _ number N
-#define WO1D1 ( 1.0/ 2.0)
-#define WO1D2 ( 1.0/ 4.0)
-#define WO1D3 ( 1.0/ 8.0)
-
-#define WO2D1_1 (-1.0/16.0)
-#define WO2D1_9 ( 9.0/16.0)
-
-#define WO2D2_11 (WO2D1_1 * WO2D1_1)
-#define WO2D2_19 (WO2D1_9 * WO2D1_1)
-#define WO2D2_91 (WO2D1_9 * WO2D1_1)
-#define WO2D2_99 (WO2D1_9 * WO2D1_9)
-
-#define WO2D3_111 (WO2D1_1 * WO2D1_1 * WO2D1_1)
-#define WO2D3_191 (WO2D1_9 * WO2D1_1 * WO2D1_1)
-#define WO2D3_911 (WO2D1_9 * WO2D1_1 * WO2D1_1)
-#define WO2D3_991 (WO2D1_9 * WO2D1_9 * WO2D1_1)
-#define WO2D3_119 (WO2D1_1 * WO2D1_1 * WO2D1_9)
-#define WO2D3_199 (WO2D1_9 * WO2D1_1 * WO2D1_9)
-#define WO2D3_919 (WO2D1_9 * WO2D1_1 * WO2D1_9)
-#define WO2D3_999 (WO2D1_9 * WO2D1_9 * WO2D1_9)
-
-#if FSGR_STRICT_DEBUG==1
-#define ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l) \
- if( (((1.0-(at))>0.0) && (!(QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr , l) > -1.0 ))) || \
- ((( (at))>0.0) && (!(QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setOther, l) > -1.0 ))) ){ \
- errMsg("INVDFSCHECK", " l"<<(alev)<<" "<<PRINT_VEC((ai),(aj),(ak))<<" fc:"<<RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr )<<" fo:"<<RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther )<<" dfl"<<l ); \
- debugMarkCell((alev), (ai),(aj),(ak));\
- CAUSE_PANIC; \
- }
- // end ADD_INT_DFSCHECK
-#define ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac) \
- if( (((1.0-(at))>0.0) && (!(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr )&(CFInter|CFFluid|CFGrCoarseInited) ))) || \
- ((( (at))>0.0) && (!(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther)&(CFInter|CFFluid|CFGrCoarseInited) ))) ){ \
- errMsg("INVFLAGCINTCHECK", " l"<<(alev)<<" at:"<<(at)<<" "<<PRINT_VEC((ai),(aj),(ak))<<\
- " fc:"<< convertCellFlagType2String(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr )) <<\
- " fold:"<< convertCellFlagType2String(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther )) ); \
- debugMarkCell((alev), (ai),(aj),(ak));\
- CAUSE_PANIC; \
- }
- // end ADD_INT_DFSCHECK
-
-#define INTUNUTCHECK(ix,iy,iz) \
- if( (RFLAG(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr) != (CFFluid|CFGrFromCoarse)) ){\
- errMsg("INTFLAGUNU_CHECK", PRINT_VEC(i,j,k)<<" child not unused at l"<<(lev+1)<<" "<<PRINT_VEC((ix),(iy),(iz))<<" flag: "<< RFLAG(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr) ); \
- debugMarkCell((lev+1), (ix),(iy),(iz));\
- CAUSE_PANIC; \
- }\
- RFLAG(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr) |= CFGrCoarseInited; \
- // INTUNUTCHECK
-#define INTSTRICTCHECK(ix,iy,iz,caseId) \
- if( QCELL(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr, l) <= 0.0 ){\
- errMsg("INVDFCCELLCHECK", "caseId:"<<caseId<<" "<<PRINT_VEC(i,j,k)<<" child inter at "<<PRINT_VEC((ix),(iy),(iz))<<" invalid df "<<l<<" = "<< QCELL(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr, l) ); \
- debugMarkCell((lev+1), (ix),(iy),(iz));\
- CAUSE_PANIC; \
- }\
- // INTSTRICTCHECK
-
-#else// FSGR_STRICT_DEBUG==1
-#define ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac)
-#define ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l)
-#define INTSTRICTCHECK(x,y,z,caseId)
-#define INTUNUTCHECK(ix,iy,iz)
-#endif// FSGR_STRICT_DEBUG==1
-
-
-#if FSGR_STRICT_DEBUG==1
-#define INTDEBOUT \
- { /*LbmFloat rho,ux,uy,uz;*/ \
- rho = ux=uy=uz=0.0; \
- FORDF0{ LbmFloat m = QCELL(lev,i,j,k, dstSet, l); \
- rho += m; ux += (this->dfDvecX[l]*m); uy += (this->dfDvecY[l]*m); uz += (this->dfDvecZ[l]*m); \
- if(ABS(m)>1.0) { errMsg("interpolateCellFromCoarse", "ICFC_DFCHECK cell "<<PRINT_IJK<<" m"<<l<<":"<< m );CAUSE_PANIC;}\
- /*errMsg("interpolateCellFromCoarse", " cell "<<PRINT_IJK<<" df"<<l<<":"<<m );*/ \
- } \
- /*if(this->mPanic) { errMsg("interpolateCellFromCoarse", "ICFC_DFOUT cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" b"<<PRINT_VEC(betx,bety,betz) ); }*/ \
- if(markNbs) errMsg("interpolateCellFromCoarse", " cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" b"<<PRINT_VEC(betx,bety,betz) ); \
- /*errMsg("interpolateCellFromCoarse", "ICFC_DFDEBUG cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" b"<<PRINT_VEC(betx,bety,betz) ); */\
- } \
- /* both cases are ok to interpolate */ \
- if( (!(RFLAG(lev,i,j,k, dstSet) & CFGrFromCoarse)) && \
- (!(RFLAG(lev,i,j,k, dstSet) & CFUnused)) ) { \
- /* might also have CFGrCoarseInited (shouldnt be a problem here)*/ \
- errMsg("interpolateCellFromCoarse", "CHECK cell not CFGrFromCoarse? "<<PRINT_IJK<<" flag:"<< RFLAG(lev,i,j,k, dstSet)<<" fstr:"<<convertCellFlagType2String( RFLAG(lev,i,j,k, dstSet) )); \
- /* FIXME check this warning...? return; this can happen !? */ \
- /*CAUSE_PANIC;*/ \
- } \
- // end INTDEBOUT
-#else // FSGR_STRICT_DEBUG==1
-#define INTDEBOUT
-#endif // FSGR_STRICT_DEBUG==1
-
-
-// t=0.0 -> only current
-// t=0.5 -> mix
-// t=1.0 -> only other
-#if OPT3D==0
-#define ADD_INT_DFS(alev, ai,aj,ak, at, afac) \
- ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac); \
- FORDF0{ \
- LbmFloat df = ( \
- QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr , l)*(1.0-(at)) + \
- QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setOther, l)*( (at)) \
- ) ; \
- ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l); \
- df *= (afac); \
- rho += df; \
- ux += (this->dfDvecX[l]*df); \
- uy += (this->dfDvecY[l]*df); \
- uz += (this->dfDvecZ[l]*df); \
- intDf[l] += df; \
- }
-// write interpolated dfs back to cell (correct non-eq. parts)
-#define IDF_WRITEBACK_ \
- FORDF0{ \
- LbmFloat eq = getCollideEq(l, rho,ux,uy,uz);\
- QCELL(lev,i,j,k, dstSet, l) = (eq+ (intDf[l]-eq)*mDfScaleDown);\
- } \
- /* check that all values are ok */ \
- INTDEBOUT
-#define IDF_WRITEBACK \
- LbmFloat omegaDst, omegaSrc;\
- /* smago new */ \
- LbmFloat feq[LBM_DFNUM]; \
- LbmFloat dfScale = mDfScaleDown; \
- FORDF0{ \
- feq[l] = getCollideEq(l, rho,ux,uy,uz); \
- } \
- if(mLevel[lev ].lcsmago>0.0) {\
- LbmFloat Qo = this->getLesNoneqTensorCoeff(intDf,feq); \
- omegaDst = this->getLesOmega(mLevel[lev+0].omega,mLevel[lev+0].lcsmago,Qo); \
- omegaSrc = this->getLesOmega(mLevel[lev-1].omega,mLevel[lev-1].lcsmago,Qo); \
- } else {\
- omegaDst = mLevel[lev+0].omega; \
- omegaSrc = mLevel[lev-1].omega;\
- } \
- \
- dfScale = (mLevel[lev+0].timestep/mLevel[lev-1].timestep)* (1.0/omegaDst-1.0)/ (1.0/omegaSrc-1.0); \
- FORDF0{ \
- /*errMsg("SMAGO"," org"<<mDfScaleDown<<" n"<<dfScale<<" qc"<< QCELL(lev,i,j,k, dstSet, l)<<" idf"<<intDf[l]<<" eq"<<feq[l] ); */ \
- QCELL(lev,i,j,k, dstSet, l) = (feq[l]+ (intDf[l]-feq[l])*dfScale);\
- } \
- /* check that all values are ok */ \
- INTDEBOUT
-
-#else //OPT3D==0
-
-#define ADDALLVALS \
- addVal = addDfFacT * RAC(addfcel , dC ); \
- intDf[dC ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dN ); \
- uy+=addVal; intDf[dN ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dS ); \
- uy-=addVal; intDf[dS ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dE ); \
- ux+=addVal; intDf[dE ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dW ); \
- ux-=addVal; intDf[dW ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dT ); \
- uz+=addVal; intDf[dT ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dB ); \
- uz-=addVal; intDf[dB ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dNE); \
- ux+=addVal; uy+=addVal; intDf[dNE] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dNW); \
- ux-=addVal; uy+=addVal; intDf[dNW] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dSE); \
- ux+=addVal; uy-=addVal; intDf[dSE] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dSW); \
- ux-=addVal; uy-=addVal; intDf[dSW] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dNT); \
- uy+=addVal; uz+=addVal; intDf[dNT] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dNB); \
- uy+=addVal; uz-=addVal; intDf[dNB] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dST); \
- uy-=addVal; uz+=addVal; intDf[dST] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dSB); \
- uy-=addVal; uz-=addVal; intDf[dSB] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dET); \
- ux+=addVal; uz+=addVal; intDf[dET] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dEB); \
- ux+=addVal; uz-=addVal; intDf[dEB] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dWT); \
- ux-=addVal; uz+=addVal; intDf[dWT] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dWB); \
- ux-=addVal; uz-=addVal; intDf[dWB] += addVal; rho += addVal;
-
-#define ADD_INT_DFS(alev, ai,aj,ak, at, afac) \
- addDfFacT = at*afac; \
- addfcel = RACPNT((alev), (ai),(aj),(ak),mLevel[(alev)].setOther); \
- ADDALLVALS\
- addDfFacT = (1.0-at)*afac; \
- addfcel = RACPNT((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr); \
- ADDALLVALS
-
-// also ugly...
-#define INTDF_C intDf[dC ]
-#define INTDF_N intDf[dN ]
-#define INTDF_S intDf[dS ]
-#define INTDF_E intDf[dE ]
-#define INTDF_W intDf[dW ]
-#define INTDF_T intDf[dT ]
-#define INTDF_B intDf[dB ]
-#define INTDF_NE intDf[dNE]
-#define INTDF_NW intDf[dNW]
-#define INTDF_SE intDf[dSE]
-#define INTDF_SW intDf[dSW]
-#define INTDF_NT intDf[dNT]
-#define INTDF_NB intDf[dNB]
-#define INTDF_ST intDf[dST]
-#define INTDF_SB intDf[dSB]
-#define INTDF_ET intDf[dET]
-#define INTDF_EB intDf[dEB]
-#define INTDF_WT intDf[dWT]
-#define INTDF_WB intDf[dWB]
-
-
-// write interpolated dfs back to cell (correct non-eq. parts)
-#define IDF_WRITEBACK_LES \
- dstcell = RACPNT(lev, i,j,k,dstSet); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- \
- lcsmeq[dC] = EQC ; \
- COLL_CALCULATE_DFEQ(lcsmeq); \
- COLL_CALCULATE_NONEQTENSOR(lev, INTDF_ )\
- COLL_CALCULATE_CSMOMEGAVAL(lev+0, lcsmDstOmega); \
- COLL_CALCULATE_CSMOMEGAVAL(lev-1, lcsmSrcOmega); \
- \
- lcsmdfscale = (mLevel[lev+0].timestep/mLevel[lev-1].timestep)* (1.0/lcsmDstOmega-1.0)/ (1.0/lcsmSrcOmega-1.0); \
- RAC(dstcell, dC ) = (lcsmeq[dC ] + (intDf[dC ]-lcsmeq[dC ] )*lcsmdfscale);\
- RAC(dstcell, dN ) = (lcsmeq[dN ] + (intDf[dN ]-lcsmeq[dN ] )*lcsmdfscale);\
- RAC(dstcell, dS ) = (lcsmeq[dS ] + (intDf[dS ]-lcsmeq[dS ] )*lcsmdfscale);\
- RAC(dstcell, dE ) = (lcsmeq[dE ] + (intDf[dE ]-lcsmeq[dE ] )*lcsmdfscale);\
- RAC(dstcell, dW ) = (lcsmeq[dW ] + (intDf[dW ]-lcsmeq[dW ] )*lcsmdfscale);\
- RAC(dstcell, dT ) = (lcsmeq[dT ] + (intDf[dT ]-lcsmeq[dT ] )*lcsmdfscale);\
- RAC(dstcell, dB ) = (lcsmeq[dB ] + (intDf[dB ]-lcsmeq[dB ] )*lcsmdfscale);\
- RAC(dstcell, dNE) = (lcsmeq[dNE] + (intDf[dNE]-lcsmeq[dNE] )*lcsmdfscale);\
- RAC(dstcell, dNW) = (lcsmeq[dNW] + (intDf[dNW]-lcsmeq[dNW] )*lcsmdfscale);\
- RAC(dstcell, dSE) = (lcsmeq[dSE] + (intDf[dSE]-lcsmeq[dSE] )*lcsmdfscale);\
- RAC(dstcell, dSW) = (lcsmeq[dSW] + (intDf[dSW]-lcsmeq[dSW] )*lcsmdfscale);\
- RAC(dstcell, dNT) = (lcsmeq[dNT] + (intDf[dNT]-lcsmeq[dNT] )*lcsmdfscale);\
- RAC(dstcell, dNB) = (lcsmeq[dNB] + (intDf[dNB]-lcsmeq[dNB] )*lcsmdfscale);\
- RAC(dstcell, dST) = (lcsmeq[dST] + (intDf[dST]-lcsmeq[dST] )*lcsmdfscale);\
- RAC(dstcell, dSB) = (lcsmeq[dSB] + (intDf[dSB]-lcsmeq[dSB] )*lcsmdfscale);\
- RAC(dstcell, dET) = (lcsmeq[dET] + (intDf[dET]-lcsmeq[dET] )*lcsmdfscale);\
- RAC(dstcell, dEB) = (lcsmeq[dEB] + (intDf[dEB]-lcsmeq[dEB] )*lcsmdfscale);\
- RAC(dstcell, dWT) = (lcsmeq[dWT] + (intDf[dWT]-lcsmeq[dWT] )*lcsmdfscale);\
- RAC(dstcell, dWB) = (lcsmeq[dWB] + (intDf[dWB]-lcsmeq[dWB] )*lcsmdfscale);\
- /* IDF_WRITEBACK optimized */
-
-#define IDF_WRITEBACK_NOLES \
- dstcell = RACPNT(lev, i,j,k,dstSet); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- \
- RAC(dstcell, dC ) = (EQC + (intDf[dC ]-EQC )*mDfScaleDown);\
- RAC(dstcell, dN ) = (EQN + (intDf[dN ]-EQN )*mDfScaleDown);\
- RAC(dstcell, dS ) = (EQS + (intDf[dS ]-EQS )*mDfScaleDown);\
- /*old*/ RAC(dstcell, dE ) = (EQE + (intDf[dE ]-EQE )*mDfScaleDown);\
- RAC(dstcell, dW ) = (EQW + (intDf[dW ]-EQW )*mDfScaleDown);\
- RAC(dstcell, dT ) = (EQT + (intDf[dT ]-EQT )*mDfScaleDown);\
- RAC(dstcell, dB ) = (EQB + (intDf[dB ]-EQB )*mDfScaleDown);\
- /*old*/ RAC(dstcell, dNE) = (EQNE + (intDf[dNE]-EQNE )*mDfScaleDown);\
- RAC(dstcell, dNW) = (EQNW + (intDf[dNW]-EQNW )*mDfScaleDown);\
- RAC(dstcell, dSE) = (EQSE + (intDf[dSE]-EQSE )*mDfScaleDown);\
- RAC(dstcell, dSW) = (EQSW + (intDf[dSW]-EQSW )*mDfScaleDown);\
- RAC(dstcell, dNT) = (EQNT + (intDf[dNT]-EQNT )*mDfScaleDown);\
- RAC(dstcell, dNB) = (EQNB + (intDf[dNB]-EQNB )*mDfScaleDown);\
- RAC(dstcell, dST) = (EQST + (intDf[dST]-EQST )*mDfScaleDown);\
- RAC(dstcell, dSB) = (EQSB + (intDf[dSB]-EQSB )*mDfScaleDown);\
- RAC(dstcell, dET) = (EQET + (intDf[dET]-EQET )*mDfScaleDown);\
- /*old*/ RAC(dstcell, dEB) = (EQEB + (intDf[dEB]-EQEB )*mDfScaleDown);\
- RAC(dstcell, dWT) = (EQWT + (intDf[dWT]-EQWT )*mDfScaleDown);\
- RAC(dstcell, dWB) = (EQWB + (intDf[dWB]-EQWB )*mDfScaleDown);\
- /* IDF_WRITEBACK optimized */
-
-#if USE_LES==1
-#define IDF_WRITEBACK IDF_WRITEBACK_LES
-#else
-#define IDF_WRITEBACK IDF_WRITEBACK_NOLES
-#endif
-
-#endif// OPT3D==0
-
-
-
-/******************************************************************************/
-/*! relaxation LES functions */
-/******************************************************************************/
-
-
-inline LbmFloat LbmFsgrSolver::getLesNoneqTensorCoeff(
- LbmFloat df[],
- LbmFloat feq[] ) {
- LbmFloat Qo = 0.0;
- for(int m=0; m< ((LBMDIM*LBMDIM)-LBMDIM)/2 ; m++) {
- LbmFloat qadd = 0.0;
- for(int l=1; l<this->cDfNum; l++) {
- if(this->lesCoeffOffdiag[m][l]==0.0) continue;
- qadd += this->lesCoeffOffdiag[m][l]*(df[l]-feq[l]);
- }
- Qo += (qadd*qadd);
- }
- Qo *= 2.0; // off diag twice
- for(int m=0; m<LBMDIM; m++) {
- LbmFloat qadd = 0.0;
- for(int l=1; l<this->cDfNum; l++) {
- if(this->lesCoeffDiag[m][l]==0.0) continue;
- qadd += this->lesCoeffDiag[m][l]*(df[l]-feq[l]);
- }
- Qo += (qadd*qadd);
- }
- Qo = sqrt(Qo);
- return Qo;
-};
-
-inline LbmFloat LbmFsgrSolver::getLesOmega(LbmFloat omega, LbmFloat csmago, LbmFloat Qo) {
- const LbmFloat tau = 1.0/omega;
- const LbmFloat nu = (2.0*tau-1.0) * (1.0/6.0);
- const LbmFloat C = csmago;
- const LbmFloat Csqr = C*C;
- LbmFloat S = -nu + sqrt( nu*nu + 18.0*Csqr*Qo ) / (6.0*Csqr);
- return( 1.0/( 3.0*( nu+Csqr*S ) +0.5 ) );
-}
-
-#define DEBUG_CALCPRINTCELL(str,df) {\
- LbmFloat prho=df[0], pux=0., puy=0., puz=0.; \
- for(int dfl=1; dfl<this->cDfNum; dfl++) { \
- prho += df[dfl]; \
- pux += (this->dfDvecX[dfl]*df[dfl]); \
- puy += (this->dfDvecY[dfl]*df[dfl]); \
- puz += (this->dfDvecZ[dfl]*df[dfl]); \
- } \
- errMsg("DEBUG_CALCPRINTCELL",">"<<str<<" rho="<<prho<<" vel="<<ntlVec3Gfx(pux,puy,puz) ); \
- } /* END DEBUG_CALCPRINTCELL */
-
-// "normal" collision
-inline void LbmFsgrSolver::collideArrays(
- int lev, int i, int j, int k, // position - more for debugging
- LbmFloat df[],
- LbmFloat &outrho, // out only!
- // velocity modifiers (returns actual velocity!)
- LbmFloat &mux, LbmFloat &muy, LbmFloat &muz,
- LbmFloat omega,
- LbmVec gravity,
- LbmFloat csmago,
- LbmFloat *newOmegaRet, LbmFloat *newQoRet
- ) {
- int l;
- LbmFloat rho=df[0];
- LbmFloat ux = 0; //mux;
- LbmFloat uy = 0; //muy;
- LbmFloat uz = 0; //muz;
- LbmFloat feq[19];
- LbmFloat omegaNew;
- LbmFloat Qo = 0.0;
-
- for(l=1; l<this->cDfNum; l++) {
- rho += df[l];
- ux += (this->dfDvecX[l]*df[l]);
- uy += (this->dfDvecY[l]*df[l]);
- uz += (this->dfDvecZ[l]*df[l]);
- }
-
-
- PRECOLLIDE_MODS(rho,ux,uy,uz, gravity);
- for(l=0; l<this->cDfNum; l++) {
- feq[l] = getCollideEq(l,rho,ux,uy,uz);
- }
-
- if(csmago>0.0) {
- Qo = getLesNoneqTensorCoeff(df,feq);
- omegaNew = getLesOmega(omega,csmago,Qo);
- } else {
- omegaNew = omega; // smago off...
- }
- if(newOmegaRet) *newOmegaRet = omegaNew; // return value for stats
- if(newQoRet) *newQoRet = Qo; // return value of non-eq. stress tensor
-
- for(l=0; l<this->cDfNum; l++) {
- df[l] = (1.0-omegaNew ) * df[l] + omegaNew * feq[l];
- }
- //if((i==16)&&(j==10)) DEBUG_CALCPRINTCELL( "2dcoll "<<PRINT_IJK, df);
-
- mux = ux;
- muy = uy;
- muz = uz;
- outrho = rho;
-
- lev=i=j=k; // debug, remove warnings
-};
-
diff --git a/intern/elbeem/intern/solver_util.cpp b/intern/elbeem/intern/solver_util.cpp
deleted file mode 100644
index ca98e26e875..00000000000
--- a/intern/elbeem/intern/solver_util.cpp
+++ /dev/null
@@ -1,1753 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Standard LBM Factory implementation
- *
- *****************************************************************************/
-
-#include "solver_class.h"
-#include "solver_relax.h"
-#include "particletracer.h"
-
-// MPT
-#include "ntl_world.h"
-#include "simulation_object.h"
-
-#include "globals.h"
-
-#include <stdlib.h>
-#include <zlib.h>
-#ifndef sqrtf
-#define sqrtf sqrt
-#endif
-
-/******************************************************************************
- * helper functions
- *****************************************************************************/
-
-// try to enhance surface?
-#define SURFACE_ENH 2
-
-//! for raytracing
-void LbmFsgrSolver::prepareVisualization( void ) {
- int lev = mMaxRefine;
- int workSet = mLevel[lev].setCurr;
-
- int mainGravDir=6; // if normalizing fails, we asume z-direction gravity
- LbmFloat mainGravLen = 0.;
- FORDF1{
- LbmFloat thisGravLen = dot(LbmVec(dfVecX[l],dfVecY[l],dfVecZ[l]), mLevel[mMaxRefine].gravity );
- if(thisGravLen>mainGravLen) {
- mainGravLen = thisGravLen;
- mainGravDir = l;
- }
- }
-
-#if LBMDIM==2
- // 2d, place in the middle of isofield slice (k=2)
-# define ZKD1 0
- // 2d z offset = 2, lbmGetData adds 1, so use one here
-# define ZKOFF 1
- // reset all values...
- for(int k= 0; k< 5; ++k)
- for(int j=0;j<mLevel[lev].lSizey-0;j++)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,j,ZKOFF)=0.0;
- }
-#else // LBMDIM==2
- // 3d, use normal bounds
-# define ZKD1 1
-# define ZKOFF k
- // reset all values...
- for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k)
- for(int j=0;j<mLevel[lev].lSizey-0;j++)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,j,ZKOFF)=0.0;
- }
-#endif // LBMDIM==2
-
- // MPT, ignore
- if((glob_mpactive) && (glob_mpnum>1) && (glob_mpindex==0)) {
- mpIso->resetAll(0.);
- }
-
-
- LbmFloat minval = mIsoValue*1.05; // / mIsoWeight[13];
- // add up...
- float val = 0.0;
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k)
- for(int j=1;j<mLevel[lev].lSizey-1;j++)
- for(int i=1;i<mLevel[lev].lSizex-1;i++) {
- const CellFlagType cflag = RFLAG(lev, i,j,k,workSet);
- //if(cflag&(CFBnd|CFEmpty)) {
-
-#if SURFACE_ENH==0
-
- // no enhancements...
- if( (cflag&(CFFluid|CFUnused)) ) {
- val = 1.;
- } else if( (cflag&CFInter) ) {
- val = (QCELL(lev, i,j,k,workSet, dFfrac));
- } else {
- continue;
- }
-
-#else // SURFACE_ENH!=1
- if(cflag&CFBnd) {
- // treated in second loop
- continue;
- } else if(cflag&CFUnused) {
- val = 1.;
- } else if( (cflag&CFFluid) && (cflag&CFNoBndFluid)) {
- // optimized fluid
- val = 1.;
- } else if( (cflag&(CFEmpty|CFInter|CFFluid)) ) {
- int noslipbnd = 0;
- int intercnt = 0;
- FORDF1 {
- const CellFlagType nbflag = RFLAG_NB(lev, i,j,k, workSet,l);
- if(nbflag&CFInter){ intercnt++; }
-
- // check all directions otherwise we get bugs with splashes on obstacles
- if(l!=mainGravDir) continue; // only check bnd along main grav. dir
- //if((nbflag&CFBnd)&&(nbflag&CFBndNoslip)){ noslipbnd=1; }
- if((nbflag&CFBnd)){ noslipbnd=1; }
- }
-
- if(cflag&CFEmpty) {
- // special empty treatment
- if((noslipbnd)&&(intercnt>6)) {
- *mpIso->lbmGetData(i,j,ZKOFF) += minval;
- } else if((noslipbnd)&&(intercnt>0)) {
- // necessary?
- *mpIso->lbmGetData(i,j,ZKOFF) += mIsoValue*0.9;
- } else {
- // nothing to do...
- }
-
- continue;
- } else if(cflag&(CFNoNbEmpty|CFFluid)) {
- // no empty nb interface cells are treated as full
- val=1.0;
- } else {
- val = (QCELL(lev, i,j,k,workSet, dFfrac));
- }
-
- if(noslipbnd) {
- if(val<minval) val = minval;
- *mpIso->lbmGetData(i,j,ZKOFF) += minval-( val * mIsoWeight[13] );
- }
- } else { // all others, unused?
- continue;
- }
-#endif // SURFACE_ENH>0
-
- *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[0] );
- *mpIso->lbmGetData( i , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[1] );
- *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[2] );
-
- *mpIso->lbmGetData( i-1 , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[3] );
- *mpIso->lbmGetData( i , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[4] );
- *mpIso->lbmGetData( i+1 , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[5] );
-
- *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[6] );
- *mpIso->lbmGetData( i , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[7] );
- *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[8] );
-
-
- *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF ) += ( val * mIsoWeight[9] );
- *mpIso->lbmGetData( i , j-1 ,ZKOFF ) += ( val * mIsoWeight[10] );
- *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF ) += ( val * mIsoWeight[11] );
-
- *mpIso->lbmGetData( i-1 , j ,ZKOFF ) += ( val * mIsoWeight[12] );
- *mpIso->lbmGetData( i , j ,ZKOFF ) += ( val * mIsoWeight[13] );
- *mpIso->lbmGetData( i+1 , j ,ZKOFF ) += ( val * mIsoWeight[14] );
-
- *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF ) += ( val * mIsoWeight[15] );
- *mpIso->lbmGetData( i , j+1 ,ZKOFF ) += ( val * mIsoWeight[16] );
- *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF ) += ( val * mIsoWeight[17] );
-
-
- *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[18] );
- *mpIso->lbmGetData( i , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[19] );
- *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[20] );
-
- *mpIso->lbmGetData( i-1 , j ,ZKOFF+ZKD1) += ( val * mIsoWeight[21] );
- *mpIso->lbmGetData( i , j ,ZKOFF+ZKD1)+= ( val * mIsoWeight[22] );
- *mpIso->lbmGetData( i+1 , j ,ZKOFF+ZKD1) += ( val * mIsoWeight[23] );
-
- *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[24] );
- *mpIso->lbmGetData( i , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[25] );
- *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[26] );
- }
-
- // TEST!?
-#if SURFACE_ENH>=2
-
- if(mFsSurfGenSetting&fssgNoObs) {
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k)
- for(int j=1;j<mLevel[lev].lSizey-1;j++)
- for(int i=1;i<mLevel[lev].lSizex-1;i++) {
- const CellFlagType cflag = RFLAG(lev, i,j,k,workSet);
- if(cflag&(CFBnd)) {
- CellFlagType nbored=0;
- LbmFloat avgfill=0.,avgfcnt=0.;
- FORDF1 {
- const int ni = i+dfVecX[l];
- const int nj = j+dfVecY[l];
- const int nk = ZKOFF+dfVecZ[l];
-
- const CellFlagType nbflag = RFLAG(lev, ni,nj,nk, workSet);
- nbored |= nbflag;
- if(nbflag&CFInter) {
- avgfill += QCELL(lev, ni,nj,nk, workSet,dFfrac); avgfcnt += 1.;
- } else if(nbflag&CFFluid) {
- avgfill += 1.; avgfcnt += 1.;
- } else if(nbflag&CFEmpty) {
- avgfill += 0.; avgfcnt += 1.;
- }
-
- //if( (ni<0) || (nj<0) || (nk<0)
- //|| (ni>=mLevel[mMaxRefine].lSizex)
- //|| (nj>=mLevel[mMaxRefine].lSizey)
- //|| (nk>=mLevel[mMaxRefine].lSizez) ) continue;
- }
-
- if(nbored&CFInter) {
- if(avgfcnt>0.) avgfill/=avgfcnt;
- *mpIso->lbmGetData(i,j,ZKOFF) = avgfill; continue;
- }
- else if(nbored&CFFluid) {
- *mpIso->lbmGetData(i,j,ZKOFF) = 1.; continue;
- }
-
- }
- }
-
- // move surface towards inner "row" of obstacle
- // cells if necessary (all obs cells without fluid/inter
- // nbs (=iso==0) next to obstacles...)
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k)
- for(int j=1;j<mLevel[lev].lSizey-1;j++)
- for(int i=1;i<mLevel[lev].lSizex-1;i++) {
- const CellFlagType cflag = RFLAG(lev, i,j,k,workSet);
- if( (cflag&(CFBnd)) && (*mpIso->lbmGetData(i,j,ZKOFF)==0.)) {
- int bndnbcnt=0;
- FORDF1 {
- const int ni = i+dfVecX[l];
- const int nj = j+dfVecY[l];
- const int nk = ZKOFF+dfVecZ[l];
- const CellFlagType nbflag = RFLAG(lev, ni,nj,nk, workSet);
- if(nbflag&CFBnd) bndnbcnt++;
- }
- if(bndnbcnt>0) *mpIso->lbmGetData(i,j,ZKOFF)=mIsoValue*0.95;
- }
- }
- }
- // */
-
- if(mFsSurfGenSetting&fssgNoNorth)
- for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k)
- for(int j=0;j<mLevel[lev].lSizey-0;j++) {
- *mpIso->lbmGetData(0, j,ZKOFF) = *mpIso->lbmGetData(1, j,ZKOFF);
- }
- if(mFsSurfGenSetting&fssgNoEast)
- for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,0, ZKOFF) = *mpIso->lbmGetData(i,1, ZKOFF);
- }
- if(mFsSurfGenSetting&fssgNoSouth)
- for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k)
- for(int j=0;j<mLevel[lev].lSizey-0;j++) {
- *mpIso->lbmGetData(mLevel[lev].lSizex-1,j,ZKOFF) = *mpIso->lbmGetData(mLevel[lev].lSizex-2,j,ZKOFF);
- }
- if(mFsSurfGenSetting&fssgNoWest)
- for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,mLevel[lev].lSizey-1,ZKOFF) = *mpIso->lbmGetData(i,mLevel[lev].lSizey-2,ZKOFF);
- }
- if(LBMDIM>2) {
- if(mFsSurfGenSetting&fssgNoBottom)
- for(int j=0;j<mLevel[lev].lSizey-0;j++)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,j,0 ) = *mpIso->lbmGetData(i,j,1 );
- }
- if(mFsSurfGenSetting&fssgNoTop)
- for(int j=0;j<mLevel[lev].lSizey-0;j++)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,j,mLevel[lev].lSizez-1) = *mpIso->lbmGetData(i,j,mLevel[lev].lSizez-2);
- }
- }
-#endif // SURFACE_ENH>=2
-
-
- // update preview, remove 2d?
- if((mOutputSurfacePreview)&&(LBMDIM==3)) {
- int pvsx = (int)(mPreviewFactor*mSizex);
- int pvsy = (int)(mPreviewFactor*mSizey);
- int pvsz = (int)(mPreviewFactor*mSizez);
- //float scale = (float)mSizex / previewSize;
- LbmFloat scalex = (LbmFloat)mSizex/(LbmFloat)pvsx;
- LbmFloat scaley = (LbmFloat)mSizey/(LbmFloat)pvsy;
- LbmFloat scalez = (LbmFloat)mSizez/(LbmFloat)pvsz;
- for(int k= 0; k< (pvsz-1); ++k)
- for(int j=0;j< pvsy;j++)
- for(int i=0;i< pvsx;i++) {
- *mpPreviewSurface->lbmGetData(i,j,k) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley), (int)(k*scalez) );
- }
- // set borders again...
- for(int k= 0; k< (pvsz-1); ++k) {
- for(int j=0;j< pvsy;j++) {
- *mpPreviewSurface->lbmGetData(0,j,k) = *mpIso->lbmGetData( 0, (int)(j*scaley), (int)(k*scalez) );
- *mpPreviewSurface->lbmGetData(pvsx-1,j,k) = *mpIso->lbmGetData( mSizex-1, (int)(j*scaley), (int)(k*scalez) );
- }
- for(int i=0;i< pvsx;i++) {
- *mpPreviewSurface->lbmGetData(i,0,k) = *mpIso->lbmGetData( (int)(i*scalex), 0, (int)(k*scalez) );
- *mpPreviewSurface->lbmGetData(i,pvsy-1,k) = *mpIso->lbmGetData( (int)(i*scalex), mSizey-1, (int)(k*scalez) );
- }
- }
- for(int j=0;j<pvsy;j++)
- for(int i=0;i<pvsx;i++) {
- *mpPreviewSurface->lbmGetData(i,j,0) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley) , 0);
- *mpPreviewSurface->lbmGetData(i,j,pvsz-1) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley) , mSizez-1);
- }
-
- if(mFarFieldSize>=1.2) {
- // also remove preview border
- for(int k= 0; k< (pvsz-1); ++k) {
- for(int j=0;j< pvsy;j++) {
- *mpPreviewSurface->lbmGetData(0,j,k) =
- *mpPreviewSurface->lbmGetData(1,j,k) =
- *mpPreviewSurface->lbmGetData(2,j,k);
- *mpPreviewSurface->lbmGetData(pvsx-1,j,k) =
- *mpPreviewSurface->lbmGetData(pvsx-2,j,k) =
- *mpPreviewSurface->lbmGetData(pvsx-3,j,k);
- //0.0;
- }
- for(int i=0;i< pvsx;i++) {
- *mpPreviewSurface->lbmGetData(i,0,k) =
- *mpPreviewSurface->lbmGetData(i,1,k) =
- *mpPreviewSurface->lbmGetData(i,2,k);
- *mpPreviewSurface->lbmGetData(i,pvsy-1,k) =
- *mpPreviewSurface->lbmGetData(i,pvsy-2,k) =
- *mpPreviewSurface->lbmGetData(i,pvsy-3,k);
- //0.0;
- }
- }
- for(int j=0;j<pvsy;j++)
- for(int i=0;i<pvsx;i++) {
- *mpPreviewSurface->lbmGetData(i,j,0) =
- *mpPreviewSurface->lbmGetData(i,j,1) =
- *mpPreviewSurface->lbmGetData(i,j,2);
- *mpPreviewSurface->lbmGetData(i,j,pvsz-1) =
- *mpPreviewSurface->lbmGetData(i,j,pvsz-2) =
- *mpPreviewSurface->lbmGetData(i,j,pvsz-3);
- //0.0;
- }
- }
- }
-
- // MPT
- #if LBM_INCLUDE_TESTSOLVERS==1
- mrIsoExchange();
- #endif // LBM_INCLUDE_TESTSOLVERS==1
-
- return;
-}
-
-/*! calculate speeds of fluid objects (or inflow) */
-void LbmFsgrSolver::recalculateObjectSpeeds() {
- const bool debugRecalc = false;
- int numobjs = (int)(this->mpGiObjects->size());
- // note - (numobjs + 1) is entry for domain settings
-
- if(debugRecalc) errMsg("recalculateObjectSpeeds","start, #obj:"<<numobjs);
- if(numobjs>255-1) {
- errFatal("LbmFsgrSolver::recalculateObjectSpeeds","More than 256 objects currently not supported...",SIMWORLD_INITERROR);
- return;
- }
- mObjectSpeeds.resize(numobjs+1);
- for(int i=0; i<(int)(numobjs+0); i++) {
- mObjectSpeeds[i] = vec2L(this->mpParam->calculateLattVelocityFromRw( vec2P( (*this->mpGiObjects)[i]->getInitialVelocity(mSimulationTime) )));
- if(debugRecalc) errMsg("recalculateObjectSpeeds","id"<<i<<" set to "<< mObjectSpeeds[i]<<", unscaled:"<< (*this->mpGiObjects)[i]->getInitialVelocity(mSimulationTime) );
- }
-
- // also reinit part slip values here
- mObjectPartslips.resize(numobjs+1);
- for(int i=0; i<=(int)(numobjs+0); i++) {
- if(i<numobjs) {
- mObjectPartslips[i] = (LbmFloat)(*this->mpGiObjects)[i]->getGeoPartSlipValue();
- } else {
- // domain setting
- mObjectPartslips[i] = this->mDomainPartSlipValue;
- }
- LbmFloat set = mObjectPartslips[i];
-
- // as in setInfluenceVelocity
- const LbmFloat dt = mLevel[mMaxRefine].timestep;
- const LbmFloat dtInter = 0.01;
- //LbmFloat facFv = 1.-set;
- // mLevel[mMaxRefine].timestep
- LbmFloat facNv = (LbmFloat)( 1.-pow( (double)(set), (double)(dt/dtInter)) );
- errMsg("mObjectPartslips","id:"<<i<<"/"<<numobjs<<" ts:"<<dt<< " its:"<<(dt/dtInter) <<" set"<<set<<" nv"<<facNv<<" test:"<<
- pow( (double)(1.-facNv),(double)(dtInter/dt)) );
- mObjectPartslips[i] = facNv;
-
- if(debugRecalc) errMsg("recalculateObjectSpeeds","id"<<i<<" parts "<< mObjectPartslips[i] );
- }
-
- if(debugRecalc) errMsg("recalculateObjectSpeeds","done, domain:"<<mObjectPartslips[numobjs]<<" n"<<numobjs);
-}
-
-
-
-/*****************************************************************************/
-/*! debug object display */
-/*****************************************************************************/
-vector<ntlGeometryObject*> LbmFsgrSolver::getDebugObjects() {
- vector<ntlGeometryObject*> debo;
- if(this->mOutputSurfacePreview) {
- debo.push_back( mpPreviewSurface );
- }
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(mUseTestdata) {
- vector<ntlGeometryObject*> tdebo;
- tdebo = mpTest->getDebugObjects();
- for(size_t i=0; i<tdebo.size(); i++) debo.push_back( tdebo[i] );
- }
-#endif // ELBEEM_PLUGIN
- return debo;
-}
-
-/******************************************************************************
- * particle handling
- *****************************************************************************/
-
-/*! init particle positions */
-int LbmFsgrSolver::initParticles() {
- int workSet = mLevel[mMaxRefine].setCurr;
- int tries = 0;
- int num = 0;
- ParticleTracer *partt = mpParticles;
-
- partt->setStart( this->mvGeoStart + ntlVec3Gfx(mLevel[mMaxRefine].nodeSize*0.5) );
- partt->setEnd ( this->mvGeoEnd + ntlVec3Gfx(mLevel[mMaxRefine].nodeSize*0.5) );
-
- partt->setSimStart( ntlVec3Gfx(0.0) );
- partt->setSimEnd ( ntlVec3Gfx(mSizex, mSizey, getForZMaxBnd(mMaxRefine)) );
-
- while( (num<partt->getNumInitialParticles()) && (tries<100*partt->getNumInitialParticles()) ) {
- LbmFloat x,y,z,t;
- x = 1.0+(( (LbmFloat)(mSizex-3.) ) * (rand()/(RAND_MAX+1.0)) );
- y = 1.0+(( (LbmFloat)(mSizey-3.) ) * (rand()/(RAND_MAX+1.0)) );
- z = 1.0+(( (LbmFloat) getForZMax1(mMaxRefine)-2. )* (rand()/(RAND_MAX+1.0)) );
- int i = (int)(x+0.5);
- int j = (int)(y+0.5);
- int k = (int)(z+0.5);
- if(LBMDIM==2) {
- k = 0; z = 0.5; // place in the middle of domain
- }
-
- //if( RFLAG(mMaxRefine, i,j,k, workSet)& (CFFluid) )
- //&& ( RFLAG(mMaxRefine, i,j,k, workSet)& CFNoNbFluid )
- //if( RFLAG(mMaxRefine, i,j,k, workSet) & (CFFluid|CFInter|CFMbndInflow) ) {
- if( RFLAG(mMaxRefine, i,j,k, workSet) & (CFNoBndFluid|CFUnused) ) {
- bool cellOk = true;
- //? FORDF1 { if(!(RFLAG_NB(mMaxRefine,i,j,k,workSet, l) & CFFluid)) cellOk = false; }
- if(!cellOk) continue;
- // in fluid...
- partt->addParticle(x,y,z);
- partt->getLast()->setStatus(PART_IN);
- partt->getLast()->setType(PART_TRACER);
-
- partt->getLast()->setSize(1.);
- // randomize size
- partt->getLast()->setSize(0.5 + (rand()/(RAND_MAX+1.0)));
-
- if( ( partt->getInitStart()>0.)
- && ( partt->getInitEnd()>0.)
- && ( partt->getInitEnd()>partt->getInitStart() )) {
- t = partt->getInitStart()+ (partt->getInitEnd()-partt->getInitStart())*(rand()/(RAND_MAX+1.0));
- partt->getLast()->setLifeTime( -t );
- }
- num++;
- }
- tries++;
- } // */
-
- /*FSGR_FORIJK1(mMaxRefine) {
- if( (RFLAG(mMaxRefine,i,j,k, workSet) & (CFNoBndFluid)) ) {
- LbmFloat rndn = (rand()/(RAND_MAX+1.0));
- if(rndn>0.0) {
- ntlVec3Gfx pos( (LbmFloat)(i)-0.5, (LbmFloat)(j)-0.5, (LbmFloat)(k)-0.5 );
- if(LBMDIM==2) { pos[2]=0.5; }
- partt->addParticle( pos[0],pos[1],pos[2] );
- partt->getLast()->setStatus(PART_IN);
- partt->getLast()->setType(PART_TRACER);
- partt->getLast()->setSize(1.0);
- }
- }
- } // */
-
-
- // DEBUG TEST
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(mUseTestdata) {
- const bool partDebug=false;
- if(mpTest->mPartTestcase==0){ errMsg("LbmTestdata"," part init "<<mpTest->mPartTestcase); }
- if(mpTest->mPartTestcase==-12){
- const int lev = mMaxRefine;
- for(int i=5;i<15;i++) {
- LbmFloat x,y,z;
- y = 0.5+(LbmFloat)(i);
- x = mLevel[lev].lSizex/20.0*10.0;
- z = mLevel[lev].lSizez/20.0*2.0;
- partt->addParticle(x,y,z);
- partt->getLast()->setStatus(PART_IN);
- partt->getLast()->setType(PART_BUBBLE);
- partt->getLast()->setSize( (-4.0+(LbmFloat)i)/1.0 );
- if(partDebug) errMsg("PARTTT","SET "<<PRINT_VEC(x,y,z)<<" p"<<partt->getLast()->getPos() <<" s"<<partt->getLast()->getSize() );
- }
- }
- if(mpTest->mPartTestcase==-11){
- const int lev = mMaxRefine;
- for(int i=5;i<15;i++) {
- LbmFloat x,y,z;
- y = 10.5+(LbmFloat)(i);
- x = mLevel[lev].lSizex/20.0*10.0;
- z = mLevel[lev].lSizez/20.0*40.0;
- partt->addParticle(x,y,z);
- partt->getLast()->setStatus(PART_IN);
- partt->getLast()->setType(PART_DROP);
- partt->getLast()->setSize( (-4.0+(LbmFloat)i)/1.0 );
- if(partDebug) errMsg("PARTTT","SET "<<PRINT_VEC(x,y,z)<<" p"<<partt->getLast()->getPos() <<" s"<<partt->getLast()->getSize() );
- }
- }
- // place floats on rectangular region FLOAT_JITTER_BND
- if(mpTest->mPartTestcase==-10){
- const int lev = mMaxRefine;
- const int sx = mLevel[lev].lSizex;
- const int sy = mLevel[lev].lSizey;
- //for(int j=-(int)(sy*0.25);j<-(int)(sy*0.25)+2;++j) { for(int i=-(int)(sx*0.25);i<-(int)(sy*0.25)+2;++i) {
- //for(int j=-(int)(sy*1.25);j<(int)(2.25*sy);++j) { for(int i=-(int)(sx*1.25);i<(int)(2.25*sx);++i) {
- for(int j=-(int)(sy*0.3);j<(int)(1.3*sy);++j) { for(int i=-(int)(sx*0.3);i<(int)(1.3*sx);++i) {
- //for(int j=-(int)(sy*0.2);j<(int)(0.2*sy);++j) { for(int i= (int)(sx*0.5);i<= (int)(0.51*sx);++i) {
- LbmFloat x,y,z;
- x = 0.0+(LbmFloat)(i);
- y = 0.0+(LbmFloat)(j);
- //z = mLevel[lev].lSizez/10.0*2.5 - 1.0;
- z = mLevel[lev].lSizez/20.0*9.5 - 1.0;
- //z = mLevel[lev].lSizez/20.0*4.5 - 1.0;
- partt->addParticle(x,y,z);
- //if( (i>0)&&(i<sx) && (j>0)&&(j<sy) ) { partt->getLast()->setStatus(PART_IN); } else { partt->getLast()->setStatus(PART_OUT); }
- partt->getLast()->setStatus(PART_IN);
- partt->getLast()->setType(PART_FLOAT);
- partt->getLast()->setSize( 15.0 );
- if(partDebug) errMsg("PARTTT","SET "<<PRINT_VEC(x,y,z)<<" p"<<partt->getLast()->getPos() <<" s"<<partt->getLast()->getSize() );
- }
- } }
- }
- // DEBUG TEST
-#endif // LBM_INCLUDE_TESTSOLVERS
-
-
- debMsgStd("LbmFsgrSolver::initParticles",DM_MSG,"Added "<<num<<" particles, genProb:"<<this->mPartGenProb<<", tries:"<<tries, 10);
- if(num != partt->getNumParticles()) return 1;
-
- return 0;
-}
-
-// helper function for particle debugging
-/*static string getParticleStatusString(int state) {
- std::ostringstream out;
- if(state&PART_DROP) out << "dropp ";
- if(state&PART_TRACER) out << "tracr ";
- if(state&PART_BUBBLE) out << "bubbl ";
- if(state&PART_FLOAT) out << "float ";
- if(state&PART_INTER) out << "inter ";
-
- if(state&PART_IN) out << "inn ";
- if(state&PART_OUT) out << "out ";
- if(state&PART_INACTIVE) out << "INACT ";
- if(state&PART_OUTFLUID) out << "outfluid ";
- return out.str();
-} // */
-
-#define P_CHANGETYPE(p, newtype) \
- p->setLifeTime(0.); \
- /* errMsg("PIT","U pit"<<(p)->getId()<<" pos:"<< (p)->getPos()<<" status:"<<convertFlags2String((p)->getFlags())<<" to "<< (newtype) ); */ \
- p->setType(newtype);
-
-// tracer defines
-#define TRACE_JITTER 0.025
-#define TRACE_RAND (rand()/(RAND_MAX+1.0))*TRACE_JITTER-(TRACE_JITTER*0.5)
-#define FFGET_NORM(var,dl) \
- if(RFLAG_NB(lev,i,j,k,workSet, dl) &(CFInter)){ (var) = QCELL_NB(lev,i,j,k,workSet,dl,dFfrac); } \
- else if(RFLAG_NB(lev,i,j,k,workSet, dl) &(CFFluid|CFUnused)){ (var) = 1.; } else (var) = 0.0;
-
-// float jitter
-#define FLOAT_JITTER_BND (FLOAT_JITTER*2.0)
-#define FLOAT_JITTBNDRAND(x) ((rand()/(RAND_MAX+1.0))*FLOAT_JITTER_BND*(1.-(x/(LbmFloat)maxdw))-(FLOAT_JITTER_BND*(1.-(x)/(LbmFloat)maxdw)*0.5))
-
-#define DEL_PART { \
- /*errMsg("PIT","DEL AT "<< __LINE__<<" type:"<<p->getType()<<" "); */ \
- p->setActive( false ); \
- continue; }
-
-void LbmFsgrSolver::advanceParticles() {
- const int level = mMaxRefine;
- const int workSet = mLevel[level].setCurr;
- LbmFloat vx=0.0,vy=0.0,vz=0.0;
- //int debugOutCounter=0; // debug output counter
-
- myTime_t parttstart = getTime();
- const LbmFloat cellsize = this->mpParam->getCellSize();
- const LbmFloat timestep = this->mpParam->getTimestep();
- //const LbmFloat viscAir = 1.79 * 1e-5; // RW2L kin. viscosity, mu
- //const LbmFloat viscWater = 1.0 * 1e-6; // RW2L kin. viscosity, mu
- const LbmFloat rhoAir = 1.2; // [kg m^-3] RW2L
- const LbmFloat rhoWater = 1000.0; // RW2L
- const LbmFloat minDropSize = 0.0005; // [m], = 2mm RW2L
- const LbmVec velAir(0.); // [m / s]
-
- const LbmFloat r1 = 0.005; // r max
- const LbmFloat r2 = 0.0005; // r min
- const LbmFloat v1 = 9.0; // v max
- const LbmFloat v2 = 2.0; // v min
- const LbmVec rwgrav = vec2L( this->mpParam->getGravity(mSimulationTime) );
- const bool useff = (mFarFieldSize>1.2); // if(mpTest->mFarfMode>0){
-
- // TODO scale bubble/part damping dep. on timestep, also drop bnd rev damping
- const int cutval = mCutoff; // use full border!?
- if(this->mStepCnt%50==49) { mpParticles->cleanup(); }
- for(vector<ParticleObject>::iterator pit= mpParticles->getParticlesBegin();
- pit!= mpParticles->getParticlesEnd(); pit++) {
- //if((*pit).getPos()[2]>10.) errMsg("PIT"," pit"<<(*pit).getId()<<" pos:"<< (*pit).getPos()<<" status:["<<getParticleStatusString((*pit).getFlags())<<"] vel:"<< (*pit).getVel() );
- if( (*pit).getActive()==false ) continue;
- // skip until reached
- ParticleObject *p = &(*pit);
- if(p->getLifeTime()<0.){
- if(p->getLifeTime() < -mSimulationTime) continue;
- else p->setLifeTime(-mLevel[level].timestep); // zero for following update
- }
- int i,j,k;
- p->setLifeTime(p->getLifeTime()+mLevel[level].timestep);
-
- // nearest neighbor, particle positions don't include empty bounds
- ntlVec3Gfx pos = p->getPos();
- i= (int)pos[0]; j= (int)pos[1]; k= (int)pos[2];// no offset necessary
- if(LBMDIM==2) { k = 0; }
-
- // only testdata handling, all for sws
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(useff && (mpTest->mFarfMode>0)) {
- p->setStatus(PART_OUT);
- mpTest->handleParticle(p, i,j,k); continue;
- }
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
- // in out tests
- if(p->getStatus()&PART_IN) { // IN
- if( (i<cutval)||(i>mSizex-1-cutval)||
- (j<cutval)||(j>mSizey-1-cutval)
- //||(k<cutval)||(k>mSizez-1-cutval)
- ) {
- if(!useff) { DEL_PART;
- } else {
- p->setStatus(PART_OUT);
- }
- }
- } else { // OUT rough check
- // check in again?
- if( (i>=cutval)&&(i<=mSizex-1-cutval)&&
- (j>=cutval)&&(j<=mSizey-1-cutval)
- ) {
- p->setStatus(PART_IN);
- }
- }
-
- if( (p->getType()==PART_BUBBLE) ||
- (p->getType()==PART_TRACER) ) {
-
- // no interpol
- vx = vy = vz = 0.0;
- if(p->getStatus()&PART_IN) { // IN
- if(k>=cutval) {
- if(k>mSizez-1-cutval) DEL_PART;
-
- if( RFLAG(level, i,j,k, workSet)&(CFFluid|CFUnused) ) {
- // still ok
- int partLev = level;
- int si=i, sj=j, sk=k;
- while(partLev>0 && RFLAG(partLev, si,sj,sk, workSet)&(CFUnused)) {
- partLev--;
- si/=2;
- sj/=2;
- sk/=2;
- }
- // get velocity from fluid cell
- if( RFLAG(partLev, si,sj,sk, workSet)&(CFFluid) ) {
- LbmFloat *ccel = RACPNT(partLev, si,sj,sk, workSet);
- FORDF1{
- LbmFloat cdf = RAC(ccel, l);
- // TODO update below
- vx += (this->dfDvecX[l]*cdf);
- vy += (this->dfDvecY[l]*cdf);
- vz += (this->dfDvecZ[l]*cdf);
- }
- // remove gravity influence
- const LbmFloat lesomega = mLevel[level].omega; // no les
- vx -= mLevel[level].gravity[0] * lesomega*0.5;
- vy -= mLevel[level].gravity[1] * lesomega*0.5;
- vz -= mLevel[level].gravity[2] * lesomega*0.5;
- } // fluid vel
-
- } else { // OUT
- // out of bounds, deactivate...
- // FIXME make fsgr treatment
- if(p->getType()==PART_BUBBLE) { P_CHANGETYPE(p, PART_FLOAT ); continue; }
- }
- } else {
- // below 3d region, just rise
- }
- } else { // OUT
-# if LBM_INCLUDE_TESTSOLVERS==1
- if(useff) { mpTest->handleParticle(p, i,j,k); }
- else DEL_PART;
-# else // LBM_INCLUDE_TESTSOLVERS==1
- DEL_PART;
-# endif // LBM_INCLUDE_TESTSOLVERS==1
- // TODO use x,y vel...?
- }
-
- ntlVec3Gfx v = p->getVel(); // dampen...
- if( (useff)&& (p->getType()==PART_BUBBLE) ) {
- // test rise
-
- if(mPartUsePhysModel) {
- LbmFloat radius = p->getSize() * minDropSize;
- //LbmVec velPart = vec2L(p->getVel()) *cellsize/timestep; // L2RW, lattice velocity
- //LbmVec velWater = LbmVec(vx,vy,vz) *cellsize/timestep;// L2RW, fluid velocity
- //LbmVec velRel = velWater - velPart;
- //LbmFloat velRelNorm = norm(velRel);
- //LbmFloat pvolume = rhoAir * 4.0/3.0 * M_PI* radius*radius*radius; // volume: 4/3 pi r^3
-
- //LbmVec fb = -rwgrav* pvolume *rhoWater;
- //LbmVec fd = velRel*6.0*M_PI*radius* (1e-3); //viscWater;
- //LbmVec change = (fb+fd) *10.0*timestep *(timestep/cellsize);
- /*if(debugOutCounter<0) {
- errMsg("PIT","BTEST1 vol="<<pvolume<<" radius="<<radius<<" vn="<<velRelNorm<<" velPart="<<velPart<<" velRel"<<velRel);
- errMsg("PIT","BTEST2 cellsize="<<cellsize<<" timestep="<<timestep<<" viscW="<<viscWater<<" ss/mb="<<(timestep/(pvolume*rhoAir)));
- errMsg("PIT","BTEST2 grav="<<rwgrav<<" " );
- errMsg("PIT","BTEST2 change="<<(change)<<" fb="<<(fb)<<" fd="<<(fd)<<" ");
- errMsg("PIT","BTEST2 change="<<norm(change)<<" fb="<<norm(fb)<<" fd="<<norm(fd)<<" ");
- } // DEBUG */
-
- LbmVec fd2 = (LbmVec(vx,vy,vz)-vec2L(p->getVel())) * 6.0*M_PI*radius* (1e-3); //viscWater;
- LbmFloat w = 0.99;
- vz = (1.0-w)*vz + w*(p->getVel()[2]-0.5*(p->getSize()/5.0)*mLevel[level].gravity[2]);
- v = ntlVec3Gfx(vx,vy,vz)+vec2G(fd2);
- p->setVel( v );
- } else {
- // non phys, half old, half fluid, use slightly slower acc
- v = v*0.5 + ntlVec3Gfx(vx,vy,vz)* 0.5-vec2G(mLevel[level].gravity)*0.5;
- p->setVel( v * 0.99 );
- }
- p->advanceVel();
-
- } else if(p->getType()==PART_TRACER) {
- v = ntlVec3Gfx(vx,vy,vz);
- CellFlagType fflag = RFLAG(level, i,j,k, workSet);
-
- if(fflag&(CFFluid|CFInter) ) { p->setInFluid(true);
- } else { p->setInFluid(false); }
-
- if( (( fflag&CFFluid ) && ( fflag&CFNoBndFluid )) ||
- (( fflag&CFInter ) && (!(fflag&CFNoNbFluid)) ) ) {
- // only real fluid
-# if LBMDIM==3
- p->advance( TRACE_RAND,TRACE_RAND,TRACE_RAND);
-# else
- p->advance( TRACE_RAND,TRACE_RAND, 0.);
-# endif
-
- } else {
- // move inwards along normal, make sure normal is valid first
- // todo use class funcs!
- const int lev = level;
- LbmFloat nx=0.,ny=0.,nz=0., nv1,nv2;
- bool nonorm = false;
- if(i<=0) { nx = -1.; nonorm = true; }
- if(i>=mSizex-1) { nx = 1.; nonorm = true; }
- if(j<=0) { ny = -1.; nonorm = true; }
- if(j>=mSizey-1) { ny = 1.; nonorm = true; }
-# if LBMDIM==3
- if(k<=0) { nz = -1.; nonorm = true; }
- if(k>=mSizez-1) { nz = 1.; nonorm = true; }
-# endif // LBMDIM==3
- if(!nonorm) {
- FFGET_NORM(nv1,dE); FFGET_NORM(nv2,dW);
- nx = 0.5* (nv2-nv1);
- FFGET_NORM(nv1,dN); FFGET_NORM(nv2,dS);
- ny = 0.5* (nv2-nv1);
-# if LBMDIM==3
- FFGET_NORM(nv1,dT); FFGET_NORM(nv2,dB);
- nz = 0.5* (nv2-nv1);
-# else // LBMDIM==3
- nz = 0.;
-# endif // LBMDIM==3
- } else {
- v = p->getVel() + vec2G(mLevel[level].gravity);
- }
- p->advanceVec( (ntlVec3Gfx(nx,ny,nz)) * -0.1 ); // + vec2G(mLevel[level].gravity);
- }
- }
-
- p->setVel( v );
- p->advanceVel();
- }
-
- // drop handling
- else if(p->getType()==PART_DROP) {
- ntlVec3Gfx v = p->getVel(); // dampen...
-
- if(mPartUsePhysModel) {
- LbmFloat radius = p->getSize() * minDropSize;
- LbmVec velPart = vec2L(p->getVel()) *cellsize /timestep; // * cellsize / timestep; // L2RW, lattice velocity
- LbmVec velRel = velAir - velPart;
- //LbmVec velRelLat = velRel /cellsize*timestep; // L2RW
- LbmFloat velRelNorm = norm(velRel);
- // TODO calculate values in lattice units, compute CD?!??!
- LbmFloat mb = rhoWater * 4.0/3.0 * M_PI* radius*radius*radius; // mass: 4/3 pi r^3 rho
- const LbmFloat rw = (r1-radius)/(r1-r2);
- const LbmFloat rmax = (0.5 + 0.5*rw);
- const LbmFloat vmax = (v2 + (v1-v2)* (1.0-rw) );
- const LbmFloat cd = (rmax) * (velRelNorm)/(vmax);
-
- LbmVec fg = rwgrav * mb;// * (1.0-rhoAir/rhoWater);
- LbmVec fd = velRel* velRelNorm* cd*M_PI *rhoAir *0.5 *radius*radius;
- LbmVec change = (fg+ fd ) *timestep / mb *(timestep/cellsize);
- //if(k>0) { errMsg("\nPIT","NTEST1 mb="<<mb<<" radius="<<radius<<" vn="<<velRelNorm<<" velPart="<<velPart<<" velRel"<<velRel<<" pgetVel="<<p->getVel() ); }
-
- v += vec2G(change);
- p->setVel(v);
- // NEW
- } else {
- p->setVel( v );
- int gravk = (int)(p->getPos()[2]+mLevel[level].gravity[2]);
- if(gravk>=0 && gravk<mSizez && RFLAG(level, i,j,gravk, workSet)&CFBnd) {
- // dont add for "resting" parts
- v[2] = 0.;
- p->setVel( v*0.9 ); // restdamping
- } else {
- p->addToVel( vec2G(mLevel[level].gravity) );
- }
- } // OLD
- p->advanceVel();
-
- if(p->getStatus()&PART_IN) { // IN
- if(k<cutval) { DEL_PART; continue; }
- if(k<=mSizez-1-cutval){
- CellFlagType pflag = RFLAG(level, i,j,k, workSet);
- //errMsg("PIT move"," at "<<PRINT_IJK<<" flag"<<convertCellFlagType2String(pflag) );
- if (pflag & CFMbndOutflow) {
- DEL_PART;
- continue;
- }
- if(pflag & (CFBnd)) {
- handleObstacleParticle(p);
- continue;
- } else if(pflag & (CFEmpty)) {
- // still ok
- } else if((pflag & CFInter)
- //&&(!(RFLAG(level, i,j,k, workSet)& CFNoNbFluid))
- ) {
- // add to no nb fluid i.f.'s, so skip if interface with fluid nb
- } else if(pflag & (CFFluid|CFUnused|CFInter) ){ // interface cells ignored here due to previous check!
- // add dropmass again, (these are only interf. with nonbfl.)
- int oi= (int)(pos[0]-1.25*v[0]+0.5);
- int oj= (int)(pos[1]-1.25*v[1]+0.5);
- int ok= (int)(pos[2]-1.25*v[2]+0.5);
- const LbmFloat size = p->getSize();
- const LbmFloat dropmass = ParticleObject::getMass(mPartDropMassSub*size);
- bool orgcellok = false;
- if( (oi<0)||(oi>mSizex-1)||
- (oj<0)||(oj>mSizey-1)||
- (ok<0)||(ok>mSizez-1) ) {
- // org cell not ok!
- } else if( RFLAG(level, oi,oj,ok, workSet) & (CFInter) ){
- orgcellok = true;
- } else {
- // search upward for interface
- oi=i; oj=j; ok=k;
- for(int kk=0; kk<5 && ok<=mSizez-2; kk++) {
- ok++; // check sizez-2 due to this increment!
- if( RFLAG(level, oi,oj,ok, workSet) & (CFInter) ){
- kk = 5; orgcellok = true;
- }
- }
- }
-
- //errMsg("PTIMPULSE"," new v"<<v<<" at "<<PRINT_VEC(oi,oj,ok)<<" , was "<<PRINT_VEC(i,j,k)<<" ok "<<orgcellok );
- if(orgcellok) {
- QCELL(level, oi,oj,ok, workSet, dMass) += dropmass;
- QCELL(level, oi,oj,ok, workSet, dFfrac) += dropmass; // assume rho=1?
-
- if(RFLAG(level, oi,oj,ok, workSet) & CFNoBndFluid){
- // check speed, perhaps normalize
- gfxReal vlensqr = normNoSqrt(v);
- if(vlensqr > 0.166*0.166) {
- v *= 1./sqrtf((float)vlensqr)*0.166;
- }
- // compute cell velocity
- LbmFloat *tcel = RACPNT(level, oi,oj,ok, workSet);
- LbmFloat velUx=0., velUy=0., velUz=0.;
- FORDF0 {
- velUx += (this->dfDvecX[l]*RAC(tcel,l));
- velUy += (this->dfDvecY[l]*RAC(tcel,l));
- velUz += (this->dfDvecZ[l]*RAC(tcel,l));
- }
- // add impulse
- /*
- LbmFloat cellVelSqr = velUx*velUx+ velUy*velUy+ velUz*velUz;
- //errMsg("PTIMPULSE"," new v"<<v<<" cvs"<<cellVelSqr<<"="<<sqrt(cellVelSqr));
- if(cellVelSqr< 0.166*0.166) {
- FORDF1 {
- const LbmFloat add = 3. * dropmass * this->dfLength[l]*(v[0]*this->dfDvecX[l]+v[1]*this->dfDvecY[l]+v[2]*this->dfDvecZ[l]);
- RAC(tcel,l) += add;
- } } // */
- } // only add impulse away from obstacles!
- } // orgcellok
-
- // FIXME make fsgr treatment
- P_CHANGETYPE(p, PART_FLOAT ); continue;
- // jitter in cell to prevent stacking when hitting a steep surface
- ntlVec3Gfx cpos = p->getPos();
- cpos[0] += (rand()/(RAND_MAX+1.0))-0.5;
- cpos[1] += (rand()/(RAND_MAX+1.0))-0.5;
- cpos[2] += (rand()/(RAND_MAX+1.0))-0.5;
- p->setPos(cpos);
- } else {
- DEL_PART;
- this->mNumParticlesLost++;
- }
- }
- } else { // OUT
-# if LBM_INCLUDE_TESTSOLVERS==1
- if(useff) { mpTest->handleParticle(p, i,j,k); }
- else{ DEL_PART; }
-# else // LBM_INCLUDE_TESTSOLVERS==1
- DEL_PART;
-# endif // LBM_INCLUDE_TESTSOLVERS==1
- }
-
- } // air particle
-
- // inter particle
- else if(p->getType()==PART_INTER) {
- // unused!?
- if(p->getStatus()&PART_IN) { // IN
- if((k<cutval)||(k>mSizez-1-cutval)) {
- // undecided particle above or below... remove?
- DEL_PART;
- }
-
- CellFlagType pflag = RFLAG(level, i,j,k, workSet);
- if(pflag& CFInter ) {
- // still ok
- } else if(pflag& (CFFluid|CFUnused) ) {
- P_CHANGETYPE(p, PART_FLOAT ); continue;
- } else if(pflag& CFEmpty ) {
- P_CHANGETYPE(p, PART_DROP ); continue;
- } else if(pflag& CFBnd ) {
- P_CHANGETYPE(p, PART_FLOAT ); continue;
- }
- } else { // OUT
- // undecided particle outside... remove?
- DEL_PART;
- }
- }
-
- // float particle
- else if(p->getType()==PART_FLOAT) {
-
- if(p->getStatus()&PART_IN) { // IN
- if(k<cutval) DEL_PART;
- // not valid for mass...
- vx = vy = vz = 0.0;
-
- // define from particletracer.h
-#if MOVE_FLOATS==1
- const int DEPTH_AVG=3; // only average interface vels
- int ccnt=0;
- for(int kk=0;kk<DEPTH_AVG;kk+=1) {
- if((k-kk)<1) continue;
- if(RFLAG(level, i,j,k, workSet)&(CFInter)) {} else continue;
- ccnt++;
- FORDF1{
- LbmFloat cdf = QCELL(level, i,j,k-kk, workSet, l);
- vx += (this->dfDvecX[l]*cdf);
- vy += (this->dfDvecY[l]*cdf);
- vz += (this->dfDvecZ[l]*cdf);
- }
- }
- if(ccnt) {
- // use halved surface velocity (todo, use omega instead)
- vx /=(LbmFloat)(ccnt * 2.0); // half xy speed! value2
- vy /=(LbmFloat)(ccnt * 2.0);
- vz /=(LbmFloat)(ccnt); }
-#else // MOVE_FLOATS==1
- vx=vy=0.; //p->setVel(ntlVec3Gfx(0.) ); // static_float
-#endif // MOVE_FLOATS==1
- vx += (rand()/(RAND_MAX+1.0))*(FLOAT_JITTER*0.2)-(FLOAT_JITTER*0.2*0.5);
- vy += (rand()/(RAND_MAX+1.0))*(FLOAT_JITTER*0.2)-(FLOAT_JITTER*0.2*0.5);
-
- //bool delfloat = false;
- if( ( RFLAG(level, i,j,k, workSet)& (CFFluid|CFUnused) ) ) {
- // in fluid cell
- vz = p->getVel()[2]-1.0*mLevel[level].gravity[2]; // simply rise...
- if(vz<0.) vz=0.;
- } else if( ( RFLAG(level, i,j,k, workSet)& CFBnd ) ) {
- // force downwards movement, move below obstacle...
- //vz = p->getVel()[2]+1.0*mLevel[level].gravity[2]; // fall...
- //if(vz>0.) vz=0.;
- DEL_PART;
- } else if( ( RFLAG(level, i,j,k, workSet)& CFInter ) ) {
- // keep in interface , one grid cell offset is added in part. gen
- } else { // all else...
- if( ( RFLAG(level, i,j,k-1, workSet)& (CFFluid|CFInter) ) ) {
- vz = p->getVel()[2]+2.0*mLevel[level].gravity[2]; // fall...
- if(vz>0.) vz=0.; }
- else { DEL_PART; }
- }
-
- p->setVel( vec2G( ntlVec3Gfx(vx,vy,vz) ) ); //?
- p->advanceVel();
- } else {
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(useff) { mpTest->handleParticle(p, i,j,k); }
- else DEL_PART;
-#else // LBM_INCLUDE_TESTSOLVERS==1
- DEL_PART;
-#endif // LBM_INCLUDE_TESTSOLVERS==1
- }
-
- // additional bnd jitter
- if((0) && (useff) && (p->getLifeTime()<3.*mLevel[level].timestep)) {
- // use half butoff border 1/8
- int maxdw = (int)(mLevel[level].lSizex*0.125*0.5);
- if(maxdw<3) maxdw=3;
- if((j>=0)&&(j<=mSizey-1)) {
- if(ABS(i-( cutval))<maxdw) { p->advance( FLOAT_JITTBNDRAND( ABS(i-( cutval))), 0.,0.); }
- if(ABS(i-(mSizex-1-cutval))<maxdw) { p->advance( FLOAT_JITTBNDRAND( ABS(i-(mSizex-1-cutval))), 0.,0.); }
- }
- }
- } // PART_FLOAT
-
- // unknown particle type
- else {
- errMsg("LbmFsgrSolver::advanceParticles","PIT pit invalid type!? "<<p->getStatus() );
- }
- }
- myTime_t parttend = getTime();
- debMsgStd("LbmFsgrSolver::advanceParticles",DM_MSG,"Time for particle update:"<< getTimeString(parttend-parttstart)<<", #particles:"<<mpParticles->getNumParticles() , 10 );
-}
-
-void LbmFsgrSolver::notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) {
- int workSet = mLevel[mMaxRefine].setCurr;
- std::ostringstream name;
-
- // debug - raw dump of ffrac values, as text!
- if(mDumpRawText) {
- name << outfilename<< frameNrStr <<".dump";
- FILE *file = fopen(name.str().c_str(),"w");
- if(file) {
-
- for(int k= getForZMinBnd(); k< getForZMaxBnd(mMaxRefine); ++k) {
- for(int j=0;j<mLevel[mMaxRefine].lSizey-0;j++) {
- for(int i=0;i<mLevel[mMaxRefine].lSizex-0;i++) {
- float val = 0.;
- if(RFLAG(mMaxRefine, i,j,k, workSet) & CFInter) {
- val = QCELL(mMaxRefine,i,j,k, mLevel[mMaxRefine].setCurr,dFfrac);
- if(val<0.) val=0.;
- if(val>1.) val=1.;
- }
- if(RFLAG(mMaxRefine, i,j,k, workSet) & CFFluid) val = 1.;
- fprintf(file, "%f ",val); // text
- //errMsg("W", PRINT_IJK<<" val:"<<val);
- }
- fprintf(file, "\n"); // text
- }
- fprintf(file, "\n"); // text
- }
- fclose(file);
-
- } // file
- } // */
-
- if(mDumpRawBinary) {
- if(!mDumpRawBinaryZip) {
- // unzipped, only fill
- name << outfilename<< frameNrStr <<".bdump";
- FILE *file = fopen(name.str().c_str(),"w");
- if(file) {
- for(int k= getForZMinBnd(); k< getForZMaxBnd(mMaxRefine); ++k) {
- for(int j=0;j<mLevel[mMaxRefine].lSizey-0;j++) {
- for(int i=0;i<mLevel[mMaxRefine].lSizex-0;i++) {
- float val = 0.;
- if(RFLAG(mMaxRefine, i,j,k, workSet) & CFInter) {
- val = QCELL(mMaxRefine,i,j,k, mLevel[mMaxRefine].setCurr,dFfrac);
- if(val<0.) val=0.;
- if(val>1.) val=1.;
- }
- if(RFLAG(mMaxRefine, i,j,k, workSet) & CFFluid) val = 1.;
- fwrite( &val, sizeof(val), 1, file); // binary
- }
- }
- }
- fclose(file);
- } // file
- } // unzipped
- else {
- // zipped, use iso values
- prepareVisualization();
- name << outfilename<< frameNrStr <<".bdump.gz";
- gzFile gzf = gzopen(name.str().c_str(),"wb9");
- if(gzf) {
- // write size
- int s;
- s=mSizex; gzwrite(gzf, &s, sizeof(s));
- s=mSizey; gzwrite(gzf, &s, sizeof(s));
- s=mSizez; gzwrite(gzf, &s, sizeof(s));
-
- // write isovalues
- for(int k= getForZMinBnd(); k< getForZMaxBnd(mMaxRefine); ++k) {
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
- for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
- float val = 0.;
- val = *mpIso->lbmGetData( i,j,k );
- gzwrite(gzf, &val, sizeof(val));
- }
- }
- }
- gzclose(gzf);
- } // gzf
- } // zip
- } // bin dump
-
- dumptype = 0; frameNr = 0; // get rid of warning
-}
-
-/*! move a particle at a boundary */
-void LbmFsgrSolver::handleObstacleParticle(ParticleObject *p) {
- //if(normNoSqrt(v)<=0.) continue; // skip stuck
- /*
- p->setVel( v * -1. ); // revert
- p->advanceVel(); // move back twice...
- if( RFLAG(mMaxRefine, i,j,k, workSet)& (CFBndNoslip)) {
- p->setVel( v * -0.5 ); // revert & dampen
- }
- p->advanceVel();
- // */
- // TODO mark/remove stuck parts!?
-
- const int level = mMaxRefine;
- const int workSet = mLevel[level].setCurr;
- LbmVec v = vec2L( p->getVel() );
- if(normNoSqrt(v)<=0.) {
- p->setVel(vec2G(mLevel[level].gravity));
- }
-
- CellFlagType pflag = CFBnd;
- ntlVec3Gfx posOrg(p->getPos());
- ntlVec3Gfx npos(0.);
- int ni=1,nj=1,nk=1;
- int tries = 0;
-
- // try to undo movement
- p->advanceVec( (p->getVel()-vec2G(mLevel[level].gravity)) * -2.);
-
- npos = p->getPos(); ni= (int)npos[0];
- nj= (int)npos[1]; nk= (int)npos[2];
- if(LBMDIM==2) { nk = 0; }
- //errMsg("BOUNDCPAR"," t"<<PRINT_VEC(ni,nj,nk)<<" v"<<v<<" p"<<npos);
-
- // delete out of domain
- if(!checkDomainBounds(level,ni,nj,nk)) {
- //errMsg("BOUNDCPAR"," DEL! ");
- p->setActive( false );
- return;
- }
- pflag = RFLAG(level, ni,nj,nk, workSet);
-
- // try to force particle out of boundary
- bool haveNorm = false;
- LbmVec bnormal;
- if(pflag&CFBnd) {
- npos = posOrg; ni= (int)npos[0];
- nj= (int)npos[1]; nk= (int)npos[2];
- if(LBMDIM==2) { nk = 0; }
-
- computeObstacleSurfaceNormalAcc(ni,nj,nk, &bnormal[0]);
- haveNorm = true;
- normalize(bnormal);
- bnormal *= 0.25;
-
- tries = 1;
- while(pflag&CFBnd && tries<=5) {
- // use increasing step sizes
- p->advanceVec( vec2G( bnormal *0.5 *(gfxReal)tries ) );
- npos = p->getPos();
- ni= (int)npos[0];
- nj= (int)npos[1];
- nk= (int)npos[2];
-
- // delete out of domain
- if(!checkDomainBounds(level,ni,nj,nk)) {
- //errMsg("BOUNDCPAR"," DEL! ");
- p->setActive( false );
- return;
- }
- pflag = RFLAG(level, ni,nj,nk, workSet);
- tries++;
- }
-
- // really stuck, delete...
- if(pflag&CFBnd) {
- p->setActive( false );
- return;
- }
- }
-
- // not in bound anymore!
- if(!haveNorm) {
- CellFlagType *bflag = &RFLAG(level, ni,nj,nk, workSet);
- LbmFloat *bcell = RACPNT(level, ni,nj,nk, workSet);
- computeObstacleSurfaceNormal(bcell,bflag, &bnormal[0]);
- }
- normalize(bnormal);
- LbmVec normComp = bnormal * dot(vec2L(v),bnormal);
- //errMsg("BOUNDCPAR","bnormal"<<bnormal<<" normComp"<<normComp<<" newv"<<(v-normComp) );
- v = (v-normComp)*0.9; // only move tangential
- v *= 0.9; // restdamping , todo use timestep
- p->setVel(vec2G(v));
- p->advanceVel();
-}
-
-/*****************************************************************************/
-/*! internal quick print function (for debugging) */
-/*****************************************************************************/
-void
-LbmFsgrSolver::printLbmCell(int level, int i, int j, int k, int set) {
- stdCellId *newcid = new stdCellId;
- newcid->level = level;
- newcid->x = i;
- newcid->y = j;
- newcid->z = k;
-
- // this function is not called upon clicking, then its from setMouseClick
- debugPrintNodeInfo( newcid, set );
- delete newcid;
-}
-void
-LbmFsgrSolver::debugMarkCellCall(int level, int vi,int vj,int vk) {
- stdCellId *newcid = new stdCellId;
- newcid->level = level;
- newcid->x = vi;
- newcid->y = vj;
- newcid->z = vk;
- this->addCellToMarkedList( newcid );
-}
-
-
-/*****************************************************************************/
-// implement CellIterator<UniformFsgrCellIdentifier> interface
-/*****************************************************************************/
-
-
-
-// values from guiflkt.cpp
-extern double guiRoiSX, guiRoiSY, guiRoiSZ, guiRoiEX, guiRoiEY, guiRoiEZ;
-extern int guiRoiMaxLev, guiRoiMinLev;
-#define CID_SX (int)( (mLevel[cid->level].lSizex-1) * guiRoiSX )
-#define CID_SY (int)( (mLevel[cid->level].lSizey-1) * guiRoiSY )
-#define CID_SZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiSZ )
-
-#define CID_EX (int)( (mLevel[cid->level].lSizex-1) * guiRoiEX )
-#define CID_EY (int)( (mLevel[cid->level].lSizey-1) * guiRoiEY )
-#define CID_EZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiEZ )
-
-CellIdentifierInterface*
-LbmFsgrSolver::getFirstCell( ) {
- int level = mMaxRefine;
-
-#if LBMDIM==3
- if(mMaxRefine>0) { level = mMaxRefine-1; } // NO1HIGHESTLEV DEBUG
-#endif
- level = guiRoiMaxLev;
- if(level>mMaxRefine) level = mMaxRefine;
-
- //errMsg("LbmFsgrSolver::getFirstCell","Celliteration started...");
- stdCellId *cid = new stdCellId;
- cid->level = level;
- cid->x = CID_SX;
- cid->y = CID_SY;
- cid->z = CID_SZ;
- return cid;
-}
-
-LbmFsgrSolver::stdCellId*
-LbmFsgrSolver::convertBaseCidToStdCid( CellIdentifierInterface* basecid) {
- //stdCellId *cid = dynamic_cast<stdCellId*>( basecid );
- stdCellId *cid = (stdCellId*)( basecid );
- return cid;
-}
-
-void LbmFsgrSolver::advanceCell( CellIdentifierInterface* basecid) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- if(cid->getEnd()) return;
-
- //debugOut(" ADb "<<cid->x<<","<<cid->y<<","<<cid->z<<" e"<<cid->getEnd(), 10);
- cid->x++;
- if(cid->x > CID_EX){ cid->x = CID_SX; cid->y++;
- if(cid->y > CID_EY){ cid->y = CID_SY; cid->z++;
- if(cid->z > CID_EZ){
- cid->level--;
- cid->x = CID_SX;
- cid->y = CID_SY;
- cid->z = CID_SZ;
- if(cid->level < guiRoiMinLev) {
- cid->level = guiRoiMaxLev;
- cid->setEnd( true );
- }
- }
- }
- }
- //debugOut(" ADa "<<cid->x<<","<<cid->y<<","<<cid->z<<" e"<<cid->getEnd(), 10);
-}
-
-bool LbmFsgrSolver::noEndCell( CellIdentifierInterface* basecid) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return (!cid->getEnd());
-}
-
-void LbmFsgrSolver::deleteCellIterator( CellIdentifierInterface** cid ) {
- delete *cid;
- *cid = NULL;
-}
-
-CellIdentifierInterface* LbmFsgrSolver::getCellAt( ntlVec3Gfx pos ) {
- //int cellok = false;
- pos -= (this->mvGeoStart);
-
- LbmFloat mmaxsize = mLevel[mMaxRefine].nodeSize;
- for(int level=mMaxRefine; level>=0; level--) { // finest first
- //for(int level=0; level<=mMaxRefine; level++) { // coarsest first
- LbmFloat nsize = mLevel[level].nodeSize;
- int x,y,z;
- // CHECK +- maxsize?
- x = (int)((pos[0]+0.5*mmaxsize) / nsize );
- y = (int)((pos[1]+0.5*mmaxsize) / nsize );
- z = (int)((pos[2]+0.5*mmaxsize) / nsize );
- if(LBMDIM==2) z = 0;
-
- // double check...
- if(x<0) continue;
- if(y<0) continue;
- if(z<0) continue;
- if(x>=mLevel[level].lSizex) continue;
- if(y>=mLevel[level].lSizey) continue;
- if(z>=mLevel[level].lSizez) continue;
-
- // return fluid/if/border cells
- if( ( (RFLAG(level, x,y,z, mLevel[level].setCurr)&(CFUnused)) ) ||
- ( (level<mMaxRefine) && (RFLAG(level, x,y,z, mLevel[level].setCurr)&(CFUnused|CFEmpty)) ) ) {
- continue;
- } // */
-
- stdCellId *newcid = new stdCellId;
- newcid->level = level;
- newcid->x = x;
- newcid->y = y;
- newcid->z = z;
- //errMsg("cellAt",this->mName<<" "<<pos<<" l"<<level<<":"<<x<<","<<y<<","<<z<<" "<<convertCellFlagType2String(RFLAG(level, x,y,z, mLevel[level].setCurr)) );
- return newcid;
- }
-
- return NULL;
-}
-
-
-// INFO functions
-
-int LbmFsgrSolver::getCellSet ( CellIdentifierInterface* basecid) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return mLevel[cid->level].setCurr;
- //return mLevel[cid->level].setOther;
-}
-
-int LbmFsgrSolver::getCellLevel ( CellIdentifierInterface* basecid) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return cid->level;
-}
-
-ntlVec3Gfx LbmFsgrSolver::getCellOrigin ( CellIdentifierInterface* basecid) {
- ntlVec3Gfx ret;
-
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- ntlVec3Gfx cs( mLevel[cid->level].nodeSize );
- if(LBMDIM==2) { cs[2] = 0.0; }
-
- if(LBMDIM==2) {
- ret =(this->mvGeoStart + ntlVec3Gfx( cid->x *cs[0], cid->y *cs[1], (this->mvGeoEnd[2]-this->mvGeoStart[2])*0.5 )
- + ntlVec3Gfx(0.0,0.0,cs[1]*-0.25)*cid->level )
- +getCellSize(basecid);
- } else {
- ret =(this->mvGeoStart + ntlVec3Gfx( cid->x *cs[0], cid->y *cs[1], cid->z *cs[2] ))
- +getCellSize(basecid);
- }
- return (ret);
-}
-
-ntlVec3Gfx LbmFsgrSolver::getCellSize ( CellIdentifierInterface* basecid) {
- // return half size
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- ntlVec3Gfx retvec( mLevel[cid->level].nodeSize * 0.5 );
- // 2d display as rectangles
- if(LBMDIM==2) { retvec[2] = 0.0; }
- return (retvec);
-}
-
-LbmFloat LbmFsgrSolver::getCellDensity ( CellIdentifierInterface* basecid,int set) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
-
- // skip non-fluid cells
- if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&(CFFluid|CFInter)) {
- // ok go on...
- } else {
- return 0.;
- }
-
- LbmFloat rho = 0.0;
- FORDF0 { rho += QCELL(cid->level, cid->x,cid->y,cid->z, set, l); } // ORG
- return ((rho-1.0) * mLevel[cid->level].simCellSize / mLevel[cid->level].timestep) +1.0; // ORG
- /*if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFInter) { // test
- LbmFloat ux,uy,uz;
- ux=uy=uz= 0.0;
- int lev = cid->level;
- LbmFloat df[27], feqOld[27];
- FORDF0 {
- rho += QCELL(lev, cid->x,cid->y,cid->z, set, l);
- ux += this->dfDvecX[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l);
- uy += this->dfDvecY[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l);
- uz += this->dfDvecZ[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l);
- df[l] = QCELL(lev, cid->x,cid->y,cid->z, set, l);
- }
- FORDF0 {
- feqOld[l] = getCollideEq(l, rho,ux,uy,uz);
- }
- // debugging mods
- //const LbmFloat Qo = this->getLesNoneqTensorCoeff(df,feqOld);
- //const LbmFloat modOmega = this->getLesOmega(mLevel[lev].omega, mLevel[lev].lcsmago,Qo);
- //rho = (2.0-modOmega) *25.0;
- //rho = Qo*100.0;
- //if(cid->x==24){ errMsg("MODOMT"," at "<<PRINT_VEC(cid->x,cid->y,cid->z)<<" = "<<rho<<" "<<Qo); }
- //else{ rho=0.0; }
- } // test
- return rho; // test */
-}
-
-LbmVec LbmFsgrSolver::getCellVelocity ( CellIdentifierInterface* basecid,int set) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
-
- // skip non-fluid cells
- if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&(CFFluid|CFInter)) {
- // ok go on...
- } else {
- return LbmVec(0.0);
- }
-
- LbmFloat ux,uy,uz;
- ux=uy=uz= 0.0;
- FORDF0 {
- ux += this->dfDvecX[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l);
- uy += this->dfDvecY[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l);
- uz += this->dfDvecZ[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l);
- }
- LbmVec vel(ux,uy,uz);
- // TODO fix...
- return (vel * mLevel[cid->level].simCellSize / mLevel[cid->level].timestep * this->mDebugVelScale); // normal
-}
-
-LbmFloat LbmFsgrSolver::getCellDf( CellIdentifierInterface* basecid,int set, int dir) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return QCELL(cid->level, cid->x,cid->y,cid->z, set, dir);
-}
-LbmFloat LbmFsgrSolver::getCellMass( CellIdentifierInterface* basecid,int set) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return QCELL(cid->level, cid->x,cid->y,cid->z, set, dMass);
-}
-LbmFloat LbmFsgrSolver::getCellFill( CellIdentifierInterface* basecid,int set) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFInter) return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac);
- if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFFluid) return 1.0;
- return 0.0;
- //return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac);
-}
-CellFlagType LbmFsgrSolver::getCellFlag( CellIdentifierInterface* basecid,int set) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return RFLAG(cid->level, cid->x,cid->y,cid->z, set);
-}
-
-LbmFloat LbmFsgrSolver::getEquilDf( int l ) {
- return this->dfEquil[l];
-}
-
-
-ntlVec3Gfx LbmFsgrSolver::getVelocityAt (float xp, float yp, float zp) {
- ntlVec3Gfx avgvel(0.0);
- LbmFloat avgnum = 0.;
-
- // taken from getCellAt!
- const int level = mMaxRefine;
- const int workSet = mLevel[level].setCurr;
- const LbmFloat nsize = mLevel[level].nodeSize;
- const int x = (int)((-this->mvGeoStart[0]+xp-0.5*nsize) / nsize );
- const int y = (int)((-this->mvGeoStart[1]+yp-0.5*nsize) / nsize );
- int z = (int)((-this->mvGeoStart[2]+zp-0.5*nsize) / nsize );
- if(LBMDIM==2) z=0;
- //errMsg("DUMPVEL","p"<<PRINT_VEC(xp,yp,zp)<<" at "<<PRINT_VEC(x,y,z)<<" max"<<PRINT_VEC(mLevel[level].lSizex,mLevel[level].lSizey,mLevel[level].lSizez) );
-
- // return fluid/if/border cells
- // search neighborhood, do smoothing
- FORDF0{
- const int i = x+this->dfVecX[l];
- const int j = y+this->dfVecY[l];
- const int k = z+this->dfVecZ[l];
-
- if( (i<0) || (j<0) || (k<0)
- || (i>=mLevel[level].lSizex)
- || (j>=mLevel[level].lSizey)
- || (k>=mLevel[level].lSizez) ) continue;
-
- if( (RFLAG(level, i,j,k, mLevel[level].setCurr)&(CFFluid|CFInter)) ) {
- ntlVec3Gfx vel(0.0);
- LbmFloat *ccel = RACPNT(level, i,j,k ,workSet); // omp
- for(int n=1; n<this->cDfNum; n++) {
- vel[0] += (this->dfDvecX[n]*RAC(ccel,n));
- vel[1] += (this->dfDvecY[n]*RAC(ccel,n));
- vel[2] += (this->dfDvecZ[n]*RAC(ccel,n));
- }
-
- avgvel += vel;
- avgnum += 1.0;
- if(l==0) { // center slightly more weight
- avgvel += vel; avgnum += 1.0;
- }
- } // */
- }
-
- if(avgnum>0.) {
- ntlVec3Gfx retv = avgvel / avgnum;
- retv *= nsize/mLevel[level].timestep;
- // scale for current animation settings (frame time)
- retv *= mpParam->getCurrentAniFrameTime();
- //errMsg("DUMPVEL","t"<<mSimulationTime<<" at "<<PRINT_VEC(xp,yp,zp)<<" ret:"<<retv<<", avgv:"<<avgvel<<" n"<<avgnum<<" nsize"<<nsize<<" ts"<<mLevel[level].timestep<<" fr"<<mpParam->getCurrentAniFrameTime() );
- return retv;
- }
- // no cells here...?
- //errMsg("DUMPVEL"," at "<<PRINT_VEC(xp,yp,zp)<<" v"<<avgvel<<" n"<<avgnum<<" no vel !?");
- return ntlVec3Gfx(0.);
-}
-
-#if LBM_USE_GUI==1
-//! show simulation info (implement SimulationObject pure virtual func)
-void
-LbmFsgrSolver::debugDisplay(int set){
- //lbmDebugDisplay< LbmFsgrSolver >( set, this );
- lbmDebugDisplay( set );
-}
-#endif
-
-/*****************************************************************************/
-// strict debugging functions
-/*****************************************************************************/
-#if FSGR_STRICT_DEBUG==1
-#define STRICT_EXIT *((int *)0)=0;
-
-int LbmFsgrSolver::debLBMGI(int level, int ii,int ij,int ik, int is) {
- if(level < 0){ errMsg("LbmStrict::debLBMGI"," invLev- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(level > mMaxRefine){ errMsg("LbmStrict::debLBMGI"," invLev+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
-
- if((ii==-1)&&(ij==0)) {
- // special case for main loop, ok
- } else {
- if(ii<0){ errMsg("LbmStrict"," invX- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ij<0){ errMsg("LbmStrict"," invY- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ii>mLevel[level].lSizex-1){ errMsg("LbmStrict"," invX+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ij>mLevel[level].lSizey-1){ errMsg("LbmStrict"," invY+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- }
- if(ik<0){ errMsg("LbmStrict"," invZ- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ik>mLevel[level].lSizez-1){ errMsg("LbmStrict"," invZ+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(is<0){ errMsg("LbmStrict"," invS- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(is>1){ errMsg("LbmStrict"," invS+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- return _LBMGI(level, ii,ij,ik, is);
-};
-
-CellFlagType& LbmFsgrSolver::debRFLAG(int level, int xx,int yy,int zz,int set){
- return _RFLAG(level, xx,yy,zz,set);
-};
-
-CellFlagType& LbmFsgrSolver::debRFLAG_NB(int level, int xx,int yy,int zz,int set, int dir) {
- if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- // warning might access all spatial nbs
- if(dir>this->cDirNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- return _RFLAG_NB(level, xx,yy,zz,set, dir);
-};
-
-CellFlagType& LbmFsgrSolver::debRFLAG_NBINV(int level, int xx,int yy,int zz,int set, int dir) {
- if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- if(dir>this->cDirNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- return _RFLAG_NBINV(level, xx,yy,zz,set, dir);
-};
-
-int LbmFsgrSolver::debLBMQI(int level, int ii,int ij,int ik, int is, int l) {
- if(level < 0){ errMsg("LbmStrict::debLBMQI"," invLev- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(level > mMaxRefine){ errMsg("LbmStrict::debLBMQI"," invLev+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
-
- if((ii==-1)&&(ij==0)) {
- // special case for main loop, ok
- } else {
- if(ii<0){ errMsg("LbmStrict"," invX- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ij<0){ errMsg("LbmStrict"," invY- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ii>mLevel[level].lSizex-1){ errMsg("LbmStrict"," invX+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ij>mLevel[level].lSizey-1){ errMsg("LbmStrict"," invY+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- }
- if(ik<0){ errMsg("LbmStrict"," invZ- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ik>mLevel[level].lSizez-1){ errMsg("LbmStrict"," invZ+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(is<0){ errMsg("LbmStrict"," invS- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(is>1){ errMsg("LbmStrict"," invS+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(l<0) { errMsg("LbmStrict"," invD- "<<" l"<<l); STRICT_EXIT; }
- if(l>this->cDfNum){ // dFfrac is an exception
- if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<<l); STRICT_EXIT; } }
-#if COMPRESSGRIDS==1
- //if((!this->mInitDone) && (is!=mLevel[level].setCurr)){ STRICT_EXIT; } // COMPRT debug
-#endif // COMPRESSGRIDS==1
- return _LBMQI(level, ii,ij,ik, is, l);
-};
-
-LbmFloat& LbmFsgrSolver::debQCELL(int level, int xx,int yy,int zz,int set,int l) {
- //errMsg("LbmStrict","debQCELL debug: l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" l"<<l<<" index"<<LBMGI(level, xx,yy,zz,set));
- return _QCELL(level, xx,yy,zz,set,l);
-};
-
-LbmFloat& LbmFsgrSolver::debQCELL_NB(int level, int xx,int yy,int zz,int set, int dir,int l) {
- if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- if(dir>this->cDfNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- return _QCELL_NB(level, xx,yy,zz,set, dir,l);
-};
-
-LbmFloat& LbmFsgrSolver::debQCELL_NBINV(int level, int xx,int yy,int zz,int set, int dir,int l) {
- if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- if(dir>this->cDfNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- return _QCELL_NBINV(level, xx,yy,zz,set, dir,l);
-};
-
-LbmFloat* LbmFsgrSolver::debRACPNT(int level, int ii,int ij,int ik, int is ) {
- return _RACPNT(level, ii,ij,ik, is );
-};
-
-LbmFloat& LbmFsgrSolver::debRAC(LbmFloat* s,int l) {
- if(l<0) { errMsg("LbmStrict"," invD- "<<" l"<<l); STRICT_EXIT; }
- if(l>dTotalNum){ errMsg("LbmStrict"," invD+ "<<" l"<<l); STRICT_EXIT; }
- //if(l>this->cDfNum){ // dFfrac is an exception
- //if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<<l); STRICT_EXIT; } }
- return _RAC(s,l);
-};
-
-#endif // FSGR_STRICT_DEBUG==1
-
-
-/******************************************************************************
- * GUI&debugging functions
- *****************************************************************************/
-
-//! display a single node
-void LbmFsgrSolver::debugPrintNodeInfo(CellIdentifierInterface* cell, int forceSet) {
- //string printInfo,
- // force printing of one set? default = -1 = off
- bool printDF = false;
- bool printRho = false;
- bool printVel = false;
- bool printFlag = false;
- bool printGeom = false;
- bool printMass=false;
- bool printBothSets = false;
- string printInfo = this->getNodeInfoString();
-
- for(size_t i=0; i<printInfo.length()-0; i++) {
- char what = printInfo[i];
- switch(what) {
- case '+': // all on
- printDF = true; printRho = true; printVel = true; printFlag = true; printGeom = true; printMass = true ;
- printBothSets = true; break;
- case '-': // all off
- printDF = false; printRho = false; printVel = false; printFlag = false; printGeom = false; printMass = false;
- printBothSets = false; break;
- case 'd': printDF = true; break;
- case 'r': printRho = true; break;
- case 'v': printVel = true; break;
- case 'f': printFlag = true; break;
- case 'g': printGeom = true; break;
- case 'm': printMass = true; break;
- case 's': printBothSets = true; break;
- default:
- errFatal("debugPrintNodeInfo","Invalid node info id "<<what,SIMWORLD_GENERICERROR); return;
- }
- }
-
- ntlVec3Gfx org = this->getCellOrigin( cell );
- ntlVec3Gfx halfsize = this->getCellSize( cell );
- int set = this->getCellSet( cell );
- debMsgStd("debugPrintNodeInfo",DM_NOTIFY, "Printing cell info '"<<printInfo<<"' for node: "<<cell->getAsString()<<" from "<<this->getName()<<" currSet:"<<set , 1);
- if(printGeom) debMsgStd(" ",DM_MSG, "Org:"<<org<<" Halfsize:"<<halfsize<<" ", 1);
-
- int setmax = 2;
- if(!printBothSets) setmax = 1;
- if(forceSet>=0) setmax = 1;
-
- for(int s=0; s<setmax; s++) {
- int workset = set;
- if(s==1){ workset = (set^1); }
- if(forceSet>=0) workset = forceSet;
- debMsgStd(" ",DM_MSG, "Printing set:"<<workset<<" orgSet:"<<set, 1);
-
- if(printDF) {
- for(int l=0; l<LBM_DFNUM; l++) { // FIXME ??
- debMsgStd(" ",DM_MSG, " Df"<<l<<": "<<this->getCellDf(cell,workset,l), 1);
- }
- }
- if(printRho) {
- debMsgStd(" ",DM_MSG, " Rho: "<<this->getCellDensity(cell,workset), 1);
- }
- if(printVel) {
- debMsgStd(" ",DM_MSG, " Vel: "<<this->getCellVelocity(cell,workset), 1);
- }
- if(printFlag) {
- CellFlagType flag = this->getCellFlag(cell,workset);
- debMsgStd(" ",DM_MSG, " Flg: "<< flag<<" "<<convertFlags2String( flag ) <<" "<<convertCellFlagType2String( flag ), 1);
- }
- if(printMass) {
- debMsgStd(" ",DM_MSG, " Mss: "<<this->getCellMass(cell,workset), 1);
- }
- // dirty... TODO fixme
- debMsgStd(" ",DM_MSG, " Flx: "<<this->getCellDf(cell,workset,dFlux), 1);
- }
-}
-
-
diff --git a/intern/elbeem/intern/utilities.cpp b/intern/elbeem/intern/utilities.cpp
deleted file mode 100644
index 40596681b90..00000000000
--- a/intern/elbeem/intern/utilities.cpp
+++ /dev/null
@@ -1,498 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Global C style utility funcions
- *
- *****************************************************************************/
-
-
-#include <iostream>
-#include <sstream>
-#ifdef WIN32
-// for timing
-#include <windows.h>
-#else
-#include <time.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#endif
-
-#include "utilities.h"
-
-#ifndef NOPNG
-#ifdef WIN32
-#include "png.h"
-#else
-#include <png.h>
-#endif
-#endif // NOPNG
-#include <zlib.h>
-
-// global debug level
-#ifdef DEBUG
-int gDebugLevel = DEBUG;
-#else // DEBUG
-int gDebugLevel = 0;
-#endif // DEBUG
-
-// global world state, acces with get/setElbeemState
-int gElbeemState = SIMWORLD_INVALID;
-
-// access global state of elbeem simulator
-void setElbeemState(int set) {
- gElbeemState = set;
-}
-int getElbeemState(void) {
- return gElbeemState;
-}
-int isSimworldOk(void) {
- return (getElbeemState() >=0);
-}
-
-// last error as string, acces with get/setElbeemErrorString
-char gElbeemErrorString[256] = {'-','\0' };
-
-// access elbeem simulator error string
-void setElbeemErrorString(const char* set) {
- strncpy(gElbeemErrorString, set, 256);
-}
-char* getElbeemErrorString(void) { return gElbeemErrorString; }
-
-
-//! for interval debugging output
-myTime_t globalIntervalTime = 0;
-//! color output setting for messages (0==off, else on)
-#ifdef WIN32
-// switch off first call
-#define DEF_globalColorSetting -1
-#else // WIN32
-// linux etc., on by default
-#define DEF_globalColorSetting 1
-#endif // WIN32
-int globalColorSetting = DEF_globalColorSetting; // linux etc., on by default
-int globalFirstEnvCheck = 0;
-void resetGlobalColorSetting() { globalColorSetting = DEF_globalColorSetting; }
-
-// global string for formatting vector output, TODO test!?
-const char *globVecFormatStr = "V[%f,%f,%f]";
-
-
-// global mp on/off switch
-bool glob_mpactive = false;
-// global access to mpi index, for debugging (e.g. in utilities.cpp)
-int glob_mpnum = -1;
-int glob_mpindex = -1;
-int glob_mppn = -1;
-
-
-//-----------------------------------------------------------------------------
-// helper function that converts a string to integer,
-// and returns an alternative value if the conversion fails
-int convertString2Int(const char *str, int alt)
-{
- int val;
- char *endptr;
- bool success=true;
-
- val = strtol(str, &endptr, 10);
- if( (str==endptr) ||
- ((str!=endptr) && (*endptr != '\0')) ) success = false;
-
- if(!success) {
- return alt;
- }
- return val;
-}
-
-//-----------------------------------------------------------------------------
-//! helper function that converts a flag field to a readable integer
-string convertFlags2String(int flags) {
- std::ostringstream ret;
- ret <<"(";
- int max = sizeof(int)*8;
- for(int i=0; i<max; i++) {
- if(flags & (1<<31)) ret <<"1";
- else ret<<"0";
- if(i<max-1) {
- //ret << ",";
- if((i%8)==7) ret << " ";
- }
- flags = flags << 1;
- }
- ret <<")";
- return ret.str();
-}
-
-#ifndef NOPNG
-//-----------------------------------------------------------------------------
-//! write png image
-int writePng(const char *fileName, unsigned char **rowsp, int w, int h)
-{
- // defaults for elbeem
- const int colortype = PNG_COLOR_TYPE_RGBA;
- const int bitdepth = 8;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- png_bytep *rows = rowsp;
-
- //FILE *fp = fopen(fileName, "wb");
- FILE *fp = NULL;
- string doing = "open for writing";
- if (!(fp = fopen(fileName, "wb"))) goto fail;
-
- if(!png_ptr) {
- doing = "create png write struct";
- if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail;
- }
- if(!info_ptr) {
- doing = "create png info struct";
- if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail;
- }
-
- if (setjmp(png_jmpbuf(png_ptr))) goto fail;
- doing = "init IO";
- png_init_io(png_ptr, fp);
- doing = "write header";
- png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
- doing = "write info";
- png_write_info(png_ptr, info_ptr);
- doing = "write image";
- png_write_image(png_ptr, rows);
- doing = "write end";
- png_write_end(png_ptr, NULL);
- doing = "write destroy structs";
- png_destroy_write_struct(&png_ptr, &info_ptr);
-
- fclose( fp );
- return 0;
-
-fail:
- errMsg("writePng","Write_png: could not "<<doing<<" !");
- if(fp) fclose( fp );
- if(png_ptr || info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
- return -1;
-}
-#else // NOPNG
-// fallback - write ppm
-int writePng(const char *fileName, unsigned char **rowsp, int w, int h)
-{
- gzFile gzf;
- string filentemp(fileName);
- // remove suffix
- if((filentemp.length()>4) && (filentemp[filentemp.length()-4]=='.')) {
- filentemp[filentemp.length()-4] = '\0';
- }
- std::ostringstream filennew;
- filennew << filentemp.c_str();
- filennew << ".ppm.gz";
-
- gzf = gzopen(filennew.str().c_str(), "wb9");
- if(!gzf) goto fail;
-
- gzprintf(gzf,"P6\n%d %d\n255\n",w,h);
- // output binary pixels
- for(int j=0;j<h;j++) {
- for(int i=0;i<h;i++) {
- // remove alpha values
- gzwrite(gzf,&rowsp[j][i*4],3);
- }
- }
-
- gzclose( gzf );
- errMsg("writePng/ppm","Write_png/ppm: wrote to "<<filennew.str()<<".");
- return 0;
-
-fail:
- errMsg("writePng/ppm","Write_png/ppm: could not write to "<<filennew.str()<<" !");
- return -1;
-}
-#endif // NOPNG
-
-
-//-----------------------------------------------------------------------------
-// helper function to determine current time
-myTime_t getTime()
-{
- myTime_t ret = 0;
-#ifdef WIN32
- LARGE_INTEGER liTimerFrequency;
- QueryPerformanceFrequency(&liTimerFrequency);
- LARGE_INTEGER liLastTime;
- QueryPerformanceCounter(&liLastTime);
- ret = (INT)( ((double)liLastTime.QuadPart / liTimerFrequency.QuadPart)*1000 ); // - mFirstTime;
-#else
- struct timeval tv;
- struct timezone tz;
- tz.tz_minuteswest = 0;
- tz.tz_dsttime = 0;
- gettimeofday(&tv,&tz);
- ret = (tv.tv_sec*1000)+(tv.tv_usec/1000); //-mFirstTime;
-#endif
- return (myTime_t)ret;
-}
-//-----------------------------------------------------------------------------
-// convert time to readable string
-string getTimeString(myTime_t usecs) {
- std::ostringstream ret;
- //myTime_t us = usecs % 1000;
- myTime_t ms = (myTime_t)( (double)usecs / (60.0*1000.0) );
- myTime_t ss = (myTime_t)( ((double)usecs / 1000.0) - ((double)ms*60.0) );
- int ps = (int)( ((double)usecs - (double)ss*1000.0)/10.0 );
-
- //ret.setf(ios::showpoint|ios::fixed);
- //ret.precision(5); ret.width(7);
-
- if(ms>0) {
- ret << ms<<"m"<< ss<<"s" ;
- } else {
- if(ps>0) {
- ret << ss<<".";
- if(ps<10) { ret <<"0"; }
- ret <<ps<<"s" ;
- } else {
- ret << ss<<"s" ;
- }
- }
- return ret.str();
-}
-
-//! helper to check if a bounding box was specified in the right way
-bool checkBoundingBox(ntlVec3Gfx s, ntlVec3Gfx e, string checker) {
- if( (s[0]>e[0]) ||
- (s[1]>e[1]) ||
- (s[2]>e[2]) ) {
- errFatal("checkBoundingBox","Check by '"<<checker<<"' for BB "<<s<<":"<<e<<" failed! Aborting...",SIMWORLD_INITERROR);
- return 1;
- }
- return 0;
-}
-
-
-
-//-----------------------------------------------------------------------------
-// debug message output
-
-static string col_black ( "\033[0;30m");
-static string col_dark_gray ( "\033[1;30m");
-static string col_bright_gray ( "\033[0;37m");
-static string col_red ( "\033[0;31m");
-static string col_bright_red ( "\033[1;31m");
-static string col_green ( "\033[0;32m");
-static string col_bright_green ( "\033[1;32m");
-static string col_bright_yellow ( "\033[1;33m");
-static string col_yellow ( "\033[0;33m");
-static string col_cyan ( "\033[0;36m");
-static string col_bright_cyan ( "\033[1;36m");
-static string col_purple ( "\033[0;35m");
-static string col_bright_purple ( "\033[1;35m");
-static string col_neutral ( "\033[0m");
-static string col_std = col_bright_gray;
-
-std::ostringstream globOutstr;
-bool globOutstrForce=false;
-#define DM_NONE 100
-void messageOutputForce(string from) {
- bool org = globOutstrForce;
- globOutstrForce = true;
- messageOutputFunc(from, DM_NONE, "\n", 0);
- globOutstrForce = org;
-}
-
-void messageOutputFunc(string from, int id, string msg, myTime_t interval) {
- // fast skip
- if((id!=DM_FATAL)&&(gDebugLevel<=0)) return;
-
- if(interval>0) {
- myTime_t currTime = getTime();
- if((currTime - globalIntervalTime)>interval) {
- globalIntervalTime = getTime();
- } else {
- return;
- }
- }
-
- // colors off?
- if( (globalColorSetting == -1) || // off for e.g. win32
- ((globalColorSetting==1) && ((id==DM_FATAL)||( getenv("ELBEEM_NOCOLOROUT") )) )
- ) {
- // only reset once
- col_std = col_black = col_dark_gray = col_bright_gray =
- col_red = col_bright_red = col_green =
- col_bright_green = col_bright_yellow =
- col_yellow = col_cyan = col_bright_cyan =
- col_purple = col_bright_purple = col_neutral = "";
- globalColorSetting = 0;
- }
-
- std::ostringstream sout;
- if(id==DM_DIRECT) {
- sout << msg;
- } else {
- sout << col_cyan<< from;
- switch(id) {
- case DM_MSG:
- sout << col_std << " message:";
- break;
- case DM_NOTIFY:
- sout << col_bright_cyan << " note:" << col_std;
- break;
- case DM_IMPORTANT:
- sout << col_yellow << " important:" << col_std;
- break;
- case DM_WARNING:
- sout << col_bright_red << " warning:" << col_std;
- break;
- case DM_ERROR:
- sout << col_red << " error:" << col_red;
- break;
- case DM_FATAL:
- sout << col_red << " fatal("<<gElbeemState<<"):" << col_red;
- break;
- case DM_NONE:
- // only internal debugging msgs
- break;
- default:
- // this shouldnt happen...
- sout << col_red << " --- messageOutputFunc error: invalid id ("<<id<<") --- aborting... \n\n" << col_std;
- break;
- }
- sout <<" "<< msg << col_std;
- }
-
- if(id==DM_FATAL) {
- strncpy(gElbeemErrorString,sout.str().c_str(), 256);
- // dont print?
- if(gDebugLevel==0) return;
- sout << "\n"; // add newline for output
- }
-
- // determine output - file==1/stdout==0 / globstr==2
- char filen[256];
- strcpy(filen,"debug_unini.txt");
- int fileout = false;
-#if ELBEEM_MPI==1
- std::ostringstream mpin;
- if(glob_mpindex>=0) {
- mpin << "elbeem_log_"<< glob_mpindex <<".txt";
- } else {
- mpin << "elbeem_log_ini.txt";
- }
- fileout = 1;
- strncpy(filen, mpin.str().c_str(),255); filen[255]='\0';
-#else
- strncpy(filen, "elbeem_debug_log.txt",255);
-#endif
-
-#ifdef WIN32
- // windows causes trouble with direct output
- fileout = 1;
-#endif // WIN32
-
-#if PARALLEL==1
- fileout = 2;// buffer out, switch off again...
- if(globOutstrForce) fileout=1;
-#endif
- if(getenv("ELBEEM_FORCESTDOUT")) {
- fileout = 0;// always direct out
- }
- //fprintf(stdout,"out deb %d, %d, '%s',l%d \n",globOutstrForce,fileout, filen, globOutstr.str().size() );
-
-#if PARALLEL==1
-#pragma omp critical
-#endif // PARALLEL==1
- {
- if(fileout==1) {
- // debug level is >0 anyway, so write to file...
- FILE *logf = fopen(filen,"a+");
- // dont complain anymore here...
- if(logf) {
- if(globOutstrForce) {
- fprintf(logf, "%s",globOutstr.str().c_str() );
- globOutstr.str(""); // reset
- }
- fprintf(logf, "%s",sout.str().c_str() );
- fclose(logf);
- }
- } else if(fileout==2) {
- globOutstr << sout.str();
- } else {
- // normal stdout output
- fprintf(stdout, "%s",sout.str().c_str() );
- if(id!=DM_DIRECT) fflush(stdout);
- }
- } // omp crit
-}
-
-// helper functions from external program using elbeem lib (e.g. Blender)
-/* set gDebugLevel according to env. var */
-extern "C"
-void elbeemCheckDebugEnv(void) {
- const char *strEnvName = "BLENDER_ELBEEMDEBUG";
- const char *strEnvName2 = "ELBEEM_DEBUGLEVEL";
- if(globalFirstEnvCheck) return;
-
- if(getenv(strEnvName)) {
- gDebugLevel = atoi(getenv(strEnvName));
- if(gDebugLevel>0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<<strEnvName<<"'='"<<getenv(strEnvName)<<"', debugLevel set to: "<<gDebugLevel<<"\n", 1);
- }
- if(getenv(strEnvName2)) {
- gDebugLevel = atoi(getenv(strEnvName2));
- if(gDebugLevel>0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<<strEnvName2<<"'='"<<getenv(strEnvName2)<<"', debugLevel set to: "<<gDebugLevel<<"\n", 1);
- }
- if(gDebugLevel< 0) gDebugLevel = 0;
- if(gDebugLevel>10) gDebugLevel = 0; // only use valid values
- globalFirstEnvCheck = 1;
-}
-
-/* elbeem debug output function */
-extern "C"
-void elbeemDebugOut(char *msg) {
- elbeemCheckDebugEnv();
- // external messages default to debug level 5...
- if(gDebugLevel<5) return;
- // delegate to messageOutputFunc
- messageOutputFunc("[External]",DM_MSG,msg,0);
-}
-
-/* set elbeem debug output level (0=off to 10=full on) */
-extern "C"
-void elbeemSetDebugLevel(int level) {
- if(level<0) level=0;
- if(level>10) level=10;
- gDebugLevel=level;
-}
-
-
-/* estimate how much memory a given setup will require */
-#include "solver_interface.h"
-
-extern "C"
-double elbeemEstimateMemreq(int res,
- float sx, float sy, float sz,
- int refine, char *retstr) {
- int resx = res, resy = res, resz = res;
- // dont use real coords, just place from 0.0 to sizeXYZ
- ntlVec3Gfx vgs(0.0), vge(sx,sy,sz);
- initGridSizes( resx,resy,resz, vgs,vge, refine, 0);
-
- double memreq = -1.0;
- string memreqStr("");
- // ignore farfield for now...
- calculateMemreqEstimate(resx,resy,resz, refine, 0., &memreq, NULL, &memreqStr );
-
- if(retstr) {
- // copy at max. 32 characters
- strncpy(retstr, memreqStr.c_str(), 32 );
- retstr[31] = '\0';
- }
- return memreq;
-}
-
-
-
diff --git a/intern/elbeem/intern/utilities.h b/intern/elbeem/intern/utilities.h
deleted file mode 100644
index 274862b93b4..00000000000
--- a/intern/elbeem/intern/utilities.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Global C style utility funcions
- *
- *****************************************************************************/
-#ifndef UTILITIES_H
-#include "ntl_vector3dim.h"
-
-
-/* debugging outputs , debug level 0 (off) to 10 (max) */
-#ifdef ELBEEM_PLUGIN
-#ifdef DEBUG
-#undef DEBUG
-#endif
-#define DEBUG 0
-#else // ELBEEM_PLUGIN
-#define DEBUG 10
-#endif // ELBEEM_PLUGIN
-extern "C" int gDebugLevel;
-
-
-// time measurements
-typedef unsigned long myTime_t;
-
-
-// state of the simulation world
-// default
-#define SIMWORLD_INVALID 0
-// performing init
-#define SIMWORLD_INITIALIZING 1
-// after init, before starting simulation
-#define SIMWORLD_INITED 2
-// stop of the simulation run, can be continued later
-#define SIMWORLD_STOP 3
-// error during init
-#define SIMWORLD_INITERROR -1
-// error during simulation
-#define SIMWORLD_PANIC -2
-// general error
-#define SIMWORLD_GENERICERROR -3
-
-// access global state of elbeem simulator
-void setElbeemState(int set);
-int getElbeemState(void);
-int isSimworldOk(void);
-
-// access elbeem simulator error string
-void setElbeemErrorString(const char* set);
-char* getElbeemErrorString(void);
-
-
-/* debug output function */
-#define DM_MSG 1
-#define DM_NOTIFY 2
-#define DM_IMPORTANT 3
-#define DM_WARNING 4
-#define DM_ERROR 5
-#define DM_DIRECT 6
-#define DM_FATAL 7
-void messageOutputFunc(string from, int id, string msg, myTime_t interval);
-
-/* debugging messages defines */
-#ifdef DEBUG
-#if LBM_PRECISION==2
-#define MSGSTREAM std::ostringstream msg; msg.precision(15); msg.width(17);
-#else
-#define MSGSTREAM std::ostringstream msg; msg.precision(7); msg.width(9);
-#endif
-
-# define debMsgDirect(mStr) if(gDebugLevel>0) { std::ostringstream msg; msg << mStr; messageOutputFunc(string(""), DM_DIRECT, msg.str(), 0); }
-# define debMsgStd(from,id,mStr,level) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, id, msg.str(), 0); }
-# define debMsgNnl(from,id,mStr,level) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr ; messageOutputFunc(from, id, msg.str(), 0); }
-# define debMsgInter(from,id,mStr,level, interval) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, id, msg.str(), interval); }
-# define debugOut(mStr,level) if(gDebugLevel>=level) { debMsgStd("D",DM_MSG,mStr,level); }
-# define debugOutNnl(mStr,level) if(gDebugLevel>=level) { debMsgNnl("D",DM_MSG,mStr,level); }
-# define debugOutInter(mStr,level, interval) debMsgInter("D",DM_MSG ,mStr,level, interval);
-/* Error output function */
-#define errMsg(from,mStr) if(gDebugLevel>0){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, DM_ERROR, msg.str(), 0); }
-#define warnMsg(from,mStr) if(gDebugLevel>0){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, DM_WARNING, msg.str(), 0); }
-
-#else
-// no messages at all...
-# define debMsgDirect(mStr)
-# define debMsgStd(from,id,mStr,level)
-# define debMsgNnl(from,id,mStr,level)
-# define debMsgInter(from,id,mStr,level, interval)
-# define debugOut(mStr,level)
-# define debugOutNnl(mStr,level)
-# define debugOutInter(mStr,level, interval)
-# define errMsg(from,mStr)
-# define warnMsg(from,mStr)
-#endif
-
-#define errorOut(mStr) { errMsg("D",mStr); }
-
-// fatal errors - have to be handled
-#define errFatal(from,mStr,errCode) { \
- setElbeemState(errCode); \
- MSGSTREAM; msg << mStr; \
- messageOutputFunc(from, DM_FATAL, msg.str(), 0); \
-}
-
-
-//! helper function that converts a string to integer
-int convertString2Int(const char *str, int alt);
-
-//! helper function that converts a flag field to a readable integer
-string convertFlags2String(int flags);
-
-//! get the current system time
-myTime_t getTime();
-//! convert time to readable string
-string getTimeString(myTime_t usecs);
-
-//! helper to check if a bounding box was specified in the right way
-bool checkBoundingBox(ntlVec3Gfx s, ntlVec3Gfx e, string checker);
-
-//! reset color output for elbeem init
-void resetGlobalColorSetting();
-
-
-/*! print some vector from 3 values e.g. for ux,uy,uz */
-#define PRINT_VEC(x,y,z) " ["<<(x)<<","<<(y)<<","<<(z)<<"] "
-
-/*! print some vector from 3 values e.g. for ux,uy,uz */
-#define PRINT_VEC2D(x,y) " ["<<(x)<<","<<(y)<<"] "
-
-/*! print l'th neighbor of i,j,k as a vector, as we need ijk all the time */
-#define PRINT_IJK_NBL PRINT_VEC(i+D::dfVecX[l],j+D::dfVecY[l],k+D::dfVecZ[l])
-
-/*! print i,j,k as a vector, as we need ijk all the time */
-#define PRINT_IJK PRINT_VEC(i,j,k)
-
-/*! print i,j,k as a vector, as we need ijk all the time */
-#define PRINT_IJ PRINT_VEC2D(i,j)
-
-/*! print some vector from 3 values e.g. for ux,uy,uz */
-#define PRINT_NTLVEC(v) " ["<<(v)[0]<<","<<(v)[1]<<","<<(v)[2]<<"] "
-
-/*! print some vector from 3 values e.g. for ux,uy,uz */
-#define PRINT_NTLVEC2D(v) " ["<<(v)[0]<<","<<(v)[1]<<"] "
-
-/*! print a triangle */
-#define PRINT_TRIANGLE(t,mpV) " { "<<PRINT_VEC( (mpV[(t).getPoints()[0]][0]),(mpV[(t).getPoints()[0]][1]),(mpV[(t).getPoints()[0]][2]) )<<\
- PRINT_VEC( (mpV[(t).getPoints()[1]][0]),(mpV[(t).getPoints()[1]][1]),(mpV[(t).getPoints()[1]][2]) )<<" | "<<\
- PRINT_VEC( (mpV[(t).getPoints()[2]][0]),(mpV[(t).getPoints()[2]][1]),(mpV[(t).getPoints()[2]][2]) )<<" } "
-
-
-// write png image
-int writePng(const char *fileName, unsigned char **rowsp, int w, int h);
-
-/* some useful templated functions
- * may require some operators for the classes
- */
-
-/* minimum */
-#ifdef MIN
-#undef MIN
-#endif
-template < class T >
-inline T
-MIN( T a, T b )
-{ return (a < b) ? a : b ; }
-
-/* maximum */
-#ifdef MAX
-#undef MAX
-#endif
-template < class T >
-inline T
-MAX( T a, T b )
-{ return (a < b) ? b : a ; }
-
-/* sign of the value */
-template < class T >
-inline T
-SIGNUM( T a )
-{ return (0 < a) ? 1 : -1 ; }
-
-/* sign, returns -1,0,1 depending on sign/value=0 */
-template < class T >
-inline T
-SIGNUM0( T a )
-{ return (0 < a) ? 1 : ( a < 0 ? -1 : 0 ) ; }
-
-/* round to nearest integer */
-inline int
-ROUND(double d)
-{ return int(d + 0.5); }
-
-/* square function */
-template < class T >
-inline T
-SQUARE( T a )
-{ return a*a; }
-
-
-#define UTILITIES_H
-#endif
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 20d0f7d1e7d..1b55e9ddd19 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -331,6 +331,7 @@ typedef enum {
GHOST_kKeyRightAlt,
GHOST_kKeyOS, // Command key on Apple, Windows key(s) on Windows
GHOST_kKeyGrLess, // German PC only!
+ GHOST_kKeyApp, /* Also known as menu key. */
GHOST_kKeyCapsLock,
GHOST_kKeyNumLock,
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index 1fbce0c1e6b..df750fc50f6 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -227,8 +227,6 @@ static void makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs,
attribs.push_back(NSOpenGLPFANoRecovery);
}
- attribs.push_back(NSOpenGLPFAAllowOfflineRenderers); // for automatic GPU switching
-
if (stereoVisual)
attribs.push_back(NSOpenGLPFAStereo);
diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp
index ba9ed6e3037..119c9f28223 100644
--- a/intern/ghost/intern/GHOST_EventPrinter.cpp
+++ b/intern/ghost/intern/GHOST_EventPrinter.cpp
@@ -234,6 +234,9 @@ void GHOST_EventPrinter::getKeyString(GHOST_TKey key, char str[32]) const
case GHOST_kKeyOS:
tstr = "OS";
break;
+ case GHOST_kKeyApp:
+ tstr = "App";
+ break;
case GHOST_kKeyGrLess:
// PC german!
tstr = "GrLess";
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 68bac7d153b..2f597aee476 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -1802,8 +1802,9 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
}
/* arrow keys should not have utf8 */
- if ((keyCode > 266) && (keyCode < 271))
+ if ((keyCode >= GHOST_kKeyLeftArrow) && (keyCode <= GHOST_kKeyDownArrow)) {
utf8_buf[0] = '\0';
+ }
/* F keys should not have utf8 */
if ((keyCode >= GHOST_kKeyF1) && (keyCode <= GHOST_kKeyF20))
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index 06a82db1de5..d3295d5584c 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -234,6 +234,7 @@ static GHOST_TKey convertSDLKey(SDL_Scancode key)
GXMAP(type, SDL_SCANCODE_RALT, GHOST_kKeyRightAlt);
GXMAP(type, SDL_SCANCODE_LGUI, GHOST_kKeyOS);
GXMAP(type, SDL_SCANCODE_RGUI, GHOST_kKeyOS);
+ GXMAP(type, SDL_SCANCODE_APPLICATION, GHOST_kKeyApp);
GXMAP(type, SDL_SCANCODE_INSERT, GHOST_kKeyInsert);
GXMAP(type, SDL_SCANCODE_DELETE, GHOST_kKeyDelete);
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 3347a6f1d14..f6a1c378167 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -29,12 +29,6 @@
# define _WIN32_IE 0x0501 /* shipped before XP, so doesn't impose additional requirements */
#endif
-/* clang-format off */
-#pragma comment(linker,"\"/manifestdependency:type='win32' \
-name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
-processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
-/* clang-format on */
-
#include <commctrl.h>
#include <shlobj.h>
#include <tlhelp32.h>
@@ -869,6 +863,9 @@ GHOST_TKey GHOST_SystemWin32::convertKey(short vKey, short scanCode, short exten
case VK_RWIN:
key = GHOST_kKeyOS;
break;
+ case VK_APPS:
+ key = GHOST_kKeyApp;
+ break;
case VK_NUMLOCK:
key = GHOST_kKeyNumLock;
break;
@@ -1204,8 +1201,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized");
if (hwnd) {
-#if 0
- // Disabled due to bug in Intel drivers, see T51959
+
if (msg == WM_NCCREATE) {
// Tell Windows to automatically handle scaling of non-client areas
// such as the caption bar. EnableNonClientDpiScaling was introduced in Windows 10
@@ -1214,13 +1210,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
GHOST_WIN32_EnableNonClientDpiScaling fpEnableNonClientDpiScaling =
(GHOST_WIN32_EnableNonClientDpiScaling)::GetProcAddress(m_user32,
"EnableNonClientDpiScaling");
-
if (fpEnableNonClientDpiScaling) {
fpEnableNonClientDpiScaling(hwnd);
}
}
}
-#endif
GHOST_WindowWin32 *window = (GHOST_WindowWin32 *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (window) {
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 72c0ad761a4..24a577a18c4 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -1721,6 +1721,7 @@ static GHOST_TKey ghost_key_from_keysym(const KeySym key)
GXMAP(type, XK_Caps_Lock, GHOST_kKeyCapsLock);
GXMAP(type, XK_Scroll_Lock, GHOST_kKeyScrollLock);
GXMAP(type, XK_Num_Lock, GHOST_kKeyNumLock);
+ GXMAP(type, XK_Menu, GHOST_kKeyApp);
/* keypad events */
diff --git a/intern/mantaflow/CMakeLists.txt b/intern/mantaflow/CMakeLists.txt
new file mode 100644
index 00000000000..9fdd8b59aca
--- /dev/null
+++ b/intern/mantaflow/CMakeLists.txt
@@ -0,0 +1,67 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2019, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Sebastian Barschkis (sebbas)
+#
+# ***** END GPL LICENSE BLOCK *****
+
+add_definitions(-DWITH_FLUID=1)
+
+if(WITH_OPENVDB)
+ add_definitions(-DOPENVDB=1)
+endif()
+
+set(INC
+ extern
+ intern/strings
+ ../../source/blender/makesdna
+ ../../source/blender/blenlib
+)
+
+# Python is always required
+add_definitions(-DWITH_PYTHON)
+
+set(INC_SYS
+ ../../extern/mantaflow/helper/util
+ ../../extern/mantaflow/helper/pwrapper
+ ../../extern/mantaflow/preprocessed
+ ${PYTHON_INCLUDE_DIRS}
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ intern/manta_python_API.cpp
+ intern/manta_fluid_API.cpp
+ intern/MANTA_main.cpp
+
+ extern/manta_python_API.h
+ extern/manta_fluid_API.h
+ intern/MANTA_main.h
+ intern/strings/fluid_script.h
+ intern/strings/smoke_script.h
+ intern/strings/liquid_script.h
+)
+
+set(LIB
+ extern_mantaflow
+)
+
+blender_add_lib(bf_intern_mantaflow "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/intern/mantaflow/extern/manta_fluid_API.h b/intern/mantaflow/extern/manta_fluid_API.h
new file mode 100644
index 00000000000..aff3a54501c
--- /dev/null
+++ b/intern/mantaflow/extern/manta_fluid_API.h
@@ -0,0 +1,226 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup mantaflow
+ */
+
+#ifndef MANTA_API_H
+#define MANTA_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct MANTA;
+
+/* Fluid functions */
+struct MANTA *manta_init(int *res, struct FluidModifierData *mmd);
+void manta_free(struct MANTA *fluid);
+void manta_ensure_obstacle(struct MANTA *fluid, struct FluidModifierData *mmd);
+void manta_ensure_guiding(struct MANTA *fluid, struct FluidModifierData *mmd);
+void manta_ensure_invelocity(struct MANTA *fluid, struct FluidModifierData *mmd);
+void manta_ensure_outflow(struct MANTA *fluid, struct FluidModifierData *mmd);
+int manta_write_config(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_write_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_config(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_noise(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_mesh(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_particles(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_guiding(struct MANTA *fluid,
+ struct FluidModifierData *mmd,
+ int framenr,
+ bool sourceDomain);
+int manta_update_liquid_structures(struct MANTA *fluid,
+ struct FluidModifierData *mmd,
+ int framenr);
+int manta_update_mesh_structures(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_update_particle_structures(struct MANTA *fluid,
+ struct FluidModifierData *mmd,
+ int framenr);
+int manta_bake_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_bake_noise(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_bake_mesh(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_bake_particles(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_bake_guiding(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+void manta_update_variables(struct MANTA *fluid, struct FluidModifierData *mmd);
+int manta_get_frame(struct MANTA *fluid);
+float manta_get_timestep(struct MANTA *fluid);
+void manta_adapt_timestep(struct MANTA *fluid);
+bool manta_needs_realloc(struct MANTA *fluid, struct FluidModifierData *mmd);
+
+/* Fluid accessors */
+size_t manta_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */);
+size_t manta_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */);
+float *manta_get_velocity_x(struct MANTA *fluid);
+float *manta_get_velocity_y(struct MANTA *fluid);
+float *manta_get_velocity_z(struct MANTA *fluid);
+float *manta_get_ob_velocity_x(struct MANTA *fluid);
+float *manta_get_ob_velocity_y(struct MANTA *fluid);
+float *manta_get_ob_velocity_z(struct MANTA *fluid);
+float *manta_get_guide_velocity_x(struct MANTA *fluid);
+float *manta_get_guide_velocity_y(struct MANTA *fluid);
+float *manta_get_guide_velocity_z(struct MANTA *fluid);
+float *manta_get_in_velocity_x(struct MANTA *fluid);
+float *manta_get_in_velocity_y(struct MANTA *fluid);
+float *manta_get_in_velocity_z(struct MANTA *fluid);
+float *manta_get_force_x(struct MANTA *fluid);
+float *manta_get_force_y(struct MANTA *fluid);
+float *manta_get_force_z(struct MANTA *fluid);
+float *manta_get_phiguide_in(struct MANTA *fluid);
+int *manta_get_num_obstacle(struct MANTA *fluid);
+int *manta_get_num_guide(struct MANTA *fluid);
+int manta_get_res_x(struct MANTA *fluid);
+int manta_get_res_y(struct MANTA *fluid);
+int manta_get_res_z(struct MANTA *fluid);
+float *manta_get_phi_in(struct MANTA *fluid);
+float *manta_get_phiobs_in(struct MANTA *fluid);
+float *manta_get_phiout_in(struct MANTA *fluid);
+
+/* Smoke functions */
+void manta_smoke_export_script(struct MANTA *smoke, struct FluidModifierData *mmd);
+void manta_smoke_export(struct MANTA *smoke,
+ float *dt,
+ float *dx,
+ float **dens,
+ float **react,
+ float **flame,
+ float **fuel,
+ float **heat,
+ float **vx,
+ float **vy,
+ float **vz,
+ float **r,
+ float **g,
+ float **b,
+ int **obstacles,
+ float **shadow);
+void manta_smoke_turbulence_export(struct MANTA *smoke,
+ float **dens,
+ float **react,
+ float **flame,
+ float **fuel,
+ float **r,
+ float **g,
+ float **b,
+ float **tcu,
+ float **tcv,
+ float **tcw,
+ float **tcu2,
+ float **tcv2,
+ float **tcw2);
+void manta_smoke_get_rgba(struct MANTA *smoke, float *data, int sequential);
+void manta_smoke_turbulence_get_rgba(struct MANTA *smoke, float *data, int sequential);
+void manta_smoke_get_rgba_from_density(struct MANTA *smoke,
+ float color[3],
+ float *data,
+ int sequential);
+void manta_smoke_turbulence_get_rgba_from_density(struct MANTA *smoke,
+ float color[3],
+ float *data,
+ int sequential);
+void manta_smoke_ensure_heat(struct MANTA *smoke, struct FluidModifierData *mmd);
+void manta_smoke_ensure_fire(struct MANTA *smoke, struct FluidModifierData *mmd);
+void manta_smoke_ensure_colors(struct MANTA *smoke, struct FluidModifierData *mmd);
+
+/* Smoke accessors */
+float *manta_smoke_get_density(struct MANTA *smoke);
+float *manta_smoke_get_fuel(struct MANTA *smoke);
+float *manta_smoke_get_react(struct MANTA *smoke);
+float *manta_smoke_get_heat(struct MANTA *smoke);
+float *manta_smoke_get_flame(struct MANTA *smoke);
+float *manta_smoke_get_shadow(struct MANTA *fluid);
+float *manta_smoke_get_color_r(struct MANTA *smoke);
+float *manta_smoke_get_color_g(struct MANTA *smoke);
+float *manta_smoke_get_color_b(struct MANTA *smoke);
+int *manta_smoke_get_obstacle(struct MANTA *smoke);
+float *manta_smoke_get_density_in(struct MANTA *smoke);
+float *manta_smoke_get_heat_in(struct MANTA *smoke);
+float *manta_smoke_get_color_r_in(struct MANTA *smoke);
+float *manta_smoke_get_color_g_in(struct MANTA *smoke);
+float *manta_smoke_get_color_b_in(struct MANTA *smoke);
+float *manta_smoke_get_fuel_in(struct MANTA *smoke);
+float *manta_smoke_get_react_in(struct MANTA *smoke);
+float *manta_smoke_get_emission_in(struct MANTA *smoke);
+int manta_smoke_has_heat(struct MANTA *smoke);
+int manta_smoke_has_fuel(struct MANTA *smoke);
+int manta_smoke_has_colors(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_density(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_fuel(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_react(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_color_r(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_color_g(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_color_b(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_flame(struct MANTA *smoke);
+int manta_smoke_turbulence_has_fuel(struct MANTA *smoke);
+int manta_smoke_turbulence_has_colors(struct MANTA *smoke);
+void manta_smoke_turbulence_get_res(struct MANTA *smoke, int *res);
+int manta_smoke_turbulence_get_cells(struct MANTA *smoke);
+
+/* Liquid functions */
+void manta_liquid_export_script(struct MANTA *smoke, struct FluidModifierData *mmd);
+void manta_liquid_ensure_sndparts(struct MANTA *fluid, struct FluidModifierData *mmd);
+
+/* Liquid accessors */
+int manta_liquid_get_particle_res_x(struct MANTA *liquid);
+int manta_liquid_get_particle_res_y(struct MANTA *liquid);
+int manta_liquid_get_particle_res_z(struct MANTA *liquid);
+int manta_liquid_get_mesh_res_x(struct MANTA *liquid);
+int manta_liquid_get_mesh_res_y(struct MANTA *liquid);
+int manta_liquid_get_mesh_res_z(struct MANTA *liquid);
+int manta_liquid_get_particle_upres(struct MANTA *liquid);
+int manta_liquid_get_mesh_upres(struct MANTA *liquid);
+int manta_liquid_get_num_verts(struct MANTA *liquid);
+int manta_liquid_get_num_normals(struct MANTA *liquid);
+int manta_liquid_get_num_triangles(struct MANTA *liquid);
+float manta_liquid_get_vertex_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_vertex_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_vertex_z_at(struct MANTA *liquid, int i);
+float manta_liquid_get_normal_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_normal_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_normal_z_at(struct MANTA *liquid, int i);
+int manta_liquid_get_triangle_x_at(struct MANTA *liquid, int i);
+int manta_liquid_get_triangle_y_at(struct MANTA *liquid, int i);
+int manta_liquid_get_triangle_z_at(struct MANTA *liquid, int i);
+float manta_liquid_get_vertvel_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_vertvel_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_vertvel_z_at(struct MANTA *liquid, int i);
+int manta_liquid_get_num_flip_particles(struct MANTA *liquid);
+int manta_liquid_get_num_snd_particles(struct MANTA *liquid);
+int manta_liquid_get_flip_particle_flag_at(struct MANTA *liquid, int i);
+int manta_liquid_get_snd_particle_flag_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_position_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_position_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_position_z_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_velocity_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_velocity_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_velocity_z_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_position_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_position_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_position_z_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_velocity_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_velocity_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_velocity_z_at(struct MANTA *liquid, int i);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MANTA_API_H_ */
diff --git a/intern/elbeem/extern/LBM_fluidsim.h b/intern/mantaflow/extern/manta_python_API.h
index 256d8c59daa..02d96d2e5f2 100644
--- a/intern/elbeem/extern/LBM_fluidsim.h
+++ b/intern/mantaflow/extern/manta_python_API.h
@@ -13,23 +13,27 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) Blender Foundation.
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*/
/** \file
- * \ingroup elbeem
+ * \ingroup mantaflow
*/
-#ifndef LBM_FLUIDSIM_H
-#define LBM_FLUIDSIM_H
+#ifndef MANTA_PYTHON_API_H
+#define MANTA_PYTHON_API_H
-/* note; elbeem.h was exported all over, should only expose LBM_fluidsim.h */
-#include "elbeem.h"
+#include "Python.h"
-/* run simulation with given config file */
-// implemented in intern/elbeem/blendercall.cpp
-int performElbeemSimulation(char *cfgfilename);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PyObject *Manta_initPython(void);
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp
new file mode 100644
index 00000000000..52d40407e0d
--- /dev/null
+++ b/intern/mantaflow/intern/MANTA_main.cpp
@@ -0,0 +1,2670 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup mantaflow
+ */
+
+#include <sstream>
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+#include <zlib.h>
+
+#include "MANTA_main.h"
+#include "manta.h"
+#include "Python.h"
+#include "fluid_script.h"
+#include "smoke_script.h"
+#include "liquid_script.h"
+
+#include "BLI_path_util.h"
+#include "BLI_utildefines.h"
+#include "BLI_fileops.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_fluid_types.h"
+
+std::atomic<bool> MANTA::mantaInitialized(false);
+std::atomic<int> MANTA::solverID(0);
+int MANTA::with_debug(0);
+
+MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID)
+{
+ if (with_debug)
+ std::cout << "MANTA: " << mCurrentID << " with res(" << res[0] << ", " << res[1] << ", "
+ << res[2] << ")" << std::endl;
+
+ mmd->domain->fluid = this;
+
+ mUsingLiquid = (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID);
+ mUsingSmoke = (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS);
+ mUsingHeat = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) && mUsingSmoke;
+ mUsingFire = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) && mUsingSmoke;
+ mUsingColors = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) && mUsingSmoke;
+ mUsingNoise = (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE) && mUsingSmoke;
+ mUsingFractions = (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid;
+ mUsingDrops = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid;
+ mUsingBubbles = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) && mUsingLiquid;
+ mUsingFloats = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) && mUsingLiquid;
+ mUsingTracers = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) && mUsingLiquid;
+ mUsingMesh = (mmd->domain->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid;
+ mUsingMVel = (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid;
+ mUsingObstacle = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE);
+ mUsingInvel = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL);
+ mUsingOutflow = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW);
+ mUsingGuiding = (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDE);
+
+ // Simulation constants
+ mTempAmb = 0; // TODO: Maybe use this later for buoyancy calculation
+ mResX = res[0];
+ mResY = res[1];
+ mResZ = res[2];
+ mMaxRes = MAX3(mResX, mResY, mResZ);
+ mConstantScaling = 64.0f / mMaxRes;
+ mConstantScaling = (mConstantScaling < 1.0f) ? 1.0f : mConstantScaling;
+ mTotalCells = mResX * mResY * mResZ;
+ mResGuiding = mmd->domain->res;
+
+ // Smoke low res grids
+ mDensity = NULL;
+ mShadow = NULL;
+ mHeat = NULL;
+ mVelocityX = NULL;
+ mVelocityY = NULL;
+ mVelocityZ = NULL;
+ mForceX = NULL;
+ mForceY = NULL;
+ mForceZ = NULL;
+ mFlame = NULL;
+ mFuel = NULL;
+ mReact = NULL;
+ mColorR = NULL;
+ mColorG = NULL;
+ mColorB = NULL;
+ mObstacle = NULL;
+ mDensityIn = NULL;
+ mHeatIn = NULL;
+ mColorRIn = NULL;
+ mColorGIn = NULL;
+ mColorBIn = NULL;
+ mFuelIn = NULL;
+ mReactIn = NULL;
+ mEmissionIn = NULL;
+
+ // Smoke high res grids
+ mDensityHigh = NULL;
+ mFlameHigh = NULL;
+ mFuelHigh = NULL;
+ mReactHigh = NULL;
+ mColorRHigh = NULL;
+ mColorGHigh = NULL;
+ mColorBHigh = NULL;
+ mTextureU = NULL;
+ mTextureV = NULL;
+ mTextureW = NULL;
+ mTextureU2 = NULL;
+ mTextureV2 = NULL;
+ mTextureW2 = NULL;
+
+ // Fluid low res grids
+ mPhiIn = NULL;
+ mPhiOutIn = NULL;
+ mPhi = NULL;
+
+ // Mesh
+ mMeshNodes = NULL;
+ mMeshTriangles = NULL;
+ mMeshVelocities = NULL;
+
+ // Fluid obstacle
+ mPhiObsIn = NULL;
+ mNumObstacle = NULL;
+ mObVelocityX = NULL;
+ mObVelocityY = NULL;
+ mObVelocityZ = NULL;
+
+ // Fluid guiding
+ mPhiGuideIn = NULL;
+ mNumGuide = NULL;
+ mGuideVelocityX = NULL;
+ mGuideVelocityY = NULL;
+ mGuideVelocityZ = NULL;
+
+ // Fluid initial velocity
+ mInVelocityX = NULL;
+ mInVelocityY = NULL;
+ mInVelocityZ = NULL;
+
+ // Secondary particles
+ mFlipParticleData = NULL;
+ mFlipParticleVelocity = NULL;
+ mSndParticleData = NULL;
+ mSndParticleVelocity = NULL;
+ mSndParticleLife = NULL;
+
+ // Only start Mantaflow once. No need to start whenever new FLUID objected is allocated
+ if (!mantaInitialized)
+ initializeMantaflow();
+
+ // Initialize Mantaflow variables in Python
+ // Liquid
+ if (mUsingLiquid) {
+ initDomain(mmd);
+ initLiquid(mmd);
+ if (mUsingObstacle)
+ initObstacle(mmd);
+ if (mUsingInvel)
+ initInVelocity(mmd);
+ if (mUsingOutflow)
+ initOutflow(mmd);
+
+ if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) {
+ mUpresParticle = mmd->domain->particle_scale;
+ mResXParticle = mUpresParticle * mResX;
+ mResYParticle = mUpresParticle * mResY;
+ mResZParticle = mUpresParticle * mResZ;
+ mTotalCellsParticles = mResXParticle * mResYParticle * mResZParticle;
+
+ initSndParts(mmd);
+ initLiquidSndParts(mmd);
+ }
+
+ if (mUsingMesh) {
+ mUpresMesh = mmd->domain->mesh_scale;
+ mResXMesh = mUpresMesh * mResX;
+ mResYMesh = mUpresMesh * mResY;
+ mResZMesh = mUpresMesh * mResZ;
+ mTotalCellsMesh = mResXMesh * mResYMesh * mResZMesh;
+
+ // Initialize Mantaflow variables in Python
+ initMesh(mmd);
+ initLiquidMesh(mmd);
+ }
+
+ if (mUsingGuiding) {
+ mResGuiding = (mmd->domain->guide_parent) ? mmd->domain->guide_res : mmd->domain->res;
+ initGuiding(mmd);
+ }
+ if (mUsingFractions) {
+ initFractions(mmd);
+ }
+ }
+
+ // Smoke
+ if (mUsingSmoke) {
+ initDomain(mmd);
+ initSmoke(mmd);
+ if (mUsingHeat)
+ initHeat(mmd);
+ if (mUsingFire)
+ initFire(mmd);
+ if (mUsingColors)
+ initColors(mmd);
+ if (mUsingObstacle)
+ initObstacle(mmd);
+ if (mUsingInvel)
+ initInVelocity(mmd);
+ if (mUsingOutflow)
+ initOutflow(mmd);
+
+ if (mUsingGuiding) {
+ mResGuiding = (mmd->domain->guide_parent) ? mmd->domain->guide_res : mmd->domain->res;
+ initGuiding(mmd);
+ }
+
+ if (mUsingNoise) {
+ int amplify = mmd->domain->noise_scale;
+ mResXNoise = amplify * mResX;
+ mResYNoise = amplify * mResY;
+ mResZNoise = amplify * mResZ;
+ mTotalCellsHigh = mResXNoise * mResYNoise * mResZNoise;
+
+ // Initialize Mantaflow variables in Python
+ initNoise(mmd);
+ initSmokeNoise(mmd);
+ if (mUsingFire)
+ initFireHigh(mmd);
+ if (mUsingColors)
+ initColorsHigh(mmd);
+ }
+ }
+ updatePointers();
+}
+
+void MANTA::initDomain(FluidModifierData *mmd)
+{
+ // Vector will hold all python commands that are to be executed
+ std::vector<std::string> pythonCommands;
+
+ // Set manta debug level first
+ pythonCommands.push_back(manta_import + manta_debuglevel);
+
+ std::ostringstream ss;
+ ss << "set_manta_debuglevel(" << with_debug << ")";
+ pythonCommands.push_back(ss.str());
+
+ // Now init basic fluid domain
+ std::string tmpString = fluid_variables + fluid_solver + fluid_alloc + fluid_cache_helper +
+ fluid_bake_multiprocessing + fluid_bake_data + fluid_bake_noise +
+ fluid_bake_mesh + fluid_bake_particles + fluid_bake_guiding +
+ fluid_file_import + fluid_file_export + fluid_save_data +
+ fluid_load_data + fluid_pre_step + fluid_post_step +
+ fluid_adapt_time_step + fluid_time_stepping;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+ runPythonString(pythonCommands);
+}
+
+void MANTA::initNoise(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_variables_noise + fluid_solver_noise;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::initSmoke(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_variables + smoke_alloc + smoke_adaptive_step + smoke_save_data +
+ smoke_load_data + smoke_step;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::initSmokeNoise(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_variables_noise + smoke_alloc_noise + smoke_wavelet_noise +
+ smoke_save_noise + smoke_load_noise + smoke_step_noise;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingNoise = true;
+}
+
+void MANTA::initHeat(FluidModifierData *mmd)
+{
+ if (!mHeat) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_alloc_heat + smoke_with_heat;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingHeat = true;
+ }
+}
+
+void MANTA::initFire(FluidModifierData *mmd)
+{
+ if (!mFuel) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_alloc_fire + smoke_with_fire;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingFire = true;
+ }
+}
+
+void MANTA::initFireHigh(FluidModifierData *mmd)
+{
+ if (!mFuelHigh) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_alloc_fire_noise + smoke_with_fire;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingFire = true;
+ }
+}
+
+void MANTA::initColors(FluidModifierData *mmd)
+{
+ if (!mColorR) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_alloc_colors + smoke_init_colors + smoke_with_colors;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingColors = true;
+ }
+}
+
+void MANTA::initColorsHigh(FluidModifierData *mmd)
+{
+ if (!mColorRHigh) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_alloc_colors_noise + smoke_init_colors_noise + smoke_with_colors;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingColors = true;
+ }
+}
+
+void MANTA::initLiquid(FluidModifierData *mmd)
+{
+ if (!mPhiIn) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = liquid_variables + liquid_alloc + liquid_init_phi + liquid_save_data +
+ liquid_save_flip + liquid_load_data + liquid_load_flip +
+ liquid_adaptive_step + liquid_step;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingLiquid = true;
+ }
+}
+
+void MANTA::initMesh(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_variables_mesh + fluid_solver_mesh + liquid_load_mesh +
+ liquid_load_meshvel;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingMesh = true;
+}
+
+void MANTA::initLiquidMesh(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = liquid_alloc_mesh + liquid_step_mesh + liquid_save_mesh +
+ liquid_save_meshvel;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingMesh = true;
+}
+
+void MANTA::initObstacle(FluidModifierData *mmd)
+{
+ if (!mPhiObsIn) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_alloc_obstacle + fluid_with_obstacle;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingObstacle = true;
+ }
+}
+
+void MANTA::initGuiding(FluidModifierData *mmd)
+{
+ if (!mPhiGuideIn) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_variables_guiding + fluid_solver_guiding + fluid_alloc_guiding +
+ fluid_save_guiding + fluid_load_vel + fluid_load_guiding;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingGuiding = true;
+ }
+}
+
+void MANTA::initFractions(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_alloc_fractions + fluid_with_fractions;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingFractions = true;
+}
+
+void MANTA::initInVelocity(FluidModifierData *mmd)
+{
+ if (!mInVelocityX) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_alloc_invel + fluid_with_invel;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingInvel = true;
+ }
+}
+
+void MANTA::initOutflow(FluidModifierData *mmd)
+{
+ if (!mPhiOutIn) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_alloc_outflow + fluid_with_outflow;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingOutflow = true;
+ }
+}
+
+void MANTA::initSndParts(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_variables_particles + fluid_solver_particles +
+ fluid_load_particles + fluid_save_particles;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::initLiquidSndParts(FluidModifierData *mmd)
+{
+ if (!mSndParticleData) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_alloc_sndparts + liquid_alloc_particles +
+ liquid_variables_particles + liquid_step_particles +
+ fluid_with_sndparts + liquid_load_particles + liquid_save_particles;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ }
+}
+
+MANTA::~MANTA()
+{
+ if (with_debug)
+ std::cout << "~FLUID: " << mCurrentID << " with res(" << mResX << ", " << mResY << ", "
+ << mResZ << ")" << std::endl;
+
+ // Destruction string for Python
+ std::string tmpString = "";
+ std::vector<std::string> pythonCommands;
+
+ tmpString += manta_import;
+ tmpString += fluid_delete_all;
+
+ // Leave out mmd argument in parseScript since only looking up IDs
+ std::string finalString = parseScript(tmpString);
+ pythonCommands.push_back(finalString);
+ runPythonString(pythonCommands);
+}
+
+void MANTA::runPythonString(std::vector<std::string> commands)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ for (std::vector<std::string>::iterator it = commands.begin(); it != commands.end(); ++it) {
+ std::string command = *it;
+
+#ifdef WIN32
+ // special treatment for windows when running python code
+ size_t cmdLength = command.length();
+ char *buffer = new char[cmdLength + 1];
+ memcpy(buffer, command.data(), cmdLength);
+
+ buffer[cmdLength] = '\0';
+ PyRun_SimpleString(buffer);
+ delete[] buffer;
+#else
+ PyRun_SimpleString(command.c_str());
+#endif
+ }
+ PyGILState_Release(gilstate);
+}
+
+void MANTA::initializeMantaflow()
+{
+ if (with_debug)
+ std::cout << "Initializing Mantaflow" << std::endl;
+
+ std::string filename = "manta_scene_" + std::to_string(mCurrentID) + ".py";
+ std::vector<std::string> fill = std::vector<std::string>();
+
+ // Initialize extension classes and wrappers
+ srand(0);
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ Pb::setup(filename, fill); // Namespace from Mantaflow (registry)
+ PyGILState_Release(gilstate);
+ mantaInitialized = true;
+}
+
+void MANTA::terminateMantaflow()
+{
+ if (with_debug)
+ std::cout << "Terminating Mantaflow" << std::endl;
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ Pb::finalize(); // Namespace from Mantaflow (registry)
+ PyGILState_Release(gilstate);
+ mantaInitialized = false;
+}
+
+std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *mmd)
+{
+ std::ostringstream ss;
+ bool is2D = false;
+ int tmpVar;
+ float tmpFloat;
+
+ if (varName == "ID") {
+ ss << mCurrentID;
+ return ss.str();
+ }
+
+ if (!mmd) {
+ if (with_debug)
+ std::cout << "Invalid modifier data in getRealValue()" << std::endl;
+ ss << "ERROR - INVALID MODIFIER DATA";
+ return ss.str();
+ }
+
+ is2D = (mmd->domain->solver_res == 2);
+
+ if (varName == "USING_SMOKE")
+ ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) ? "True" : "False");
+ else if (varName == "USING_LIQUID")
+ ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) ? "True" : "False");
+ else if (varName == "USING_COLORS")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS ? "True" : "False");
+ else if (varName == "USING_HEAT")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT ? "True" : "False");
+ else if (varName == "USING_FIRE")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE ? "True" : "False");
+ else if (varName == "USING_NOISE")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE ? "True" : "False");
+ else if (varName == "USING_OBSTACLE")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE ? "True" : "False");
+ else if (varName == "USING_GUIDING")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDE ? "True" : "False");
+ else if (varName == "USING_INVEL")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL ? "True" : "False");
+ else if (varName == "USING_OUTFLOW")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW ? "True" : "False");
+ else if (varName == "USING_LOG_DISSOLVE")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG ? "True" : "False");
+ else if (varName == "USING_DISSOLVE")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE ? "True" : "False");
+ else if (varName == "SOLVER_DIM")
+ ss << mmd->domain->solver_res;
+ else if (varName == "DO_OPEN") {
+ tmpVar = (FLUID_DOMAIN_BORDER_BACK | FLUID_DOMAIN_BORDER_FRONT | FLUID_DOMAIN_BORDER_LEFT |
+ FLUID_DOMAIN_BORDER_RIGHT | FLUID_DOMAIN_BORDER_BOTTOM | FLUID_DOMAIN_BORDER_TOP);
+ ss << (((mmd->domain->border_collisions & tmpVar) == tmpVar) ? "False" : "True");
+ }
+ else if (varName == "BOUND_CONDITIONS") {
+ if (mmd->domain->solver_res == 2) {
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0)
+ ss << "x";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0)
+ ss << "X";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0)
+ ss << "y";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0)
+ ss << "Y";
+ }
+ if (mmd->domain->solver_res == 3) {
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0)
+ ss << "x";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0)
+ ss << "X";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0)
+ ss << "y";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0)
+ ss << "Y";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BOTTOM) == 0)
+ ss << "z";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_TOP) == 0)
+ ss << "Z";
+ }
+ }
+ else if (varName == "BOUNDARY_WIDTH")
+ ss << mmd->domain->boundary_width;
+ else if (varName == "RES")
+ ss << mMaxRes;
+ else if (varName == "RESX")
+ ss << mResX;
+ else if (varName == "RESY")
+ if (is2D) {
+ ss << mResZ;
+ }
+ else {
+ ss << mResY;
+ }
+ else if (varName == "RESZ") {
+ if (is2D) {
+ ss << 1;
+ }
+ else {
+ ss << mResZ;
+ }
+ }
+ else if (varName == "FRAME_LENGTH")
+ ss << mmd->domain->frame_length;
+ else if (varName == "CFL")
+ ss << mmd->domain->cfl_condition;
+ else if (varName == "DT")
+ ss << mmd->domain->dt;
+ else if (varName == "TIMESTEPS_MIN")
+ ss << mmd->domain->timesteps_minimum;
+ else if (varName == "TIMESTEPS_MAX")
+ ss << mmd->domain->timesteps_maximum;
+ else if (varName == "TIME_TOTAL")
+ ss << mmd->domain->time_total;
+ else if (varName == "TIME_PER_FRAME")
+ ss << mmd->domain->time_per_frame;
+ else if (varName == "VORTICITY")
+ ss << mmd->domain->vorticity / mConstantScaling;
+ else if (varName == "FLAME_VORTICITY")
+ ss << mmd->domain->flame_vorticity / mConstantScaling;
+ else if (varName == "NOISE_SCALE")
+ ss << mmd->domain->noise_scale;
+ else if (varName == "MESH_SCALE")
+ ss << mmd->domain->mesh_scale;
+ else if (varName == "PARTICLE_SCALE")
+ ss << mmd->domain->particle_scale;
+ else if (varName == "NOISE_RESX")
+ ss << mResXNoise;
+ else if (varName == "NOISE_RESY") {
+ if (is2D) {
+ ss << mResZNoise;
+ }
+ else {
+ ss << mResYNoise;
+ }
+ }
+ else if (varName == "NOISE_RESZ") {
+ if (is2D) {
+ ss << 1;
+ }
+ else {
+ ss << mResZNoise;
+ }
+ }
+ else if (varName == "MESH_RESX")
+ ss << mResXMesh;
+ else if (varName == "MESH_RESY") {
+ if (is2D) {
+ ss << mResZMesh;
+ }
+ else {
+ ss << mResYMesh;
+ }
+ }
+ else if (varName == "MESH_RESZ") {
+ if (is2D) {
+ ss << 1;
+ }
+ else {
+ ss << mResZMesh;
+ }
+ }
+ else if (varName == "PARTICLE_RESX")
+ ss << mResXParticle;
+ else if (varName == "PARTICLE_RESY") {
+ if (is2D) {
+ ss << mResZParticle;
+ }
+ else {
+ ss << mResYParticle;
+ }
+ }
+ else if (varName == "PARTICLE_RESZ") {
+ if (is2D) {
+ ss << 1;
+ }
+ else {
+ ss << mResZParticle;
+ }
+ }
+ else if (varName == "GUIDING_RESX")
+ ss << mResGuiding[0];
+ else if (varName == "GUIDING_RESY") {
+ if (is2D) {
+ ss << mResGuiding[2];
+ }
+ else {
+ ss << mResGuiding[1];
+ }
+ }
+ else if (varName == "GUIDING_RESZ") {
+ if (is2D) {
+ ss << 1;
+ }
+ else {
+ ss << mResGuiding[2];
+ }
+ }
+ else if (varName == "MIN_RESX")
+ ss << mmd->domain->res_min[0];
+ else if (varName == "MIN_RESY")
+ ss << mmd->domain->res_min[1];
+ else if (varName == "MIN_RESZ")
+ ss << mmd->domain->res_min[2];
+ else if (varName == "BASE_RESX")
+ ss << mmd->domain->base_res[0];
+ else if (varName == "BASE_RESY")
+ ss << mmd->domain->base_res[1];
+ else if (varName == "BASE_RESZ")
+ ss << mmd->domain->base_res[2];
+ else if (varName == "WLT_STR")
+ ss << mmd->domain->noise_strength;
+ else if (varName == "NOISE_POSSCALE")
+ ss << mmd->domain->noise_pos_scale;
+ else if (varName == "NOISE_TIMEANIM")
+ ss << mmd->domain->noise_time_anim;
+ else if (varName == "COLOR_R")
+ ss << mmd->domain->active_color[0];
+ else if (varName == "COLOR_G")
+ ss << mmd->domain->active_color[1];
+ else if (varName == "COLOR_B")
+ ss << mmd->domain->active_color[2];
+ else if (varName == "BUOYANCY_ALPHA")
+ ss << mmd->domain->alpha;
+ else if (varName == "BUOYANCY_BETA")
+ ss << mmd->domain->beta;
+ else if (varName == "DISSOLVE_SPEED")
+ ss << mmd->domain->diss_speed;
+ else if (varName == "BURNING_RATE")
+ ss << mmd->domain->burning_rate;
+ else if (varName == "FLAME_SMOKE")
+ ss << mmd->domain->flame_smoke;
+ else if (varName == "IGNITION_TEMP")
+ ss << mmd->domain->flame_ignition;
+ else if (varName == "MAX_TEMP")
+ ss << mmd->domain->flame_max_temp;
+ else if (varName == "FLAME_SMOKE_COLOR_X")
+ ss << mmd->domain->flame_smoke_color[0];
+ else if (varName == "FLAME_SMOKE_COLOR_Y")
+ ss << mmd->domain->flame_smoke_color[1];
+ else if (varName == "FLAME_SMOKE_COLOR_Z")
+ ss << mmd->domain->flame_smoke_color[2];
+ else if (varName == "CURRENT_FRAME")
+ ss << mmd->time;
+ else if (varName == "END_FRAME")
+ ss << mmd->domain->cache_frame_end;
+ else if (varName == "SIMULATION_METHOD") {
+ if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_FLIP) {
+ ss << "'FLIP'";
+ }
+ else if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_APIC) {
+ ss << "'APIC'";
+ }
+ else {
+ ss << "'NONE'";
+ }
+ }
+ else if (varName == "FLIP_RATIO")
+ ss << mmd->domain->flip_ratio;
+ else if (varName == "PARTICLE_RANDOMNESS")
+ ss << mmd->domain->particle_randomness;
+ else if (varName == "PARTICLE_NUMBER")
+ ss << mmd->domain->particle_number;
+ else if (varName == "PARTICLE_MINIMUM")
+ ss << mmd->domain->particle_minimum;
+ else if (varName == "PARTICLE_MAXIMUM")
+ ss << mmd->domain->particle_maximum;
+ else if (varName == "PARTICLE_RADIUS")
+ ss << mmd->domain->particle_radius;
+ else if (varName == "FRACTIONS_THRESHOLD")
+ ss << mmd->domain->fractions_threshold;
+ else if (varName == "MESH_CONCAVE_UPPER")
+ ss << mmd->domain->mesh_concave_upper;
+ else if (varName == "MESH_CONCAVE_LOWER")
+ ss << mmd->domain->mesh_concave_lower;
+ else if (varName == "MESH_PARTICLE_RADIUS")
+ ss << mmd->domain->mesh_particle_radius;
+ else if (varName == "MESH_SMOOTHEN_POS")
+ ss << mmd->domain->mesh_smoothen_pos;
+ else if (varName == "MESH_SMOOTHEN_NEG")
+ ss << mmd->domain->mesh_smoothen_neg;
+ else if (varName == "USING_MESH")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_MESH ? "True" : "False");
+ else if (varName == "USING_IMPROVED_MESH")
+ ss << (mmd->domain->mesh_generator == FLUID_DOMAIN_MESH_IMPROVED ? "True" : "False");
+ else if (varName == "PARTICLE_BAND_WIDTH")
+ ss << mmd->domain->particle_band_width;
+ else if (varName == "SNDPARTICLE_TAU_MIN_WC")
+ ss << mmd->domain->sndparticle_tau_min_wc;
+ else if (varName == "SNDPARTICLE_TAU_MAX_WC")
+ ss << mmd->domain->sndparticle_tau_max_wc;
+ else if (varName == "SNDPARTICLE_TAU_MIN_TA")
+ ss << mmd->domain->sndparticle_tau_min_ta;
+ else if (varName == "SNDPARTICLE_TAU_MAX_TA")
+ ss << mmd->domain->sndparticle_tau_max_ta;
+ else if (varName == "SNDPARTICLE_TAU_MIN_K")
+ ss << mmd->domain->sndparticle_tau_min_k;
+ else if (varName == "SNDPARTICLE_TAU_MAX_K")
+ ss << mmd->domain->sndparticle_tau_max_k;
+ else if (varName == "SNDPARTICLE_K_WC")
+ ss << mmd->domain->sndparticle_k_wc;
+ else if (varName == "SNDPARTICLE_K_TA")
+ ss << mmd->domain->sndparticle_k_ta;
+ else if (varName == "SNDPARTICLE_K_B")
+ ss << mmd->domain->sndparticle_k_b;
+ else if (varName == "SNDPARTICLE_K_D")
+ ss << mmd->domain->sndparticle_k_d;
+ else if (varName == "SNDPARTICLE_L_MIN")
+ ss << mmd->domain->sndparticle_l_min;
+ else if (varName == "SNDPARTICLE_L_MAX")
+ ss << mmd->domain->sndparticle_l_max;
+ else if (varName == "SNDPARTICLE_BOUNDARY_DELETE")
+ ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_DELETE);
+ else if (varName == "SNDPARTICLE_BOUNDARY_PUSHOUT")
+ ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_PUSHOUT);
+ else if (varName == "SNDPARTICLE_POTENTIAL_RADIUS")
+ ss << mmd->domain->sndparticle_potential_radius;
+ else if (varName == "SNDPARTICLE_UPDATE_RADIUS")
+ ss << mmd->domain->sndparticle_update_radius;
+ else if (varName == "LIQUID_SURFACE_TENSION")
+ ss << mmd->domain->surface_tension;
+ else if (varName == "FLUID_VISCOSITY")
+ ss << mmd->domain->viscosity_base * pow(10.0f, -mmd->domain->viscosity_exponent);
+ else if (varName == "FLUID_DOMAIN_SIZE") {
+ tmpFloat = MAX3(
+ mmd->domain->global_size[0], mmd->domain->global_size[1], mmd->domain->global_size[2]);
+ ss << tmpFloat;
+ }
+ else if (varName == "SNDPARTICLE_TYPES") {
+ if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) {
+ ss << "PtypeSpray";
+ }
+ if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) {
+ if (!ss.str().empty())
+ ss << "|";
+ ss << "PtypeBubble";
+ }
+ if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) {
+ if (!ss.str().empty())
+ ss << "|";
+ ss << "PtypeFoam";
+ }
+ if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) {
+ if (!ss.str().empty())
+ ss << "|";
+ ss << "PtypeTracer";
+ }
+ if (ss.str().empty())
+ ss << "0";
+ }
+ else if (varName == "USING_SNDPARTS") {
+ tmpVar = (FLUID_DOMAIN_PARTICLE_SPRAY | FLUID_DOMAIN_PARTICLE_BUBBLE |
+ FLUID_DOMAIN_PARTICLE_FOAM | FLUID_DOMAIN_PARTICLE_TRACER);
+ ss << (((mmd->domain->particle_type & tmpVar)) ? "True" : "False");
+ }
+ else if (varName == "GUIDING_ALPHA")
+ ss << mmd->domain->guide_alpha;
+ else if (varName == "GUIDING_BETA")
+ ss << mmd->domain->guide_beta;
+ else if (varName == "GUIDING_FACTOR")
+ ss << mmd->domain->guide_vel_factor;
+ else if (varName == "GRAVITY_X")
+ ss << mmd->domain->gravity[0];
+ else if (varName == "GRAVITY_Y")
+ ss << mmd->domain->gravity[1];
+ else if (varName == "GRAVITY_Z")
+ ss << mmd->domain->gravity[2];
+ else if (varName == "CACHE_DIR")
+ ss << mmd->domain->cache_directory;
+ else if (varName == "USING_ADAPTIVETIME")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME ? "True" : "False");
+ else if (varName == "USING_SPEEDVECTORS")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS ? "True" : "False");
+ else if (varName == "USING_FRACTIONS")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS ? "True" : "False");
+ else
+ std::cout << "ERROR: Unknown option: " << varName << std::endl;
+ return ss.str();
+}
+
+std::string MANTA::parseLine(const std::string &line, FluidModifierData *mmd)
+{
+ if (line.size() == 0)
+ return "";
+ std::string res = "";
+ int currPos = 0, start_del = 0, end_del = -1;
+ bool readingVar = false;
+ const char delimiter = '$';
+ while (currPos < line.size()) {
+ if (line[currPos] == delimiter && !readingVar) {
+ readingVar = true;
+ start_del = currPos + 1;
+ res += line.substr(end_del + 1, currPos - end_del - 1);
+ }
+ else if (line[currPos] == delimiter && readingVar) {
+ readingVar = false;
+ end_del = currPos;
+ res += getRealValue(line.substr(start_del, currPos - start_del), mmd);
+ }
+ currPos++;
+ }
+ res += line.substr(end_del + 1, line.size() - end_del);
+ return res;
+}
+
+std::string MANTA::parseScript(const std::string &setup_string, FluidModifierData *mmd)
+{
+ std::istringstream f(setup_string);
+ std::ostringstream res;
+ std::string line = "";
+ while (getline(f, line)) {
+ res << parseLine(line, mmd) << "\n";
+ }
+ return res.str();
+}
+
+static std::string getCacheFileEnding(char cache_format)
+{
+ if (MANTA::with_debug)
+ std::cout << "MANTA::getCacheFileEnding()" << std::endl;
+
+ switch (cache_format) {
+ case FLUID_DOMAIN_FILE_UNI:
+ return ".uni";
+ case FLUID_DOMAIN_FILE_OPENVDB:
+ return ".vdb";
+ case FLUID_DOMAIN_FILE_RAW:
+ return ".raw";
+ case FLUID_DOMAIN_FILE_BIN_OBJECT:
+ return ".bobj.gz";
+ case FLUID_DOMAIN_FILE_OBJECT:
+ return ".obj";
+ default:
+ if (MANTA::with_debug)
+ std::cout << "Error: Could not find file extension" << std::endl;
+ return ".uni";
+ }
+}
+
+int MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr)
+{
+ if (MANTA::with_debug)
+ std::cout << "MANTA::updateFlipStructures()" << std::endl;
+
+ // Ensure empty data structures at start
+ if (mFlipParticleData)
+ mFlipParticleData->clear();
+ if (mFlipParticleVelocity)
+ mFlipParticleVelocity->clear();
+
+ if (!mUsingLiquid)
+ return 0;
+ if (BLI_path_is_rel(mmd->domain->cache_directory))
+ return 0;
+
+ std::ostringstream ss;
+ char cacheDir[FILE_MAX], targetFile[FILE_MAX];
+ cacheDir[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+
+ // TODO (sebbas): Use pp_xl and pVel_xl when using upres simulation?
+
+ ss << "pp_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateParticlesFromFile(targetFile, false, false);
+ }
+
+ ss.str("");
+ ss << "pVel_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateParticlesFromFile(targetFile, false, true);
+ }
+ return 1;
+}
+
+int MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr)
+{
+ if (MANTA::with_debug)
+ std::cout << "MANTA::updateMeshStructures()" << std::endl;
+
+ if (!mUsingMesh)
+ return 0;
+ if (BLI_path_is_rel(mmd->domain->cache_directory))
+ return 0;
+
+ // Ensure empty data structures at start
+ if (mMeshNodes)
+ mMeshNodes->clear();
+ if (mMeshTriangles)
+ mMeshTriangles->clear();
+ if (mMeshVelocities)
+ mMeshVelocities->clear();
+
+ std::ostringstream ss;
+ char cacheDir[FILE_MAX], targetFile[FILE_MAX];
+ cacheDir[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format);
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+
+ ss << "lMesh_####" << mformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateMeshFromFile(targetFile);
+ }
+
+ if (mUsingMVel) {
+ ss.str("");
+ ss << "lVelMesh_####" << dformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateMeshFromFile(targetFile);
+ }
+ }
+ return 1;
+}
+
+int MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr)
+{
+ if (MANTA::with_debug)
+ std::cout << "MANTA::updateParticleStructures()" << std::endl;
+
+ if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers)
+ return 0;
+ if (BLI_path_is_rel(mmd->domain->cache_directory))
+ return 0;
+
+ // Ensure empty data structures at start
+ if (mSndParticleData)
+ mSndParticleData->clear();
+ if (mSndParticleVelocity)
+ mSndParticleVelocity->clear();
+ if (mSndParticleLife)
+ mSndParticleLife->clear();
+
+ std::ostringstream ss;
+ char cacheDir[FILE_MAX], targetFile[FILE_MAX];
+ cacheDir[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+
+ ss << "ppSnd_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateParticlesFromFile(targetFile, true, false);
+ }
+
+ ss.str("");
+ ss << "pVelSnd_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateParticlesFromFile(targetFile, true, true);
+ }
+
+ ss.str("");
+ ss << "pLifeSnd_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateParticlesFromFile(targetFile, true, false);
+ }
+ return 1;
+}
+
+/* Dirty hack: Needed to format paths from python code that is run via PyRun_SimpleString */
+static std::string escapeSlashes(std::string const &s)
+{
+ std::string result = "";
+ for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i) {
+ unsigned char c = *i;
+ if (c == '\\')
+ result += "\\\\";
+ else
+ result += c;
+ }
+ return result;
+}
+
+int MANTA::writeConfiguration(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::writeConfiguration()" << std::endl;
+
+ FluidDomainSettings *mds = mmd->domain;
+ std::ostringstream ss;
+ char cacheDir[FILE_MAX], targetFile[FILE_MAX];
+ ;
+ cacheDir[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_make_safe(cacheDir);
+ BLI_dir_create_recursive(cacheDir); /* Create 'config' subdir if it does not exist already */
+
+ ss.str("");
+ ss << "config_####" << dformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ gzFile gzf = gzopen(targetFile, "wb1"); // do some compression
+ if (!gzf)
+ std::cerr << "writeConfiguration: can't open file: " << targetFile << std::endl;
+
+ gzwrite(gzf, &mds->active_fields, sizeof(int));
+ gzwrite(gzf, &mds->res, 3 * sizeof(int));
+ gzwrite(gzf, &mds->dx, sizeof(float));
+ gzwrite(gzf, &mds->dt, sizeof(float));
+ gzwrite(gzf, &mds->p0, 3 * sizeof(float));
+ gzwrite(gzf, &mds->p1, 3 * sizeof(float));
+ gzwrite(gzf, &mds->dp0, 3 * sizeof(float));
+ gzwrite(gzf, &mds->shift, 3 * sizeof(int));
+ gzwrite(gzf, &mds->obj_shift_f, 3 * sizeof(float));
+ gzwrite(gzf, &mds->obmat, 16 * sizeof(float));
+ gzwrite(gzf, &mds->base_res, 3 * sizeof(int));
+ gzwrite(gzf, &mds->res_min, 3 * sizeof(int));
+ gzwrite(gzf, &mds->res_max, 3 * sizeof(int));
+ gzwrite(gzf, &mds->active_color, 3 * sizeof(float));
+
+ gzclose(gzf);
+
+ return 1;
+}
+
+int MANTA::writeData(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::writeData()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX];
+ cacheDirData[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+
+ ss.str("");
+ ss << "fluid_save_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " << framenr
+ << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ if (mUsingSmoke) {
+ ss.str("");
+ ss << "smoke_save_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ if (mUsingLiquid) {
+ ss.str("");
+ ss << "liquid_save_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ ss.str("");
+ ss << "liquid_save_flip_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::readConfiguration(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readConfiguration()" << std::endl;
+
+ FluidDomainSettings *mds = mmd->domain;
+ std::ostringstream ss;
+ char cacheDir[FILE_MAX], targetFile[FILE_MAX];
+ cacheDir[0] = '\0';
+ targetFile[0] = '\0';
+ float dummy;
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_make_safe(cacheDir);
+
+ ss.str("");
+ ss << "config_####" << dformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ gzFile gzf = gzopen(targetFile, "rb"); // do some compression
+ if (!gzf)
+ std::cerr << "readConfiguration: can't open file: " << targetFile << std::endl;
+
+ gzread(gzf, &mds->active_fields, sizeof(int));
+ gzread(gzf, &mds->res, 3 * sizeof(int));
+ gzread(gzf, &mds->dx, sizeof(float));
+ gzread(gzf, &dummy, sizeof(float)); // dt not needed right now
+ gzread(gzf, &mds->p0, 3 * sizeof(float));
+ gzread(gzf, &mds->p1, 3 * sizeof(float));
+ gzread(gzf, &mds->dp0, 3 * sizeof(float));
+ gzread(gzf, &mds->shift, 3 * sizeof(int));
+ gzread(gzf, &mds->obj_shift_f, 3 * sizeof(float));
+ gzread(gzf, &mds->obmat, 16 * sizeof(float));
+ gzread(gzf, &mds->base_res, 3 * sizeof(int));
+ gzread(gzf, &mds->res_min, 3 * sizeof(int));
+ gzread(gzf, &mds->res_max, 3 * sizeof(int));
+ gzread(gzf, &mds->active_color, 3 * sizeof(float));
+ mds->total_cells = mds->res[0] * mds->res[1] * mds->res[2];
+
+ gzclose(gzf);
+ return 1;
+}
+
+int MANTA::readData(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readData()" << std::endl;
+
+ if (!mUsingSmoke && !mUsingLiquid)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX], targetFile[FILE_MAX];
+ cacheDirData[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+
+ if (mUsingSmoke) {
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "density_####" << dformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirData, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ ss.str("");
+ ss << "fluid_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ ss.str("");
+ ss << "smoke_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ if (mUsingLiquid) {
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "phiIn_####" << dformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirData, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ ss.str("");
+ ss << "fluid_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ ss.str("");
+ ss << "liquid_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ ss.str("");
+ ss << "liquid_load_flip_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::readNoise(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readNoise()" << std::endl;
+
+ if (!mUsingNoise)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirNoise[FILE_MAX], targetFile[FILE_MAX];
+ cacheDirNoise[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format);
+
+ BLI_path_join(cacheDirNoise,
+ sizeof(cacheDirNoise),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_NOISE,
+ NULL);
+ BLI_path_make_safe(cacheDirNoise);
+
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "density_noise_####" << nformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirNoise, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ if (mUsingSmoke && mUsingNoise) {
+ ss.str("");
+ ss << "smoke_load_noise_" << mCurrentID << "('" << escapeSlashes(cacheDirNoise) << "', "
+ << framenr << ", '" << nformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::readMesh(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readMesh()" << std::endl;
+
+ if (!mUsingMesh)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirMesh[FILE_MAX], targetFile[FILE_MAX];
+ cacheDirMesh[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format);
+
+ BLI_path_join(cacheDirMesh,
+ sizeof(cacheDirMesh),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_MESH,
+ NULL);
+ BLI_path_make_safe(cacheDirMesh);
+
+ if (mUsingLiquid) {
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "lMesh_####" << mformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirMesh, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ ss.str("");
+ ss << "liquid_load_mesh_" << mCurrentID << "('" << escapeSlashes(cacheDirMesh) << "', "
+ << framenr << ", '" << mformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ if (mUsingMVel) {
+ ss.str("");
+ ss << "liquid_load_meshvel_" << mCurrentID << "('" << escapeSlashes(cacheDirMesh) << "', "
+ << framenr << ", '" << mformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ }
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::readParticles(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readParticles()" << std::endl;
+
+ if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirParticles[FILE_MAX], targetFile[FILE_MAX];
+ cacheDirParticles[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+
+ BLI_path_join(cacheDirParticles,
+ sizeof(cacheDirParticles),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_PARTICLES,
+ NULL);
+ BLI_path_make_safe(cacheDirParticles);
+
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "ppSnd_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirParticles, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) {
+ ss.str("");
+ ss << "fluid_load_particles_" << mCurrentID << "('" << escapeSlashes(cacheDirParticles)
+ << "', " << framenr << ", '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+ ss.str("");
+ ss << "liquid_load_particles_" << mCurrentID << "('" << escapeSlashes(cacheDirParticles)
+ << "', " << framenr << ", '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain)
+{
+ if (with_debug)
+ std::cout << "MANTA::readGuiding()" << std::endl;
+
+ if (!mUsingGuiding)
+ return 0;
+ if (!mmd->domain)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirGuiding[FILE_MAX], targetFile[FILE_MAX];
+ cacheDirGuiding[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string gformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ const char *subdir = (sourceDomain) ? FLUID_DOMAIN_DIR_DATA : FLUID_DOMAIN_DIR_GUIDE;
+
+ BLI_path_join(
+ cacheDirGuiding, sizeof(cacheDirGuiding), mmd->domain->cache_directory, subdir, NULL);
+ BLI_path_make_safe(cacheDirGuiding);
+
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "guidevel_####" << gformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirGuiding, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ if (sourceDomain) {
+ ss.str("");
+ ss << "fluid_load_vel_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', "
+ << framenr << ", '" << gformat << "')";
+ }
+ else {
+ ss.str("");
+ ss << "fluid_load_guiding_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', "
+ << framenr << ", '" << gformat << "')";
+ }
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeData(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeData()" << std::endl;
+
+ std::string tmpString, finalString;
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX], cacheDirGuiding[FILE_MAX];
+ cacheDirData[0] = '\0';
+ cacheDirGuiding[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ std::string gformat = dformat; // Use same data format for guiding format
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_join(cacheDirGuiding,
+ sizeof(cacheDirGuiding),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_GUIDE,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+ BLI_path_make_safe(cacheDirGuiding);
+
+ ss.str("");
+ ss << "bake_fluid_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirGuiding) << "', " << framenr << ", '" << dformat << "', '" << pformat
+ << "', '" << gformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeNoise(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeNoise()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX], cacheDirNoise[FILE_MAX];
+ cacheDirData[0] = '\0';
+ cacheDirNoise[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format);
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_join(cacheDirNoise,
+ sizeof(cacheDirNoise),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_NOISE,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+ BLI_path_make_safe(cacheDirNoise);
+
+ ss.str("");
+ ss << "bake_noise_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirNoise) << "', " << framenr << ", '" << dformat << "', '" << nformat
+ << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeMesh(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeMesh()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX], cacheDirMesh[FILE_MAX];
+ cacheDirData[0] = '\0';
+ cacheDirMesh[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format);
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_join(cacheDirMesh,
+ sizeof(cacheDirMesh),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_MESH,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+ BLI_path_make_safe(cacheDirMesh);
+
+ ss.str("");
+ ss << "bake_mesh_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirMesh) << "', " << framenr << ", '" << dformat << "', '" << mformat
+ << "', '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeParticles(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeParticles()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX], cacheDirParticles[FILE_MAX];
+ cacheDirData[0] = '\0';
+ cacheDirParticles[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_join(cacheDirParticles,
+ sizeof(cacheDirParticles),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_PARTICLES,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+ BLI_path_make_safe(cacheDirParticles);
+
+ ss.str("");
+ ss << "bake_particles_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirParticles) << "', " << framenr << ", '" << dformat << "', '"
+ << pformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeGuiding(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeGuiding()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirGuiding[FILE_MAX];
+ cacheDirGuiding[0] = '\0';
+
+ std::string gformat = getCacheFileEnding(mmd->domain->cache_data_format);
+
+ BLI_path_join(cacheDirGuiding,
+ sizeof(cacheDirGuiding),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_GUIDE,
+ NULL);
+ BLI_path_make_safe(cacheDirGuiding);
+
+ ss.str("");
+ ss << "bake_guiding_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', " << framenr
+ << ", '" << gformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+void MANTA::updateVariables(FluidModifierData *mmd)
+{
+ std::string tmpString, finalString;
+ std::vector<std::string> pythonCommands;
+
+ tmpString += fluid_variables;
+ if (mUsingSmoke)
+ tmpString += smoke_variables;
+ if (mUsingLiquid)
+ tmpString += liquid_variables;
+ if (mUsingGuiding)
+ tmpString += fluid_variables_guiding;
+ if (mUsingNoise) {
+ tmpString += fluid_variables_noise;
+ tmpString += smoke_variables_noise;
+ tmpString += smoke_wavelet_noise;
+ }
+ if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) {
+ tmpString += fluid_variables_particles;
+ tmpString += liquid_variables_particles;
+ }
+ if (mUsingMesh)
+ tmpString += fluid_variables_mesh;
+
+ finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::exportSmokeScript(FluidModifierData *mmd)
+{
+ if (with_debug)
+ std::cout << "MANTA::exportSmokeScript()" << std::endl;
+
+ char cacheDir[FILE_MAX] = "\0";
+ char cacheDirScript[FILE_MAX] = "\0";
+
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_path_make_safe(cacheDir);
+ /* Create 'script' subdir if it does not exist already */
+ BLI_dir_create_recursive(cacheDir);
+ BLI_path_join(cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_SMOKE_SCRIPT, NULL);
+ BLI_path_make_safe(cacheDir);
+
+ bool noise = mmd->domain->flags & FLUID_DOMAIN_USE_NOISE;
+ bool heat = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT;
+ bool colors = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS;
+ bool fire = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE;
+ bool obstacle = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
+ bool guiding = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE;
+ bool invel = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
+
+ std::string manta_script;
+
+ // Libraries
+ manta_script += header_libraries + manta_import;
+
+ // Variables
+ manta_script += header_variables + fluid_variables + smoke_variables;
+ if (noise) {
+ manta_script += fluid_variables_noise + smoke_variables_noise;
+ }
+ if (guiding)
+ manta_script += fluid_variables_guiding;
+
+ // Solvers
+ manta_script += header_solvers + fluid_solver;
+ if (noise)
+ manta_script += fluid_solver_noise;
+ if (guiding)
+ manta_script += fluid_solver_guiding;
+
+ // Grids
+ manta_script += header_grids + fluid_alloc + smoke_alloc;
+ if (noise) {
+ manta_script += smoke_alloc_noise;
+ if (colors)
+ manta_script += smoke_alloc_colors_noise;
+ if (fire)
+ manta_script += smoke_alloc_fire_noise;
+ }
+ if (heat)
+ manta_script += smoke_alloc_heat;
+ if (colors)
+ manta_script += smoke_alloc_colors;
+ if (fire)
+ manta_script += smoke_alloc_fire;
+ if (guiding)
+ manta_script += fluid_alloc_guiding;
+ if (obstacle)
+ manta_script += fluid_alloc_obstacle;
+ if (invel)
+ manta_script += fluid_alloc_invel;
+
+ // Noise field
+ if (noise)
+ manta_script += smoke_wavelet_noise;
+
+ // Time
+ manta_script += header_time + fluid_time_stepping + fluid_adapt_time_step;
+
+ // Import
+ manta_script += header_import + fluid_file_import + fluid_cache_helper + fluid_load_data +
+ smoke_load_data;
+ if (noise)
+ manta_script += smoke_load_noise;
+ if (guiding)
+ manta_script += fluid_load_guiding;
+
+ // Pre/Post Steps
+ manta_script += header_prepost + fluid_pre_step + fluid_post_step;
+
+ // Steps
+ manta_script += header_steps + smoke_adaptive_step + smoke_step;
+ if (noise) {
+ manta_script += smoke_step_noise;
+ }
+
+ // Main
+ manta_script += header_main + smoke_standalone + fluid_standalone;
+
+ // Fill in missing variables in script
+ std::string final_script = MANTA::parseScript(manta_script, mmd);
+
+ // Write script
+ std::ofstream myfile;
+ myfile.open(cacheDirScript);
+ myfile << final_script;
+ myfile.close();
+}
+
+void MANTA::exportLiquidScript(FluidModifierData *mmd)
+{
+ if (with_debug)
+ std::cout << "MANTA::exportLiquidScript()" << std::endl;
+
+ char cacheDir[FILE_MAX] = "\0";
+ char cacheDirScript[FILE_MAX] = "\0";
+
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_path_make_safe(cacheDir);
+ /* Create 'script' subdir if it does not exist already */
+ BLI_dir_create_recursive(cacheDir);
+ BLI_path_join(
+ cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_LIQUID_SCRIPT, NULL);
+ BLI_path_make_safe(cacheDirScript);
+
+ bool mesh = mmd->domain->flags & FLUID_DOMAIN_USE_MESH;
+ bool drops = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY;
+ bool bubble = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE;
+ bool floater = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
+ bool tracer = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER;
+ bool obstacle = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
+ bool guiding = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE;
+ bool invel = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
+
+ std::string manta_script;
+
+ // Libraries
+ manta_script += header_libraries + manta_import;
+
+ // Variables
+ manta_script += header_variables + fluid_variables + liquid_variables;
+ if (mesh)
+ manta_script += fluid_variables_mesh;
+ if (drops || bubble || floater || tracer)
+ manta_script += fluid_variables_particles + liquid_variables_particles;
+ if (guiding)
+ manta_script += fluid_variables_guiding;
+
+ // Solvers
+ manta_script += header_solvers + fluid_solver;
+ if (mesh)
+ manta_script += fluid_solver_mesh;
+ if (drops || bubble || floater || tracer)
+ manta_script += fluid_solver_particles;
+ if (guiding)
+ manta_script += fluid_solver_guiding;
+
+ // Grids
+ manta_script += header_grids + fluid_alloc + liquid_alloc;
+ if (mesh)
+ manta_script += liquid_alloc_mesh;
+ if (drops || bubble || floater || tracer)
+ manta_script += fluid_alloc_sndparts + liquid_alloc_particles;
+ if (guiding)
+ manta_script += fluid_alloc_guiding;
+ if (obstacle)
+ manta_script += fluid_alloc_obstacle;
+ if (invel)
+ manta_script += fluid_alloc_invel;
+
+ // Domain init
+ manta_script += header_gridinit + liquid_init_phi;
+
+ // Time
+ manta_script += header_time + fluid_time_stepping + fluid_adapt_time_step;
+
+ // Import
+ manta_script += header_import + fluid_file_import + fluid_cache_helper + fluid_load_data +
+ liquid_load_data + liquid_load_flip;
+ if (mesh)
+ manta_script += liquid_load_mesh;
+ if (drops || bubble || floater || tracer)
+ manta_script += fluid_load_particles + liquid_load_particles;
+ if (guiding)
+ manta_script += fluid_load_guiding;
+
+ // Pre/Post Steps
+ manta_script += header_prepost + fluid_pre_step + fluid_post_step;
+
+ // Steps
+ manta_script += header_steps + liquid_adaptive_step + liquid_step;
+ if (mesh)
+ manta_script += liquid_step_mesh;
+ if (drops || bubble || floater || tracer)
+ manta_script += liquid_step_particles;
+
+ // Main
+ manta_script += header_main + liquid_standalone + fluid_standalone;
+
+ // Fill in missing variables in script
+ std::string final_script = MANTA::parseScript(manta_script, mmd);
+
+ // Write script
+ std::ofstream myfile;
+ myfile.open(cacheDirScript);
+ myfile << final_script;
+ myfile.close();
+}
+
+/* Call Mantaflow python functions through this function. Use isAttribute for object attributes,
+ * e.g. s.cfl (here 's' is varname, 'cfl' functionName, and isAttribute true) */
+static PyObject *callPythonFunction(std::string varName,
+ std::string functionName,
+ bool isAttribute = false)
+{
+ if ((varName == "") || (functionName == "")) {
+ if (MANTA::with_debug)
+ std::cout << "Missing Python variable name and/or function name -- name is: " << varName
+ << ", function name is: " << functionName << std::endl;
+ return NULL;
+ }
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ PyObject *main = NULL, *var = NULL, *func = NULL, *returnedValue = NULL;
+
+ /* Be sure to initialise Python before importing main. */
+ Py_Initialize();
+
+ // Get pyobject that holds result value
+ main = PyImport_ImportModule("__main__");
+ if (!main)
+ return NULL;
+
+ var = PyObject_GetAttrString(main, varName.c_str());
+ if (!var)
+ return NULL;
+
+ func = PyObject_GetAttrString(var, functionName.c_str());
+
+ Py_DECREF(var);
+ if (!func)
+ return NULL;
+
+ if (!isAttribute) {
+ returnedValue = PyObject_CallObject(func, NULL);
+ Py_DECREF(func);
+ }
+
+ PyGILState_Release(gilstate);
+ return (!isAttribute) ? returnedValue : func;
+}
+
+static char *pyObjectToString(PyObject *inputObject)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ PyObject *encoded = PyUnicode_AsUTF8String(inputObject);
+ char *result = PyBytes_AsString(encoded);
+ Py_DECREF(encoded);
+ Py_DECREF(inputObject);
+
+ PyGILState_Release(gilstate);
+ return result;
+}
+
+static double pyObjectToDouble(PyObject *inputObject)
+{
+ // Cannot use PyFloat_AsDouble() since its error check crashes - likely because of Real (aka
+ // float) type in Mantaflow
+ return PyFloat_AS_DOUBLE(inputObject);
+}
+
+static long pyObjectToLong(PyObject *inputObject)
+{
+ return PyLong_AsLong(inputObject);
+}
+
+static void *stringToPointer(char *inputString)
+{
+ std::string str(inputString);
+ std::istringstream in(str);
+ void *dataPointer = NULL;
+ in >> dataPointer;
+ return dataPointer;
+}
+
+int MANTA::getFrame()
+{
+ if (with_debug)
+ std::cout << "MANTA::getFrame()" << std::endl;
+
+ std::string func = "frame";
+ std::string id = std::to_string(mCurrentID);
+ std::string solver = "s" + id;
+
+ return pyObjectToLong(callPythonFunction(solver, func, true));
+}
+
+float MANTA::getTimestep()
+{
+ if (with_debug)
+ std::cout << "MANTA::getTimestep()" << std::endl;
+
+ std::string func = "timestep";
+ std::string id = std::to_string(mCurrentID);
+ std::string solver = "s" + id;
+
+ return pyObjectToDouble(callPythonFunction(solver, func, true));
+}
+
+bool MANTA::needsRealloc(FluidModifierData *mmd)
+{
+ FluidDomainSettings *mds = mmd->domain;
+ return (mds->res[0] != mResX || mds->res[1] != mResY || mds->res[2] != mResZ);
+}
+
+void MANTA::adaptTimestep()
+{
+ if (with_debug)
+ std::cout << "MANTA::adaptTimestep()" << std::endl;
+
+ std::vector<std::string> pythonCommands;
+ std::ostringstream ss;
+
+ ss << "fluid_adapt_time_step_" << mCurrentID << "()";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::updateMeshFromFile(const char *filename)
+{
+ std::string fname(filename);
+ std::string::size_type idx;
+
+ idx = fname.rfind('.');
+ if (idx != std::string::npos) {
+ std::string extension = fname.substr(idx + 1);
+
+ if (extension.compare("gz") == 0)
+ updateMeshFromBobj(filename);
+ else if (extension.compare("obj") == 0)
+ updateMeshFromObj(filename);
+ else if (extension.compare("uni") == 0)
+ updateMeshFromUni(filename);
+ else
+ std::cerr << "updateMeshFromFile: invalid file extension in file: " << filename << std::endl;
+ }
+ else {
+ std::cerr << "updateMeshFromFile: unable to open file: " << filename << std::endl;
+ }
+}
+
+void MANTA::updateMeshFromBobj(const char *filename)
+{
+ if (with_debug)
+ std::cout << "MANTA::updateMeshFromBobj()" << std::endl;
+
+ gzFile gzf;
+ float fbuffer[3];
+ int ibuffer[3];
+ int numBuffer = 0;
+
+ gzf = (gzFile)BLI_gzopen(filename, "rb1"); // do some compression
+ if (!gzf)
+ std::cerr << "updateMeshData: unable to open file: " << filename << std::endl;
+
+ // Num vertices
+ gzread(gzf, &numBuffer, sizeof(int));
+
+ if (with_debug)
+ std::cout << "read mesh , num verts: " << numBuffer << " , in file: " << filename << std::endl;
+
+ if (numBuffer) {
+ // Vertices
+ mMeshNodes->resize(numBuffer);
+ for (std::vector<Node>::iterator it = mMeshNodes->begin(); it != mMeshNodes->end(); ++it) {
+ gzread(gzf, fbuffer, sizeof(float) * 3);
+ it->pos[0] = fbuffer[0];
+ it->pos[1] = fbuffer[1];
+ it->pos[2] = fbuffer[2];
+ }
+ }
+
+ // Num normals
+ gzread(gzf, &numBuffer, sizeof(int));
+
+ if (with_debug)
+ std::cout << "read mesh , num normals : " << numBuffer << " , in file: " << filename
+ << std::endl;
+
+ if (numBuffer) {
+ // Normals
+ if (!getNumVertices())
+ mMeshNodes->resize(numBuffer);
+ for (std::vector<Node>::iterator it = mMeshNodes->begin(); it != mMeshNodes->end(); ++it) {
+ gzread(gzf, fbuffer, sizeof(float) * 3);
+ it->normal[0] = fbuffer[0];
+ it->normal[1] = fbuffer[1];
+ it->normal[2] = fbuffer[2];
+ }
+ }
+
+ // Num triangles
+ gzread(gzf, &numBuffer, sizeof(int));
+
+ if (with_debug)
+ std::cout << "read mesh , num triangles : " << numBuffer << " , in file: " << filename
+ << std::endl;
+
+ if (numBuffer) {
+ // Triangles
+ mMeshTriangles->resize(numBuffer);
+ MANTA::Triangle *bufferTriangle;
+ for (std::vector<Triangle>::iterator it = mMeshTriangles->begin(); it != mMeshTriangles->end();
+ ++it) {
+ gzread(gzf, ibuffer, sizeof(int) * 3);
+ bufferTriangle = (MANTA::Triangle *)ibuffer;
+ it->c[0] = bufferTriangle->c[0];
+ it->c[1] = bufferTriangle->c[1];
+ it->c[2] = bufferTriangle->c[2];
+ }
+ }
+ gzclose(gzf);
+}
+
+void MANTA::updateMeshFromObj(const char *filename)
+{
+ if (with_debug)
+ std::cout << "MANTA::updateMeshFromObj()" << std::endl;
+
+ std::ifstream ifs(filename);
+ float fbuffer[3];
+ int ibuffer[3];
+ int cntVerts = 0, cntNormals = 0, cntTris = 0;
+
+ if (!ifs.good())
+ std::cerr << "updateMeshDataFromObj: unable to open file: " << filename << std::endl;
+
+ while (ifs.good() && !ifs.eof()) {
+ std::string id;
+ ifs >> id;
+
+ if (id[0] == '#') {
+ // comment
+ getline(ifs, id);
+ continue;
+ }
+ if (id == "vt") {
+ // tex coord, ignore
+ }
+ else if (id == "vn") {
+ // normals
+ if (getNumVertices() != cntVerts)
+ std::cerr << "updateMeshDataFromObj: invalid amount of mesh nodes" << std::endl;
+
+ ifs >> fbuffer[0] >> fbuffer[1] >> fbuffer[2];
+ MANTA::Node *node = &mMeshNodes->at(cntNormals);
+ (*node).normal[0] = fbuffer[0];
+ (*node).normal[1] = fbuffer[1];
+ (*node).normal[2] = fbuffer[2];
+ cntNormals++;
+ }
+ else if (id == "v") {
+ // vertex
+ ifs >> fbuffer[0] >> fbuffer[1] >> fbuffer[2];
+ MANTA::Node node;
+ node.pos[0] = fbuffer[0];
+ node.pos[1] = fbuffer[1];
+ node.pos[2] = fbuffer[2];
+ mMeshNodes->push_back(node);
+ cntVerts++;
+ }
+ else if (id == "g") {
+ // group
+ std::string group;
+ ifs >> group;
+ }
+ else if (id == "f") {
+ // face
+ std::string face;
+ for (int i = 0; i < 3; i++) {
+ ifs >> face;
+ if (face.find('/') != std::string::npos)
+ face = face.substr(0, face.find('/')); // ignore other indices
+ int idx = atoi(face.c_str()) - 1;
+ if (idx < 0)
+ std::cerr << "updateMeshDataFromObj: invalid face encountered" << std::endl;
+ ibuffer[i] = idx;
+ }
+ MANTA::Triangle triangle;
+ triangle.c[0] = ibuffer[0];
+ triangle.c[1] = ibuffer[1];
+ triangle.c[2] = ibuffer[2];
+ mMeshTriangles->push_back(triangle);
+ cntTris++;
+ }
+ else {
+ // whatever, ignore
+ }
+ // kill rest of line
+ getline(ifs, id);
+ }
+ ifs.close();
+}
+
+void MANTA::updateMeshFromUni(const char *filename)
+{
+ if (with_debug)
+ std::cout << "MANTA::updateMeshFromUni()" << std::endl;
+
+ gzFile gzf;
+ float fbuffer[4];
+ int ibuffer[4];
+
+ gzf = (gzFile)BLI_gzopen(filename, "rb1"); // do some compression
+ if (!gzf)
+ std::cout << "updateMeshFromUni: unable to open file" << std::endl;
+
+ char ID[5] = {0, 0, 0, 0, 0};
+ gzread(gzf, ID, 4);
+
+ std::vector<pVel> *velocityPointer = mMeshVelocities;
+
+ // mdata uni header
+ const int STR_LEN_PDATA = 256;
+ int elementType, bytesPerElement, numParticles;
+ char info[STR_LEN_PDATA]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+
+ // read mesh header
+ gzread(gzf, &ibuffer, sizeof(int) * 4); // num particles, dimX, dimY, dimZ
+ gzread(gzf, &elementType, sizeof(int));
+ gzread(gzf, &bytesPerElement, sizeof(int));
+ gzread(gzf, &info, sizeof(info));
+ gzread(gzf, &timestamp, sizeof(unsigned long long));
+
+ if (with_debug)
+ std::cout << "read " << ibuffer[0] << " vertices in file: " << filename << std::endl;
+
+ // Sanity checks
+ const int meshSize = sizeof(float) * 3 + sizeof(int);
+ if (!(bytesPerElement == meshSize) && (elementType == 0)) {
+ std::cout << "particle type doesn't match" << std::endl;
+ }
+ if (!ibuffer[0]) { // Any vertices present?
+ if (with_debug)
+ std::cout << "no vertices present yet" << std::endl;
+ return;
+ }
+
+ // Reading mesh
+ if (!strcmp(ID, "MB01")) {
+ // TODO (sebbas): Future update could add uni mesh support
+ }
+ // Reading mesh data file v1 with vec3
+ else if (!strcmp(ID, "MD01")) {
+ numParticles = ibuffer[0];
+
+ velocityPointer->resize(numParticles);
+ MANTA::pVel *bufferPVel;
+ for (std::vector<pVel>::iterator it = velocityPointer->begin(); it != velocityPointer->end();
+ ++it) {
+ gzread(gzf, fbuffer, sizeof(float) * 3);
+ bufferPVel = (MANTA::pVel *)fbuffer;
+ it->pos[0] = bufferPVel->pos[0];
+ it->pos[1] = bufferPVel->pos[1];
+ it->pos[2] = bufferPVel->pos[2];
+ }
+ }
+
+ gzclose(gzf);
+}
+
+void MANTA::updateParticlesFromFile(const char *filename, bool isSecondarySys, bool isVelData)
+{
+ if (with_debug)
+ std::cout << "MANTA::updateParticlesFromFile()" << std::endl;
+
+ std::string fname(filename);
+ std::string::size_type idx;
+
+ idx = fname.rfind('.');
+ if (idx != std::string::npos) {
+ std::string extension = fname.substr(idx + 1);
+
+ if (extension.compare("uni") == 0)
+ updateParticlesFromUni(filename, isSecondarySys, isVelData);
+ else
+ std::cerr << "updateParticlesFromFile: invalid file extension in file: " << filename
+ << std::endl;
+ }
+ else {
+ std::cerr << "updateParticlesFromFile: unable to open file: " << filename << std::endl;
+ }
+}
+
+void MANTA::updateParticlesFromUni(const char *filename, bool isSecondarySys, bool isVelData)
+{
+ if (with_debug)
+ std::cout << "MANTA::updateParticlesFromUni()" << std::endl;
+
+ gzFile gzf;
+ float fbuffer[4];
+ int ibuffer[4];
+
+ gzf = (gzFile)BLI_gzopen(filename, "rb1"); // do some compression
+ if (!gzf)
+ std::cout << "updateParticlesFromUni: unable to open file" << std::endl;
+
+ char ID[5] = {0, 0, 0, 0, 0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "PB01")) {
+ std::cout << "particle uni file format v01 not supported anymore" << std::endl;
+ return;
+ }
+
+ // Pointer to FLIP system or to secondary particle system
+ std::vector<pData> *dataPointer = NULL;
+ std::vector<pVel> *velocityPointer = NULL;
+ std::vector<float> *lifePointer = NULL;
+
+ if (isSecondarySys) {
+ dataPointer = mSndParticleData;
+ velocityPointer = mSndParticleVelocity;
+ lifePointer = mSndParticleLife;
+ }
+ else {
+ dataPointer = mFlipParticleData;
+ velocityPointer = mFlipParticleVelocity;
+ }
+
+ // pdata uni header
+ const int STR_LEN_PDATA = 256;
+ int elementType, bytesPerElement, numParticles;
+ char info[STR_LEN_PDATA]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+
+ // read particle header
+ gzread(gzf, &ibuffer, sizeof(int) * 4); // num particles, dimX, dimY, dimZ
+ gzread(gzf, &elementType, sizeof(int));
+ gzread(gzf, &bytesPerElement, sizeof(int));
+ gzread(gzf, &info, sizeof(info));
+ gzread(gzf, &timestamp, sizeof(unsigned long long));
+
+ if (with_debug)
+ std::cout << "read " << ibuffer[0] << " particles in file: " << filename << std::endl;
+
+ // Sanity checks
+ const int partSysSize = sizeof(float) * 3 + sizeof(int);
+ if (!(bytesPerElement == partSysSize) && (elementType == 0)) {
+ std::cout << "particle type doesn't match" << std::endl;
+ }
+ if (!ibuffer[0]) { // Any particles present?
+ if (with_debug)
+ std::cout << "no particles present yet" << std::endl;
+ return;
+ }
+
+ numParticles = ibuffer[0];
+
+ // Reading base particle system file v2
+ if (!strcmp(ID, "PB02")) {
+ dataPointer->resize(numParticles);
+ MANTA::pData *bufferPData;
+ for (std::vector<pData>::iterator it = dataPointer->begin(); it != dataPointer->end(); ++it) {
+ gzread(gzf, fbuffer, sizeof(float) * 3 + sizeof(int));
+ bufferPData = (MANTA::pData *)fbuffer;
+ it->pos[0] = bufferPData->pos[0];
+ it->pos[1] = bufferPData->pos[1];
+ it->pos[2] = bufferPData->pos[2];
+ it->flag = bufferPData->flag;
+ }
+ }
+ // Reading particle data file v1 with velocities
+ else if (!strcmp(ID, "PD01") && isVelData) {
+ velocityPointer->resize(numParticles);
+ MANTA::pVel *bufferPVel;
+ for (std::vector<pVel>::iterator it = velocityPointer->begin(); it != velocityPointer->end();
+ ++it) {
+ gzread(gzf, fbuffer, sizeof(float) * 3);
+ bufferPVel = (MANTA::pVel *)fbuffer;
+ it->pos[0] = bufferPVel->pos[0];
+ it->pos[1] = bufferPVel->pos[1];
+ it->pos[2] = bufferPVel->pos[2];
+ }
+ }
+ // Reading particle data file v1 with lifetime
+ else if (!strcmp(ID, "PD01")) {
+ lifePointer->resize(numParticles);
+ float *bufferPLife;
+ for (std::vector<float>::iterator it = lifePointer->begin(); it != lifePointer->end(); ++it) {
+ gzread(gzf, fbuffer, sizeof(float));
+ bufferPLife = (float *)fbuffer;
+ *it = *bufferPLife;
+ }
+ }
+
+ gzclose(gzf);
+}
+
+template<typename T>
+void MANTA::setPointers(std::vector<std::tuple<T **, std::string, std::string, bool>> objects)
+{
+ PyObject *mantaObject = NULL;
+
+ for (typename std::vector<std::tuple<T **, std::string, std::string, bool>>::iterator it =
+ objects.begin();
+ it != objects.end();
+ ++it) {
+ if (!std::get<3>(*it))
+ continue;
+ mantaObject = callPythonFunction(std::get<1>(*it), std::get<2>(*it));
+ if (mantaObject) {
+ (*std::get<0>(*it)) = (T *)stringToPointer(pyObjectToString(mantaObject));
+ }
+ else {
+ (*std::get<0>(*it)) = NULL;
+ }
+ }
+}
+
+void MANTA::updatePointers()
+{
+ if (with_debug)
+ std::cout << "MANTA::updatePointers()" << std::endl;
+
+ std::string func = "getDataPointer";
+ std::string funcNodes = "getNodesDataPointer";
+ std::string funcTris = "getTrisDataPointer";
+
+ std::string id = std::to_string(mCurrentID);
+ std::string solver = "s" + id;
+ std::string parts = "pp" + id;
+ std::string snd = "sp" + id;
+ std::string mesh = "sm" + id;
+ std::string mesh2 = "mesh" + id;
+ std::string noise = "sn" + id;
+ std::string solver_ext = "_" + solver;
+ std::string parts_ext = "_" + parts;
+ std::string snd_ext = "_" + snd;
+ std::string mesh_ext = "_" + mesh;
+ std::string mesh_ext2 = "_" + mesh2;
+ std::string noise_ext = "_" + noise;
+
+ std::vector<std::tuple<int **, std::string, std::string, bool>> mantaIntObjects;
+ mantaIntObjects.push_back(std::make_tuple(&mObstacle, "flags" + solver_ext, func, true));
+ mantaIntObjects.push_back(
+ std::make_tuple(&mNumObstacle, "numObs" + solver_ext, func, mUsingObstacle));
+ mantaIntObjects.push_back(
+ std::make_tuple(&mNumGuide, "numGuides" + solver_ext, func, mUsingGuiding));
+
+ std::vector<std::tuple<float **, std::string, std::string, bool>> mantaFloatObjects;
+ mantaFloatObjects.push_back(std::make_tuple(&mPhiIn, "phiIn" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mVelocityX, "x_vel" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mVelocityY, "y_vel" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mVelocityZ, "z_vel" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mForceX, "x_force" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mForceY, "y_force" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mForceZ, "z_force" + solver_ext, func, true));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mPhiOutIn, "phiOutIn" + solver_ext, func, mUsingOutflow));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mPhiObsIn, "phiObsIn" + solver_ext, func, mUsingObstacle));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mObVelocityX, "x_obvel" + solver_ext, func, mUsingObstacle));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mObVelocityY, "y_obvel" + solver_ext, func, mUsingObstacle));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mObVelocityZ, "z_obvel" + solver_ext, func, mUsingObstacle));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mPhiGuideIn, "phiGuideIn" + solver_ext, func, mUsingGuiding));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mGuideVelocityX, "x_guidevel" + solver_ext, func, mUsingGuiding));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mGuideVelocityY, "y_guidevel" + solver_ext, func, mUsingGuiding));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mGuideVelocityZ, "z_guidevel" + solver_ext, func, mUsingGuiding));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mInVelocityX, "x_invel" + solver_ext, func, mUsingInvel));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mInVelocityY, "y_invel" + solver_ext, func, mUsingInvel));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mInVelocityZ, "z_invel" + solver_ext, func, mUsingInvel));
+
+ mantaFloatObjects.push_back(std::make_tuple(&mPhi, "phi" + solver_ext, func, mUsingLiquid));
+
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mDensity, "density" + solver_ext, func, mUsingSmoke));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mDensityIn, "densityIn" + solver_ext, func, mUsingSmoke));
+ mantaFloatObjects.push_back(std::make_tuple(&mShadow, "shadow" + solver_ext, func, mUsingSmoke));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mEmissionIn, "emissionIn" + solver_ext, func, mUsingSmoke));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mHeat, "heat" + solver_ext, func, mUsingSmoke & mUsingHeat));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mHeatIn, "heatIn" + solver_ext, func, mUsingSmoke & mUsingHeat));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mFlame, "flame" + solver_ext, func, mUsingSmoke & mUsingFire));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mFuel, "fuel" + solver_ext, func, mUsingSmoke & mUsingFire));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mReact, "react" + solver_ext, func, mUsingSmoke & mUsingFire));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mFuelIn, "fuelIn" + solver_ext, func, mUsingSmoke & mUsingFire));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mReactIn, "reactIn" + solver_ext, func, mUsingSmoke & mUsingFire));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorR, "color_r" + solver_ext, func, mUsingSmoke & mUsingColors));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorG, "color_g" + solver_ext, func, mUsingSmoke & mUsingColors));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorB, "color_b" + solver_ext, func, mUsingSmoke & mUsingColors));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorRIn, "color_r_in" + solver_ext, func, mUsingSmoke & mUsingColors));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorGIn, "color_g_in" + solver_ext, func, mUsingSmoke & mUsingColors));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorBIn, "color_b_in" + solver_ext, func, mUsingSmoke & mUsingColors));
+
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mDensityHigh, "density" + noise_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureU, "texture_u" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureV, "texture_v" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureW, "texture_w" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureU2, "texture_u2" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureV2, "texture_v2" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureW2, "texture_w2" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mFlameHigh, "flame" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingFire));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mFuelHigh, "fuel" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingFire));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mReactHigh, "react" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingFire));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mColorRHigh, "color_r" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingColors));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mColorGHigh, "color_g" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingColors));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mColorRHigh, "color_b" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingColors));
+
+ std::vector<std::tuple<std::vector<pData> **, std::string, std::string, bool>> mantaPDataObjects;
+ mantaPDataObjects.push_back(
+ std::make_tuple(&mFlipParticleData, "pp" + solver_ext, func, mUsingLiquid));
+ mantaPDataObjects.push_back(std::make_tuple(
+ &mSndParticleData,
+ "ppSnd" + snd_ext,
+ func,
+ mUsingLiquid & (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers)));
+
+ std::vector<std::tuple<std::vector<pVel> **, std::string, std::string, bool>> mantaPVelObjects;
+ mantaPVelObjects.push_back(
+ std::make_tuple(&mFlipParticleVelocity, "pVel" + parts_ext, func, mUsingLiquid));
+ mantaPVelObjects.push_back(std::make_tuple(
+ &mMeshVelocities, "mVel" + mesh_ext2, func, mUsingLiquid & mUsingMesh & mUsingMVel));
+ mantaPVelObjects.push_back(std::make_tuple(
+ &mSndParticleVelocity,
+ "pVelSnd" + parts_ext,
+ func,
+ mUsingLiquid & (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers)));
+
+ std::vector<std::tuple<std::vector<Node> **, std::string, std::string, bool>> mantaNodeObjects;
+ mantaNodeObjects.push_back(
+ std::make_tuple(&mMeshNodes, "mesh" + mesh_ext, funcNodes, mUsingLiquid & mUsingMesh));
+
+ std::vector<std::tuple<std::vector<Triangle> **, std::string, std::string, bool>>
+ mantaTriangleObjects;
+ mantaTriangleObjects.push_back(
+ std::make_tuple(&mMeshTriangles, "mesh" + mesh_ext, funcTris, mUsingLiquid & mUsingMesh));
+
+ std::vector<std::tuple<std::vector<float> **, std::string, std::string, bool>>
+ mantaFloatVecObjects;
+ mantaFloatVecObjects.push_back(std::make_tuple(
+ &mSndParticleLife,
+ "pLifeSnd" + parts_ext,
+ func,
+ mUsingLiquid & (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers)));
+
+ setPointers(mantaIntObjects);
+ setPointers(mantaFloatObjects);
+ setPointers(mantaPDataObjects);
+ setPointers(mantaPVelObjects);
+ setPointers(mantaNodeObjects);
+ setPointers(mantaTriangleObjects);
+ setPointers(mantaFloatVecObjects);
+}
diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h
new file mode 100644
index 00000000000..1c18cb8affa
--- /dev/null
+++ b/intern/mantaflow/intern/MANTA_main.h
@@ -0,0 +1,844 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup mantaflow
+ */
+
+#ifndef MANTA_A_H
+#define MANTA_A_H
+
+#include <string>
+#include <vector>
+#include <atomic>
+#include <cassert>
+
+struct MANTA {
+ public:
+ MANTA(int *res, struct FluidModifierData *mmd);
+ MANTA(){};
+ virtual ~MANTA();
+
+ // Mirroring Mantaflow structures for particle data (pVel also used for mesh vert vels)
+ typedef struct PData {
+ float pos[3];
+ int flag;
+ } pData;
+ typedef struct PVel {
+ float pos[3];
+ } pVel;
+
+ // Mirroring Mantaflow structures for meshes
+ typedef struct Node {
+ int flags;
+ float pos[3], normal[3];
+ } Node;
+ typedef struct Triangle {
+ int c[3];
+ int flags;
+ } Triangle;
+
+ // Manta step, handling everything
+ void step(struct FluidModifierData *mmd, int startFrame);
+
+ // Grid initialization functions
+ void initHeat(struct FluidModifierData *mmd);
+ void initFire(struct FluidModifierData *mmd);
+ void initColors(struct FluidModifierData *mmd);
+ void initFireHigh(struct FluidModifierData *mmd);
+ void initColorsHigh(struct FluidModifierData *mmd);
+ void initLiquid(FluidModifierData *mmd);
+ void initLiquidMesh(FluidModifierData *mmd);
+ void initObstacle(FluidModifierData *mmd);
+ void initGuiding(FluidModifierData *mmd);
+ void initFractions(FluidModifierData *mmd);
+ void initInVelocity(FluidModifierData *mmd);
+ void initOutflow(FluidModifierData *mmd);
+ void initSndParts(FluidModifierData *mmd);
+ void initLiquidSndParts(FluidModifierData *mmd);
+
+ // Pointer transfer: Mantaflow -> Blender
+ void updatePointers();
+
+ // Write cache
+ int writeConfiguration(FluidModifierData *mmd, int framenr);
+ int writeData(FluidModifierData *mmd, int framenr);
+ // write call for noise, mesh and particles were left in bake calls for now
+
+ // Read cache (via Manta save/load)
+ int readConfiguration(FluidModifierData *mmd, int framenr);
+ int readData(FluidModifierData *mmd, int framenr);
+ int readNoise(FluidModifierData *mmd, int framenr);
+ int readMesh(FluidModifierData *mmd, int framenr);
+ int readParticles(FluidModifierData *mmd, int framenr);
+ int readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain);
+
+ // Read cache (via file read functions in MANTA - e.g. read .bobj.gz meshes, .uni particles)
+ int updateMeshStructures(FluidModifierData *mmd, int framenr);
+ int updateFlipStructures(FluidModifierData *mmd, int framenr);
+ int updateParticleStructures(FluidModifierData *mmd, int framenr);
+ void updateVariables(FluidModifierData *mmd);
+
+ // Bake cache
+ int bakeData(FluidModifierData *mmd, int framenr);
+ int bakeNoise(FluidModifierData *mmd, int framenr);
+ int bakeMesh(FluidModifierData *mmd, int framenr);
+ int bakeParticles(FluidModifierData *mmd, int framenr);
+ int bakeGuiding(FluidModifierData *mmd, int framenr);
+
+ // IO for Mantaflow scene script
+ void exportSmokeScript(struct FluidModifierData *mmd);
+ void exportLiquidScript(struct FluidModifierData *mmd);
+
+ inline size_t getTotalCells()
+ {
+ return mTotalCells;
+ }
+ inline size_t getTotalCellsHigh()
+ {
+ return mTotalCellsHigh;
+ }
+ inline bool usingNoise()
+ {
+ return mUsingNoise;
+ }
+ inline int getResX()
+ {
+ return mResX;
+ }
+ inline int getResY()
+ {
+ return mResY;
+ }
+ inline int getResZ()
+ {
+ return mResZ;
+ }
+ inline int getParticleResX()
+ {
+ return mResXParticle;
+ }
+ inline int getParticleResY()
+ {
+ return mResYParticle;
+ }
+ inline int getParticleResZ()
+ {
+ return mResZParticle;
+ }
+ inline int getMeshResX()
+ {
+ return mResXMesh;
+ }
+ inline int getMeshResY()
+ {
+ return mResYMesh;
+ }
+ inline int getMeshResZ()
+ {
+ return mResZMesh;
+ }
+ inline int getResXHigh()
+ {
+ return mResXNoise;
+ }
+ inline int getResYHigh()
+ {
+ return mResYNoise;
+ }
+ inline int getResZHigh()
+ {
+ return mResZNoise;
+ }
+ inline int getMeshUpres()
+ {
+ return mUpresMesh;
+ }
+ inline int getParticleUpres()
+ {
+ return mUpresParticle;
+ }
+
+ // Smoke getters
+ inline float *getDensity()
+ {
+ return mDensity;
+ }
+ inline float *getHeat()
+ {
+ return mHeat;
+ }
+ inline float *getVelocityX()
+ {
+ return mVelocityX;
+ }
+ inline float *getVelocityY()
+ {
+ return mVelocityY;
+ }
+ inline float *getVelocityZ()
+ {
+ return mVelocityZ;
+ }
+ inline float *getObVelocityX()
+ {
+ return mObVelocityX;
+ }
+ inline float *getObVelocityY()
+ {
+ return mObVelocityY;
+ }
+ inline float *getObVelocityZ()
+ {
+ return mObVelocityZ;
+ }
+ inline float *getGuideVelocityX()
+ {
+ return mGuideVelocityX;
+ }
+ inline float *getGuideVelocityY()
+ {
+ return mGuideVelocityY;
+ }
+ inline float *getGuideVelocityZ()
+ {
+ return mGuideVelocityZ;
+ }
+ inline float *getInVelocityX()
+ {
+ return mInVelocityX;
+ }
+ inline float *getInVelocityY()
+ {
+ return mInVelocityY;
+ }
+ inline float *getInVelocityZ()
+ {
+ return mInVelocityZ;
+ }
+ inline float *getForceX()
+ {
+ return mForceX;
+ }
+ inline float *getForceY()
+ {
+ return mForceY;
+ }
+ inline float *getForceZ()
+ {
+ return mForceZ;
+ }
+ inline int *getObstacle()
+ {
+ return mObstacle;
+ }
+ inline int *getNumObstacle()
+ {
+ return mNumObstacle;
+ }
+ inline int *getNumGuide()
+ {
+ return mNumGuide;
+ }
+ inline float *getFlame()
+ {
+ return mFlame;
+ }
+ inline float *getFuel()
+ {
+ return mFuel;
+ }
+ inline float *getReact()
+ {
+ return mReact;
+ }
+ inline float *getColorR()
+ {
+ return mColorR;
+ }
+ inline float *getColorG()
+ {
+ return mColorG;
+ }
+ inline float *getColorB()
+ {
+ return mColorB;
+ }
+ inline float *getShadow()
+ {
+ return mShadow;
+ }
+ inline float *getDensityIn()
+ {
+ return mDensityIn;
+ }
+ inline float *getHeatIn()
+ {
+ return mHeatIn;
+ }
+ inline float *getColorRIn()
+ {
+ return mColorRIn;
+ }
+ inline float *getColorGIn()
+ {
+ return mColorGIn;
+ }
+ inline float *getColorBIn()
+ {
+ return mColorBIn;
+ }
+ inline float *getFuelIn()
+ {
+ return mFuelIn;
+ }
+ inline float *getReactIn()
+ {
+ return mReactIn;
+ }
+ inline float *getEmissionIn()
+ {
+ return mEmissionIn;
+ }
+
+ inline float *getDensityHigh()
+ {
+ return mDensityHigh;
+ }
+ inline float *getFlameHigh()
+ {
+ return mFlameHigh;
+ }
+ inline float *getFuelHigh()
+ {
+ return mFuelHigh;
+ }
+ inline float *getReactHigh()
+ {
+ return mReactHigh;
+ }
+ inline float *getColorRHigh()
+ {
+ return mColorRHigh;
+ }
+ inline float *getColorGHigh()
+ {
+ return mColorGHigh;
+ }
+ inline float *getColorBHigh()
+ {
+ return mColorBHigh;
+ }
+ inline float *getTextureU()
+ {
+ return mTextureU;
+ }
+ inline float *getTextureV()
+ {
+ return mTextureV;
+ }
+ inline float *getTextureW()
+ {
+ return mTextureW;
+ }
+ inline float *getTextureU2()
+ {
+ return mTextureU2;
+ }
+ inline float *getTextureV2()
+ {
+ return mTextureV2;
+ }
+ inline float *getTextureW2()
+ {
+ return mTextureW2;
+ }
+
+ inline float *getPhiIn()
+ {
+ return mPhiIn;
+ }
+ inline float *getPhiObsIn()
+ {
+ return mPhiObsIn;
+ }
+ inline float *getPhiGuideIn()
+ {
+ return mPhiGuideIn;
+ }
+ inline float *getPhiOutIn()
+ {
+ return mPhiOutIn;
+ }
+ inline float *getPhi()
+ {
+ return mPhi;
+ }
+
+ static std::atomic<bool> mantaInitialized;
+ static std::atomic<int> solverID;
+ static int with_debug; // on or off (1 or 0), also sets manta debug level
+
+ // Mesh getters
+ inline int getNumVertices()
+ {
+ return (mMeshNodes && !mMeshNodes->empty()) ? mMeshNodes->size() : 0;
+ }
+ inline int getNumNormals()
+ {
+ return (mMeshNodes && !mMeshNodes->empty()) ? mMeshNodes->size() : 0;
+ }
+ inline int getNumTriangles()
+ {
+ return (mMeshTriangles && !mMeshTriangles->empty()) ? mMeshTriangles->size() : 0;
+ }
+
+ inline float getVertexXAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getVertexYAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getVertexZAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ inline float getNormalXAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].normal[0];
+ }
+ return 0.0f;
+ }
+ inline float getNormalYAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].normal[1];
+ }
+ return 0.0f;
+ }
+ inline float getNormalZAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].normal[2];
+ }
+ return 0.0f;
+ }
+
+ inline int getTriangleXAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshTriangles && !mMeshTriangles->empty()) {
+ assert(i < mMeshTriangles->size());
+ return (*mMeshTriangles)[i].c[0];
+ }
+ return 0;
+ }
+ inline int getTriangleYAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshTriangles && !mMeshTriangles->empty()) {
+ assert(i < mMeshTriangles->size());
+ return (*mMeshTriangles)[i].c[1];
+ }
+ return 0;
+ }
+ inline int getTriangleZAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshTriangles && !mMeshTriangles->empty()) {
+ assert(i < mMeshTriangles->size());
+ return (*mMeshTriangles)[i].c[2];
+ }
+ return 0;
+ }
+
+ inline float getVertVelXAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshVelocities && !mMeshVelocities->empty()) {
+ assert(i < mMeshVelocities->size());
+ return (*mMeshVelocities)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getVertVelYAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshVelocities && !mMeshVelocities->empty()) {
+ assert(i < mMeshVelocities->size());
+ return (*mMeshVelocities)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getVertVelZAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshVelocities && !mMeshVelocities->empty()) {
+ assert(i < mMeshVelocities->size());
+ return (*mMeshVelocities)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ // Particle getters
+ inline int getFlipParticleFlagAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleData && !mFlipParticleData->empty()) {
+ assert(i < mFlipParticleData->size());
+ return (*mFlipParticleData)[i].flag;
+ }
+ return 0;
+ }
+ inline int getSndParticleFlagAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleData && !mSndParticleData->empty()) {
+ assert(i < mSndParticleData->size());
+ return (*mSndParticleData)[i].flag;
+ }
+ return 0;
+ }
+
+ inline float getFlipParticlePositionXAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleData && !mFlipParticleData->empty()) {
+ assert(i < mFlipParticleData->size());
+ return (*mFlipParticleData)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getFlipParticlePositionYAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleData && !mFlipParticleData->empty()) {
+ assert(i < mFlipParticleData->size());
+ return (*mFlipParticleData)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getFlipParticlePositionZAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleData && !mFlipParticleData->empty()) {
+ assert(i < mFlipParticleData->size());
+ return (*mFlipParticleData)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ inline float getSndParticlePositionXAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleData && !mSndParticleData->empty()) {
+ assert(i < mSndParticleData->size());
+ return (*mSndParticleData)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getSndParticlePositionYAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleData && !mSndParticleData->empty()) {
+ assert(i < mSndParticleData->size());
+ return (*mSndParticleData)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getSndParticlePositionZAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleData && !mSndParticleData->empty()) {
+ assert(i < mSndParticleData->size());
+ return (*mSndParticleData)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ inline float getFlipParticleVelocityXAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) {
+ assert(i < mFlipParticleVelocity->size());
+ return (*mFlipParticleVelocity)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getFlipParticleVelocityYAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) {
+ assert(i < mFlipParticleVelocity->size());
+ return (*mFlipParticleVelocity)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getFlipParticleVelocityZAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) {
+ assert(i < mFlipParticleVelocity->size());
+ return (*mFlipParticleVelocity)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ inline float getSndParticleVelocityXAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleVelocity && !mSndParticleVelocity->empty()) {
+ assert(i < mSndParticleVelocity->size());
+ return (*mSndParticleVelocity)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getSndParticleVelocityYAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleVelocity && !mSndParticleVelocity->empty()) {
+ assert(i < mSndParticleVelocity->size());
+ return (*mSndParticleVelocity)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getSndParticleVelocityZAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleVelocity && !mSndParticleVelocity->empty()) {
+ assert(i < mSndParticleVelocity->size());
+ return (*mSndParticleVelocity)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ inline float *getFlipParticleData()
+ {
+ return (mFlipParticleData && !mFlipParticleData->empty()) ?
+ (float *)&mFlipParticleData->front() :
+ NULL;
+ }
+ inline float *getSndParticleData()
+ {
+ return (mSndParticleData && !mSndParticleData->empty()) ? (float *)&mSndParticleData->front() :
+ NULL;
+ }
+
+ inline float *getFlipParticleVelocity()
+ {
+ return (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) ?
+ (float *)&mFlipParticleVelocity->front() :
+ NULL;
+ }
+ inline float *getSndParticleVelocity()
+ {
+ return (mSndParticleVelocity && !mSndParticleVelocity->empty()) ?
+ (float *)&mSndParticleVelocity->front() :
+ NULL;
+ }
+ inline float *getSndParticleLife()
+ {
+ return (mSndParticleLife && !mSndParticleLife->empty()) ? (float *)&mSndParticleLife->front() :
+ NULL;
+ }
+
+ inline int getNumFlipParticles()
+ {
+ return (mFlipParticleData && !mFlipParticleData->empty()) ? mFlipParticleData->size() : 0;
+ }
+ inline int getNumSndParticles()
+ {
+ return (mSndParticleData && !mSndParticleData->empty()) ? mSndParticleData->size() : 0;
+ }
+
+ // Direct access to solver time attributes
+ int getFrame();
+ float getTimestep();
+ void adaptTimestep();
+
+ bool needsRealloc(FluidModifierData *mmd);
+
+ private:
+ // simulation constants
+ size_t mTotalCells;
+ size_t mTotalCellsHigh;
+ size_t mTotalCellsMesh;
+ size_t mTotalCellsParticles;
+
+ int mCurrentID;
+
+ bool mUsingHeat;
+ bool mUsingColors;
+ bool mUsingFire;
+ bool mUsingObstacle;
+ bool mUsingGuiding;
+ bool mUsingFractions;
+ bool mUsingInvel;
+ bool mUsingOutflow;
+ bool mUsingNoise;
+ bool mUsingMesh;
+ bool mUsingMVel;
+ bool mUsingLiquid;
+ bool mUsingSmoke;
+ bool mUsingDrops;
+ bool mUsingBubbles;
+ bool mUsingFloats;
+ bool mUsingTracers;
+
+ int mResX;
+ int mResY;
+ int mResZ;
+ int mMaxRes;
+
+ int mResXNoise;
+ int mResYNoise;
+ int mResZNoise;
+ int mResXMesh;
+ int mResYMesh;
+ int mResZMesh;
+ int mResXParticle;
+ int mResYParticle;
+ int mResZParticle;
+ int *mResGuiding;
+
+ int mUpresMesh;
+ int mUpresParticle;
+
+ float mTempAmb; /* ambient temperature */
+ float mConstantScaling;
+
+ // Fluid grids
+ float *mVelocityX;
+ float *mVelocityY;
+ float *mVelocityZ;
+ float *mObVelocityX;
+ float *mObVelocityY;
+ float *mObVelocityZ;
+ float *mGuideVelocityX;
+ float *mGuideVelocityY;
+ float *mGuideVelocityZ;
+ float *mInVelocityX;
+ float *mInVelocityY;
+ float *mInVelocityZ;
+ float *mForceX;
+ float *mForceY;
+ float *mForceZ;
+ int *mObstacle;
+ int *mNumObstacle;
+ int *mNumGuide;
+
+ // Smoke grids
+ float *mDensity;
+ float *mHeat;
+ float *mFlame;
+ float *mFuel;
+ float *mReact;
+ float *mColorR;
+ float *mColorG;
+ float *mColorB;
+ float *mShadow;
+ float *mDensityIn;
+ float *mHeatIn;
+ float *mFuelIn;
+ float *mReactIn;
+ float *mEmissionIn;
+ float *mColorRIn;
+ float *mColorGIn;
+ float *mColorBIn;
+ float *mDensityHigh;
+ float *mFlameHigh;
+ float *mFuelHigh;
+ float *mReactHigh;
+ float *mColorRHigh;
+ float *mColorGHigh;
+ float *mColorBHigh;
+ float *mTextureU;
+ float *mTextureV;
+ float *mTextureW;
+ float *mTextureU2;
+ float *mTextureV2;
+ float *mTextureW2;
+
+ // Liquid grids
+ float *mPhiIn;
+ float *mPhiObsIn;
+ float *mPhiGuideIn;
+ float *mPhiOutIn;
+ float *mPhi;
+
+ // Mesh fields
+ std::vector<Node> *mMeshNodes;
+ std::vector<Triangle> *mMeshTriangles;
+ std::vector<pVel> *mMeshVelocities;
+
+ // Particle fields
+ std::vector<pData> *mFlipParticleData;
+ std::vector<pVel> *mFlipParticleVelocity;
+
+ std::vector<pData> *mSndParticleData;
+ std::vector<pVel> *mSndParticleVelocity;
+ std::vector<float> *mSndParticleLife;
+
+ void initDomain(struct FluidModifierData *mmd);
+ void initNoise(struct FluidModifierData *mmd);
+ void initMesh(struct FluidModifierData *mmd);
+ void initSmoke(struct FluidModifierData *mmd);
+ void initSmokeNoise(struct FluidModifierData *mmd);
+ void initializeMantaflow();
+ void terminateMantaflow();
+ void runPythonString(std::vector<std::string> commands);
+ std::string getRealValue(const std::string &varName, FluidModifierData *mmd);
+ std::string parseLine(const std::string &line, FluidModifierData *mmd);
+ std::string parseScript(const std::string &setup_string, FluidModifierData *mmd = NULL);
+ void updateMeshFromBobj(const char *filename);
+ void updateMeshFromObj(const char *filename);
+ void updateMeshFromUni(const char *filename);
+ void updateParticlesFromUni(const char *filename, bool isSecondarySys, bool isVelData);
+ void updateMeshFromFile(const char *filename);
+ void updateParticlesFromFile(const char *filename, bool isSecondarySys, bool isVelData);
+ template<class T>
+ void setPointers(std::vector<std::tuple<T **, std::string, std::string, bool>>);
+};
+
+#endif
diff --git a/intern/mantaflow/intern/manta_fluid_API.cpp b/intern/mantaflow/intern/manta_fluid_API.cpp
new file mode 100644
index 00000000000..240bbd77085
--- /dev/null
+++ b/intern/mantaflow/intern/manta_fluid_API.cpp
@@ -0,0 +1,866 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup mantaflow
+ */
+
+#include <cmath>
+
+#include "MANTA_main.h"
+#include "manta_fluid_API.h"
+
+/* Fluid functions */
+MANTA *manta_init(int *res, struct FluidModifierData *mmd)
+{
+ return new MANTA(res, mmd);
+}
+void manta_free(MANTA *fluid)
+{
+ delete fluid;
+ fluid = nullptr;
+}
+
+void manta_ensure_obstacle(MANTA *fluid, struct FluidModifierData *mmd)
+{
+ if (!fluid)
+ return;
+ fluid->initObstacle(mmd);
+ fluid->updatePointers();
+}
+void manta_ensure_guiding(MANTA *fluid, struct FluidModifierData *mmd)
+{
+ if (!fluid)
+ return;
+ fluid->initGuiding(mmd);
+ fluid->updatePointers();
+}
+void manta_ensure_invelocity(MANTA *fluid, struct FluidModifierData *mmd)
+{
+ if (!fluid)
+ return;
+ fluid->initInVelocity(mmd);
+ fluid->updatePointers();
+}
+void manta_ensure_outflow(MANTA *fluid, struct FluidModifierData *mmd)
+{
+ if (!fluid)
+ return;
+ fluid->initOutflow(mmd);
+ fluid->updatePointers();
+}
+
+int manta_write_config(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->writeConfiguration(mmd, framenr);
+}
+
+int manta_write_data(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->writeData(mmd, framenr);
+}
+
+int manta_read_config(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readConfiguration(mmd, framenr);
+}
+
+int manta_read_data(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readData(mmd, framenr);
+}
+
+int manta_read_noise(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readNoise(mmd, framenr);
+}
+
+int manta_read_mesh(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readMesh(mmd, framenr);
+}
+
+int manta_read_particles(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readParticles(mmd, framenr);
+}
+
+int manta_read_guiding(MANTA *fluid, FluidModifierData *mmd, int framenr, bool sourceDomain)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readGuiding(mmd, framenr, sourceDomain);
+}
+
+int manta_update_liquid_structures(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->updateFlipStructures(mmd, framenr);
+}
+
+int manta_update_mesh_structures(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->updateMeshStructures(mmd, framenr);
+}
+
+int manta_update_particle_structures(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->updateParticleStructures(mmd, framenr);
+}
+
+int manta_bake_data(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeData(mmd, framenr);
+}
+
+int manta_bake_noise(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeNoise(mmd, framenr);
+}
+
+int manta_bake_mesh(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeMesh(mmd, framenr);
+}
+
+int manta_bake_particles(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeParticles(mmd, framenr);
+}
+
+int manta_bake_guiding(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeGuiding(mmd, framenr);
+}
+
+void manta_update_variables(MANTA *fluid, FluidModifierData *mmd)
+{
+ if (!fluid)
+ return;
+ fluid->updateVariables(mmd);
+}
+
+int manta_get_frame(MANTA *fluid)
+{
+ if (!fluid)
+ return 0;
+ return fluid->getFrame();
+}
+
+float manta_get_timestep(MANTA *fluid)
+{
+ if (!fluid)
+ return 0;
+ return fluid->getTimestep();
+}
+
+void manta_adapt_timestep(MANTA *fluid)
+{
+ if (!fluid)
+ return;
+ fluid->adaptTimestep();
+}
+
+bool manta_needs_realloc(MANTA *fluid, FluidModifierData *mmd)
+{
+ if (!fluid)
+ return false;
+ return fluid->needsRealloc(mmd);
+}
+
+/* Fluid accessors */
+size_t manta_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */)
+{
+ return x + y * max_x + z * max_x * max_y;
+}
+size_t manta_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */)
+{
+ return x + y * max_x;
+}
+float *manta_get_velocity_x(MANTA *fluid)
+{
+ return fluid->getVelocityX();
+}
+float *manta_get_velocity_y(MANTA *fluid)
+{
+ return fluid->getVelocityY();
+}
+float *manta_get_velocity_z(MANTA *fluid)
+{
+ return fluid->getVelocityZ();
+}
+
+float *manta_get_ob_velocity_x(MANTA *fluid)
+{
+ return fluid->getObVelocityX();
+}
+float *manta_get_ob_velocity_y(MANTA *fluid)
+{
+ return fluid->getObVelocityY();
+}
+float *manta_get_ob_velocity_z(MANTA *fluid)
+{
+ return fluid->getObVelocityZ();
+}
+
+float *manta_get_guide_velocity_x(MANTA *fluid)
+{
+ return fluid->getGuideVelocityX();
+}
+float *manta_get_guide_velocity_y(MANTA *fluid)
+{
+ return fluid->getGuideVelocityY();
+}
+float *manta_get_guide_velocity_z(MANTA *fluid)
+{
+ return fluid->getGuideVelocityZ();
+}
+
+float *manta_get_in_velocity_x(MANTA *fluid)
+{
+ return fluid->getInVelocityX();
+}
+float *manta_get_in_velocity_y(MANTA *fluid)
+{
+ return fluid->getInVelocityY();
+}
+float *manta_get_in_velocity_z(MANTA *fluid)
+{
+ return fluid->getInVelocityZ();
+}
+
+float *manta_get_force_x(MANTA *fluid)
+{
+ return fluid->getForceX();
+}
+float *manta_get_force_y(MANTA *fluid)
+{
+ return fluid->getForceY();
+}
+float *manta_get_force_z(MANTA *fluid)
+{
+ return fluid->getForceZ();
+}
+
+float *manta_get_phiguide_in(MANTA *fluid)
+{
+ return fluid->getPhiGuideIn();
+}
+
+int *manta_get_num_obstacle(MANTA *fluid)
+{
+ return fluid->getNumObstacle();
+}
+int *manta_get_num_guide(MANTA *fluid)
+{
+ return fluid->getNumGuide();
+}
+
+int manta_get_res_x(MANTA *fluid)
+{
+ return fluid->getResX();
+}
+int manta_get_res_y(MANTA *fluid)
+{
+ return fluid->getResY();
+}
+int manta_get_res_z(MANTA *fluid)
+{
+ return fluid->getResZ();
+}
+
+float *manta_get_phi_in(MANTA *fluid)
+{
+ return fluid->getPhiIn();
+}
+float *manta_get_phiobs_in(MANTA *fluid)
+{
+ return fluid->getPhiObsIn();
+}
+float *manta_get_phiout_in(MANTA *fluid)
+{
+ return fluid->getPhiOutIn();
+}
+
+/* Smoke functions */
+void manta_smoke_export_script(MANTA *smoke, FluidModifierData *mmd)
+{
+ if (!smoke || !mmd)
+ return;
+ smoke->exportSmokeScript(mmd);
+}
+
+void manta_smoke_export(MANTA *smoke,
+ float *dt,
+ float *dx,
+ float **dens,
+ float **react,
+ float **flame,
+ float **fuel,
+ float **heat,
+ float **vx,
+ float **vy,
+ float **vz,
+ float **r,
+ float **g,
+ float **b,
+ int **obstacle,
+ float **shadow)
+{
+ if (dens)
+ *dens = smoke->getDensity();
+ if (fuel)
+ *fuel = smoke->getFuel();
+ if (react)
+ *react = smoke->getReact();
+ if (flame)
+ *flame = smoke->getFlame();
+ if (heat)
+ *heat = smoke->getHeat();
+ *vx = smoke->getVelocityX();
+ *vy = smoke->getVelocityY();
+ *vz = smoke->getVelocityZ();
+ if (r)
+ *r = smoke->getColorR();
+ if (g)
+ *g = smoke->getColorG();
+ if (b)
+ *b = smoke->getColorB();
+ *obstacle = smoke->getObstacle();
+ *shadow = smoke->getShadow();
+ *dt = 1; // dummy value, not needed for smoke
+ *dx = 1; // dummy value, not needed for smoke
+}
+
+void manta_smoke_turbulence_export(MANTA *smoke,
+ float **dens,
+ float **react,
+ float **flame,
+ float **fuel,
+ float **r,
+ float **g,
+ float **b,
+ float **tcu,
+ float **tcv,
+ float **tcw,
+ float **tcu2,
+ float **tcv2,
+ float **tcw2)
+{
+ if (!smoke && !(smoke->usingNoise()))
+ return;
+
+ *dens = smoke->getDensityHigh();
+ if (fuel)
+ *fuel = smoke->getFuelHigh();
+ if (react)
+ *react = smoke->getReactHigh();
+ if (flame)
+ *flame = smoke->getFlameHigh();
+ if (r)
+ *r = smoke->getColorRHigh();
+ if (g)
+ *g = smoke->getColorGHigh();
+ if (b)
+ *b = smoke->getColorBHigh();
+ *tcu = smoke->getTextureU();
+ *tcv = smoke->getTextureV();
+ *tcw = smoke->getTextureW();
+
+ *tcu2 = smoke->getTextureU2();
+ *tcv2 = smoke->getTextureV2();
+ *tcw2 = smoke->getTextureW2();
+}
+
+static void get_rgba(
+ float *r, float *g, float *b, float *a, int total_cells, float *data, int sequential)
+{
+ int i;
+ /* Use offsets to map RGB grids to to correct location in data grid. */
+ int m = 4, i_g = 1, i_b = 2, i_a = 3;
+ if (sequential) {
+ m = 1;
+ i_g *= total_cells;
+ i_b *= total_cells;
+ i_a *= total_cells;
+ }
+
+ for (i = 0; i < total_cells; i++) {
+ float alpha = a[i];
+ if (alpha) {
+ data[i * m] = r[i];
+ data[i * m + i_g] = g[i];
+ data[i * m + i_b] = b[i];
+ }
+ else {
+ data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f;
+ }
+ data[i * m + i_a] = alpha;
+ }
+}
+
+void manta_smoke_get_rgba(MANTA *smoke, float *data, int sequential)
+{
+ get_rgba(smoke->getColorR(),
+ smoke->getColorG(),
+ smoke->getColorB(),
+ smoke->getDensity(),
+ smoke->getTotalCells(),
+ data,
+ sequential);
+}
+
+void manta_smoke_turbulence_get_rgba(MANTA *smoke, float *data, int sequential)
+{
+ get_rgba(smoke->getColorRHigh(),
+ smoke->getColorGHigh(),
+ smoke->getColorBHigh(),
+ smoke->getDensityHigh(),
+ smoke->getTotalCellsHigh(),
+ data,
+ sequential);
+}
+
+static void get_rgba_from_density(
+ float color[3], float *a, int total_cells, float *data, int sequential)
+{
+ int i;
+ int m = 4, i_g = 1, i_b = 2, i_a = 3;
+ if (sequential) {
+ m = 1;
+ i_g *= total_cells;
+ i_b *= total_cells;
+ i_a *= total_cells;
+ }
+
+ for (i = 0; i < total_cells; i++) {
+ float alpha = a[i];
+ if (alpha) {
+ data[i * m] = color[0] * alpha;
+ data[i * m + i_g] = color[1] * alpha;
+ data[i * m + i_b] = color[2] * alpha;
+ }
+ else {
+ data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f;
+ }
+ data[i * m + i_a] = alpha;
+ }
+}
+
+void manta_smoke_get_rgba_from_density(MANTA *smoke, float color[3], float *data, int sequential)
+{
+ get_rgba_from_density(color, smoke->getDensity(), smoke->getTotalCells(), data, sequential);
+}
+
+void manta_smoke_turbulence_get_rgba_from_density(MANTA *smoke,
+ float color[3],
+ float *data,
+ int sequential)
+{
+ get_rgba_from_density(
+ color, smoke->getDensityHigh(), smoke->getTotalCellsHigh(), data, sequential);
+}
+
+void manta_smoke_ensure_heat(MANTA *smoke, struct FluidModifierData *mmd)
+{
+ if (smoke) {
+ smoke->initHeat(mmd);
+ smoke->updatePointers();
+ }
+}
+
+void manta_smoke_ensure_fire(MANTA *smoke, struct FluidModifierData *mmd)
+{
+ if (smoke) {
+ smoke->initFire(mmd);
+ if (smoke->usingNoise()) {
+ smoke->initFireHigh(mmd);
+ }
+ smoke->updatePointers();
+ }
+}
+
+void manta_smoke_ensure_colors(MANTA *smoke, struct FluidModifierData *mmd)
+{
+ if (smoke) {
+ smoke->initColors(mmd);
+ if (smoke->usingNoise()) {
+ smoke->initColorsHigh(mmd);
+ }
+ smoke->updatePointers();
+ }
+}
+
+/* Smoke accessors */
+float *manta_smoke_get_density(MANTA *smoke)
+{
+ return smoke->getDensity();
+}
+float *manta_smoke_get_fuel(MANTA *smoke)
+{
+ return smoke->getFuel();
+}
+float *manta_smoke_get_react(MANTA *smoke)
+{
+ return smoke->getReact();
+}
+float *manta_smoke_get_heat(MANTA *smoke)
+{
+ return smoke->getHeat();
+}
+float *manta_smoke_get_flame(MANTA *smoke)
+{
+ return smoke->getFlame();
+}
+float *manta_smoke_get_shadow(MANTA *fluid)
+{
+ return fluid->getShadow();
+}
+
+float *manta_smoke_get_color_r(MANTA *smoke)
+{
+ return smoke->getColorR();
+}
+float *manta_smoke_get_color_g(MANTA *smoke)
+{
+ return smoke->getColorG();
+}
+float *manta_smoke_get_color_b(MANTA *smoke)
+{
+ return smoke->getColorB();
+}
+
+int *manta_smoke_get_obstacle(MANTA *smoke)
+{
+ return smoke->getObstacle();
+}
+
+float *manta_smoke_get_density_in(MANTA *smoke)
+{
+ return smoke->getDensityIn();
+}
+float *manta_smoke_get_heat_in(MANTA *smoke)
+{
+ return smoke->getHeatIn();
+}
+float *manta_smoke_get_color_r_in(MANTA *smoke)
+{
+ return smoke->getColorRIn();
+}
+float *manta_smoke_get_color_g_in(MANTA *smoke)
+{
+ return smoke->getColorGIn();
+}
+float *manta_smoke_get_color_b_in(MANTA *smoke)
+{
+ return smoke->getColorBIn();
+}
+float *manta_smoke_get_fuel_in(MANTA *smoke)
+{
+ return smoke->getFuelIn();
+}
+float *manta_smoke_get_react_in(MANTA *smoke)
+{
+ return smoke->getReactIn();
+}
+float *manta_smoke_get_emission_in(MANTA *smoke)
+{
+ return smoke->getEmissionIn();
+}
+
+int manta_smoke_has_heat(MANTA *smoke)
+{
+ return (smoke->getHeat()) ? 1 : 0;
+}
+int manta_smoke_has_fuel(MANTA *smoke)
+{
+ return (smoke->getFuel()) ? 1 : 0;
+}
+int manta_smoke_has_colors(MANTA *smoke)
+{
+ return (smoke->getColorR() && smoke->getColorG() && smoke->getColorB()) ? 1 : 0;
+}
+
+float *manta_smoke_turbulence_get_density(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getDensityHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_fuel(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getFuelHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_react(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getReactHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_color_r(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getColorRHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_color_g(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getColorGHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_color_b(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getColorBHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_flame(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getFlameHigh() : nullptr;
+}
+
+int manta_smoke_turbulence_has_fuel(MANTA *smoke)
+{
+ return (smoke->getFuelHigh()) ? 1 : 0;
+}
+int manta_smoke_turbulence_has_colors(MANTA *smoke)
+{
+ return (smoke->getColorRHigh() && smoke->getColorGHigh() && smoke->getColorBHigh()) ? 1 : 0;
+}
+
+void manta_smoke_turbulence_get_res(MANTA *smoke, int *res)
+{
+ if (smoke && smoke->usingNoise()) {
+ res[0] = smoke->getResXHigh();
+ res[1] = smoke->getResYHigh();
+ res[2] = smoke->getResZHigh();
+ }
+}
+int manta_smoke_turbulence_get_cells(MANTA *smoke)
+{
+ int total_cells_high = smoke->getResXHigh() * smoke->getResYHigh() * smoke->getResZHigh();
+ return (smoke && smoke->usingNoise()) ? total_cells_high : 0;
+}
+
+/* Liquid functions */
+void manta_liquid_export_script(MANTA *liquid, FluidModifierData *mmd)
+{
+ if (!liquid || !mmd)
+ return;
+ liquid->exportLiquidScript(mmd);
+}
+
+void manta_liquid_ensure_sndparts(MANTA *liquid, struct FluidModifierData *mmd)
+{
+ if (liquid) {
+ liquid->initLiquidSndParts(mmd);
+ liquid->updatePointers();
+ }
+}
+
+/* Liquid accessors */
+int manta_liquid_get_particle_res_x(MANTA *liquid)
+{
+ return liquid->getParticleResX();
+}
+int manta_liquid_get_particle_res_y(MANTA *liquid)
+{
+ return liquid->getParticleResY();
+}
+int manta_liquid_get_particle_res_z(MANTA *liquid)
+{
+ return liquid->getParticleResZ();
+}
+
+int manta_liquid_get_mesh_res_x(MANTA *liquid)
+{
+ return liquid->getMeshResX();
+}
+int manta_liquid_get_mesh_res_y(MANTA *liquid)
+{
+ return liquid->getMeshResY();
+}
+int manta_liquid_get_mesh_res_z(MANTA *liquid)
+{
+ return liquid->getMeshResZ();
+}
+
+int manta_liquid_get_particle_upres(MANTA *liquid)
+{
+ return liquid->getParticleUpres();
+}
+int manta_liquid_get_mesh_upres(MANTA *liquid)
+{
+ return liquid->getMeshUpres();
+}
+
+int manta_liquid_get_num_verts(MANTA *liquid)
+{
+ return liquid->getNumVertices();
+}
+int manta_liquid_get_num_normals(MANTA *liquid)
+{
+ return liquid->getNumNormals();
+}
+int manta_liquid_get_num_triangles(MANTA *liquid)
+{
+ return liquid->getNumTriangles();
+}
+
+float manta_liquid_get_vertex_x_at(MANTA *liquid, int i)
+{
+ return liquid->getVertexXAt(i);
+}
+float manta_liquid_get_vertex_y_at(MANTA *liquid, int i)
+{
+ return liquid->getVertexYAt(i);
+}
+float manta_liquid_get_vertex_z_at(MANTA *liquid, int i)
+{
+ return liquid->getVertexZAt(i);
+}
+
+float manta_liquid_get_normal_x_at(MANTA *liquid, int i)
+{
+ return liquid->getNormalXAt(i);
+}
+float manta_liquid_get_normal_y_at(MANTA *liquid, int i)
+{
+ return liquid->getNormalYAt(i);
+}
+float manta_liquid_get_normal_z_at(MANTA *liquid, int i)
+{
+ return liquid->getNormalZAt(i);
+}
+
+int manta_liquid_get_triangle_x_at(MANTA *liquid, int i)
+{
+ return liquid->getTriangleXAt(i);
+}
+int manta_liquid_get_triangle_y_at(MANTA *liquid, int i)
+{
+ return liquid->getTriangleYAt(i);
+}
+int manta_liquid_get_triangle_z_at(MANTA *liquid, int i)
+{
+ return liquid->getTriangleZAt(i);
+}
+
+float manta_liquid_get_vertvel_x_at(MANTA *liquid, int i)
+{
+ return liquid->getVertVelXAt(i);
+}
+float manta_liquid_get_vertvel_y_at(MANTA *liquid, int i)
+{
+ return liquid->getVertVelYAt(i);
+}
+float manta_liquid_get_vertvel_z_at(MANTA *liquid, int i)
+{
+ return liquid->getVertVelZAt(i);
+}
+
+int manta_liquid_get_num_flip_particles(MANTA *liquid)
+{
+ return liquid->getNumFlipParticles();
+}
+int manta_liquid_get_num_snd_particles(MANTA *liquid)
+{
+ return liquid->getNumSndParticles();
+}
+
+int manta_liquid_get_flip_particle_flag_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleFlagAt(i);
+}
+int manta_liquid_get_snd_particle_flag_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleFlagAt(i);
+}
+
+float manta_liquid_get_flip_particle_position_x_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticlePositionXAt(i);
+}
+float manta_liquid_get_flip_particle_position_y_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticlePositionYAt(i);
+}
+float manta_liquid_get_flip_particle_position_z_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticlePositionZAt(i);
+}
+
+float manta_liquid_get_flip_particle_velocity_x_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleVelocityXAt(i);
+}
+float manta_liquid_get_flip_particle_velocity_y_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleVelocityYAt(i);
+}
+float manta_liquid_get_flip_particle_velocity_z_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleVelocityZAt(i);
+}
+
+float manta_liquid_get_snd_particle_position_x_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticlePositionXAt(i);
+}
+float manta_liquid_get_snd_particle_position_y_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticlePositionYAt(i);
+}
+float manta_liquid_get_snd_particle_position_z_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticlePositionZAt(i);
+}
+
+float manta_liquid_get_snd_particle_velocity_x_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleVelocityXAt(i);
+}
+float manta_liquid_get_snd_particle_velocity_y_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleVelocityYAt(i);
+}
+float manta_liquid_get_snd_particle_velocity_z_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleVelocityZAt(i);
+}
diff --git a/intern/mantaflow/intern/manta_python_API.cpp b/intern/mantaflow/intern/manta_python_API.cpp
new file mode 100644
index 00000000000..8f7a396410a
--- /dev/null
+++ b/intern/mantaflow/intern/manta_python_API.cpp
@@ -0,0 +1,30 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup mantaflow
+ */
+
+#include "manta_python_API.h"
+#include "manta.h"
+
+PyObject *Manta_initPython(void)
+{
+ return Pb::PyInit_Main();
+}
diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h
new file mode 100644
index 00000000000..565b942c582
--- /dev/null
+++ b/intern/mantaflow/intern/strings/fluid_script.h
@@ -0,0 +1,799 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup mantaflow
+ */
+
+#include <string>
+
+//////////////////////////////////////////////////////////////////////
+// LIBRARIES
+//////////////////////////////////////////////////////////////////////
+
+const std::string manta_import =
+ "\
+from manta import *\n\
+import os.path, shutil, math, sys, gc, multiprocessing, platform, time\n\
+\n\
+withMPBake = False # Bake files asynchronously\n\
+withMPSave = True # Save files asynchronously\n\
+isWindows = platform.system() != 'Darwin' and platform.system() != 'Linux'\n\
+# TODO (sebbas): Use this to simulate Windows multiprocessing (has default mode spawn)\n\
+#try:\n\
+# multiprocessing.set_start_method('spawn')\n\
+#except:\n\
+# pass\n\
+\n\
+bpy = sys.modules.get('bpy')\n\
+if bpy is not None:\n\
+ sys.executable = bpy.app.binary_path_python\n";
+
+//////////////////////////////////////////////////////////////////////
+// DEBUG
+//////////////////////////////////////////////////////////////////////
+
+const std::string manta_debuglevel =
+ "\n\
+def set_manta_debuglevel(level):\n\
+ setDebugLevel(level=level)\n # level 0 = mute all output from manta\n";
+
+//////////////////////////////////////////////////////////////////////
+// SOLVERS
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_solver =
+ "\n\
+mantaMsg('Solver base')\n\
+s$ID$ = Solver(name='solver_base$ID$', gridSize=gs_s$ID$, dim=dim_s$ID$)\n";
+
+const std::string fluid_solver_noise =
+ "\n\
+mantaMsg('Solver noise')\n\
+sn$ID$ = Solver(name='solver_noise$ID$', gridSize=gs_sn$ID$)\n";
+
+const std::string fluid_solver_mesh =
+ "\n\
+mantaMsg('Solver mesh')\n\
+sm$ID$ = Solver(name='solver_mesh$ID$', gridSize=gs_sm$ID$)\n";
+
+const std::string fluid_solver_particles =
+ "\n\
+mantaMsg('Solver particles')\n\
+sp$ID$ = Solver(name='solver_particles$ID$', gridSize=gs_sp$ID$)\n";
+
+const std::string fluid_solver_guiding =
+ "\n\
+mantaMsg('Solver guiding')\n\
+sg$ID$ = Solver(name='solver_guiding$ID$', gridSize=gs_sg$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// VARIABLES
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_variables =
+ "\n\
+mantaMsg('Fluid variables')\n\
+dim_s$ID$ = $SOLVER_DIM$\n\
+res_s$ID$ = $RES$\n\
+gravity_s$ID$ = vec3($GRAVITY_X$, $GRAVITY_Y$, $GRAVITY_Z$)\n\
+gs_s$ID$ = vec3($RESX$, $RESY$, $RESZ$)\n\
+maxVel_s$ID$ = 0\n\
+\n\
+doOpen_s$ID$ = $DO_OPEN$\n\
+boundConditions_s$ID$ = '$BOUND_CONDITIONS$'\n\
+boundaryWidth_s$ID$ = $BOUNDARY_WIDTH$\n\
+\n\
+using_smoke_s$ID$ = $USING_SMOKE$\n\
+using_liquid_s$ID$ = $USING_LIQUID$\n\
+using_noise_s$ID$ = $USING_NOISE$\n\
+using_adaptTime_s$ID$ = $USING_ADAPTIVETIME$\n\
+using_obstacle_s$ID$ = $USING_OBSTACLE$\n\
+using_guiding_s$ID$ = $USING_GUIDING$\n\
+using_fractions_s$ID$ = $USING_FRACTIONS$\n\
+using_invel_s$ID$ = $USING_INVEL$\n\
+using_outflow_s$ID$ = $USING_OUTFLOW$\n\
+using_sndparts_s$ID$ = $USING_SNDPARTS$\n\
+using_speedvectors_s$ID$ = $USING_SPEEDVECTORS$\n\
+\n\
+# Fluid time params\n\
+timeTotal_s$ID$ = $TIME_TOTAL$\n\
+timePerFrame_s$ID$ = $TIME_PER_FRAME$\n\
+frameLength_s$ID$ = $FRAME_LENGTH$\n\
+dt0_s$ID$ = $DT$\n\
+cflCond_s$ID$ = $CFL$\n\
+timestepsMin_s$ID$ = $TIMESTEPS_MIN$\n\
+timestepsMax_s$ID$ = $TIMESTEPS_MAX$\n\
+\n\
+# Fluid diffusion / viscosity\n\
+domainSize_s$ID$ = $FLUID_DOMAIN_SIZE$ # longest domain side in meters\n\
+viscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\
+\n\
+# Factor to convert blender velocities to manta velocities\n\
+toMantaUnitsFac_s$ID$ = (1.0 / (1.0 / res_s$ID$))\n # = dt/dx * 1/dt ";
+
+const std::string fluid_variables_noise =
+ "\n\
+mantaMsg('Fluid variables noise')\n\
+upres_sn$ID$ = $NOISE_SCALE$\n\
+gs_sn$ID$ = vec3(upres_sn$ID$*gs_s$ID$.x, upres_sn$ID$*gs_s$ID$.y, upres_sn$ID$*gs_s$ID$.z)\n";
+
+const std::string fluid_variables_mesh =
+ "\n\
+mantaMsg('Fluid variables mesh')\n\
+upres_sm$ID$ = $MESH_SCALE$\n\
+gs_sm$ID$ = vec3(upres_sm$ID$*gs_s$ID$.x, upres_sm$ID$*gs_s$ID$.y, upres_sm$ID$*gs_s$ID$.z)\n";
+
+const std::string fluid_variables_particles =
+ "\n\
+mantaMsg('Fluid variables particles')\n\
+upres_sp$ID$ = $PARTICLE_SCALE$\n\
+gs_sp$ID$ = vec3(upres_sp$ID$*gs_s$ID$.x, upres_sp$ID$*gs_s$ID$.y, upres_sp$ID$*gs_s$ID$.z)\n";
+
+const std::string fluid_variables_guiding =
+ "\n\
+mantaMsg('Fluid variables guiding')\n\
+gs_sg$ID$ = vec3($GUIDING_RESX$, $GUIDING_RESY$, $GUIDING_RESZ$)\n\
+\n\
+alpha_sg$ID$ = $GUIDING_ALPHA$\n\
+beta_sg$ID$ = $GUIDING_BETA$\n\
+gamma_sg$ID$ = $GUIDING_FACTOR$\n\
+tau_sg$ID$ = 1.0\n\
+sigma_sg$ID$ = 0.99/tau_sg$ID$\n\
+theta_sg$ID$ = 1.0\n";
+
+const std::string fluid_with_obstacle =
+ "\n\
+using_obstacle_s$ID$ = True\n";
+
+const std::string fluid_with_guiding =
+ "\n\
+using_guiding_s$ID$ = True\n";
+
+const std::string fluid_with_fractions =
+ "\n\
+using_fractions_s$ID$ = True\n";
+
+const std::string fluid_with_invel =
+ "\n\
+using_invel_s$ID$ = True\n";
+
+const std::string fluid_with_outflow =
+ "\n\
+using_outflow_s$ID$ = True\n";
+
+const std::string fluid_with_sndparts =
+ "\n\
+using_sndparts_s$ID$ = True\n";
+
+//////////////////////////////////////////////////////////////////////
+// ADAPTIVE TIME STEPPING
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_time_stepping =
+ "\n\
+mantaMsg('Fluid adaptive time stepping')\n\
+s$ID$.frameLength = frameLength_s$ID$\n\
+s$ID$.timestepMin = s$ID$.frameLength / max(1, timestepsMax_s$ID$)\n\
+s$ID$.timestepMax = s$ID$.frameLength / max(1, timestepsMin_s$ID$)\n\
+s$ID$.cfl = cflCond_s$ID$\n\
+s$ID$.timePerFrame = timePerFrame_s$ID$\n\
+s$ID$.timestep = dt0_s$ID$\n\
+s$ID$.timeTotal = timeTotal_s$ID$\n\
+#mantaMsg('timestep: ' + str(s$ID$.timestep) + ' // timPerFrame: ' + str(s$ID$.timePerFrame) + ' // frameLength: ' + str(s$ID$.frameLength) + ' // timeTotal: ' + str(s$ID$.timeTotal) )\n";
+
+const std::string fluid_adapt_time_step =
+ "\n\
+def fluid_adapt_time_step_$ID$():\n\
+ mantaMsg('Fluid adapt time step')\n\
+ \n\
+ # time params are animatable\n\
+ s$ID$.frameLength = frameLength_s$ID$\n\
+ s$ID$.cfl = cflCond_s$ID$\n\
+ \n\
+ # ensure that vel grid is full (remember: adaptive domain can reallocate solver)\n\
+ copyRealToVec3(sourceX=x_vel_s$ID$, sourceY=y_vel_s$ID$, sourceZ=z_vel_s$ID$, target=vel_s$ID$)\n\
+ maxVel_s$ID$ = vel_s$ID$.getMax() if vel_s$ID$ else 0\n\
+ if using_adaptTime_s$ID$:\n\
+ mantaMsg('Adapt timestep, maxvel: ' + str(maxVel_s$ID$))\n\
+ s$ID$.adaptTimestep(maxVel_s$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// GRIDS
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_alloc =
+ "\n\
+mantaMsg('Fluid alloc data')\n\
+flags_s$ID$ = s$ID$.create(FlagGrid)\n\
+vel_s$ID$ = s$ID$.create(MACGrid)\n\
+velC_s$ID$ = s$ID$.create(MACGrid)\n\
+x_vel_s$ID$ = s$ID$.create(RealGrid)\n\
+y_vel_s$ID$ = s$ID$.create(RealGrid)\n\
+z_vel_s$ID$ = s$ID$.create(RealGrid)\n\
+pressure_s$ID$ = s$ID$.create(RealGrid)\n\
+phiObs_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+phiIn_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+phiOut_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+forces_s$ID$ = s$ID$.create(Vec3Grid)\n\
+x_force_s$ID$ = s$ID$.create(RealGrid)\n\
+y_force_s$ID$ = s$ID$.create(RealGrid)\n\
+z_force_s$ID$ = s$ID$.create(RealGrid)\n\
+obvel_s$ID$ = None\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+fluid_data_dict_s$ID$ = dict(vel=vel_s$ID$, phiObs=phiObs_s$ID$, phiIn=phiIn_s$ID$, phiOut=phiOut_s$ID$, flags=flags_s$ID$)\n";
+
+const std::string fluid_alloc_obstacle =
+ "\n\
+mantaMsg('Allocating obstacle data')\n\
+numObs_s$ID$ = s$ID$.create(IntGrid)\n\
+phiObsIn_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+obvel_s$ID$ = s$ID$.create(MACGrid)\n\
+obvelC_s$ID$ = s$ID$.create(Vec3Grid)\n\
+x_obvel_s$ID$ = s$ID$.create(RealGrid)\n\
+y_obvel_s$ID$ = s$ID$.create(RealGrid)\n\
+z_obvel_s$ID$ = s$ID$.create(RealGrid)\n\
+\n\
+tmpDict_s$ID$ = dict(phiObsIn=phiObsIn_s$ID$)\n\
+fluid_data_dict_s$ID$.update(tmpDict_s$ID$)\n";
+
+const std::string fluid_alloc_guiding =
+ "\n\
+mantaMsg('Allocating guiding data')\n\
+velT_s$ID$ = s$ID$.create(MACGrid)\n\
+weightGuide_s$ID$ = s$ID$.create(RealGrid)\n\
+numGuides_s$ID$ = s$ID$.create(IntGrid)\n\
+phiGuideIn_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+guidevelC_s$ID$ = s$ID$.create(Vec3Grid)\n\
+x_guidevel_s$ID$ = s$ID$.create(RealGrid)\n\
+y_guidevel_s$ID$ = s$ID$.create(RealGrid)\n\
+z_guidevel_s$ID$ = s$ID$.create(RealGrid)\n\
+\n\
+# Final guide vel grid needs to have independent size\n\
+guidevel_sg$ID$ = sg$ID$.create(MACGrid)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+fluid_guiding_dict_s$ID$ = dict(guidevel=guidevel_sg$ID$)\n";
+
+const std::string fluid_alloc_fractions =
+ "\n\
+mantaMsg('Allocating fractions data')\n\
+fractions_s$ID$ = s$ID$.create(MACGrid)\n";
+
+const std::string fluid_alloc_invel =
+ "\n\
+mantaMsg('Allocating initial velocity data')\n\
+invelC_s$ID$ = s$ID$.create(VecGrid)\n\
+invel_s$ID$ = s$ID$.create(MACGrid)\n\
+x_invel_s$ID$ = s$ID$.create(RealGrid)\n\
+y_invel_s$ID$ = s$ID$.create(RealGrid)\n\
+z_invel_s$ID$ = s$ID$.create(RealGrid)\n";
+
+const std::string fluid_alloc_outflow =
+ "\n\
+mantaMsg('Allocating outflow data')\n\
+phiOutIn_s$ID$ = s$ID$.create(LevelsetGrid)\n";
+
+const std::string fluid_alloc_sndparts =
+ "\n\
+mantaMsg('Allocating snd parts low')\n\
+ppSnd_sp$ID$ = sp$ID$.create(BasicParticleSystem)\n\
+pVelSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataVec3)\n\
+pForceSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataVec3)\n\
+pLifeSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataReal)\n\
+vel_sp$ID$ = sp$ID$.create(MACGrid)\n\
+flags_sp$ID$ = sp$ID$.create(FlagGrid)\n\
+phi_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
+phiIn_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
+phiObs_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
+phiObsIn_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+fluid_particles_dict_s$ID$ = dict(ppSnd=ppSnd_sp$ID$, pVelSnd=pVelSnd_pp$ID$, pLifeSnd=pLifeSnd_pp$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// PRE / POST STEP
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_pre_step =
+ "\n\
+def fluid_pre_step_$ID$():\n\
+ mantaMsg('Fluid pre step')\n\
+ \n\
+ phiObs_s$ID$.setConst(9999)\n\
+ phiOut_s$ID$.setConst(9999)\n\
+ \n\
+ # Main vel grid is copied in adapt time step function\n\
+ \n\
+ # translate obvels (world space) to grid space\n\
+ if using_obstacle_s$ID$:\n\
+ x_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ y_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ z_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ copyRealToVec3(sourceX=x_obvel_s$ID$, sourceY=y_obvel_s$ID$, sourceZ=z_obvel_s$ID$, target=obvelC_s$ID$)\n\
+ \n\
+ # translate invels (world space) to grid space\n\
+ if using_invel_s$ID$:\n\
+ x_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ y_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ z_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ copyRealToVec3(sourceX=x_invel_s$ID$, sourceY=y_invel_s$ID$, sourceZ=z_invel_s$ID$, target=invelC_s$ID$)\n\
+ \n\
+ if using_guiding_s$ID$:\n\
+ weightGuide_s$ID$.multConst(0)\n\
+ weightGuide_s$ID$.addConst(alpha_sg$ID$)\n\
+ interpolateMACGrid(source=guidevel_sg$ID$, target=velT_s$ID$)\n\
+ velT_s$ID$.multConst(vec3(gamma_sg$ID$))\n\
+ \n\
+ # translate external forces (world space) to grid space\n\
+ x_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ y_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ z_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ copyRealToVec3(sourceX=x_force_s$ID$, sourceY=y_force_s$ID$, sourceZ=z_force_s$ID$, target=forces_s$ID$)\n\
+ \n\
+ # If obstacle has velocity, i.e. is a moving obstacle, switch to dynamic preconditioner\n\
+ if using_smoke_s$ID$ and using_obstacle_s$ID$ and obvelC_s$ID$.getMax() > 0:\n\
+ mantaMsg('Using dynamic preconditioner')\n\
+ preconditioner_s$ID$ = PcMGDynamic\n\
+ else:\n\
+ mantaMsg('Using static preconditioner')\n\
+ preconditioner_s$ID$ = PcMGStatic\n";
+
+const std::string fluid_post_step =
+ "\n\
+def fluid_post_step_$ID$():\n\
+ mantaMsg('Fluid post step')\n\
+ forces_s$ID$.clear()\n\
+ x_force_s$ID$.clear()\n\
+ y_force_s$ID$.clear()\n\
+ z_force_s$ID$.clear()\n\
+ \n\
+ if using_guiding_s$ID$:\n\
+ weightGuide_s$ID$.clear()\n\
+ if using_invel_s$ID$:\n\
+ x_invel_s$ID$.clear()\n\
+ y_invel_s$ID$.clear()\n\
+ z_invel_s$ID$.clear()\n\
+ invel_s$ID$.clear()\n\
+ invelC_s$ID$.clear()\n\
+ \n\
+ # Copy vel grid to reals grids (which Blender internal will in turn use for vel access)\n\
+ copyVec3ToReal(source=vel_s$ID$, targetX=x_vel_s$ID$, targetY=y_vel_s$ID$, targetZ=z_vel_s$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// DESTRUCTION
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_delete_all =
+ "\n\
+mantaMsg('Deleting fluid')\n\
+# Clear all helper dictionaries first\n\
+mantaMsg('Clear helper dictionaries')\n\
+if 'liquid_data_dict_s$ID$' in globals(): liquid_data_dict_s$ID$.clear()\n\
+if 'liquid_flip_dict_s$ID$' in globals(): liquid_flip_dict_s$ID$.clear()\n\
+if 'liquid_mesh_dict_s$ID$' in globals(): liquid_mesh_dict_s$ID$.clear()\n\
+if 'liquid_meshvel_dict_s$ID$' in globals(): liquid_meshvel_dict_s$ID$.clear()\n\
+if 'liquid_particles_dict_s$ID$' in globals(): liquid_particles_dict_s$ID$.clear()\n\
+if 'smoke_data_dict_s$ID$' in globals(): smoke_data_dict_s$ID$.clear()\n\
+if 'smoke_noise_dict_s$ID$' in globals(): smoke_noise_dict_s$ID$.clear()\n\
+if 'fluid_particles_dict_s$ID$' in globals(): fluid_particles_dict_s$ID$.clear()\n\
+if 'fluid_guiding_dict_s$ID$' in globals(): fluid_guiding_dict_s$ID$.clear()\n\
+if 'fluid_data_dict_s$ID$' in globals(): fluid_data_dict_s$ID$.clear()\n\
+if 'fluid_vel_dict_s$ID$' in globals(): fluid_vel_dict_s$ID$.clear()\n\
+\n\
+# Delete all childs from objects (e.g. pdata for particles)\n\
+mantaMsg('Release solver childs childs')\n\
+for var in list(globals()):\n\
+ if var.endswith('_pp$ID$') or var.endswith('_mesh$ID$'):\n\
+ del globals()[var]\n\
+\n\
+# Now delete childs from solver objects\n\
+mantaMsg('Release solver childs')\n\
+for var in list(globals()):\n\
+ if var.endswith('_s$ID$') or var.endswith('_sn$ID$') or var.endswith('_sm$ID$') or var.endswith('_sp$ID$') or var.endswith('_sg$ID$'):\n\
+ del globals()[var]\n\
+\n\
+# Extra cleanup for multigrid and fluid guiding\n\
+mantaMsg('Release multigrid')\n\
+if 's$ID$' in globals(): releaseMG(s$ID$)\n\
+if 'sn$ID$' in globals(): releaseMG(sn$ID$)\n\
+mantaMsg('Release fluid guiding')\n\
+releaseBlurPrecomp()\n\
+\n\
+# Release unreferenced memory (if there is some left, can in fact happen)\n\
+gc.collect()\n\
+\n\
+# Now it is safe to delete solver objects (always need to be deleted last)\n\
+mantaMsg('Delete base solver')\n\
+if 's$ID$' in globals(): del s$ID$\n\
+mantaMsg('Delete noise solver')\n\
+if 'sn$ID$' in globals(): del sn$ID$\n\
+mantaMsg('Delete mesh solver')\n\
+if 'sm$ID$' in globals(): del sm$ID$\n\
+mantaMsg('Delete particle solver')\n\
+if 'sp$ID$' in globals(): del sp$ID$\n\
+mantaMsg('Delete guiding solver')\n\
+if 'sg$ID$' in globals(): del sg$ID$\n\
+\n\
+# Release unreferenced memory (if there is some left)\n\
+gc.collect()\n";
+
+//////////////////////////////////////////////////////////////////////
+// BAKE
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_cache_helper =
+ "\n\
+def fluid_cache_get_framenr_formatted_$ID$(framenr):\n\
+ return str(framenr).zfill(4) # framenr with leading zeroes\n";
+
+const std::string fluid_bake_multiprocessing =
+ "\n\
+def fluid_cache_multiprocessing_start_$ID$(function, framenr, format_data=None, format_noise=None, format_mesh=None, format_particles=None, format_guiding=None, path_data=None, path_noise=None, path_mesh=None, path_particles=None, path_guiding=None, dict=None, do_join=True):\n\
+ mantaMsg('Multiprocessing cache')\n\
+ if __name__ == '__main__':\n\
+ args = (framenr,)\n\
+ if format_data:\n\
+ args += (format_data,)\n\
+ if format_noise:\n\
+ args += (format_noise,)\n\
+ if format_mesh:\n\
+ args += (format_mesh,)\n\
+ if format_particles:\n\
+ args += (format_particles,)\n\
+ if format_guiding:\n\
+ args += (format_guiding,)\n\
+ if path_data:\n\
+ args += (path_data,)\n\
+ if path_noise:\n\
+ args += (path_noise,)\n\
+ if path_mesh:\n\
+ args += (path_mesh,)\n\
+ if path_particles:\n\
+ args += (path_particles,)\n\
+ if path_guiding:\n\
+ args += (path_guiding,)\n\
+ if dict:\n\
+ args += (dict,)\n\
+ p$ID$ = multiprocessing.Process(target=function, args=args)\n\
+ p$ID$.start()\n\
+ if do_join:\n\
+ p$ID$.join()\n";
+
+const std::string fluid_bake_data =
+ "\n\
+def bake_fluid_process_data_$ID$(framenr, format_data, format_particles, format_guiding, path_data, path_guiding):\n\
+ mantaMsg('Bake fluid data')\n\
+ \n\
+ s$ID$.frame = framenr\n\
+ # Must not set 'timeTotal' here. Remember, this function is called from manta.c while-loop\n\
+ \n\
+ start_time = time.time()\n\
+ if using_smoke_s$ID$:\n\
+ smoke_adaptive_step_$ID$(framenr)\n\
+ if using_liquid_s$ID$:\n\
+ liquid_adaptive_step_$ID$(framenr)\n\
+ mantaMsg('--- Step: %s seconds ---' % (time.time() - start_time))\n\
+\n\
+def bake_fluid_data_$ID$(path_data, path_guiding, framenr, format_data, format_particles, format_guiding):\n\
+ if not withMPBake or isWindows:\n\
+ bake_fluid_process_data_$ID$(framenr, format_data, format_particles, format_guiding, path_data, path_guiding)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=bake_fluid_process_data_$ID$, framenr=framenr, format_data=format_data, format_particles=format_particles, format_guiding=format_guiding, path_data=path_data, path_guiding=path_guiding, do_join=False)\n";
+
+const std::string fluid_bake_noise =
+ "\n\
+def bake_noise_process_$ID$(framenr, format_data, format_noise, path_data, path_noise):\n\
+ mantaMsg('Bake fluid noise')\n\
+ \n\
+ sn$ID$.frame = framenr\n\
+ sn$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\
+ sn$ID$.timestep = dt0_s$ID$\n\
+ mantaMsg('sn$ID$.timeTotal: ' + str(sn$ID$.timeTotal))\n\
+ \n\
+ smoke_step_noise_$ID$(framenr)\n\
+ smoke_save_noise_$ID$(path_noise, framenr, format_noise)\n\
+\n\
+def bake_noise_$ID$(path_data, path_noise, framenr, format_data, format_noise):\n\
+ if not withMPBake or isWindows:\n\
+ bake_noise_process_$ID$(framenr, format_data, format_noise, path_data, path_noise)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=bake_noise_process_$ID$, framenr=framenr, format_data=format_data, format_noise=format_noise, path_data=path_data, path_noise=path_noise)\n";
+
+const std::string fluid_bake_mesh =
+ "\n\
+def bake_mesh_process_$ID$(framenr, format_data, format_mesh, format_particles, path_data, path_mesh):\n\
+ mantaMsg('Bake fluid mesh')\n\
+ \n\
+ sm$ID$.frame = framenr\n\
+ sm$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\
+ sm$ID$.timestep = dt0_s$ID$\n\
+ \n\
+ #if using_smoke_s$ID$:\n\
+ # TODO (sebbas): Future update could include smoke mesh (vortex sheets)\n\
+ if using_liquid_s$ID$:\n\
+ liquid_step_mesh_$ID$()\n\
+ liquid_save_mesh_$ID$(path_mesh, framenr, format_mesh)\n\
+ if using_speedvectors_s$ID$:\n\
+ liquid_save_meshvel_$ID$(path_mesh, framenr, format_data)\n\
+\n\
+def bake_mesh_$ID$(path_data, path_mesh, framenr, format_data, format_mesh, format_particles):\n\
+ if not withMPBake or isWindows:\n\
+ bake_mesh_process_$ID$(framenr, format_data, format_mesh, format_particles, path_data, path_mesh)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=bake_mesh_process_$ID$, framenr=framenr, format_data=format_data, format_mesh=format_mesh, format_particles=format_particles, path_data=path_data, path_mesh=path_mesh)\n";
+
+const std::string fluid_bake_particles =
+ "\n\
+def bake_particles_process_$ID$(framenr, format_data, format_particles, path_data, path_particles):\n\
+ mantaMsg('Bake secondary particles')\n\
+ \n\
+ sp$ID$.frame = framenr\n\
+ sp$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\
+ sp$ID$.timestep = dt0_s$ID$\n\
+ \n\
+ fluid_load_data_$ID$(path_data, framenr, format_data)\n\
+ #if using_smoke_s$ID$:\n\
+ # TODO (sebbas): Future update could include smoke particles (e.g. fire sparks)\n\
+ if using_liquid_s$ID$:\n\
+ liquid_load_data_$ID$(path_data, framenr, format_data)\n\
+ liquid_step_particles_$ID$()\n\
+ fluid_save_particles_$ID$(path_particles, framenr, format_particles)\n\
+ liquid_save_particles_$ID$(path_particles, framenr, format_particles)\n\
+\n\
+def bake_particles_$ID$(path_data, path_particles, framenr, format_data, format_particles):\n\
+ if not withMPBake or isWindows:\n\
+ bake_particles_process_$ID$(framenr, format_data, format_particles, path_data, path_particles)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=bake_particles_process_$ID$, framenr=framenr, format_data=format_data, format_particles=format_particles, path_data=path_data, path_particles=path_particles)\n";
+
+const std::string fluid_bake_guiding =
+ "\n\
+def bake_guiding_process_$ID$(framenr, format_guiding, path_guiding):\n\
+ mantaMsg('Bake fluid guiding')\n\
+ \n\
+ if framenr>1:\n\
+ fluid_load_guiding_$ID$(path_guiding, framenr-1, format_guiding)\n\
+ \n\
+ x_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\
+ y_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\
+ z_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\
+ copyRealToVec3(sourceX=x_guidevel_s$ID$, sourceY=y_guidevel_s$ID$, sourceZ=z_guidevel_s$ID$, target=guidevelC_s$ID$)\n\
+ \n\
+ mantaMsg('Extrapolating guiding velocity')\n\
+ # ensure velocities inside of guiding object, slightly add guiding vels outside of object too\n\
+ extrapolateVec3Simple(vel=guidevelC_s$ID$, phi=phiGuideIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateVec3Simple(vel=guidevelC_s$ID$, phi=phiGuideIn_s$ID$, distance=4, inside=False)\n\
+ resampleVec3ToMac(source=guidevelC_s$ID$, target=guidevel_sg$ID$)\n\
+ \n\
+ fluid_save_guiding_$ID$(path_guiding, framenr, format_guiding)\n\
+\n\
+def bake_guiding_$ID$(path_guiding, framenr, format_guiding):\n\
+ if not withMPBake or isWindows:\n\
+ bake_guiding_process_$ID$(framenr, format_guiding, path_guiding)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=bake_guiding_process_$ID$, framenr=framenr, format_guiding=format_guiding, path_guiding=path_guiding)\n";
+
+//////////////////////////////////////////////////////////////////////
+// IMPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_file_import =
+ "\n\
+def fluid_file_import_s$ID$(dict, path, framenr, file_format):\n\
+ try:\n\
+ framenr = fluid_cache_get_framenr_formatted_$ID$(framenr)\n\
+ for name, object in dict.items():\n\
+ file = os.path.join(path, name + '_' + framenr + file_format)\n\
+ if os.path.isfile(file):\n\
+ object.load(file)\n\
+ else:\n\
+ mantaMsg('Could not load file ' + str(file))\n\
+ except:\n\
+ mantaMsg('exception found')\n\
+ #mantaMsg(str(e))\n\
+ pass # Just skip file load errors for now\n";
+
+const std::string fluid_load_particles =
+ "\n\
+def fluid_load_particles_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid load particles, frame ' + str(framenr))\n\
+ fluid_file_import_s$ID$(dict=fluid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string fluid_load_data =
+ "\n\
+def fluid_load_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid load data, frame ' + str(framenr))\n\
+ fluid_file_import_s$ID$(dict=fluid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ \n\
+ # When adaptive domain bake is resumed we need correct values in xyz vel grids\n\
+ copyVec3ToReal(source=vel_s$ID$, targetX=x_vel_s$ID$, targetY=y_vel_s$ID$, targetZ=z_vel_s$ID$)\n";
+
+const std::string fluid_load_guiding =
+ "\n\
+def fluid_load_guiding_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid load guiding, frame ' + str(framenr))\n\
+ fluid_file_import_s$ID$(dict=fluid_guiding_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string fluid_load_vel =
+ "\n\
+def fluid_load_vel_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid load vel, frame ' + str(framenr))\n\
+ fluid_vel_dict = dict(vel=guidevel_sg$ID$)\n\
+ fluid_file_import_s$ID$(dict=fluid_vel_dict, path=path, framenr=framenr, file_format=file_format)\n";
+
+//////////////////////////////////////////////////////////////////////
+// EXPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_file_export =
+ "\n\
+def fluid_file_export_s$ID$(framenr, file_format, path, dict, mode_override=True, skip_subframes=True):\n\
+ if skip_subframes and ((timePerFrame_s$ID$ + dt0_s$ID$) < frameLength_s$ID$):\n\
+ return\n\
+ mantaMsg('Fluid file export, frame: ' + str(framenr))\n\
+ try:\n\
+ framenr = fluid_cache_get_framenr_formatted_$ID$(framenr)\n\
+ if not os.path.exists(path):\n\
+ os.makedirs(path)\n\
+ for name, object in dict.items():\n\
+ file = os.path.join(path, name + '_' + framenr + file_format)\n\
+ if not os.path.isfile(file) or mode_override: object.save(file)\n\
+ except Exception as e:\n\
+ mantaMsg(str(e))\n\
+ pass # Just skip file save errors for now\n";
+
+const std::string fluid_save_particles =
+ "\n\
+def fluid_save_particles_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save particles, frame ' + str(framenr))\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=fluid_particles_dict_s$ID$, framenr=framenr, file_format=file_format, path=path)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=fluid_particles_dict_s$ID$, do_join=False)\n";
+
+const std::string fluid_save_data =
+ "\n\
+def fluid_save_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid save data, frame ' + str(framenr))\n\
+ start_time = time.time()\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(framenr=framenr, file_format=file_format, path=path, dict=fluid_data_dict_s$ID$)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=fluid_data_dict_s$ID$, do_join=False)\n\
+ mantaMsg('--- Save: %s seconds ---' % (time.time() - start_time))\n";
+
+const std::string fluid_save_guiding =
+ "\n\
+def fluid_save_guiding_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid save guiding, frame ' + str(framenr))\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=fluid_guiding_dict_s$ID$, framenr=framenr, file_format=file_format, path=path)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=fluid_guiding_dict_s$ID$, do_join=False)\n";
+
+//////////////////////////////////////////////////////////////////////
+// STANDALONE MODE
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_standalone =
+ "\n\
+gui = None\n\
+if (GUI):\n\
+ gui=Gui()\n\
+ gui.show()\n\
+ gui.pause()\n\
+\n\
+cache_dir = '$CACHE_DIR$'\n\
+file_format_data = '.uni'\n\
+file_format_noise = '.uni'\n\
+file_format_particles = '.uni'\n\
+file_format_mesh = '.bobj.gz'\n\
+\n\
+# Start and stop for simulation\n\
+current_frame = $CURRENT_FRAME$\n\
+end_frame = $END_FRAME$\n\
+\n\
+# How many frame to load from cache\n\
+from_cache_cnt = 100\n\
+\n\
+loop_cnt = 0\n\
+while current_frame <= end_frame:\n\
+ \n\
+ # Load already simulated data from cache:\n\
+ if loop_cnt < from_cache_cnt:\n\
+ load(current_frame)\n\
+ \n\
+ # Otherwise simulate new data\n\
+ else:\n\
+ while(s$ID$.frame <= current_frame):\n\
+ if using_adaptTime_s$ID$:\n\
+ fluid_adapt_time_step_$ID$()\n\
+ step(current_frame)\n\
+ \n\
+ current_frame += 1\n\
+ loop_cnt += 1\n\
+ \n\
+ if gui:\n\
+ gui.pause()\n";
+
+//////////////////////////////////////////////////////////////////////
+// SCRIPT SECTION HEADERS
+//////////////////////////////////////////////////////////////////////
+
+const std::string header_libraries =
+ "\n\
+######################################################################\n\
+## LIBRARIES\n\
+######################################################################\n";
+
+const std::string header_main =
+ "\n\
+######################################################################\n\
+## MAIN\n\
+######################################################################\n";
+
+const std::string header_prepost =
+ "\n\
+######################################################################\n\
+## PRE/POST STEPS\n\
+######################################################################\n";
+
+const std::string header_steps =
+ "\n\
+######################################################################\n\
+## STEPS\n\
+######################################################################\n";
+
+const std::string header_import =
+ "\n\
+######################################################################\n\
+## IMPORT\n\
+######################################################################\n";
+
+const std::string header_grids =
+ "\n\
+######################################################################\n\
+## GRIDS\n\
+######################################################################\n";
+
+const std::string header_solvers =
+ "\n\
+######################################################################\n\
+## SOLVERS\n\
+######################################################################\n";
+
+const std::string header_variables =
+ "\n\
+######################################################################\n\
+## VARIABLES\n\
+######################################################################\n";
+
+const std::string header_time =
+ "\n\
+######################################################################\n\
+## ADAPTIVE TIME\n\
+######################################################################\n";
+
+const std::string header_gridinit =
+ "\n\
+######################################################################\n\
+## DOMAIN INIT\n\
+######################################################################\n";
diff --git a/intern/mantaflow/intern/strings/liquid_script.h b/intern/mantaflow/intern/strings/liquid_script.h
new file mode 100644
index 00000000000..fc516201e87
--- /dev/null
+++ b/intern/mantaflow/intern/strings/liquid_script.h
@@ -0,0 +1,455 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup mantaflow
+ */
+
+#include <string>
+
+//////////////////////////////////////////////////////////////////////
+// VARIABLES
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_variables =
+ "\n\
+mantaMsg('Liquid variables')\n\
+narrowBandWidth_s$ID$ = 3\n\
+combineBandWidth_s$ID$ = narrowBandWidth_s$ID$ - 1\n\
+adjustedNarrowBandWidth_s$ID$ = $PARTICLE_BAND_WIDTH$ # only used in adjustNumber to control band width\n\
+particleNumber_s$ID$ = $PARTICLE_NUMBER$\n\
+minParticles_s$ID$ = $PARTICLE_MINIMUM$\n\
+maxParticles_s$ID$ = $PARTICLE_MAXIMUM$\n\
+radiusFactor_s$ID$ = $PARTICLE_RADIUS$\n\
+using_mesh_s$ID$ = $USING_MESH$\n\
+using_final_mesh_s$ID$ = $USING_IMPROVED_MESH$\n\
+using_fractions_s$ID$ = $USING_FRACTIONS$\n\
+fracThreshold_s$ID$ = $FRACTIONS_THRESHOLD$\n\
+flipRatio_s$ID$ = $FLIP_RATIO$\n\
+concaveUpper_s$ID$ = $MESH_CONCAVE_UPPER$\n\
+concaveLower_s$ID$ = $MESH_CONCAVE_LOWER$\n\
+meshRadiusFactor_s$ID$ = $MESH_PARTICLE_RADIUS$\n\
+smoothenPos_s$ID$ = $MESH_SMOOTHEN_POS$\n\
+smoothenNeg_s$ID$ = $MESH_SMOOTHEN_NEG$\n\
+randomness_s$ID$ = $PARTICLE_RANDOMNESS$\n\
+surfaceTension_s$ID$ = $LIQUID_SURFACE_TENSION$\n";
+
+const std::string liquid_variables_particles =
+ "\n\
+tauMin_wc_sp$ID$ = $SNDPARTICLE_TAU_MIN_WC$\n\
+tauMax_wc_sp$ID$ = $SNDPARTICLE_TAU_MAX_WC$\n\
+tauMin_ta_sp$ID$ = $SNDPARTICLE_TAU_MIN_TA$\n\
+tauMax_ta_sp$ID$ = $SNDPARTICLE_TAU_MAX_TA$\n\
+tauMin_k_sp$ID$ = $SNDPARTICLE_TAU_MIN_K$\n\
+tauMax_k_sp$ID$ = $SNDPARTICLE_TAU_MAX_K$\n\
+k_wc_sp$ID$ = $SNDPARTICLE_K_WC$\n\
+k_ta_sp$ID$ = $SNDPARTICLE_K_TA$\n\
+k_b_sp$ID$ = $SNDPARTICLE_K_B$\n\
+k_d_sp$ID$ = $SNDPARTICLE_K_D$\n\
+lMin_sp$ID$ = $SNDPARTICLE_L_MIN$\n\
+lMax_sp$ID$ = $SNDPARTICLE_L_MAX$\n\
+c_s_sp$ID$ = 0.4 # classification constant for snd parts\n\
+c_b_sp$ID$ = 0.77 # classification constant for snd parts\n\
+pot_radius_sp$ID$ = $SNDPARTICLE_POTENTIAL_RADIUS$\n\
+update_radius_sp$ID$ = $SNDPARTICLE_UPDATE_RADIUS$\n\
+scaleFromManta_sp$ID$ = $FLUID_DOMAIN_SIZE$ / float(res_s$ID$) # resize factor for snd parts\n";
+
+//////////////////////////////////////////////////////////////////////
+// GRIDS & MESH & PARTICLESYSTEM
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_alloc =
+ "\n\
+mantaMsg('Liquid alloc')\n\
+phiParts_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+phi_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+phiTmp_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+curvature_s$ID$ = s$ID$.create(RealGrid)\n\
+velOld_s$ID$ = s$ID$.create(MACGrid)\n\
+velParts_s$ID$ = s$ID$.create(MACGrid)\n\
+mapWeights_s$ID$ = s$ID$.create(MACGrid)\n\
+fractions_s$ID$ = None # allocated dynamically\n\
+\n\
+pp_s$ID$ = s$ID$.create(BasicParticleSystem)\n\
+pVel_pp$ID$ = pp_s$ID$.create(PdataVec3)\n\
+\n\
+# Acceleration data for particle nbs\n\
+pindex_s$ID$ = s$ID$.create(ParticleIndexSystem)\n\
+gpi_s$ID$ = s$ID$.create(IntGrid)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+liquid_data_dict_s$ID$ = dict(phiParts=phiParts_s$ID$, phi=phi_s$ID$, phiTmp=phiTmp_s$ID$)\n\
+liquid_flip_dict_s$ID$ = dict(pp=pp_s$ID$, pVel=pVel_pp$ID$)\n";
+
+const std::string liquid_alloc_mesh =
+ "\n\
+mantaMsg('Liquid alloc mesh')\n\
+phiParts_sm$ID$ = sm$ID$.create(LevelsetGrid)\n\
+phi_sm$ID$ = sm$ID$.create(LevelsetGrid)\n\
+pp_sm$ID$ = sm$ID$.create(BasicParticleSystem)\n\
+flags_sm$ID$ = sm$ID$.create(FlagGrid)\n\
+mesh_sm$ID$ = sm$ID$.create(Mesh)\n\
+\n\
+if using_speedvectors_s$ID$:\n\
+ mVel_mesh$ID$ = mesh_sm$ID$.create(MdataVec3)\n\
+ vel_sm$ID$ = sm$ID$.create(MACGrid)\n\
+\n\
+# Acceleration data for particle nbs\n\
+pindex_sm$ID$ = sm$ID$.create(ParticleIndexSystem)\n\
+gpi_sm$ID$ = sm$ID$.create(IntGrid)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+liquid_mesh_dict_s$ID$ = dict(lMesh=mesh_sm$ID$)\n\
+\n\
+if using_speedvectors_s$ID$:\n\
+ liquid_meshvel_dict_s$ID$ = dict(lVelMesh=mVel_mesh$ID$)\n";
+
+const std::string liquid_alloc_particles =
+ "\n\
+normal_sp$ID$ = sp$ID$.create(VecGrid)\n\
+neighborRatio_sp$ID$ = sp$ID$.create(RealGrid)\n\
+trappedAir_sp$ID$ = sp$ID$.create(RealGrid)\n\
+waveCrest_sp$ID$ = sp$ID$.create(RealGrid)\n\
+kineticEnergy_sp$ID$ = sp$ID$.create(RealGrid)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+liquid_particles_dict_s$ID$ = dict(trappedAir=trappedAir_sp$ID$, waveCrest=waveCrest_sp$ID$, kineticEnergy=kineticEnergy_sp$ID$)\n";
+
+const std::string liquid_init_phi =
+ "\n\
+# Prepare domain\n\
+phi_s$ID$.initFromFlags(flags_s$ID$)\n\
+phiIn_s$ID$.initFromFlags(flags_s$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// STEP FUNCTIONS
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_adaptive_step =
+ "\n\
+def liquid_adaptive_step_$ID$(framenr):\n\
+ mantaMsg('Manta step, frame ' + str(framenr))\n\
+ s$ID$.frame = framenr\n\
+ \n\
+ fluid_pre_step_$ID$()\n\
+ \n\
+ flags_s$ID$.initDomain(boundaryWidth=1 if using_fractions_s$ID$ else 0, phiWalls=phiObs_s$ID$, outflow=boundConditions_s$ID$)\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ mantaMsg('Initializing obstacle levelset')\n\
+ phiObsIn_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\
+ extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ phiObs_s$ID$.join(phiObsIn_s$ID$)\n\
+ \n\
+ # Using boundaryWidth=2 to not search beginning from walls (just a performance optimization)\n\
+ # Additional sanity check: fill holes in phiObs which can result after joining with phiObsIn\n\
+ phiObs_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ \n\
+ mantaMsg('Initializing fluid levelset')\n\
+ extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ phi_s$ID$.join(phiIn_s$ID$)\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ phi_s$ID$.subtract(phiObsIn_s$ID$)\n\
+ \n\
+ if using_outflow_s$ID$:\n\
+ phiOut_s$ID$.join(phiOutIn_s$ID$)\n\
+ \n\
+ if using_fractions_s$ID$:\n\
+ updateFractions(flags=flags_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$, boundaryWidth=boundaryWidth_s$ID$, fracThreshold=fracThreshold_s$ID$)\n\
+ setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, fractions=fractions_s$ID$, phiIn=phiIn_s$ID$)\n\
+ \n\
+ # add initial velocity: set invel as source grid to ensure const vels in inflow region, sampling makes use of this\n\
+ if using_invel_s$ID$:\n\
+ extrapolateVec3Simple(vel=invelC_s$ID$, phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ resampleVec3ToMac(source=invelC_s$ID$, target=invel_s$ID$)\n\
+ pVel_pp$ID$.setSource(invel_s$ID$, isMAC=True)\n\
+ \n\
+ sampleLevelsetWithParticles(phi=phiIn_s$ID$, flags=flags_s$ID$, parts=pp_s$ID$, discretization=particleNumber_s$ID$, randomness=randomness_s$ID$)\n\
+ flags_s$ID$.updateFromLevelset(phi_s$ID$)\n\
+ \n\
+ mantaMsg('Liquid step / s$ID$.frame: ' + str(s$ID$.frame))\n\
+ liquid_step_$ID$()\n\
+ \n\
+ s$ID$.step()\n\
+ \n\
+ fluid_post_step_$ID$()\n";
+
+const std::string liquid_step =
+ "\n\
+def liquid_step_$ID$():\n\
+ mantaMsg('Liquid step')\n\
+ \n\
+ mantaMsg('Advecting particles')\n\
+ pp_s$ID$.advectInGrid(flags=flags_s$ID$, vel=vel_s$ID$, integrationMode=IntRK4, deleteInObstacle=False, stopInObstacle=False)\n\
+ \n\
+ mantaMsg('Pushing particles out of obstacles')\n\
+ pushOutofObs(parts=pp_s$ID$, flags=flags_s$ID$, phiObs=phiObs_s$ID$)\n\
+ \n\
+ mantaMsg('Advecting phi')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=phi_s$ID$, order=1) # first order is usually enough\n\
+ mantaMsg('Advecting velocity')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=vel_s$ID$, order=2)\n\
+ \n\
+ phiTmp_s$ID$.copyFrom(phi_s$ID$) # save original phi for later use in mesh creation\n\
+ \n\
+ # create level set of particles\n\
+ gridParticleIndex(parts=pp_s$ID$, flags=flags_s$ID$, indexSys=pindex_s$ID$, index=gpi_s$ID$)\n\
+ unionParticleLevelset(parts=pp_s$ID$, indexSys=pindex_s$ID$, flags=flags_s$ID$, index=gpi_s$ID$, phi=phiParts_s$ID$, radiusFactor=radiusFactor_s$ID$)\n\
+ \n\
+ # combine level set of particles with grid level set\n\
+ phi_s$ID$.addConst(1.) # shrink slightly\n\
+ phi_s$ID$.join(phiParts_s$ID$)\n\
+ extrapolateLsSimple(phi=phi_s$ID$, distance=narrowBandWidth_s$ID$+2, inside=True)\n\
+ extrapolateLsSimple(phi=phi_s$ID$, distance=3)\n\
+ phi_s$ID$.setBoundNeumann(0) # make sure no particles are placed at outer boundary\n\
+ \n\
+ if doOpen_s$ID$ or using_outflow_s$ID$:\n\
+ resetOutflow(flags=flags_s$ID$, phi=phi_s$ID$, parts=pp_s$ID$, index=gpi_s$ID$, indexSys=pindex_s$ID$)\n\
+ flags_s$ID$.updateFromLevelset(phi_s$ID$)\n\
+ \n\
+ # combine particles velocities with advected grid velocities\n\
+ mapPartsToMAC(vel=velParts_s$ID$, flags=flags_s$ID$, velOld=velOld_s$ID$, parts=pp_s$ID$, partVel=pVel_pp$ID$, weight=mapWeights_s$ID$)\n\
+ extrapolateMACFromWeight(vel=velParts_s$ID$, distance=2, weight=mapWeights_s$ID$)\n\
+ combineGridVel(vel=velParts_s$ID$, weight=mapWeights_s$ID$, combineVel=vel_s$ID$, phi=phi_s$ID$, narrowBand=combineBandWidth_s$ID$, thresh=0)\n\
+ velOld_s$ID$.copyFrom(vel_s$ID$)\n\
+ \n\
+ # forces & pressure solve\n\
+ addGravity(flags=flags_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$)\n\
+ \n\
+ mantaMsg('Adding external forces')\n\
+ addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ mantaMsg('Extrapolating object velocity')\n\
+ # ensure velocities inside of obs object, slightly add obvels outside of obs object\n\
+ extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=3, inside=False)\n\
+ resampleVec3ToMac(source=obvelC_s$ID$, target=obvel_s$ID$)\n\
+ \n\
+ extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=2, intoObs=True if using_fractions_s$ID$ else False)\n\
+ \n\
+ # vel diffusion / viscosity!\n\
+ if viscosity_s$ID$ > 0.:\n\
+ mantaMsg('Viscosity')\n\
+ # diffusion param for solve = const * dt / dx^2\n\
+ alphaV = viscosity_s$ID$ * s$ID$.timestep * float(res_s$ID$*res_s$ID$)\n\
+ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
+ cgSolveDiffusion(flags_s$ID$, vel_s$ID$, alphaV)\n\
+ \n\
+ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
+ \n\
+ mantaMsg('Calculating curvature')\n\
+ getLaplacian(laplacian=curvature_s$ID$, grid=phi_s$ID$)\n\
+ \n\
+ if using_guiding_s$ID$:\n\
+ mantaMsg('Guiding and pressure')\n\
+ PD_fluid_guiding(vel=vel_s$ID$, velT=velT_s$ID$, flags=flags_s$ID$, phi=phi_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, weight=weightGuide_s$ID$, blurRadius=beta_sg$ID$, pressure=pressure_s$ID$, tau=tau_sg$ID$, sigma=sigma_sg$ID$, theta=theta_sg$ID$, zeroPressureFixing=not doOpen_s$ID$)\n\
+ else:\n\
+ mantaMsg('Pressure')\n\
+ solvePressure(flags=flags_s$ID$, vel=vel_s$ID$, pressure=pressure_s$ID$, phi=phi_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, obvel=obvel_s$ID$ if using_fractions_s$ID$ else None)\n\
+ \n\
+ extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=4, intoObs=True if using_fractions_s$ID$ else False)\n\
+ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
+ \n\
+ if not using_fractions_s$ID$:\n\
+ extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=(int(maxVel_s$ID$*1.25)))\n\
+ \n\
+ # set source grids for resampling, used in adjustNumber!\n\
+ pVel_pp$ID$.setSource(vel_s$ID$, isMAC=True)\n\
+ adjustNumber(parts=pp_s$ID$, vel=vel_s$ID$, flags=flags_s$ID$, minParticles=minParticles_s$ID$, maxParticles=maxParticles_s$ID$, phi=phi_s$ID$, exclude=phiObs_s$ID$, radiusFactor=radiusFactor_s$ID$, narrowBand=adjustedNarrowBandWidth_s$ID$)\n\
+ flipVelocityUpdate(vel=vel_s$ID$, velOld=velOld_s$ID$, flags=flags_s$ID$, parts=pp_s$ID$, partVel=pVel_pp$ID$, flipRatio=flipRatio_s$ID$)\n";
+
+const std::string liquid_step_mesh =
+ "\n\
+def liquid_step_mesh_$ID$():\n\
+ mantaMsg('Liquid step mesh')\n\
+ \n\
+ interpolateGrid(target=phi_sm$ID$, source=phiTmp_s$ID$)\n\
+ \n\
+ # create surface\n\
+ pp_sm$ID$.readParticles(pp_s$ID$)\n\
+ gridParticleIndex(parts=pp_sm$ID$, flags=flags_sm$ID$, indexSys=pindex_sm$ID$, index=gpi_sm$ID$)\n\
+ \n\
+ if using_final_mesh_s$ID$:\n\
+ mantaMsg('Liquid using improved particle levelset')\n\
+ improvedParticleLevelset(pp_sm$ID$, pindex_sm$ID$, flags_sm$ID$, gpi_sm$ID$, phiParts_sm$ID$, meshRadiusFactor_s$ID$, smoothenPos_s$ID$, smoothenNeg_s$ID$, concaveLower_s$ID$, concaveUpper_s$ID$)\n\
+ else:\n\
+ mantaMsg('Liquid using union particle levelset')\n\
+ unionParticleLevelset(pp_sm$ID$, pindex_sm$ID$, flags_sm$ID$, gpi_sm$ID$, phiParts_sm$ID$, meshRadiusFactor_s$ID$)\n\
+ \n\
+ phi_sm$ID$.addConst(1.) # shrink slightly\n\
+ phi_sm$ID$.join(phiParts_sm$ID$)\n\
+ extrapolateLsSimple(phi=phi_sm$ID$, distance=narrowBandWidth_s$ID$+2, inside=True)\n\
+ extrapolateLsSimple(phi=phi_sm$ID$, distance=3)\n\
+ phi_sm$ID$.setBoundNeumann(0) # make sure no particles are placed at outer boundary\n\
+ \n\
+ # Vert vel vector needs to pull data from vel grid with correct dim\n\
+ if using_speedvectors_s$ID$:\n\
+ interpolateMACGrid(target=vel_sm$ID$, source=vel_s$ID$)\n\
+ mVel_mesh$ID$.setSource(vel_sm$ID$, isMAC=True)\n\
+ \n\
+ phi_sm$ID$.setBound(0.5,int(((upres_sm$ID$)*2)-2) )\n\
+ phi_sm$ID$.createMesh(mesh_sm$ID$)\n";
+
+const std::string liquid_step_particles =
+ "\n\
+def liquid_step_particles_$ID$():\n\
+ mantaMsg('Secondary particles step')\n\
+ \n\
+ # no upres: just use the loaded grids\n\
+ if upres_sp$ID$ <= 1:\n\
+ flags_sp$ID$.copyFrom(flags_s$ID$)\n\
+ vel_sp$ID$.copyFrom(vel_s$ID$)\n\
+ phiObs_sp$ID$.copyFrom(phiObs_s$ID$)\n\
+ phi_sp$ID$.copyFrom(phi_s$ID$)\n\
+ \n\
+ # with upres: recreate grids\n\
+ else:\n\
+ # create highres grids by interpolation\n\
+ interpolateMACGrid(target=vel_sp$ID$, source=vel_s$ID$)\n\
+ interpolateGrid(target=phi_sp$ID$, source=phi_s$ID$)\n\
+ flags_sp$ID$.initDomain(boundaryWidth=boundaryWidth_s$ID$, phiWalls=phiObs_sp$ID$, outflow=boundConditions_s$ID$)\n\
+ flags_sp$ID$.updateFromLevelset(levelset=phi_sp$ID$)\n\
+ \n\
+ # actual secondary simulation\n\
+ #extrapolateLsSimple(phi=phi_sp$ID$, distance=radius+1, inside=True)\n\
+ flipComputeSecondaryParticlePotentials(potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, normal=normal_sp$ID$, phi=phi_sp$ID$, radius=pot_radius_sp$ID$, tauMinTA=tauMin_ta_sp$ID$, tauMaxTA=tauMax_ta_sp$ID$, tauMinWC=tauMin_wc_sp$ID$, tauMaxWC=tauMax_wc_sp$ID$, tauMinKE=tauMin_k_sp$ID$, tauMaxKE=tauMax_k_sp$ID$, scaleFromManta=scaleFromManta_sp$ID$)\n\
+ flipSampleSecondaryParticles(mode='single', flags=flags_sp$ID$, v=vel_sp$ID$, pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, lMin=lMin_sp$ID$, lMax=lMax_sp$ID$, potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, k_ta=k_ta_sp$ID$, k_wc=k_wc_sp$ID$, dt=s$ID$.frameLength)\n\
+ flipUpdateSecondaryParticles(mode='linear', pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, f_sec=pForceSnd_pp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, neighborRatio=neighborRatio_sp$ID$, radius=update_radius_sp$ID$, gravity=gravity_s$ID$, k_b=k_b_sp$ID$, k_d=k_d_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, dt=s$ID$.frameLength)\n\
+ if $SNDPARTICLE_BOUNDARY_PUSHOUT$:\n\
+ pushOutofObs(parts = ppSnd_sp$ID$, flags = flags_sp$ID$, phiObs = phiObs_sp$ID$, shift = 1.0)\n\
+ flipDeleteParticlesInObstacle(pts=ppSnd_sp$ID$, flags=flags_sp$ID$)\n\
+ #debugGridInfo(flags = flags_sp$ID$, grid = trappedAir_sp$ID$, name = 'Trapped Air')\n\
+ #debugGridInfo(flags = flags_sp$ID$, grid = waveCrest_sp$ID$, name = 'Wave Crest')\n\
+ #debugGridInfo(flags = flags_sp$ID$, grid = kineticEnergy_sp$ID$, name = 'Kinetic Energy')\n";
+
+//////////////////////////////////////////////////////////////////////
+// IMPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_load_data =
+ "\n\
+def liquid_load_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid load data')\n\
+ fluid_file_import_s$ID$(dict=liquid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_load_flip =
+ "\n\
+def liquid_load_flip_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid load flip')\n\
+ fluid_file_import_s$ID$(dict=liquid_flip_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_load_mesh =
+ "\n\
+def liquid_load_mesh_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid load mesh')\n\
+ fluid_file_import_s$ID$(dict=liquid_mesh_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_load_meshvel =
+ "\n\
+def liquid_load_meshvel_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid load meshvel')\n\
+ fluid_file_import_s$ID$(dict=liquid_meshvel_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_load_particles =
+ "\n\
+def liquid_load_particles_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid load particles')\n\
+ fluid_file_import_s$ID$(dict=liquid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+//////////////////////////////////////////////////////////////////////
+// EXPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_save_data =
+ "\n\
+def liquid_save_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save data')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=liquid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_data_dict_s$ID$, do_join=False)\n";
+
+const std::string liquid_save_flip =
+ "\n\
+def liquid_save_flip_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save flip')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=liquid_flip_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_flip_dict_s$ID$, do_join=False)\n";
+
+const std::string liquid_save_mesh =
+ "\n\
+def liquid_save_mesh_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save mesh')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=liquid_mesh_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_mesh_dict_s$ID$, do_join=False)\n";
+
+const std::string liquid_save_meshvel =
+ "\n\
+def liquid_save_meshvel_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save mesh vel')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=liquid_meshvel_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_meshvel_dict_s$ID$, do_join=False)\n";
+
+const std::string liquid_save_particles =
+ "\n\
+def liquid_save_particles_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save particles')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=liquid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_particles_dict_s$ID$, do_join=False)\n";
+
+//////////////////////////////////////////////////////////////////////
+// STANDALONE MODE
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_standalone =
+ "\n\
+# Helper function to call cache load functions\n\
+def load(frame):\n\
+ fluid_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\
+ liquid_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\
+ liquid_load_flip_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_particles)\n\
+ if using_sndparts_s$ID$:\n\
+ fluid_load_particles_$ID$(os.path.join(cache_dir, 'particles'), frame, file_format_particles)\n\
+ liquid_load_particles_$ID$(os.path.join(cache_dir, 'particles'), frame, file_format_particles)\n\
+ if using_mesh_s$ID$:\n\
+ liquid_load_mesh_$ID$(os.path.join(cache_dir, 'mesh'), frame, file_format_mesh)\n\
+ if using_guiding_s$ID$:\n\
+ fluid_load_guiding_$ID$(os.path.join(cache_dir, 'guiding'), frame, file_format_data)\n\
+\n\
+# Helper function to call step functions\n\
+def step(frame):\n\
+ liquid_adaptive_step_$ID$(frame)\n\
+ if using_mesh_s$ID$:\n\
+ liquid_step_mesh_$ID$()\n\
+ if using_sndparts_s$ID$:\n\
+ liquid_step_particles_$ID$()\n";
diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h
new file mode 100644
index 00000000000..186f56c0707
--- /dev/null
+++ b/intern/mantaflow/intern/strings/smoke_script.h
@@ -0,0 +1,575 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup mantaflow
+ */
+
+#include <string>
+
+//////////////////////////////////////////////////////////////////////
+// VARIABLES
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_variables =
+ "\n\
+mantaMsg('Smoke variables low')\n\
+preconditioner_s$ID$ = PcMGDynamic\n\
+using_colors_s$ID$ = $USING_COLORS$\n\
+using_heat_s$ID$ = $USING_HEAT$\n\
+using_fire_s$ID$ = $USING_FIRE$\n\
+using_noise_s$ID$ = $USING_NOISE$\n\
+vorticity_s$ID$ = $VORTICITY$\n\
+buoyancy_dens_s$ID$ = float($BUOYANCY_ALPHA$) / float($FLUID_DOMAIN_SIZE$)\n\
+buoyancy_heat_s$ID$ = float($BUOYANCY_BETA$) / float($FLUID_DOMAIN_SIZE$)\n\
+dissolveSpeed_s$ID$ = $DISSOLVE_SPEED$\n\
+using_logdissolve_s$ID$ = $USING_LOG_DISSOLVE$\n\
+using_dissolve_s$ID$ = $USING_DISSOLVE$\n\
+flameVorticity_s$ID$ = $FLAME_VORTICITY$\n\
+burningRate_s$ID$ = $BURNING_RATE$\n\
+flameSmoke_s$ID$ = $FLAME_SMOKE$\n\
+ignitionTemp_s$ID$ = $IGNITION_TEMP$\n\
+maxTemp_s$ID$ = $MAX_TEMP$\n\
+flameSmokeColor_s$ID$ = vec3($FLAME_SMOKE_COLOR_X$,$FLAME_SMOKE_COLOR_Y$,$FLAME_SMOKE_COLOR_Z$)\n";
+
+const std::string smoke_variables_noise =
+ "\n\
+mantaMsg('Smoke variables noise')\n\
+wltStrength_s$ID$ = $WLT_STR$\n\
+uvs_s$ID$ = 2\n\
+uvs_offset_s$ID$ = vec3($MIN_RESX$, $MIN_RESY$, $MIN_RESZ$)\n\
+octaves_s$ID$ = int(math.log(upres_sn$ID$) / math.log(2.0) + 0.5) if (upres_sn$ID$ > 1) else 1\n";
+
+const std::string smoke_wavelet_noise =
+ "\n\
+# wavelet noise params\n\
+wltnoise_sn$ID$.posScale = vec3(int($BASE_RESX$), int($BASE_RESY$), int($BASE_RESZ$)) * (1. / $NOISE_POSSCALE$)\n\
+wltnoise_sn$ID$.timeAnim = $NOISE_TIMEANIM$\n";
+
+const std::string smoke_with_heat =
+ "\n\
+using_heat_s$ID$ = True\n";
+
+const std::string smoke_with_colors =
+ "\n\
+using_colors_s$ID$ = True\n";
+
+const std::string smoke_with_fire =
+ "\n\
+using_fire_s$ID$ = True\n";
+
+//////////////////////////////////////////////////////////////////////
+// GRIDS
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_alloc =
+ "\n\
+mantaMsg('Smoke alloc')\n\
+shadow_s$ID$ = s$ID$.create(RealGrid)\n\
+emissionIn_s$ID$ = s$ID$.create(RealGrid)\n\
+density_s$ID$ = s$ID$.create(RealGrid)\n\
+densityIn_s$ID$ = s$ID$.create(RealGrid)\n\
+heat_s$ID$ = None # allocated dynamically\n\
+heatIn_s$ID$ = None\n\
+flame_s$ID$ = None\n\
+fuel_s$ID$ = None\n\
+react_s$ID$ = None\n\
+fuelIn_s$ID$ = None\n\
+reactIn_s$ID$ = None\n\
+color_r_s$ID$ = None\n\
+color_g_s$ID$ = None\n\
+color_b_s$ID$ = None\n\
+color_r_in_s$ID$ = None\n\
+color_g_in_s$ID$ = None\n\
+color_b_in_s$ID$ = None\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+smoke_data_dict_s$ID$ = dict(density=density_s$ID$, shadow=shadow_s$ID$, densityIn=densityIn_s$ID$, emissionIn=emissionIn_s$ID$)\n";
+
+const std::string smoke_alloc_noise =
+ "\n\
+mantaMsg('Smoke alloc noise')\n\
+vel_sn$ID$ = sn$ID$.create(MACGrid)\n\
+density_sn$ID$ = sn$ID$.create(RealGrid)\n\
+phiIn_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\
+phiOut_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\
+phiObs_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\
+flags_sn$ID$ = sn$ID$.create(FlagGrid)\n\
+tmpIn_sn$ID$ = sn$ID$.create(RealGrid)\n\
+emissionIn_sn$ID$ = sn$ID$.create(RealGrid)\n\
+energy_s$ID$ = s$ID$.create(RealGrid)\n\
+tempFlag_s$ID$ = s$ID$.create(FlagGrid)\n\
+texture_u_s$ID$ = s$ID$.create(RealGrid)\n\
+texture_v_s$ID$ = s$ID$.create(RealGrid)\n\
+texture_w_s$ID$ = s$ID$.create(RealGrid)\n\
+texture_u2_s$ID$ = s$ID$.create(RealGrid)\n\
+texture_v2_s$ID$ = s$ID$.create(RealGrid)\n\
+texture_w2_s$ID$ = s$ID$.create(RealGrid)\n\
+flame_sn$ID$ = None\n\
+fuel_sn$ID$ = None\n\
+react_sn$ID$ = None\n\
+color_r_sn$ID$ = None\n\
+color_g_sn$ID$ = None\n\
+color_b_sn$ID$ = None\n\
+wltnoise_sn$ID$ = sn$ID$.create(NoiseField, fixedSeed=265, loadFromFile=True)\n\
+\n\
+mantaMsg('Initializing UV Grids')\n\
+uvGrid0_s$ID$ = s$ID$.create(VecGrid)\n\
+uvGrid1_s$ID$ = s$ID$.create(VecGrid)\n\
+resetUvGrid(target=uvGrid0_s$ID$, offset=uvs_offset_s$ID$)\n\
+resetUvGrid(target=uvGrid1_s$ID$, offset=uvs_offset_s$ID$)\n\
+\n\
+# Sync UV and texture grids\n\
+copyVec3ToReal(source=uvGrid0_s$ID$, targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\
+copyVec3ToReal(source=uvGrid1_s$ID$, targetX=texture_u2_s$ID$, targetY=texture_v2_s$ID$, targetZ=texture_w2_s$ID$)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+smoke_noise_dict_s$ID$ = dict(density_noise=density_sn$ID$, uv0_noise=uvGrid0_s$ID$, uv1_noise=uvGrid1_s$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// ADDITIONAL GRIDS
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_alloc_colors =
+ "\n\
+# Sanity check, clear grids first\n\
+if 'color_r_s$ID$' in globals(): del color_r_s$ID$\n\
+if 'color_g_s$ID$' in globals(): del color_g_s$ID$\n\
+if 'color_b_s$ID$' in globals(): del color_b_s$ID$\n\
+\n\
+mantaMsg('Allocating colors')\n\
+color_r_s$ID$ = s$ID$.create(RealGrid)\n\
+color_g_s$ID$ = s$ID$.create(RealGrid)\n\
+color_b_s$ID$ = s$ID$.create(RealGrid)\n\
+color_r_in_s$ID$ = s$ID$.create(RealGrid)\n\
+color_g_in_s$ID$ = s$ID$.create(RealGrid)\n\
+color_b_in_s$ID$ = s$ID$.create(RealGrid)\n\
+\n\
+# Add objects to dict to load them later on\n\
+if 'smoke_data_dict_s$ID$' in globals():\n\
+ smoke_data_dict_s$ID$.update(color_r=color_r_s$ID$, color_g=color_g_s$ID$, color_b=color_b_s$ID$)\n\
+ smoke_data_dict_s$ID$.update(color_r_in=color_r_in_s$ID$, color_g_in=color_g_in_s$ID$, color_b_in=color_b_in_s$ID$)\n";
+
+const std::string smoke_alloc_colors_noise =
+ "\n\
+# Sanity check, clear grids first\n\
+if 'color_r_sn$ID$' in globals(): del color_r_sn$ID$\n\
+if 'color_g_sn$ID$' in globals(): del color_g_sn$ID$\n\
+if 'color_b_sn$ID$' in globals(): del color_b_sn$ID$\n\
+\n\
+mantaMsg('Allocating colors noise')\n\
+color_r_sn$ID$ = sn$ID$.create(RealGrid)\n\
+color_g_sn$ID$ = sn$ID$.create(RealGrid)\n\
+color_b_sn$ID$ = sn$ID$.create(RealGrid)\n\
+\n\
+# Add objects to dict to load them later on\n\
+if 'smoke_noise_dict_s$ID$' in globals():\n\
+ smoke_noise_dict_s$ID$.update(color_r_noise=color_r_sn$ID$, color_g_noise=color_g_sn$ID$, color_b_noise=color_b_sn$ID$)\n";
+
+const std::string smoke_init_colors =
+ "\n\
+mantaMsg('Initializing colors')\n\
+color_r_s$ID$.copyFrom(density_s$ID$) \n\
+color_r_s$ID$.multConst($COLOR_R$) \n\
+color_g_s$ID$.copyFrom(density_s$ID$) \n\
+color_g_s$ID$.multConst($COLOR_G$) \n\
+color_b_s$ID$.copyFrom(density_s$ID$) \n\
+color_b_s$ID$.multConst($COLOR_B$)\n";
+
+const std::string smoke_init_colors_noise =
+ "\n\
+mantaMsg('Initializing colors noise')\n\
+color_r_sn$ID$.copyFrom(density_sn$ID$) \n\
+color_r_sn$ID$.multConst($COLOR_R$) \n\
+color_g_sn$ID$.copyFrom(density_sn$ID$) \n\
+color_g_sn$ID$.multConst($COLOR_G$) \n\
+color_b_sn$ID$.copyFrom(density_sn$ID$) \n\
+color_b_sn$ID$.multConst($COLOR_B$)\n";
+
+const std::string smoke_alloc_heat =
+ "\n\
+# Sanity check, clear grids first\n\
+if 'heat_s$ID$' in globals(): del heat_s$ID$\n\
+if 'heatIn_s$ID$' in globals(): del heatIn_s$ID$\n\
+\n\
+mantaMsg('Allocating heat')\n\
+heat_s$ID$ = s$ID$.create(RealGrid)\n\
+heatIn_s$ID$ = s$ID$.create(RealGrid)\n\
+\n\
+# Add objects to dict to load them later on\n\
+if 'smoke_data_dict_s$ID$' in globals():\n\
+ smoke_data_dict_s$ID$.update(heat=heat_s$ID$, heatIn=heatIn_s$ID$)\n";
+
+const std::string smoke_alloc_fire =
+ "\n\
+# Sanity check, clear grids first\n\
+if 'flame_s$ID$' in globals(): del flame_s$ID$\n\
+if 'fuel_s$ID$' in globals(): del fuel_s$ID$\n\
+if 'react_s$ID$' in globals(): del react_s$ID$\n\
+if 'fuelIn_s$ID$' in globals(): del fuelIn_s$ID$\n\
+if 'reactIn_s$ID$' in globals(): del reactIn_s$ID$\n\
+\n\
+mantaMsg('Allocating fire')\n\
+flame_s$ID$ = s$ID$.create(RealGrid)\n\
+fuel_s$ID$ = s$ID$.create(RealGrid)\n\
+react_s$ID$ = s$ID$.create(RealGrid)\n\
+fuelIn_s$ID$ = s$ID$.create(RealGrid)\n\
+reactIn_s$ID$ = s$ID$.create(RealGrid)\n\
+\n\
+# Add objects to dict to load them later on\n\
+if 'smoke_data_dict_s$ID$' in globals():\n\
+ smoke_data_dict_s$ID$.update(flame=flame_s$ID$, fuel=fuel_s$ID$, react=react_s$ID$)\n\
+ smoke_data_dict_s$ID$.update(fuelIn=fuelIn_s$ID$, reactIn=reactIn_s$ID$)\n";
+
+const std::string smoke_alloc_fire_noise =
+ "\n\
+# Sanity check, clear grids first\n\
+if 'flame_sn$ID$' in globals(): del flame_sn$ID$\n\
+if 'fuel_sn$ID$' in globals(): del fuel_sn$ID$\n\
+if 'react_sn$ID$' in globals(): del react_sn$ID$\n\
+\n\
+mantaMsg('Allocating fire noise')\n\
+flame_sn$ID$ = sn$ID$.create(RealGrid)\n\
+fuel_sn$ID$ = sn$ID$.create(RealGrid)\n\
+react_sn$ID$ = sn$ID$.create(RealGrid)\n\
+\n\
+# Add objects to dict to load them later on\n\
+if 'smoke_noise_dict_s$ID$' in globals():\n\
+ smoke_noise_dict_s$ID$.update(flame_noise=flame_sn$ID$, fuel_noise=fuel_sn$ID$, react_noise=react_sn$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// STEP FUNCTIONS
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_adaptive_step =
+ "\n\
+def smoke_adaptive_step_$ID$(framenr):\n\
+ mantaMsg('Manta step, frame ' + str(framenr))\n\
+ s$ID$.frame = framenr\n\
+ \n\
+ fluid_pre_step_$ID$()\n\
+ \n\
+ flags_s$ID$.initDomain(boundaryWidth=0, phiWalls=phiObs_s$ID$, outflow=boundConditions_s$ID$)\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ mantaMsg('Initializing obstacle levelset')\n\
+ phiObsIn_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\
+ extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ phiObs_s$ID$.join(phiObsIn_s$ID$)\n\
+ \n\
+ # Using boundaryWidth=2 to not search beginning from walls (just a performance optimization)\n\
+ # Additional sanity check: fill holes in phiObs which can result after joining with phiObsIn\n\
+ phiObs_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ \n\
+ mantaMsg('Initializing fluid levelset')\n\
+ extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ \n\
+ if using_outflow_s$ID$:\n\
+ phiOut_s$ID$.join(phiOutIn_s$ID$)\n\
+ \n\
+ setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, phiIn=phiIn_s$ID$)\n\
+ flags_s$ID$.fillGrid()\n\
+ \n\
+ if timePerFrame_s$ID$ == 0: # Only apply inflow once per frame\n\
+ mantaMsg('Smoke inflow at frame: ' + str(framenr))\n\
+ applyEmission(flags=flags_s$ID$, target=density_s$ID$, source=densityIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ if using_heat_s$ID$:\n\
+ applyEmission(flags=flags_s$ID$, target=heat_s$ID$, source=heatIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ if using_colors_s$ID$:\n\
+ applyEmission(flags=flags_s$ID$, target=color_r_s$ID$, source=color_r_in_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ applyEmission(flags=flags_s$ID$, target=color_g_s$ID$, source=color_g_in_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ applyEmission(flags=flags_s$ID$, target=color_b_s$ID$, source=color_b_in_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ if using_fire_s$ID$:\n\
+ applyEmission(flags=flags_s$ID$, target=fuel_s$ID$, source=fuelIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ applyEmission(flags=flags_s$ID$, target=react_s$ID$, source=reactIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ mantaMsg('Smoke step / s$ID$.frame: ' + str(s$ID$.frame))\n\
+ if using_fire_s$ID$:\n\
+ process_burn_$ID$()\n\
+ smoke_step_$ID$()\n\
+ if using_fire_s$ID$:\n\
+ update_flame_$ID$()\n\
+ \n\
+ s$ID$.step()\n\
+ \n\
+ fluid_post_step_$ID$()\n";
+
+const std::string smoke_step =
+ "\n\
+def smoke_step_$ID$():\n\
+ mantaMsg('Smoke step low')\n\
+ \n\
+ if using_dissolve_s$ID$:\n\
+ mantaMsg('Dissolving smoke')\n\
+ dissolveSmoke(flags=flags_s$ID$, density=density_s$ID$, heat=heat_s$ID$, red=color_r_s$ID$, green=color_g_s$ID$, blue=color_b_s$ID$, speed=dissolveSpeed_s$ID$, logFalloff=using_logdissolve_s$ID$)\n\
+ \n\
+ mantaMsg('Advecting density')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=density_s$ID$, order=2)\n\
+ \n\
+ if using_heat_s$ID$:\n\
+ mantaMsg('Advecting heat')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=heat_s$ID$, order=2)\n\
+ \n\
+ if using_fire_s$ID$:\n\
+ mantaMsg('Advecting fire')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=fuel_s$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=react_s$ID$, order=2)\n\
+ \n\
+ if using_colors_s$ID$:\n\
+ mantaMsg('Advecting colors')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=color_r_s$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=color_g_s$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=color_b_s$ID$, order=2)\n\
+ \n\
+ mantaMsg('Advecting velocity')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=vel_s$ID$, order=2)\n\
+ \n\
+ if doOpen_s$ID$ or using_outflow_s$ID$:\n\
+ resetOutflow(flags=flags_s$ID$, real=density_s$ID$)\n\
+ \n\
+ mantaMsg('Vorticity')\n\
+ if using_fire_s$ID$:\n\
+ flame_s$ID$.copyFrom(fuel_s$ID$) # temporarily misuse flame grid as vorticity storage\n\
+ flame_s$ID$.multConst(flameVorticity_s$ID$)\n\
+ vorticityConfinement(vel=vel_s$ID$, flags=flags_s$ID$, strengthGlobal=vorticity_s$ID$, strengthCell=flame_s$ID$ if using_fire_s$ID$ else None)\n\
+ \n\
+ if using_heat_s$ID$:\n\
+ mantaMsg('Adding heat buoyancy')\n\
+ addBuoyancy(flags=flags_s$ID$, density=heat_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_heat_s$ID$)\n\
+ mantaMsg('Adding buoyancy')\n\
+ addBuoyancy(flags=flags_s$ID$, density=density_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_dens_s$ID$)\n\
+ \n\
+ mantaMsg('Adding forces')\n\
+ addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ mantaMsg('Extrapolating object velocity')\n\
+ # ensure velocities inside of obs object, slightly add obvels outside of obs object\n\
+ extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=3, inside=False)\n\
+ resampleVec3ToMac(source=obvelC_s$ID$, target=obvel_s$ID$)\n\
+ \n\
+ # add initial velocity\n\
+ if using_invel_s$ID$:\n\
+ resampleVec3ToMac(source=invelC_s$ID$, target=invel_s$ID$)\n\
+ setInitialVelocity(flags=flags_s$ID$, vel=vel_s$ID$, invel=invel_s$ID$)\n\
+ \n\
+ mantaMsg('Walls')\n\
+ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=obvel_s$ID$ if using_obstacle_s$ID$ else None)\n\
+ \n\
+ if using_guiding_s$ID$:\n\
+ mantaMsg('Guiding and pressure')\n\
+ PD_fluid_guiding(vel=vel_s$ID$, velT=velT_s$ID$, flags=flags_s$ID$, weight=weightGuide_s$ID$, blurRadius=beta_sg$ID$, pressure=pressure_s$ID$, tau=tau_sg$ID$, sigma=sigma_sg$ID$, theta=theta_sg$ID$, preconditioner=preconditioner_s$ID$, zeroPressureFixing=not doOpen_s$ID$)\n\
+ else:\n\
+ mantaMsg('Pressure')\n\
+ solvePressure(flags=flags_s$ID$, vel=vel_s$ID$, pressure=pressure_s$ID$, preconditioner=preconditioner_s$ID$, zeroPressureFixing=not doOpen_s$ID$) # closed domains require pressure fixing\n\
+\n\
+def process_burn_$ID$():\n\
+ mantaMsg('Process burn')\n\
+ processBurn(fuel=fuel_s$ID$, density=density_s$ID$, react=react_s$ID$, red=color_r_s$ID$ if using_colors_s$ID$ else None, green=color_g_s$ID$ if using_colors_s$ID$ else None, blue=color_b_s$ID$ if using_colors_s$ID$ else None, heat=heat_s$ID$ if using_heat_s$ID$ else None, burningRate=burningRate_s$ID$, flameSmoke=flameSmoke_s$ID$, ignitionTemp=ignitionTemp_s$ID$, maxTemp=maxTemp_s$ID$, flameSmokeColor=flameSmokeColor_s$ID$)\n\
+\n\
+def update_flame_$ID$():\n\
+ mantaMsg('Update flame')\n\
+ updateFlame(react=react_s$ID$, flame=flame_s$ID$)\n";
+
+const std::string smoke_step_noise =
+ "\n\
+def smoke_step_noise_$ID$(framenr):\n\
+ mantaMsg('Manta step noise, frame ' + str(framenr))\n\
+ sn$ID$.frame = framenr\n\
+ \n\
+ copyRealToVec3(sourceX=texture_u_s$ID$, sourceY=texture_v_s$ID$, sourceZ=texture_w_s$ID$, target=uvGrid0_s$ID$)\n\
+ copyRealToVec3(sourceX=texture_u2_s$ID$, sourceY=texture_v2_s$ID$, sourceZ=texture_w2_s$ID$, target=uvGrid1_s$ID$)\n\
+ \n\
+ flags_sn$ID$.initDomain(boundaryWidth=0, phiWalls=phiObs_sn$ID$, outflow=boundConditions_s$ID$)\n\
+ \n\
+ mantaMsg('Interpolating grids')\n\
+ # Join big obstacle levelset after initDomain() call as it overwrites everything in phiObs\n\
+ if using_obstacle_s$ID$:\n\
+ interpolateGrid(target=phiIn_sn$ID$, source=phiObsIn_s$ID$) # mis-use phiIn_sn\n\
+ phiObs_sn$ID$.join(phiIn_sn$ID$)\n\
+ if using_outflow_s$ID$:\n\
+ interpolateGrid(target=phiOut_sn$ID$, source=phiOut_s$ID$)\n\
+ interpolateGrid(target=phiIn_sn$ID$, source=phiIn_s$ID$)\n\
+ interpolateMACGrid(target=vel_sn$ID$, source=vel_s$ID$)\n\
+ \n\
+ setObstacleFlags(flags=flags_sn$ID$, phiObs=phiObs_sn$ID$, phiOut=phiOut_sn$ID$, phiIn=phiIn_sn$ID$)\n\
+ flags_sn$ID$.fillGrid()\n\
+ \n\
+ # Interpolate emission grids and apply them to big noise grids\n\
+ interpolateGrid(source=densityIn_s$ID$, target=tmpIn_sn$ID$)\n\
+ interpolateGrid(source=emissionIn_s$ID$, target=emissionIn_sn$ID$)\n\
+ \n\
+ # Higher-res noise grid needs scaled emission values\n\
+ tmpIn_sn$ID$.multConst(float(upres_sn$ID$))\n\
+ applyEmission(flags=flags_sn$ID$, target=density_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ if using_colors_s$ID$:\n\
+ interpolateGrid(source=color_r_in_s$ID$, target=tmpIn_sn$ID$)\n\
+ applyEmission(flags=flags_sn$ID$, target=color_r_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ interpolateGrid(source=color_g_in_s$ID$, target=tmpIn_sn$ID$)\n\
+ applyEmission(flags=flags_sn$ID$, target=color_g_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ interpolateGrid(source=color_b_in_s$ID$, target=tmpIn_sn$ID$)\n\
+ applyEmission(flags=flags_sn$ID$, target=color_b_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ if using_fire_s$ID$:\n\
+ interpolateGrid(source=fuelIn_s$ID$, target=tmpIn_sn$ID$)\n\
+ applyEmission(flags=flags_sn$ID$, target=fuel_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ interpolateGrid(source=reactIn_s$ID$, target=tmpIn_sn$ID$)\n\
+ applyEmission(flags=flags_sn$ID$, target=react_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ mantaMsg('Noise step / sn$ID$.frame: ' + str(sn$ID$.frame))\n\
+ if using_fire_s$ID$:\n\
+ process_burn_noise_$ID$()\n\
+ step_noise_$ID$()\n\
+ if using_fire_s$ID$:\n\
+ update_flame_noise_$ID$()\n\
+ \n\
+ sn$ID$.step()\n\
+ \n\
+ copyVec3ToReal(source=uvGrid0_s$ID$, targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\
+ copyVec3ToReal(source=uvGrid1_s$ID$, targetX=texture_u2_s$ID$, targetY=texture_v2_s$ID$, targetZ=texture_w2_s$ID$)\n\
+\n\
+def step_noise_$ID$():\n\
+ mantaMsg('Smoke step noise')\n\
+ \n\
+ if using_dissolve_s$ID$:\n\
+ mantaMsg('Dissolving noise')\n\
+ dissolveSmoke(flags=flags_sn$ID$, density=density_sn$ID$, heat=None, red=color_r_sn$ID$, green=color_g_sn$ID$, blue=color_b_sn$ID$, speed=dissolveSpeed_s$ID$, logFalloff=using_logdissolve_s$ID$)\n\
+ \n\
+ mantaMsg('Advecting UVs and updating UV weight')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=uvGrid0_s$ID$, order=2)\n\
+ updateUvWeight(resetTime=sn$ID$.timestep*10.0 , index=0, numUvs=uvs_s$ID$, uv=uvGrid0_s$ID$, offset=uvs_offset_s$ID$)\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=uvGrid1_s$ID$, order=2)\n\
+ updateUvWeight(resetTime=sn$ID$.timestep*10.0 , index=1, numUvs=uvs_s$ID$, uv=uvGrid1_s$ID$, offset=uvs_offset_s$ID$)\n\
+ \n\
+ mantaMsg('Energy')\n\
+ computeEnergy(flags=flags_s$ID$, vel=vel_s$ID$, energy=energy_s$ID$)\n\
+ \n\
+ tempFlag_s$ID$.copyFrom(flags_s$ID$)\n\
+ extrapolateSimpleFlags(flags=flags_s$ID$, val=tempFlag_s$ID$, distance=2, flagFrom=FlagObstacle, flagTo=FlagFluid)\n\
+ extrapolateSimpleFlags(flags=tempFlag_s$ID$, val=energy_s$ID$, distance=6, flagFrom=FlagFluid, flagTo=FlagObstacle)\n\
+ computeWaveletCoeffs(energy_s$ID$)\n\
+ \n\
+ sStr_s$ID$ = 1.0 * wltStrength_s$ID$\n\
+ sPos_s$ID$ = 2.0\n\
+ \n\
+ mantaMsg('Applying noise vec')\n\
+ for o in range(octaves_s$ID$):\n\
+ uvWeight_s$ID$ = getUvWeight(uvGrid0_s$ID$)\n\
+ applyNoiseVec3(flags=flags_sn$ID$, target=vel_sn$ID$, noise=wltnoise_sn$ID$, scale=sStr_s$ID$ * uvWeight_s$ID$, scaleSpatial=sPos_s$ID$ , weight=energy_s$ID$, uv=uvGrid0_s$ID$)\n\
+ uvWeight_s$ID$ = getUvWeight(uvGrid1_s$ID$)\n\
+ applyNoiseVec3(flags=flags_sn$ID$, target=vel_sn$ID$, noise=wltnoise_sn$ID$, scale=sStr_s$ID$ * uvWeight_s$ID$, scaleSpatial=sPos_s$ID$ , weight=energy_s$ID$, uv=uvGrid1_s$ID$)\n\
+ \n\
+ sStr_s$ID$ *= 0.06 # magic kolmogorov factor \n\
+ sPos_s$ID$ *= 2.0 \n\
+ \n\
+ for substep in range(int(upres_sn$ID$)):\n\
+ if using_colors_s$ID$: \n\
+ mantaMsg('Advecting colors noise')\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=color_r_sn$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=color_g_sn$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=color_b_sn$ID$, order=2)\n\
+ \n\
+ if using_fire_s$ID$: \n\
+ mantaMsg('Advecting fire noise')\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=fuel_sn$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=react_sn$ID$, order=2)\n\
+ \n\
+ mantaMsg('Advecting density noise')\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=density_sn$ID$, order=2)\n\
+\n\
+def process_burn_noise_$ID$():\n\
+ mantaMsg('Process burn noise')\n\
+ processBurn(fuel=fuel_sn$ID$, density=density_sn$ID$, react=react_sn$ID$, red=color_r_sn$ID$ if using_colors_s$ID$ else None, green=color_g_sn$ID$ if using_colors_s$ID$ else None, blue=color_b_sn$ID$ if using_colors_s$ID$ else None, burningRate=burningRate_s$ID$, flameSmoke=flameSmoke_s$ID$, ignitionTemp=ignitionTemp_s$ID$, maxTemp=maxTemp_s$ID$, flameSmokeColor=flameSmokeColor_s$ID$)\n\
+\n\
+def update_flame_noise_$ID$():\n\
+ mantaMsg('Update flame noise')\n\
+ updateFlame(react=react_sn$ID$, flame=flame_sn$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// IMPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_load_data =
+ "\n\
+def smoke_load_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Smoke load data')\n\
+ fluid_file_import_s$ID$(dict=smoke_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string smoke_load_noise =
+ "\n\
+def smoke_load_noise_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Smoke load noise')\n\
+ fluid_file_import_s$ID$(dict=smoke_noise_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ \n\
+ # Fill up xyz texture grids, important when resuming a bake\n\
+ copyVec3ToReal(source=uvGrid0_s$ID$, targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\
+ copyVec3ToReal(source=uvGrid1_s$ID$, targetX=texture_u2_s$ID$, targetY=texture_v2_s$ID$, targetZ=texture_w2_s$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// EXPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_save_data =
+ "\n\
+def smoke_save_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Smoke save data')\n\
+ start_time = time.time()\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(framenr=framenr, file_format=file_format, path=path, dict=smoke_data_dict_s$ID$,)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=smoke_data_dict_s$ID$, do_join=False)\n\
+ mantaMsg('--- Save: %s seconds ---' % (time.time() - start_time))\n";
+
+const std::string smoke_save_noise =
+ "\n\
+def smoke_save_noise_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Smoke save noise')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=smoke_noise_dict_s$ID$, framenr=framenr, file_format=file_format, path=path)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=smoke_noise_dict_s$ID$, do_join=False)\n";
+
+//////////////////////////////////////////////////////////////////////
+// STANDALONE MODE
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_standalone =
+ "\n\
+# Helper function to call cache load functions\n\
+def load(frame):\n\
+ fluid_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\
+ smoke_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\
+ if using_noise_s$ID$:\n\
+ smoke_load_noise_$ID$(os.path.join(cache_dir, 'noise'), frame, file_format_noise)\n\
+ if using_guiding_s$ID$:\n\
+ fluid_load_guiding_$ID$(os.path.join(cache_dir, 'guiding'), frame, file_format_data)\n\
+\n\
+# Helper function to call step functions\n\
+def step(frame):\n\
+ smoke_adaptive_step_$ID$(frame)\n\
+ if using_noise_s$ID$:\n\
+ smoke_step_noise_$ID$(frame)\n";
diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl
index 04e96e8ed3c..9787398e2ae 100644
--- a/intern/opencolorio/gpu_shader_display_transform.glsl
+++ b/intern/opencolorio/gpu_shader_display_transform.glsl
@@ -16,7 +16,7 @@ out vec4 fragColor;
*/
uniform sampler1D curve_mapping_texture;
uniform int curve_mapping_lut_size;
-uniform ivec4 use_curve_mapping_extend_extrapolate;
+uniform int use_curve_mapping_extend_extrapolate;
uniform vec4 curve_mapping_mintable;
uniform vec4 curve_mapping_range;
uniform vec4 curve_mapping_ext_in_x;
@@ -42,8 +42,8 @@ float read_curve_mapping(int table, int index)
float curvemap_calc_extend(int table, float x, vec2 first, vec2 last)
{
if (x <= first[0]) {
- if (use_curve_mapping_extend_extrapolate[table] == 0) {
- /* no extrapolate */
+ if (use_curve_mapping_extend_extrapolate == 0) {
+ /* horizontal extrapolation */
return first[1];
}
else {
@@ -55,8 +55,8 @@ float curvemap_calc_extend(int table, float x, vec2 first, vec2 last)
}
}
else if (x >= last[0]) {
- if (use_curve_mapping_extend_extrapolate[table] == 0) {
- /* no extrapolate */
+ if (use_curve_mapping_extend_extrapolate == 0) {
+ /* horizontal extrapolation */
return last[1];
}
else {
diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h
index 9ba2d8fb8f9..5670b37f892 100644
--- a/intern/opencolorio/ocio_capi.h
+++ b/intern/opencolorio/ocio_capi.h
@@ -73,10 +73,10 @@ typedef struct OCIO_CurveMappingSettings {
int lut_size;
/* Extend extrapolation flags for all the tables.
- * if use_extend_extrapolate[T] != 0 means extrapolation for
- * table T is needed.
+ * if use_extend_extrapolate != 0 means extrapolation for
+ * curve.
*/
- int use_extend_extrapolate[4];
+ int use_extend_extrapolate;
/* Minimal X value of the curve mapping tables. */
float mintable[4];
diff --git a/intern/opencolorio/ocio_impl_glsl.cc b/intern/opencolorio/ocio_impl_glsl.cc
index 99d59c8d989..a80e29a2dec 100644
--- a/intern/opencolorio/ocio_impl_glsl.cc
+++ b/intern/opencolorio/ocio_impl_glsl.cc
@@ -499,8 +499,8 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r,
if (use_curve_mapping) {
immUniform1i("curve_mapping_texture", 2);
immUniform1i("curve_mapping_lut_size", curve_mapping_settings->lut_size);
- immUniform4iv("use_curve_mapping_extend_extrapolate",
- curve_mapping_settings->use_extend_extrapolate);
+ immUniform1i("use_curve_mapping_extend_extrapolate",
+ curve_mapping_settings->use_extend_extrapolate);
immUniform4fv("curve_mapping_mintable", curve_mapping_settings->mintable);
immUniform4fv("curve_mapping_range", curve_mapping_settings->range);
immUniform4fv("curve_mapping_ext_in_x", curve_mapping_settings->ext_in_x);
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
index c5dd4509976..431258aa415 100644
--- a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
@@ -812,11 +812,8 @@ OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal(
StencilTableFactory::Create(*refiner, face_varying_stencil_options));
}
// Generate bi-cubic patch table for the limit surface.
- // TODO(sergey): Ideally we would want to expose end-cap settings via
- // C-API to make it more generic. Currently it matches old Blender's
- // subsurf code.
PatchTableFactory::Options patch_options(level);
- patch_options.SetEndCapType(PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS);
+ patch_options.SetEndCapType(PatchTableFactory::Options::ENDCAP_GREGORY_BASIS);
patch_options.useInfSharpPatch = use_inf_sharp_patch;
patch_options.generateFVarTables = has_face_varying_data;
patch_options.generateFVarLegacyLinearPatches = false;
diff --git a/intern/smoke/CMakeLists.txt b/intern/smoke/CMakeLists.txt
deleted file mode 100644
index 5c8e495fa93..00000000000
--- a/intern/smoke/CMakeLists.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-# ***** END GPL LICENSE BLOCK *****
-
-set(INC
- intern
- ../memutil
-)
-
-set(INC_SYS
- ${BULLET_INCLUDE_DIRS}
- ${PNG_INCLUDE_DIRS}
- ${ZLIB_INCLUDE_DIRS}
-)
-
-set(SRC
- intern/EIGENVALUE_HELPER.cpp
- intern/FLUID_3D.cpp
- intern/FLUID_3D_SOLVERS.cpp
- intern/FLUID_3D_STATIC.cpp
- intern/LU_HELPER.cpp
- intern/SPHERE.cpp
- intern/WTURBULENCE.cpp
- intern/smoke_API.cpp
-
- extern/smoke_API.h
- intern/EIGENVALUE_HELPER.h
- intern/FFT_NOISE.h
- intern/FLUID_3D.h
- intern/IMAGE.h
- intern/INTERPOLATE.h
- intern/LU_HELPER.h
- intern/MERSENNETWISTER.h
- intern/OBSTACLE.h
- intern/SPHERE.h
- intern/VEC3.h
- intern/WAVELET_NOISE.h
- intern/WTURBULENCE.h
- intern/tnt/jama_eig.h
- intern/tnt/jama_lu.h
- intern/tnt/tnt.h
- intern/tnt/tnt_array1d.h
- intern/tnt/tnt_array1d_utils.h
- intern/tnt/tnt_array2d.h
- intern/tnt/tnt_array2d_utils.h
- intern/tnt/tnt_array3d.h
- intern/tnt/tnt_array3d_utils.h
- intern/tnt/tnt_cmat.h
- intern/tnt/tnt_fortran_array1d.h
- intern/tnt/tnt_fortran_array1d_utils.h
- intern/tnt/tnt_fortran_array2d.h
- intern/tnt/tnt_fortran_array2d_utils.h
- intern/tnt/tnt_fortran_array3d.h
- intern/tnt/tnt_fortran_array3d_utils.h
- intern/tnt/tnt_i_refvec.h
- intern/tnt/tnt_math_utils.h
- intern/tnt/tnt_sparse_matrix_csr.h
- intern/tnt/tnt_stopwatch.h
- intern/tnt/tnt_subscript.h
- intern/tnt/tnt_vec.h
- intern/tnt/tnt_version.h
-)
-
-set(LIB
-)
-
-# quiet -Wundef
-add_definitions(-DDDF_DEBUG=0)
-
-if(WITH_OPENMP)
- add_definitions(-DPARALLEL=1)
-else()
- add_definitions(-DPARALLEL=0)
-endif()
-
-if(WITH_FFTW3)
- add_definitions(-DWITH_FFTW3)
- list(APPEND INC_SYS
- ${FFTW3_INCLUDE_DIRS}
- )
-endif()
-
-blender_add_lib(bf_intern_smoke "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/intern/smoke/extern/smoke_API.h b/intern/smoke/extern/smoke_API.h
deleted file mode 100644
index 169f679526c..00000000000
--- a/intern/smoke/extern/smoke_API.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2009 by Daniel Genrich
- * All rights reserved.
- */
-
-/** \file
- * \ingroup smoke
- */
-
-
-#ifndef SMOKE_API_H_
-#define SMOKE_API_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct FLUID_3D;
-
-// low res
-struct FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors);
-void smoke_free(struct FLUID_3D *fluid);
-
-void smoke_initBlenderRNA(struct FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
- float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp);
-void smoke_step(struct FLUID_3D *fluid, float gravity[3], float dtSubdiv);
-
-float *smoke_get_density(struct FLUID_3D *fluid);
-float *smoke_get_flame(struct FLUID_3D *fluid);
-float *smoke_get_fuel(struct FLUID_3D *fluid);
-float *smoke_get_react(struct FLUID_3D *fluid);
-float *smoke_get_color_r(struct FLUID_3D *fluid);
-float *smoke_get_color_g(struct FLUID_3D *fluid);
-float *smoke_get_color_b(struct FLUID_3D *fluid);
-void smoke_get_rgba(struct FLUID_3D *fluid, float *data, int sequential);
-void smoke_get_rgba_from_density(struct FLUID_3D *fluid, float color[3], float *data, int sequential);
-float *smoke_get_heat(struct FLUID_3D *fluid);
-float *smoke_get_velocity_x(struct FLUID_3D *fluid);
-float *smoke_get_velocity_y(struct FLUID_3D *fluid);
-float *smoke_get_velocity_z(struct FLUID_3D *fluid);
-
-/* Moving obstacle velocity provided by blender */
-void smoke_get_ob_velocity(struct FLUID_3D *fluid, float **x, float **y, float **z);
-
-float *smoke_get_force_x(struct FLUID_3D *fluid);
-float *smoke_get_force_y(struct FLUID_3D *fluid);
-float *smoke_get_force_z(struct FLUID_3D *fluid);
-
-unsigned char *smoke_get_obstacle(struct FLUID_3D *fluid);
-
-size_t smoke_get_index(int x, int max_x, int y, int max_y, int z);
-size_t smoke_get_index2d(int x, int max_x, int y);
-
-void smoke_dissolve(struct FLUID_3D *fluid, int speed, int log);
-
-// wavelet turbulence functions
-struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors);
-void smoke_turbulence_free(struct WTURBULENCE *wt);
-void smoke_turbulence_step(struct WTURBULENCE *wt, struct FLUID_3D *fluid);
-
-float *smoke_turbulence_get_density(struct WTURBULENCE *wt);
-float *smoke_turbulence_get_color_r(struct WTURBULENCE *wt);
-float *smoke_turbulence_get_color_g(struct WTURBULENCE *wt);
-float *smoke_turbulence_get_color_b(struct WTURBULENCE *wt);
-void smoke_turbulence_get_rgba(struct WTURBULENCE *wt, float *data, int sequential);
-void smoke_turbulence_get_rgba_from_density(struct WTURBULENCE *wt, float color[3], float *data, int sequential);
-float *smoke_turbulence_get_flame(struct WTURBULENCE *wt);
-float *smoke_turbulence_get_fuel(struct WTURBULENCE *wt);
-float *smoke_turbulence_get_react(struct WTURBULENCE *wt);
-void smoke_turbulence_get_res(struct WTURBULENCE *wt, int *res);
-int smoke_turbulence_get_cells(struct WTURBULENCE *wt);
-void smoke_turbulence_set_noise(struct WTURBULENCE *wt, int type, const char *noisefile_path);
-void smoke_initWaveletBlenderRNA(struct WTURBULENCE *wt, float *strength);
-void smoke_dissolve_wavelet(struct WTURBULENCE *wt, int speed, int log);
-
-/* export */
-void smoke_export(struct FLUID_3D *fluid, float *dt, float *dx, float **dens, float **react, float **flame, float **fuel, float **heat, float **heatold,
- float **vx, float **vy, float **vz, float **r, float **g, float **b, unsigned char **obstacles);
-void smoke_turbulence_export(struct WTURBULENCE *wt, float **dens, float **react, float **flame, float **fuel,
- float **r, float **g, float **b, float **tcu, float **tcv, float **tcw);
-
-/* data fields */
-int smoke_has_heat(struct FLUID_3D *fluid);
-int smoke_has_fuel(struct FLUID_3D *fluid);
-int smoke_has_colors(struct FLUID_3D *fluid);
-int smoke_turbulence_has_fuel(struct WTURBULENCE *wt);
-int smoke_turbulence_has_colors(struct WTURBULENCE *wt);
-
-void smoke_ensure_heat(struct FLUID_3D *fluid);
-void smoke_ensure_fire(struct FLUID_3D *fluid, struct WTURBULENCE *wt);
-void smoke_ensure_colors(struct FLUID_3D *fluid, struct WTURBULENCE *wt, float init_r, float init_g, float init_b);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SMOKE_API_H_ */
diff --git a/intern/smoke/intern/EIGENVALUE_HELPER.cpp b/intern/smoke/intern/EIGENVALUE_HELPER.cpp
deleted file mode 100644
index fbfd6d3bd22..00000000000
--- a/intern/smoke/intern/EIGENVALUE_HELPER.cpp
+++ /dev/null
@@ -1,888 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-
-#include "EIGENVALUE_HELPER.h"
-
-
-void Eigentred2(sEigenvalue& eval) {
-
- // This is derived from the Algol procedures tred2 by
- // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
- // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- int n=eval.n;
-
- for (int j = 0; j < n; j++) {
- eval.d[j] = eval.V[n-1][j];
- }
-
- // Householder reduction to tridiagonal form.
-
- for (int i = n-1; i > 0; i--) {
-
- // Scale to avoid under/overflow.
-
- float scale = 0.0;
- float h = 0.0;
- for (int k = 0; k < i; k++) {
- scale = scale + fabs(eval.d[k]);
- }
- if (scale == 0.0f) {
- eval.e[i] = eval.d[i-1];
- for (int j = 0; j < i; j++) {
- eval.d[j] = eval.V[i-1][j];
- eval.V[i][j] = 0.0;
- eval.V[j][i] = 0.0;
- }
- } else {
-
- // Generate Householder vector.
-
- for (int k = 0; k < i; k++) {
- eval.d[k] /= scale;
- h += eval.d[k] * eval.d[k];
- }
- float f = eval.d[i-1];
- float g = sqrt(h);
- if (f > 0) {
- g = -g;
- }
- eval.e[i] = scale * g;
- h = h - f * g;
- eval.d[i-1] = f - g;
- for (int j = 0; j < i; j++) {
- eval.e[j] = 0.0;
- }
-
- // Apply similarity transformation to remaining columns.
-
- for (int j = 0; j < i; j++) {
- f = eval.d[j];
- eval.V[j][i] = f;
- g = eval.e[j] + eval.V[j][j] * f;
- for (int k = j+1; k <= i-1; k++) {
- g += eval.V[k][j] * eval.d[k];
- eval.e[k] += eval.V[k][j] * f;
- }
- eval.e[j] = g;
- }
- f = 0.0;
- for (int j = 0; j < i; j++) {
- eval.e[j] /= h;
- f += eval.e[j] * eval.d[j];
- }
- float hh = f / (h + h);
- for (int j = 0; j < i; j++) {
- eval.e[j] -= hh * eval.d[j];
- }
- for (int j = 0; j < i; j++) {
- f = eval.d[j];
- g = eval.e[j];
- for (int k = j; k <= i-1; k++) {
- eval.V[k][j] -= (f * eval.e[k] + g * eval.d[k]);
- }
- eval.d[j] = eval.V[i-1][j];
- eval.V[i][j] = 0.0;
- }
- }
- eval.d[i] = h;
- }
-
- // Accumulate transformations.
-
- for (int i = 0; i < n-1; i++) {
- eval.V[n-1][i] = eval.V[i][i];
- eval.V[i][i] = 1.0;
- float h = eval.d[i+1];
- if (h != 0.0f) {
- for (int k = 0; k <= i; k++) {
- eval.d[k] = eval.V[k][i+1] / h;
- }
- for (int j = 0; j <= i; j++) {
- float g = 0.0;
- for (int k = 0; k <= i; k++) {
- g += eval.V[k][i+1] * eval.V[k][j];
- }
- for (int k = 0; k <= i; k++) {
- eval.V[k][j] -= g * eval.d[k];
- }
- }
- }
- for (int k = 0; k <= i; k++) {
- eval.V[k][i+1] = 0.0;
- }
- }
- for (int j = 0; j < n; j++) {
- eval.d[j] = eval.V[n-1][j];
- eval.V[n-1][j] = 0.0;
- }
- eval.V[n-1][n-1] = 1.0;
- eval.e[0] = 0.0;
-}
-
-void Eigencdiv(sEigenvalue& eval, float xr, float xi, float yr, float yi) {
- float r,d;
- if (fabs(yr) > fabs(yi)) {
- r = yi/yr;
- d = yr + r*yi;
- eval.cdivr = (xr + r*xi)/d;
- eval.cdivi = (xi - r*xr)/d;
- } else {
- r = yr/yi;
- d = yi + r*yr;
- eval.cdivr = (r*xr + xi)/d;
- eval.cdivi = (r*xi - xr)/d;
- }
- }
-
-void Eigentql2 (sEigenvalue& eval) {
-
- // This is derived from the Algol procedures tql2, by
- // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
- // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- int n=eval.n;
-
- for (int i = 1; i < n; i++) {
- eval.e[i-1] = eval.e[i];
- }
- eval.e[n-1] = 0.0;
-
- float f = 0.0;
- float tst1 = 0.0;
- float eps = pow(2.0,-52.0);
- for (int l = 0; l < n; l++) {
-
- // Find small subdiagonal element
-
- tst1 = max(tst1,fabs(eval.d[l]) + fabs(eval.e[l]));
- int m = l;
-
- // Original while-loop from Java code
- while (m < n) {
- if (fabs(eval.e[m]) <= eps*tst1) {
- break;
- }
- m++;
- }
-
-
- // If m == l, d[l] is an eigenvalue,
- // otherwise, iterate.
-
- if (m > l) {
- int iter = 0;
- do {
- iter = iter + 1; // (Could check iteration count here.)
-
- // Compute implicit shift
-
- float g = eval.d[l];
- float p = (eval.d[l+1] - g) / (2.0f * eval.e[l]);
- float r = hypot(p,1.0);
- if (p < 0) {
- r = -r;
- }
- eval.d[l] = eval.e[l] / (p + r);
- eval.d[l+1] = eval.e[l] * (p + r);
- float dl1 = eval.d[l+1];
- float h = g - eval.d[l];
- for (int i = l+2; i < n; i++) {
- eval.d[i] -= h;
- }
- f = f + h;
-
- // Implicit QL transformation.
-
- p = eval.d[m];
- float c = 1.0;
- float c2 = c;
- float c3 = c;
- float el1 = eval.e[l+1];
- float s = 0.0;
- float s2 = 0.0;
- for (int i = m-1; i >= l; i--) {
- c3 = c2;
- c2 = c;
- s2 = s;
- g = c * eval.e[i];
- h = c * p;
- r = hypot(p,eval.e[i]);
- eval.e[i+1] = s * r;
- s = eval.e[i] / r;
- c = p / r;
- p = c * eval.d[i] - s * g;
- eval.d[i+1] = h + s * (c * g + s * eval.d[i]);
-
- // Accumulate transformation.
-
- for (int k = 0; k < n; k++) {
- h = eval.V[k][i+1];
- eval.V[k][i+1] = s * eval.V[k][i] + c * h;
- eval.V[k][i] = c * eval.V[k][i] - s * h;
- }
- }
- p = -s * s2 * c3 * el1 * eval.e[l] / dl1;
- eval.e[l] = s * p;
- eval.d[l] = c * p;
-
- // Check for convergence.
-
- } while (fabs(eval.e[l]) > eps*tst1);
- }
- eval.d[l] = eval.d[l] + f;
- eval.e[l] = 0.0;
- }
-
- // Sort eigenvalues and corresponding vectors.
-
- for (int i = 0; i < n-1; i++) {
- int k = i;
- float p = eval.d[i];
- for (int j = i+1; j < n; j++) {
- if (eval.d[j] < p) {
- k = j;
- p = eval.d[j];
- }
- }
- if (k != i) {
- eval.d[k] = eval.d[i];
- eval.d[i] = p;
- for (int j = 0; j < n; j++) {
- p = eval.V[j][i];
- eval.V[j][i] = eval.V[j][k];
- eval.V[j][k] = p;
- }
- }
- }
-}
-
-void Eigenorthes (sEigenvalue& eval) {
-
- // This is derived from the Algol procedures orthes and ortran,
- // by Martin and Wilkinson, Handbook for Auto. Comp.,
- // Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutines in EISPACK.
-
- int n=eval.n;
-
- int low = 0;
- int high = n-1;
-
- for (int m = low+1; m <= high-1; m++) {
-
- // Scale column.
-
- float scale = 0.0;
- for (int i = m; i <= high; i++) {
- scale = scale + fabs(eval.H[i][m-1]);
- }
- if (scale != 0.0f) {
-
- // Compute Householder transformation.
-
- float h = 0.0;
- for (int i = high; i >= m; i--) {
- eval.ort[i] = eval.H[i][m-1]/scale;
- h += eval.ort[i] * eval.ort[i];
- }
- float g = sqrt(h);
- if (eval.ort[m] > 0) {
- g = -g;
- }
- h = h - eval.ort[m] * g;
- eval.ort[m] = eval.ort[m] - g;
-
- // Apply Householder similarity transformation
- // H = (I-u*u'/h)*H*(I-u*u')/h)
-
- for (int j = m; j < n; j++) {
- float f = 0.0;
- for (int i = high; i >= m; i--) {
- f += eval.ort[i]*eval.H[i][j];
- }
- f = f/h;
- for (int i = m; i <= high; i++) {
- eval.H[i][j] -= f*eval.ort[i];
- }
- }
-
- for (int i = 0; i <= high; i++) {
- float f = 0.0;
- for (int j = high; j >= m; j--) {
- f += eval.ort[j]*eval.H[i][j];
- }
- f = f/h;
- for (int j = m; j <= high; j++) {
- eval.H[i][j] -= f*eval.ort[j];
- }
- }
- eval.ort[m] = scale*eval.ort[m];
- eval.H[m][m-1] = scale*g;
- }
- }
-
- // Accumulate transformations (Algol's ortran).
-
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- eval.V[i][j] = (i == j ? 1.0 : 0.0);
- }
- }
-
- for (int m = high-1; m >= low+1; m--) {
- if (eval.H[m][m-1] != 0.0f) {
- for (int i = m+1; i <= high; i++) {
- eval.ort[i] = eval.H[i][m-1];
- }
- for (int j = m; j <= high; j++) {
- float g = 0.0;
- for (int i = m; i <= high; i++) {
- g += eval.ort[i] * eval.V[i][j];
- }
- // Double division avoids possible underflow
- g = (g / eval.ort[m]) / eval.H[m][m-1];
- for (int i = m; i <= high; i++) {
- eval.V[i][j] += g * eval.ort[i];
- }
- }
- }
- }
- }
-
-void Eigenhqr2 (sEigenvalue& eval) {
-
- // This is derived from the Algol procedure hqr2,
- // by Martin and Wilkinson, Handbook for Auto. Comp.,
- // Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- // Initialize
-
- int nn = eval.n;
- int n = nn-1;
- int low = 0;
- int high = nn-1;
- float eps = pow(2.0,-52.0);
- float exshift = 0.0;
- float p=0,q=0,r=0,s=0,z=0,t,w,x,y;
-
- // Store roots isolated by balanc and compute matrix norm
-
- float norm = 0.0;
- for (int i = 0; i < nn; i++) {
- if ((i < low) || (i > high)) {
- eval.d[i] = eval.H[i][i];
- eval.e[i] = 0.0;
- }
- for (int j = max(i-1,0); j < nn; j++) {
- norm = norm + fabs(eval.H[i][j]);
- }
- }
-
- // Outer loop over eigenvalue index
-
- int iter = 0;
- int totIter = 0;
- while (n >= low) {
-
- // NT limit no. of iterations
- totIter++;
- if(totIter>100) {
- //if(totIter>15) std::cout<<"!!!!iter ABORT !!!!!!! "<<totIter<<"\n";
- // NT hack/fix, return large eigenvalues
- for (int i = 0; i < nn; i++) {
- eval.d[i] = 10000.;
- eval.e[i] = 10000.;
- }
- return;
- }
-
- // Look for single small sub-diagonal element
-
- int l = n;
- while (l > low) {
- s = fabs(eval.H[l-1][l-1]) + fabs(eval.H[l][l]);
- if (s == 0.0f) {
- s = norm;
- }
- if (fabs(eval.H[l][l-1]) < eps * s) {
- break;
- }
- l--;
- }
-
- // Check for convergence
- // One root found
-
- if (l == n) {
- eval.H[n][n] = eval.H[n][n] + exshift;
- eval.d[n] = eval.H[n][n];
- eval.e[n] = 0.0;
- n--;
- iter = 0;
-
- // Two roots found
-
- } else if (l == n-1) {
- w = eval.H[n][n-1] * eval.H[n-1][n];
- p = (eval.H[n-1][n-1] - eval.H[n][n]) / 2.0f;
- q = p * p + w;
- z = sqrt(fabs(q));
- eval.H[n][n] = eval.H[n][n] + exshift;
- eval.H[n-1][n-1] = eval.H[n-1][n-1] + exshift;
- x = eval.H[n][n];
-
- // float pair
-
- if (q >= 0) {
- if (p >= 0) {
- z = p + z;
- } else {
- z = p - z;
- }
- eval.d[n-1] = x + z;
- eval.d[n] = eval.d[n-1];
- if (z != 0.0f) {
- eval.d[n] = x - w / z;
- }
- eval.e[n-1] = 0.0;
- eval.e[n] = 0.0;
- x = eval.H[n][n-1];
- s = fabs(x) + fabs(z);
- p = x / s;
- q = z / s;
- r = sqrt(p * p+q * q);
- p = p / r;
- q = q / r;
-
- // Row modification
-
- for (int j = n-1; j < nn; j++) {
- z = eval.H[n-1][j];
- eval.H[n-1][j] = q * z + p * eval.H[n][j];
- eval.H[n][j] = q * eval.H[n][j] - p * z;
- }
-
- // Column modification
-
- for (int i = 0; i <= n; i++) {
- z = eval.H[i][n-1];
- eval.H[i][n-1] = q * z + p * eval.H[i][n];
- eval.H[i][n] = q * eval.H[i][n] - p * z;
- }
-
- // Accumulate transformations
-
- for (int i = low; i <= high; i++) {
- z = eval.V[i][n-1];
- eval.V[i][n-1] = q * z + p * eval.V[i][n];
- eval.V[i][n] = q * eval.V[i][n] - p * z;
- }
-
- // Complex pair
-
- } else {
- eval.d[n-1] = x + p;
- eval.d[n] = x + p;
- eval.e[n-1] = z;
- eval.e[n] = -z;
- }
- n = n - 2;
- iter = 0;
-
- // No convergence yet
-
- } else {
-
- // Form shift
-
- x = eval.H[n][n];
- y = 0.0;
- w = 0.0;
- if (l < n) {
- y = eval.H[n-1][n-1];
- w = eval.H[n][n-1] * eval.H[n-1][n];
- }
-
- // Wilkinson's original ad hoc shift
-
- if (iter == 10) {
- exshift += x;
- for (int i = low; i <= n; i++) {
- eval.H[i][i] -= x;
- }
- s = fabs(eval.H[n][n-1]) + fabs(eval.H[n-1][n-2]);
- x = y = 0.75f * s;
- w = -0.4375f * s * s;
- }
-
- // MATLAB's new ad hoc shift
-
- if (iter == 30) {
- s = (y - x) / 2.0f;
- s = s * s + w;
- if (s > 0) {
- s = sqrt(s);
- if (y < x) {
- s = -s;
- }
- s = x - w / ((y - x) / 2.0f + s);
- for (int i = low; i <= n; i++) {
- eval.H[i][i] -= s;
- }
- exshift += s;
- x = y = w = 0.964;
- }
- }
-
- iter = iter + 1; // (Could check iteration count here.)
-
- // Look for two consecutive small sub-diagonal elements
-
- int m = n-2;
- while (m >= l) {
- z = eval.H[m][m];
- r = x - z;
- s = y - z;
- p = (r * s - w) / eval.H[m+1][m] + eval.H[m][m+1];
- q = eval.H[m+1][m+1] - z - r - s;
- r = eval.H[m+2][m+1];
- s = fabs(p) + fabs(q) + fabs(r);
- p = p / s;
- q = q / s;
- r = r / s;
- if (m == l) {
- break;
- }
- if (fabs(eval.H[m][m-1]) * (fabs(q) + fabs(r)) <
- eps * (fabs(p) * (fabs(eval.H[m-1][m-1]) + fabs(z) +
- fabs(eval.H[m+1][m+1])))) {
- break;
- }
- m--;
- }
-
- for (int i = m+2; i <= n; i++) {
- eval.H[i][i-2] = 0.0;
- if (i > m+2) {
- eval.H[i][i-3] = 0.0;
- }
- }
-
- // Double QR step involving rows l:n and columns m:n
-
- for (int k = m; k <= n-1; k++) {
- int notlast = (k != n-1);
- if (k != m) {
- p = eval.H[k][k-1];
- q = eval.H[k+1][k-1];
- r = (notlast ? eval.H[k+2][k-1] : 0.0f);
- x = fabs(p) + fabs(q) + fabs(r);
- if (x != 0.0f) {
- p = p / x;
- q = q / x;
- r = r / x;
- }
- }
- if (x == 0.0f) {
- break;
- }
- s = sqrt(p * p + q * q + r * r);
- if (p < 0) {
- s = -s;
- }
- if (s != 0) {
- if (k != m) {
- eval.H[k][k-1] = -s * x;
- } else if (l != m) {
- eval.H[k][k-1] = -eval.H[k][k-1];
- }
- p = p + s;
- x = p / s;
- y = q / s;
- z = r / s;
- q = q / p;
- r = r / p;
-
- // Row modification
-
- for (int j = k; j < nn; j++) {
- p = eval.H[k][j] + q * eval.H[k+1][j];
- if (notlast) {
- p = p + r * eval.H[k+2][j];
- eval.H[k+2][j] = eval.H[k+2][j] - p * z;
- }
- eval.H[k][j] = eval.H[k][j] - p * x;
- eval.H[k+1][j] = eval.H[k+1][j] - p * y;
- }
-
- // Column modification
-
- for (int i = 0; i <= min(n,k+3); i++) {
- p = x * eval.H[i][k] + y * eval.H[i][k+1];
- if (notlast) {
- p = p + z * eval.H[i][k+2];
- eval.H[i][k+2] = eval.H[i][k+2] - p * r;
- }
- eval.H[i][k] = eval.H[i][k] - p;
- eval.H[i][k+1] = eval.H[i][k+1] - p * q;
- }
-
- // Accumulate transformations
-
- for (int i = low; i <= high; i++) {
- p = x * eval.V[i][k] + y * eval.V[i][k+1];
- if (notlast) {
- p = p + z * eval.V[i][k+2];
- eval.V[i][k+2] = eval.V[i][k+2] - p * r;
- }
- eval.V[i][k] = eval.V[i][k] - p;
- eval.V[i][k+1] = eval.V[i][k+1] - p * q;
- }
- } // (s != 0)
- } // k loop
- } // check convergence
- } // while (n >= low)
- //if(totIter>15) std::cout<<"!!!!iter "<<totIter<<"\n";
-
- // Backsubstitute to find vectors of upper triangular form
-
- if (norm == 0.0f) {
- return;
- }
-
- for (n = nn-1; n >= 0; n--) {
- p = eval.d[n];
- q = eval.e[n];
-
- // float vector
-
- if (q == 0) {
- int l = n;
- eval.H[n][n] = 1.0;
- for (int i = n-1; i >= 0; i--) {
- w = eval.H[i][i] - p;
- r = 0.0;
- for (int j = l; j <= n; j++) {
- r = r + eval.H[i][j] * eval.H[j][n];
- }
- if (eval.e[i] < 0.0f) {
- z = w;
- s = r;
- } else {
- l = i;
- if (eval.e[i] == 0.0f) {
- if (w != 0.0f) {
- eval.H[i][n] = -r / w;
- } else {
- eval.H[i][n] = -r / (eps * norm);
- }
-
- // Solve real equations
-
- } else {
- x = eval.H[i][i+1];
- y = eval.H[i+1][i];
- q = (eval.d[i] - p) * (eval.d[i] - p) + eval.e[i] * eval.e[i];
- t = (x * s - z * r) / q;
- eval.H[i][n] = t;
- if (fabs(x) > fabs(z)) {
- eval.H[i+1][n] = (-r - w * t) / x;
- } else {
- eval.H[i+1][n] = (-s - y * t) / z;
- }
- }
-
- // Overflow control
-
- t = fabs(eval.H[i][n]);
- if ((eps * t) * t > 1) {
- for (int j = i; j <= n; j++) {
- eval.H[j][n] = eval.H[j][n] / t;
- }
- }
- }
- }
-
- // Complex vector
-
- } else if (q < 0) {
- int l = n-1;
-
- // Last vector component imaginary so matrix is triangular
-
- if (fabs(eval.H[n][n-1]) > fabs(eval.H[n-1][n])) {
- eval.H[n-1][n-1] = q / eval.H[n][n-1];
- eval.H[n-1][n] = -(eval.H[n][n] - p) / eval.H[n][n-1];
- } else {
- Eigencdiv(eval, 0.0,-eval.H[n-1][n],eval.H[n-1][n-1]-p,q);
- eval.H[n-1][n-1] = eval.cdivr;
- eval.H[n-1][n] = eval.cdivi;
- }
- eval.H[n][n-1] = 0.0;
- eval.H[n][n] = 1.0;
- for (int i = n-2; i >= 0; i--) {
- float ra,sa,vr,vi;
- ra = 0.0;
- sa = 0.0;
- for (int j = l; j <= n; j++) {
- ra = ra + eval.H[i][j] * eval.H[j][n-1];
- sa = sa + eval.H[i][j] * eval.H[j][n];
- }
- w = eval.H[i][i] - p;
-
- if (eval.e[i] < 0.0f) {
- z = w;
- r = ra;
- s = sa;
- } else {
- l = i;
- if (eval.e[i] == 0) {
- Eigencdiv(eval,-ra,-sa,w,q);
- eval.H[i][n-1] = eval.cdivr;
- eval.H[i][n] = eval.cdivi;
- } else {
-
- // Solve complex equations
-
- x = eval.H[i][i+1];
- y = eval.H[i+1][i];
- vr = (eval.d[i] - p) * (eval.d[i] - p) + eval.e[i] * eval.e[i] - q * q;
- vi = (eval.d[i] - p) * 2.0f * q;
- if ((vr == 0.0f) && (vi == 0.0f)) {
- vr = eps * norm * (fabs(w) + fabs(q) +
- fabs(x) + fabs(y) + fabs(z));
- }
- Eigencdiv(eval, x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
- eval.H[i][n-1] = eval.cdivr;
- eval.H[i][n] = eval.cdivi;
- if (fabs(x) > (fabs(z) + fabs(q))) {
- eval.H[i+1][n-1] = (-ra - w * eval.H[i][n-1] + q * eval.H[i][n]) / x;
- eval.H[i+1][n] = (-sa - w * eval.H[i][n] - q * eval.H[i][n-1]) / x;
- } else {
- Eigencdiv(eval, -r-y*eval.H[i][n-1],-s-y*eval.H[i][n],z,q);
- eval.H[i+1][n-1] = eval.cdivr;
- eval.H[i+1][n] = eval.cdivi;
- }
- }
-
- // Overflow control
-
- t = max(fabs(eval.H[i][n-1]),fabs(eval.H[i][n]));
- if ((eps * t) * t > 1) {
- for (int j = i; j <= n; j++) {
- eval.H[j][n-1] = eval.H[j][n-1] / t;
- eval.H[j][n] = eval.H[j][n] / t;
- }
- }
- }
- }
- }
- }
-
- // Vectors of isolated roots
-
- for (int i = 0; i < nn; i++) {
- if (i < low || i > high) {
- for (int j = i; j < nn; j++) {
- eval.V[i][j] = eval.H[i][j];
- }
- }
- }
-
- // Back transformation to get eigenvectors of original matrix
-
- for (int j = nn-1; j >= low; j--) {
- for (int i = low; i <= high; i++) {
- z = 0.0;
- for (int k = low; k <= min(j,high); k++) {
- z = z + eval.V[i][k] * eval.H[k][j];
- }
- eval.V[i][j] = z;
- }
- }
-}
-
-
-
-int computeEigenvalues3x3(
- float dout[3],
- float a[3][3])
-{
- /*TNT::Array2D<float> A = TNT::Array2D<float>(3,3, &a[0][0]);
- TNT::Array1D<float> eig = TNT::Array1D<float>(3);
- TNT::Array1D<float> eigImag = TNT::Array1D<float>(3);
- JAMA::Eigenvalue<float> jeig = JAMA::Eigenvalue<float>(A);*/
-
- sEigenvalue jeig;
-
- // Compute the values
- {
- jeig.n = 3;
- int n=3;
- //V = Array2D<float>(n,n);
- //d = Array1D<float>(n);
- //e = Array1D<float>(n);
- for (int y=0; y<3; y++)
- {
- jeig.d[y]=0.0f;
- jeig.e[y]=0.0f;
- for (int t=0; t<3; t++) jeig.V[y][t]=0.0f;
- }
-
- jeig.issymmetric = 1;
- for (int j = 0; (j < 3) && jeig.issymmetric; j++) {
- for (int i = 0; (i < 3) && jeig.issymmetric; i++) {
- jeig.issymmetric = (a[i][j] == a[j][i]);
- }
- }
-
- if (jeig.issymmetric) {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- jeig.V[i][j] = a[i][j];
- }
- }
-
- // Tridiagonalize.
- Eigentred2(jeig);
-
- // Diagonalize.
- Eigentql2(jeig);
-
- } else {
- //H = TNT::Array2D<float>(n,n);
- for (int y=0; y<3; y++)
- {
- jeig.ort[y]=0.0f;
- for (int t=0; t<3; t++) jeig.H[y][t]=0.0f;
- }
- //ort = TNT::Array1D<float>(n);
-
- for (int j = 0; j < n; j++) {
- for (int i = 0; i < n; i++) {
- jeig.H[i][j] = a[i][j];
- }
- }
-
- // Reduce to Hessenberg form.
- Eigenorthes(jeig);
-
- // Reduce Hessenberg to real Schur form.
- Eigenhqr2(jeig);
- }
- }
-
- //jeig.getfloatEigenvalues(eig);
-
- // complex ones
- //jeig.getImagEigenvalues(eigImag);
- dout[0] = sqrt(jeig.d[0]*jeig.d[0] + jeig.e[0]*jeig.e[0]);
- dout[1] = sqrt(jeig.d[1]*jeig.d[1] + jeig.e[1]*jeig.e[1]);
- dout[2] = sqrt(jeig.d[2]*jeig.d[2] + jeig.e[2]*jeig.e[2]);
- return 0;
-}
diff --git a/intern/smoke/intern/EIGENVALUE_HELPER.h b/intern/smoke/intern/EIGENVALUE_HELPER.h
deleted file mode 100644
index ef204b442d9..00000000000
--- a/intern/smoke/intern/EIGENVALUE_HELPER.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-//////////////////////////////////////////////////////////////////////
-// Modified to not require TNT matrix library anymore. It was very slow
-// when being run in parallel. Required TNT JAMA::Eigenvalue libraries were
-// converted into independent functions.
-// - MiikaH
-//
-//////////////////////////////////////////////////////////////////////
-// Helper function, compute eigenvalues of 3x3 matrix
-//////////////////////////////////////////////////////////////////////
-
-#ifndef EIGENVAL_HELPER_H
-#define EIGENVAL_HELPER_H
-
-//#include "tnt/jama_eig.h"
-
-#include <algorithm>
-#include <cmath>
-
-using namespace std;
-
-//////////////////////////////////////////////////////////////////////
-// eigenvalues of 3x3 non-symmetric matrix
-//////////////////////////////////////////////////////////////////////
-
-
-struct sEigenvalue
-{
- int n;
- int issymmetric;
- float d[3]; /* real part */
- float e[3]; /* img part */
- float V[3][3]; /* Eigenvectors */
-
- float H[3][3];
-
-
- float ort[3];
-
- float cdivr;
- float cdivi;
-};
-
-void Eigentred2(sEigenvalue& eval);
-
-void Eigencdiv(sEigenvalue& eval, float xr, float xi, float yr, float yi);
-
-void Eigentql2 (sEigenvalue& eval);
-
-void Eigenorthes (sEigenvalue& eval);
-
-void Eigenhqr2 (sEigenvalue& eval);
-
-int computeEigenvalues3x3(float dout[3], float a[3][3]);
-
-
-#endif
diff --git a/intern/smoke/intern/FFT_NOISE.h b/intern/smoke/intern/FFT_NOISE.h
deleted file mode 100644
index d44cbabd64e..00000000000
--- a/intern/smoke/intern/FFT_NOISE.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-/////////////////////////////////////////////////////////////////////////
-//
-
-#ifndef FFT_NOISE_H_
-#define FFT_NOISE_H_
-
-#ifdef WITH_FFTW3
-#include <iostream>
-#include <fftw3.h>
-#include <MERSENNETWISTER.h>
-
-#include "WAVELET_NOISE.h"
-
-#ifndef M_PI
-#define M_PI 3.14159265
-#endif
-
-/////////////////////////////////////////////////////////////////////////
-// shift spectrum to the format that FFTW expects
-/////////////////////////////////////////////////////////////////////////
-static void shift3D(float*& field, int xRes, int yRes, int zRes)
-{
- int xHalf = xRes / 2;
- int yHalf = yRes / 2;
- int zHalf = zRes / 2;
- // int slabSize = xRes * yRes;
- for (int z = 0; z < zHalf; z++)
- for (int y = 0; y < yHalf; y++)
- for (int x = 0; x < xHalf; x++)
- {
- int index = x + y * xRes + z * xRes * yRes;
- float temp;
- int xSwap = xHalf;
- int ySwap = yHalf * xRes;
- int zSwap = zHalf * xRes * yRes;
-
- // [0,0,0] to [1,1,1]
- temp = field[index];
- field[index] = field[index + xSwap + ySwap + zSwap];
- field[index + xSwap + ySwap + zSwap] = temp;
-
- // [1,0,0] to [0,1,1]
- temp = field[index + xSwap];
- field[index + xSwap] = field[index + ySwap + zSwap];
- field[index + ySwap + zSwap] = temp;
-
- // [0,1,0] to [1,0,1]
- temp = field[index + ySwap];
- field[index + ySwap] = field[index + xSwap + zSwap];
- field[index + xSwap + zSwap] = temp;
-
- // [0,0,1] to [1,1,0]
- temp = field[index + zSwap];
- field[index + zSwap] = field[index + xSwap + ySwap];
- field[index + xSwap + ySwap] = temp;
- }
-}
-
-static void generatTile_FFT(float* const noiseTileData, std::string filename)
-{
- if (loadTile(noiseTileData, filename)) return;
-
- int res = NOISE_TILE_SIZE;
- int xRes = res;
- int yRes = res;
- int zRes = res;
- int totalCells = xRes * yRes * zRes;
-
- // create and shift the filter
- float* filter = new float[totalCells];
- for (int z = 0; z < zRes; z++)
- for (int y = 0; y < yRes; y++)
- for (int x = 0; x < xRes; x++)
- {
- int index = x + y * xRes + z * xRes * yRes;
- float diff[] = {(float)abs(x - xRes / 2),
- (float)abs(y - yRes / 2),
- (float)abs(z - zRes / 2)};
- float radius = sqrtf(diff[0] * diff[0] +
- diff[1] * diff[1] +
- diff[2] * diff[2]) / (xRes / 2);
- radius *= M_PI;
- float H = cos((M_PI / 2.0f) * log(4.0f * radius / M_PI) / log(2.0f));
- H = H * H;
- float filtered = H;
-
- // clamp everything outside the wanted band
- if (radius >= M_PI / 2.0f)
- filtered = 0.0f;
-
- // make sure to capture all low frequencies
- if (radius <= M_PI / 4.0f)
- filtered = 1.0f;
-
- filter[index] = filtered;
- }
- shift3D(filter, xRes, yRes, zRes);
-
- // create the noise
- float* noise = new float[totalCells];
- int index = 0;
- MTRand twister;
- for (int z = 0; z < zRes; z++)
- for (int y = 0; y < yRes; y++)
- for (int x = 0; x < xRes; x++, index++)
- noise[index] = twister.randNorm();
-
- // create padded field
- fftw_complex* forward = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * totalCells);
-
- // init padded field
- index = 0;
- for (int z = 0; z < zRes; z++)
- for (int y = 0; y < yRes; y++)
- for (int x = 0; x < xRes; x++, index++)
- {
- forward[index][0] = noise[index];
- forward[index][1] = 0.0f;
- }
-
- // forward FFT
- fftw_complex* backward = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * totalCells);
- fftw_plan forwardPlan = fftw_plan_dft_3d(xRes, yRes, zRes, forward, backward, FFTW_FORWARD, FFTW_ESTIMATE);
- fftw_execute(forwardPlan);
- fftw_destroy_plan(forwardPlan);
-
- // apply filter
- index = 0;
- for (int z = 0; z < zRes; z++)
- for (int y = 0; y < yRes; y++)
- for (int x = 0; x < xRes; x++, index++)
- {
- backward[index][0] *= filter[index];
- backward[index][1] *= filter[index];
- }
-
- // backward FFT
- fftw_plan backwardPlan = fftw_plan_dft_3d(xRes, yRes, zRes, backward, forward, FFTW_BACKWARD, FFTW_ESTIMATE);
- fftw_execute(backwardPlan);
- fftw_destroy_plan(backwardPlan);
-
- // subtract out the low frequency components
- index = 0;
- for (int z = 0; z < zRes; z++)
- for (int y = 0; y < yRes; y++)
- for (int x = 0; x < xRes; x++, index++)
- noise[index] -= forward[index][0] / totalCells;
-
- // fill noiseTileData
- memcpy(noiseTileData, noise, sizeof(float) * totalCells);
- // save out the noise tile
- saveTile(noise, filename);
-
- fftw_free(forward);
- fftw_free(backward);
- delete[] filter;
- delete[] noise;
-}
-
-#endif
-
-#endif /* FFT_NOISE_H_ */
diff --git a/intern/smoke/intern/FLUID_3D.cpp b/intern/smoke/intern/FLUID_3D.cpp
deleted file mode 100644
index e76abea35d8..00000000000
--- a/intern/smoke/intern/FLUID_3D.cpp
+++ /dev/null
@@ -1,1792 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// FLUID_3D.cpp: implementation of the FLUID_3D class.
-//
-//////////////////////////////////////////////////////////////////////
-// Heavy parallel optimization done. Many of the old functions now
-// take begin and end parameters and process only specified part of the data.
-// Some functions were divided into multiple ones.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#include "FLUID_3D.h"
-#include "IMAGE.h"
-#include <INTERPOLATE.h>
-#include "SPHERE.h"
-#include <zlib.h>
-
-#include "float.h"
-
-#if PARALLEL==1
-#include <omp.h>
-#endif // PARALLEL
-
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
-FLUID_3D::FLUID_3D(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors) :
- _xRes(res[0]), _yRes(res[1]), _zRes(res[2]), _res(0.0f)
-{
- // set simulation consts
- _dt = dtdef; // just in case. set in step from a RNA factor
-
- _iterations = 100;
- _tempAmb = 0;
- _heatDiffusion = 1e-3;
- _totalTime = 0.0f;
- _totalSteps = 0;
- _res = Vec3Int(_xRes,_yRes,_zRes);
- _maxRes = MAX3(_xRes, _yRes, _zRes);
-
- // initialize wavelet turbulence
- /*
- if(amplify)
- _wTurbulence = new WTURBULENCE(_res[0],_res[1],_res[2], amplify, noisetype);
- else
- _wTurbulence = NULL;
- */
-
- // scale the constants according to the refinement of the grid
- if (!dx)
- _dx = 1.0f / (float)_maxRes;
- else
- _dx = dx;
- _constantScaling = 64.0f / _maxRes;
- _constantScaling = (_constantScaling < 1.0f) ? 1.0f : _constantScaling;
- _vorticityEps = 2.0f / _constantScaling; // Just in case set a default value
-
- // allocate arrays
- _totalCells = _xRes * _yRes * _zRes;
- _slabSize = _xRes * _yRes;
- _xVelocity = new float[_totalCells];
- _yVelocity = new float[_totalCells];
- _zVelocity = new float[_totalCells];
- _xVelocityOb = new float[_totalCells];
- _yVelocityOb = new float[_totalCells];
- _zVelocityOb = new float[_totalCells];
- _xVelocityOld = new float[_totalCells];
- _yVelocityOld = new float[_totalCells];
- _zVelocityOld = new float[_totalCells];
- _xForce = new float[_totalCells];
- _yForce = new float[_totalCells];
- _zForce = new float[_totalCells];
- _density = new float[_totalCells];
- _densityOld = new float[_totalCells];
- _obstacles = new unsigned char[_totalCells]; // set 0 at end of step
-
- // For threaded version:
- _xVelocityTemp = new float[_totalCells];
- _yVelocityTemp = new float[_totalCells];
- _zVelocityTemp = new float[_totalCells];
- _densityTemp = new float[_totalCells];
-
- // DG TODO: check if alloc went fine
-
- for (int x = 0; x < _totalCells; x++)
- {
- _density[x] = 0.0f;
- _densityOld[x] = 0.0f;
- _xVelocity[x] = 0.0f;
- _yVelocity[x] = 0.0f;
- _zVelocity[x] = 0.0f;
- _xVelocityOb[x] = 0.0f;
- _yVelocityOb[x] = 0.0f;
- _zVelocityOb[x] = 0.0f;
- _xVelocityOld[x] = 0.0f;
- _yVelocityOld[x] = 0.0f;
- _zVelocityOld[x] = 0.0f;
- _xForce[x] = 0.0f;
- _yForce[x] = 0.0f;
- _zForce[x] = 0.0f;
- _obstacles[x] = false;
- }
-
- /* heat */
- _heat = _heatOld = _heatTemp = NULL;
- if (init_heat) {
- initHeat();
- }
- // Fire simulation
- _flame = _fuel = _fuelTemp = _fuelOld = NULL;
- _react = _reactTemp = _reactOld = NULL;
- if (init_fire) {
- initFire();
- }
- // Smoke color
- _color_r = _color_rOld = _color_rTemp = NULL;
- _color_g = _color_gOld = _color_gTemp = NULL;
- _color_b = _color_bOld = _color_bTemp = NULL;
- if (init_colors) {
- initColors(0.0f, 0.0f, 0.0f);
- }
-
- // boundary conditions of the fluid domain
- // set default values -> vertically non-colliding
- _domainBcFront = true;
- _domainBcTop = false;
- _domainBcLeft = true;
- _domainBcBack = _domainBcFront;
- _domainBcBottom = _domainBcTop;
- _domainBcRight = _domainBcLeft;
-
- _colloPrev = 1; // default value
-}
-
-void FLUID_3D::initHeat()
-{
- if (!_heat) {
- _heat = new float[_totalCells];
- _heatOld = new float[_totalCells];
- _heatTemp = new float[_totalCells];
-
- for (int x = 0; x < _totalCells; x++)
- {
- _heat[x] = 0.0f;
- _heatOld[x] = 0.0f;
- }
- }
-}
-
-void FLUID_3D::initFire()
-{
- if (!_flame) {
- _flame = new float[_totalCells];
- _fuel = new float[_totalCells];
- _fuelTemp = new float[_totalCells];
- _fuelOld = new float[_totalCells];
- _react = new float[_totalCells];
- _reactTemp = new float[_totalCells];
- _reactOld = new float[_totalCells];
-
- for (int x = 0; x < _totalCells; x++)
- {
- _flame[x] = 0.0f;
- _fuel[x] = 0.0f;
- _fuelTemp[x] = 0.0f;
- _fuelOld[x] = 0.0f;
- _react[x] = 0.0f;
- _reactTemp[x] = 0.0f;
- _reactOld[x] = 0.0f;
- }
- }
-}
-
-void FLUID_3D::initColors(float init_r, float init_g, float init_b)
-{
- if (!_color_r) {
- _color_r = new float[_totalCells];
- _color_rOld = new float[_totalCells];
- _color_rTemp = new float[_totalCells];
- _color_g = new float[_totalCells];
- _color_gOld = new float[_totalCells];
- _color_gTemp = new float[_totalCells];
- _color_b = new float[_totalCells];
- _color_bOld = new float[_totalCells];
- _color_bTemp = new float[_totalCells];
-
- for (int x = 0; x < _totalCells; x++)
- {
- _color_r[x] = _density[x] * init_r;
- _color_rOld[x] = 0.0f;
- _color_g[x] = _density[x] * init_g;
- _color_gOld[x] = 0.0f;
- _color_b[x] = _density[x] * init_b;
- _color_bOld[x] = 0.0f;
- }
- }
-}
-
-void FLUID_3D::setBorderObstacles()
-{
-
- // set side obstacles
- unsigned int index;
- for (int y = 0; y < _yRes; y++)
- for (int x = 0; x < _xRes; x++)
- {
- // bottom slab
- index = x + y * _xRes;
- if(_domainBcBottom) _obstacles[index] = 1;
-
- // top slab
- index += _totalCells - _slabSize;
- if(_domainBcTop) _obstacles[index] = 1;
- }
-
- for (int z = 0; z < _zRes; z++)
- for (int x = 0; x < _xRes; x++)
- {
- // front slab
- index = x + z * _slabSize;
- if(_domainBcFront) _obstacles[index] = 1;
-
- // back slab
- index += _slabSize - _xRes;
- if(_domainBcBack) _obstacles[index] = 1;
- }
-
- for (int z = 0; z < _zRes; z++)
- for (int y = 0; y < _yRes; y++)
- {
- // left slab
- index = y * _xRes + z * _slabSize;
- if(_domainBcLeft) _obstacles[index] = 1;
-
- // right slab
- index += _xRes - 1;
- if(_domainBcRight) _obstacles[index] = 1;
- }
-}
-
-FLUID_3D::~FLUID_3D()
-{
- if (_xVelocity) delete[] _xVelocity;
- if (_yVelocity) delete[] _yVelocity;
- if (_zVelocity) delete[] _zVelocity;
- if (_xVelocityOb) delete[] _xVelocityOb;
- if (_yVelocityOb) delete[] _yVelocityOb;
- if (_zVelocityOb) delete[] _zVelocityOb;
- if (_xVelocityOld) delete[] _xVelocityOld;
- if (_yVelocityOld) delete[] _yVelocityOld;
- if (_zVelocityOld) delete[] _zVelocityOld;
- if (_xForce) delete[] _xForce;
- if (_yForce) delete[] _yForce;
- if (_zForce) delete[] _zForce;
- if (_density) delete[] _density;
- if (_densityOld) delete[] _densityOld;
- if (_heat) delete[] _heat;
- if (_heatOld) delete[] _heatOld;
- if (_obstacles) delete[] _obstacles;
-
- if (_xVelocityTemp) delete[] _xVelocityTemp;
- if (_yVelocityTemp) delete[] _yVelocityTemp;
- if (_zVelocityTemp) delete[] _zVelocityTemp;
- if (_densityTemp) delete[] _densityTemp;
- if (_heatTemp) delete[] _heatTemp;
-
- if (_flame) delete[] _flame;
- if (_fuel) delete[] _fuel;
- if (_fuelTemp) delete[] _fuelTemp;
- if (_fuelOld) delete[] _fuelOld;
- if (_react) delete[] _react;
- if (_reactTemp) delete[] _reactTemp;
- if (_reactOld) delete[] _reactOld;
-
- if (_color_r) delete[] _color_r;
- if (_color_rOld) delete[] _color_rOld;
- if (_color_rTemp) delete[] _color_rTemp;
- if (_color_g) delete[] _color_g;
- if (_color_gOld) delete[] _color_gOld;
- if (_color_gTemp) delete[] _color_gTemp;
- if (_color_b) delete[] _color_b;
- if (_color_bOld) delete[] _color_bOld;
- if (_color_bTemp) delete[] _color_bTemp;
-
- // printf("deleted fluid\n");
-}
-
-// init direct access functions from blender
-void FLUID_3D::initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *borderCollision, float *burning_rate,
- float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp)
-{
- _alpha = alpha;
- _beta = beta;
- _dtFactor = dt_factor;
- _vorticityRNA = vorticity;
- _borderColli = borderCollision;
- _burning_rate = burning_rate;
- _flame_smoke = flame_smoke;
- _flame_smoke_color = flame_smoke_color;
- _flame_vorticity = flame_vorticity;
- _ignition_temp = flame_ignition_temp;
- _max_temp = flame_max_temp;
-}
-
-//////////////////////////////////////////////////////////////////////
-// step simulation once
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::step(float dt, float gravity[3])
-{
-#if 0
- // If border rules have been changed
- if (_colloPrev != *_borderColli) {
- printf("Border collisions changed\n");
-
- // DG TODO: Need to check that no animated obstacle flags are overwritten
- setBorderCollisions();
- }
-#endif
-
- // DG: TODO for the moment redo border for every timestep since it's been deleted every time by moving obstacles
- setBorderCollisions();
-
-
- // set delta time by dt_factor
- _dt = (*_dtFactor) * dt;
- // set vorticity from RNA value
- _vorticityEps = (*_vorticityRNA)/_constantScaling;
-
-#if PARALLEL==1
- int threadval = 1;
- threadval = omp_get_max_threads();
-
- int stepParts = 1;
- float partSize = _zRes;
-
- stepParts = threadval*2; // Dividing parallelized sections into numOfThreads * 2 sections
- partSize = (float)_zRes/stepParts; // Size of one part;
-
- if (partSize < 4) {stepParts = threadval; // If the slice gets too low (might actually slow things down, change it to larger
- partSize = (float)_zRes/stepParts;}
- if (partSize < 4) {stepParts = (int)(ceil((float)_zRes/4.0f)); // If it's still too low (only possible on future systems with +24 cores), change it to 4
- partSize = (float)_zRes/stepParts;}
-#else
- int zBegin=0;
- int zEnd=_zRes;
-#endif
-
- wipeBoundariesSL(0, _zRes);
-
-#if PARALLEL==1
- #pragma omp parallel
- {
- #pragma omp for schedule(static,1)
- for (int i=0; i<stepParts; i++)
- {
- int zBegin = (int)((float)i*partSize + 0.5f);
- int zEnd = (int)((float)(i+1)*partSize + 0.5f);
-#endif
-
- addVorticity(zBegin, zEnd);
- addBuoyancy(_heat, _density, gravity, zBegin, zEnd);
- addForce(zBegin, zEnd);
-
-#if PARALLEL==1
- } // end of parallel
- #pragma omp barrier
-
- #pragma omp single
- {
-#endif
- /*
- * addForce() changed Temp values to preserve thread safety
- * (previous functions in per thread loop still needed
- * original velocity data)
- *
- * So swap temp values to velocity
- */
- SWAP_POINTERS(_xVelocity, _xVelocityTemp);
- SWAP_POINTERS(_yVelocity, _yVelocityTemp);
- SWAP_POINTERS(_zVelocity, _zVelocityTemp);
-#if PARALLEL==1
- } // end of single
-
- #pragma omp barrier
-
- #pragma omp for
- for (int i=0; i<2; i++)
- {
- if (i==0)
- {
-#endif
- project();
-#if PARALLEL==1
- }
- else if (i==1)
- {
-#endif
- if (_heat) {
- diffuseHeat();
- }
-#if PARALLEL==1
- }
- }
-
- #pragma omp barrier
-
- #pragma omp single
- {
-#endif
- /*
- * For thread safety use "Old" to read
- * "current" values but still allow changing values.
- */
- SWAP_POINTERS(_xVelocity, _xVelocityOld);
- SWAP_POINTERS(_yVelocity, _yVelocityOld);
- SWAP_POINTERS(_zVelocity, _zVelocityOld);
- SWAP_POINTERS(_density, _densityOld);
- SWAP_POINTERS(_heat, _heatOld);
-
- SWAP_POINTERS(_fuel, _fuelOld);
- SWAP_POINTERS(_react, _reactOld);
-
- SWAP_POINTERS(_color_r, _color_rOld);
- SWAP_POINTERS(_color_g, _color_gOld);
- SWAP_POINTERS(_color_b, _color_bOld);
-
- advectMacCormackBegin(0, _zRes);
-
-#if PARALLEL==1
- } // end of single
-
- #pragma omp barrier
-
-
- #pragma omp for schedule(static,1)
- for (int i=0; i<stepParts; i++)
- {
-
- int zBegin = (int)((float)i*partSize + 0.5f);
- int zEnd = (int)((float)(i+1)*partSize + 0.5f);
-#endif
-
- advectMacCormackEnd1(zBegin, zEnd);
-
-#if PARALLEL==1
- } // end of parallel
-
- #pragma omp barrier
-
- #pragma omp for schedule(static,1)
- for (int i=0; i<stepParts; i++)
- {
-
- int zBegin = (int)((float)i*partSize + 0.5f);
- int zEnd = (int)((float)(i+1)*partSize + 0.5f);
-#endif
-
- advectMacCormackEnd2(zBegin, zEnd);
-
- artificialDampingSL(zBegin, zEnd);
-
- // Using forces as temp arrays
-
-#if PARALLEL==1
- }
- }
-
-
-
- for (int i=1; i<stepParts; i++)
- {
- int zPos=(int)((float)i*partSize + 0.5f);
-
- artificialDampingExactSL(zPos);
-
- }
-#endif
-
- /*
- * swap final velocity back to Velocity array
- * from temp xForce storage
- */
- SWAP_POINTERS(_xVelocity, _xForce);
- SWAP_POINTERS(_yVelocity, _yForce);
- SWAP_POINTERS(_zVelocity, _zForce);
-
- _totalTime += _dt;
- _totalSteps++;
-
- for (int i = 0; i < _totalCells; i++)
- {
- _xForce[i] = _yForce[i] = _zForce[i] = 0.0f;
- }
-
-}
-
-
-// Set border collision model from RNA setting
-
-void FLUID_3D::setBorderCollisions() {
-
-
- _colloPrev = *_borderColli; // saving the current value
-
- // boundary conditions of the fluid domain
- if (_colloPrev == 0)
- {
- // No collisions
- _domainBcFront = false;
- _domainBcTop = false;
- _domainBcLeft = false;
- }
- else if (_colloPrev == 2)
- {
- // Collide with all sides
- _domainBcFront = true;
- _domainBcTop = true;
- _domainBcLeft = true;
- }
- else
- {
- // Default values: Collide with "walls", but not top and bottom
- _domainBcFront = true;
- _domainBcTop = false;
- _domainBcLeft = true;
- }
-
- _domainBcBack = _domainBcFront;
- _domainBcBottom = _domainBcTop;
- _domainBcRight = _domainBcLeft;
-
-
-
- // set side obstacles
- setBorderObstacles();
-}
-
-//////////////////////////////////////////////////////////////////////
-// helper function to dampen co-located grid artifacts of given arrays in intervals
-// (only needed for velocity, strength (w) depends on testcase...
-//////////////////////////////////////////////////////////////////////
-
-
-void FLUID_3D::artificialDampingSL(int zBegin, int zEnd) {
- const float w = 0.9;
-
- memmove(_xForce+(_slabSize*zBegin), _xVelocityTemp+(_slabSize*zBegin), sizeof(float)*_slabSize*(zEnd-zBegin));
- memmove(_yForce+(_slabSize*zBegin), _yVelocityTemp+(_slabSize*zBegin), sizeof(float)*_slabSize*(zEnd-zBegin));
- memmove(_zForce+(_slabSize*zBegin), _zVelocityTemp+(_slabSize*zBegin), sizeof(float)*_slabSize*(zEnd-zBegin));
-
-
- if(_totalSteps % 4 == 1) {
- for (int z = zBegin+1; z < zEnd-1; z++)
- for (int y = 1; y < _res[1]-1; y++)
- for (int x = 1+(y+z)%2; x < _res[0]-1; x+=2) {
- const int index = x + y*_res[0] + z * _slabSize;
- _xForce[index] = (1-w)*_xVelocityTemp[index] + 1.0f/6.0f * w*(
- _xVelocityTemp[index+1] + _xVelocityTemp[index-1] +
- _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] +
- _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] );
-
- _yForce[index] = (1-w)*_yVelocityTemp[index] + 1.0f/6.0f * w*(
- _yVelocityTemp[index+1] + _yVelocityTemp[index-1] +
- _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] +
- _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] );
-
- _zForce[index] = (1-w)*_zVelocityTemp[index] + 1.0f/6.0f * w*(
- _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
- _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
- _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
- }
- }
-
- if(_totalSteps % 4 == 3) {
- for (int z = zBegin+1; z < zEnd-1; z++)
- for (int y = 1; y < _res[1]-1; y++)
- for (int x = 1+(y+z+1)%2; x < _res[0]-1; x+=2) {
- const int index = x + y*_res[0] + z * _slabSize;
- _xForce[index] = (1-w)*_xVelocityTemp[index] + 1.0f/6.0f * w*(
- _xVelocityTemp[index+1] + _xVelocityTemp[index-1] +
- _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] +
- _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] );
-
- _yForce[index] = (1-w)*_yVelocityTemp[index] + 1.0f/6.0f * w*(
- _yVelocityTemp[index+1] + _yVelocityTemp[index-1] +
- _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] +
- _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] );
-
- _zForce[index] = (1-w)*_zVelocityTemp[index] + 1.0f/6.0f * w*(
- _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
- _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
- _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
- }
-
- }
-}
-
-
-
-void FLUID_3D::artificialDampingExactSL(int pos) {
- const float w = 0.9;
- int index, x,y,z;
-
-
- size_t posslab;
-
- for (z=pos-1; z<=pos; z++)
- {
- posslab=z * _slabSize;
-
- if(_totalSteps % 4 == 1) {
- for (y = 1; y < _res[1]-1; y++)
- for (x = 1+(y+z)%2; x < _res[0]-1; x+=2) {
- index = x + y*_res[0] + posslab;
- /*
- * Uses xForce as temporary storage to allow other threads to read
- * old values from xVelocityTemp
- */
- _xForce[index] = (1-w)*_xVelocityTemp[index] + 1.0f/6.0f * w*(
- _xVelocityTemp[index+1] + _xVelocityTemp[index-1] +
- _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] +
- _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] );
-
- _yForce[index] = (1-w)*_yVelocityTemp[index] + 1.0f/6.0f * w*(
- _yVelocityTemp[index+1] + _yVelocityTemp[index-1] +
- _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] +
- _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] );
-
- _zForce[index] = (1-w)*_zVelocityTemp[index] + 1.0f/6.0f * w*(
- _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
- _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
- _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
-
- }
- }
-
- if(_totalSteps % 4 == 3) {
- for (y = 1; y < _res[1]-1; y++)
- for (x = 1+(y+z+1)%2; x < _res[0]-1; x+=2) {
- index = x + y*_res[0] + posslab;
-
- /*
- * Uses xForce as temporary storage to allow other threads to read
- * old values from xVelocityTemp
- */
- _xForce[index] = (1-w)*_xVelocityTemp[index] + 1.0f/6.0f * w*(
- _xVelocityTemp[index+1] + _xVelocityTemp[index-1] +
- _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] +
- _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] );
-
- _yForce[index] = (1-w)*_yVelocityTemp[index] + 1.0f/6.0f * w*(
- _yVelocityTemp[index+1] + _yVelocityTemp[index-1] +
- _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] +
- _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] );
-
- _zForce[index] = (1-w)*_zVelocityTemp[index] + 1.0f/6.0f * w*(
- _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
- _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
- _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
-
- }
-
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// copy out the boundary in all directions
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::copyBorderAll(float* field, int zBegin, int zEnd)
-{
- int index, x, y, z;
- int zSize = zEnd-zBegin;
- int _blockTotalCells=_slabSize * zSize;
-
- if (zBegin==0)
- for (int y = 0; y < _yRes; y++)
- for (int x = 0; x < _xRes; x++)
- {
- // front slab
- index = x + y * _xRes;
- field[index] = field[index + _slabSize];
- }
-
- if (zEnd==_zRes)
- for (y = 0; y < _yRes; y++)
- for (x = 0; x < _xRes; x++)
- {
-
- // back slab
- index = x + y * _xRes + _blockTotalCells - _slabSize;
- field[index] = field[index - _slabSize];
- }
-
- for (z = 0; z < zSize; z++)
- for (x = 0; x < _xRes; x++)
- {
- // bottom slab
- index = x + z * _slabSize;
- field[index] = field[index + _xRes];
-
- // top slab
- index += _slabSize - _xRes;
- field[index] = field[index - _xRes];
- }
-
- for (z = 0; z < zSize; z++)
- for (y = 0; y < _yRes; y++)
- {
- // left slab
- index = y * _xRes + z * _slabSize;
- field[index] = field[index + 1];
-
- // right slab
- index += _xRes - 1;
- field[index] = field[index - 1];
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// wipe boundaries of velocity and density
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::wipeBoundaries(int zBegin, int zEnd)
-{
- setZeroBorder(_xVelocity, _res, zBegin, zEnd);
- setZeroBorder(_yVelocity, _res, zBegin, zEnd);
- setZeroBorder(_zVelocity, _res, zBegin, zEnd);
- setZeroBorder(_density, _res, zBegin, zEnd);
- if (_fuel) {
- setZeroBorder(_fuel, _res, zBegin, zEnd);
- setZeroBorder(_react, _res, zBegin, zEnd);
- }
- if (_color_r) {
- setZeroBorder(_color_r, _res, zBegin, zEnd);
- setZeroBorder(_color_g, _res, zBegin, zEnd);
- setZeroBorder(_color_b, _res, zBegin, zEnd);
- }
-}
-
-void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
-{
-
- /////////////////////////////////////
- // setZeroBorder to all:
- /////////////////////////////////////
-
- /////////////////////////////////////
- // setZeroX
- /////////////////////////////////////
-
- const int slabSize = _xRes * _yRes;
- int index, x,y,z;
-
- for (z = zBegin; z < zEnd; z++)
- for (y = 0; y < _yRes; y++)
- {
- // left slab
- index = y * _xRes + z * slabSize;
- _xVelocity[index] = 0.0f;
- _yVelocity[index] = 0.0f;
- _zVelocity[index] = 0.0f;
- _density[index] = 0.0f;
- if (_fuel) {
- _fuel[index] = 0.0f;
- _react[index] = 0.0f;
- }
- if (_color_r) {
- _color_r[index] = 0.0f;
- _color_g[index] = 0.0f;
- _color_b[index] = 0.0f;
- }
-
- // right slab
- index += _xRes - 1;
- _xVelocity[index] = 0.0f;
- _yVelocity[index] = 0.0f;
- _zVelocity[index] = 0.0f;
- _density[index] = 0.0f;
- if (_fuel) {
- _fuel[index] = 0.0f;
- _react[index] = 0.0f;
- }
- if (_color_r) {
- _color_r[index] = 0.0f;
- _color_g[index] = 0.0f;
- _color_b[index] = 0.0f;
- }
- }
-
- /////////////////////////////////////
- // setZeroY
- /////////////////////////////////////
-
- for (z = zBegin; z < zEnd; z++)
- for (x = 0; x < _xRes; x++)
- {
- // bottom slab
- index = x + z * slabSize;
- _xVelocity[index] = 0.0f;
- _yVelocity[index] = 0.0f;
- _zVelocity[index] = 0.0f;
- _density[index] = 0.0f;
- if (_fuel) {
- _fuel[index] = 0.0f;
- _react[index] = 0.0f;
- }
- if (_color_r) {
- _color_r[index] = 0.0f;
- _color_g[index] = 0.0f;
- _color_b[index] = 0.0f;
- }
-
- // top slab
- index += slabSize - _xRes;
- _xVelocity[index] = 0.0f;
- _yVelocity[index] = 0.0f;
- _zVelocity[index] = 0.0f;
- _density[index] = 0.0f;
- if (_fuel) {
- _fuel[index] = 0.0f;
- _react[index] = 0.0f;
- }
- if (_color_r) {
- _color_r[index] = 0.0f;
- _color_g[index] = 0.0f;
- _color_b[index] = 0.0f;
- }
-
- }
-
- /////////////////////////////////////
- // setZeroZ
- /////////////////////////////////////
-
-
- const int totalCells = _xRes * _yRes * _zRes;
-
- index = 0;
- if (zBegin == 0)
- for (y = 0; y < _yRes; y++)
- for (x = 0; x < _xRes; x++, index++)
- {
- // front slab
- _xVelocity[index] = 0.0f;
- _yVelocity[index] = 0.0f;
- _zVelocity[index] = 0.0f;
- _density[index] = 0.0f;
- if (_fuel) {
- _fuel[index] = 0.0f;
- _react[index] = 0.0f;
- }
- if (_color_r) {
- _color_r[index] = 0.0f;
- _color_g[index] = 0.0f;
- _color_b[index] = 0.0f;
- }
- }
-
- if (zEnd == _zRes)
- {
- index=0;
- int index_top=0;
- const int cellsslab = totalCells - slabSize;
-
- for (y = 0; y < _yRes; y++)
- for (x = 0; x < _xRes; x++, index++)
- {
-
- // back slab
- index_top = index + cellsslab;
- _xVelocity[index_top] = 0.0f;
- _yVelocity[index_top] = 0.0f;
- _zVelocity[index_top] = 0.0f;
- _density[index_top] = 0.0f;
- if (_fuel) {
- _fuel[index_top] = 0.0f;
- _react[index_top] = 0.0f;
- }
- if (_color_r) {
- _color_r[index_top] = 0.0f;
- _color_g[index_top] = 0.0f;
- _color_b[index_top] = 0.0f;
- }
- }
- }
-
-}
-//////////////////////////////////////////////////////////////////////
-// add forces to velocity field
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::addForce(int zBegin, int zEnd)
-{
- int begin=zBegin * _slabSize;
- int end=begin + (zEnd - zBegin) * _slabSize;
-
- for (int i = begin; i < end; i++)
- {
- _xVelocityTemp[i] = _xVelocity[i] + _dt * _xForce[i];
- _yVelocityTemp[i] = _yVelocity[i] + _dt * _yForce[i];
- _zVelocityTemp[i] = _zVelocity[i] + _dt * _zForce[i];
- }
-}
-//////////////////////////////////////////////////////////////////////
-// project into divergence free field
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::project()
-{
- int x, y, z;
- size_t index;
-
- float *_pressure = new float[_totalCells];
- float *_divergence = new float[_totalCells];
-
- memset(_pressure, 0, sizeof(float)*_totalCells);
- memset(_divergence, 0, sizeof(float)*_totalCells);
-
- // set velocity and pressure inside of obstacles to zero
- setObstacleBoundaries(_pressure, 0, _zRes);
-
- // copy out the boundaries
- if(!_domainBcLeft) setNeumannX(_xVelocity, _res, 0, _zRes);
- else setZeroX(_xVelocity, _res, 0, _zRes);
-
- if(!_domainBcFront) setNeumannY(_yVelocity, _res, 0, _zRes);
- else setZeroY(_yVelocity, _res, 0, _zRes);
-
- if(!_domainBcTop) setNeumannZ(_zVelocity, _res, 0, _zRes);
- else setZeroZ(_zVelocity, _res, 0, _zRes);
-
- // calculate divergence
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
-
- if(_obstacles[index])
- {
- _divergence[index] = 0.0f;
- continue;
- }
-
-
- float xright = _xVelocity[index + 1];
- float xleft = _xVelocity[index - 1];
- float yup = _yVelocity[index + _xRes];
- float ydown = _yVelocity[index - _xRes];
- float ztop = _zVelocity[index + _slabSize];
- float zbottom = _zVelocity[index - _slabSize];
-
- if(_obstacles[index+1]) xright = - _xVelocity[index]; // DG: +=
- if(_obstacles[index-1]) xleft = - _xVelocity[index];
- if(_obstacles[index+_xRes]) yup = - _yVelocity[index];
- if(_obstacles[index-_xRes]) ydown = - _yVelocity[index];
- if(_obstacles[index+_slabSize]) ztop = - _zVelocity[index];
- if(_obstacles[index-_slabSize]) zbottom = - _zVelocity[index];
-
- if(_obstacles[index+1] & 8) xright += _xVelocityOb[index + 1];
- if(_obstacles[index-1] & 8) xleft += _xVelocityOb[index - 1];
- if(_obstacles[index+_xRes] & 8) yup += _yVelocityOb[index + _xRes];
- if(_obstacles[index-_xRes] & 8) ydown += _yVelocityOb[index - _xRes];
- if(_obstacles[index+_slabSize] & 8) ztop += _zVelocityOb[index + _slabSize];
- if(_obstacles[index-_slabSize] & 8) zbottom += _zVelocityOb[index - _slabSize];
-
- _divergence[index] = -_dx * 0.5f * (
- xright - xleft +
- yup - ydown +
- ztop - zbottom );
-
- // Pressure is zero anyway since now a local array is used
- _pressure[index] = 0.0f;
- }
-
- copyBorderAll(_pressure, 0, _zRes);
-
- // fix fluid compression caused in isolated components by obstacle movement
- fixObstacleCompression(_divergence);
-
- // solve Poisson equation
- solvePressurePre(_pressure, _divergence, _obstacles);
-
- setObstaclePressure(_pressure, 0, _zRes);
-
- // project out solution
- // New idea for code from NVIDIA graphic gems 3 - DG
- float invDx = 1.0f / _dx;
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- float vMask[3] = {1.0f, 1.0f, 1.0f}, vObst[3] = {0, 0, 0};
- // float vR = 0.0f, vL = 0.0f, vT = 0.0f, vB = 0.0f, vD = 0.0f, vU = 0.0f; // UNUSED
-
- float pC = _pressure[index]; // center
- float pR = _pressure[index + 1]; // right
- float pL = _pressure[index - 1]; // left
- float pU = _pressure[index + _xRes]; // Up
- float pD = _pressure[index - _xRes]; // Down
- float pT = _pressure[index + _slabSize]; // top
- float pB = _pressure[index - _slabSize]; // bottom
-
- if(!_obstacles[index])
- {
- // DG TODO: What if obstacle is left + right and one of them is moving?
- if(_obstacles[index+1]) { pR = pC; vObst[0] = _xVelocityOb[index + 1]; vMask[0] = 0; }
- if(_obstacles[index-1]) { pL = pC; vObst[0] = _xVelocityOb[index - 1]; vMask[0] = 0; }
- if(_obstacles[index+_xRes]) { pU = pC; vObst[1] = _yVelocityOb[index + _xRes]; vMask[1] = 0; }
- if(_obstacles[index-_xRes]) { pD = pC; vObst[1] = _yVelocityOb[index - _xRes]; vMask[1] = 0; }
- if(_obstacles[index+_slabSize]) { pT = pC; vObst[2] = _zVelocityOb[index + _slabSize]; vMask[2] = 0; }
- if(_obstacles[index-_slabSize]) { pB = pC; vObst[2] = _zVelocityOb[index - _slabSize]; vMask[2] = 0; }
-
- _xVelocity[index] -= 0.5f * (pR - pL) * invDx;
- _yVelocity[index] -= 0.5f * (pU - pD) * invDx;
- _zVelocity[index] -= 0.5f * (pT - pB) * invDx;
-
- _xVelocity[index] = (vMask[0] * _xVelocity[index]) + vObst[0];
- _yVelocity[index] = (vMask[1] * _yVelocity[index]) + vObst[1];
- _zVelocity[index] = (vMask[2] * _zVelocity[index]) + vObst[2];
- }
- else
- {
- _xVelocity[index] = _xVelocityOb[index];
- _yVelocity[index] = _yVelocityOb[index];
- _zVelocity[index] = _zVelocityOb[index];
- }
- }
-
- // DG: was enabled in original code but now we do this later
- // setObstacleVelocity(0, _zRes);
-
- if (_pressure) delete[] _pressure;
- if (_divergence) delete[] _divergence;
-}
-
-//////////////////////////////////////////////////////////////////////
-// calculate the obstacle velocity at boundary
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setObstacleVelocity(int zBegin, int zEnd)
-{
-
- // completely TODO <-- who wrote this and what is here TODO? DG
-
- const size_t index_ = _slabSize + _xRes + 1;
-
- //int vIndex=_slabSize + _xRes + 1;
-
- int bb=0;
- int bt=0;
-
- if (zBegin == 0) {bb = 1;}
- if (zEnd == _zRes) {bt = 1;}
-
- // tag remaining obstacle blocks
- for (int z = zBegin + bb; z < zEnd - bt; z++)
- {
- size_t index = index_ +(z-1)*_slabSize;
-
- for (int y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (int x = 1; x < _xRes - 1; x++, index++)
- {
- if (!_obstacles[index])
- {
- // if(_obstacles[index+1]) xright = - _xVelocityOb[index];
- if((_obstacles[index - 1] & 8) && abs(_xVelocityOb[index - 1]) > FLT_EPSILON )
- {
- // printf("velocity x!\n");
- _xVelocity[index] = _xVelocityOb[index - 1];
- _xVelocity[index - 1] = _xVelocityOb[index - 1];
- }
- // if(_obstacles[index+_xRes]) yup = - _yVelocityOb[index];
- if((_obstacles[index - _xRes] & 8) && abs(_yVelocityOb[index - _xRes]) > FLT_EPSILON)
- {
- // printf("velocity y!\n");
- _yVelocity[index] = _yVelocityOb[index - _xRes];
- _yVelocity[index - _xRes] = _yVelocityOb[index - _xRes];
- }
- // if(_obstacles[index+_slabSize]) ztop = - _zVelocityOb[index];
- if((_obstacles[index - _slabSize] & 8) && abs(_zVelocityOb[index - _slabSize]) > FLT_EPSILON)
- {
- // printf("velocity z!\n");
- _zVelocity[index] = _zVelocityOb[index - _slabSize];
- _zVelocity[index - _slabSize] = _zVelocityOb[index - _slabSize];
- }
- }
- else
- {
- _density[index] = 0;
- }
- //vIndex++;
- } // x loop
- //vIndex += 2;
- } // y loop
- //vIndex += 2 * _xRes;
- } // z loop
-}
-
-//////////////////////////////////////////////////////////////////////
-// diffuse heat
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::diffuseHeat()
-{
- SWAP_POINTERS(_heat, _heatOld);
-
- copyBorderAll(_heatOld, 0, _zRes);
- solveHeat(_heat, _heatOld, _obstacles);
-
- // zero out inside obstacles
- for (int x = 0; x < _totalCells; x++)
- if (_obstacles[x])
- _heat[x] = 0.0f;
-}
-
-//////////////////////////////////////////////////////////////////////
-// stamp an obstacle in the _obstacles field
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::addObstacle(OBSTACLE* obstacle)
-{
- int index = 0;
- for (int z = 0; z < _zRes; z++)
- for (int y = 0; y < _yRes; y++)
- for (int x = 0; x < _xRes; x++, index++)
- if (obstacle->inside(x * _dx, y * _dx, z * _dx)) {
- _obstacles[index] = true;
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// calculate the obstacle directional types
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setObstaclePressure(float *_pressure, int zBegin, int zEnd)
-{
-
- // completely TODO <-- who wrote this and what is here TODO? DG
-
- const size_t index_ = _slabSize + _xRes + 1;
-
- //int vIndex=_slabSize + _xRes + 1;
-
- int bb=0;
- int bt=0;
-
- if (zBegin == 0) {bb = 1;}
- if (zEnd == _zRes) {bt = 1;}
-
- // tag remaining obstacle blocks
- for (int z = zBegin + bb; z < zEnd - bt; z++)
- {
- size_t index = index_ +(z-1)*_slabSize;
-
- for (int y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (int x = 1; x < _xRes - 1; x++, index++)
- {
- // could do cascade of ifs, but they are a pain
- if (_obstacles[index] /* && !(_obstacles[index] & 8) DG TODO TEST THIS CONDITION */)
- {
- const int top = _obstacles[index + _slabSize];
- const int bottom= _obstacles[index - _slabSize];
- const int up = _obstacles[index + _xRes];
- const int down = _obstacles[index - _xRes];
- const int left = _obstacles[index - 1];
- const int right = _obstacles[index + 1];
-
- // unused
- // const bool fullz = (top && bottom);
- // const bool fully = (up && down);
- //const bool fullx = (left && right);
-
- /*
- _xVelocity[index] =
- _yVelocity[index] =
- _zVelocity[index] = 0.0f;
- */
- _pressure[index] = 0.0f;
-
- // average pressure neighbors
- float pcnt = 0.;
- if (left && !right) {
- _pressure[index] += _pressure[index + 1];
- pcnt += 1.0f;
- }
- if (!left && right) {
- _pressure[index] += _pressure[index - 1];
- pcnt += 1.0f;
- }
- if (up && !down) {
- _pressure[index] += _pressure[index - _xRes];
- pcnt += 1.0f;
- }
- if (!up && down) {
- _pressure[index] += _pressure[index + _xRes];
- pcnt += 1.0f;
- }
- if (top && !bottom) {
- _pressure[index] += _pressure[index - _slabSize];
- pcnt += 1.0f;
- }
- if (!top && bottom) {
- _pressure[index] += _pressure[index + _slabSize];
- pcnt += 1.0f;
- }
-
- if(pcnt > 0.000001f)
- _pressure[index] /= pcnt;
-
- // TODO? set correct velocity bc's
- // velocities are only set to zero right now
- // this means it's not a full no-slip boundary condition
- // but a "half-slip" - still looks ok right now
- }
- //vIndex++;
- } // x loop
- //vIndex += 2;
- } // y loop
- //vIndex += 2 * _xRes;
- } // z loop
-}
-
-void FLUID_3D::setObstacleBoundaries(float *_pressure, int zBegin, int zEnd)
-{
- // cull degenerate obstacles , move to addObstacle?
-
- // r = b - Ax
- const size_t index_ = _slabSize + _xRes + 1;
-
- int bb=0;
- int bt=0;
-
- if (zBegin == 0) {bb = 1;}
- if (zEnd == _zRes) {bt = 1;}
-
- for (int z = zBegin + bb; z < zEnd - bt; z++)
- {
- size_t index = index_ +(z-1)*_slabSize;
-
- for (int y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (int x = 1; x < _xRes - 1; x++, index++)
- {
- if (_obstacles[index] != EMPTY)
- {
- const int top = _obstacles[index + _slabSize];
- const int bottom= _obstacles[index - _slabSize];
- const int up = _obstacles[index + _xRes];
- const int down = _obstacles[index - _xRes];
- const int left = _obstacles[index - 1];
- const int right = _obstacles[index + 1];
-
- int counter = 0;
- if (up) counter++;
- if (down) counter++;
- if (left) counter++;
- if (right) counter++;
- if (top) counter++;
- if (bottom) counter++;
-
- if (counter < 3)
- _obstacles[index] = EMPTY;
- }
- if (_obstacles[index])
- {
- _xVelocity[index] =
- _yVelocity[index] =
- _zVelocity[index] = 0.0f;
- _pressure[index] = 0.0f;
- }
- //vIndex++;
- } // x-loop
- //vIndex += 2;
- } // y-loop
- //vIndex += 2* _xRes;
- } // z-loop
-}
-
-void FLUID_3D::floodFillComponent(int *buffer, size_t *queue, size_t limit, size_t pos, int from, int to)
-{
- /* Flood 'from' cells with 'to' in the grid. Rely on (from != 0 && from != to && edges == 0) to stop. */
- int offsets[] = { -1, +1, -_xRes, +_xRes, -_slabSize, +_slabSize };
- size_t qend = 0;
-
- buffer[pos] = to;
- queue[qend++] = pos;
-
- for (size_t qidx = 0; qidx < qend; qidx++)
- {
- pos = queue[qidx];
-
- for (int i = 0; i < 6; i++)
- {
- size_t next = pos + offsets[i];
-
- if (next < limit && buffer[next] == from)
- {
- buffer[next] = to;
- queue[qend++] = next;
- }
- }
- }
-}
-
-void FLUID_3D::mergeComponents(int *buffer, size_t *queue, size_t cur, size_t other)
-{
- /* Replace higher value with lower. */
- if (buffer[other] < buffer[cur])
- {
- floodFillComponent(buffer, queue, cur, cur, buffer[cur], buffer[other]);
- }
- else if (buffer[cur] < buffer[other])
- {
- floodFillComponent(buffer, queue, cur, other, buffer[other], buffer[cur]);
- }
-}
-
-void FLUID_3D::fixObstacleCompression(float *divergence)
-{
- int x, y, z;
- size_t index;
-
- /* Find compartments completely separated by obstacles.
- * Edge of the domain is automatically component 0. */
- int *component = new int[_totalCells];
- size_t *queue = new size_t[_totalCells];
-
- memset(component, 0, sizeof(int) * _totalCells);
-
- int next_id = 1;
-
- for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
- {
- for (y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- if(!_obstacles[index])
- {
- /* Check for connection to the domain edge at iteration end. */
- if ((x == _xRes-2 && !_obstacles[index + 1]) ||
- (y == _yRes-2 && !_obstacles[index + _xRes]) ||
- (z == _zRes-2 && !_obstacles[index + _slabSize]))
- {
- component[index] = 0;
- }
- else {
- component[index] = next_id;
- }
-
- if (!_obstacles[index - 1])
- mergeComponents(component, queue, index, index - 1);
- if (!_obstacles[index - _xRes])
- mergeComponents(component, queue, index, index - _xRes);
- if (!_obstacles[index - _slabSize])
- mergeComponents(component, queue, index, index - _slabSize);
-
- if (component[index] == next_id)
- next_id++;
- }
- }
- }
- }
-
- delete[] queue;
-
- /* Compute average divergence within each component. */
- float *total_divergence = new float[next_id];
- int *component_size = new int[next_id];
-
- memset(total_divergence, 0, sizeof(float) * next_id);
- memset(component_size, 0, sizeof(int) * next_id);
-
- for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
- {
- for (y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- if(!_obstacles[index])
- {
- int ci = component[index];
-
- component_size[ci]++;
- total_divergence[ci] += divergence[index];
- }
- }
- }
- }
-
- /* Adjust divergence to make the average zero in each component except the edge. */
- total_divergence[0] = 0.0f;
-
- for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
- {
- for (y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- if(!_obstacles[index])
- {
- int ci = component[index];
-
- divergence[index] -= total_divergence[ci] / component_size[ci];
- }
- }
- }
- }
-
- delete[] component;
- delete[] component_size;
- delete[] total_divergence;
-}
-
-//////////////////////////////////////////////////////////////////////
-// add buoyancy forces
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::addBuoyancy(float *heat, float *density, float gravity[3], int zBegin, int zEnd)
-{
- int index = zBegin*_slabSize;
-
- for (int z = zBegin; z < zEnd; z++)
- for (int y = 0; y < _yRes; y++)
- for (int x = 0; x < _xRes; x++, index++)
- {
- float buoyancy = *_alpha * density[index] + (*_beta * (((heat) ? heat[index] : 0.0f) - _tempAmb));
- _xForce[index] -= gravity[0] * buoyancy;
- _yForce[index] -= gravity[1] * buoyancy;
- _zForce[index] -= gravity[2] * buoyancy;
- }
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// add vorticity to the force field
-//////////////////////////////////////////////////////////////////////
-#define VORT_VEL(i, j) \
- ((_obstacles[obpos[(i)]] & 8) ? ((abs(objvelocity[(j)][obpos[(i)]]) > FLT_EPSILON) ? objvelocity[(j)][obpos[(i)]] : velocity[(j)][index]) : velocity[(j)][obpos[(i)]])
-
-void FLUID_3D::addVorticity(int zBegin, int zEnd)
-{
- // set flame vorticity from RNA value
- float flame_vorticity = (*_flame_vorticity)/_constantScaling;
- //int x,y,z,index;
- if(_vorticityEps+flame_vorticity<=0.0f) return;
-
- int _blockSize=zEnd-zBegin;
- int _blockTotalCells = _slabSize * (_blockSize+2);
-
- float *_xVorticity, *_yVorticity, *_zVorticity, *_vorticity;
-
- int bb=0;
- int bt=0;
- int bb1=-1;
- int bt1=-1;
-
- if (zBegin == 0) {bb1 = 1; bb = 1; _blockTotalCells-=_blockSize;}
- if (zEnd == _zRes) {bt1 = 1;bt = 1; _blockTotalCells-=_blockSize;}
-
- _xVorticity = new float[_blockTotalCells];
- _yVorticity = new float[_blockTotalCells];
- _zVorticity = new float[_blockTotalCells];
- _vorticity = new float[_blockTotalCells];
-
- memset(_xVorticity, 0, sizeof(float)*_blockTotalCells);
- memset(_yVorticity, 0, sizeof(float)*_blockTotalCells);
- memset(_zVorticity, 0, sizeof(float)*_blockTotalCells);
- memset(_vorticity, 0, sizeof(float)*_blockTotalCells);
-
- //const size_t indexsetupV=_slabSize;
- const size_t index_ = _slabSize + _xRes + 1;
-
- // calculate vorticity
- float gridSize = 0.5f / _dx;
- //index = _slabSize + _xRes + 1;
-
- float *velocity[3];
- float *objvelocity[3];
-
- velocity[0] = _xVelocity;
- velocity[1] = _yVelocity;
- velocity[2] = _zVelocity;
-
- objvelocity[0] = _xVelocityOb;
- objvelocity[1] = _yVelocityOb;
- objvelocity[2] = _zVelocityOb;
-
- size_t vIndex=_xRes + 1;
- for (int z = zBegin + bb1; z < (zEnd - bt1); z++)
- {
- size_t index = index_ +(z-1)*_slabSize;
- vIndex = index-(zBegin-1+bb)*_slabSize;
-
- for (int y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (int x = 1; x < _xRes - 1; x++, index++)
- {
- if (!_obstacles[index])
- {
- int obpos[6];
-
- obpos[0] = (_obstacles[index + _xRes] == 1) ? index : index + _xRes; // up
- obpos[1] = (_obstacles[index - _xRes] == 1) ? index : index - _xRes; // down
- float dy = (obpos[0] == index || obpos[1] == index) ? 1.0f / _dx : gridSize;
-
- obpos[2] = (_obstacles[index + _slabSize] == 1) ? index : index + _slabSize; // out
- obpos[3] = (_obstacles[index - _slabSize] == 1) ? index : index - _slabSize; // in
- float dz = (obpos[2] == index || obpos[3] == index) ? 1.0f / _dx : gridSize;
-
- obpos[4] = (_obstacles[index + 1] == 1) ? index : index + 1; // right
- obpos[5] = (_obstacles[index - 1] == 1) ? index : index - 1; // left
- float dx = (obpos[4] == index || obpos[5] == index) ? 1.0f / _dx : gridSize;
-
- float xV[2], yV[2], zV[2];
-
- zV[1] = VORT_VEL(0, 2);
- zV[0] = VORT_VEL(1, 2);
- yV[1] = VORT_VEL(2, 1);
- yV[0] = VORT_VEL(3, 1);
- _xVorticity[vIndex] = (zV[1] - zV[0]) * dy + (-yV[1] + yV[0]) * dz;
-
- xV[1] = VORT_VEL(2, 0);
- xV[0] = VORT_VEL(3, 0);
- zV[1] = VORT_VEL(4, 2);
- zV[0] = VORT_VEL(5, 2);
- _yVorticity[vIndex] = (xV[1] - xV[0]) * dz + (-zV[1] + zV[0]) * dx;
-
- yV[1] = VORT_VEL(4, 1);
- yV[0] = VORT_VEL(5, 1);
- xV[1] = VORT_VEL(0, 0);
- xV[0] = VORT_VEL(1, 0);
- _zVorticity[vIndex] = (yV[1] - yV[0]) * dx + (-xV[1] + xV[0])* dy;
-
- _vorticity[vIndex] = sqrtf(_xVorticity[vIndex] * _xVorticity[vIndex] +
- _yVorticity[vIndex] * _yVorticity[vIndex] +
- _zVorticity[vIndex] * _zVorticity[vIndex]);
-
- }
- vIndex++;
- }
- vIndex+=2;
- }
- //vIndex+=2*_xRes;
- }
-
- // calculate normalized vorticity vectors
- float eps = _vorticityEps;
-
- //index = _slabSize + _xRes + 1;
- vIndex=_slabSize + _xRes + 1;
-
- for (int z = zBegin + bb; z < (zEnd - bt); z++)
- {
- size_t index = index_ +(z-1)*_slabSize;
- vIndex = index-(zBegin-1+bb)*_slabSize;
-
- for (int y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (int x = 1; x < _xRes - 1; x++, index++)
- {
- //
-
- if (!_obstacles[index])
- {
- float N[3];
-
- int up = (_obstacles[index + _xRes] == 1) ? vIndex : vIndex + _xRes;
- int down = (_obstacles[index - _xRes] == 1) ? vIndex : vIndex - _xRes;
- float dy = (up == vIndex || down == vIndex) ? 1.0f / _dx : gridSize;
-
- int out = (_obstacles[index + _slabSize] == 1) ? vIndex : vIndex + _slabSize;
- int in = (_obstacles[index - _slabSize] == 1) ? vIndex : vIndex - _slabSize;
- float dz = (out == vIndex || in == vIndex) ? 1.0f / _dx : gridSize;
-
- int right = (_obstacles[index + 1] == 1) ? vIndex : vIndex + 1;
- int left = (_obstacles[index - 1] == 1) ? vIndex : vIndex - 1;
- float dx = (right == vIndex || left == vIndex) ? 1.0f / _dx : gridSize;
-
- N[0] = (_vorticity[right] - _vorticity[left]) * dx;
- N[1] = (_vorticity[up] - _vorticity[down]) * dy;
- N[2] = (_vorticity[out] - _vorticity[in]) * dz;
-
- float magnitude = sqrtf(N[0] * N[0] + N[1] * N[1] + N[2] * N[2]);
- if (magnitude > FLT_EPSILON)
- {
- float flame_vort = (_fuel) ? _fuel[index]*flame_vorticity : 0.0f;
- magnitude = 1.0f / magnitude;
- N[0] *= magnitude;
- N[1] *= magnitude;
- N[2] *= magnitude;
-
- _xForce[index] += (N[1] * _zVorticity[vIndex] - N[2] * _yVorticity[vIndex]) * _dx * (eps + flame_vort);
- _yForce[index] += (N[2] * _xVorticity[vIndex] - N[0] * _zVorticity[vIndex]) * _dx * (eps + flame_vort);
- _zForce[index] += (N[0] * _yVorticity[vIndex] - N[1] * _xVorticity[vIndex]) * _dx * (eps + flame_vort);
- }
- } // if
- vIndex++;
- } // x loop
- vIndex+=2;
- } // y loop
- //vIndex+=2*_xRes;
- } // z loop
-
- if (_xVorticity) delete[] _xVorticity;
- if (_yVorticity) delete[] _yVorticity;
- if (_zVorticity) delete[] _zVorticity;
- if (_vorticity) delete[] _vorticity;
-}
-
-
-void FLUID_3D::advectMacCormackBegin(int zBegin, int zEnd)
-{
- Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
-
- setZeroX(_xVelocityOld, res, zBegin, zEnd);
- setZeroY(_yVelocityOld, res, zBegin, zEnd);
- setZeroZ(_zVelocityOld, res, zBegin, zEnd);
-}
-
-//////////////////////////////////////////////////////////////////////
-// Advect using the MacCormack method from the Selle paper
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::advectMacCormackEnd1(int zBegin, int zEnd)
-{
- Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
-
- const float dt0 = _dt / _dx;
-
- int begin=zBegin * _slabSize;
- int end=begin + (zEnd - zBegin) * _slabSize;
- for (int x = begin; x < end; x++)
- _xForce[x] = 0.0;
-
- // advectFieldMacCormack1(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res)
-
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _densityTemp, res, zBegin, zEnd);
- if (_heat) {
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heatTemp, res, zBegin, zEnd);
- }
- if (_fuel) {
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _fuelOld, _fuelTemp, res, zBegin, zEnd);
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _reactOld, _reactTemp, res, zBegin, zEnd);
- }
- if (_color_r) {
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_rOld, _color_rTemp, res, zBegin, zEnd);
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_gOld, _color_gTemp, res, zBegin, zEnd);
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_bOld, _color_bTemp, res, zBegin, zEnd);
- }
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocity, res, zBegin, zEnd);
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocity, res, zBegin, zEnd);
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocity, res, zBegin, zEnd);
-
- // Have to wait untill all the threads are done -> so continuing in step 3
-}
-
-//////////////////////////////////////////////////////////////////////
-// Advect using the MacCormack method from the Selle paper
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::advectMacCormackEnd2(int zBegin, int zEnd)
-{
- const float dt0 = _dt / _dx;
- Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
-
- // use force array as temp array
- float* t1 = _xForce;
-
- // advectFieldMacCormack2(dt, xVelocity, yVelocity, zVelocity, oldField, newField, tempfield, temp, res, obstacles)
-
- /* finish advection */
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _density, _densityTemp, t1, res, _obstacles, zBegin, zEnd);
- if (_heat) {
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, _heatTemp, t1, res, _obstacles, zBegin, zEnd);
- }
- if (_fuel) {
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _fuelOld, _fuel, _fuelTemp, t1, res, _obstacles, zBegin, zEnd);
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _reactOld, _react, _reactTemp, t1, res, _obstacles, zBegin, zEnd);
- }
- if (_color_r) {
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_rOld, _color_r, _color_rTemp, t1, res, _obstacles, zBegin, zEnd);
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_gOld, _color_g, _color_gTemp, t1, res, _obstacles, zBegin, zEnd);
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_bOld, _color_b, _color_bTemp, t1, res, _obstacles, zBegin, zEnd);
- }
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocityTemp, _xVelocity, t1, res, _obstacles, zBegin, zEnd);
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocityTemp, _yVelocity, t1, res, _obstacles, zBegin, zEnd);
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocityTemp, _zVelocity, t1, res, _obstacles, zBegin, zEnd);
-
- /* set boundary conditions for velocity */
- if(!_domainBcLeft) copyBorderX(_xVelocityTemp, res, zBegin, zEnd);
- else setZeroX(_xVelocityTemp, res, zBegin, zEnd);
-
- if(!_domainBcFront) copyBorderY(_yVelocityTemp, res, zBegin, zEnd);
- else setZeroY(_yVelocityTemp, res, zBegin, zEnd);
-
- if(!_domainBcTop) copyBorderZ(_zVelocityTemp, res, zBegin, zEnd);
- else setZeroZ(_zVelocityTemp, res, zBegin, zEnd);
-
- /* clear data boundaries */
- setZeroBorder(_density, res, zBegin, zEnd);
- if (_fuel) {
- setZeroBorder(_fuel, res, zBegin, zEnd);
- setZeroBorder(_react, res, zBegin, zEnd);
- }
- if (_color_r) {
- setZeroBorder(_color_r, res, zBegin, zEnd);
- setZeroBorder(_color_g, res, zBegin, zEnd);
- setZeroBorder(_color_b, res, zBegin, zEnd);
- }
-}
-
-
-void FLUID_3D::processBurn(float *fuel, float *smoke, float *react, float *heat,
- float *r, float *g, float *b, int total_cells, float dt)
-{
- float burning_rate = *_burning_rate;
- float flame_smoke = *_flame_smoke;
- float ignition_point = *_ignition_temp;
- float temp_max = *_max_temp;
-
- for (int index = 0; index < total_cells; index++)
- {
- float orig_fuel = fuel[index];
- float orig_smoke = smoke[index];
- float smoke_emit = 0.0f;
- float flame = 0.0f;
-
- /* process fuel */
- fuel[index] -= burning_rate * dt;
- if (fuel[index] < 0.0f) fuel[index] = 0.0f;
- /* process reaction coordinate */
- if (orig_fuel > FLT_EPSILON) {
- react[index] *= fuel[index]/orig_fuel;
- flame = pow(react[index], 0.5f);
- }
- else {
- react[index] = 0.0f;
- }
-
- /* emit smoke based on fuel burn rate and "flame_smoke" factor */
- smoke_emit = (orig_fuel < 1.0f) ? (1.0f - orig_fuel)*0.5f : 0.0f;
- smoke_emit = (smoke_emit + 0.5f) * (orig_fuel-fuel[index]) * 0.1f * flame_smoke;
- smoke[index] += smoke_emit;
- CLAMP(smoke[index], 0.0f, 1.0f);
-
- /* set fluid temperature from the flame temperature profile */
- if (heat && flame)
- heat[index] = (1.0f - flame)*ignition_point + flame*temp_max;
-
- /* mix new color */
- if (r && smoke_emit > FLT_EPSILON) {
- float smoke_factor = smoke[index]/(orig_smoke+smoke_emit);
- r[index] = (r[index] + _flame_smoke_color[0] * smoke_emit) * smoke_factor;
- g[index] = (g[index] + _flame_smoke_color[1] * smoke_emit) * smoke_factor;
- b[index] = (b[index] + _flame_smoke_color[2] * smoke_emit) * smoke_factor;
- }
- }
-}
-
-void FLUID_3D::updateFlame(float *react, float *flame, int total_cells)
-{
- for (int index = 0; index < total_cells; index++)
- {
- /* model flame temperature curve from the reaction coordinate (fuel)
- * TODO: Would probably be best to get rid of whole "flame" data field.
- * Currently it's just sqrt mirror of reaction coordinate, and therefore
- * basically just waste of memory and disk space...
- */
- if (react[index]>0.0f) {
- /* do a smooth falloff for rest of the values */
- flame[index] = pow(react[index], 0.5f);
- }
- else
- flame[index] = 0.0f;
- }
-}
diff --git a/intern/smoke/intern/FLUID_3D.h b/intern/smoke/intern/FLUID_3D.h
deleted file mode 100644
index 097451836f2..00000000000
--- a/intern/smoke/intern/FLUID_3D.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// FLUID_3D.h: interface for the FLUID_3D class.
-//
-//////////////////////////////////////////////////////////////////////
-// Heavy parallel optimization done. Many of the old functions now
-// take begin and end parameters and process only specified part of the data.
-// Some functions were divided into multiple ones.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#ifndef FLUID_3D_H
-#define FLUID_3D_H
-
-#include <cstdlib>
-#include <cmath>
-#include <cstring>
-#include <iostream>
-#include "OBSTACLE.h"
-// #include "WTURBULENCE.h"
-#include "VEC3.h"
-
-using namespace std;
-using namespace BasicVector;
-struct WTURBULENCE;
-
-struct FLUID_3D
-{
- public:
- FLUID_3D(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors);
- FLUID_3D() {};
- virtual ~FLUID_3D();
-
- void initHeat();
- void initFire();
- void initColors(float init_r, float init_g, float init_b);
-
- void initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
- float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *ignition_temp, float *max_temp);
-
- // create & allocate vector noise advection
- void initVectorNoise(int amplify);
-
- void addSmokeColumn();
- static void addSmokeTestCase(float* field, Vec3Int res);
-
- void step(float dt, float gravity[3]);
- void addObstacle(OBSTACLE* obstacle);
-
- const float* xVelocity() { return _xVelocity; };
- const float* yVelocity() { return _yVelocity; };
- const float* zVelocity() { return _zVelocity; };
-
- int xRes() const { return _xRes; };
- int yRes() const { return _yRes; };
- int zRes() const { return _zRes; };
-
- public:
- // dimensions
- int _xRes, _yRes, _zRes, _maxRes;
- Vec3Int _res;
- size_t _totalCells;
- int _slabSize;
- float _dx;
- float _p0[3];
- float _p1[3];
- float _totalTime;
- int _totalSteps;
- int _totalImgDumps;
- int _totalVelDumps;
-
- void artificialDampingSL(int zBegin, int zEnd);
- void artificialDampingExactSL(int pos);
-
- void setBorderObstacles();
-
- // fields
- float* _density;
- float* _densityOld;
- float* _heat;
- float* _heatOld;
- float* _xVelocity;
- float* _yVelocity;
- float* _zVelocity;
- float* _xVelocityOb;
- float* _yVelocityOb;
- float* _zVelocityOb;
- float* _xVelocityOld;
- float* _yVelocityOld;
- float* _zVelocityOld;
- float* _xForce;
- float* _yForce;
- float* _zForce;
- unsigned char* _obstacles; /* only used (useful) for static obstacles like domain boundaries */
- unsigned char* _obstaclesAnim;
-
- // Required for proper threading:
- float* _xVelocityTemp;
- float* _yVelocityTemp;
- float* _zVelocityTemp;
- float* _heatTemp;
- float* _densityTemp;
-
- // fire simulation
- float *_flame;
- float *_fuel;
- float *_fuelTemp;
- float *_fuelOld;
- float *_react;
- float *_reactTemp;
- float *_reactOld;
-
- // smoke color
- float *_color_r;
- float *_color_rOld;
- float *_color_rTemp;
- float *_color_g;
- float *_color_gOld;
- float *_color_gTemp;
- float *_color_b;
- float *_color_bOld;
- float *_color_bTemp;
-
-
- // CG fields
- int _iterations;
-
- // simulation constants
- float _dt;
- float *_dtFactor;
- float _vorticityEps;
- float _heatDiffusion;
- float *_vorticityRNA; // RNA-pointer.
- float *_alpha; // for the buoyancy density term <-- as pointer to get blender RNA in here
- float *_beta; // was _buoyancy <-- as pointer to get blender RNA in here
- float _tempAmb; /* ambient temperature */
- float _constantScaling;
-
- bool _domainBcFront; // z
- bool _domainBcTop; // y
- bool _domainBcLeft; // x
- bool _domainBcBack; // DOMAIN_BC_FRONT
- bool _domainBcBottom; // DOMAIN_BC_TOP
- bool _domainBcRight; // DOMAIN_BC_LEFT
- int *_borderColli; // border collision rules <-- as pointer to get blender RNA in here
- int _colloPrev; // To track whether value has been changed (to not
- // have to recalibrate borders if nothing has changed
- void setBorderCollisions();
-
- void setObstacleVelocity(int zBegin, int zEnd);
-
- // WTURBULENCE object, if active
- // WTURBULENCE* _wTurbulence;
-
- // boundary setting functions
- void copyBorderAll(float* field, int zBegin, int zEnd);
-
- // timestepping functions
- void wipeBoundaries(int zBegin, int zEnd);
- void wipeBoundariesSL(int zBegin, int zEnd);
- void addForce(int zBegin, int zEnd);
- void addVorticity(int zBegin, int zEnd);
- void addBuoyancy(float *heat, float *density, float gravity[3], int zBegin, int zEnd);
-
- // solver stuff
- void project();
- void diffuseHeat();
- void diffuseColor();
- void solvePressure(float* field, float* b, unsigned char* skip);
- void solvePressurePre(float* field, float* b, unsigned char* skip);
- void solveHeat(float* field, float* b, unsigned char* skip);
- void solveDiffusion(float* field, float* b, float* factor);
-
-
- // handle obstacle boundaries
- void setObstacleBoundaries(float *_pressure, int zBegin, int zEnd);
- void setObstaclePressure(float *_pressure, int zBegin, int zEnd);
-
- void fixObstacleCompression(float *divergence);
-
- public:
- // advection, accessed e.g. by WTURBULENCE class
- //void advectMacCormack();
- void advectMacCormackBegin(int zBegin, int zEnd);
- void advectMacCormackEnd1(int zBegin, int zEnd);
- void advectMacCormackEnd2(int zBegin, int zEnd);
-
- void floodFillComponent(int *components, size_t *queue, size_t limit, size_t start, int from, int to);
- void mergeComponents(int *components, size_t *queue, size_t cur, size_t other);
-
- /* burning */
- float *_burning_rate; // RNA pointer
- float *_flame_smoke; // RNA pointer
- float *_flame_smoke_color; // RNA pointer
- float *_flame_vorticity; // RNA pointer
- float *_ignition_temp; // RNA pointer
- float *_max_temp; // RNA pointer
- void processBurn(float *fuel, float *smoke, float *react, float *heat,
- float *r, float *g, float *b, int total_cells, float dt);
- void updateFlame(float *react, float *flame, int total_cells);
-
- // boundary setting functions
- static void copyBorderX(float* field, Vec3Int res, int zBegin, int zEnd);
- static void copyBorderY(float* field, Vec3Int res, int zBegin, int zEnd);
- static void copyBorderZ(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setNeumannX(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setNeumannY(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setZeroX(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setZeroY(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setZeroZ(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setZeroBorder(float* field, Vec3Int res, int zBegin, int zEnd) {
- setZeroX(field, res, zBegin, zEnd);
- setZeroY(field, res, zBegin, zEnd);
- setZeroZ(field, res, zBegin, zEnd);
- };
-
-
-
- // static advection functions, also used by WTURBULENCE
- static void advectFieldSemiLagrange(const float dt, const float* velx, const float* vely, const float* velz,
- float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd);
- static void advectFieldMacCormack1(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* tempResult, Vec3Int res, int zBegin, int zEnd);
- static void advectFieldMacCormack2(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* newField, float* tempResult, float* temp1,Vec3Int res, const unsigned char* obstacles, int zBegin, int zEnd);
-
-
- // temp ones for testing
- /*static void advectFieldMacCormack(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* newField, float* temp1, float* temp2, Vec3Int res, const unsigned char* obstacles);*/
- /*static void advectFieldSemiLagrange2(const float dt, const float* velx, const float* vely, const float* velz,
- float* oldField, float* newField, Vec3Int res);*/
-
- // maccormack helper functions
- static void clampExtrema(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd);
- static void clampOutsideRays(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* newField, Vec3Int res, const unsigned char* obstacles, const float *oldAdvection, int zBegin, int zEnd);
-
-
-
- // output helper functions
- // static void writeImageSliceXY(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.);
- // static void writeImageSliceYZ(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.);
- // static void writeImageSliceXZ(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.);
- // static void writeProjectedIntern(const float *field, Vec3Int res, int dir1, int dir2, string prefix, int picCnt, float scale=1.);
-};
-
-#endif
diff --git a/intern/smoke/intern/FLUID_3D_SOLVERS.cpp b/intern/smoke/intern/FLUID_3D_SOLVERS.cpp
deleted file mode 100644
index b05c45e1a02..00000000000
--- a/intern/smoke/intern/FLUID_3D_SOLVERS.cpp
+++ /dev/null
@@ -1,328 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// FLUID_3D.cpp: implementation of the FLUID_3D class.
-//
-//////////////////////////////////////////////////////////////////////
-// Both solvers optimized by merging loops and precalculating
-// stuff used in iteration loop.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#include "FLUID_3D.h"
-#include <cstring>
-#define SOLVER_ACCURACY 1e-06
-
-//////////////////////////////////////////////////////////////////////
-// solve the heat equation with CG
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::solveHeat(float* field, float* b, unsigned char* skip)
-{
- int x, y, z;
- const int twoxr = 2 * _xRes;
- size_t index;
- const float heatConst = _dt * _heatDiffusion / (_dx * _dx);
- float *_q, *_residual, *_direction, *_Acenter;
-
- // i = 0
- int i = 0;
-
- _residual = new float[_totalCells]; // set 0
- _direction = new float[_totalCells]; // set 0
- _q = new float[_totalCells]; // set 0
- _Acenter = new float[_totalCells]; // set 0
-
- memset(_residual, 0, sizeof(float)*_totalCells);
- memset(_q, 0, sizeof(float)*_totalCells);
- memset(_direction, 0, sizeof(float)*_totalCells);
- memset(_Acenter, 0, sizeof(float)*_totalCells);
-
- float deltaNew = 0.0f;
-
- // r = b - Ax
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += twoxr)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- // if the cell is a variable
- _Acenter[index] = 1.0f;
- if (!skip[index])
- {
- // set the matrix to the Poisson stencil in order
- if (!skip[index + 1]) _Acenter[index] += heatConst;
- if (!skip[index - 1]) _Acenter[index] += heatConst;
- if (!skip[index + _xRes]) _Acenter[index] += heatConst;
- if (!skip[index - _xRes]) _Acenter[index] += heatConst;
- if (!skip[index + _slabSize]) _Acenter[index] += heatConst;
- if (!skip[index - _slabSize]) _Acenter[index] += heatConst;
-
- _residual[index] = b[index] - (_Acenter[index] * field[index] +
- field[index - 1] * (skip[index - 1] ? 0.0f : -heatConst) +
- field[index + 1] * (skip[index + 1] ? 0.0f : -heatConst) +
- field[index - _xRes] * (skip[index - _xRes] ? 0.0f : -heatConst) +
- field[index + _xRes] * (skip[index + _xRes] ? 0.0f : -heatConst) +
- field[index - _slabSize] * (skip[index - _slabSize] ? 0.0f : -heatConst) +
- field[index + _slabSize] * (skip[index + _slabSize] ? 0.0f : -heatConst));
- }
- else
- {
- _residual[index] = 0.0f;
- }
-
- _direction[index] = _residual[index];
- deltaNew += _residual[index] * _residual[index];
- }
-
-
- // While deltaNew > (eps^2) * delta0
- const float eps = SOLVER_ACCURACY;
- float maxR = 2.0f * eps;
- while ((i < _iterations) && (maxR > eps))
- {
- // q = Ad
- float alpha = 0.0f;
-
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += twoxr)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- // if the cell is a variable
- if (!skip[index])
- {
-
- _q[index] = (_Acenter[index] * _direction[index] +
- _direction[index - 1] * (skip[index - 1] ? 0.0f : -heatConst) +
- _direction[index + 1] * (skip[index + 1] ? 0.0f : -heatConst) +
- _direction[index - _xRes] * (skip[index - _xRes] ? 0.0f : -heatConst) +
- _direction[index + _xRes] * (skip[index + _xRes] ? 0.0f : -heatConst) +
- _direction[index - _slabSize] * (skip[index - _slabSize] ? 0.0f : -heatConst) +
- _direction[index + _slabSize] * (skip[index + _slabSize] ? 0.0f : -heatConst));
- }
- else
- {
- _q[index] = 0.0f;
- }
- alpha += _direction[index] * _q[index];
- }
-
- if (fabs(alpha) > 0.0f)
- alpha = deltaNew / alpha;
-
- float deltaOld = deltaNew;
- deltaNew = 0.0f;
-
- maxR = 0.0f;
-
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += twoxr)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- field[index] += alpha * _direction[index];
-
- _residual[index] -= alpha * _q[index];
- maxR = (_residual[index] > maxR) ? _residual[index] : maxR;
-
- deltaNew += _residual[index] * _residual[index];
- }
-
- float beta = deltaNew / deltaOld;
-
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += twoxr)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- _direction[index] = _residual[index] + beta * _direction[index];
-
-
- i++;
- }
- // cout << i << " iterations converged to " << maxR << endl;
-
- if (_residual) delete[] _residual;
- if (_direction) delete[] _direction;
- if (_q) delete[] _q;
- if (_Acenter) delete[] _Acenter;
-}
-
-void FLUID_3D::solvePressurePre(float* field, float* b, unsigned char* skip)
-{
- int x, y, z;
- size_t index;
- float *_q, *_Precond, *_h, *_residual, *_direction;
-
- // i = 0
- int i = 0;
-
- _residual = new float[_totalCells]; // set 0
- _direction = new float[_totalCells]; // set 0
- _q = new float[_totalCells]; // set 0
- _h = new float[_totalCells]; // set 0
- _Precond = new float[_totalCells]; // set 0
-
- memset(_residual, 0, sizeof(float)*_xRes*_yRes*_zRes);
- memset(_q, 0, sizeof(float)*_xRes*_yRes*_zRes);
- memset(_direction, 0, sizeof(float)*_xRes*_yRes*_zRes);
- memset(_h, 0, sizeof(float)*_xRes*_yRes*_zRes);
- memset(_Precond, 0, sizeof(float)*_xRes*_yRes*_zRes);
-
- float deltaNew = 0.0f;
-
- // r = b - Ax
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- // if the cell is a variable
- float Acenter = 0.0f;
- if (!skip[index])
- {
- // set the matrix to the Poisson stencil in order
- if (!skip[index + 1]) Acenter += 1.0f;
- if (!skip[index - 1]) Acenter += 1.0f;
- if (!skip[index + _xRes]) Acenter += 1.0f;
- if (!skip[index - _xRes]) Acenter += 1.0f;
- if (!skip[index + _slabSize]) Acenter += 1.0f;
- if (!skip[index - _slabSize]) Acenter += 1.0f;
-
- _residual[index] = b[index] - (Acenter * field[index] +
- field[index - 1] * (skip[index - 1] ? 0.0f : -1.0f) +
- field[index + 1] * (skip[index + 1] ? 0.0f : -1.0f) +
- field[index - _xRes] * (skip[index - _xRes] ? 0.0f : -1.0f)+
- field[index + _xRes] * (skip[index + _xRes] ? 0.0f : -1.0f)+
- field[index - _slabSize] * (skip[index - _slabSize] ? 0.0f : -1.0f)+
- field[index + _slabSize] * (skip[index + _slabSize] ? 0.0f : -1.0f) );
- }
- else
- {
- _residual[index] = 0.0f;
- }
-
- // P^-1
- if(Acenter < 1.0f)
- _Precond[index] = 0.0;
- else
- _Precond[index] = 1.0f / Acenter;
-
- // p = P^-1 * r
- _direction[index] = _residual[index] * _Precond[index];
-
- deltaNew += _residual[index] * _direction[index];
- }
-
-
- // While deltaNew > (eps^2) * delta0
- const float eps = SOLVER_ACCURACY;
- //while ((i < _iterations) && (deltaNew > eps*delta0))
- float maxR = 2.0f * eps;
- // while (i < _iterations)
- while ((i < _iterations) && (maxR > 0.001f * eps))
- {
-
- float alpha = 0.0f;
-
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- // if the cell is a variable
- float Acenter = 0.0f;
- if (!skip[index])
- {
- // set the matrix to the Poisson stencil in order
- if (!skip[index + 1]) Acenter += 1.0f;
- if (!skip[index - 1]) Acenter += 1.0f;
- if (!skip[index + _xRes]) Acenter += 1.0f;
- if (!skip[index - _xRes]) Acenter += 1.0f;
- if (!skip[index + _slabSize]) Acenter += 1.0f;
- if (!skip[index - _slabSize]) Acenter += 1.0f;
-
- _q[index] = Acenter * _direction[index] +
- _direction[index - 1] * (skip[index - 1] ? 0.0f : -1.0f) +
- _direction[index + 1] * (skip[index + 1] ? 0.0f : -1.0f) +
- _direction[index - _xRes] * (skip[index - _xRes] ? 0.0f : -1.0f) +
- _direction[index + _xRes] * (skip[index + _xRes] ? 0.0f : -1.0f)+
- _direction[index - _slabSize] * (skip[index - _slabSize] ? 0.0f : -1.0f) +
- _direction[index + _slabSize] * (skip[index + _slabSize] ? 0.0f : -1.0f);
- }
- else
- {
- _q[index] = 0.0f;
- }
-
- alpha += _direction[index] * _q[index];
- }
-
-
- if (fabs(alpha) > 0.0f)
- alpha = deltaNew / alpha;
-
- float deltaOld = deltaNew;
- deltaNew = 0.0f;
-
- maxR = 0.0;
-
- float tmp;
-
- // x = x + alpha * d
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- field[index] += alpha * _direction[index];
-
- _residual[index] -= alpha * _q[index];
-
- _h[index] = _Precond[index] * _residual[index];
-
- tmp = _residual[index] * _h[index];
- deltaNew += tmp;
- maxR = (tmp > maxR) ? tmp : maxR;
-
- }
-
-
- // beta = deltaNew / deltaOld
- float beta = deltaNew / deltaOld;
-
- // d = h + beta * d
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- _direction[index] = _h[index] + beta * _direction[index];
-
- // i = i + 1
- i++;
- }
- // cout << i << " iterations converged to " << sqrt(maxR) << endl;
-
- if (_h) delete[] _h;
- if (_Precond) delete[] _Precond;
- if (_residual) delete[] _residual;
- if (_direction) delete[] _direction;
- if (_q) delete[] _q;
-}
diff --git a/intern/smoke/intern/FLUID_3D_STATIC.cpp b/intern/smoke/intern/FLUID_3D_STATIC.cpp
deleted file mode 100644
index 60c13ae9e60..00000000000
--- a/intern/smoke/intern/FLUID_3D_STATIC.cpp
+++ /dev/null
@@ -1,646 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// FLUID_3D.cpp: implementation of the static functions of the FLUID_3D class.
-//
-//////////////////////////////////////////////////////////////////////
-// Heavy parallel optimization done. Many of the old functions now
-// take begin and end parameters and process only specified part of the data.
-// Some functions were divided into multiple ones.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#include <zlib.h>
-#include "FLUID_3D.h"
-#include "IMAGE.h"
-#include "WTURBULENCE.h"
-#include "INTERPOLATE.h"
-
-//////////////////////////////////////////////////////////////////////
-// add a test cube of density to the center
-//////////////////////////////////////////////////////////////////////
-/*
-void FLUID_3D::addSmokeColumn() {
- addSmokeTestCase(_density, _res, 1.0);
- // addSmokeTestCase(_zVelocity, _res, 1.0);
- addSmokeTestCase(_heat, _res, 1.0);
- if (_wTurbulence) {
- addSmokeTestCase(_wTurbulence->getDensityBig(), _wTurbulence->getResBig(), 1.0);
- }
-}
-*/
-
-//////////////////////////////////////////////////////////////////////
-// generic static version, so that it can be applied to the
-// WTURBULENCE grid as well
-//////////////////////////////////////////////////////////////////////
-
-void FLUID_3D::addSmokeTestCase(float* field, Vec3Int res)
-{
- const int slabSize = res[0]*res[1]; int maxRes = (int)MAX3V(res);
- float dx = 1.0f / (float)maxRes;
-
- float xTotal = dx * res[0];
- float yTotal = dx * res[1];
-
- float heighMin = 0.05;
- float heighMax = 0.10;
-
- for (int y = 0; y < res[2]; y++)
- for (int z = (int)(heighMin*res[2]); z <= (int)(heighMax * res[2]); z++)
- for (int x = 0; x < res[0]; x++) {
- float xLength = x * dx - xTotal * 0.4f;
- float yLength = y * dx - yTotal * 0.5f;
- float radius = sqrtf(xLength * xLength + yLength * yLength);
-
- if (radius < 0.075f * xTotal) {
- int index = x + y * res[0] + z * slabSize;
- field[index] = 1.0f;
- }
- }
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// set x direction to Neumann boundary conditions
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setNeumannX(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int y = 0; y < res[1]; y++)
- {
- // left slab
- index = y * res[0] + z * slabSize;
- field[index] = field[index + 2];
-
- // right slab
- index = y * res[0] + z * slabSize + res[0] - 1;
- field[index] = field[index - 2];
- }
- }
-
-//////////////////////////////////////////////////////////////////////
-// set y direction to Neumann boundary conditions
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setNeumannY(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int x = 0; x < res[0]; x++)
- {
- // front slab
- index = x + z * slabSize;
- field[index] = field[index + 2 * res[0]];
-
- // back slab
- index = x + z * slabSize + slabSize - res[0];
- field[index] = field[index - 2 * res[0]];
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// set z direction to Neumann boundary conditions
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- const int totalCells = res[0] * res[1] * res[2];
- const int cellsslab = totalCells - slabSize;
- int index;
-
- if (zBegin == 0) {
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++)
- {
- // front slab
- index = x + y * res[0];
- field[index] = field[index + 2 * slabSize];
- }
- }
-
- if (zEnd == res[2]) {
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++)
- {
- // back slab
- index = x + y * res[0] + cellsslab;
- field[index] = field[index - 2 * slabSize];
- }
- }
-
-}
-
-//////////////////////////////////////////////////////////////////////
-// set x direction to zero
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setZeroX(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int y = 0; y < res[1]; y++)
- {
- // left slab
- index = y * res[0] + z * slabSize;
- field[index] = 0.0f;
-
- // right slab
- index += res[0] - 1;
- field[index] = 0.0f;
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// set y direction to zero
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setZeroY(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int x = 0; x < res[0]; x++)
- {
- // bottom slab
- index = x + z * slabSize;
- field[index] = 0.0f;
-
- // top slab
- index += slabSize - res[0];
- field[index] = 0.0f;
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// set z direction to zero
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setZeroZ(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- const int totalCells = res[0] * res[1] * res[2];
-
- int index = 0;
- if (zBegin == 0)
- {
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
- // front slab
- field[index] = 0.0f;
- }
- }
-
- if (zEnd == res[2])
- {
- index=0;
- int indexx=0;
- const int cellsslab = totalCells - slabSize;
-
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
-
- // back slab
- indexx = index + cellsslab;
- field[indexx] = 0.0f;
- }
- }
- }
-//////////////////////////////////////////////////////////////////////
-// copy grid boundary
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::copyBorderX(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int y = 0; y < res[1]; y++)
- {
- // left slab
- index = y * res[0] + z * slabSize;
- field[index] = field[index + 1];
-
- // right slab
- index += res[0] - 1;
- field[index] = field[index - 1];
- }
-}
-void FLUID_3D::copyBorderY(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- //const int totalCells = res[0] * res[1] * res[2];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int x = 0; x < res[0]; x++)
- {
- // bottom slab
- index = x + z * slabSize;
- field[index] = field[index + res[0]];
- // top slab
- index += slabSize - res[0];
- field[index] = field[index - res[0]];
- }
-}
-void FLUID_3D::copyBorderZ(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- const int totalCells = res[0] * res[1] * res[2];
- int index=0;
-
- if (zBegin == 0)
- {
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
- field[index] = field[index + slabSize];
- }
- }
-
- if (zEnd == res[2])
- {
-
- index=0;
- int indexx=0;
- const int cellsslab = totalCells - slabSize;
-
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
- // back slab
- indexx = index + cellsslab;
- field[indexx] = field[indexx - slabSize];
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-// advect field with the semi lagrangian method
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::advectFieldSemiLagrange(const float dt, const float* velx, const float* vely, const float* velz,
- float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd)
-{
- const int xres = res[0];
- const int yres = res[1];
- const int zres = res[2];
- const int slabSize = res[0] * res[1];
-
-
- for (int z = zBegin; z < zEnd; z++)
- for (int y = 0; y < yres; y++)
- for (int x = 0; x < xres; x++)
- {
- const int index = x + y * xres + z * xres*yres;
-
- // backtrace
- float xTrace = x - dt * velx[index];
- float yTrace = y - dt * vely[index];
- float zTrace = z - dt * velz[index];
-
- // clamp backtrace to grid boundaries
- if (xTrace < 0.5f) xTrace = 0.5f;
- if (xTrace > xres - 1.5f) xTrace = xres - 1.5f;
- if (yTrace < 0.5f) yTrace = 0.5f;
- if (yTrace > yres - 1.5f) yTrace = yres - 1.5f;
- if (zTrace < 0.5f) zTrace = 0.5f;
- if (zTrace > zres - 1.5f) zTrace = zres - 1.5f;
-
- // locate neighbors to interpolate
- const int x0 = (int)xTrace;
- const int x1 = x0 + 1;
- const int y0 = (int)yTrace;
- const int y1 = y0 + 1;
- const int z0 = (int)zTrace;
- const int z1 = z0 + 1;
-
- // get interpolation weights
- const float s1 = xTrace - x0;
- const float s0 = 1.0f - s1;
- const float t1 = yTrace - y0;
- const float t0 = 1.0f - t1;
- const float u1 = zTrace - z0;
- const float u0 = 1.0f - u1;
-
- const int i000 = x0 + y0 * xres + z0 * slabSize;
- const int i010 = x0 + y1 * xres + z0 * slabSize;
- const int i100 = x1 + y0 * xres + z0 * slabSize;
- const int i110 = x1 + y1 * xres + z0 * slabSize;
- const int i001 = x0 + y0 * xres + z1 * slabSize;
- const int i011 = x0 + y1 * xres + z1 * slabSize;
- const int i101 = x1 + y0 * xres + z1 * slabSize;
- const int i111 = x1 + y1 * xres + z1 * slabSize;
-
- // interpolate
- // (indices could be computed once)
- newField[index] = u0 * (s0 * (t0 * oldField[i000] +
- t1 * oldField[i010]) +
- s1 * (t0 * oldField[i100] +
- t1 * oldField[i110])) +
- u1 * (s0 * (t0 * oldField[i001] +
- t1 * oldField[i011]) +
- s1 * (t0 * oldField[i101] +
- t1 * oldField[i111]));
- }
-}
-
-
-/////////////////////////////////////////////////////////////////////
-// advect field with the maccormack method
-//
-// comments are the pseudocode from selle's paper
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::advectFieldMacCormack1(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* tempResult, Vec3Int res, int zBegin, int zEnd)
-{
- /*const int sx= res[0];
- const int sy= res[1];
- const int sz= res[2];
-
- for (int x = 0; x < sx * sy * sz; x++)
- phiHatN[x] = phiHatN1[x] = oldField[x];*/ // not needed as all the values are written first
-
- float*& phiN = oldField;
- float*& phiN1 = tempResult;
-
-
-
- // phiHatN1 = A(phiN)
- advectFieldSemiLagrange( dt, xVelocity, yVelocity, zVelocity, phiN, phiN1, res, zBegin, zEnd); // uses wide data from old field and velocities (both are whole)
-}
-
-
-
-void FLUID_3D::advectFieldMacCormack2(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* newField, float* tempResult, float* temp1, Vec3Int res, const unsigned char* obstacles, int zBegin, int zEnd)
-{
- float* phiHatN = tempResult;
- float* t1 = temp1;
- const int sx= res[0];
- const int sy= res[1];
-
- float*& phiN = oldField;
- float*& phiN1 = newField;
-
-
-
- // phiHatN = A^R(phiHatN1)
- advectFieldSemiLagrange( -1.0f*dt, xVelocity, yVelocity, zVelocity, phiHatN, t1, res, zBegin, zEnd); // uses wide data from old field and velocities (both are whole)
-
- // phiN1 = phiHatN1 + (phiN - phiHatN) / 2
- const int border = 0;
- for (int z = zBegin+border; z < zEnd-border; z++)
- for (int y = border; y < sy-border; y++)
- for (int x = border; x < sx-border; x++) {
- int index = x + y * sx + z * sx*sy;
- phiN1[index] = phiHatN[index] + (phiN[index] - t1[index]) * 0.50f;
- //phiN1[index] = phiHatN1[index]; // debug, correction off
- }
- copyBorderX(phiN1, res, zBegin, zEnd);
- copyBorderY(phiN1, res, zBegin, zEnd);
- copyBorderZ(phiN1, res, zBegin, zEnd);
-
- // clamp any newly created extrema
- clampExtrema(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res, zBegin, zEnd); // uses wide data from old field and velocities (both are whole)
-
- // if the error estimate was bad, revert to first order
- clampOutsideRays(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res, obstacles, phiHatN, zBegin, zEnd); // phiHatN is only used at cells within thread range, so its ok
-
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// Clamp the extrema generated by the BFECC error correction
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::clampExtrema(const float dt, const float* velx, const float* vely, const float* velz,
- float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd)
-{
- const int xres= res[0];
- const int yres= res[1];
- const int zres= res[2];
- const int slabSize = res[0] * res[1];
-
- int bb=0;
- int bt=0;
-
- if (zBegin == 0) {bb = 1;}
- if (zEnd == res[2]) {bt = 1;}
-
-
- for (int z = zBegin+bb; z < zEnd-bt; z++)
- for (int y = 1; y < yres-1; y++)
- for (int x = 1; x < xres-1; x++)
- {
- const int index = x + y * xres+ z * xres*yres;
- // backtrace
- float xTrace = x - dt * velx[index];
- float yTrace = y - dt * vely[index];
- float zTrace = z - dt * velz[index];
-
- // clamp backtrace to grid boundaries
- if (xTrace < 0.5f) xTrace = 0.5f;
- if (xTrace > xres - 1.5f) xTrace = xres - 1.5f;
- if (yTrace < 0.5f) yTrace = 0.5f;
- if (yTrace > yres - 1.5f) yTrace = yres - 1.5f;
- if (zTrace < 0.5f) zTrace = 0.5f;
- if (zTrace > zres - 1.5f) zTrace = zres - 1.5f;
-
- // locate neighbors to interpolate
- const int x0 = (int)xTrace;
- const int x1 = x0 + 1;
- const int y0 = (int)yTrace;
- const int y1 = y0 + 1;
- const int z0 = (int)zTrace;
- const int z1 = z0 + 1;
-
- const int i000 = x0 + y0 * xres + z0 * slabSize;
- const int i010 = x0 + y1 * xres + z0 * slabSize;
- const int i100 = x1 + y0 * xres + z0 * slabSize;
- const int i110 = x1 + y1 * xres + z0 * slabSize;
- const int i001 = x0 + y0 * xres + z1 * slabSize;
- const int i011 = x0 + y1 * xres + z1 * slabSize;
- const int i101 = x1 + y0 * xres + z1 * slabSize;
- const int i111 = x1 + y1 * xres + z1 * slabSize;
-
- float minField = oldField[i000];
- float maxField = oldField[i000];
-
- minField = (oldField[i010] < minField) ? oldField[i010] : minField;
- maxField = (oldField[i010] > maxField) ? oldField[i010] : maxField;
-
- minField = (oldField[i100] < minField) ? oldField[i100] : minField;
- maxField = (oldField[i100] > maxField) ? oldField[i100] : maxField;
-
- minField = (oldField[i110] < minField) ? oldField[i110] : minField;
- maxField = (oldField[i110] > maxField) ? oldField[i110] : maxField;
-
- minField = (oldField[i001] < minField) ? oldField[i001] : minField;
- maxField = (oldField[i001] > maxField) ? oldField[i001] : maxField;
-
- minField = (oldField[i011] < minField) ? oldField[i011] : minField;
- maxField = (oldField[i011] > maxField) ? oldField[i011] : maxField;
-
- minField = (oldField[i101] < minField) ? oldField[i101] : minField;
- maxField = (oldField[i101] > maxField) ? oldField[i101] : maxField;
-
- minField = (oldField[i111] < minField) ? oldField[i111] : minField;
- maxField = (oldField[i111] > maxField) ? oldField[i111] : maxField;
-
- newField[index] = (newField[index] > maxField) ? maxField : newField[index];
- newField[index] = (newField[index] < minField) ? minField : newField[index];
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// Reverts any backtraces that go into boundaries back to first
-// order -- in this case the error correction term was totally
-// incorrect
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::clampOutsideRays(const float dt, const float* velx, const float* vely, const float* velz,
- float* oldField, float* newField, Vec3Int res, const unsigned char* obstacles, const float *oldAdvection, int zBegin, int zEnd)
-{
- const int sx= res[0];
- const int sy= res[1];
- const int sz= res[2];
- const int slabSize = res[0] * res[1];
-
- int bb=0;
- int bt=0;
-
- if (zBegin == 0) {bb = 1;}
- if (zEnd == res[2]) {bt = 1;}
-
- for (int z = zBegin+bb; z < zEnd-bt; z++)
- for (int y = 1; y < sy-1; y++)
- for (int x = 1; x < sx-1; x++)
- {
- const int index = x + y * sx+ z * slabSize;
- // backtrace
- float xBackward = x + dt * velx[index];
- float yBackward = y + dt * vely[index];
- float zBackward = z + dt * velz[index];
- float xTrace = x - dt * velx[index];
- float yTrace = y - dt * vely[index];
- float zTrace = z - dt * velz[index];
-
- // see if it goes outside the boundaries
- bool hasObstacle =
- (zTrace < 1.0f) || (zTrace > sz - 2.0f) ||
- (yTrace < 1.0f) || (yTrace > sy - 2.0f) ||
- (xTrace < 1.0f) || (xTrace > sx - 2.0f) ||
- (zBackward < 1.0f) || (zBackward > sz - 2.0f) ||
- (yBackward < 1.0f) || (yBackward > sy - 2.0f) ||
- (xBackward < 1.0f) || (xBackward > sx - 2.0f);
- // reuse old advection instead of doing another one...
- if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
-
- // clamp to prevent an out of bounds access when looking into
- // the _obstacles array
- zTrace = (zTrace < 0.5f) ? 0.5f : zTrace;
- zTrace = (zTrace > sz - 1.5f) ? sz - 1.5f : zTrace;
- yTrace = (yTrace < 0.5f) ? 0.5f : yTrace;
- yTrace = (yTrace > sy - 1.5f) ? sy - 1.5f : yTrace;
- xTrace = (xTrace < 0.5f) ? 0.5f : xTrace;
- xTrace = (xTrace > sx - 1.5f) ? sx - 1.5f : xTrace;
-
- // locate neighbors to interpolate,
- // do backward first since we will use the forward indices if a
- // reversion is actually necessary
- zBackward = (zBackward < 0.5f) ? 0.5f : zBackward;
- zBackward = (zBackward > sz - 1.5f) ? sz - 1.5f : zBackward;
- yBackward = (yBackward < 0.5f) ? 0.5f : yBackward;
- yBackward = (yBackward > sy - 1.5f) ? sy - 1.5f : yBackward;
- xBackward = (xBackward < 0.5f) ? 0.5f : xBackward;
- xBackward = (xBackward > sx - 1.5f) ? sx - 1.5f : xBackward;
-
- int x0 = (int)xBackward;
- int x1 = x0 + 1;
- int y0 = (int)yBackward;
- int y1 = y0 + 1;
- int z0 = (int)zBackward;
- int z1 = z0 + 1;
- if(obstacles && !hasObstacle) {
- hasObstacle = hasObstacle ||
- obstacles[x0 + y0 * sx + z0*slabSize] ||
- obstacles[x0 + y1 * sx + z0*slabSize] ||
- obstacles[x1 + y0 * sx + z0*slabSize] ||
- obstacles[x1 + y1 * sx + z0*slabSize] ||
- obstacles[x0 + y0 * sx + z1*slabSize] ||
- obstacles[x0 + y1 * sx + z1*slabSize] ||
- obstacles[x1 + y0 * sx + z1*slabSize] ||
- obstacles[x1 + y1 * sx + z1*slabSize] ;
- }
- // reuse old advection instead of doing another one...
- if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
-
- x0 = (int)xTrace;
- x1 = x0 + 1;
- y0 = (int)yTrace;
- y1 = y0 + 1;
- z0 = (int)zTrace;
- z1 = z0 + 1;
- if(obstacles && !hasObstacle) {
- hasObstacle = hasObstacle ||
- obstacles[x0 + y0 * sx + z0*slabSize] ||
- obstacles[x0 + y1 * sx + z0*slabSize] ||
- obstacles[x1 + y0 * sx + z0*slabSize] ||
- obstacles[x1 + y1 * sx + z0*slabSize] ||
- obstacles[x0 + y0 * sx + z1*slabSize] ||
- obstacles[x0 + y1 * sx + z1*slabSize] ||
- obstacles[x1 + y0 * sx + z1*slabSize] ||
- obstacles[x1 + y1 * sx + z1*slabSize] ;
- } // obstacle array
- // reuse old advection instead of doing another one...
- if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
-
- // see if either the forward or backward ray went into
- // a boundary
- if (hasObstacle) {
- // get interpolation weights
- float s1 = xTrace - x0;
- float s0 = 1.0f - s1;
- float t1 = yTrace - y0;
- float t0 = 1.0f - t1;
- float u1 = zTrace - z0;
- float u0 = 1.0f - u1;
-
- const int i000 = x0 + y0 * sx + z0 * slabSize;
- const int i010 = x0 + y1 * sx + z0 * slabSize;
- const int i100 = x1 + y0 * sx + z0 * slabSize;
- const int i110 = x1 + y1 * sx + z0 * slabSize;
- const int i001 = x0 + y0 * sx + z1 * slabSize;
- const int i011 = x0 + y1 * sx + z1 * slabSize;
- const int i101 = x1 + y0 * sx + z1 * slabSize;
- const int i111 = x1 + y1 * sx + z1 * slabSize;
-
- // interpolate, (indices could be computed once)
- newField[index] = u0 * (s0 * (
- t0 * oldField[i000] +
- t1 * oldField[i010]) +
- s1 * (t0 * oldField[i100] +
- t1 * oldField[i110])) +
- u1 * (s0 * (t0 * oldField[i001] +
- t1 * oldField[i011]) +
- s1 * (t0 * oldField[i101] +
- t1 * oldField[i111]));
- }
- } // xyz
-}
diff --git a/intern/smoke/intern/IMAGE.h b/intern/smoke/intern/IMAGE.h
deleted file mode 100644
index 4680e4eace2..00000000000
--- a/intern/smoke/intern/IMAGE.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-//////////////////////////////////////////////////////////////////////
-//
-#ifndef IMAGE_H
-#define IMAGE_H
-
-#include <stdlib.h>
-#include <string>
-#include <fstream>
-#include <sstream>
-#include <zlib.h>
-
-//////////////////////////////////////////////////////////////////////
-// NT helper functions
-//////////////////////////////////////////////////////////////////////
-template < class T > inline T ABS( T a ) {
- return (0 < a) ? a : -a ;
-}
-
-template < class T > inline void SWAP_POINTERS( T &a, T &b ) {
- T temp = a;
- a = b;
- b = temp;
-}
-
-template < class T > inline void CLAMP( T &a, T b=0., T c=1.) {
- if(a<b) { a=b; return; }
- if(a>c) { a=c; return; }
-}
-
-template < class T > inline T MIN( const T& a, const T& b) {
- return (a < b) ? a : b;
-}
-
-template < class T > inline T MAX( const T& a, const T& b) {
- return (a > b) ? a : b;
-}
-
-template < class T > inline T MAX3( const T& a, const T& b, const T& c) {
- T max = (a > b) ? a : b;
- max = (max > c) ? max : c;
- return max;
-}
-
-template < class T > inline float MAX3V( const T& vec) {
- float max = (vec[0] > vec[1]) ? vec[0] : vec[1];
- max = (max > vec[2]) ? max : vec[2];
- return max;
-}
-
-template < class T > inline float MIN3V( const T& vec) {
- float min = (vec[0] < vec[1]) ? vec[0] : vec[1];
- min = (min < vec[2]) ? min : vec[2];
- return min;
-}
-
-//////////////////////////////////////////////////////////////////////
-// PNG, POV-Ray, and PBRT output functions
-//////////////////////////////////////////////////////////////////////
-#ifndef NOPNG
-#ifdef WIN32
-#include "png.h"
-#else
-#include <png.h>
-#endif
-#endif // NOPNG
-
-/*
- NOTE when someone decided to uncomment the following code, please remember to put it between #ifndef NOPNG #endif
-*/
-namespace IMAGE {
- /*
- static int writePng(const char *fileName, unsigned char **rowsp, int w, int h)
- {
- // defaults
- const int colortype = PNG_COLOR_TYPE_RGBA;
- const int bitdepth = 8;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- png_bytep *rows = rowsp;
-
- FILE *fp = NULL;
- std::string doing = "open for writing";
- if (!(fp = fopen(fileName, "wb"))) goto fail;
-
- if(!png_ptr) {
- doing = "create png write struct";
- if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail;
- }
- if(!info_ptr) {
- doing = "create png info struct";
- if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail;
- }
-
- if (setjmp(png_jmpbuf(png_ptr))) goto fail;
- doing = "init IO";
- png_init_io(png_ptr, fp);
- doing = "write header";
- png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
- doing = "write info";
- png_write_info(png_ptr, info_ptr);
- doing = "write image";
- png_write_image(png_ptr, rows);
- doing = "write end";
- png_write_end(png_ptr, NULL);
- doing = "write destroy structs";
- png_destroy_write_struct(&png_ptr, &info_ptr);
-
- fclose( fp );
- return 0;
-
- fail:
- std::cerr << "writePng: could not "<<doing<<" !\n";
- if(fp) fclose( fp );
- if(png_ptr || info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
- return -1;
- }
- */
-
- /////////////////////////////////////////////////////////////////////////////////
- // write a numbered PNG file out, padded with zeros up to three zeros
- /////////////////////////////////////////////////////////////////////////////////
- /*
- static void dumpNumberedPNG(int counter, std::string prefix, float* field, int xRes, int yRes)
- {
- char buffer[256];
- sprintf(buffer,"%04i", counter);
- std::string number = std::string(buffer);
-
- unsigned char pngbuf[xRes*yRes*4];
- unsigned char *rows[yRes];
- float *pfield = field;
- for (int j=0; j<yRes; j++) {
- for (int i=0; i<xRes; i++) {
- float val = *pfield;
- if(val>1.) val=1.;
- if(val<0.) val=0.;
- pngbuf[(j*xRes+i)*4+0] = (unsigned char)(val*255.);
- pngbuf[(j*xRes+i)*4+1] = (unsigned char)(val*255.);
- pngbuf[(j*xRes+i)*4+2] = (unsigned char)(val*255.);
- pfield++;
- pngbuf[(j*xRes+i)*4+3] = 255;
- }
- rows[j] = &pngbuf[(yRes-j-1)*xRes*4];
- }
- std::string filenamePNG = prefix + number + std::string(".png");
- writePng(filenamePNG.c_str(), rows, xRes, yRes, false);
- printf("Writing %s\n", filenamePNG.c_str());
-
- }
-*/
- /////////////////////////////////////////////////////////////////////////////////
- // export pbrt volumegrid geometry object
- /////////////////////////////////////////////////////////////////////////////////
- /*
- static void dumpPBRT(int counter, std::string prefix, float* fieldOrg, int xRes, int yRes, int zRes)
- {
- char buffer[256];
- sprintf(buffer,"%04i", counter);
- std::string number = std::string(buffer);
-
- std::string filenamePbrt = prefix + number + std::string(".pbrt.gz");
- printf("Writing PBRT %s\n", filenamePbrt.c_str());
-
- float *field = new float[xRes*yRes*zRes];
- // normalize values
- float maxDensVal = ABS(fieldOrg[0]);
- float targetNorm = 0.5;
- for (int i = 0; i < xRes * yRes * zRes; i++) {
- if(ABS(fieldOrg[i])>maxDensVal) maxDensVal = ABS(fieldOrg[i]);
- field[i] = 0.;
- }
- if(maxDensVal>0.) {
- for (int i = 0; i < xRes * yRes * zRes; i++) {
- field[i] = ABS(fieldOrg[i]) / maxDensVal * targetNorm;
- }
- }
-
- std::fstream fout;
- fout.open(filenamePbrt.c_str(), std::ios::out);
-
- int maxRes = (xRes > yRes) ? xRes : yRes;
- maxRes = (maxRes > zRes) ? maxRes : zRes;
-
- const float xSize = 1.0 / (float)maxRes * (float)xRes;
- const float ySize = 1.0 / (float)maxRes * (float)yRes;
- const float zSize = 1.0 / (float)maxRes * (float)zRes;
-
- gzFile file;
- file = gzopen(filenamePbrt.c_str(), "wb1");
- if (file == NULL) {
- std::cerr << " Couldn't write file " << filenamePbrt << "!!!" << std::endl;
- return;
- }
-
- // dimensions
- gzprintf(file, "Volume \"volumegrid\" \n");
- gzprintf(file, " \"integer nx\" %i\n", xRes);
- gzprintf(file, " \"integer ny\" %i\n", yRes);
- gzprintf(file, " \"integer nz\" %i\n", zRes);
- gzprintf(file, " \"point p0\" [ 0.0 0.0 0.0 ] \"point p1\" [%f %f %f ] \n", xSize, ySize, zSize);
- gzprintf(file, " \"float density\" [ \n");
- for (int i = 0; i < xRes * yRes * zRes; i++)
- gzprintf(file, "%f ", field[i]);
- gzprintf(file, "] \n \n");
-
- gzclose(file);
- delete[] field;
- }
- */
-
- /////////////////////////////////////////////////////////////////////////////////
- // 3D df3 export
- /////////////////////////////////////////////////////////////////////////////////
-/*
- static void dumpDF3(int counter, std::string prefix, float* fieldOrg, int xRes, int yRes, int zRes)
- {
- char buffer[256];
-
- // do deferred copying to final directory, better for network directories
- sprintf(buffer,"%04i", counter);
- std::string number = std::string(buffer);
- std::string filenameDf3 = prefix + number + std::string(".df3.gz");
- printf("Writing DF3 %s\n", filenameDf3.c_str());
-
- gzFile file;
- file = gzopen(filenameDf3.c_str(), "wb1");
- if (file == NULL) {
- std::cerr << " Couldn't write file " << filenameDf3 << "!!!" << std::endl;
- return;
- }
-
- // dimensions
- const int byteSize = 2;
- const unsigned short int onx=xRes,ony=yRes,onz=zRes;
- unsigned short int nx,ny,nz;
- nx = onx >> 8;
- ny = ony >> 8;
- nz = onz >> 8;
- nx += (onx << 8);
- ny += (ony << 8);
- nz += (onz << 8);
- gzwrite(file, (void*)&nx, sizeof(short));
- gzwrite(file, (void*)&ny, sizeof(short));
- gzwrite(file, (void*)&nz, sizeof(short));
- const int nitems = onx*ony*onz;
- const float mul = (float)( (1<<(8*byteSize))-1);
-
- unsigned short int *buf = new unsigned short int[nitems];
- for (int k = 0; k < onz; k++)
- for (int j = 0; j < ony; j++)
- for (int i = 0; i < onx; i++) {
- float val = fieldOrg[k*(onx*ony)+j*onx+i] ;
- CLAMP(val);
- buf[k*(onx*ony)+j*onx+i] = (short int)(val*mul);
- }
- gzwrite(file, (void*)buf, sizeof(unsigned short int)* nitems);
-
- gzclose(file);
- delete[] buf;
- }
- */
-
-};
-
-
-#endif
-
diff --git a/intern/smoke/intern/INTERPOLATE.h b/intern/smoke/intern/INTERPOLATE.h
deleted file mode 100644
index e9821e4f93e..00000000000
--- a/intern/smoke/intern/INTERPOLATE.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-//////////////////////////////////////////////////////////////////////
-#ifndef INTERPOLATE_H
-#define INTERPOLATE_H
-
-#include <iostream>
-#include <VEC3.h>
-
-namespace INTERPOLATE {
-
-//////////////////////////////////////////////////////////////////////
-// linear interpolators
-//////////////////////////////////////////////////////////////////////
-static inline float lerp(float t, float a, float b) {
- return ( a + t * (b - a) );
-}
-
-static inline float lerp(float* field, float x, float y, int res) {
- // clamp backtrace to grid boundaries
- if (x < 0.5f) x = 0.5f;
- if (x > res - 1.5f) x = res - 1.5f;
- if (y < 0.5f) y = 0.5f;
- if (y > res - 1.5f) y = res - 1.5f;
-
- const int x0 = (int)x;
- const int y0 = (int)y;
- x -= x0;
- y -= y0;
- float d00, d10, d01, d11;
-
- // lerp the velocities
- d00 = field[x0 + y0 * res];
- d10 = field[(x0 + 1) + y0 * res];
- d01 = field[x0 + (y0 + 1) * res];
- d11 = field[(x0 + 1) + (y0 + 1) * res];
- return lerp(y, lerp(x, d00, d10),
- lerp(x, d01, d11));
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// 3d linear interpolation
-//////////////////////////////////////////////////////////////////////////////////////////
-static inline float lerp3d(float* field, float x, float y, float z, int xres, int yres, int zres) {
- // clamp pos to grid boundaries
- if (x < 0.5f) x = 0.5f;
- if (x > xres - 1.5f) x = xres - 1.5f;
- if (y < 0.5f) y = 0.5f;
- if (y > yres - 1.5f) y = yres - 1.5f;
- if (z < 0.5f) z = 0.5f;
- if (z > zres - 1.5f) z = zres - 1.5f;
-
- // locate neighbors to interpolate
- const int x0 = (int)x;
- const int x1 = x0 + 1;
- const int y0 = (int)y;
- const int y1 = y0 + 1;
- const int z0 = (int)z;
- const int z1 = z0 + 1;
-
- // get interpolation weights
- const float s1 = x - (float)x0;
- const float s0 = 1.0f - s1;
- const float t1 = y - (float)y0;
- const float t0 = 1.0f - t1;
- const float u1 = z - (float)z0;
- const float u0 = 1.0f - u1;
-
- const int slabSize = xres*yres;
- const int i000 = x0 + y0 * xres + z0 * slabSize;
- const int i010 = x0 + y1 * xres + z0 * slabSize;
- const int i100 = x1 + y0 * xres + z0 * slabSize;
- const int i110 = x1 + y1 * xres + z0 * slabSize;
- const int i001 = x0 + y0 * xres + z1 * slabSize;
- const int i011 = x0 + y1 * xres + z1 * slabSize;
- const int i101 = x1 + y0 * xres + z1 * slabSize;
- const int i111 = x1 + y1 * xres + z1 * slabSize;
-
- // interpolate (indices could be computed once)
- return ( u0 * (s0 * (t0 * field[i000] +
- t1 * field[i010]) +
- s1 * (t0 * field[i100] +
- t1 * field[i110])) +
- u1 * (s0 * (t0 * field[i001] +
- t1 * field[i011]) +
- s1 * (t0 * field[i101] +
- t1 * field[i111])) );
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// convert field entries of type T to floats, then interpolate
-//////////////////////////////////////////////////////////////////////////////////////////
-template <class T>
-static inline float lerp3dToFloat(T* field1,
- float x, float y, float z, int xres, int yres, int zres) {
- // clamp pos to grid boundaries
- if (x < 0.5f) x = 0.5f;
- if (x > xres - 1.5f) x = xres - 1.5f;
- if (y < 0.5f) y = 0.5f;
- if (y > yres - 1.5f) y = yres - 1.5f;
- if (z < 0.5f) z = 0.5f;
- if (z > zres - 1.5f) z = zres - 1.5f;
-
- // locate neighbors to interpolate
- const int x0 = (int)x;
- const int x1 = x0 + 1;
- const int y0 = (int)y;
- const int y1 = y0 + 1;
- const int z0 = (int)z;
- const int z1 = z0 + 1;
-
- // get interpolation weights
- const float s1 = x - (float)x0;
- const float s0 = 1.0f - s1;
- const float t1 = y - (float)y0;
- const float t0 = 1.0f - t1;
- const float u1 = z - (float)z0;
- const float u0 = 1.0f - u1;
-
- const int slabSize = xres*yres;
- const int i000 = x0 + y0 * xres + z0 * slabSize;
- const int i010 = x0 + y1 * xres + z0 * slabSize;
- const int i100 = x1 + y0 * xres + z0 * slabSize;
- const int i110 = x1 + y1 * xres + z0 * slabSize;
- const int i001 = x0 + y0 * xres + z1 * slabSize;
- const int i011 = x0 + y1 * xres + z1 * slabSize;
- const int i101 = x1 + y0 * xres + z1 * slabSize;
- const int i111 = x1 + y1 * xres + z1 * slabSize;
-
- // interpolate (indices could be computed once)
- return (float)(
- ( u0 * (s0 * (t0 * (float)field1[i000] +
- t1 * (float)field1[i010]) +
- s1 * (t0 * (float)field1[i100] +
- t1 * (float)field1[i110])) +
- u1 * (s0 * (t0 * (float)field1[i001] +
- t1 * (float)field1[i011]) +
- s1 * (t0 * (float)field1[i101] +
- t1 * (float)field1[i111])) ) );
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// interpolate a vector from 3 fields
-//////////////////////////////////////////////////////////////////////////////////////////
-static inline Vec3 lerp3dVec(float* field1, float* field2, float* field3,
- float x, float y, float z, int xres, int yres, int zres) {
- // clamp pos to grid boundaries
- if (x < 0.5f) x = 0.5f;
- if (x > xres - 1.5f) x = xres - 1.5f;
- if (y < 0.5f) y = 0.5f;
- if (y > yres - 1.5f) y = yres - 1.5f;
- if (z < 0.5f) z = 0.5f;
- if (z > zres - 1.5f) z = zres - 1.5f;
-
- // locate neighbors to interpolate
- const int x0 = (int)x;
- const int x1 = x0 + 1;
- const int y0 = (int)y;
- const int y1 = y0 + 1;
- const int z0 = (int)z;
- const int z1 = z0 + 1;
-
- // get interpolation weights
- const float s1 = x - (float)x0;
- const float s0 = 1.0f - s1;
- const float t1 = y - (float)y0;
- const float t0 = 1.0f - t1;
- const float u1 = z - (float)z0;
- const float u0 = 1.0f - u1;
-
- const int slabSize = xres*yres;
- const int i000 = x0 + y0 * xres + z0 * slabSize;
- const int i010 = x0 + y1 * xres + z0 * slabSize;
- const int i100 = x1 + y0 * xres + z0 * slabSize;
- const int i110 = x1 + y1 * xres + z0 * slabSize;
- const int i001 = x0 + y0 * xres + z1 * slabSize;
- const int i011 = x0 + y1 * xres + z1 * slabSize;
- const int i101 = x1 + y0 * xres + z1 * slabSize;
- const int i111 = x1 + y1 * xres + z1 * slabSize;
-
- // interpolate (indices could be computed once)
- return Vec3(
- ( u0 * (s0 * (t0 * field1[i000] +
- t1 * field1[i010]) +
- s1 * (t0 * field1[i100] +
- t1 * field1[i110])) +
- u1 * (s0 * (t0 * field1[i001] +
- t1 * field1[i011]) +
- s1 * (t0 * field1[i101] +
- t1 * field1[i111])) ) ,
- ( u0 * (s0 * (t0 * field2[i000] +
- t1 * field2[i010]) +
- s1 * (t0 * field2[i100] +
- t1 * field2[i110])) +
- u1 * (s0 * (t0 * field2[i001] +
- t1 * field2[i011]) +
- s1 * (t0 * field2[i101] +
- t1 * field2[i111])) ) ,
- ( u0 * (s0 * (t0 * field3[i000] +
- t1 * field3[i010]) +
- s1 * (t0 * field3[i100] +
- t1 * field3[i110])) +
- u1 * (s0 * (t0 * field3[i001] +
- t1 * field3[i011]) +
- s1 * (t0 * field3[i101] +
- t1 * field3[i111])) )
- );
-}
-
-};
-#endif
diff --git a/intern/smoke/intern/LICENSE.txt b/intern/smoke/intern/LICENSE.txt
deleted file mode 100644
index 94a9ed024d3..00000000000
--- a/intern/smoke/intern/LICENSE.txt
+++ /dev/null
@@ -1,674 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/intern/smoke/intern/LU_HELPER.cpp b/intern/smoke/intern/LU_HELPER.cpp
deleted file mode 100644
index 0a4260c2e64..00000000000
--- a/intern/smoke/intern/LU_HELPER.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-
-#include "LU_HELPER.h"
-
-int isNonsingular (sLU LU_) {
- for (int j = 0; j < 3; j++) {
- if (LU_.values[j][j] == 0)
- return 0;
- }
- return 1;
-}
-
-sLU computeLU( float a[3][3])
-{
- sLU result;
- int m=3;
- int n=3;
-
- //float LU_[3][3];
- for (int i = 0; i < m; i++) {
- result.piv[i] = i;
- for (int j = 0; j < n; j++) result.values[i][j]=a[i][j];
- }
-
- result.pivsign = 1;
- //Real *LUrowi = 0;;
- //Array1D<Real> LUcolj(m);
- //float *LUrowi = 0;
- float LUcolj[3];
-
- // Outer loop.
-
- for (int j = 0; j < n; j++) {
-
- // Make a copy of the j-th column to localize references.
-
- for (int i = 0; i < m; i++) {
- LUcolj[i] = result.values[i][j];
- }
-
- // Apply previous transformations.
-
- for (int i = 0; i < m; i++) {
- //float LUrowi[3];
- //LUrowi = result.values[i];
-
- // Most of the time is spent in the following dot product.
-
- int kmax = min(i,j);
- double s = 0.0;
- for (int k = 0; k < kmax; k++) {
- s += (double)(result.values[i][k]*LUcolj[k]);
- }
-
- result.values[i][j] = LUcolj[i] -= (float)s;
- }
-
- // Find pivot and exchange if necessary.
-
- int p = j;
- for (int i = j+1; i < m; i++) {
- if (abs(LUcolj[i]) > abs(LUcolj[p])) {
- p = i;
- }
- }
- if (p != j) {
- int k=0;
- for (k = 0; k < n; k++) {
- double t = result.values[p][k];
- result.values[p][k] = result.values[j][k];
- result.values[j][k] = t;
- }
- k = result.piv[p];
- result.piv[p] = result.piv[j];
- result.piv[j] = k;
- result.pivsign = -result.pivsign;
- }
-
- // Compute multipliers.
-
- if ((j < m) && (result.values[j][j] != 0.0f)) {
- for (int i = j+1; i < m; i++) {
- result.values[i][j] /= result.values[j][j];
- }
- }
- }
-
- return result;
-}
-
-void solveLU3x3(sLU& A, float x[3], float b[3])
-{
- //TNT::Array1D<float> jamaB = TNT::Array1D<float>(3, &b[0]);
- //TNT::Array1D<float> jamaX = A.solve(jamaB);
-
-
- // Solve A, B
-
- {
- if (!isNonsingular(A)) {
- x[0]=0.0f;
- x[1]=0.0f;
- x[2]=0.0f;
- return;
- }
-
-
- //Array1D<Real> Ax = permute_copy(b, piv);
- float Ax[3];
-
- // permute copy: b , A.piv
- {
- for (int i = 0; i < 3; i++)
- Ax[i] = b[A.piv[i]];
- }
-
- // Solve L*Y = B(piv)
- for (int k = 0; k < 3; k++) {
- for (int i = k+1; i < 3; i++) {
- Ax[i] -= Ax[k]*A.values[i][k];
- }
- }
-
- // Solve U*X = Y;
- for (int k = 2; k >= 0; k--) {
- Ax[k] /= A.values[k][k];
- for (int i = 0; i < k; i++)
- Ax[i] -= Ax[k]*A.values[i][k];
- }
-
-
- x[0] = Ax[0];
- x[1] = Ax[1];
- x[2] = Ax[2];
- return;
- }
-}
diff --git a/intern/smoke/intern/LU_HELPER.h b/intern/smoke/intern/LU_HELPER.h
deleted file mode 100644
index 3cc8e9e3ced..00000000000
--- a/intern/smoke/intern/LU_HELPER.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-//////////////////////////////////////////////////////////////////////
-// Modified to not require TNT matrix library anymore. It was very slow
-// when being run in parallel. Required TNT JAMA:LU libraries were
-// converted into independent functions.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#ifndef LU_HELPER_H
-#define LU_HELPER_H
-
-#include <cmath>
-#include <algorithm>
-
-using namespace std;
-
-//////////////////////////////////////////////////////////////////////
-// Helper function, compute eigenvalues of 3x3 matrix
-//////////////////////////////////////////////////////////////////////
-
-struct sLU
-{
- float values[3][3];
- int pivsign;
- int piv[3];
-};
-
-
-int isNonsingular (sLU LU_);
-sLU computeLU( float a[3][3]);
-void solveLU3x3(sLU& A, float x[3], float b[3]);
-
-
-#endif
diff --git a/intern/smoke/intern/MERSENNETWISTER.h b/intern/smoke/intern/MERSENNETWISTER.h
deleted file mode 100644
index b142ca4072b..00000000000
--- a/intern/smoke/intern/MERSENNETWISTER.h
+++ /dev/null
@@ -1,432 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-// MersenneTwister.h
-// Mersenne Twister random number generator -- a C++ class MTRand
-// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
-// Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com
-
-// The Mersenne Twister is an algorithm for generating random numbers. It
-// was designed with consideration of the flaws in various other generators.
-// The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
-// are far greater. The generator is also fast; it avoids multiplication and
-// division, and it benefits from caches and pipelines. For more information
-// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html
-
-// Reference
-// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
-// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
-// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
-
-// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
-// Copyright (C) 2000 - 2003, Richard J. Wagner
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//
-// 1. Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-//
-// 3. The names of its contributors may not be used to endorse or promote
-// products derived from this software without specific prior written
-// permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// The original code included the following notice:
-//
-// When you use this, send an email to: matumoto@math.keio.ac.jp
-// with an appropriate reference to your work.
-//
-// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu
-// when you write.
-
-#ifndef MERSENNETWISTER_H
-#define MERSENNETWISTER_H
-
-// Not thread safe (unless auto-initialization is avoided and each thread has
-// its own MTRand object)
-
-#include <iostream>
-#include <limits.h>
-#include <stdio.h>
-#include <time.h>
-#include <math.h>
-
-class MTRand {
-// Data
-public:
- typedef unsigned long uint32; // unsigned integer type, at least 32 bits
-
- enum { N = 624 }; // length of state vector
- enum { SAVE = N + 1 }; // length of array for save()
-
-protected:
- enum { M = 397 }; // period parameter
-
- uint32 state[N]; // internal state
- uint32 *pNext; // next value to get from state
- int left; // number of values left before reload needed
-
-
-//Methods
-public:
- MTRand( const uint32& oneSeed ); // initialize with a simple uint32
- MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or an array
- MTRand(); // auto-initialize with /dev/urandom or time() and clock()
-
- // Do NOT use for CRYPTOGRAPHY without securely hashing several returned
- // values together, otherwise the generator state can be learned after
- // reading 624 consecutive values.
-
- // Access to 32-bit random numbers
- double rand(); // real number in [0,1]
- double rand( const double& n ); // real number in [0,n]
- double randExc(); // real number in [0,1)
- double randExc( const double& n ); // real number in [0,n)
- double randDblExc(); // real number in (0,1)
- double randDblExc( const double& n ); // real number in (0,n)
- uint32 randInt(); // integer in [0,2^32-1]
- uint32 randInt( const uint32& n ); // integer in [0,n] for n < 2^32
- double operator()() { return rand(); } // same as rand()
-
- // Access to 53-bit random numbers (capacity of IEEE double precision)
- double rand53(); // real number in [0,1)
-
- // Access to nonuniform random number distributions
- double randNorm( const double& mean = 0.0, const double& variance = 1.0 );
-
- // Re-seeding functions with same behavior as initializers
- void seed( const uint32 oneSeed );
- void seed( uint32 *const bigSeed, const uint32 seedLength = N );
- void seed();
-
- // Saving and loading generator state
- void save( uint32* saveArray ) const; // to array of size SAVE
- void load( uint32 *const loadArray ); // from such array
- friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand );
- friend std::istream& operator>>( std::istream& is, MTRand& mtrand );
-
-protected:
- void initialize( const uint32 oneSeed );
- void reload();
- uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; }
- uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; }
- uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; }
- uint32 mixBits( const uint32& u, const uint32& v ) const
- { return hiBit(u) | loBits(v); }
- uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const
- { return m ^ (mixBits(s0,s1)>>1) ^ ((~loBit(s1) + 1) & 0x9908b0dfUL); }
- static uint32 hash( time_t t, clock_t c );
-};
-
-
-inline MTRand::MTRand( const uint32& oneSeed )
- { seed(oneSeed); }
-
-inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength )
- { seed(bigSeed,seedLength); }
-
-inline MTRand::MTRand()
- { seed(); }
-
-inline double MTRand::rand()
- { return double(randInt()) * (1.0/4294967295.0); }
-
-inline double MTRand::rand( const double& n )
- { return rand() * n; }
-
-inline double MTRand::randExc()
- { return double(randInt()) * (1.0/4294967296.0); }
-
-inline double MTRand::randExc( const double& n )
- { return randExc() * n; }
-
-inline double MTRand::randDblExc()
- { return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); }
-
-inline double MTRand::randDblExc( const double& n )
- { return randDblExc() * n; }
-
-inline double MTRand::rand53()
-{
- uint32 a = randInt() >> 5, b = randInt() >> 6;
- return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0); // by Isaku Wada
-}
-
-inline double MTRand::randNorm( const double& mean, const double& variance )
-{
- // Return a real number from a normal (Gaussian) distribution with given
- // mean and variance by Box-Muller method
- double r = sqrt( -2.0 * log( 1.0-randDblExc()) ) * variance;
- double phi = 2.0 * 3.14159265358979323846264338328 * randExc();
- return mean + r * cos(phi);
-}
-
-inline MTRand::uint32 MTRand::randInt()
-{
- // Pull a 32-bit integer from the generator state
- // Every other access function simply transforms the numbers extracted here
-
- if( left == 0 ) reload();
- --left;
-
- uint32 s1;
- s1 = *pNext++;
- s1 ^= (s1 >> 11);
- s1 ^= (s1 << 7) & 0x9d2c5680UL;
- s1 ^= (s1 << 15) & 0xefc60000UL;
- return ( s1 ^ (s1 >> 18) );
-}
-
-inline MTRand::uint32 MTRand::randInt( const uint32& n )
-{
- // Find which bits are used in n
- // Optimized by Magnus Jonsson (magnus@smartelectronix.com)
- uint32 used = n;
- used |= used >> 1;
- used |= used >> 2;
- used |= used >> 4;
- used |= used >> 8;
- used |= used >> 16;
-
- // Draw numbers until one is found in [0,n]
- uint32 i;
- do
- i = randInt() & used; // toss unused bits to shorten search
- while( i > n );
- return i;
-}
-
-
-inline void MTRand::seed( const uint32 oneSeed )
-{
- // Seed the generator with a simple uint32
- initialize(oneSeed);
- reload();
-}
-
-
-inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
-{
- // Seed the generator with an array of uint32's
- // There are 2^19937-1 possible initial states. This function allows
- // all of those to be accessed by providing at least 19937 bits (with a
- // default seed length of N = 624 uint32's). Any bits above the lower 32
- // in each element are discarded.
- // Just call seed() if you want to get array from /dev/urandom
- initialize(19650218UL);
- int i = 1;
- uint32 j = 0;
- int k = ( (uint32)N > seedLength ? (uint32)N : seedLength );
- for( ; k; --k )
- {
- state[i] =
- state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL );
- state[i] += ( bigSeed[j] & 0xffffffffUL ) + j;
- state[i] &= 0xffffffffUL;
- ++i; ++j;
- if( i >= N ) { state[0] = state[N-1]; i = 1; }
- if( j >= seedLength ) j = 0;
- }
- for( k = N - 1; k; --k )
- {
- state[i] =
- state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL );
- state[i] -= i;
- state[i] &= 0xffffffffUL;
- ++i;
- if( i >= N ) { state[0] = state[N-1]; i = 1; }
- }
- state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array
- reload();
-}
-
-
-inline void MTRand::seed()
-{
- // seed deterministically to produce reproducible runs
- seed(123456);
-
- /*
- // Seed the generator with an array from /dev/urandom if available
- // Otherwise use a hash of time() and clock() values
-
- // First try getting an array from /dev/urandom
- FILE* urandom = fopen( "/dev/urandom", "rb" );
- if( urandom )
- {
- uint32 bigSeed[N];
- uint32 *s = bigSeed;
- int i = N;
- bool success = true;
- while( success && i-- )
- success = fread( s++, sizeof(uint32), 1, urandom );
- fclose(urandom);
- if( success ) { seed( bigSeed, N ); return; }
- }
-
- // Was not successful, so use time() and clock() instead
- seed( hash( time(NULL), clock() ) );
- */
-}
-
-
-inline void MTRand::initialize( const uint32 seed )
-{
- // Initialize generator state with seed
- // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
- // In previous versions, most significant bits (MSBs) of the seed affect
- // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
- uint32 *s = state;
- uint32 *r = state;
- int i = 1;
- *s++ = seed & 0xffffffffUL;
- for( ; i < N; ++i )
- {
- *s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
- r++;
- }
-}
-
-
-inline void MTRand::reload()
-{
- // Generate N new values in state
- // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
- uint32 *p = state;
- int i;
- for( i = N - M; i--; ++p )
- *p = twist( p[M], p[0], p[1] );
- for( i = M; --i; ++p )
- *p = twist( p[M-N], p[0], p[1] );
- *p = twist( p[M-N], p[0], state[0] );
-
- left = N, pNext = state;
-}
-
-
-inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )
-{
- // Get a uint32 from t and c
- // Better than uint32(x) in case x is floating point in [0,1]
- // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
-
- static uint32 differ = 0; // guarantee time-based seeds will change
-
- uint32 h1 = 0;
- unsigned char *p = (unsigned char *) &t;
- for( size_t i = 0; i < sizeof(t); ++i )
- {
- h1 *= UCHAR_MAX + 2U;
- h1 += p[i];
- }
- uint32 h2 = 0;
- p = (unsigned char *) &c;
- for( size_t j = 0; j < sizeof(c); ++j )
- {
- h2 *= UCHAR_MAX + 2U;
- h2 += p[j];
- }
- return ( h1 + differ++ ) ^ h2;
-}
-
-
-inline void MTRand::save( uint32* saveArray ) const
-{
- uint32 *sa = saveArray;
- const uint32 *s = state;
- int i = N;
- for( ; i--; *sa++ = *s++ ) {}
- *sa = left;
-}
-
-
-inline void MTRand::load( uint32 *const loadArray )
-{
- uint32 *s = state;
- uint32 *la = loadArray;
- int i = N;
- for( ; i--; *s++ = *la++ ) {}
- left = *la;
- pNext = &state[N-left];
-}
-
-
-inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
-{
- const MTRand::uint32 *s = mtrand.state;
- int i = mtrand.N;
- for( ; i--; os << *s++ << "\t" ) {}
- return os << mtrand.left;
-}
-
-
-inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
-{
- MTRand::uint32 *s = mtrand.state;
- int i = mtrand.N;
- for( ; i--; is >> *s++ ) {}
- is >> mtrand.left;
- mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
- return is;
-}
-
-#endif // MERSENNETWISTER_H
-
-// Change log:
-//
-// v0.1 - First release on 15 May 2000
-// - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
-// - Translated from C to C++
-// - Made completely ANSI compliant
-// - Designed convenient interface for initialization, seeding, and
-// obtaining numbers in default or user-defined ranges
-// - Added automatic seeding from /dev/urandom or time() and clock()
-// - Provided functions for saving and loading generator state
-//
-// v0.2 - Fixed bug which reloaded generator one step too late
-//
-// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew
-//
-// v0.4 - Removed trailing newline in saved generator format to be consistent
-// with output format of built-in types
-//
-// v0.5 - Improved portability by replacing static const int's with enum's and
-// clarifying return values in seed(); suggested by Eric Heimburg
-// - Removed MAXINT constant; use 0xffffffffUL instead
-//
-// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits
-// - Changed integer [0,n] generator to give better uniformity
-//
-// v0.7 - Fixed operator precedence ambiguity in reload()
-// - Added access for real numbers in (0,1) and (0,n)
-//
-// v0.8 - Included time.h header to properly support time_t and clock_t
-//
-// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto
-// - Allowed for seeding with arrays of any length
-// - Added access for real numbers in [0,1) with 53-bit resolution
-// - Added access for real numbers from normal (Gaussian) distributions
-// - Increased overall speed by optimizing twist()
-// - Doubled speed of integer [0,n] generation
-// - Fixed out-of-range number generation on 64-bit machines
-// - Improved portability by substituting literal constants for long enum's
-// - Changed license from GNU LGPL to BSD
-
diff --git a/intern/smoke/intern/Makefile.FFT b/intern/smoke/intern/Makefile.FFT
deleted file mode 100644
index 7e9d089cec2..00000000000
--- a/intern/smoke/intern/Makefile.FFT
+++ /dev/null
@@ -1,22 +0,0 @@
-# common stuff
-LDFLAGS_COMMON = -lfftw3 #-lglut -lglu32 -lopengl32 -lz -lpng
-CFLAGS_COMMON = -c -Wall -I./ #-I/cygdrive/c/lib/glvu/include -D_WIN32
-
-CC = g++
-CFLAGS = ${CFLAGS_COMMON} -O3 -Wno-unused
-LDFLAGS = ${LDFLAGS_COMMON}
-EXECUTABLE = noiseFFT
-
-SOURCES = noiseFFT.cpp
-OBJECTS = $(SOURCES:.cpp=.o)
-
-all: $(SOURCES) $(EXECUTABLE)
-
-$(EXECUTABLE): $(OBJECTS)
- $(CC) $(OBJECTS) $(LDFLAGS) -o $@
-
-.cpp.o:
- $(CC) $(CFLAGS) $< -o $@
-
-clean:
- rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
diff --git a/intern/smoke/intern/Makefile.cygwin b/intern/smoke/intern/Makefile.cygwin
deleted file mode 100644
index 2a747219554..00000000000
--- a/intern/smoke/intern/Makefile.cygwin
+++ /dev/null
@@ -1,23 +0,0 @@
-CC = g++
-LDFLAGS = -lz -lpng
-CFLAGS = -O3 -Wno-unused -c -Wall -I./ -D_WIN32
-EXECUTABLE = FLUID_3D
-
-SOURCES = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp
-OBJECTS = $(SOURCES:.cpp=.o)
-
-all: $(SOURCES) $(EXECUTABLE)
-
-$(EXECUTABLE): $(OBJECTS)
- $(CC) $(OBJECTS) $(LDFLAGS) -o $@
-
-.cpp.o:
- $(CC) $(CFLAGS) $< -o $@
-
-SPHERE.o: SPHERE.h
-FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp
-FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp
-main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp
-
-clean:
- rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
diff --git a/intern/smoke/intern/Makefile.linux b/intern/smoke/intern/Makefile.linux
deleted file mode 100644
index 5fbb6e6c3e3..00000000000
--- a/intern/smoke/intern/Makefile.linux
+++ /dev/null
@@ -1,23 +0,0 @@
-CC = g++
-LDFLAGS = -lz -lpng -fopenmp -lgomp
-CFLAGS = -c -Wall -I./ -fopenmp -DPARALLEL=1 -O3 -Wno-unused
-EXECUTABLE = FLUID_3D
-
-SOURCES = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp
-OBJECTS = $(SOURCES:.cpp=.o)
-
-all: $(SOURCES) $(EXECUTABLE)
-
-$(EXECUTABLE): $(OBJECTS)
- $(CC) $(OBJECTS) $(LDFLAGS) -o $@
-
-.cpp.o:
- $(CC) $(CFLAGS) $< -o $@
-
-SPHERE.o: SPHERE.h
-FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp
-FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp
-main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp
-
-clean:
- rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
diff --git a/intern/smoke/intern/Makefile.mac b/intern/smoke/intern/Makefile.mac
deleted file mode 100644
index d0b7bd38c85..00000000000
--- a/intern/smoke/intern/Makefile.mac
+++ /dev/null
@@ -1,35 +0,0 @@
-CC = g++
-
-# uncomment the other two OPENMP_... lines, if your gcc supports OpenMP
-#OPENMP_FLAGS = -fopenmp -DPARALLEL=1 -I/opt/gcc-4.3/usr/local/include
-#OPENMPLD_FLAGS = -fopenmp -lgomp -I/opt/gcc-4.3/usr/local/lib
-OPENMP_FLAGS =
-OPENMPLD_FLAGS =
-
-# assumes MacPorts libpng installation
-PNG_INCLUDE = -I/opt/local/include
-PNG_LIBS = -I/opt/local/lib
-
-LDFLAGS = $(PNG_LIBS)-lz -lpng $(OPENMPLD_FLAGS)
-CFLAGS = -c -Wall -I./ $(PNG_INCLUDE) $(OPENMP_FLAGS) -O3 -Wno-unused
-EXECUTABLE = FLUID_3D
-
-SOURCES = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp
-OBJECTS = $(SOURCES:.cpp=.o)
-
-all: $(SOURCES) $(EXECUTABLE)
-
-$(EXECUTABLE): $(OBJECTS)
- $(CC) $(OBJECTS) $(LDFLAGS) -o $@
-
-.cpp.o:
- $(CC) $(CFLAGS) $< -o $@
-
-SPHERE.o: SPHERE.h
-FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp
-FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp
-main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp
-
-clean:
- rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
-
diff --git a/intern/smoke/intern/OBSTACLE.h b/intern/smoke/intern/OBSTACLE.h
deleted file mode 100644
index a23b484e7c1..00000000000
--- a/intern/smoke/intern/OBSTACLE.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// OBSTACLE.h: interface for the OBSTACLE class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#ifndef OBSTACLE_H
-#define OBSTACLE_H
-
-enum OBSTACLE_FLAGS {
- EMPTY = 0,
- /* 1 is used to flag an object cell */
- MARCHED = 2,
- RETIRED = 4,
- ANIMATED = 8,
-};
-
-class OBSTACLE
-{
-public:
- OBSTACLE() {};
- virtual ~OBSTACLE() {};
-
- virtual bool inside(float x, float y, float z) = 0;
-};
-
-#endif
diff --git a/intern/smoke/intern/SPHERE.cpp b/intern/smoke/intern/SPHERE.cpp
deleted file mode 100644
index 914ed5666c3..00000000000
--- a/intern/smoke/intern/SPHERE.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// SPHERE.cpp: implementation of the SPHERE class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#include "SPHERE.h"
-
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
-SPHERE::SPHERE(float x, float y, float z, float radius) :
- _radius(radius)
-{
- _center[0] = x;
- _center[1] = y;
- _center[2] = z;
-}
-
-SPHERE::~SPHERE()
-{
-
-}
-
-bool SPHERE::inside(float x, float y, float z)
-{
- float translate[] = {x - _center[0], y - _center[1], z - _center[2]};
- float magnitude = translate[0] * translate[0] +
- translate[1] * translate[1] +
- translate[2] * translate[2];
-
- return (magnitude < _radius * _radius) ? true : false;
-}
diff --git a/intern/smoke/intern/SPHERE.h b/intern/smoke/intern/SPHERE.h
deleted file mode 100644
index 6fdc93a5ee9..00000000000
--- a/intern/smoke/intern/SPHERE.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// SPHERE.h: interface for the SPHERE class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#ifndef SPHERE_H
-#define SPHERE_H
-
-#include "OBSTACLE.h"
-
-class SPHERE : public OBSTACLE
-{
-public:
- SPHERE(float x, float y, float z, float radius);
- virtual ~SPHERE();
-
- bool inside(float x, float y, float z);
-
-private:
- float _center[3];
- float _radius;
-};
-
-#endif
diff --git a/intern/smoke/intern/VEC3.h b/intern/smoke/intern/VEC3.h
deleted file mode 100644
index 3672da74196..00000000000
--- a/intern/smoke/intern/VEC3.h
+++ /dev/null
@@ -1,991 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/******************************************************************************
- * Copyright 2007 Nils Thuerey
- * Basic vector class
- *****************************************************************************/
-#ifndef BASICVECTOR_H
-#define BASICVECTOR_H
-
-#include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <iostream>
-#include <sstream>
-
-// use which fp-precision? 1=float, 2=double
-#ifndef FLOATINGPOINT_PRECISION
-#if DDF_DEBUG==1
-#define FLOATINGPOINT_PRECISION 2
-#else // DDF_DEBUG==1
-#define FLOATINGPOINT_PRECISION 1
-#endif // DDF_DEBUG==1
-#endif
-
-// VECTOR_EPSILON is the minimal vector length
-// In order to be able to discriminate floating point values near zero, and
-// to be sure not to fail a comparison because of roundoff errors, use this
-// value as a threshold.
-
-#if FLOATINGPOINT_PRECISION==1
-typedef float Real;
-#define FP_REAL_MAX __FLT_MAX__
-#define VECTOR_EPSILON (1e-5f)
-#else
-typedef double Real;
-#define FP_REAL_MAX __DBL_MAX__
-#define VECTOR_EPSILON (1e-10)
-#endif
-
-
-// hardcoded limits for now...
-// for e.g. MSVC compiler...
-// some of these defines can be needed
-// for linux systems as well (e.g. FLT_MAX)
-#ifndef __FLT_MAX__
-# ifdef FLT_MAX // try to use it instead
-# define __FLT_MAX__ FLT_MAX
-# else // FLT_MAX
-# define __FLT_MAX__ 3.402823466e+38f
-# endif // FLT_MAX
-#endif // __FLT_MAX__
-#ifndef __DBL_MAX__
-# ifdef DBL_MAX // try to use it instead
-# define __DBL_MAX__ DBL_MAX
-# else // DBL_MAX
-# define __DBL_MAX__ 1.7976931348623158e+308
-# endif // DBL_MAX
-#endif // __DBL_MAX__
-
-#ifndef FLT_MAX
-#define FLT_MAX __FLT_MAX__
-#endif
-
-#ifndef DBL_MAX
-#define DBL_MAX __DBL_MAX__
-#endif
-
-#ifndef M_PI
-# define M_PI 3.1415926536
-# define M_E 2.7182818284
-#endif
-
-
-
-namespace BasicVector {
-
-
-// basic inlined vector class
-template<class Scalar>
-class Vector3Dim
-{
-public:
- // Constructor
- inline Vector3Dim();
- // Copy-Constructor
- inline Vector3Dim(const Vector3Dim<Scalar> &v );
- inline Vector3Dim(const float *);
- inline Vector3Dim(const double *);
- // construct a vector from one Scalar
- inline Vector3Dim(Scalar);
- // construct a vector from three Scalars
- inline Vector3Dim(Scalar, Scalar, Scalar);
-
- // get address of array for OpenGL
- Scalar *getAddress() { return value; }
-
- // Assignment operator
- inline const Vector3Dim<Scalar>& operator= (const Vector3Dim<Scalar>& v);
- // Assignment operator
- inline const Vector3Dim<Scalar>& operator= (Scalar s);
- // Assign and add operator
- inline const Vector3Dim<Scalar>& operator+= (const Vector3Dim<Scalar>& v);
- // Assign and add operator
- inline const Vector3Dim<Scalar>& operator+= (Scalar s);
- // Assign and sub operator
- inline const Vector3Dim<Scalar>& operator-= (const Vector3Dim<Scalar>& v);
- // Assign and sub operator
- inline const Vector3Dim<Scalar>& operator-= (Scalar s);
- // Assign and mult operator
- inline const Vector3Dim<Scalar>& operator*= (const Vector3Dim<Scalar>& v);
- // Assign and mult operator
- inline const Vector3Dim<Scalar>& operator*= (Scalar s);
- // Assign and div operator
- inline const Vector3Dim<Scalar>& operator/= (const Vector3Dim<Scalar>& v);
- // Assign and div operator
- inline const Vector3Dim<Scalar>& operator/= (Scalar s);
-
-
- // unary operator
- inline Vector3Dim<Scalar> operator- () const;
-
- // binary operator add
- inline Vector3Dim<Scalar> operator+ (const Vector3Dim<Scalar>&) const;
- // binary operator add
- inline Vector3Dim<Scalar> operator+ (Scalar) const;
- // binary operator sub
- inline Vector3Dim<Scalar> operator- (const Vector3Dim<Scalar>&) const;
- // binary operator sub
- inline Vector3Dim<Scalar> operator- (Scalar) const;
- // binary operator mult
- inline Vector3Dim<Scalar> operator* (const Vector3Dim<Scalar>&) const;
- // binary operator mult
- inline Vector3Dim<Scalar> operator* (Scalar) const;
- // binary operator div
- inline Vector3Dim<Scalar> operator/ (const Vector3Dim<Scalar>&) const;
- // binary operator div
- inline Vector3Dim<Scalar> operator/ (Scalar) const;
-
- // Projection normal to a vector
- inline Vector3Dim<Scalar> getOrthogonalntlVector3Dim() const;
- // Project into a plane
- inline const Vector3Dim<Scalar>& projectNormalTo(const Vector3Dim<Scalar> &v);
-
- // minimize
- inline const Vector3Dim<Scalar> &minimize(const Vector3Dim<Scalar> &);
- // maximize
- inline const Vector3Dim<Scalar> &maximize(const Vector3Dim<Scalar> &);
-
- // access operator
- inline Scalar& operator[](unsigned int i);
- // access operator
- inline const Scalar& operator[](unsigned int i) const;
-
- //! actual values
- union {
- struct {
- Scalar value[3];
- };
- struct {
- Scalar x;
- Scalar y;
- Scalar z;
- };
- struct {
- Scalar X;
- Scalar Y;
- Scalar Z;
- };
- };
-protected:
-
-};
-
-
-
-
-
-//------------------------------------------------------------------------------
-// VECTOR inline FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Constructor.
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim( void )
-{
- value[0] = value[1] = value[2] = 0;
-}
-
-
-
-/*************************************************************************
- Copy-Constructor.
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim( const Vector3Dim<Scalar> &v )
-{
- value[0] = v.value[0];
- value[1] = v.value[1];
- value[2] = v.value[2];
-}
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim( const float *fvalue)
-{
- value[0] = (Scalar)fvalue[0];
- value[1] = (Scalar)fvalue[1];
- value[2] = (Scalar)fvalue[2];
-}
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim( const double *fvalue)
-{
- value[0] = (Scalar)fvalue[0];
- value[1] = (Scalar)fvalue[1];
- value[2] = (Scalar)fvalue[2];
-}
-
-
-
-/*************************************************************************
- Constructor for a vector from a single Scalar. All components of
- the vector get the same value.
- \param s The value to set
- \return The new vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim(Scalar s )
-{
- value[0]= s;
- value[1]= s;
- value[2]= s;
-}
-
-
-/*************************************************************************
- Constructor for a vector from three Scalars.
- \param s1 The value for the first vector component
- \param s2 The value for the second vector component
- \param s3 The value for the third vector component
- \return The new vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim(Scalar s1, Scalar s2, Scalar s3)
-{
- value[0]= s1;
- value[1]= s2;
- value[2]= s3;
-}
-
-
-
-/*************************************************************************
- Copy a Vector3Dim componentwise.
- \param v vector with values to be copied
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator=( const Vector3Dim<Scalar> &v )
-{
- value[0] = v.value[0];
- value[1] = v.value[1];
- value[2] = v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Copy a Scalar to each component.
- \param s The value to copy
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator=(Scalar s)
-{
- value[0] = s;
- value[1] = s;
- value[2] = s;
- return *this;
-}
-
-
-/*************************************************************************
- Add another Vector3Dim componentwise.
- \param v vector with values to be added
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator+=( const Vector3Dim<Scalar> &v )
-{
- value[0] += v.value[0];
- value[1] += v.value[1];
- value[2] += v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Add a Scalar value to each component.
- \param s Value to add
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator+=(Scalar s)
-{
- value[0] += s;
- value[1] += s;
- value[2] += s;
- return *this;
-}
-
-
-/*************************************************************************
- Subtract another vector componentwise.
- \param v vector of values to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator-=( const Vector3Dim<Scalar> &v )
-{
- value[0] -= v.value[0];
- value[1] -= v.value[1];
- value[2] -= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Subtract a Scalar value from each component.
- \param s Value to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator-=(Scalar s)
-{
- value[0]-= s;
- value[1]-= s;
- value[2]-= s;
- return *this;
-}
-
-
-/*************************************************************************
- Multiply with another vector componentwise.
- \param v vector of values to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator*=( const Vector3Dim<Scalar> &v )
-{
- value[0] *= v.value[0];
- value[1] *= v.value[1];
- value[2] *= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Multiply each component with a Scalar value.
- \param s Value to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator*=(Scalar s)
-{
- value[0] *= s;
- value[1] *= s;
- value[2] *= s;
- return *this;
-}
-
-
-/*************************************************************************
- Divide by another Vector3Dim componentwise.
- \param v vector of values to divide by
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator/=( const Vector3Dim<Scalar> &v )
-{
- value[0] /= v.value[0];
- value[1] /= v.value[1];
- value[2] /= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Divide each component by a Scalar value.
- \param s Value to divide by
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator/=(Scalar s)
-{
- value[0] /= s;
- value[1] /= s;
- value[2] /= s;
- return *this;
-}
-
-
-//------------------------------------------------------------------------------
-// unary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build componentwise the negative this vector.
- \return The new (negative) vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator-() const
-{
- return Vector3Dim<Scalar>(-value[0], -value[1], -value[2]);
-}
-
-
-
-//------------------------------------------------------------------------------
-// binary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build a vector with another vector added componentwise.
- \param v The second vector to add
- \return The sum vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator+( const Vector3Dim<Scalar> &v ) const
-{
- return Vector3Dim<Scalar>(value[0]+v.value[0],
- value[1]+v.value[1],
- value[2]+v.value[2]);
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value added to each component.
- \param s The Scalar value to add
- \return The sum vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator+(Scalar s) const
-{
- return Vector3Dim<Scalar>(value[0]+s,
- value[1]+s,
- value[2]+s);
-}
-
-
-/*************************************************************************
- Build a vector with another vector subtracted componentwise.
- \param v The second vector to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator-( const Vector3Dim<Scalar> &v ) const
-{
- return Vector3Dim<Scalar>(value[0]-v.value[0],
- value[1]-v.value[1],
- value[2]-v.value[2]);
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value subtracted componentwise.
- \param s The Scalar value to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator-(Scalar s ) const
-{
- return Vector3Dim<Scalar>(value[0]-s,
- value[1]-s,
- value[2]-s);
-}
-
-
-
-/*************************************************************************
- Build a vector with another vector multiplied by componentwise.
- \param v The second vector to muliply with
- \return The product vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator*( const Vector3Dim<Scalar>& v) const
-{
- return Vector3Dim<Scalar>(value[0]*v.value[0],
- value[1]*v.value[1],
- value[2]*v.value[2]);
-}
-
-
-/*************************************************************************
- Build a Vector3Dim with a Scalar value multiplied to each component.
- \param s The Scalar value to multiply with
- \return The product vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator*(Scalar s) const
-{
- return Vector3Dim<Scalar>(value[0]*s, value[1]*s, value[2]*s);
-}
-
-
-/*************************************************************************
- Build a vector divided componentwise by another vector.
- \param v The second vector to divide by
- \return The ratio vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator/(const Vector3Dim<Scalar>& v) const
-{
- return Vector3Dim<Scalar>(value[0]/v.value[0],
- value[1]/v.value[1],
- value[2]/v.value[2]);
-}
-
-
-
-/*************************************************************************
- Build a vector divided componentwise by a Scalar value.
- \param s The Scalar value to divide by
- \return The ratio vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator/(Scalar s) const
-{
- return Vector3Dim<Scalar>(value[0]/s,
- value[1]/s,
- value[2]/s);
-}
-
-
-
-
-
-/*************************************************************************
- Get a particular component of the vector.
- \param i Number of Scalar to get
- \return Reference to the component
- */
-template<class Scalar>
-inline Scalar&
-Vector3Dim<Scalar>::operator[]( unsigned int i )
-{
- return value[i];
-}
-
-
-/*************************************************************************
- Get a particular component of a constant vector.
- \param i Number of Scalar to get
- \return Reference to the component
- */
-template<class Scalar>
-inline const Scalar&
-Vector3Dim<Scalar>::operator[]( unsigned int i ) const
-{
- return value[i];
-}
-
-
-
-//------------------------------------------------------------------------------
-// BLITZ compatibility functions
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Compute the scalar product with another vector.
- \param v The second vector to work with
- \return The value of the scalar product
- */
-template<class Scalar>
-inline Scalar dot(const Vector3Dim<Scalar> &t, const Vector3Dim<Scalar> &v )
-{
- //return t.value[0]*v.value[0] + t.value[1]*v.value[1] + t.value[2]*v.value[2];
- return ((t[0]*v[0]) + (t[1]*v[1]) + (t[2]*v[2]));
-}
-
-
-/*************************************************************************
- Calculate the cross product of this and another vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar> cross(const Vector3Dim<Scalar> &t, const Vector3Dim<Scalar> &v)
-{
- Vector3Dim<Scalar> cp(
- ((t[1]*v[2]) - (t[2]*v[1])),
- ((t[2]*v[0]) - (t[0]*v[2])),
- ((t[0]*v[1]) - (t[1]*v[0])) );
- return cp;
-}
-
-
-
-
-/*************************************************************************
- Compute a vector that is orthonormal to self. Nothing else can be assumed
- for the direction of the new vector.
- \return The orthonormal vector
- */
-template<class Scalar>
-Vector3Dim<Scalar>
-Vector3Dim<Scalar>::getOrthogonalntlVector3Dim() const
-{
- // Determine the component with max. absolute value
- int max= (fabs(value[0]) > fabs(value[1])) ? 0 : 1;
- max= (fabs(value[max]) > fabs(value[2])) ? max : 2;
-
- /*************************************************************************
- Choose another axis than the one with max. component and project
- orthogonal to self
- */
- Vector3Dim<Scalar> vec(0.0);
- vec[(max+1)%3]= 1;
- vec.normalize();
- vec.projectNormalTo(this->getNormalized());
- return vec;
-}
-
-
-/*************************************************************************
- Projects the vector into a plane normal to the given vector, which must
- have unit length. Self is modified.
- \param v The plane normal
- \return The projected vector
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::projectNormalTo(const Vector3Dim<Scalar> &v)
-{
- Scalar sprod = dot(*this,v);
- value[0]= value[0] - v.value[0] * sprod;
- value[1]= value[1] - v.value[1] * sprod;
- value[2]= value[2] - v.value[2] * sprod;
- return *this;
-}
-
-
-
-//------------------------------------------------------------------------------
-// Other helper functions
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Minimize the vector, i.e. set each entry of the vector to the minimum
- of both values.
- \param pnt The second vector to compare with
- \return Reference to the modified self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar> &
-Vector3Dim<Scalar>::minimize(const Vector3Dim<Scalar> &pnt)
-{
- for (unsigned int i = 0; i < 3; i++)
- value[i] = MIN(value[i],pnt[i]);
- return *this;
-}
-
-
-
-/*************************************************************************
- Maximize the vector, i.e. set each entry of the vector to the maximum
- of both values.
- \param pnt The second vector to compare with
- \return Reference to the modified self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar> &
-Vector3Dim<Scalar>::maximize(const Vector3Dim<Scalar> &pnt)
-{
- for (unsigned int i = 0; i < 3; i++)
- value[i] = MAX(value[i],pnt[i]);
- return *this;
-}
-
-
-
-
-
-
-/************************************************************************/
-// HELPER FUNCTIONS, independent of implementation
-/************************************************************************/
-
-#define VECTOR_TYPE Vector3Dim<Scalar>
-
-
-/*************************************************************************
- Compute the length (norm) of the vector.
- \return The value of the norm
- */
-template<class Scalar>
-inline Scalar norm( const VECTOR_TYPE &v)
-{
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- return (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) ? 1. : sqrt(l);
-}
-
-// for e.g. min max operator
-inline Real normHelper(const Vector3Dim<Real> &v) {
- return norm(v);
-}
-inline Real normHelper(const Real &v) {
- return (0.0f < v) ? v : -v ;
-}
-inline Real normHelper(const int &v) {
- return (0 < v) ? (Real)(v) : (Real)(-v) ;
-}
-
-
-/*************************************************************************
- Same as getNorm but doesnt sqrt
- */
-template<class Scalar>
-inline Scalar normNoSqrt( const VECTOR_TYPE &v)
-{
- return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
-}
-
-
-/*************************************************************************
- Compute a normalized vector based on this vector.
- \return The new normalized vector
- */
-template<class Scalar>
-inline VECTOR_TYPE getNormalized( const VECTOR_TYPE &v)
-{
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON)
- return v; /* normalized "enough"... */
- else if (l > VECTOR_EPSILON*VECTOR_EPSILON)
- {
- Scalar fac = 1./sqrt(l);
- return VECTOR_TYPE(v[0]*fac, v[1]*fac, v[2]*fac);
- }
- else
- return VECTOR_TYPE((Scalar)0);
-}
-
-
-/*************************************************************************
- Compute the norm of the vector and normalize it.
- \return The value of the norm
- */
-template<class Scalar>
-inline Scalar normalize( VECTOR_TYPE &v)
-{
- Scalar norm;
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) {
- norm = 1.;
- } else if (l > VECTOR_EPSILON*VECTOR_EPSILON) {
- norm = sqrt(l);
- Scalar fac = 1./norm;
- v[0] *= fac;
- v[1] *= fac;
- v[2] *= fac;
- } else {
- v[0]= v[1]= v[2]= 0;
- norm = 0.;
- }
- return (Scalar)norm;
-}
-
-
-/*************************************************************************
- Compute a vector, that is self (as an incoming
- vector) reflected at a surface with a distinct normal vector. Note
- that the normal is reversed, if the scalar product with it is positive.
- \param n The surface normal
- \return The new reflected vector
- */
-template<class Scalar>
-inline VECTOR_TYPE reflectVector(const VECTOR_TYPE &t, const VECTOR_TYPE &n)
-{
- VECTOR_TYPE nn= (dot(t, n) > 0.0) ? (n*-1.0) : n;
- return ( t - nn * (2.0 * dot(nn, t)) );
-}
-
-
-
-/*************************************************************************
- * My own refraction calculation
- * Taken from Glassner's book, section 5.2 (Heckberts method)
- */
-template<class Scalar>
-inline VECTOR_TYPE refractVector(const VECTOR_TYPE &t, const VECTOR_TYPE &normal, Scalar nt, Scalar nair, int &refRefl)
-{
- Scalar eta = nair / nt;
- Scalar n = -dot(t, normal);
- Scalar tt = 1.0 + eta*eta* (n*n-1.0);
- if(tt<0.0) {
- // we have total reflection!
- refRefl = 1;
- } else {
- // normal reflection
- tt = eta*n - sqrt(tt);
- return( t*eta + normal*tt );
- }
- return t;
-}
-
-
-/*************************************************************************
- Test two ntlVector3Dims for equality based on the equality of their
- values within a small threshold.
- \param c The second vector to compare
- \return TRUE if both are equal
- \sa getEpsilon()
- */
-template<class Scalar>
-inline bool equal(const VECTOR_TYPE &v, const VECTOR_TYPE &c)
-{
- return (ABS(v[0]-c[0]) +
- ABS(v[1]-c[1]) +
- ABS(v[2]-c[2]) < VECTOR_EPSILON);
-}
-
-
-/*************************************************************************
- * Assume this vector is an RGB color, and convert it to HSV
- */
-template<class Scalar>
-inline void rgbToHsv( VECTOR_TYPE &V )
-{
- Scalar h=0,s=0,v=0;
- Scalar maxrgb, minrgb, delta;
- // convert to hsv...
- maxrgb = V[0];
- int maxindex = 1;
- if(V[2] > maxrgb){ maxrgb = V[2]; maxindex = 2; }
- if(V[1] > maxrgb){ maxrgb = V[1]; maxindex = 3; }
- minrgb = V[0];
- if(V[2] < minrgb) minrgb = V[2];
- if(V[1] < minrgb) minrgb = V[1];
-
- v = maxrgb;
- delta = maxrgb-minrgb;
-
- if(maxrgb > 0) s = delta/maxrgb;
- else s = 0;
-
- h = 0;
- if(s > 0) {
- if(maxindex == 1) {
- h = ((V[1]-V[2])/delta) + 0.0; }
- if(maxindex == 2) {
- h = ((V[2]-V[0])/delta) + 2.0; }
- if(maxindex == 3) {
- h = ((V[0]-V[1])/delta) + 4.0; }
- h *= 60.0;
- if(h < 0.0) h += 360.0;
- }
-
- V[0] = h;
- V[1] = s;
- V[2] = v;
-}
-
-/*************************************************************************
- * Assume this vector is HSV and convert to RGB
- */
-template<class Scalar>
-inline void hsvToRgb( VECTOR_TYPE &V )
-{
- Scalar h = V[0], s = V[1], v = V[2];
- Scalar r=0,g=0,b=0;
- Scalar p,q,t, fracth;
- int floorh;
- // ...and back to rgb
- if(s == 0) {
- r = g = b = v; }
- else {
- h /= 60.0;
- floorh = (int)h;
- fracth = h - floorh;
- p = v * (1.0 - s);
- q = v * (1.0 - (s * fracth));
- t = v * (1.0 - (s * (1.0 - fracth)));
- switch (floorh) {
- case 0: r = v; g = t; b = p; break;
- case 1: r = q; g = v; b = p; break;
- case 2: r = p; g = v; b = t; break;
- case 3: r = p; g = q; b = v; break;
- case 4: r = t; g = p; b = v; break;
- case 5: r = v; g = p; b = q; break;
- }
- }
-
- V[0] = r;
- V[1] = g;
- V[2] = b;
-}
-
-//------------------------------------------------------------------------------
-// STREAM FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-//! global string for formatting vector output in utilities.cpp
-//extern const char *globVecFormatStr;
-#if 0
-static const char *globVecFormatStr = "[%6.4f,%6.4f,%6.4f]";
-#endif
-
-/*************************************************************************
- Outputs the object in human readable form using the format
- [x,y,z]
- */
-template<class Scalar>
-std::ostream&
-operator<<( std::ostream& os, const BasicVector::Vector3Dim<Scalar>& i )
-{
-#if 0
- char buf[256];
-# if _WIN32
- sprintf(buf,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]);
-# else
- snprintf(buf,256,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]);
-# endif
- os << std::string(buf);
-#else
- (void)i; /* Ignored. */
-#endif
- return os;
-}
-
-
-/*************************************************************************
- Reads the contents of the object from a stream using the same format
- as the output operator.
- */
-template<class Scalar>
-std::istream&
-operator>>( std::istream& is, BasicVector::Vector3Dim<Scalar>& i )
-{
- char c;
- char dummy[3];
- is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c;
- return is;
-}
-
-
-/**************************************************************************/
-// typedefs!
-/**************************************************************************/
-
-/* get minimal vector length value that can be discriminated. */
-inline Real getVecEpsilon() { return (Real)VECTOR_EPSILON; }
-
-// a 3D integer vector
-typedef Vector3Dim<int> Vec3Int;
-
-// a 3D vector
-typedef Vector3Dim<Real> Vec3;
-
-
-}; // namespace
-
-
-#endif /* BASICVECTOR_H */
diff --git a/intern/smoke/intern/WAVELET_NOISE.h b/intern/smoke/intern/WAVELET_NOISE.h
deleted file mode 100644
index 13ffe1e9697..00000000000
--- a/intern/smoke/intern/WAVELET_NOISE.h
+++ /dev/null
@@ -1,519 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-//////////////////////////////////////////////////////////////////////////////////////////
-// Wavelet noise functions
-//
-// This code is based on the C code provided in the appendices of:
-//
-// @article{1073264,
-// author = {Robert L. Cook and Tony DeRose},
-// title = {Wavelet noise},
-// journal = {ACM Trans. Graph.},
-// volume = {24},
-// number = {3},
-// year = {2005},
-// issn = {0730-0301},
-// pages = {803--811},
-// doi = {http://doi.acm.org/10.1145/1073204.1073264},
-// publisher = {ACM},
-// address = {New York, NY, USA},
-// }
-//
-//////////////////////////////////////////////////////////////////////////////////////////
-
-#ifndef WAVELET_NOISE_H
-#define WAVELET_NOISE_H
-
-#include <MERSENNETWISTER.h>
-
-#include <string.h>
-
-#ifdef WIN32
-#include <float.h>
-#define isnan _isnan
-#endif
-
-// Tile file header, update revision upon any change done to the noise generator
-static const char tilefile_headerstring[] = "Noise Tile File rev. ";
-static const char tilefile_revision[] = "001";
-
-#define NOISE_TILE_SIZE 128
-static const int noiseTileSize = NOISE_TILE_SIZE;
-
-// warning - noiseTileSize has to be 128^3!
-#define modFast128(x) ((x) & 127)
-#define modFast64(x) ((x) & 63)
-#define DOWNCOEFFS 0.000334f,-0.001528f, 0.000410f, 0.003545f,-0.000938f,-0.008233f, 0.002172f, 0.019120f, \
- -0.005040f,-0.044412f, 0.011655f, 0.103311f,-0.025936f,-0.243780f, 0.033979f, 0.655340f, \
- 0.655340f, 0.033979f,-0.243780f,-0.025936f, 0.103311f, 0.011655f,-0.044412f,-0.005040f, \
- 0.019120f, 0.002172f,-0.008233f,-0.000938f, 0.003546f, 0.000410f,-0.001528f, 0.000334f
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Wavelet downsampling -- periodic boundary conditions
-//////////////////////////////////////////////////////////////////////////////////////////
-static void downsampleX(float *from, float *to, int n){
- // if these values are not local incorrect results are generated
- float downCoeffs[32] = { DOWNCOEFFS };
- const float *a = &downCoeffs[16];
- for (int i = 0; i < n / 2; i++) {
- to[i] = 0;
- for (int k = 2 * i - 16; k < 2 * i + 16; k++)
- to[i] += a[k - 2 * i] * from[modFast128(k)];
- }
-}
-static void downsampleY(float *from, float *to, int n){
- // if these values are not local incorrect results are generated
- float downCoeffs[32] = { DOWNCOEFFS };
- const float *a = &downCoeffs[16];
- for (int i = 0; i < n / 2; i++) {
- to[i * n] = 0;
- for (int k = 2 * i - 16; k < 2 * i + 16; k++)
- to[i * n] += a[k - 2 * i] * from[modFast128(k) * n];
- }
-}
-static void downsampleZ(float *from, float *to, int n){
- // if these values are not local incorrect results are generated
- float downCoeffs[32] = { DOWNCOEFFS };
- const float *a = &downCoeffs[16];
- for (int i = 0; i < n / 2; i++) {
- to[i * n * n] = 0;
- for (int k = 2 * i - 16; k < 2 * i + 16; k++)
- to[i * n * n] += a[k - 2 * i] * from[modFast128(k) * n * n];
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Wavelet downsampling -- Neumann boundary conditions
-//////////////////////////////////////////////////////////////////////////////////////////
-static void downsampleNeumann(const float *from, float *to, int n, int stride)
-{
- // if these values are not local incorrect results are generated
- float downCoeffs[32] = { DOWNCOEFFS };
- const float *const aCoCenter= &downCoeffs[16];
- for (int i = 0; i <= n / 2; i++) {
- to[i * stride] = 0;
- for (int k = 2 * i - 16; k < 2 * i + 16; k++) {
- // handle boundary
- float fromval;
- if (k < 0) {
- fromval = from[0];
- } else if(k > n - 1) {
- fromval = from[(n - 1) * stride];
- } else {
- fromval = from[k * stride];
- }
- to[i * stride] += aCoCenter[k - 2 * i] * fromval;
- }
- }
-}
-static void downsampleXNeumann(float* to, const float* from, int sx,int sy, int sz) {
- for (int iy = 0; iy < sy; iy++)
- for (int iz = 0; iz < sz; iz++) {
- const int i = iy * sx + iz*sx*sy;
- downsampleNeumann(&from[i], &to[i], sx, 1);
- }
-}
-static void downsampleYNeumann(float* to, const float* from, int sx,int sy, int sz) {
- for (int ix = 0; ix < sx; ix++)
- for (int iz = 0; iz < sz; iz++) {
- const int i = ix + iz*sx*sy;
- downsampleNeumann(&from[i], &to[i], sy, sx);
- }
-}
-static void downsampleZNeumann(float* to, const float* from, int sx,int sy, int sz) {
- for (int ix = 0; ix < sx; ix++)
- for (int iy = 0; iy < sy; iy++) {
- const int i = ix + iy*sx;
- downsampleNeumann(&from[i], &to[i], sz, sx*sy);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Wavelet upsampling - periodic boundary conditions
-//////////////////////////////////////////////////////////////////////////////////////////
-static float _upCoeffs[4] = {0.25f, 0.75f, 0.75f, 0.25f};
-static void upsampleX(float *from, float *to, int n) {
- const float *p = &_upCoeffs[2];
-
- for (int i = 0; i < n; i++) {
- to[i] = 0;
- for (int k = i / 2; k <= i / 2 + 1; k++)
- to[i] += p[i - 2 * k] * from[modFast64(k)];
- }
-}
-static void upsampleY(float *from, float *to, int n) {
- const float *p = &_upCoeffs[2];
-
- for (int i = 0; i < n; i++) {
- to[i * n] = 0;
- for (int k = i / 2; k <= i / 2 + 1; k++)
- to[i * n] += p[i - 2 * k] * from[modFast64(k) * n];
- }
-}
-static void upsampleZ(float *from, float *to, int n) {
- const float *p = &_upCoeffs[2];
-
- for (int i = 0; i < n; i++) {
- to[i * n * n] = 0;
- for (int k = i / 2; k <= i / 2 + 1; k++)
- to[i * n * n] += p[i - 2 * k] * from[modFast64(k) * n * n];
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Wavelet upsampling - Neumann boundary conditions
-//////////////////////////////////////////////////////////////////////////////////////////
-static void upsampleNeumann(const float *from, float *to, int n, int stride) {
- static const float *const pCoCenter = &_upCoeffs[2];
- for (int i = 0; i < n; i++) {
- to[i * stride] = 0;
- for (int k = i / 2; k <= i / 2 + 1; k++) {
- float fromval;
- if(k>n/2) {
- fromval = from[(n/2) * stride];
- } else {
- fromval = from[k * stride];
- }
- to[i * stride] += pCoCenter[i - 2 * k] * fromval;
- }
- }
-}
-static void upsampleXNeumann(float* to, const float* from, int sx, int sy, int sz) {
- for (int iy = 0; iy < sy; iy++)
- for (int iz = 0; iz < sz; iz++) {
- const int i = iy * sx + iz*sx*sy;
- upsampleNeumann(&from[i], &to[i], sx, 1);
- }
-}
-static void upsampleYNeumann(float* to, const float* from, int sx, int sy, int sz) {
- for (int ix = 0; ix < sx; ix++)
- for (int iz = 0; iz < sz; iz++) {
- const int i = ix + iz*sx*sy;
- upsampleNeumann(&from[i], &to[i], sy, sx);
- }
-}
-static void upsampleZNeumann(float* to, const float* from, int sx, int sy, int sz) {
- for (int ix = 0; ix < sx; ix++)
- for (int iy = 0; iy < sy; iy++) {
- const int i = ix + iy*sx;
- upsampleNeumann(&from[i], &to[i], sz, sx*sy);
- }
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// load in an existing noise tile
-//////////////////////////////////////////////////////////////////////////////////////////
-static bool loadTile(float* const noiseTileData, std::string filename)
-{
- FILE* file;
- char headerbuffer[64];
- size_t headerlen;
- size_t bread;
- int endiantest = 1;
- char endianness;
-
- file = fopen(filename.c_str(), "rb");
-
- if (file == NULL) {
- printf("loadTile: No noise tile '%s' found.\n", filename.c_str());
- return false;
- }
-
- //Check header
- headerlen = strlen(tilefile_headerstring) + strlen(tilefile_revision) + 2;
- bread = fread((void*)headerbuffer, 1, headerlen, file);
- if (*((unsigned char*)&endiantest) == 1)
- endianness = 'L';
- else
- endianness = 'B';
- if ((bread != headerlen)
- || (strncmp(headerbuffer, tilefile_headerstring, strlen(tilefile_headerstring)))
- || (strncmp(headerbuffer+ strlen(tilefile_headerstring), tilefile_revision, strlen(tilefile_revision)))
- || (headerbuffer[headerlen-2] != endianness)
- || (headerbuffer[headerlen-1] != (char)((char)sizeof(long)+'0')))
- {
- printf("loadTile : Noise tile '%s' was generated on an incompatible platform.\n",filename.c_str());
- fclose(file);
- return false;
- }
-
- // dimensions
- size_t gridSize = noiseTileSize * noiseTileSize * noiseTileSize;
-
- // noiseTileData memory is managed by caller
- bread = fread((void*)noiseTileData, sizeof(float), gridSize, file);
- fclose(file);
- printf("Noise tile file '%s' loaded.\n", filename.c_str());
-
- if (bread != gridSize) {
- printf("loadTile: Noise tile '%s' is wrong size %d.\n", filename.c_str(), (int)bread);
- return false;
- }
-
- // check for invalid nan tile data that could be generated. bug is now
- // fixed, but invalid files may still hang around
- if (isnan(noiseTileData[0])) {
- printf("loadTile: Noise tile '%s' contains nan values.\n", filename.c_str());
- return false;
- }
-
- return true;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// write out an existing noise tile
-//////////////////////////////////////////////////////////////////////////////////////////
-static void saveTile(float* const noiseTileData, std::string filename)
-{
- FILE* file;
- file = fopen(filename.c_str(), "wb");
- int endiantest=1;
- char longsize;
-
- if (file == NULL) {
- printf("saveTile: Noise tile '%s' could not be saved.\n", filename.c_str());
- return;
- }
-
- //Write file header
- fwrite(tilefile_headerstring, strlen(tilefile_headerstring), 1, file);
- fwrite(tilefile_revision, strlen(tilefile_revision), 1, file);
- //Endianness
- if (*((unsigned char*)&endiantest) == 1)
- fwrite("L", 1, 1, file); //Little endian
- else
- fwrite("B",1,1,file); //Big endian
- //32/64bit
- longsize = (char)sizeof(long)+'0';
- fwrite(&longsize, 1, 1, file);
-
-
- fwrite((void*)noiseTileData, sizeof(float), noiseTileSize * noiseTileSize * noiseTileSize, file);
- fclose(file);
-
- printf("saveTile: Noise tile file '%s' saved.\n", filename.c_str());
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// create a new noise tile if necessary
-//////////////////////////////////////////////////////////////////////////////////////////
-static void generateTile_WAVELET(float* const noiseTileData, std::string filename) {
- // if a tile already exists, just use that
- if (loadTile(noiseTileData, filename)) return;
-
- const int n = noiseTileSize;
- const int n3 = n*n*n;
- std::cout <<"Generating new 3d noise tile size="<<n<<"^3 \n";
- MTRand twister;
-
- float *temp13 = new float[n3];
- float *temp23 = new float[n3];
- float *noise3 = new float[n3];
-
- // initialize
- for (int i = 0; i < n3; i++) {
- temp13[i] = temp23[i] = noise3[i] = 0.;
- }
-
- // Step 1. Fill the tile with random numbers in the range -1 to 1.
- for (int i = 0; i < n3; i++)
- noise3[i] = twister.randNorm();
-
- // Steps 2 and 3. Downsample and upsample the tile
- for (int iy = 0; iy < n; iy++)
- for (int iz = 0; iz < n; iz++) {
- const int i = iy * n + iz*n*n;
- downsampleX(&noise3[i], &temp13[i], n);
- upsampleX (&temp13[i], &temp23[i], n);
- }
- for (int ix = 0; ix < n; ix++)
- for (int iz = 0; iz < n; iz++) {
- const int i = ix + iz*n*n;
- downsampleY(&temp23[i], &temp13[i], n);
- upsampleY (&temp13[i], &temp23[i], n);
- }
- for (int ix = 0; ix < n; ix++)
- for (int iy = 0; iy < n; iy++) {
- const int i = ix + iy*n;
- downsampleZ(&temp23[i], &temp13[i], n);
- upsampleZ (&temp13[i], &temp23[i], n);
- }
-
- // Step 4. Subtract out the coarse-scale contribution
- for (int i = 0; i < n3; i++)
- noise3[i] -= temp23[i];
-
- // Avoid even/odd variance difference by adding odd-offset version of noise to itself.
- int offset = n / 2;
- if (offset % 2 == 0) offset++;
-
- int icnt=0;
- for (int ix = 0; ix < n; ix++)
- for (int iy = 0; iy < n; iy++)
- for (int iz = 0; iz < n; iz++) {
- temp13[icnt] = noise3[modFast128(ix+offset) + modFast128(iy+offset)*n + modFast128(iz+offset)*n*n];
- icnt++;
- }
-
- for (int i = 0; i < n3; i++)
- noise3[i] += temp13[i];
-
- for (int i = 0; i < n3; i++)
- noiseTileData[i] = noise3[i];
-
- saveTile(noise3, filename);
- delete[] temp13;
- delete[] temp23;
- delete[] noise3;
- std::cout <<"Generating new 3d noise done\n";
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// x derivative of noise
-//////////////////////////////////////////////////////////////////////////////////////////
-static inline float WNoiseDx(Vec3 p, float* data) {
- int c[3], mid[3], n = noiseTileSize;
- float w[3][3], t, result = 0;
-
- mid[0] = (int)ceil(p[0] - 0.5f);
- t = mid[0] - (p[0] - 0.5f);
- w[0][0] = -t;
- w[0][2] = (1.f - t);
- w[0][1] = 2.0f * t - 1.0f;
-
- mid[1] = (int)ceil(p[1] - 0.5f);
- t = mid[1] - (p[1] - 0.5f);
- w[1][0] = t * t / 2;
- w[1][2] = (1 - t) * (1 - t) / 2;
- w[1][1] = 1 - w[1][0] - w[1][2];
-
- mid[2] = (int)ceil(p[2] - 0.5f);
- t = mid[2] - (p[2] - 0.5f);
- w[2][0] = t * t / 2;
- w[2][2] = (1 - t) * (1 - t)/2;
- w[2][1] = 1 - w[2][0] - w[2][2];
-
- // to optimize, explicitly unroll this loop
- for (int z = -1; z <=1; z++)
- for (int y = -1; y <=1; y++)
- for (int x = -1; x <=1; x++)
- {
- float weight = 1.0f;
- c[0] = modFast128(mid[0] + x);
- weight *= w[0][x+1];
- c[1] = modFast128(mid[1] + y);
- weight *= w[1][y+1];
- c[2] = modFast128(mid[2] + z);
- weight *= w[2][z+1];
- result += weight * data[c[2]*n*n+c[1]*n+c[0]];
- }
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// y derivative of noise
-//////////////////////////////////////////////////////////////////////////////////////////
-static inline float WNoiseDy(Vec3 p, float* data) {
- int c[3], mid[3], n=noiseTileSize;
- float w[3][3], t, result =0;
-
- mid[0] = (int)ceil(p[0] - 0.5f);
- t = mid[0]-(p[0] - 0.5f);
- w[0][0] = t * t / 2;
- w[0][2] = (1 - t) * (1 - t) / 2;
- w[0][1] = 1 - w[0][0] - w[0][2];
-
- mid[1] = (int)ceil(p[1] - 0.5f);
- t = mid[1]-(p[1] - 0.5f);
- w[1][0] = -t;
- w[1][2] = (1.f - t);
- w[1][1] = 2.0f * t - 1.0f;
-
- mid[2] = (int)ceil(p[2] - 0.5f);
- t = mid[2] - (p[2] - 0.5f);
- w[2][0] = t * t / 2;
- w[2][2] = (1 - t) * (1 - t)/2;
- w[2][1] = 1 - w[2][0] - w[2][2];
-
- // to optimize, explicitly unroll this loop
- for (int z = -1; z <=1; z++)
- for (int y = -1; y <=1; y++)
- for (int x = -1; x <=1; x++)
- {
- float weight = 1.0f;
- c[0] = modFast128(mid[0] + x);
- weight *= w[0][x+1];
- c[1] = modFast128(mid[1] + y);
- weight *= w[1][y+1];
- c[2] = modFast128(mid[2] + z);
- weight *= w[2][z+1];
- result += weight * data[c[2]*n*n+c[1]*n+c[0]];
- }
-
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// z derivative of noise
-//////////////////////////////////////////////////////////////////////////////////////////
-static inline float WNoiseDz(Vec3 p, float* data) {
- int c[3], mid[3], n=noiseTileSize;
- float w[3][3], t, result =0;
-
- mid[0] = (int)ceil(p[0] - 0.5f);
- t = mid[0]-(p[0] - 0.5f);
- w[0][0] = t * t / 2;
- w[0][2] = (1 - t) * (1 - t) / 2;
- w[0][1] = 1 - w[0][0] - w[0][2];
-
- mid[1] = (int)ceil(p[1] - 0.5f);
- t = mid[1]-(p[1] - 0.5f);
- w[1][0] = t * t / 2;
- w[1][2] = (1 - t) * (1 - t) / 2;
- w[1][1] = 1 - w[1][0] - w[1][2];
-
- mid[2] = (int)ceil(p[2] - 0.5f);
- t = mid[2] - (p[2] - 0.5f);
- w[2][0] = -t;
- w[2][2] = (1.f - t);
- w[2][1] = 2.0f * t - 1.0f;
-
- // to optimize, explicitly unroll this loop
- for (int z = -1; z <=1; z++)
- for (int y = -1; y <=1; y++)
- for (int x = -1; x <=1; x++)
- {
- float weight = 1.0f;
- c[0] = modFast128(mid[0] + x);
- weight *= w[0][x+1];
- c[1] = modFast128(mid[1] + y);
- weight *= w[1][y+1];
- c[2] = modFast128(mid[2] + z);
- weight *= w[2][z+1];
- result += weight * data[c[2]*n*n+c[1]*n+c[0]];
- }
- return result;
-}
-
-#endif
-
diff --git a/intern/smoke/intern/WTURBULENCE.cpp b/intern/smoke/intern/WTURBULENCE.cpp
deleted file mode 100644
index 0703412d013..00000000000
--- a/intern/smoke/intern/WTURBULENCE.cpp
+++ /dev/null
@@ -1,1198 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// WTURBULENCE handling
-///////////////////////////////////////////////////////////////////////////////////
-// Parallelized turbulence even further. TNT matrix library functions
-// rewritten to improve performance.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#include "WTURBULENCE.h"
-#include "INTERPOLATE.h"
-#include "IMAGE.h"
-#include <MERSENNETWISTER.h>
-#include "WAVELET_NOISE.h"
-#include "FFT_NOISE.h"
-#include "EIGENVALUE_HELPER.h"
-#include "LU_HELPER.h"
-#include "SPHERE.h"
-#include <zlib.h>
-#include <math.h>
-
-// needed to access static advection functions
-#include "FLUID_3D.h"
-
-#if PARALLEL==1
-#include <omp.h>
-#endif // PARALLEL
-
-// 2^ {-5/6}
-static const float persistence = 0.56123f;
-
-//////////////////////////////////////////////////////////////////////
-// constructor
-//////////////////////////////////////////////////////////////////////
-WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors)
-{
- // if noise magnitude is below this threshold, its contribution
- // is negilgible, so stop evaluating new octaves
- _cullingThreshold = 1e-3;
-
- // factor by which to increase the simulation resolution
- _amplify = amplify;
-
- // manually adjust the overall amount of turbulence
- // DG - RNA-fied _strength = 2.;
-
- // add the corresponding octaves of noise
- _octaves = (int)(log((float)_amplify) / log(2.0f) + 0.5f); // XXX DEBUG/ TODO: int casting correct? - dg
-
- // noise resolution
- _xResBig = _amplify * xResSm;
- _yResBig = _amplify * yResSm;
- _zResBig = _amplify * zResSm;
- _resBig = Vec3Int(_xResBig, _yResBig, _zResBig);
- _invResBig = Vec3(1.0f/(float)_resBig[0], 1.0f/(float)_resBig[1], 1.0f/(float)_resBig[2]);
- _slabSizeBig = _xResBig*_yResBig;
- _totalCellsBig = _slabSizeBig * _zResBig;
-
- // original / small resolution
- _xResSm = xResSm;
- _yResSm = yResSm;
- _zResSm = zResSm;
- _resSm = Vec3Int(xResSm, yResSm, zResSm);
- _invResSm = Vec3(1.0f/(float)_resSm[0], 1.0f/(float)_resSm[1], 1.0f/(float)_resSm[2] );
- _slabSizeSm = _xResSm*_yResSm;
- _totalCellsSm = _slabSizeSm * _zResSm;
-
- // allocate high resolution density field
- _totalStepsBig = 0;
- _densityBig = new float[_totalCellsBig];
- _densityBigOld = new float[_totalCellsBig];
-
- for(int i = 0; i < _totalCellsBig; i++) {
- _densityBig[i] =
- _densityBigOld[i] = 0.;
- }
-
- /* fire */
- _flameBig = _fuelBig = _fuelBigOld = NULL;
- _reactBig = _reactBigOld = NULL;
- if (init_fire) {
- initFire();
- }
- /* colors */
- _color_rBig = _color_rBigOld = NULL;
- _color_gBig = _color_gBigOld = NULL;
- _color_bBig = _color_bBigOld = NULL;
- if (init_colors) {
- initColors(0.0f, 0.0f, 0.0f);
- }
-
- // allocate & init texture coordinates
- _tcU = new float[_totalCellsSm];
- _tcV = new float[_totalCellsSm];
- _tcW = new float[_totalCellsSm];
- _tcTemp = new float[_totalCellsSm];
-
- // map all
- const float dx = 1.0f/(float)(_resSm[0]);
- const float dy = 1.0f/(float)(_resSm[1]);
- const float dz = 1.0f/(float)(_resSm[2]);
- int index = 0;
- for (int z = 0; z < _zResSm; z++)
- for (int y = 0; y < _yResSm; y++)
- for (int x = 0; x < _xResSm; x++, index++)
- {
- _tcU[index] = x*dx;
- _tcV[index] = y*dy;
- _tcW[index] = z*dz;
- _tcTemp[index] = 0.;
- }
-
- // noise tiles
- _noiseTile = new float[noiseTileSize * noiseTileSize * noiseTileSize];
- setNoise(noisetype, noisefile_path);
-}
-
-void WTURBULENCE::initFire()
-{
- if (!_fuelBig) {
- _flameBig = new float[_totalCellsBig];
- _fuelBig = new float[_totalCellsBig];
- _fuelBigOld = new float[_totalCellsBig];
- _reactBig = new float[_totalCellsBig];
- _reactBigOld = new float[_totalCellsBig];
-
- for(int i = 0; i < _totalCellsBig; i++) {
- _flameBig[i] =
- _fuelBig[i] =
- _fuelBigOld[i] = 0.;
- _reactBig[i] =
- _reactBigOld[i] = 0.;
- }
- }
-}
-
-void WTURBULENCE::initColors(float init_r, float init_g, float init_b)
-{
- if (!_color_rBig) {
- _color_rBig = new float[_totalCellsBig];
- _color_rBigOld = new float[_totalCellsBig];
- _color_gBig = new float[_totalCellsBig];
- _color_gBigOld = new float[_totalCellsBig];
- _color_bBig = new float[_totalCellsBig];
- _color_bBigOld = new float[_totalCellsBig];
-
- for(int i = 0; i < _totalCellsBig; i++) {
- _color_rBig[i] = _densityBig[i] * init_r;
- _color_rBigOld[i] = 0.0f;
- _color_gBig[i] = _densityBig[i] * init_g;
- _color_gBigOld[i] = 0.0f;
- _color_bBig[i] = _densityBig[i] * init_b;
- _color_bBigOld[i] = 0.0f;
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// destructor
-//////////////////////////////////////////////////////////////////////
-WTURBULENCE::~WTURBULENCE() {
- delete[] _densityBig;
- delete[] _densityBigOld;
- if (_flameBig) delete[] _flameBig;
- if (_fuelBig) delete[] _fuelBig;
- if (_fuelBigOld) delete[] _fuelBigOld;
- if (_reactBig) delete[] _reactBig;
- if (_reactBigOld) delete[] _reactBigOld;
-
- if (_color_rBig) delete[] _color_rBig;
- if (_color_rBigOld) delete[] _color_rBigOld;
- if (_color_gBig) delete[] _color_gBig;
- if (_color_gBigOld) delete[] _color_gBigOld;
- if (_color_bBig) delete[] _color_bBig;
- if (_color_bBigOld) delete[] _color_bBigOld;
-
- delete[] _tcU;
- delete[] _tcV;
- delete[] _tcW;
- delete[] _tcTemp;
-
- delete[] _noiseTile;
-}
-
-//////////////////////////////////////////////////////////////////////
-// Change noise type
-//
-// type (1<<0) = wavelet / 2
-// type (1<<1) = FFT / 4
-// type (1<<2) = curl / 8
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::setNoise(int type, const char *noisefile_path)
-{
- if(type == (1<<1)) // FFT
- {
-#ifdef WITH_FFTW3
- // needs fft
- std::string noiseTileFilename = std::string(noisefile_path) + std::string("noise.fft");
- generatTile_FFT(_noiseTile, noiseTileFilename);
- return;
-#else
- fprintf(stderr, "FFTW not enabled, falling back to wavelet noise.\n");
-#endif
- }
-#if 0
- if(type == (1<<2)) // curl
- {
- // TODO: not supported yet
- return;
- }
-#endif
-
- std::string noiseTileFilename = std::string(noisefile_path) + std::string("noise.wavelets");
- generateTile_WAVELET(_noiseTile, noiseTileFilename);
-}
-
-// init direct access functions from blender
-void WTURBULENCE::initBlenderRNA(float *strength)
-{
- _strength = strength;
-}
-
-//////////////////////////////////////////////////////////////////////
-// Get the smallest valid x derivative
-//
-// Takes the one-sided finite difference in both directions and
-// selects the smaller of the two
-//////////////////////////////////////////////////////////////////////
-static float minDx(int x, int y, int z, float* input, const Vec3Int& res)
-{
- const int index = x + y * res[0] + z * res[0] * res[1];
- const int maxx = res[0]-2;
-
- // get grid values
- float center = input[index];
- float left = (x <= 1) ? FLT_MAX : input[index - 1];
- float right = (x >= maxx) ? FLT_MAX : input[index + 1];
-
- const float dx = res[0];
-
- // get all the derivative estimates
- float dLeft = (x <= 1) ? FLT_MAX : (center - left) * dx;
- float dRight = (x >= maxx) ? FLT_MAX : (right - center) * dx;
- float dCenter = (x <= 1 || x >= maxx) ? FLT_MAX : (right - left) * dx * 0.5f;
-
- // if it's on a boundary, only one estimate is valid
- if (x <= 1) return dRight;
- if (x >= maxx) return dLeft;
-
- // if it's not on a boundary, get the smallest one
- float finalD;
- finalD = (fabs(dCenter) < fabs(dRight)) ? dCenter : dRight;
- finalD = (fabs(finalD) < fabs(dLeft)) ? finalD : dLeft;
-
- return finalD;
-}
-
-//////////////////////////////////////////////////////////////////////
-// get the smallest valid y derivative
-//
-// Takes the one-sided finite difference in both directions and
-// selects the smaller of the two
-//////////////////////////////////////////////////////////////////////
-static float minDy(int x, int y, int z, float* input, const Vec3Int& res)
-{
- const int index = x + y * res[0] + z * res[0] * res[1];
- const int maxy = res[1]-2;
-
- // get grid values
- float center = input[index];
- float down = (y <= 1) ? FLT_MAX : input[index - res[0]];
- float up = (y >= maxy) ? FLT_MAX : input[index + res[0]];
-
- const float dx = res[1]; // only for square domains
-
- // get all the derivative estimates
- float dDown = (y <= 1) ? FLT_MAX : (center - down) * dx;
- float dUp = (y >= maxy) ? FLT_MAX : (up - center) * dx;
- float dCenter = (y <= 1 || y >= maxy) ? FLT_MAX : (up - down) * dx * 0.5f;
-
- // if it's on a boundary, only one estimate is valid
- if (y <= 1) return dUp;
- if (y >= maxy) return dDown;
-
- // if it's not on a boundary, get the smallest one
- float finalD = (fabs(dCenter) < fabs(dUp)) ? dCenter : dUp;
- finalD = (fabs(finalD) < fabs(dDown)) ? finalD : dDown;
-
- return finalD;
-}
-
-//////////////////////////////////////////////////////////////////////
-// get the smallest valid z derivative
-//
-// Takes the one-sided finite difference in both directions and
-// selects the smaller of the two
-//////////////////////////////////////////////////////////////////////
-static float minDz(int x, int y, int z, float* input, const Vec3Int& res)
-{
- const int slab = res[0]*res[1];
- const int index = x + y * res[0] + z * slab;
- const int maxz = res[2]-2;
-
- // get grid values
- float center = input[index];
- float front = (z <= 1) ? FLT_MAX : input[index - slab];
- float back = (z >= maxz) ? FLT_MAX : input[index + slab];
-
- const float dx = res[2]; // only for square domains
-
- // get all the derivative estimates
- float dfront = (z <= 1) ? FLT_MAX : (center - front) * dx;
- float dback = (z >= maxz) ? FLT_MAX : (back - center) * dx;
- float dCenter = (z <= 1 || z >= maxz) ? FLT_MAX : (back - front) * dx * 0.5f;
-
- // if it's on a boundary, only one estimate is valid
- if (z <= 1) return dback;
- if (z >= maxz) return dfront;
-
- // if it's not on a boundary, get the smallest one
- float finalD = (fabs(dCenter) < fabs(dback)) ? dCenter : dback;
- finalD = (fabs(finalD) < fabs(dfront)) ? finalD : dfront;
-
- return finalD;
-}
-
-//////////////////////////////////////////////////////////////////////
-// handle texture coordinates (advection, reset, eigenvalues),
-// Beware -- uses big density maccormack as temporary arrays
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::advectTextureCoordinates (float dtOrg, float* xvel, float* yvel, float* zvel, float *tempBig1, float *tempBig2) {
-
- // advection
- SWAP_POINTERS(_tcTemp, _tcU);
- FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel,
- _tcTemp, tempBig1, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel,
- _tcTemp, _tcU, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]);
-
- SWAP_POINTERS(_tcTemp, _tcV);
- FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel,
- _tcTemp, tempBig1, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel,
- _tcTemp, _tcV, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]);
-
- SWAP_POINTERS(_tcTemp, _tcW);
- FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel,
- _tcTemp, tempBig1, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel,
- _tcTemp, _tcW, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]);
-}
-
-//////////////////////////////////////////////////////////////////////
-// Compute the eigenvalues of the advected texture
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::computeEigenvalues(float *_eigMin, float *_eigMax) {
- // stats
- float maxeig = -1.;
- float mineig = 10.;
-
- // texture coordinate eigenvalues
- for (int z = 1; z < _zResSm-1; z++) {
- for (int y = 1; y < _yResSm-1; y++)
- for (int x = 1; x < _xResSm-1; x++)
- {
- const int index = x+ y *_resSm[0] + z*_slabSizeSm;
-
- // compute jacobian
- float jacobian[3][3] = {
- { minDx(x, y, z, _tcU, _resSm), minDx(x, y, z, _tcV, _resSm), minDx(x, y, z, _tcW, _resSm) } ,
- { minDy(x, y, z, _tcU, _resSm), minDy(x, y, z, _tcV, _resSm), minDy(x, y, z, _tcW, _resSm) } ,
- { minDz(x, y, z, _tcU, _resSm), minDz(x, y, z, _tcV, _resSm), minDz(x, y, z, _tcW, _resSm) }
- };
-
- // ONLY compute the eigenvalues after checking that the matrix
- // is nonsingular
- sLU LU = computeLU(jacobian);
-
- if (isNonsingular(LU))
- {
- // get the analytic eigenvalues, quite slow right now...
- Vec3 eigenvalues = Vec3(1.);
- computeEigenvalues3x3( &eigenvalues[0], jacobian);
- _eigMax[index] = MAX3V(eigenvalues);
- _eigMin[index] = MIN3V(eigenvalues);
- maxeig = MAX(_eigMax[index],maxeig);
- mineig = MIN(_eigMin[index],mineig);
- }
- else
- {
- _eigMax[index] = 10.0f;
- _eigMin[index] = 0.1;
- }
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// advect & reset texture coordinates based on eigenvalues
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::resetTextureCoordinates(float *_eigMin, float *_eigMax)
-{
- // allowed deformation of the textures
- const float limit = 2.f;
- const float limitInv = 1.0f/limit;
-
- // standard reset
- int resets = 0;
- const float dx = 1.0f/(float)(_resSm[0]);
- const float dy = 1.0f/(float)(_resSm[1]);
- const float dz = 1.0f/(float)(_resSm[2]);
-
- for (int z = 1; z < _zResSm-1; z++)
- for (int y = 1; y < _yResSm-1; y++)
- for (int x = 1; x < _xResSm-1; x++)
- {
- const int index = x+ y *_resSm[0] + z*_slabSizeSm;
- if (_eigMax[index] > limit || _eigMin[index] < limitInv)
- {
- _tcU[index] = (float)x * dx;
- _tcV[index] = (float)y * dy;
- _tcW[index] = (float)z * dz;
- resets++;
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// Compute the highest frequency component of the wavelet
-// decomposition
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::decomposeEnergy(float *_energy, float *_highFreqEnergy)
-{
- // do the decomposition -- the goal here is to have
- // the energy with the high frequency component stomped out
- // stored in _tcTemp when it is done. _highFreqEnergy is only used
- // as an additional temp array
-
- // downsample input
- downsampleXNeumann(_highFreqEnergy, _energy, _xResSm, _yResSm, _zResSm);
- downsampleYNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm);
- downsampleZNeumann(_highFreqEnergy, _tcTemp, _xResSm, _yResSm, _zResSm);
-
- // upsample input
- upsampleZNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm);
- upsampleYNeumann(_highFreqEnergy, _tcTemp, _xResSm, _yResSm, _zResSm);
- upsampleXNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm);
-
- // subtract the down and upsampled field from the original field --
- // what should be left over is solely the high frequency component
- int index = 0;
- for (int z = 0; z < _zResSm; z++)
- for (int y = 0; y < _yResSm; y++) {
- for (int x = 0; x < _xResSm; x++, index++) {
- // brute force reset of boundaries
- if(z >= _zResSm - 1 || x >= _xResSm - 1 || y >= _yResSm - 1 || z <= 0 || y <= 0 || x <= 0)
- _highFreqEnergy[index] = 0.;
- else
- _highFreqEnergy[index] = _energy[index] - _tcTemp[index];
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// compute velocity from energies and march into obstacles
-// for wavelet decomposition
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::computeEnergy(float *_energy, float* xvel, float* yvel, float* zvel, unsigned char *origObstacles)
-{
- unsigned char *obstacles = new unsigned char[_totalCellsSm];
- memcpy(obstacles, origObstacles, sizeof(unsigned char) * _totalCellsSm);
-
- // compute everywhere
- for (int x = 0; x < _totalCellsSm; x++)
- _energy[x] = 0.5f * (xvel[x] * xvel[x] + yvel[x] * yvel[x] + zvel[x] * zvel[x]);
-
- FLUID_3D::copyBorderX(_energy, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderY(_energy, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderZ(_energy, _resSm, 0 , _resSm[2]);
-
- // pseudo-march the values into the obstacles
- // the wavelet upsampler only uses a 3x3 support neighborhood, so
- // propagating the values in by 4 should be sufficient
- int index;
-
- // iterate
- for (int iter = 0; iter < 4; iter++)
- {
- index = _slabSizeSm + _xResSm + 1;
- for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm)
- for (int y = 1; y < _yResSm - 1; y++, index += 2)
- for (int x = 1; x < _xResSm - 1; x++, index++)
- if (obstacles[index] && obstacles[index] != RETIRED)
- {
- float sum = 0.0f;
- int valid = 0;
-
- if (!obstacles[index + 1] || obstacles[index + 1] == RETIRED)
- {
- sum += _energy[index + 1];
- valid++;
- }
- if (!obstacles[index - 1] || obstacles[index - 1] == RETIRED)
- {
- sum += _energy[index - 1];
- valid++;
- }
- if (!obstacles[index + _xResSm] || obstacles[index + _xResSm] == RETIRED)
- {
- sum += _energy[index + _xResSm];
- valid++;
- }
- if (!obstacles[index - _xResSm] || obstacles[index - _xResSm] == RETIRED)
- {
- sum += _energy[index - _xResSm];
- valid++;
- }
- if (!obstacles[index + _slabSizeSm] || obstacles[index + _slabSizeSm] == RETIRED)
- {
- sum += _energy[index + _slabSizeSm];
- valid++;
- }
- if (!obstacles[index - _slabSizeSm] || obstacles[index - _slabSizeSm] == RETIRED)
- {
- sum += _energy[index - _slabSizeSm];
- valid++;
- }
- if (valid > 0)
- {
- _energy[index] = sum / (float)valid;
- obstacles[index] = MARCHED;
- }
- }
- index = _slabSizeSm + _xResSm + 1;
- for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm)
- for (int y = 1; y < _yResSm - 1; y++, index += 2)
- for (int x = 1; x < _xResSm - 1; x++, index++)
- if (obstacles[index] == MARCHED)
- obstacles[index] = RETIRED;
- }
- index = _slabSizeSm + _xResSm + 1;
- for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm)
- for (int y = 1; y < _yResSm - 1; y++, index += 2)
- for (int x = 1; x < _xResSm - 1; x++, index++)
- if (obstacles[index])
- obstacles[index] = 1; // DG TODO ? animated obstacle flag?
-
- delete [] obstacles;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Evaluate derivatives
-//////////////////////////////////////////////////////////////////////////////////////////
-Vec3 WTURBULENCE::WVelocity(Vec3 orgPos)
-{
- // arbitrarily offset evaluation points
- const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2.0,0,0);
- const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2.0,0);
- const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2.0);
-
- const float f1y = WNoiseDy(p1, _noiseTile);
- const float f1z = WNoiseDz(p1, _noiseTile);
-
- const float f2x = WNoiseDx(p2, _noiseTile);
- const float f2z = WNoiseDz(p2, _noiseTile);
-
- const float f3x = WNoiseDx(p3, _noiseTile);
- const float f3y = WNoiseDy(p3, _noiseTile);
-
- Vec3 ret = Vec3(
- f3y - f2z,
- f1z - f3x,
- f2x - f1y );
- return ret;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Evaluate derivatives with Jacobian
-//////////////////////////////////////////////////////////////////////////////////////////
-Vec3 WTURBULENCE::WVelocityWithJacobian(const Vec3& orgPos, float* xUnwarped, float* yUnwarped, float* zUnwarped)
-{
- // arbitrarily offset evaluation points
- const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2.0,0,0);
- const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2.0,0);
- const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2.0);
-
- Vec3 final;
- final[0] = WNoiseDx(p1, _noiseTile);
- final[1] = WNoiseDy(p1, _noiseTile);
- final[2] = WNoiseDz(p1, _noiseTile);
- // UNUSED const float f1x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2];
- const float f1y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2];
- const float f1z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2];
-
- final[0] = WNoiseDx(p2, _noiseTile);
- final[1] = WNoiseDy(p2, _noiseTile);
- final[2] = WNoiseDz(p2, _noiseTile);
- const float f2x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2];
- // UNUSED const float f2y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2];
- const float f2z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2];
-
- final[0] = WNoiseDx(p3, _noiseTile);
- final[1] = WNoiseDy(p3, _noiseTile);
- final[2] = WNoiseDz(p3, _noiseTile);
- const float f3x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2];
- const float f3y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2];
- // UNUSED const float f3z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2];
-
- Vec3 ret = Vec3(
- f3y - f2z,
- f1z - f3x,
- f2x - f1y );
- return ret;
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// perform an actual noise advection step
-//////////////////////////////////////////////////////////////////////
-/*void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles)
-{
- // enlarge timestep to match grid
- const float dt = dtOrg * _amplify;
- const float invAmp = 1.0f / _amplify;
- float *tempBig1 = new float[_totalCellsBig];
- float *tempBig2 = new float[_totalCellsBig];
- float *bigUx = new float[_totalCellsBig];
- float *bigUy = new float[_totalCellsBig];
- float *bigUz = new float[_totalCellsBig];
- float *_energy = new float[_totalCellsSm];
- float *highFreqEnergy = new float[_totalCellsSm];
- float *eigMin = new float[_totalCellsSm];
- float *eigMax = new float[_totalCellsSm];
-
- memset(tempBig1, 0, sizeof(float)*_totalCellsBig);
- memset(tempBig2, 0, sizeof(float)*_totalCellsBig);
- memset(highFreqEnergy, 0, sizeof(float)*_totalCellsSm);
- memset(eigMin, 0, sizeof(float)*_totalCellsSm);
- memset(eigMax, 0, sizeof(float)*_totalCellsSm);
-
- // prepare textures
- advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempBig1, tempBig2);
-
- // compute eigenvalues of the texture coordinates
- computeEigenvalues(eigMin, eigMax);
-
- // do wavelet decomposition of energy
- computeEnergy(_energy, xvel, yvel, zvel, obstacles);
- decomposeEnergy(_energy, highFreqEnergy);
-
- // zero out coefficients inside of the obstacle
- for (int x = 0; x < _totalCellsSm; x++)
- if (obstacles[x]) _energy[x] = 0.f;
-
- float maxVelocity = 0.;
- for (int z = 1; z < _zResBig - 1; z++)
- for (int y = 1; y < _yResBig - 1; y++)
- for (int x = 1; x < _xResBig - 1; x++)
- {
- // get unit position for both fine and coarse grid
- const Vec3 pos = Vec3(x,y,z);
- const Vec3 posSm = pos * invAmp;
-
- // get grid index for both fine and coarse grid
- const int index = x + y *_xResBig + z *_slabSizeBig;
- const int indexSmall = (int)posSm[0] + (int)posSm[1] * _xResSm + (int)posSm[2] * _slabSizeSm;
-
- // get a linearly interpolated velocity and texcoords
- // from the coarse grid
- Vec3 vel = INTERPOLATE::lerp3dVec( xvel,yvel,zvel,
- posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
- Vec3 uvw = INTERPOLATE::lerp3dVec( _tcU,_tcV,_tcW,
- posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
-
- // multiply the texture coordinate by _resSm so that turbulence
- // synthesis begins at the first octave that the coarse grid
- // cannot capture
- Vec3 texCoord = Vec3(uvw[0] * _resSm[0],
- uvw[1] * _resSm[1],
- uvw[2] * _resSm[2]);
-
- // retrieve wavelet energy at highest frequency
- float energy = INTERPOLATE::lerp3d(
- highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm);
-
- // base amplitude for octave 0
- float coefficient = sqrtf(2.0f * fabs(energy));
- const float amplitude = *_strength * fabs(0.5 * coefficient) * persistence;
-
- // add noise to velocity, but only if the turbulence is
- // sufficiently undeformed, and the energy is large enough
- // to make a difference
- const bool addNoise = eigMax[indexSmall] < 2. &&
- eigMin[indexSmall] > 0.5;
- if (addNoise && amplitude > _cullingThreshold) {
- // base amplitude for octave 0
- float amplitudeScaled = amplitude;
-
- for (int octave = 0; octave < _octaves; octave++)
- {
- // multiply the vector noise times the maximum allowed
- // noise amplitude at this octave, and add it to the total
- vel += WVelocity(texCoord) * amplitudeScaled;
-
- // scale coefficient for next octave
- amplitudeScaled *= persistence;
- texCoord *= 2.0f;
- }
- }
-
- // Store velocity + turbulence in big grid for maccormack step
- //
- // If you wanted to save memory, you would instead perform a
- // semi-Lagrangian backtrace for the current grid cell here. Then
- // you could just throw the velocity away.
- bigUx[index] = vel[0];
- bigUy[index] = vel[1];
- bigUz[index] = vel[2];
-
- // compute the velocity magnitude for substepping later
- const float velMag = bigUx[index] * bigUx[index] +
- bigUy[index] * bigUy[index] +
- bigUz[index] * bigUz[index];
- if (velMag > maxVelocity) maxVelocity = velMag;
-
- // zero out velocity inside obstacles
- float obsCheck = INTERPOLATE::lerp3dToFloat(
- obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm);
- if (obsCheck > 0.95)
- bigUx[index] = bigUy[index] = bigUz[index] = 0.;
- }
-
- // prepare density for an advection
- SWAP_POINTERS(_densityBig, _densityBigOld);
-
- // based on the maximum velocity present, see if we need to substep,
- // but cap the maximum number of substeps to 5
- const int maxSubSteps = 5;
- maxVelocity = sqrt(maxVelocity) * dt;
- int totalSubsteps = (int)(maxVelocity / (float)maxSubSteps);
- totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
- totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
- const float dtSubdiv = dt / (float)totalSubsteps;
-
- // set boundaries of big velocity grid
- FLUID_3D::setZeroX(bigUx, _resBig, 0, _resBig[2]);
- FLUID_3D::setZeroY(bigUy, _resBig, 0, _resBig[2]);
- FLUID_3D::setZeroZ(bigUz, _resBig, 0, _resBig[2]);
-
- // do the MacCormack advection, with substepping if necessary
- for(int substep = 0; substep < totalSubsteps; substep++)
- {
- FLUID_3D::advectFieldMacCormack(dtSubdiv, bigUx, bigUy, bigUz,
- _densityBigOld, _densityBig, tempBig1, tempBig2, _resBig, NULL);
-
- if (substep < totalSubsteps - 1)
- SWAP_POINTERS(_densityBig, _densityBigOld);
- } // substep
-
- // wipe the density borders
- FLUID_3D::setZeroBorder(_densityBig, _resBig, 0, _resBig[2]);
-
- // reset texture coordinates now in preparation for next timestep
- // Shouldn't do this before generating the noise because then the
- // eigenvalues stored do not reflect the underlying texture coordinates
- resetTextureCoordinates(eigMin, eigMax);
-
- delete[] tempBig1;
- delete[] tempBig2;
- delete[] bigUx;
- delete[] bigUy;
- delete[] bigUz;
- delete[] _energy;
- delete[] highFreqEnergy;
-
- delete[] eigMin;
- delete[] eigMax;
-
-
- _totalStepsBig++;
-}*/
-
-//struct
-
-//////////////////////////////////////////////////////////////////////
-// perform the full turbulence algorithm, including OpenMP
-// if available
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles)
-{
- // enlarge timestep to match grid
- const float dt = dtOrg * _amplify;
- const float invAmp = 1.0f / _amplify;
- float *tempFuelBig = NULL, *tempReactBig = NULL;
- float *tempColor_rBig = NULL, *tempColor_gBig = NULL, *tempColor_bBig = NULL;
- float *tempDensityBig = (float *)calloc(_totalCellsBig, sizeof(float));
- float *tempBig = (float *)calloc(_totalCellsBig, sizeof(float));
- float *bigUx = (float *)calloc(_totalCellsBig, sizeof(float));
- float *bigUy = (float *)calloc(_totalCellsBig, sizeof(float));
- float *bigUz = (float *)calloc(_totalCellsBig, sizeof(float));
- float *_energy = (float *)calloc(_totalCellsSm, sizeof(float));
- float *highFreqEnergy = (float *)calloc(_totalCellsSm, sizeof(float));
- float *eigMin = (float *)calloc(_totalCellsSm, sizeof(float));
- float *eigMax = (float *)calloc(_totalCellsSm, sizeof(float));
-
- if (_fuelBig) {
- tempFuelBig = (float *)calloc(_totalCellsBig, sizeof(float));
- tempReactBig = (float *)calloc(_totalCellsBig, sizeof(float));
- }
- if (_color_rBig) {
- tempColor_rBig = (float *)calloc(_totalCellsBig, sizeof(float));
- tempColor_gBig = (float *)calloc(_totalCellsBig, sizeof(float));
- tempColor_bBig = (float *)calloc(_totalCellsBig, sizeof(float));
- }
-
- memset(_tcTemp, 0, sizeof(float)*_totalCellsSm);
-
-
- // prepare textures
- advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempDensityBig, tempBig);
-
- // do wavelet decomposition of energy
- computeEnergy(_energy, xvel, yvel, zvel, obstacles);
-
- for (int x = 0; x < _totalCellsSm; x++)
- if (obstacles[x]) _energy[x] = 0.f;
-
- decomposeEnergy(_energy, highFreqEnergy);
-
- // zero out coefficients inside of the obstacle
- for (int x = 0; x < _totalCellsSm; x++)
- if (obstacles[x]) highFreqEnergy[x] = 0.f;
-
- Vec3Int ressm(_xResSm, _yResSm, _zResSm);
- FLUID_3D::setNeumannX(highFreqEnergy, ressm, 0 , ressm[2]);
- FLUID_3D::setNeumannY(highFreqEnergy, ressm, 0 , ressm[2]);
- FLUID_3D::setNeumannZ(highFreqEnergy, ressm, 0 , ressm[2]);
-
-
- int threadval = 1;
-#if PARALLEL==1
- threadval = omp_get_max_threads();
-#endif
-
-
- // parallel region setup
- // Uses omp_get_max_trheads to get number of required cells.
- float* maxVelMagThreads = new float[threadval];
-
- for (int i=0; i<threadval; i++) maxVelMagThreads[i] = -1.0f;
-
-#if PARALLEL==1
-
-#pragma omp parallel
-#endif
- { float maxVelMag1 = 0.;
-#if PARALLEL==1
- const int id = omp_get_thread_num(); /*, num = omp_get_num_threads(); */
-#endif
-
- // vector noise main loop
-#if PARALLEL==1
-#pragma omp for schedule(static,1)
-#endif
- for (int zSmall = 0; zSmall < _zResSm; zSmall++)
- {
- for (int ySmall = 0; ySmall < _yResSm; ySmall++)
- for (int xSmall = 0; xSmall < _xResSm; xSmall++)
- {
- const int indexSmall = xSmall + ySmall * _xResSm + zSmall * _slabSizeSm;
-
- // compute jacobian
- float jacobian[3][3] = {
- { minDx(xSmall, ySmall, zSmall, _tcU, _resSm), minDx(xSmall, ySmall, zSmall, _tcV, _resSm), minDx(xSmall, ySmall, zSmall, _tcW, _resSm) } ,
- { minDy(xSmall, ySmall, zSmall, _tcU, _resSm), minDy(xSmall, ySmall, zSmall, _tcV, _resSm), minDy(xSmall, ySmall, zSmall, _tcW, _resSm) } ,
- { minDz(xSmall, ySmall, zSmall, _tcU, _resSm), minDz(xSmall, ySmall, zSmall, _tcV, _resSm), minDz(xSmall, ySmall, zSmall, _tcW, _resSm) }
- };
-
- // get LU factorization of texture jacobian and apply
- // it to unit vectors
- sLU LU = computeLU(jacobian);
- float xUnwarped[3], yUnwarped[3], zUnwarped[3];
- float xWarped[3], yWarped[3], zWarped[3];
- bool nonSingular = isNonsingular(LU);
-
- xUnwarped[0] = 1.0f; xUnwarped[1] = 0.0f; xUnwarped[2] = 0.0f;
- yUnwarped[0] = 0.0f; yUnwarped[1] = 1.0f; yUnwarped[2] = 0.0f;
- zUnwarped[0] = 0.0f; zUnwarped[1] = 0.0f; zUnwarped[2] = 1.0f;
-
- xWarped[0] = 1.0f; xWarped[1] = 0.0f; xWarped[2] = 0.0f;
- yWarped[0] = 0.0f; yWarped[1] = 1.0f; yWarped[2] = 0.0f;
- zWarped[0] = 0.0f; zWarped[1] = 0.0f; zWarped[2] = 1.0f;
-
-#if 0
- // UNUSED
- float eigMax = 10.0f;
- float eigMin = 0.1f;
-#endif
- if (nonSingular)
- {
- solveLU3x3(LU, xUnwarped, xWarped);
- solveLU3x3(LU, yUnwarped, yWarped);
- solveLU3x3(LU, zUnwarped, zWarped);
-
- // compute the eigenvalues while we have the Jacobian available
- Vec3 eigenvalues = Vec3(1.);
- computeEigenvalues3x3( &eigenvalues[0], jacobian);
- eigMax[indexSmall] = MAX3V(eigenvalues);
- eigMin[indexSmall] = MIN3V(eigenvalues);
- }
-
- // make sure to skip one on the beginning and end
- int xStart = (xSmall == 0) ? 1 : 0;
- int xEnd = (xSmall == _xResSm - 1) ? _amplify - 1 : _amplify;
- int yStart = (ySmall == 0) ? 1 : 0;
- int yEnd = (ySmall == _yResSm - 1) ? _amplify - 1 : _amplify;
- int zStart = (zSmall == 0) ? 1 : 0;
- int zEnd = (zSmall == _zResSm - 1) ? _amplify - 1 : _amplify;
-
- for (int zBig = zStart; zBig < zEnd; zBig++)
- for (int yBig = yStart; yBig < yEnd; yBig++)
- for (int xBig = xStart; xBig < xEnd; xBig++)
- {
- const int x = xSmall * _amplify + xBig;
- const int y = ySmall * _amplify + yBig;
- const int z = zSmall * _amplify + zBig;
-
- // get unit position for both fine and coarse grid
- const Vec3 pos = Vec3(x,y,z);
- const Vec3 posSm = pos * invAmp;
-
- // get grid index for both fine and coarse grid
- const int index = x + y *_xResBig + z *_slabSizeBig;
-
- // get a linearly interpolated velocity and texcoords
- // from the coarse grid
- Vec3 vel = INTERPOLATE::lerp3dVec( xvel,yvel,zvel,
- posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
- Vec3 uvw = INTERPOLATE::lerp3dVec( _tcU,_tcV,_tcW,
- posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
-
- // multiply the texture coordinate by _resSm so that turbulence
- // synthesis begins at the first octave that the coarse grid
- // cannot capture
- Vec3 texCoord = Vec3(uvw[0] * _resSm[0],
- uvw[1] * _resSm[1],
- uvw[2] * _resSm[2]);
-
- // retrieve wavelet energy at highest frequency
- float energy = INTERPOLATE::lerp3d(
- highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm);
-
- // base amplitude for octave 0
- float coefficient = sqrtf(2.0f * fabs(energy));
- const float amplitude = *_strength * fabs(0.5f * coefficient) * persistence;
-
- // add noise to velocity, but only if the turbulence is
- // sufficiently undeformed, and the energy is large enough
- // to make a difference
- const bool addNoise = eigMax[indexSmall] < 2.0f &&
- eigMin[indexSmall] > 0.5f;
- if (addNoise && amplitude > _cullingThreshold) {
- // base amplitude for octave 0
- float amplitudeScaled = amplitude;
-
- for (int octave = 0; octave < _octaves; octave++)
- {
- // multiply the vector noise times the maximum allowed
- // noise amplitude at this octave, and add it to the total
- vel += WVelocityWithJacobian(texCoord, &xUnwarped[0], &yUnwarped[0], &zUnwarped[0]) * amplitudeScaled;
-
- // scale coefficient for next octave
- amplitudeScaled *= persistence;
- texCoord *= 2.0f;
- }
- }
-
- // Store velocity + turbulence in big grid for maccormack step
- //
- // If you wanted to save memory, you would instead perform a
- // semi-Lagrangian backtrace for the current grid cell here. Then
- // you could just throw the velocity away.
- bigUx[index] = vel[0];
- bigUy[index] = vel[1];
- bigUz[index] = vel[2];
-
- // compute the velocity magnitude for substepping later
- const float velMag = bigUx[index] * bigUx[index] +
- bigUy[index] * bigUy[index] +
- bigUz[index] * bigUz[index];
- if (velMag > maxVelMag1) maxVelMag1 = velMag;
-
- // zero out velocity inside obstacles
- float obsCheck = INTERPOLATE::lerp3dToFloat(
- obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm);
- if (obsCheck > 0.95f)
- bigUx[index] = bigUy[index] = bigUz[index] = 0.;
- } // xyz*/
-
-#if PARALLEL==1
- maxVelMagThreads[id] = maxVelMag1;
-#else
- maxVelMagThreads[0] = maxVelMag1;
-#endif
- }
- }
- } // omp
-
- // compute maximum over threads
- float maxVelMag = maxVelMagThreads[0];
-#if PARALLEL==1
- for (int i = 1; i < threadval; i++)
- if (maxVelMag < maxVelMagThreads[i])
- maxVelMag = maxVelMagThreads[i];
-#endif
- delete [] maxVelMagThreads;
-
-
- // prepare density for an advection
- SWAP_POINTERS(_densityBig, _densityBigOld);
- SWAP_POINTERS(_fuelBig, _fuelBigOld);
- SWAP_POINTERS(_reactBig, _reactBigOld);
- SWAP_POINTERS(_color_rBig, _color_rBigOld);
- SWAP_POINTERS(_color_gBig, _color_gBigOld);
- SWAP_POINTERS(_color_bBig, _color_bBigOld);
-
- // based on the maximum velocity present, see if we need to substep,
- // but cap the maximum number of substeps to 5
- const int maxSubSteps = 25;
- const int maxVel = 5;
- maxVelMag = sqrt(maxVelMag) * dt;
- int totalSubsteps = (int)(maxVelMag / (float)maxVel);
- totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
- // printf("totalSubsteps: %d\n", totalSubsteps);
- totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
- const float dtSubdiv = dt / (float)totalSubsteps;
-
- // set boundaries of big velocity grid
- FLUID_3D::setZeroX(bigUx, _resBig, 0 , _resBig[2]);
- FLUID_3D::setZeroY(bigUy, _resBig, 0 , _resBig[2]);
- FLUID_3D::setZeroZ(bigUz, _resBig, 0 , _resBig[2]);
-
-#if PARALLEL==1
- int stepParts = threadval*2; // Dividing parallelized sections into numOfThreads * 2 sections
- float partSize = (float)_zResBig/stepParts; // Size of one part;
-
- if (partSize < 4) {stepParts = threadval; // If the slice gets too low (might actually slow things down, change it to larger
- partSize = (float)_zResBig/stepParts;}
- if (partSize < 4) {stepParts = (int)(ceil((float)_zResBig/4.0f)); // If it's still too low (only possible on future systems with +24 cores), change it to 4
- partSize = (float)_zResBig/stepParts;}
-#else
- int zBegin=0;
- int zEnd=_resBig[2];
-#endif
-
- // do the MacCormack advection, with substepping if necessary
- for(int substep = 0; substep < totalSubsteps; substep++)
- {
-
-#if PARALLEL==1
- #pragma omp parallel
- {
-
- #pragma omp for schedule(static,1)
- for (int i=0; i<stepParts; i++)
- {
- int zBegin = (int)((float)i*partSize + 0.5f);
- int zEnd = (int)((float)(i+1)*partSize + 0.5f);
-#endif
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _densityBigOld, tempDensityBig, _resBig, zBegin, zEnd);
- if (_fuelBig) {
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _fuelBigOld, tempFuelBig, _resBig, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _reactBigOld, tempReactBig, _resBig, zBegin, zEnd);
- }
- if (_color_rBig) {
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _color_rBigOld, tempColor_rBig, _resBig, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _color_gBigOld, tempColor_gBig, _resBig, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _color_bBigOld, tempColor_bBig, _resBig, zBegin, zEnd);
- }
-#if PARALLEL==1
- }
-
- #pragma omp barrier
-
- #pragma omp for schedule(static,1)
- for (int i=0; i<stepParts; i++)
- {
- int zBegin = (int)((float)i*partSize + 0.5f);
- int zEnd = (int)((float)(i+1)*partSize + 0.5f);
-#endif
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _densityBigOld, _densityBig, tempDensityBig, tempBig, _resBig, NULL, zBegin, zEnd);
- if (_fuelBig) {
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _fuelBigOld, _fuelBig, tempFuelBig, tempBig, _resBig, NULL, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _reactBigOld, _reactBig, tempReactBig, tempBig, _resBig, NULL, zBegin, zEnd);
- }
- if (_color_rBig) {
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _color_rBigOld, _color_rBig, tempColor_rBig, tempBig, _resBig, NULL, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _color_gBigOld, _color_gBig, tempColor_gBig, tempBig, _resBig, NULL, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _color_bBigOld, _color_bBig, tempColor_bBig, tempBig, _resBig, NULL, zBegin, zEnd);
- }
-#if PARALLEL==1
- }
- }
-#endif
-
- if (substep < totalSubsteps - 1) {
- SWAP_POINTERS(_densityBig, _densityBigOld);
- SWAP_POINTERS(_fuelBig, _fuelBigOld);
- SWAP_POINTERS(_reactBig, _reactBigOld);
- SWAP_POINTERS(_color_rBig, _color_rBigOld);
- SWAP_POINTERS(_color_gBig, _color_gBigOld);
- SWAP_POINTERS(_color_bBig, _color_bBigOld);
- }
- } // substep
-
- free(tempDensityBig);
- if (tempFuelBig) free(tempFuelBig);
- if (tempReactBig) free(tempReactBig);
- if (tempColor_rBig) free(tempColor_rBig);
- if (tempColor_gBig) free(tempColor_gBig);
- if (tempColor_bBig) free(tempColor_bBig);
- free(tempBig);
- free(bigUx);
- free(bigUy);
- free(bigUz);
- free(_energy);
- free(highFreqEnergy);
-
- // wipe the density borders
- FLUID_3D::setZeroBorder(_densityBig, _resBig, 0 , _resBig[2]);
- if (_fuelBig) {
- FLUID_3D::setZeroBorder(_fuelBig, _resBig, 0 , _resBig[2]);
- FLUID_3D::setZeroBorder(_reactBig, _resBig, 0 , _resBig[2]);
- }
- if (_color_rBig) {
- FLUID_3D::setZeroBorder(_color_rBig, _resBig, 0 , _resBig[2]);
- FLUID_3D::setZeroBorder(_color_gBig, _resBig, 0 , _resBig[2]);
- FLUID_3D::setZeroBorder(_color_bBig, _resBig, 0 , _resBig[2]);
- }
-
- // reset texture coordinates now in preparation for next timestep
- // Shouldn't do this before generating the noise because then the
- // eigenvalues stored do not reflect the underlying texture coordinates
- resetTextureCoordinates(eigMin, eigMax);
-
- free(eigMin);
- free(eigMax);
-
- // output files
- // string prefix = string("./amplified.preview/density_bigxy_");
- // FLUID_3D::writeImageSliceXY(_densityBig, _resBig, _resBig[2]/2, prefix, _totalStepsBig, 1.0f);
- //string df3prefix = string("./df3/density_big_");
- //IMAGE::dumpDF3(_totalStepsBig, df3prefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]);
- // string pbrtPrefix = string("./pbrt/density_big_");
- // IMAGE::dumpPBRT(_totalStepsBig, pbrtPrefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]);
-
- _totalStepsBig++;
-}
diff --git a/intern/smoke/intern/WTURBULENCE.h b/intern/smoke/intern/WTURBULENCE.h
deleted file mode 100644
index 7ad04cfd36e..00000000000
--- a/intern/smoke/intern/WTURBULENCE.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// WTURBULENCE handling
-///////////////////////////////////////////////////////////////////////////////////
-
-#ifndef WTURBULENCE_H
-#define WTURBULENCE_H
-
-#include "VEC3.h"
-using namespace BasicVector;
-class SIMPLE_PARSER;
-
-///////////////////////////////////////////////////////////////////////////////
-/// Main WTURBULENCE class, stores large density array etc.
-///////////////////////////////////////////////////////////////////////////////
-struct WTURBULENCE
-{
- public:
- // both config files can be NULL, altCfg might override values from noiseCfg
- WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors);
-
- /// destructor
- virtual ~WTURBULENCE();
-
- void initFire();
- void initColors(float init_r, float init_g, float init_b);
-
- void setNoise(int type, const char *noisefile_path);
- void initBlenderRNA(float *strength);
-
- // step more readable version -- no rotation correction
- void stepTurbulenceReadable(float dt, float* xvel, float* yvel, float* zvel, unsigned char *obstacles);
-
- // step more complete version -- include rotation correction
- // and use OpenMP if available
- void stepTurbulenceFull(float dt, float* xvel, float* yvel, float* zvel, unsigned char *obstacles);
-
- // texcoord functions
- void advectTextureCoordinates(float dtOrg, float* xvel, float* yvel, float* zvel, float *tempBig1, float *tempBig2);
- void resetTextureCoordinates(float *_eigMin, float *_eigMax);
-
- void computeEnergy(float *energy, float* xvel, float* yvel, float* zvel, unsigned char *obstacles);
-
- // evaluate wavelet noise function
- Vec3 WVelocity(Vec3 p);
- Vec3 WVelocityWithJacobian(const Vec3& p, float* xUnwarped, float* yUnwarped, float* zUnwarped);
-
- // access functions
- inline float* getDensityBig() { return _densityBig; }
- inline float* getFlameBig() { return _flameBig; }
- inline float* getFuelBig() { return _fuelBig; }
- inline float* getArrayTcU() { return _tcU; }
- inline float* getArrayTcV() { return _tcV; }
- inline float* getArrayTcW() { return _tcW; }
-
- inline Vec3Int getResSm() { return _resSm; } // small resolution
- inline Vec3Int getResBig() { return _resBig; }
- inline int getOctaves() { return _octaves; }
-
- // is accessed on through rna gui
- float *_strength;
-
- // protected:
- // enlargement factor from original velocity field / simulation
- // _Big = _amplify * _Sm
- int _amplify;
- int _octaves;
-
- // noise settings
- float _cullingThreshold;
- // float _noiseStrength;
- // float _noiseSizeScale;
- // bool _uvwAdvection;
- // bool _uvwReset;
- // float _noiseTimeanimSpeed;
- // int _dumpInterval;
- // nt _noiseControlType;
- // debug, scale density for projections output images
- // float _outputScale;
-
- // noise resolution
- int _xResBig;
- int _yResBig;
- int _zResBig;
- Vec3Int _resBig;
- Vec3 _invResBig;
- int _totalCellsBig;
- int _slabSizeBig;
- // original / small resolution
- int _xResSm;
- int _yResSm;
- int _zResSm;
- Vec3Int _resSm;
- Vec3 _invResSm;
- int _totalCellsSm;
- int _slabSizeSm;
-
- float* _densityBig;
- float* _densityBigOld;
- float* _flameBig;
- float* _fuelBig;
- float* _fuelBigOld;
- float* _reactBig;
- float* _reactBigOld;
-
- float* _color_rBig;
- float* _color_rBigOld;
- float* _color_gBig;
- float* _color_gBigOld;
- float* _color_bBig;
- float* _color_bBigOld;
-
- // texture coordinates for noise
- float* _tcU;
- float* _tcV;
- float* _tcW;
- float* _tcTemp;
-
- // noise data
- float* _noiseTile;
- //float* _noiseTileExt;
-
- // step counter
- int _totalStepsBig;
-
- void computeEigenvalues(float *_eigMin, float *_eigMax);
- void decomposeEnergy(float *energy, float *_highFreqEnergy);
-};
-
-#endif // WTURBULENCE_H
-
diff --git a/intern/smoke/intern/smoke_API.cpp b/intern/smoke/intern/smoke_API.cpp
deleted file mode 100644
index a02fa3bd684..00000000000
--- a/intern/smoke/intern/smoke_API.cpp
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2009 by Daniel Genrich
- * All rights reserved.
- */
-
-/** \file
- * \ingroup smoke
- */
-
-#include "FLUID_3D.h"
-#include "WTURBULENCE.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "../extern/smoke_API.h" /* to ensure valid prototypes */
-
-extern "C" FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors)
-{
- FLUID_3D *fluid = new FLUID_3D(res, dx, dtdef, use_heat, use_fire, use_colors);
- return fluid;
-}
-
-extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors)
-{
- if (amplify)
- return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, noisefile_path, use_fire, use_colors);
- else
- return NULL;
-}
-
-extern "C" void smoke_free(FLUID_3D *fluid)
-{
- delete fluid;
- fluid = NULL;
-}
-
-extern "C" void smoke_turbulence_free(WTURBULENCE *wt)
-{
- delete wt;
- wt = NULL;
-}
-
-extern "C" size_t smoke_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */)
-{
- return x + y * max_x + z * max_x*max_y;
-}
-
-extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */)
-{
- return x + y * max_x;
-}
-
-extern "C" void smoke_step(FLUID_3D *fluid, float gravity[3], float dtSubdiv)
-{
- if (fluid->_fuel) {
- fluid->processBurn(fluid->_fuel, fluid->_density, fluid->_react, fluid->_heat,
- fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_totalCells, (*fluid->_dtFactor)*dtSubdiv);
- }
- fluid->step(dtSubdiv, gravity);
-
- if (fluid->_fuel) {
- fluid->updateFlame(fluid->_react, fluid->_flame, fluid->_totalCells);
- }
-}
-
-extern "C" void smoke_turbulence_step(WTURBULENCE *wt, FLUID_3D *fluid)
-{
- if (wt->_fuelBig) {
- fluid->processBurn(wt->_fuelBig, wt->_densityBig, wt->_reactBig, 0,
- wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_totalCellsBig, fluid->_dt);
- }
- wt->stepTurbulenceFull(fluid->_dt/fluid->_dx, fluid->_xVelocity, fluid->_yVelocity, fluid->_zVelocity, fluid->_obstacles);
-
- if (wt->_fuelBig) {
- fluid->updateFlame(wt->_reactBig, wt->_flameBig, wt->_totalCellsBig);
- }
-}
-
-extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
- float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp)
-{
- fluid->initBlenderRNA(alpha, beta, dt_factor, vorticity, border_colli, burning_rate, flame_smoke, flame_smoke_color, flame_vorticity, flame_ignition_temp, flame_max_temp);
-}
-
-extern "C" void smoke_initWaveletBlenderRNA(WTURBULENCE *wt, float *strength)
-{
- wt->initBlenderRNA(strength);
-}
-
-static void data_dissolve(float *density, float *heat, float *r, float *g, float *b, int total_cells, int speed, int log)
-{
- if (log) {
- /* max density/speed = dydx */
- float fac = 1.0f - (1.0f / (float)speed);
-
- for(size_t i = 0; i < total_cells; i++)
- {
- /* density */
- density[i] *= fac;
-
- /* heat */
- if (heat) {
- heat[i] *= fac;
- }
-
- /* color */
- if (r) {
- r[i] *= fac;
- g[i] *= fac;
- b[i] *= fac;
- }
- }
- }
- else // linear falloff
- {
- /* max density/speed = dydx */
- float dydx = 1.0f / (float)speed;
-
- for(size_t i = 0; i < total_cells; i++)
- {
- float d = density[i];
- /* density */
- density[i] -= dydx;
- if (density[i] < 0.0f)
- density[i] = 0.0f;
-
- /* heat */
- if (heat) {
- if (abs(heat[i]) < dydx) heat[i] = 0.0f;
- else if (heat[i] > 0.0f) heat[i] -= dydx;
- else if (heat[i] < 0.0f) heat[i] += dydx;
- }
-
- /* color */
- if (r && d) {
- r[i] *= (density[i]/d);
- g[i] *= (density[i]/d);
- b[i] *= (density[i]/d);
- }
-
- }
- }
-}
-
-extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log)
-{
- data_dissolve(fluid->_density, fluid->_heat, fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_totalCells, speed, log);
-}
-
-extern "C" void smoke_dissolve_wavelet(WTURBULENCE *wt, int speed, int log)
-{
- data_dissolve(wt->_densityBig, 0, wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_totalCellsBig, speed, log);
-}
-
-extern "C" void smoke_export(FLUID_3D *fluid, float *dt, float *dx, float **dens, float **react, float **flame, float **fuel, float **heat,
- float **heatold, float **vx, float **vy, float **vz, float **r, float **g, float **b, unsigned char **obstacles)
-{
- *dens = fluid->_density;
- if(fuel)
- *fuel = fluid->_fuel;
- if(react)
- *react = fluid->_react;
- if(flame)
- *flame = fluid->_flame;
- if(heat)
- *heat = fluid->_heat;
- if(heatold)
- *heatold = fluid->_heatOld;
- *vx = fluid->_xVelocity;
- *vy = fluid->_yVelocity;
- *vz = fluid->_zVelocity;
- if(r)
- *r = fluid->_color_r;
- if(g)
- *g = fluid->_color_g;
- if(b)
- *b = fluid->_color_b;
- *obstacles = fluid->_obstacles;
- *dt = fluid->_dt;
- *dx = fluid->_dx;
-}
-
-extern "C" void smoke_turbulence_export(WTURBULENCE *wt, float **dens, float **react, float **flame, float **fuel,
- float **r, float **g, float **b , float **tcu, float **tcv, float **tcw)
-{
- if (!wt)
- return;
-
- *dens = wt->_densityBig;
- if(fuel)
- *fuel = wt->_fuelBig;
- if(react)
- *react = wt->_reactBig;
- if(flame)
- *flame = wt->_flameBig;
- if(r)
- *r = wt->_color_rBig;
- if(g)
- *g = wt->_color_gBig;
- if(b)
- *b = wt->_color_bBig;
- *tcu = wt->_tcU;
- *tcv = wt->_tcV;
- *tcw = wt->_tcW;
-}
-
-extern "C" float *smoke_get_density(FLUID_3D *fluid)
-{
- return fluid->_density;
-}
-
-extern "C" float *smoke_get_fuel(FLUID_3D *fluid)
-{
- return fluid->_fuel;
-}
-
-extern "C" float *smoke_get_react(FLUID_3D *fluid)
-{
- return fluid->_react;
-}
-
-extern "C" float *smoke_get_heat(FLUID_3D *fluid)
-{
- return fluid->_heat;
-}
-
-extern "C" float *smoke_get_velocity_x(FLUID_3D *fluid)
-{
- return fluid->_xVelocity;
-}
-
-extern "C" float *smoke_get_velocity_y(FLUID_3D *fluid)
-{
- return fluid->_yVelocity;
-}
-
-extern "C" float *smoke_get_velocity_z(FLUID_3D *fluid)
-{
- return fluid->_zVelocity;
-}
-
-extern "C" float *smoke_get_force_x(FLUID_3D *fluid)
-{
- return fluid->_xForce;
-}
-
-extern "C" float *smoke_get_force_y(FLUID_3D *fluid)
-{
- return fluid->_yForce;
-}
-
-extern "C" float *smoke_get_force_z(FLUID_3D *fluid)
-{
- return fluid->_zForce;
-}
-
-extern "C" float *smoke_get_flame(FLUID_3D *fluid)
-{
- return fluid->_flame;
-}
-
-extern "C" float *smoke_get_color_r(FLUID_3D *fluid)
-{
- return fluid->_color_r;
-}
-
-extern "C" float *smoke_get_color_g(FLUID_3D *fluid)
-{
- return fluid->_color_g;
-}
-
-extern "C" float *smoke_get_color_b(FLUID_3D *fluid)
-{
- return fluid->_color_b;
-}
-
-static void get_rgba(float *r, float *g, float *b, float *a, int total_cells, float *data, int sequential)
-{
- int i;
- int m = 4, i_g = 1, i_b = 2, i_a = 3;
- /* sequential data */
- if (sequential) {
- m = 1;
- i_g *= total_cells;
- i_b *= total_cells;
- i_a *= total_cells;
- }
-
- for (i=0; i<total_cells; i++) {
- float alpha = a[i];
- if (alpha) {
- data[i*m ] = r[i];
- data[i*m+i_g] = g[i];
- data[i*m+i_b] = b[i];
- }
- else {
- data[i*m ] = data[i*m+i_g] = data[i*m+i_b] = 0.0f;
- }
- data[i*m+i_a] = alpha;
- }
-}
-
-extern "C" void smoke_get_rgba(FLUID_3D *fluid, float *data, int sequential)
-{
- get_rgba(fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_density, fluid->_totalCells, data, sequential);
-}
-
-extern "C" void smoke_turbulence_get_rgba(WTURBULENCE *wt, float *data, int sequential)
-{
- get_rgba(wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_densityBig, wt->_totalCellsBig, data, sequential);
-}
-
-/* get a single color premultiplied voxel grid */
-static void get_rgba_from_density(float color[3], float *a, int total_cells, float *data, int sequential)
-{
- int i;
- int m = 4, i_g = 1, i_b = 2, i_a = 3;
- /* sequential data */
- if (sequential) {
- m = 1;
- i_g *= total_cells;
- i_b *= total_cells;
- i_a *= total_cells;
- }
-
- for (i=0; i<total_cells; i++) {
- float alpha = a[i];
- if (alpha) {
- data[i*m ] = color[0] * alpha;
- data[i*m+i_g] = color[1] * alpha;
- data[i*m+i_b] = color[2] * alpha;
- }
- else {
- data[i*m ] = data[i*m+i_g] = data[i*m+i_b] = 0.0f;
- }
- data[i*m+i_a] = alpha;
- }
-}
-
-extern "C" void smoke_get_rgba_from_density(FLUID_3D *fluid, float color[3], float *data, int sequential)
-{
- get_rgba_from_density(color, fluid->_density, fluid->_totalCells, data, sequential);
-}
-
-extern "C" void smoke_turbulence_get_rgba_from_density(WTURBULENCE *wt, float color[3], float *data, int sequential)
-{
- get_rgba_from_density(color, wt->_densityBig, wt->_totalCellsBig, data, sequential);
-}
-
-extern "C" float *smoke_turbulence_get_density(WTURBULENCE *wt)
-{
- return wt ? wt->getDensityBig() : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_fuel(WTURBULENCE *wt)
-{
- return wt ? wt->getFuelBig() : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_react(WTURBULENCE *wt)
-{
- return wt ? wt->_reactBig : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_color_r(WTURBULENCE *wt)
-{
- return wt ? wt->_color_rBig : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_color_g(WTURBULENCE *wt)
-{
- return wt ? wt->_color_gBig : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_color_b(WTURBULENCE *wt)
-{
- return wt ? wt->_color_bBig : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_flame(WTURBULENCE *wt)
-{
- return wt ? wt->getFlameBig() : NULL;
-}
-
-extern "C" void smoke_turbulence_get_res(WTURBULENCE *wt, int *res)
-{
- if (wt) {
- Vec3Int r = wt->getResBig();
- res[0] = r[0];
- res[1] = r[1];
- res[2] = r[2];
- }
-}
-
-extern "C" int smoke_turbulence_get_cells(WTURBULENCE *wt)
-{
- if (wt) {
- Vec3Int r = wt->getResBig();
- return r[0] * r[1] * r[2];
- }
- return 0;
-}
-
-extern "C" unsigned char *smoke_get_obstacle(FLUID_3D *fluid)
-{
- return fluid->_obstacles;
-}
-
-extern "C" void smoke_get_ob_velocity(FLUID_3D *fluid, float **x, float **y, float **z)
-{
- *x = fluid->_xVelocityOb;
- *y = fluid->_yVelocityOb;
- *z = fluid->_zVelocityOb;
-}
-
-#if 0
-extern "C" unsigned char *smoke_get_obstacle_anim(FLUID_3D *fluid)
-{
- return fluid->_obstaclesAnim;
-}
-#endif
-
-extern "C" void smoke_turbulence_set_noise(WTURBULENCE *wt, int type, const char *noisefile_path)
-{
- wt->setNoise(type, noisefile_path);
-}
-
-extern "C" int smoke_has_heat(FLUID_3D *fluid)
-{
- return (fluid->_heat) ? 1 : 0;
-}
-
-extern "C" int smoke_has_fuel(FLUID_3D *fluid)
-{
- return (fluid->_fuel) ? 1 : 0;
-}
-
-extern "C" int smoke_has_colors(FLUID_3D *fluid)
-{
- return (fluid->_color_r && fluid->_color_g && fluid->_color_b) ? 1 : 0;
-}
-
-extern "C" int smoke_turbulence_has_fuel(WTURBULENCE *wt)
-{
- return (wt->_fuelBig) ? 1 : 0;
-}
-
-extern "C" int smoke_turbulence_has_colors(WTURBULENCE *wt)
-{
- return (wt->_color_rBig && wt->_color_gBig && wt->_color_bBig) ? 1 : 0;
-}
-
-/* additional field initialization */
-extern "C" void smoke_ensure_heat(FLUID_3D *fluid)
-{
- if (fluid) {
- fluid->initHeat();
- }
-}
-
-extern "C" void smoke_ensure_fire(FLUID_3D *fluid, WTURBULENCE *wt)
-{
- if (fluid) {
- fluid->initFire();
- }
- if (wt) {
- wt->initFire();
- }
-}
-
-extern "C" void smoke_ensure_colors(FLUID_3D *fluid, WTURBULENCE *wt, float init_r, float init_g, float init_b)
-{
- if (fluid) {
- fluid->initColors(init_r, init_g, init_b);
- }
- if (wt) {
- wt->initColors(init_r, init_g, init_b);
- }
-}
diff --git a/intern/smoke/intern/tnt/jama_eig.h b/intern/smoke/intern/tnt/jama_eig.h
deleted file mode 100644
index 8b1ac999798..00000000000
--- a/intern/smoke/intern/tnt/jama_eig.h
+++ /dev/null
@@ -1,1053 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-#ifndef JAMA_EIG_H
-#define JAMA_EIG_H
-
-
-#include "tnt_array1d.h"
-#include "tnt_array2d.h"
-#include "tnt_math_utils.h"
-
-#include <algorithm>
-// for min(), max() below
-
-#include <cmath>
-// for fabs() below
-
-using namespace TNT;
-using namespace std;
-
-// NT debugging
-//static int gEigenDebug=0;
-//if(gEigenDebug) std::cerr<<"n="<<n<<" m="<<m<<" l="<<l<<"\n";
-// m has to be smaller l! in line 262
-// gcc can get confused with abs calls, replaced by fabs
-
-namespace JAMA
-{
-
-/**
-
- Computes eigenvalues and eigenvectors of a real (non-complex)
- matrix.
-<P>
- If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is
- diagonal and the eigenvector matrix V is orthogonal. That is,
- the diagonal values of D are the eigenvalues, and
- V*V' = I, where I is the identity matrix. The columns of V
- represent the eigenvectors in the sense that A*V = V*D.
-
-<P>
- If A is not symmetric, then the eigenvalue matrix D is block diagonal
- with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
- a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex
- eigenvalues look like
-<pre>
-
- u + iv . . . . .
- . u - iv . . . .
- . . a + ib . . .
- . . . a - ib . .
- . . . . x .
- . . . . . y
-</pre>
- then D looks like
-<pre>
-
- u v . . . .
- -v u . . . .
- . . a b . .
- . . -b a . .
- . . . . x .
- . . . . . y
-</pre>
- This keeps V a real matrix in both symmetric and non-symmetric
- cases, and A*V = V*D.
-
-
-
- <p>
- The matrix V may be badly
- conditioned, or even singular, so the validity of the equation
- A = V*D*inverse(V) depends upon the condition number of V.
-
- <p>
- (Adapted from JAMA, a Java Matrix Library, developed by jointly
- by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
-**/
-
-template <class Real>
-class Eigenvalue
-{
-
-
- /** Row and column dimension (square matrix). */
- int n;
-
- int issymmetric; /* boolean*/
-
- /** Arrays for internal storage of eigenvalues. */
-
- TNT::Array1D<Real> d; /* real part */
- TNT::Array1D<Real> e; /* img part */
-
- /** Array for internal storage of eigenvectors. */
- TNT::Array2D<Real> V;
-
- /** Array for internal storage of nonsymmetric Hessenberg form.
- @serial internal storage of nonsymmetric Hessenberg form.
- */
- TNT::Array2D<Real> H;
-
-
- /** Working storage for nonsymmetric algorithm.
- @serial working storage for nonsymmetric algorithm.
- */
- TNT::Array1D<Real> ort;
-
-
- // Symmetric Householder reduction to tridiagonal form.
-
- void tred2() {
-
- // This is derived from the Algol procedures tred2 by
- // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
- // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- for (int j = 0; j < n; j++) {
- d[j] = V[n-1][j];
- }
-
- // Householder reduction to tridiagonal form.
-
- for (int i = n-1; i > 0; i--) {
-
- // Scale to avoid under/overflow.
-
- Real scale = 0.0;
- Real h = 0.0;
- for (int k = 0; k < i; k++) {
- scale = scale + fabs(d[k]);
- }
- if (scale == 0.0) {
- e[i] = d[i-1];
- for (int j = 0; j < i; j++) {
- d[j] = V[i-1][j];
- V[i][j] = 0.0;
- V[j][i] = 0.0;
- }
- } else {
-
- // Generate Householder vector.
-
- for (int k = 0; k < i; k++) {
- d[k] /= scale;
- h += d[k] * d[k];
- }
- Real f = d[i-1];
- Real g = sqrt(h);
- if (f > 0) {
- g = -g;
- }
- e[i] = scale * g;
- h = h - f * g;
- d[i-1] = f - g;
- for (int j = 0; j < i; j++) {
- e[j] = 0.0;
- }
-
- // Apply similarity transformation to remaining columns.
-
- for (int j = 0; j < i; j++) {
- f = d[j];
- V[j][i] = f;
- g = e[j] + V[j][j] * f;
- for (int k = j+1; k <= i-1; k++) {
- g += V[k][j] * d[k];
- e[k] += V[k][j] * f;
- }
- e[j] = g;
- }
- f = 0.0;
- for (int j = 0; j < i; j++) {
- e[j] /= h;
- f += e[j] * d[j];
- }
- Real hh = f / (h + h);
- for (int j = 0; j < i; j++) {
- e[j] -= hh * d[j];
- }
- for (int j = 0; j < i; j++) {
- f = d[j];
- g = e[j];
- for (int k = j; k <= i-1; k++) {
- V[k][j] -= (f * e[k] + g * d[k]);
- }
- d[j] = V[i-1][j];
- V[i][j] = 0.0;
- }
- }
- d[i] = h;
- }
-
- // Accumulate transformations.
-
- for (int i = 0; i < n-1; i++) {
- V[n-1][i] = V[i][i];
- V[i][i] = 1.0;
- Real h = d[i+1];
- if (h != 0.0) {
- for (int k = 0; k <= i; k++) {
- d[k] = V[k][i+1] / h;
- }
- for (int j = 0; j <= i; j++) {
- Real g = 0.0;
- for (int k = 0; k <= i; k++) {
- g += V[k][i+1] * V[k][j];
- }
- for (int k = 0; k <= i; k++) {
- V[k][j] -= g * d[k];
- }
- }
- }
- for (int k = 0; k <= i; k++) {
- V[k][i+1] = 0.0;
- }
- }
- for (int j = 0; j < n; j++) {
- d[j] = V[n-1][j];
- V[n-1][j] = 0.0;
- }
- V[n-1][n-1] = 1.0;
- e[0] = 0.0;
- }
-
- // Symmetric tridiagonal QL algorithm.
-
- void tql2 () {
-
- // This is derived from the Algol procedures tql2, by
- // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
- // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- for (int i = 1; i < n; i++) {
- e[i-1] = e[i];
- }
- e[n-1] = 0.0;
-
- Real f = 0.0;
- Real tst1 = 0.0;
- Real eps = pow(2.0,-52.0);
- for (int l = 0; l < n; l++) {
-
- // Find small subdiagonal element
-
- tst1 = max(tst1,fabs(d[l]) + fabs(e[l]));
- int m = l;
-
- // Original while-loop from Java code
- while (m < n) {
- if (fabs(e[m]) <= eps*tst1) {
- break;
- }
- m++;
- }
-
-
- // If m == l, d[l] is an eigenvalue,
- // otherwise, iterate.
-
- if (m > l) {
- int iter = 0;
- do {
- iter = iter + 1; // (Could check iteration count here.)
-
- // Compute implicit shift
-
- Real g = d[l];
- Real p = (d[l+1] - g) / (2.0 * e[l]);
- Real r = hypot(p,1.0);
- if (p < 0) {
- r = -r;
- }
- d[l] = e[l] / (p + r);
- d[l+1] = e[l] * (p + r);
- Real dl1 = d[l+1];
- Real h = g - d[l];
- for (int i = l+2; i < n; i++) {
- d[i] -= h;
- }
- f = f + h;
-
- // Implicit QL transformation.
-
- p = d[m];
- Real c = 1.0;
- Real c2 = c;
- Real c3 = c;
- Real el1 = e[l+1];
- Real s = 0.0;
- Real s2 = 0.0;
- for (int i = m-1; i >= l; i--) {
- c3 = c2;
- c2 = c;
- s2 = s;
- g = c * e[i];
- h = c * p;
- r = hypot(p,e[i]);
- e[i+1] = s * r;
- s = e[i] / r;
- c = p / r;
- p = c * d[i] - s * g;
- d[i+1] = h + s * (c * g + s * d[i]);
-
- // Accumulate transformation.
-
- for (int k = 0; k < n; k++) {
- h = V[k][i+1];
- V[k][i+1] = s * V[k][i] + c * h;
- V[k][i] = c * V[k][i] - s * h;
- }
- }
- p = -s * s2 * c3 * el1 * e[l] / dl1;
- e[l] = s * p;
- d[l] = c * p;
-
- // Check for convergence.
-
- } while (fabs(e[l]) > eps*tst1);
- }
- d[l] = d[l] + f;
- e[l] = 0.0;
- }
-
- // Sort eigenvalues and corresponding vectors.
-
- for (int i = 0; i < n-1; i++) {
- int k = i;
- Real p = d[i];
- for (int j = i+1; j < n; j++) {
- if (d[j] < p) {
- k = j;
- p = d[j];
- }
- }
- if (k != i) {
- d[k] = d[i];
- d[i] = p;
- for (int j = 0; j < n; j++) {
- p = V[j][i];
- V[j][i] = V[j][k];
- V[j][k] = p;
- }
- }
- }
- }
-
- // Nonsymmetric reduction to Hessenberg form.
-
- void orthes () {
-
- // This is derived from the Algol procedures orthes and ortran,
- // by Martin and Wilkinson, Handbook for Auto. Comp.,
- // Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutines in EISPACK.
-
- int low = 0;
- int high = n-1;
-
- for (int m = low+1; m <= high-1; m++) {
-
- // Scale column.
-
- Real scale = 0.0;
- for (int i = m; i <= high; i++) {
- scale = scale + fabs(H[i][m-1]);
- }
- if (scale != 0.0) {
-
- // Compute Householder transformation.
-
- Real h = 0.0;
- for (int i = high; i >= m; i--) {
- ort[i] = H[i][m-1]/scale;
- h += ort[i] * ort[i];
- }
- Real g = sqrt(h);
- if (ort[m] > 0) {
- g = -g;
- }
- h = h - ort[m] * g;
- ort[m] = ort[m] - g;
-
- // Apply Householder similarity transformation
- // H = (I-u*u'/h)*H*(I-u*u')/h)
-
- for (int j = m; j < n; j++) {
- Real f = 0.0;
- for (int i = high; i >= m; i--) {
- f += ort[i]*H[i][j];
- }
- f = f/h;
- for (int i = m; i <= high; i++) {
- H[i][j] -= f*ort[i];
- }
- }
-
- for (int i = 0; i <= high; i++) {
- Real f = 0.0;
- for (int j = high; j >= m; j--) {
- f += ort[j]*H[i][j];
- }
- f = f/h;
- for (int j = m; j <= high; j++) {
- H[i][j] -= f*ort[j];
- }
- }
- ort[m] = scale*ort[m];
- H[m][m-1] = scale*g;
- }
- }
-
- // Accumulate transformations (Algol's ortran).
-
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- V[i][j] = (i == j ? 1.0 : 0.0);
- }
- }
-
- for (int m = high-1; m >= low+1; m--) {
- if (H[m][m-1] != 0.0) {
- for (int i = m+1; i <= high; i++) {
- ort[i] = H[i][m-1];
- }
- for (int j = m; j <= high; j++) {
- Real g = 0.0;
- for (int i = m; i <= high; i++) {
- g += ort[i] * V[i][j];
- }
- // Double division avoids possible underflow
- g = (g / ort[m]) / H[m][m-1];
- for (int i = m; i <= high; i++) {
- V[i][j] += g * ort[i];
- }
- }
- }
- }
- }
-
-
- // Complex scalar division.
-
- Real cdivr, cdivi;
- void cdiv(Real xr, Real xi, Real yr, Real yi) {
- Real r,d;
- if (fabs(yr) > fabs(yi)) {
- r = yi/yr;
- d = yr + r*yi;
- cdivr = (xr + r*xi)/d;
- cdivi = (xi - r*xr)/d;
- } else {
- r = yr/yi;
- d = yi + r*yr;
- cdivr = (r*xr + xi)/d;
- cdivi = (r*xi - xr)/d;
- }
- }
-
-
- // Nonsymmetric reduction from Hessenberg to real Schur form.
-
- void hqr2 () {
-
- // This is derived from the Algol procedure hqr2,
- // by Martin and Wilkinson, Handbook for Auto. Comp.,
- // Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- // Initialize
-
- int nn = this->n;
- int n = nn-1;
- int low = 0;
- int high = nn-1;
- Real eps = pow(2.0,-52.0);
- Real exshift = 0.0;
- Real p=0,q=0,r=0,s=0,z=0,t,w,x,y;
-
- // Store roots isolated by balanc and compute matrix norm
-
- Real norm = 0.0;
- for (int i = 0; i < nn; i++) {
- if ((i < low) || (i > high)) {
- d[i] = H[i][i];
- e[i] = 0.0;
- }
- for (int j = max(i-1,0); j < nn; j++) {
- norm = norm + fabs(H[i][j]);
- }
- }
-
- // Outer loop over eigenvalue index
-
- int iter = 0;
- int totIter = 0;
- while (n >= low) {
-
- // NT limit no. of iterations
- totIter++;
- if(totIter>100) {
- //if(totIter>15) std::cout<<"!!!!iter ABORT !!!!!!! "<<totIter<<"\n";
- // NT hack/fix, return large eigenvalues
- for (int i = 0; i < nn; i++) {
- d[i] = 10000.;
- e[i] = 10000.;
- }
- return;
- }
-
- // Look for single small sub-diagonal element
-
- int l = n;
- while (l > low) {
- s = fabs(H[l-1][l-1]) + fabs(H[l][l]);
- if (s == 0.0) {
- s = norm;
- }
- if (fabs(H[l][l-1]) < eps * s) {
- break;
- }
- l--;
- }
-
- // Check for convergence
- // One root found
-
- if (l == n) {
- H[n][n] = H[n][n] + exshift;
- d[n] = H[n][n];
- e[n] = 0.0;
- n--;
- iter = 0;
-
- // Two roots found
-
- } else if (l == n-1) {
- w = H[n][n-1] * H[n-1][n];
- p = (H[n-1][n-1] - H[n][n]) / 2.0;
- q = p * p + w;
- z = sqrt(fabs(q));
- H[n][n] = H[n][n] + exshift;
- H[n-1][n-1] = H[n-1][n-1] + exshift;
- x = H[n][n];
-
- // Real pair
-
- if (q >= 0) {
- if (p >= 0) {
- z = p + z;
- } else {
- z = p - z;
- }
- d[n-1] = x + z;
- d[n] = d[n-1];
- if (z != 0.0) {
- d[n] = x - w / z;
- }
- e[n-1] = 0.0;
- e[n] = 0.0;
- x = H[n][n-1];
- s = fabs(x) + fabs(z);
- p = x / s;
- q = z / s;
- r = sqrt(p * p+q * q);
- p = p / r;
- q = q / r;
-
- // Row modification
-
- for (int j = n-1; j < nn; j++) {
- z = H[n-1][j];
- H[n-1][j] = q * z + p * H[n][j];
- H[n][j] = q * H[n][j] - p * z;
- }
-
- // Column modification
-
- for (int i = 0; i <= n; i++) {
- z = H[i][n-1];
- H[i][n-1] = q * z + p * H[i][n];
- H[i][n] = q * H[i][n] - p * z;
- }
-
- // Accumulate transformations
-
- for (int i = low; i <= high; i++) {
- z = V[i][n-1];
- V[i][n-1] = q * z + p * V[i][n];
- V[i][n] = q * V[i][n] - p * z;
- }
-
- // Complex pair
-
- } else {
- d[n-1] = x + p;
- d[n] = x + p;
- e[n-1] = z;
- e[n] = -z;
- }
- n = n - 2;
- iter = 0;
-
- // No convergence yet
-
- } else {
-
- // Form shift
-
- x = H[n][n];
- y = 0.0;
- w = 0.0;
- if (l < n) {
- y = H[n-1][n-1];
- w = H[n][n-1] * H[n-1][n];
- }
-
- // Wilkinson's original ad hoc shift
-
- if (iter == 10) {
- exshift += x;
- for (int i = low; i <= n; i++) {
- H[i][i] -= x;
- }
- s = fabs(H[n][n-1]) + fabs(H[n-1][n-2]);
- x = y = 0.75 * s;
- w = -0.4375 * s * s;
- }
-
- // MATLAB's new ad hoc shift
-
- if (iter == 30) {
- s = (y - x) / 2.0;
- s = s * s + w;
- if (s > 0) {
- s = sqrt(s);
- if (y < x) {
- s = -s;
- }
- s = x - w / ((y - x) / 2.0 + s);
- for (int i = low; i <= n; i++) {
- H[i][i] -= s;
- }
- exshift += s;
- x = y = w = 0.964;
- }
- }
-
- iter = iter + 1; // (Could check iteration count here.)
-
- // Look for two consecutive small sub-diagonal elements
-
- int m = n-2;
- while (m >= l) {
- z = H[m][m];
- r = x - z;
- s = y - z;
- p = (r * s - w) / H[m+1][m] + H[m][m+1];
- q = H[m+1][m+1] - z - r - s;
- r = H[m+2][m+1];
- s = fabs(p) + fabs(q) + fabs(r);
- p = p / s;
- q = q / s;
- r = r / s;
- if (m == l) {
- break;
- }
- if (fabs(H[m][m-1]) * (fabs(q) + fabs(r)) <
- eps * (fabs(p) * (fabs(H[m-1][m-1]) + fabs(z) +
- fabs(H[m+1][m+1])))) {
- break;
- }
- m--;
- }
-
- for (int i = m+2; i <= n; i++) {
- H[i][i-2] = 0.0;
- if (i > m+2) {
- H[i][i-3] = 0.0;
- }
- }
-
- // Double QR step involving rows l:n and columns m:n
-
- for (int k = m; k <= n-1; k++) {
- int notlast = (k != n-1);
- if (k != m) {
- p = H[k][k-1];
- q = H[k+1][k-1];
- r = (notlast ? H[k+2][k-1] : 0.0);
- x = fabs(p) + fabs(q) + fabs(r);
- if (x != 0.0) {
- p = p / x;
- q = q / x;
- r = r / x;
- }
- }
- if (x == 0.0) {
- break;
- }
- s = sqrt(p * p + q * q + r * r);
- if (p < 0) {
- s = -s;
- }
- if (s != 0) {
- if (k != m) {
- H[k][k-1] = -s * x;
- } else if (l != m) {
- H[k][k-1] = -H[k][k-1];
- }
- p = p + s;
- x = p / s;
- y = q / s;
- z = r / s;
- q = q / p;
- r = r / p;
-
- // Row modification
-
- for (int j = k; j < nn; j++) {
- p = H[k][j] + q * H[k+1][j];
- if (notlast) {
- p = p + r * H[k+2][j];
- H[k+2][j] = H[k+2][j] - p * z;
- }
- H[k][j] = H[k][j] - p * x;
- H[k+1][j] = H[k+1][j] - p * y;
- }
-
- // Column modification
-
- for (int i = 0; i <= min(n,k+3); i++) {
- p = x * H[i][k] + y * H[i][k+1];
- if (notlast) {
- p = p + z * H[i][k+2];
- H[i][k+2] = H[i][k+2] - p * r;
- }
- H[i][k] = H[i][k] - p;
- H[i][k+1] = H[i][k+1] - p * q;
- }
-
- // Accumulate transformations
-
- for (int i = low; i <= high; i++) {
- p = x * V[i][k] + y * V[i][k+1];
- if (notlast) {
- p = p + z * V[i][k+2];
- V[i][k+2] = V[i][k+2] - p * r;
- }
- V[i][k] = V[i][k] - p;
- V[i][k+1] = V[i][k+1] - p * q;
- }
- } // (s != 0)
- } // k loop
- } // check convergence
- } // while (n >= low)
- //if(totIter>15) std::cout<<"!!!!iter "<<totIter<<"\n";
-
- // Backsubstitute to find vectors of upper triangular form
-
- if (norm == 0.0) {
- return;
- }
-
- for (n = nn-1; n >= 0; n--) {
- p = d[n];
- q = e[n];
-
- // Real vector
-
- if (q == 0) {
- int l = n;
- H[n][n] = 1.0;
- for (int i = n-1; i >= 0; i--) {
- w = H[i][i] - p;
- r = 0.0;
- for (int j = l; j <= n; j++) {
- r = r + H[i][j] * H[j][n];
- }
- if (e[i] < 0.0) {
- z = w;
- s = r;
- } else {
- l = i;
- if (e[i] == 0.0) {
- if (w != 0.0) {
- H[i][n] = -r / w;
- } else {
- H[i][n] = -r / (eps * norm);
- }
-
- // Solve real equations
-
- } else {
- x = H[i][i+1];
- y = H[i+1][i];
- q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
- t = (x * s - z * r) / q;
- H[i][n] = t;
- if (fabs(x) > fabs(z)) {
- H[i+1][n] = (-r - w * t) / x;
- } else {
- H[i+1][n] = (-s - y * t) / z;
- }
- }
-
- // Overflow control
-
- t = fabs(H[i][n]);
- if ((eps * t) * t > 1) {
- for (int j = i; j <= n; j++) {
- H[j][n] = H[j][n] / t;
- }
- }
- }
- }
-
- // Complex vector
-
- } else if (q < 0) {
- int l = n-1;
-
- // Last vector component imaginary so matrix is triangular
-
- if (fabs(H[n][n-1]) > fabs(H[n-1][n])) {
- H[n-1][n-1] = q / H[n][n-1];
- H[n-1][n] = -(H[n][n] - p) / H[n][n-1];
- } else {
- cdiv(0.0,-H[n-1][n],H[n-1][n-1]-p,q);
- H[n-1][n-1] = cdivr;
- H[n-1][n] = cdivi;
- }
- H[n][n-1] = 0.0;
- H[n][n] = 1.0;
- for (int i = n-2; i >= 0; i--) {
- Real ra,sa,vr,vi;
- ra = 0.0;
- sa = 0.0;
- for (int j = l; j <= n; j++) {
- ra = ra + H[i][j] * H[j][n-1];
- sa = sa + H[i][j] * H[j][n];
- }
- w = H[i][i] - p;
-
- if (e[i] < 0.0) {
- z = w;
- r = ra;
- s = sa;
- } else {
- l = i;
- if (e[i] == 0) {
- cdiv(-ra,-sa,w,q);
- H[i][n-1] = cdivr;
- H[i][n] = cdivi;
- } else {
-
- // Solve complex equations
-
- x = H[i][i+1];
- y = H[i+1][i];
- vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
- vi = (d[i] - p) * 2.0 * q;
- if ((vr == 0.0) && (vi == 0.0)) {
- vr = eps * norm * (fabs(w) + fabs(q) +
- fabs(x) + fabs(y) + fabs(z));
- }
- cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
- H[i][n-1] = cdivr;
- H[i][n] = cdivi;
- if (fabs(x) > (fabs(z) + fabs(q))) {
- H[i+1][n-1] = (-ra - w * H[i][n-1] + q * H[i][n]) / x;
- H[i+1][n] = (-sa - w * H[i][n] - q * H[i][n-1]) / x;
- } else {
- cdiv(-r-y*H[i][n-1],-s-y*H[i][n],z,q);
- H[i+1][n-1] = cdivr;
- H[i+1][n] = cdivi;
- }
- }
-
- // Overflow control
-
- t = max(fabs(H[i][n-1]),fabs(H[i][n]));
- if ((eps * t) * t > 1) {
- for (int j = i; j <= n; j++) {
- H[j][n-1] = H[j][n-1] / t;
- H[j][n] = H[j][n] / t;
- }
- }
- }
- }
- }
- }
-
- // Vectors of isolated roots
-
- for (int i = 0; i < nn; i++) {
- if (i < low || i > high) {
- for (int j = i; j < nn; j++) {
- V[i][j] = H[i][j];
- }
- }
- }
-
- // Back transformation to get eigenvectors of original matrix
-
- for (int j = nn-1; j >= low; j--) {
- for (int i = low; i <= high; i++) {
- z = 0.0;
- for (int k = low; k <= min(j,high); k++) {
- z = z + V[i][k] * H[k][j];
- }
- V[i][j] = z;
- }
- }
- }
-
-public:
-
-
- /** Check for symmetry, then construct the eigenvalue decomposition
- @param A Square real (non-complex) matrix
- */
-
- Eigenvalue(const TNT::Array2D<Real> &A) {
- n = A.dim2();
- V = Array2D<Real>(n,n);
- d = Array1D<Real>(n);
- e = Array1D<Real>(n);
-
- issymmetric = 1;
- for (int j = 0; (j < n) && issymmetric; j++) {
- for (int i = 0; (i < n) && issymmetric; i++) {
- issymmetric = (A[i][j] == A[j][i]);
- }
- }
-
- if (issymmetric) {
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- V[i][j] = A[i][j];
- }
- }
-
- // Tridiagonalize.
- tred2();
-
- // Diagonalize.
- tql2();
-
- } else {
- H = TNT::Array2D<Real>(n,n);
- ort = TNT::Array1D<Real>(n);
-
- for (int j = 0; j < n; j++) {
- for (int i = 0; i < n; i++) {
- H[i][j] = A[i][j];
- }
- }
-
- // Reduce to Hessenberg form.
- orthes();
-
- // Reduce Hessenberg to real Schur form.
- hqr2();
- }
- }
-
-
- /** Return the eigenvector matrix
- @return V
- */
-
- void getV (TNT::Array2D<Real> &V_) {
- V_ = V;
- return;
- }
-
- /** Return the real parts of the eigenvalues
- @return real(diag(D))
- */
-
- void getRealEigenvalues (TNT::Array1D<Real> &d_) {
- d_ = d;
- return ;
- }
-
- /** Return the imaginary parts of the eigenvalues
- in parameter e_.
-
- @pararm e_: new matrix with imaginary parts of the eigenvalues.
- */
- void getImagEigenvalues (TNT::Array1D<Real> &e_) {
- e_ = e;
- return;
- }
-
-
-/**
- Computes the block diagonal eigenvalue matrix.
- If the original matrix A is not symmetric, then the eigenvalue
- matrix D is block diagonal with the real eigenvalues in 1-by-1
- blocks and any complex eigenvalues,
- a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex
- eigenvalues look like
-<pre>
-
- u + iv . . . . .
- . u - iv . . . .
- . . a + ib . . .
- . . . a - ib . .
- . . . . x .
- . . . . . y
-</pre>
- then D looks like
-<pre>
-
- u v . . . .
- -v u . . . .
- . . a b . .
- . . -b a . .
- . . . . x .
- . . . . . y
-</pre>
- This keeps V a real matrix in both symmetric and non-symmetric
- cases, and A*V = V*D.
-
- @param D: upon return, the matrix is filled with the block diagonal
- eigenvalue matrix.
-
-*/
- void getD (TNT::Array2D<Real> &D) {
- D = Array2D<Real>(n,n);
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- D[i][j] = 0.0;
- }
- D[i][i] = d[i];
- if (e[i] > 0) {
- D[i][i+1] = e[i];
- } else if (e[i] < 0) {
- D[i][i-1] = e[i];
- }
- }
- }
-};
-
-} //namespace JAMA
-
-
-#endif
-// JAMA_EIG_H
diff --git a/intern/smoke/intern/tnt/jama_lu.h b/intern/smoke/intern/tnt/jama_lu.h
deleted file mode 100644
index 7855c060eca..00000000000
--- a/intern/smoke/intern/tnt/jama_lu.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-#ifndef JAMA_LU_H
-#define JAMA_LU_H
-
-#include "tnt.h"
-#include <algorithm>
-//for min(), max() below
-
-using namespace TNT;
-using namespace std;
-
-namespace JAMA
-{
-
- /** LU Decomposition.
- <P>
- For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
- unit lower triangular matrix L, an n-by-n upper triangular matrix U,
- and a permutation vector piv of length m so that A(piv,:) = L*U.
- If m < n, then L is m-by-m and U is m-by-n.
- <P>
- The LU decompostion with pivoting always exists, even if the matrix is
- singular, so the constructor will never fail. The primary use of the
- LU decomposition is in the solution of square systems of simultaneous
- linear equations. This will fail if isNonsingular() returns false.
- */
-template <class Real>
-class LU
-{
-
-
-
- /* Array for internal storage of decomposition. */
- Array2D<Real> LU_;
- int m, n, pivsign;
- Array1D<int> piv;
-
-
- Array2D<Real> permute_copy(const Array2D<Real> &A,
- const Array1D<int> &piv, int j0, int j1)
- {
- int piv_length = piv.dim();
-
- Array2D<Real> X(piv_length, j1-j0+1);
-
-
- for (int i = 0; i < piv_length; i++)
- for (int j = j0; j <= j1; j++)
- X[i][j-j0] = A[piv[i]][j];
-
- return X;
- }
-
- Array1D<Real> permute_copy(const Array1D<Real> &A,
- const Array1D<int> &piv)
- {
- int piv_length = piv.dim();
- if (piv_length != A.dim())
- return Array1D<Real>();
-
- Array1D<Real> x(piv_length);
-
-
- for (int i = 0; i < piv_length; i++)
- x[i] = A[piv[i]];
-
- return x;
- }
-
-
- public :
-
- /** LU Decomposition
- @param A Rectangular matrix
- @return LU Decomposition object to access L, U and piv.
- */
-
- LU (const Array2D<Real> &A) : LU_(A.copy()), m(A.dim1()), n(A.dim2()),
- piv(A.dim1())
-
- {
-
- // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
-
-
- for (int i = 0; i < m; i++) {
- piv[i] = i;
- }
- pivsign = 1;
- Real *LUrowi = 0;;
- Array1D<Real> LUcolj(m);
-
- // Outer loop.
-
- for (int j = 0; j < n; j++) {
-
- // Make a copy of the j-th column to localize references.
-
- for (int i = 0; i < m; i++) {
- LUcolj[i] = LU_[i][j];
- }
-
- // Apply previous transformations.
-
- for (int i = 0; i < m; i++) {
- LUrowi = LU_[i];
-
- // Most of the time is spent in the following dot product.
-
- int kmax = min(i,j);
- double s = 0.0;
- for (int k = 0; k < kmax; k++) {
- s += LUrowi[k]*LUcolj[k];
- }
-
- LUrowi[j] = LUcolj[i] -= s;
- }
-
- // Find pivot and exchange if necessary.
-
- int p = j;
- for (int i = j+1; i < m; i++) {
- if (abs(LUcolj[i]) > abs(LUcolj[p])) {
- p = i;
- }
- }
- if (p != j) {
- int k=0;
- for (k = 0; k < n; k++) {
- double t = LU_[p][k];
- LU_[p][k] = LU_[j][k];
- LU_[j][k] = t;
- }
- k = piv[p];
- piv[p] = piv[j];
- piv[j] = k;
- pivsign = -pivsign;
- }
-
- // Compute multipliers.
-
- if ((j < m) && (LU_[j][j] != 0.0)) {
- for (int i = j+1; i < m; i++) {
- LU_[i][j] /= LU_[j][j];
- }
- }
- }
- }
-
-
- /** Is the matrix nonsingular?
- @return 1 (true) if upper triangular factor U (and hence A)
- is nonsingular, 0 otherwise.
- */
-
- int isNonsingular () {
- for (int j = 0; j < n; j++) {
- if (LU_[j][j] == 0)
- return 0;
- }
- return 1;
- }
-
- /** Return lower triangular factor
- @return L
- */
-
- Array2D<Real> getL () {
- Array2D<Real> L_(m,n);
- for (int i = 0; i < m; i++) {
- for (int j = 0; j < n; j++) {
- if (i > j) {
- L_[i][j] = LU_[i][j];
- } else if (i == j) {
- L_[i][j] = 1.0;
- } else {
- L_[i][j] = 0.0;
- }
- }
- }
- return L_;
- }
-
- /** Return upper triangular factor
- @return U portion of LU factorization.
- */
-
- Array2D<Real> getU () {
- Array2D<Real> U_(n,n);
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- if (i <= j) {
- U_[i][j] = LU_[i][j];
- } else {
- U_[i][j] = 0.0;
- }
- }
- }
- return U_;
- }
-
- /** Return pivot permutation vector
- @return piv
- */
-
- Array1D<int> getPivot () {
- return piv;
- }
-
-
- /** Compute determinant using LU factors.
- @return determinant of A, or 0 if A is not square.
- */
-
- Real det () {
- if (m != n) {
- return Real(0);
- }
- Real d = Real(pivsign);
- for (int j = 0; j < n; j++) {
- d *= LU_[j][j];
- }
- return d;
- }
-
- /** Solve A*X = B
- @param B A Matrix with as many rows as A and any number of columns.
- @return X so that L*U*X = B(piv,:), if B is nonconformant, returns
- 0x0 (null) array.
- */
-
- Array2D<Real> solve (const Array2D<Real> &B)
- {
-
- /* Dimensions: A is mxn, X is nxk, B is mxk */
-
- if (B.dim1() != m) {
- return Array2D<Real>(0,0);
- }
- if (!isNonsingular()) {
- return Array2D<Real>(0,0);
- }
-
- // Copy right hand side with pivoting
- int nx = B.dim2();
-
-
- Array2D<Real> X = permute_copy(B, piv, 0, nx-1);
-
- // Solve L*Y = B(piv,:)
- for (int k = 0; k < n; k++) {
- for (int i = k+1; i < n; i++) {
- for (int j = 0; j < nx; j++) {
- X[i][j] -= X[k][j]*LU_[i][k];
- }
- }
- }
- // Solve U*X = Y;
- for (int k = n-1; k >= 0; k--) {
- for (int j = 0; j < nx; j++) {
- X[k][j] /= LU_[k][k];
- }
- for (int i = 0; i < k; i++) {
- for (int j = 0; j < nx; j++) {
- X[i][j] -= X[k][j]*LU_[i][k];
- }
- }
- }
- return X;
- }
-
-
- /** Solve A*x = b, where x and b are vectors of length equal
- to the number of rows in A.
-
- @param b a vector (Array1D> of length equal to the first dimension
- of A.
- @return x a vector (Array1D> so that L*U*x = b(piv), if B is nonconformant,
- returns 0x0 (null) array.
- */
-
- Array1D<Real> solve (const Array1D<Real> &b)
- {
-
- /* Dimensions: A is mxn, X is nxk, B is mxk */
-
- if (b.dim1() != m) {
- return Array1D<Real>();
- }
- if (!isNonsingular()) {
- return Array1D<Real>();
- }
-
-
- Array1D<Real> x = permute_copy(b, piv);
-
- // Solve L*Y = B(piv)
- for (int k = 0; k < n; k++) {
- for (int i = k+1; i < n; i++) {
- x[i] -= x[k]*LU_[i][k];
- }
- }
-
- // Solve U*X = Y;
- for (int k = n-1; k >= 0; k--) {
- x[k] /= LU_[k][k];
- for (int i = 0; i < k; i++)
- x[i] -= x[k]*LU_[i][k];
- }
-
-
- return x;
- }
-
-}; /* class LU */
-
-} /* namespace JAMA */
-
-#endif
-/* JAMA_LU_H */
diff --git a/intern/smoke/intern/tnt/tnt.h b/intern/smoke/intern/tnt/tnt.h
deleted file mode 100644
index ef9de784bb3..00000000000
--- a/intern/smoke/intern/tnt/tnt.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_H
-#define TNT_H
-
-
-
-//---------------------------------------------------------------------
-// Define this macro if you want TNT to track some of the out-of-bounds
-// indexing. This can encur a small run-time overhead, but is recommended
-// while developing code. It can be turned off for production runs.
-//
-// #define TNT_BOUNDS_CHECK
-//---------------------------------------------------------------------
-//
-
-//#define TNT_BOUNDS_CHECK
-
-
-
-#include "tnt_version.h"
-#include "tnt_math_utils.h"
-#include "tnt_array1d.h"
-#include "tnt_array2d.h"
-#include "tnt_array3d.h"
-#include "tnt_array1d_utils.h"
-#include "tnt_array2d_utils.h"
-#include "tnt_array3d_utils.h"
-
-#include "tnt_fortran_array1d.h"
-#include "tnt_fortran_array2d.h"
-#include "tnt_fortran_array3d.h"
-#include "tnt_fortran_array1d_utils.h"
-#include "tnt_fortran_array2d_utils.h"
-#include "tnt_fortran_array3d_utils.h"
-
-#include "tnt_sparse_matrix_csr.h"
-
-#include "tnt_stopwatch.h"
-#include "tnt_subscript.h"
-#include "tnt_vec.h"
-#include "tnt_cmat.h"
-
-
-#endif
-// TNT_H
diff --git a/intern/smoke/intern/tnt/tnt_array1d.h b/intern/smoke/intern/tnt/tnt_array1d.h
deleted file mode 100644
index 999cbd08d24..00000000000
--- a/intern/smoke/intern/tnt/tnt_array1d.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_ARRAY1D_H
-#define TNT_ARRAY1D_H
-
-//#include <cstdlib>
-#include <iostream>
-
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-
-#include "tnt_i_refvec.h"
-
-namespace TNT
-{
-
-template <class T>
-class Array1D
-{
-
- private:
-
- /* ... */
- i_refvec<T> v_;
- int n_;
- T* data_; /* this normally points to v_.begin(), but
- * could also point to a portion (subvector)
- * of v_.
- */
-
- void copy_(T* p, const T* q, int len) const;
- void set_(T* begin, T* end, const T& val);
-
-
- public:
-
- typedef T value_type;
-
-
- Array1D();
- explicit Array1D(int n);
- Array1D(int n, const T &a);
- Array1D(int n, T *a);
- inline Array1D(const Array1D &A);
- inline operator T*();
- inline operator const T*();
- inline Array1D & operator=(const T &a);
- inline Array1D & operator=(const Array1D &A);
- inline Array1D & ref(const Array1D &A);
- Array1D copy() const;
- Array1D & inject(const Array1D & A);
- inline T& operator[](int i);
- inline const T& operator[](int i) const;
- inline int dim1() const;
- inline int dim() const;
- ~Array1D();
-
-
- /* ... extended interface ... */
-
- inline int ref_count() const;
- inline Array1D<T> subarray(int i0, int i1);
-
-};
-
-
-
-
-template <class T>
-Array1D<T>::Array1D() : v_(), n_(0), data_(0) {}
-
-template <class T>
-Array1D<T>::Array1D(const Array1D<T> &A) : v_(A.v_), n_(A.n_),
- data_(A.data_)
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Array1D(const Array1D<T> &A) \n";
-#endif
-
-}
-
-
-template <class T>
-Array1D<T>::Array1D(int n) : v_(n), n_(n), data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Array1D(int n) \n";
-#endif
-}
-
-template <class T>
-Array1D<T>::Array1D(int n, const T &val) : v_(n), n_(n), data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Array1D(int n, const T& val) \n";
-#endif
- set_(data_, data_+ n, val);
-
-}
-
-template <class T>
-Array1D<T>::Array1D(int n, T *a) : v_(a), n_(n) , data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Array1D(int n, T* a) \n";
-#endif
-}
-
-template <class T>
-inline Array1D<T>::operator T*()
-{
- return &(v_[0]);
-}
-
-
-template <class T>
-inline Array1D<T>::operator const T*()
-{
- return &(v_[0]);
-}
-
-
-
-template <class T>
-inline T& Array1D<T>::operator[](int i)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i>= 0);
- assert(i < n_);
-#endif
- return data_[i];
-}
-
-template <class T>
-inline const T& Array1D<T>::operator[](int i) const
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i>= 0);
- assert(i < n_);
-#endif
- return data_[i];
-}
-
-
-
-
-template <class T>
-Array1D<T> & Array1D<T>::operator=(const T &a)
-{
- set_(data_, data_+n_, a);
- return *this;
-}
-
-template <class T>
-Array1D<T> Array1D<T>::copy() const
-{
- Array1D A( n_);
- copy_(A.data_, data_, n_);
-
- return A;
-}
-
-
-template <class T>
-Array1D<T> & Array1D<T>::inject(const Array1D &A)
-{
- if (A.n_ == n_)
- copy_(data_, A.data_, n_);
-
- return *this;
-}
-
-
-
-
-
-template <class T>
-Array1D<T> & Array1D<T>::ref(const Array1D<T> &A)
-{
- if (this != &A)
- {
- v_ = A.v_; /* operator= handles the reference counting. */
- n_ = A.n_;
- data_ = A.data_;
-
- }
- return *this;
-}
-
-template <class T>
-Array1D<T> & Array1D<T>::operator=(const Array1D<T> &A)
-{
- return ref(A);
-}
-
-template <class T>
-inline int Array1D<T>::dim1() const { return n_; }
-
-template <class T>
-inline int Array1D<T>::dim() const { return n_; }
-
-template <class T>
-Array1D<T>::~Array1D() {}
-
-
-/* ............................ exented interface ......................*/
-
-template <class T>
-inline int Array1D<T>::ref_count() const
-{
- return v_.ref_count();
-}
-
-template <class T>
-inline Array1D<T> Array1D<T>::subarray(int i0, int i1)
-{
- if ((i0 > 0) && (i1 < n_) || (i0 <= i1))
- {
- Array1D<T> X(*this); /* create a new instance of this array. */
- X.n_ = i1-i0+1;
- X.data_ += i0;
-
- return X;
- }
- else
- {
- return Array1D<T>();
- }
-}
-
-
-/* private internal functions */
-
-
-template <class T>
-void Array1D<T>::set_(T* begin, T* end, const T& a)
-{
- for (T* p=begin; p<end; p++)
- *p = a;
-
-}
-
-template <class T>
-void Array1D<T>::copy_(T* p, const T* q, int len) const
-{
- T *end = p + len;
- while (p<end )
- *p++ = *q++;
-
-}
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_ARRAY1D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_array1d_utils.h b/intern/smoke/intern/tnt/tnt_array1d_utils.h
deleted file mode 100644
index 4ff0c803325..00000000000
--- a/intern/smoke/intern/tnt/tnt_array1d_utils.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-#ifndef TNT_ARRAY1D_UTILS_H
-#define TNT_ARRAY1D_UTILS_H
-
-#include <cstdlib>
-#include <cassert>
-
-namespace TNT
-{
-
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Array1D<T> &A)
-{
- int N=A.dim1();
-
-#ifdef TNT_DEBUG
- s << "addr: " << (void *) &A[0] << "\n";
-#endif
- s << N << "\n";
- for (int j=0; j<N; j++)
- {
- s << A[j] << "\n";
- }
- s << "\n";
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Array1D<T> &A)
-{
- int N;
- s >> N;
-
- Array1D<T> B(N);
- for (int i=0; i<N; i++)
- s >> B[i];
- A = B;
- return s;
-}
-
-
-
-template <class T>
-Array1D<T> operator+(const Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Array1D<T>();
-
- else
- {
- Array1D<T> C(n);
-
- for (int i=0; i<n; i++)
- {
- C[i] = A[i] + B[i];
- }
- return C;
- }
-}
-
-
-
-template <class T>
-Array1D<T> operator-(const Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Array1D<T>();
-
- else
- {
- Array1D<T> C(n);
-
- for (int i=0; i<n; i++)
- {
- C[i] = A[i] - B[i];
- }
- return C;
- }
-}
-
-
-template <class T>
-Array1D<T> operator*(const Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Array1D<T>();
-
- else
- {
- Array1D<T> C(n);
-
- for (int i=0; i<n; i++)
- {
- C[i] = A[i] * B[i];
- }
- return C;
- }
-}
-
-
-template <class T>
-Array1D<T> operator/(const Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Array1D<T>();
-
- else
- {
- Array1D<T> C(n);
-
- for (int i=0; i<n; i++)
- {
- C[i] = A[i] / B[i];
- }
- return C;
- }
-}
-
-
-
-
-
-
-
-
-
-template <class T>
-Array1D<T>& operator+=(Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=0; i<n; i++)
- {
- A[i] += B[i];
- }
- }
- return A;
-}
-
-
-
-
-template <class T>
-Array1D<T>& operator-=(Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=0; i<n; i++)
- {
- A[i] -= B[i];
- }
- }
- return A;
-}
-
-
-
-template <class T>
-Array1D<T>& operator*=(Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=0; i<n; i++)
- {
- A[i] *= B[i];
- }
- }
- return A;
-}
-
-
-
-
-template <class T>
-Array1D<T>& operator/=(Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=0; i<n; i++)
- {
- A[i] /= B[i];
- }
- }
- return A;
-}
-
-
-
-
-
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_array2d.h b/intern/smoke/intern/tnt/tnt_array2d.h
deleted file mode 100644
index e96beab9367..00000000000
--- a/intern/smoke/intern/tnt/tnt_array2d.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_ARRAY2D_H
-#define TNT_ARRAY2D_H
-
-#include <cstdlib>
-#include <iostream>
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-#include "tnt_array1d.h"
-
-namespace TNT
-{
-
-template <class T>
-class Array2D
-{
-
-
- private:
-
-
-
- Array1D<T> data_;
- Array1D<T*> v_;
- int m_;
- int n_;
-
- public:
-
- typedef T value_type;
- Array2D();
- Array2D(int m, int n);
- Array2D(int m, int n, T *a);
- Array2D(int m, int n, const T &a);
- inline Array2D(const Array2D &A);
- inline operator T**();
- inline operator const T**();
- inline Array2D & operator=(const T &a);
- inline Array2D & operator=(const Array2D &A);
- inline Array2D & ref(const Array2D &A);
- Array2D copy() const;
- Array2D & inject(const Array2D & A);
- inline T* operator[](int i);
- inline const T* operator[](int i) const;
- inline int dim1() const;
- inline int dim2() const;
- ~Array2D();
-
- /* extended interface (not part of the standard) */
-
-
- inline int ref_count();
- inline int ref_count_data();
- inline int ref_count_dim1();
- Array2D subarray(int i0, int i1, int j0, int j1);
-
-};
-
-
-template <class T>
-Array2D<T>::Array2D() : data_(), v_(), m_(0), n_(0) {}
-
-template <class T>
-Array2D<T>::Array2D(const Array2D<T> &A) : data_(A.data_), v_(A.v_),
- m_(A.m_), n_(A.n_) {}
-
-
-
-
-template <class T>
-Array2D<T>::Array2D(int m, int n) : data_(m*n), v_(m), m_(m), n_(n)
-{
- if (m>0 && n>0)
- {
- T* p = &(data_[0]);
- for (int i=0; i<m; i++)
- {
- v_[i] = p;
- p += n;
- }
- }
-}
-
-
-
-template <class T>
-Array2D<T>::Array2D(int m, int n, const T &val) : data_(m*n), v_(m),
- m_(m), n_(n)
-{
- if (m>0 && n>0)
- {
- data_ = val;
- T* p = &(data_[0]);
- for (int i=0; i<m; i++)
- {
- v_[i] = p;
- p += n;
- }
- }
-}
-
-template <class T>
-Array2D<T>::Array2D(int m, int n, T *a) : data_(m*n, a), v_(m), m_(m), n_(n)
-{
- if (m>0 && n>0)
- {
- T* p = &(data_[0]);
-
- for (int i=0; i<m; i++)
- {
- v_[i] = p;
- p += n;
- }
- }
-}
-
-
-template <class T>
-inline T* Array2D<T>::operator[](int i)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 0);
- assert(i < m_);
-#endif
-
-return v_[i];
-
-}
-
-
-template <class T>
-inline const T* Array2D<T>::operator[](int i) const
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 0);
- assert(i < m_);
-#endif
-
-return v_[i];
-
-}
-
-template <class T>
-Array2D<T> & Array2D<T>::operator=(const T &a)
-{
- /* non-optimzied, but will work with subarrays in future verions */
-
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- v_[i][j] = a;
- return *this;
-}
-
-
-
-
-template <class T>
-Array2D<T> Array2D<T>::copy() const
-{
- Array2D A(m_, n_);
-
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- A[i][j] = v_[i][j];
-
-
- return A;
-}
-
-
-template <class T>
-Array2D<T> & Array2D<T>::inject(const Array2D &A)
-{
- if (A.m_ == m_ && A.n_ == n_)
- {
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- v_[i][j] = A[i][j];
- }
- return *this;
-}
-
-
-
-
-template <class T>
-Array2D<T> & Array2D<T>::ref(const Array2D<T> &A)
-{
- if (this != &A)
- {
- v_ = A.v_;
- data_ = A.data_;
- m_ = A.m_;
- n_ = A.n_;
-
- }
- return *this;
-}
-
-
-
-template <class T>
-Array2D<T> & Array2D<T>::operator=(const Array2D<T> &A)
-{
- return ref(A);
-}
-
-template <class T>
-inline int Array2D<T>::dim1() const { return m_; }
-
-template <class T>
-inline int Array2D<T>::dim2() const { return n_; }
-
-
-template <class T>
-Array2D<T>::~Array2D() {}
-
-
-
-
-template <class T>
-inline Array2D<T>::operator T**()
-{
- return &(v_[0]);
-}
-template <class T>
-inline Array2D<T>::operator const T**()
-{
- return &(v_[0]);
-}
-
-/* ............... extended interface ............... */
-/**
- Create a new view to a subarray defined by the boundaries
- [i0][i0] and [i1][j1]. The size of the subarray is
- (i1-i0) by (j1-j0). If either of these lengths are zero
- or negative, the subarray view is null.
-
-*/
-template <class T>
-Array2D<T> Array2D<T>::subarray(int i0, int i1, int j0, int j1)
-{
- Array2D<T> A;
- int m = i1-i0+1;
- int n = j1-j0+1;
-
- /* if either length is zero or negative, this is an invalide
- subarray. return a null view.
- */
- if (m<1 || n<1)
- return A;
-
- A.data_ = data_;
- A.m_ = m;
- A.n_ = n;
- A.v_ = Array1D<T*>(m);
- T* p = &(data_[0]) + i0 * n_ + j0;
- for (int i=0; i<m; i++)
- {
- A.v_[i] = p + i*n_;
-
- }
- return A;
-}
-
-template <class T>
-inline int Array2D<T>::ref_count()
-{
- return ref_count_data();
-}
-
-
-
-template <class T>
-inline int Array2D<T>::ref_count_data()
-{
- return data_.ref_count();
-}
-
-template <class T>
-inline int Array2D<T>::ref_count_dim1()
-{
- return v_.ref_count();
-}
-
-
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_ARRAY2D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_array2d_utils.h b/intern/smoke/intern/tnt/tnt_array2d_utils.h
deleted file mode 100644
index 63f98073506..00000000000
--- a/intern/smoke/intern/tnt/tnt_array2d_utils.h
+++ /dev/null
@@ -1,290 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_ARRAY2D_UTILS_H
-#define TNT_ARRAY2D_UTILS_H
-
-#include <cstdlib>
-#include <cassert>
-
-namespace TNT
-{
-
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Array2D<T> &A)
-{
- int M=A.dim1();
- int N=A.dim2();
-
- s << M << " " << N << "\n";
-
- for (int i=0; i<M; i++)
- {
- for (int j=0; j<N; j++)
- {
- s << A[i][j] << " ";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Array2D<T> &A)
-{
-
- int M, N;
-
- s >> M >> N;
-
- Array2D<T> B(M,N);
-
- for (int i=0; i<M; i++)
- for (int j=0; j<N; j++)
- {
- s >> B[i][j];
- }
-
- A = B;
- return s;
-}
-
-
-template <class T>
-Array2D<T> operator+(const Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Array2D<T>();
-
- else
- {
- Array2D<T> C(m,n);
-
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- C[i][j] = A[i][j] + B[i][j];
- }
- return C;
- }
-}
-
-template <class T>
-Array2D<T> operator-(const Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Array2D<T>();
-
- else
- {
- Array2D<T> C(m,n);
-
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- C[i][j] = A[i][j] - B[i][j];
- }
- return C;
- }
-}
-
-
-template <class T>
-Array2D<T> operator*(const Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Array2D<T>();
-
- else
- {
- Array2D<T> C(m,n);
-
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- C[i][j] = A[i][j] * B[i][j];
- }
- return C;
- }
-}
-
-
-
-
-template <class T>
-Array2D<T> operator/(const Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Array2D<T>();
-
- else
- {
- Array2D<T> C(m,n);
-
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- C[i][j] = A[i][j] / B[i][j];
- }
- return C;
- }
-}
-
-
-
-
-
-template <class T>
-Array2D<T>& operator+=(Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- A[i][j] += B[i][j];
- }
- }
- return A;
-}
-
-
-
-template <class T>
-Array2D<T>& operator-=(Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- A[i][j] -= B[i][j];
- }
- }
- return A;
-}
-
-
-
-template <class T>
-Array2D<T>& operator*=(Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- A[i][j] *= B[i][j];
- }
- }
- return A;
-}
-
-
-
-
-
-template <class T>
-Array2D<T>& operator/=(Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- A[i][j] /= B[i][j];
- }
- }
- return A;
-}
-
-/**
- Matrix Multiply: compute C = A*B, where C[i][j]
- is the dot-product of row i of A and column j of B.
-
-
- @param A an (m x n) array
- @param B an (n x k) array
- @return the (m x k) array A*B, or a null array (0x0)
- if the matrices are non-conformant (i.e. the number
- of columns of A are different than the number of rows of B.)
-
-
-*/
-template <class T>
-Array2D<T> matmult(const Array2D<T> &A, const Array2D<T> &B)
-{
- if (A.dim2() != B.dim1())
- return Array2D<T>();
-
- int M = A.dim1();
- int N = A.dim2();
- int K = B.dim2();
-
- Array2D<T> C(M,K);
-
- for (int i=0; i<M; i++)
- for (int j=0; j<K; j++)
- {
- T sum = 0;
-
- for (int k=0; k<N; k++)
- sum += A[i][k] * B [k][j];
-
- C[i][j] = sum;
- }
-
- return C;
-
-}
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_array3d.h b/intern/smoke/intern/tnt/tnt_array3d.h
deleted file mode 100644
index e62358ea614..00000000000
--- a/intern/smoke/intern/tnt/tnt_array3d.h
+++ /dev/null
@@ -1,299 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_ARRAY3D_H
-#define TNT_ARRAY3D_H
-
-#include <cstdlib>
-#include <iostream>
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-#include "tnt_array1d.h"
-#include "tnt_array2d.h"
-
-namespace TNT
-{
-
-template <class T>
-class Array3D
-{
-
-
- private:
- Array1D<T> data_;
- Array2D<T*> v_;
- int m_;
- int n_;
- int g_;
-
-
- public:
-
- typedef T value_type;
-
- Array3D();
- Array3D(int m, int n, int g);
- Array3D(int m, int n, int g, T val);
- Array3D(int m, int n, int g, T *a);
-
- inline operator T***();
- inline operator const T***();
- inline Array3D(const Array3D &A);
- inline Array3D & operator=(const T &a);
- inline Array3D & operator=(const Array3D &A);
- inline Array3D & ref(const Array3D &A);
- Array3D copy() const;
- Array3D & inject(const Array3D & A);
-
- inline T** operator[](int i);
- inline const T* const * operator[](int i) const;
- inline int dim1() const;
- inline int dim2() const;
- inline int dim3() const;
- ~Array3D();
-
- /* extended interface */
-
- inline int ref_count(){ return data_.ref_count(); }
- Array3D subarray(int i0, int i1, int j0, int j1,
- int k0, int k1);
-};
-
-template <class T>
-Array3D<T>::Array3D() : data_(), v_(), m_(0), n_(0) {}
-
-template <class T>
-Array3D<T>::Array3D(const Array3D<T> &A) : data_(A.data_),
- v_(A.v_), m_(A.m_), n_(A.n_), g_(A.g_)
-{
-}
-
-
-
-template <class T>
-Array3D<T>::Array3D(int m, int n, int g) : data_(m*n*g), v_(m,n),
- m_(m), n_(n), g_(g)
-{
-
- if (m>0 && n>0 && g>0)
- {
- T* p = & (data_[0]);
- int ng = n_*g_;
-
- for (int i=0; i<m_; i++)
- {
- T* ping = p+ i*ng;
- for (int j=0; j<n; j++)
- v_[i][j] = ping + j*g_;
- }
- }
-}
-
-
-
-template <class T>
-Array3D<T>::Array3D(int m, int n, int g, T val) : data_(m*n*g, val),
- v_(m,n), m_(m), n_(n), g_(g)
-{
- if (m>0 && n>0 && g>0)
- {
-
- T* p = & (data_[0]);
- int ng = n_*g_;
-
- for (int i=0; i<m_; i++)
- {
- T* ping = p+ i*ng;
- for (int j=0; j<n; j++)
- v_[i][j] = ping + j*g_;
- }
- }
-}
-
-
-
-template <class T>
-Array3D<T>::Array3D(int m, int n, int g, T* a) :
- data_(m*n*g, a), v_(m,n), m_(m), n_(n), g_(g)
-{
-
- if (m>0 && n>0 && g>0)
- {
- T* p = & (data_[0]);
- int ng = n_*g_;
-
- for (int i=0; i<m_; i++)
- {
- T* ping = p+ i*ng;
- for (int j=0; j<n; j++)
- v_[i][j] = ping + j*g_;
- }
- }
-}
-
-
-
-template <class T>
-inline T** Array3D<T>::operator[](int i)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 0);
- assert(i < m_);
-#endif
-
-return v_[i];
-
-}
-
-template <class T>
-inline const T* const * Array3D<T>::operator[](int i) const
-{ return v_[i]; }
-
-template <class T>
-Array3D<T> & Array3D<T>::operator=(const T &a)
-{
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- for (int k=0; k<g_; k++)
- v_[i][j][k] = a;
-
- return *this;
-}
-
-template <class T>
-Array3D<T> Array3D<T>::copy() const
-{
- Array3D A(m_, n_, g_);
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- for (int k=0; k<g_; k++)
- A.v_[i][j][k] = v_[i][j][k];
-
- return A;
-}
-
-
-template <class T>
-Array3D<T> & Array3D<T>::inject(const Array3D &A)
-{
- if (A.m_ == m_ && A.n_ == n_ && A.g_ == g_)
-
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- for (int k=0; k<g_; k++)
- v_[i][j][k] = A.v_[i][j][k];
-
- return *this;
-}
-
-
-
-template <class T>
-Array3D<T> & Array3D<T>::ref(const Array3D<T> &A)
-{
- if (this != &A)
- {
- m_ = A.m_;
- n_ = A.n_;
- g_ = A.g_;
- v_ = A.v_;
- data_ = A.data_;
- }
- return *this;
-}
-
-template <class T>
-Array3D<T> & Array3D<T>::operator=(const Array3D<T> &A)
-{
- return ref(A);
-}
-
-
-template <class T>
-inline int Array3D<T>::dim1() const { return m_; }
-
-template <class T>
-inline int Array3D<T>::dim2() const { return n_; }
-
-template <class T>
-inline int Array3D<T>::dim3() const { return g_; }
-
-
-
-template <class T>
-Array3D<T>::~Array3D() {}
-
-template <class T>
-inline Array3D<T>::operator T***()
-{
- return v_;
-}
-
-
-template <class T>
-inline Array3D<T>::operator const T***()
-{
- return v_;
-}
-
-/* extended interface */
-template <class T>
-Array3D<T> Array3D<T>::subarray(int i0, int i1, int j0,
- int j1, int k0, int k1)
-{
-
- /* check that ranges are valid. */
- if (!( 0 <= i0 && i0 <= i1 && i1 < m_ &&
- 0 <= j0 && j0 <= j1 && j1 < n_ &&
- 0 <= k0 && k0 <= k1 && k1 < g_))
- return Array3D<T>(); /* null array */
-
-
- Array3D<T> A;
- A.data_ = data_;
- A.m_ = i1-i0+1;
- A.n_ = j1-j0+1;
- A.g_ = k1-k0+1;
- A.v_ = Array2D<T*>(A.m_,A.n_);
- T* p = &(data_[0]) + i0*n_*g_ + j0*g_ + k0;
-
- for (int i=0; i<A.m_; i++)
- {
- T* ping = p + i*n_*g_;
- for (int j=0; j<A.n_; j++)
- A.v_[i][j] = ping + j*g_ ;
- }
-
- return A;
-}
-
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_ARRAY3D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_array3d_utils.h b/intern/smoke/intern/tnt/tnt_array3d_utils.h
deleted file mode 100644
index cbc02365f9a..00000000000
--- a/intern/smoke/intern/tnt/tnt_array3d_utils.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-
-
-#ifndef TNT_ARRAY3D_UTILS_H
-#define TNT_ARRAY3D_UTILS_H
-
-#include <cstdlib>
-#include <cassert>
-
-namespace TNT
-{
-
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Array3D<T> &A)
-{
- int M=A.dim1();
- int N=A.dim2();
- int K=A.dim3();
-
- s << M << " " << N << " " << K << "\n";
-
- for (int i=0; i<M; i++)
- {
- for (int j=0; j<N; j++)
- {
- for (int k=0; k<K; k++)
- s << A[i][j][k] << " ";
- s << "\n";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Array3D<T> &A)
-{
-
- int M, N, K;
-
- s >> M >> N >> K;
-
- Array3D<T> B(M,N,K);
-
- for (int i=0; i<M; i++)
- for (int j=0; j<N; j++)
- for (int k=0; k<K; k++)
- s >> B[i][j][k];
-
- A = B;
- return s;
-}
-
-
-
-template <class T>
-Array3D<T> operator+(const Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Array3D<T>();
-
- else
- {
- Array3D<T> C(m,n,p);
-
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- C[i][j][k] = A[i][j][k] + B[i][j][k];
-
- return C;
- }
-}
-
-
-template <class T>
-Array3D<T> operator-(const Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Array3D<T>();
-
- else
- {
- Array3D<T> C(m,n,p);
-
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- C[i][j][k] = A[i][j][k] - B[i][j][k];
-
- return C;
- }
-}
-
-
-
-
-template <class T>
-Array3D<T> operator*(const Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Array3D<T>();
-
- else
- {
- Array3D<T> C(m,n,p);
-
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- C[i][j][k] = A[i][j][k] * B[i][j][k];
-
- return C;
- }
-}
-
-
-template <class T>
-Array3D<T> operator/(const Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Array3D<T>();
-
- else
- {
- Array3D<T> C(m,n,p);
-
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- C[i][j][k] = A[i][j][k] / B[i][j][k];
-
- return C;
- }
-}
-
-
-
-template <class T>
-Array3D<T>& operator+=(Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- A[i][j][k] += B[i][j][k];
- }
-
- return A;
-}
-
-template <class T>
-Array3D<T>& operator-=(Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- A[i][j][k] -= B[i][j][k];
- }
-
- return A;
-}
-
-template <class T>
-Array3D<T>& operator*=(Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- A[i][j][k] *= B[i][j][k];
- }
-
- return A;
-}
-
-
-template <class T>
-Array3D<T>& operator/=(Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- A[i][j][k] /= B[i][j][k];
- }
-
- return A;
-}
-
-
-
-
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_cmat.h b/intern/smoke/intern/tnt/tnt_cmat.h
deleted file mode 100644
index 34d5412a9b8..00000000000
--- a/intern/smoke/intern/tnt/tnt_cmat.h
+++ /dev/null
@@ -1,583 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-// C compatible matrix: row-oriented, 0-based [i][j] and 1-based (i,j) indexing
-//
-
-#ifndef TNT_CMAT_H
-#define TNT_CMAT_H
-
-#include "tnt_subscript.h"
-#include "tnt_vec.h"
-#include <cstdlib>
-#include <cassert>
-#include <iostream>
-#include <sstream>
-
-namespace TNT
-{
-
-
-template <class T>
-class Matrix
-{
-
-
- public:
-
- typedef Subscript size_type;
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- Subscript lbound() const { return 1;}
-
- protected:
- Subscript m_;
- Subscript n_;
- Subscript mn_; // total size
- T* v_;
- T** row_;
- T* vm1_ ; // these point to the same data, but are 1-based
- T** rowm1_;
-
- // internal helper function to create the array
- // of row pointers
-
- void initialize(Subscript M, Subscript N)
- {
- mn_ = M*N;
- m_ = M;
- n_ = N;
-
- v_ = new T[mn_];
- row_ = new T*[M];
- rowm1_ = new T*[M];
-
- assert(v_ != NULL);
- assert(row_ != NULL);
- assert(rowm1_ != NULL);
-
- T* p = v_;
- vm1_ = v_ - 1;
- for (Subscript i=0; i<M; i++)
- {
- row_[i] = p;
- rowm1_[i] = p-1;
- p += N ;
-
- }
-
- rowm1_ -- ; // compensate for 1-based offset
- }
-
- void copy(const T* v)
- {
- Subscript N = m_ * n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = v[i];
- v_[i+1] = v[i+1];
- v_[i+2] = v[i+2];
- v_[i+3] = v[i+3];
- }
-
- for (i=N4; i< N; i++)
- v_[i] = v[i];
-#else
-
- for (i=0; i< N; i++)
- v_[i] = v[i];
-#endif
- }
-
- void set(const T& val)
- {
- Subscript N = m_ * n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = val;
- v_[i+1] = val;
- v_[i+2] = val;
- v_[i+3] = val;
- }
-
- for (i=N4; i< N; i++)
- v_[i] = val;
-#else
-
- for (i=0; i< N; i++)
- v_[i] = val;
-
-#endif
- }
-
-
-
- void destroy()
- {
- /* do nothing, if no memory has been previously allocated */
- if (v_ == NULL) return ;
-
- /* if we are here, then matrix was previously allocated */
- if (v_ != NULL) delete [] (v_);
- if (row_ != NULL) delete [] (row_);
-
- /* return rowm1_ back to original value */
- rowm1_ ++;
- if (rowm1_ != NULL ) delete [] (rowm1_);
- }
-
-
- public:
-
- operator T**(){ return row_; }
- operator T**() const { return row_; }
-
-
- Subscript size() const { return mn_; }
-
- // constructors
-
- Matrix() : m_(0), n_(0), mn_(0), v_(0), row_(0), vm1_(0), rowm1_(0) {};
-
- Matrix(const Matrix<T> &A)
- {
- initialize(A.m_, A.n_);
- copy(A.v_);
- }
-
- Matrix(Subscript M, Subscript N, const T& value = T())
- {
- initialize(M,N);
- set(value);
- }
-
- Matrix(Subscript M, Subscript N, const T* v)
- {
- initialize(M,N);
- copy(v);
- }
-
- Matrix(Subscript M, Subscript N, const char *s)
- {
- initialize(M,N);
- //std::istrstream ins(s);
- std::istringstream ins(s);
-
- Subscript i, j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- ins >> row_[i][j];
- }
-
- // destructor
- //
- ~Matrix()
- {
- destroy();
- }
-
-
- // reallocating
- //
- Matrix<T>& newsize(Subscript M, Subscript N)
- {
- if (num_rows() == M && num_cols() == N)
- return *this;
-
- destroy();
- initialize(M,N);
-
- return *this;
- }
-
-
-
-
- // assignments
- //
- Matrix<T>& operator=(const Matrix<T> &A)
- {
- if (v_ == A.v_)
- return *this;
-
- if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc
- copy(A.v_);
-
- else
- {
- destroy();
- initialize(A.m_, A.n_);
- copy(A.v_);
- }
-
- return *this;
- }
-
- Matrix<T>& operator=(const T& scalar)
- {
- set(scalar);
- return *this;
- }
-
-
- Subscript dim(Subscript d) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( d >= 1);
- assert( d <= 2);
-#endif
- return (d==1) ? m_ : ((d==2) ? n_ : 0);
- }
-
- Subscript num_rows() const { return m_; }
- Subscript num_cols() const { return n_; }
-
-
-
-
- inline T* operator[](Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i < m_) ;
-#endif
- return row_[i];
- }
-
- inline const T* operator[](Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i < m_) ;
-#endif
- return row_[i];
- }
-
- inline reference operator()(Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= mn_) ;
-#endif
- return vm1_[i];
- }
-
- inline const_reference operator()(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= mn_) ;
-#endif
- return vm1_[i];
- }
-
-
-
- inline reference operator()(Subscript i, Subscript j)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= m_) ;
- assert(1<=j);
- assert(j <= n_);
-#endif
- return rowm1_[i][j];
- }
-
-
-
- inline const_reference operator() (Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= m_) ;
- assert(1<=j);
- assert(j <= n_);
-#endif
- return rowm1_[i][j];
- }
-
-
-
-
-};
-
-
-/* *************************** I/O ********************************/
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Matrix<T> &A)
-{
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- s << M << " " << N << "\n";
-
- for (Subscript i=0; i<M; i++)
- {
- for (Subscript j=0; j<N; j++)
- {
- s << A[i][j] << " ";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Matrix<T> &A)
-{
-
- Subscript M, N;
-
- s >> M >> N;
-
- if ( !(M == A.num_rows() && N == A.num_cols() ))
- {
- A.newsize(M,N);
- }
-
-
- for (Subscript i=0; i<M; i++)
- for (Subscript j=0; j<N; j++)
- {
- s >> A[i][j];
- }
-
-
- return s;
-}
-
-// *******************[ basic matrix algorithms ]***************************
-
-
-template <class T>
-Matrix<T> operator+(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- tmp[i][j] = A[i][j] + B[i][j];
-
- return tmp;
-}
-
-template <class T>
-Matrix<T> operator-(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- tmp[i][j] = A[i][j] - B[i][j];
-
- return tmp;
-}
-
-template <class T>
-Matrix<T> mult_element(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- tmp[i][j] = A[i][j] * B[i][j];
-
- return tmp;
-}
-
-
-template <class T>
-Matrix<T> transpose(const Matrix<T> &A)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- Matrix<T> S(N,M);
- Subscript i, j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- S[j][i] = A[i][j];
-
- return S;
-}
-
-
-
-template <class T>
-inline Matrix<T> matmult(const Matrix<T> &A,
- const Matrix<T> &B)
-{
-
-#ifdef TNT_BOUNDS_CHECK
- assert(A.num_cols() == B.num_rows());
-#endif
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
- Subscript K = B.num_cols();
-
- Matrix<T> tmp(M,K);
- T sum;
-
- for (Subscript i=0; i<M; i++)
- for (Subscript k=0; k<K; k++)
- {
- sum = 0;
- for (Subscript j=0; j<N; j++)
- sum = sum + A[i][j] * B[j][k];
-
- tmp[i][k] = sum;
- }
-
- return tmp;
-}
-
-template <class T>
-inline Matrix<T> operator*(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- return matmult(A,B);
-}
-
-template <class T>
-inline int matmult(Matrix<T>& C, const Matrix<T> &A,
- const Matrix<T> &B)
-{
-
- assert(A.num_cols() == B.num_rows());
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
- Subscript K = B.num_cols();
-
- C.newsize(M,K);
-
- T sum;
-
- const T* row_i;
- const T* col_k;
-
- for (Subscript i=0; i<M; i++)
- for (Subscript k=0; k<K; k++)
- {
- row_i = &(A[i][0]);
- col_k = &(B[0][k]);
- sum = 0;
- for (Subscript j=0; j<N; j++)
- {
- sum += *row_i * *col_k;
- row_i++;
- col_k += K;
- }
- C[i][k] = sum;
- }
-
- return 0;
-}
-
-
-template <class T>
-Vector<T> matmult(const Matrix<T> &A, const Vector<T> &x)
-{
-
-#ifdef TNT_BOUNDS_CHECK
- assert(A.num_cols() == x.dim());
-#endif
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- Vector<T> tmp(M);
- T sum;
-
- for (Subscript i=0; i<M; i++)
- {
- sum = 0;
- const T* rowi = A[i];
- for (Subscript j=0; j<N; j++)
- sum = sum + rowi[j] * x[j];
-
- tmp[i] = sum;
- }
-
- return tmp;
-}
-
-template <class T>
-inline Vector<T> operator*(const Matrix<T> &A, const Vector<T> &x)
-{
- return matmult(A,x);
-}
-
-} // namespace TNT
-
-#endif
-// CMAT_H
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array1d.h b/intern/smoke/intern/tnt/tnt_fortran_array1d.h
deleted file mode 100644
index 45a764cf3e0..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array1d.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_FORTRAN_ARRAY1D_H
-#define TNT_FORTRAN_ARRAY1D_H
-
-#include <cstdlib>
-#include <iostream>
-
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-
-#include "tnt_i_refvec.h"
-
-namespace TNT
-{
-
-template <class T>
-class Fortran_Array1D
-{
-
- private:
-
- i_refvec<T> v_;
- int n_;
- T* data_; /* this normally points to v_.begin(), but
- * could also point to a portion (subvector)
- * of v_.
- */
-
- void initialize_(int n);
- void copy_(T* p, const T* q, int len) const;
- void set_(T* begin, T* end, const T& val);
-
-
- public:
-
- typedef T value_type;
-
-
- Fortran_Array1D();
- explicit Fortran_Array1D(int n);
- Fortran_Array1D(int n, const T &a);
- Fortran_Array1D(int n, T *a);
- inline Fortran_Array1D(const Fortran_Array1D &A);
- inline Fortran_Array1D & operator=(const T &a);
- inline Fortran_Array1D & operator=(const Fortran_Array1D &A);
- inline Fortran_Array1D & ref(const Fortran_Array1D &A);
- Fortran_Array1D copy() const;
- Fortran_Array1D & inject(const Fortran_Array1D & A);
- inline T& operator()(int i);
- inline const T& operator()(int i) const;
- inline int dim1() const;
- inline int dim() const;
- ~Fortran_Array1D();
-
-
- /* ... extended interface ... */
-
- inline int ref_count() const;
- inline Fortran_Array1D<T> subarray(int i0, int i1);
-
-};
-
-
-
-
-template <class T>
-Fortran_Array1D<T>::Fortran_Array1D() : v_(), n_(0), data_(0) {}
-
-template <class T>
-Fortran_Array1D<T>::Fortran_Array1D(const Fortran_Array1D<T> &A) : v_(A.v_), n_(A.n_),
- data_(A.data_)
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Fortran_Array1D(const Fortran_Array1D<T> &A) \n";
-#endif
-
-}
-
-
-template <class T>
-Fortran_Array1D<T>::Fortran_Array1D(int n) : v_(n), n_(n), data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Fortran_Array1D(int n) \n";
-#endif
-}
-
-template <class T>
-Fortran_Array1D<T>::Fortran_Array1D(int n, const T &val) : v_(n), n_(n), data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Fortran_Array1D(int n, const T& val) \n";
-#endif
- set_(data_, data_+ n, val);
-
-}
-
-template <class T>
-Fortran_Array1D<T>::Fortran_Array1D(int n, T *a) : v_(a), n_(n) , data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Fortran_Array1D(int n, T* a) \n";
-#endif
-}
-
-template <class T>
-inline T& Fortran_Array1D<T>::operator()(int i)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i>= 1);
- assert(i <= n_);
-#endif
- return data_[i-1];
-}
-
-template <class T>
-inline const T& Fortran_Array1D<T>::operator()(int i) const
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i>= 1);
- assert(i <= n_);
-#endif
- return data_[i-1];
-}
-
-
-
-
-template <class T>
-Fortran_Array1D<T> & Fortran_Array1D<T>::operator=(const T &a)
-{
- set_(data_, data_+n_, a);
- return *this;
-}
-
-template <class T>
-Fortran_Array1D<T> Fortran_Array1D<T>::copy() const
-{
- Fortran_Array1D A( n_);
- copy_(A.data_, data_, n_);
-
- return A;
-}
-
-
-template <class T>
-Fortran_Array1D<T> & Fortran_Array1D<T>::inject(const Fortran_Array1D &A)
-{
- if (A.n_ == n_)
- copy_(data_, A.data_, n_);
-
- return *this;
-}
-
-
-
-
-
-template <class T>
-Fortran_Array1D<T> & Fortran_Array1D<T>::ref(const Fortran_Array1D<T> &A)
-{
- if (this != &A)
- {
- v_ = A.v_; /* operator= handles the reference counting. */
- n_ = A.n_;
- data_ = A.data_;
-
- }
- return *this;
-}
-
-template <class T>
-Fortran_Array1D<T> & Fortran_Array1D<T>::operator=(const Fortran_Array1D<T> &A)
-{
- return ref(A);
-}
-
-template <class T>
-inline int Fortran_Array1D<T>::dim1() const { return n_; }
-
-template <class T>
-inline int Fortran_Array1D<T>::dim() const { return n_; }
-
-template <class T>
-Fortran_Array1D<T>::~Fortran_Array1D() {}
-
-
-/* ............................ exented interface ......................*/
-
-template <class T>
-inline int Fortran_Array1D<T>::ref_count() const
-{
- return v_.ref_count();
-}
-
-template <class T>
-inline Fortran_Array1D<T> Fortran_Array1D<T>::subarray(int i0, int i1)
-{
-#ifdef TNT_DEBUG
- std::cout << "entered subarray. \n";
-#endif
- if ((i0 > 0) && (i1 < n_) || (i0 <= i1))
- {
- Fortran_Array1D<T> X(*this); /* create a new instance of this array. */
- X.n_ = i1-i0+1;
- X.data_ += i0;
-
- return X;
- }
- else
- {
-#ifdef TNT_DEBUG
- std::cout << "subarray: null return.\n";
-#endif
- return Fortran_Array1D<T>();
- }
-}
-
-
-/* private internal functions */
-
-
-template <class T>
-void Fortran_Array1D<T>::set_(T* begin, T* end, const T& a)
-{
- for (T* p=begin; p<end; p++)
- *p = a;
-
-}
-
-template <class T>
-void Fortran_Array1D<T>::copy_(T* p, const T* q, int len) const
-{
- T *end = p + len;
- while (p<end )
- *p++ = *q++;
-
-}
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_FORTRAN_ARRAY1D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array1d_utils.h b/intern/smoke/intern/tnt/tnt_fortran_array1d_utils.h
deleted file mode 100644
index f06b33f1910..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array1d_utils.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-#ifndef TNT_FORTRAN_ARRAY1D_UTILS_H
-#define TNT_FORTRAN_ARRAY1D_UTILS_H
-
-#include <iostream>
-
-namespace TNT
-{
-
-
-/**
- Write an array to a character outstream. Output format is one that can
- be read back in via the in-stream operator: one integer
- denoting the array dimension (n), followed by n elements,
- one per line.
-
-*/
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Fortran_Array1D<T> &A)
-{
- int N=A.dim1();
-
- s << N << "\n";
- for (int j=1; j<=N; j++)
- {
- s << A(j) << "\n";
- }
- s << "\n";
-
- return s;
-}
-
-/**
- Read an array from a character stream. Input format
- is one integer, denoting the dimension (n), followed
- by n whitespace-separated elments. Newlines are ignored
-
- <p>
- Note: the array being read into references new memory
- storage. If the intent is to fill an existing conformant
- array, use <code> cin >> B; A.inject(B) ); </code>
- instead or read the elements in one-a-time by hand.
-
- @param s the charater to read from (typically <code>std::in</code>)
- @param A the array to read into.
-*/
-template <class T>
-std::istream& operator>>(std::istream &s, Fortran_Array1D<T> &A)
-{
- int N;
- s >> N;
-
- Fortran_Array1D<T> B(N);
- for (int i=1; i<=N; i++)
- s >> B(i);
- A = B;
- return s;
-}
-
-
-template <class T>
-Fortran_Array1D<T> operator+(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Fortran_Array1D<T>();
-
- else
- {
- Fortran_Array1D<T> C(n);
-
- for (int i=1; i<=n; i++)
- {
- C(i) = A(i) + B(i);
- }
- return C;
- }
-}
-
-
-
-template <class T>
-Fortran_Array1D<T> operator-(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Fortran_Array1D<T>();
-
- else
- {
- Fortran_Array1D<T> C(n);
-
- for (int i=1; i<=n; i++)
- {
- C(i) = A(i) - B(i);
- }
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array1D<T> operator*(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Fortran_Array1D<T>();
-
- else
- {
- Fortran_Array1D<T> C(n);
-
- for (int i=1; i<=n; i++)
- {
- C(i) = A(i) * B(i);
- }
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array1D<T> operator/(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Fortran_Array1D<T>();
-
- else
- {
- Fortran_Array1D<T> C(n);
-
- for (int i=1; i<=n; i++)
- {
- C(i) = A(i) / B(i);
- }
- return C;
- }
-}
-
-
-
-
-
-
-
-
-
-template <class T>
-Fortran_Array1D<T>& operator+=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=1; i<=n; i++)
- {
- A(i) += B(i);
- }
- }
- return A;
-}
-
-
-
-
-template <class T>
-Fortran_Array1D<T>& operator-=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=1; i<=n; i++)
- {
- A(i) -= B(i);
- }
- }
- return A;
-}
-
-
-
-template <class T>
-Fortran_Array1D<T>& operator*=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=1; i<=n; i++)
- {
- A(i) *= B(i);
- }
- }
- return A;
-}
-
-
-
-
-template <class T>
-Fortran_Array1D<T>& operator/=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=1; i<=n; i++)
- {
- A(i) /= B(i);
- }
- }
- return A;
-}
-
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array2d.h b/intern/smoke/intern/tnt/tnt_fortran_array2d.h
deleted file mode 100644
index 7f14d5436e9..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array2d.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT): Two-dimensional Fortran numerical array
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_FORTRAN_ARRAY2D_H
-#define TNT_FORTRAN_ARRAY2D_H
-
-#include <cstdlib>
-#include <iostream>
-
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-#include "tnt_i_refvec.h"
-
-namespace TNT
-{
-
-template <class T>
-class Fortran_Array2D
-{
-
-
- private:
- i_refvec<T> v_;
- int m_;
- int n_;
- T* data_;
-
-
- void initialize_(int n);
- void copy_(T* p, const T* q, int len);
- void set_(T* begin, T* end, const T& val);
-
- public:
-
- typedef T value_type;
-
- Fortran_Array2D();
- Fortran_Array2D(int m, int n);
- Fortran_Array2D(int m, int n, T *a);
- Fortran_Array2D(int m, int n, const T &a);
- inline Fortran_Array2D(const Fortran_Array2D &A);
- inline Fortran_Array2D & operator=(const T &a);
- inline Fortran_Array2D & operator=(const Fortran_Array2D &A);
- inline Fortran_Array2D & ref(const Fortran_Array2D &A);
- Fortran_Array2D copy() const;
- Fortran_Array2D & inject(const Fortran_Array2D & A);
- inline T& operator()(int i, int j);
- inline const T& operator()(int i, int j) const ;
- inline int dim1() const;
- inline int dim2() const;
- ~Fortran_Array2D();
-
- /* extended interface */
-
- inline int ref_count() const;
-
-};
-
-template <class T>
-Fortran_Array2D<T>::Fortran_Array2D() : v_(), m_(0), n_(0), data_(0) {}
-
-
-template <class T>
-Fortran_Array2D<T>::Fortran_Array2D(const Fortran_Array2D<T> &A) : v_(A.v_),
- m_(A.m_), n_(A.n_), data_(A.data_) {}
-
-
-
-template <class T>
-Fortran_Array2D<T>::Fortran_Array2D(int m, int n) : v_(m*n), m_(m), n_(n),
- data_(v_.begin()) {}
-
-template <class T>
-Fortran_Array2D<T>::Fortran_Array2D(int m, int n, const T &val) :
- v_(m*n), m_(m), n_(n), data_(v_.begin())
-{
- set_(data_, data_+m*n, val);
-}
-
-
-template <class T>
-Fortran_Array2D<T>::Fortran_Array2D(int m, int n, T *a) : v_(a),
- m_(m), n_(n), data_(v_.begin()) {}
-
-
-
-
-template <class T>
-inline T& Fortran_Array2D<T>::operator()(int i, int j)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 1);
- assert(i <= m_);
- assert(j >= 1);
- assert(j <= n_);
-#endif
-
- return v_[ (j-1)*m_ + (i-1) ];
-
-}
-
-template <class T>
-inline const T& Fortran_Array2D<T>::operator()(int i, int j) const
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 1);
- assert(i <= m_);
- assert(j >= 1);
- assert(j <= n_);
-#endif
-
- return v_[ (j-1)*m_ + (i-1) ];
-
-}
-
-
-template <class T>
-Fortran_Array2D<T> & Fortran_Array2D<T>::operator=(const T &a)
-{
- set_(data_, data_+m_*n_, a);
- return *this;
-}
-
-template <class T>
-Fortran_Array2D<T> Fortran_Array2D<T>::copy() const
-{
-
- Fortran_Array2D B(m_,n_);
-
- B.inject(*this);
- return B;
-}
-
-
-template <class T>
-Fortran_Array2D<T> & Fortran_Array2D<T>::inject(const Fortran_Array2D &A)
-{
- if (m_ == A.m_ && n_ == A.n_)
- copy_(data_, A.data_, m_*n_);
-
- return *this;
-}
-
-
-
-template <class T>
-Fortran_Array2D<T> & Fortran_Array2D<T>::ref(const Fortran_Array2D<T> &A)
-{
- if (this != &A)
- {
- v_ = A.v_;
- m_ = A.m_;
- n_ = A.n_;
- data_ = A.data_;
- }
- return *this;
-}
-
-template <class T>
-Fortran_Array2D<T> & Fortran_Array2D<T>::operator=(const Fortran_Array2D<T> &A)
-{
- return ref(A);
-}
-
-template <class T>
-inline int Fortran_Array2D<T>::dim1() const { return m_; }
-
-template <class T>
-inline int Fortran_Array2D<T>::dim2() const { return n_; }
-
-
-template <class T>
-Fortran_Array2D<T>::~Fortran_Array2D()
-{
-}
-
-template <class T>
-inline int Fortran_Array2D<T>::ref_count() const { return v_.ref_count(); }
-
-
-
-
-template <class T>
-void Fortran_Array2D<T>::set_(T* begin, T* end, const T& a)
-{
- for (T* p=begin; p<end; p++)
- *p = a;
-
-}
-
-template <class T>
-void Fortran_Array2D<T>::copy_(T* p, const T* q, int len)
-{
- T *end = p + len;
- while (p<end )
- *p++ = *q++;
-
-}
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_FORTRAN_ARRAY2D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array2d_utils.h b/intern/smoke/intern/tnt/tnt_fortran_array2d_utils.h
deleted file mode 100644
index 078d34c087e..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array2d_utils.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_FORTRAN_ARRAY2D_UTILS_H
-#define TNT_FORTRAN_ARRAY2D_UTILS_H
-
-#include <iostream>
-
-namespace TNT
-{
-
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Fortran_Array2D<T> &A)
-{
- int M=A.dim1();
- int N=A.dim2();
-
- s << M << " " << N << "\n";
-
- for (int i=1; i<=M; i++)
- {
- for (int j=1; j<=N; j++)
- {
- s << A(i,j) << " ";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Fortran_Array2D<T> &A)
-{
-
- int M, N;
-
- s >> M >> N;
-
- Fortran_Array2D<T> B(M,N);
-
- for (int i=1; i<=M; i++)
- for (int j=1; j<=N; j++)
- {
- s >> B(i,j);
- }
-
- A = B;
- return s;
-}
-
-
-
-
-template <class T>
-Fortran_Array2D<T> operator+(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Fortran_Array2D<T>();
-
- else
- {
- Fortran_Array2D<T> C(m,n);
-
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- C(i,j) = A(i,j) + B(i,j);
- }
- return C;
- }
-}
-
-template <class T>
-Fortran_Array2D<T> operator-(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Fortran_Array2D<T>();
-
- else
- {
- Fortran_Array2D<T> C(m,n);
-
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- C(i,j) = A(i,j) - B(i,j);
- }
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array2D<T> operator*(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Fortran_Array2D<T>();
-
- else
- {
- Fortran_Array2D<T> C(m,n);
-
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- C(i,j) = A(i,j) * B(i,j);
- }
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array2D<T> operator/(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Fortran_Array2D<T>();
-
- else
- {
- Fortran_Array2D<T> C(m,n);
-
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- C(i,j) = A(i,j) / B(i,j);
- }
- return C;
- }
-}
-
-
-
-template <class T>
-Fortran_Array2D<T>& operator+=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- A(i,j) += B(i,j);
- }
- }
- return A;
-}
-
-template <class T>
-Fortran_Array2D<T>& operator-=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- A(i,j) -= B(i,j);
- }
- }
- return A;
-}
-
-template <class T>
-Fortran_Array2D<T>& operator*=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- A(i,j) *= B(i,j);
- }
- }
- return A;
-}
-
-template <class T>
-Fortran_Array2D<T>& operator/=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- A(i,j) /= B(i,j);
- }
- }
- return A;
-}
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array3d.h b/intern/smoke/intern/tnt/tnt_fortran_array3d.h
deleted file mode 100644
index ee3de255a15..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array3d.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT): Three-dimensional Fortran numerical array
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_FORTRAN_ARRAY3D_H
-#define TNT_FORTRAN_ARRAY3D_H
-
-#include <cstdlib>
-#include <iostream>
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-#include "tnt_i_refvec.h"
-
-namespace TNT
-{
-
-template <class T>
-class Fortran_Array3D
-{
-
-
- private:
-
-
- i_refvec<T> v_;
- int m_;
- int n_;
- int k_;
- T* data_;
-
- public:
-
- typedef T value_type;
-
- Fortran_Array3D();
- Fortran_Array3D(int m, int n, int k);
- Fortran_Array3D(int m, int n, int k, T *a);
- Fortran_Array3D(int m, int n, int k, const T &a);
- inline Fortran_Array3D(const Fortran_Array3D &A);
- inline Fortran_Array3D & operator=(const T &a);
- inline Fortran_Array3D & operator=(const Fortran_Array3D &A);
- inline Fortran_Array3D & ref(const Fortran_Array3D &A);
- Fortran_Array3D copy() const;
- Fortran_Array3D & inject(const Fortran_Array3D & A);
- inline T& operator()(int i, int j, int k);
- inline const T& operator()(int i, int j, int k) const ;
- inline int dim1() const;
- inline int dim2() const;
- inline int dim3() const;
- inline int ref_count() const;
- ~Fortran_Array3D();
-
-
-};
-
-template <class T>
-Fortran_Array3D<T>::Fortran_Array3D() : v_(), m_(0), n_(0), k_(0), data_(0) {}
-
-
-template <class T>
-Fortran_Array3D<T>::Fortran_Array3D(const Fortran_Array3D<T> &A) :
- v_(A.v_), m_(A.m_), n_(A.n_), k_(A.k_), data_(A.data_) {}
-
-
-
-template <class T>
-Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k) :
- v_(m*n*k), m_(m), n_(n), k_(k), data_(v_.begin()) {}
-
-
-
-template <class T>
-Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k, const T &val) :
- v_(m*n*k), m_(m), n_(n), k_(k), data_(v_.begin())
-{
- for (T* p = data_; p < data_ + m*n*k; p++)
- *p = val;
-}
-
-template <class T>
-Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k, T *a) :
- v_(a), m_(m), n_(n), k_(k), data_(v_.begin()) {}
-
-
-
-
-template <class T>
-inline T& Fortran_Array3D<T>::operator()(int i, int j, int k)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 1);
- assert(i <= m_);
- assert(j >= 1);
- assert(j <= n_);
- assert(k >= 1);
- assert(k <= k_);
-#endif
-
- return data_[(k-1)*m_*n_ + (j-1) * m_ + i-1];
-
-}
-
-template <class T>
-inline const T& Fortran_Array3D<T>::operator()(int i, int j, int k) const
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 1);
- assert(i <= m_);
- assert(j >= 1);
- assert(j <= n_);
- assert(k >= 1);
- assert(k <= k_);
-#endif
-
- return data_[(k-1)*m_*n_ + (j-1) * m_ + i-1];
-}
-
-
-template <class T>
-Fortran_Array3D<T> & Fortran_Array3D<T>::operator=(const T &a)
-{
-
- T *end = data_ + m_*n_*k_;
-
- for (T *p=data_; p != end; *p++ = a);
-
- return *this;
-}
-
-template <class T>
-Fortran_Array3D<T> Fortran_Array3D<T>::copy() const
-{
-
- Fortran_Array3D B(m_, n_, k_);
- B.inject(*this);
- return B;
-
-}
-
-
-template <class T>
-Fortran_Array3D<T> & Fortran_Array3D<T>::inject(const Fortran_Array3D &A)
-{
-
- if (m_ == A.m_ && n_ == A.n_ && k_ == A.k_)
- {
- T *p = data_;
- T *end = data_ + m_*n_*k_;
- const T* q = A.data_;
- for (; p < end; *p++ = *q++);
- }
- return *this;
-}
-
-
-
-
-template <class T>
-Fortran_Array3D<T> & Fortran_Array3D<T>::ref(const Fortran_Array3D<T> &A)
-{
-
- if (this != &A)
- {
- v_ = A.v_;
- m_ = A.m_;
- n_ = A.n_;
- k_ = A.k_;
- data_ = A.data_;
- }
- return *this;
-}
-
-template <class T>
-Fortran_Array3D<T> & Fortran_Array3D<T>::operator=(const Fortran_Array3D<T> &A)
-{
- return ref(A);
-}
-
-template <class T>
-inline int Fortran_Array3D<T>::dim1() const { return m_; }
-
-template <class T>
-inline int Fortran_Array3D<T>::dim2() const { return n_; }
-
-template <class T>
-inline int Fortran_Array3D<T>::dim3() const { return k_; }
-
-
-template <class T>
-inline int Fortran_Array3D<T>::ref_count() const
-{
- return v_.ref_count();
-}
-
-template <class T>
-Fortran_Array3D<T>::~Fortran_Array3D()
-{
-}
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_FORTRAN_ARRAY3D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array3d_utils.h b/intern/smoke/intern/tnt/tnt_fortran_array3d_utils.h
deleted file mode 100644
index d337932380b..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array3d_utils.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_FORTRAN_ARRAY3D_UTILS_H
-#define TNT_FORTRAN_ARRAY3D_UTILS_H
-
-#include <cstdlib>
-#include <cassert>
-
-namespace TNT
-{
-
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Fortran_Array3D<T> &A)
-{
- int M=A.dim1();
- int N=A.dim2();
- int K=A.dim3();
-
- s << M << " " << N << " " << K << "\n";
-
- for (int i=1; i<=M; i++)
- {
- for (int j=1; j<=N; j++)
- {
- for (int k=1; k<=K; k++)
- s << A(i,j,k) << " ";
- s << "\n";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Fortran_Array3D<T> &A)
-{
-
- int M, N, K;
-
- s >> M >> N >> K;
-
- Fortran_Array3D<T> B(M,N,K);
-
- for (int i=1; i<=M; i++)
- for (int j=1; j<=N; j++)
- for (int k=1; k<=K; k++)
- s >> B(i,j,k);
-
- A = B;
- return s;
-}
-
-
-template <class T>
-Fortran_Array3D<T> operator+(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Fortran_Array3D<T>();
-
- else
- {
- Fortran_Array3D<T> C(m,n,p);
-
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- C(i,j,k) = A(i,j,k)+ B(i,j,k);
-
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array3D<T> operator-(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Fortran_Array3D<T>();
-
- else
- {
- Fortran_Array3D<T> C(m,n,p);
-
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- C(i,j,k) = A(i,j,k)- B(i,j,k);
-
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array3D<T> operator*(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Fortran_Array3D<T>();
-
- else
- {
- Fortran_Array3D<T> C(m,n,p);
-
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- C(i,j,k) = A(i,j,k)* B(i,j,k);
-
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array3D<T> operator/(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Fortran_Array3D<T>();
-
- else
- {
- Fortran_Array3D<T> C(m,n,p);
-
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- C(i,j,k) = A(i,j,k)/ B(i,j,k);
-
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array3D<T>& operator+=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- A(i,j,k) += B(i,j,k);
- }
-
- return A;
-}
-
-
-template <class T>
-Fortran_Array3D<T>& operator-=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- A(i,j,k) -= B(i,j,k);
- }
-
- return A;
-}
-
-
-template <class T>
-Fortran_Array3D<T>& operator*=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- A(i,j,k) *= B(i,j,k);
- }
-
- return A;
-}
-
-
-template <class T>
-Fortran_Array3D<T>& operator/=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- A(i,j,k) /= B(i,j,k);
- }
-
- return A;
-}
-
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_i_refvec.h b/intern/smoke/intern/tnt/tnt_i_refvec.h
deleted file mode 100644
index eaf8a4d0e68..00000000000
--- a/intern/smoke/intern/tnt/tnt_i_refvec.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_I_REFVEC_H
-#define TNT_I_REFVEC_H
-
-#include <cstdlib>
-#include <iostream>
-
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-namespace TNT
-{
-/*
- Internal representation of ref-counted array. The TNT
- arrays all use this building block.
-
- <p>
- If an array block is created by TNT, then every time
- an assignment is made, the left-hand-side reference
- is decreased by one, and the right-hand-side refernce
- count is increased by one. If the array block was
- external to TNT, the refernce count is a NULL pointer
- regardless of how many references are made, since the
- memory is not freed by TNT.
-
-
-
-*/
-template <class T>
-class i_refvec
-{
-
-
- private:
- T* data_;
- int *ref_count_;
-
-
- public:
-
- i_refvec();
- explicit i_refvec(int n);
- inline i_refvec(T* data);
- inline i_refvec(const i_refvec &v);
- inline T* begin();
- inline const T* begin() const;
- inline T& operator[](int i);
- inline const T& operator[](int i) const;
- inline i_refvec<T> & operator=(const i_refvec<T> &V);
- void copy_(T* p, const T* q, const T* e);
- void set_(T* p, const T* b, const T* e);
- inline int ref_count() const;
- inline int is_null() const;
- inline void destroy();
- ~i_refvec();
-
-};
-
-template <class T>
-void i_refvec<T>::copy_(T* p, const T* q, const T* e)
-{
- for (T* t=p; q<e; t++, q++)
- *t= *q;
-}
-
-template <class T>
-i_refvec<T>::i_refvec() : data_(NULL), ref_count_(NULL) {}
-
-/**
- In case n is 0 or negative, it does NOT call new.
-*/
-template <class T>
-i_refvec<T>::i_refvec(int n) : data_(NULL), ref_count_(NULL)
-{
- if (n >= 1)
- {
-#ifdef TNT_DEBUG
- std::cout << "new data storage.\n";
-#endif
- data_ = new T[n];
- ref_count_ = new int;
- *ref_count_ = 1;
- }
-}
-
-template <class T>
-inline i_refvec<T>::i_refvec(const i_refvec<T> &V): data_(V.data_),
- ref_count_(V.ref_count_)
-{
- if (V.ref_count_ != NULL)
- (*(V.ref_count_))++;
-}
-
-
-template <class T>
-i_refvec<T>::i_refvec(T* data) : data_(data), ref_count_(NULL) {}
-
-template <class T>
-inline T* i_refvec<T>::begin()
-{
- return data_;
-}
-
-template <class T>
-inline const T& i_refvec<T>::operator[](int i) const
-{
- return data_[i];
-}
-
-template <class T>
-inline T& i_refvec<T>::operator[](int i)
-{
- return data_[i];
-}
-
-
-template <class T>
-inline const T* i_refvec<T>::begin() const
-{
- return data_;
-}
-
-
-
-template <class T>
-i_refvec<T> & i_refvec<T>::operator=(const i_refvec<T> &V)
-{
- if (this == &V)
- return *this;
-
-
- if (ref_count_ != NULL)
- {
- (*ref_count_) --;
- if ((*ref_count_) == 0)
- destroy();
- }
-
- data_ = V.data_;
- ref_count_ = V.ref_count_;
-
- if (V.ref_count_ != NULL)
- (*(V.ref_count_))++;
-
- return *this;
-}
-
-template <class T>
-void i_refvec<T>::destroy()
-{
- if (ref_count_ != NULL)
- {
-#ifdef TNT_DEBUG
- std::cout << "destorying data... \n";
-#endif
- delete ref_count_;
-
-#ifdef TNT_DEBUG
- std::cout << "deleted ref_count_ ...\n";
-#endif
- if (data_ != NULL)
- delete []data_;
-#ifdef TNT_DEBUG
- std::cout << "deleted data_[] ...\n";
-#endif
- data_ = NULL;
- }
-}
-
-/*
-* return 1 is vector is empty, 0 otherwise
-*
-* if is_null() is false and ref_count() is 0, then
-*
-*/
-template<class T>
-int i_refvec<T>::is_null() const
-{
- return (data_ == NULL ? 1 : 0);
-}
-
-/*
-* returns -1 if data is external,
-* returns 0 if a is NULL array,
-* otherwise returns the positive number of vectors sharing
-* this data space.
-*/
-template <class T>
-int i_refvec<T>::ref_count() const
-{
- if (data_ == NULL)
- return 0;
- else
- return (ref_count_ != NULL ? *ref_count_ : -1) ;
-}
-
-template <class T>
-i_refvec<T>::~i_refvec()
-{
- if (ref_count_ != NULL)
- {
- (*ref_count_)--;
-
- if (*ref_count_ == 0)
- destroy();
- }
-}
-
-
-} /* namespace TNT */
-
-
-
-
-
-#endif
-/* TNT_I_REFVEC_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_math_utils.h b/intern/smoke/intern/tnt/tnt_math_utils.h
deleted file mode 100644
index ed4a3b7f78f..00000000000
--- a/intern/smoke/intern/tnt/tnt_math_utils.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-#ifndef MATH_UTILS_H
-#define MATH_UTILS_H
-
-/* needed for fabs, sqrt() below */
-#include <cmath>
-
-namespace TNT
-{
-/**
- @returns hypotenuse of real (non-complex) scalars a and b by
- avoiding underflow/overflow
- using (a * sqrt( 1 + (b/a) * (b/a))), rather than
- sqrt(a*a + b*b).
-*/
-template <class Real>
-Real hypot(const Real &a, const Real &b)
-{
-
- if (a== 0)
- return fabs(b);
- else
- {
- Real c = b/a;
- return fabs(a) * sqrt(1 + c*c);
- }
-}
-} /* TNT namespace */
-
-
-
-#endif
-/* MATH_UTILS_H */
diff --git a/intern/smoke/intern/tnt/tnt_sparse_matrix_csr.h b/intern/smoke/intern/tnt/tnt_sparse_matrix_csr.h
deleted file mode 100644
index 61d52542641..00000000000
--- a/intern/smoke/intern/tnt/tnt_sparse_matrix_csr.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_SPARSE_MATRIX_CSR_H
-#define TNT_SPARSE_MATRIX_CSR_H
-
-#include "tnt_array1d.h"
-
-namespace TNT
-{
-
-
-/**
- Read-only view of a sparse matrix in compressed-row storage
- format. Neither array elements (nonzeros) nor sparsity
- structure can be modified. If modifications are required,
- create a new view.
-
- <p>
- Index values begin at 0.
-
- <p>
- <b>Storage requirements:</b> An (m x n) matrix with
- nz nonzeros requires no more than ((T+I)*nz + M*I)
- bytes, where T is the size of data elements and
- I is the size of integers.
-
-
-*/
-template <class T>
-class Sparse_Matrix_CompRow {
-
-private:
- Array1D<T> val_; // data values (nz_ elements)
- Array1D<int> rowptr_; // row_ptr (dim_[0]+1 elements)
- Array1D<int> colind_; // col_ind (nz_ elements)
-
- int dim1_; // number of rows
- int dim2_; // number of cols
-
-public:
-
- Sparse_Matrix_CompRow(const Sparse_Matrix_CompRow &S);
- Sparse_Matrix_CompRow(int M, int N, int nz, const T *val,
- const int *r, const int *c);
-
-
-
- inline const T& val(int i) const { return val_[i]; }
- inline const int& row_ptr(int i) const { return rowptr_[i]; }
- inline const int& col_ind(int i) const { return colind_[i];}
-
- inline int dim1() const {return dim1_;}
- inline int dim2() const {return dim2_;}
- int NumNonzeros() const {return val_.dim1();}
-
-
- Sparse_Matrix_CompRow& operator=(
- const Sparse_Matrix_CompRow &R);
-
-
-
-};
-
-/**
- Construct a read-only view of existing sparse matrix in
- compressed-row storage format.
-
- @param M the number of rows of sparse matrix
- @param N the number of columns of sparse matrix
- @param nz the number of nonzeros
- @param val a contiguous list of nonzero values
- @param r row-pointers: r[i] denotes the begining position of row i
- (i.e. the ith row begins at val[row[i]]).
- @param c column-indices: c[i] denotes the column location of val[i]
-*/
-template <class T>
-Sparse_Matrix_CompRow<T>::Sparse_Matrix_CompRow(int M, int N, int nz,
- const T *val, const int *r, const int *c) : val_(nz,val),
- rowptr_(M, r), colind_(nz, c), dim1_(M), dim2_(N) {}
-
-
-}
-// namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_stopwatch.h b/intern/smoke/intern/tnt/tnt_stopwatch.h
deleted file mode 100644
index a4eb09acbc4..00000000000
--- a/intern/smoke/intern/tnt/tnt_stopwatch.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef STOPWATCH_H
-#define STOPWATCH_H
-
-// for clock() and CLOCKS_PER_SEC
-#include <time.h>
-
-
-namespace TNT
-{
-
-inline static double seconds(void)
-{
- const double secs_per_tick = 1.0 / CLOCKS_PER_SEC;
- return ( (double) clock() ) * secs_per_tick;
-}
-
-class Stopwatch {
- private:
- int running_;
- double start_time_;
- double total_;
-
- public:
- inline Stopwatch();
- inline void start();
- inline double stop();
- inline double read();
- inline void resume();
- inline int running();
-};
-
-inline Stopwatch::Stopwatch() : running_(0), start_time_(0.0), total_(0.0) {}
-
-void Stopwatch::start()
-{
- running_ = 1;
- total_ = 0.0;
- start_time_ = seconds();
-}
-
-double Stopwatch::stop()
-{
- if (running_)
- {
- total_ += (seconds() - start_time_);
- running_ = 0;
- }
- return total_;
-}
-
-inline void Stopwatch::resume()
-{
- if (!running_)
- {
- start_time_ = seconds();
- running_ = 1;
- }
-}
-
-
-inline double Stopwatch::read()
-{
- if (running_)
- {
- stop();
- resume();
- }
- return total_;
-}
-
-
-} /* TNT namespace */
-#endif
-
-
-
diff --git a/intern/smoke/intern/tnt/tnt_subscript.h b/intern/smoke/intern/tnt/tnt_subscript.h
deleted file mode 100644
index 00cc0220bd1..00000000000
--- a/intern/smoke/intern/tnt/tnt_subscript.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_SUBSCRPT_H
-#define TNT_SUBSCRPT_H
-
-
-//---------------------------------------------------------------------
-// This definition describes the default TNT data type used for
-// indexing into TNT matrices and vectors. The data type should
-// be wide enough to index into large arrays. It defaults to an
-// "int", but can be overriden at compile time redefining TNT_SUBSCRIPT_TYPE,
-// e.g.
-//
-// c++ -DTNT_SUBSCRIPT_TYPE='unsigned int' ...
-//
-//---------------------------------------------------------------------
-//
-
-#ifndef TNT_SUBSCRIPT_TYPE
-#define TNT_SUBSCRIPT_TYPE int
-#endif
-
-namespace TNT
-{
- typedef TNT_SUBSCRIPT_TYPE Subscript;
-} /* namespace TNT */
-
-
-// () indexing in TNT means 1-offset, i.e. x(1) and A(1,1) are the
-// first elements. This offset is left as a macro for future
-// purposes, but should not be changed in the current release.
-//
-//
-#define TNT_BASE_OFFSET (1)
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_vec.h b/intern/smoke/intern/tnt/tnt_vec.h
deleted file mode 100644
index 77458c6b8c1..00000000000
--- a/intern/smoke/intern/tnt/tnt_vec.h
+++ /dev/null
@@ -1,407 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_VEC_H
-#define TNT_VEC_H
-
-#include "tnt_subscript.h"
-#include <cstdlib>
-#include <cassert>
-#include <iostream>
-#include <sstream>
-
-namespace TNT
-{
-
-/**
- <b>[Deprecatred]</b> Value-based vector class from pre-1.0
- TNT version. Kept here for backward compatiblity, but should
- use the newer TNT::Array1D classes instead.
-
-*/
-
-template <class T>
-class Vector
-{
-
-
- public:
-
- typedef Subscript size_type;
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- Subscript lbound() const { return 1;}
-
- protected:
- T* v_;
- T* vm1_; // pointer adjustment for optimzied 1-offset indexing
- Subscript n_;
-
- // internal helper function to create the array
- // of row pointers
-
- void initialize(Subscript N)
- {
- // adjust pointers so that they are 1-offset:
- // v_[] is the internal contiguous array, it is still 0-offset
- //
- assert(v_ == NULL);
- v_ = new T[N];
- assert(v_ != NULL);
- vm1_ = v_-1;
- n_ = N;
- }
-
- void copy(const T* v)
- {
- Subscript N = n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = v[i];
- v_[i+1] = v[i+1];
- v_[i+2] = v[i+2];
- v_[i+3] = v[i+3];
- }
-
- for (i=N4; i< N; i++)
- v_[i] = v[i];
-#else
-
- for (i=0; i< N; i++)
- v_[i] = v[i];
-#endif
- }
-
- void set(const T& val)
- {
- Subscript N = n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = val;
- v_[i+1] = val;
- v_[i+2] = val;
- v_[i+3] = val;
- }
-
- for (i=N4; i< N; i++)
- v_[i] = val;
-#else
-
- for (i=0; i< N; i++)
- v_[i] = val;
-
-#endif
- }
-
-
-
- void destroy()
- {
- /* do nothing, if no memory has been previously allocated */
- if (v_ == NULL) return ;
-
- /* if we are here, then matrix was previously allocated */
- delete [] (v_);
-
- v_ = NULL;
- vm1_ = NULL;
- }
-
-
- public:
-
- // access
-
- iterator begin() { return v_;}
- iterator end() { return v_ + n_; }
- iterator begin() const { return v_;}
- iterator end() const { return v_ + n_; }
-
- // destructor
-
- ~Vector()
- {
- destroy();
- }
-
- // constructors
-
- Vector() : v_(0), vm1_(0), n_(0) {};
-
- Vector(const Vector<T> &A) : v_(0), vm1_(0), n_(0)
- {
- initialize(A.n_);
- copy(A.v_);
- }
-
- Vector(Subscript N, const T& value = T()) : v_(0), vm1_(0), n_(0)
- {
- initialize(N);
- set(value);
- }
-
- Vector(Subscript N, const T* v) : v_(0), vm1_(0), n_(0)
- {
- initialize(N);
- copy(v);
- }
-
- Vector(Subscript N, char *s) : v_(0), vm1_(0), n_(0)
- {
- initialize(N);
- std::istringstream ins(s);
-
- Subscript i;
-
- for (i=0; i<N; i++)
- ins >> v_[i];
- }
-
-
- // methods
- //
- Vector<T>& newsize(Subscript N)
- {
- if (n_ == N) return *this;
-
- destroy();
- initialize(N);
-
- return *this;
- }
-
-
- // assignments
- //
- Vector<T>& operator=(const Vector<T> &A)
- {
- if (v_ == A.v_)
- return *this;
-
- if (n_ == A.n_) // no need to re-alloc
- copy(A.v_);
-
- else
- {
- destroy();
- initialize(A.n_);
- copy(A.v_);
- }
-
- return *this;
- }
-
- Vector<T>& operator=(const T& scalar)
- {
- set(scalar);
- return *this;
- }
-
- inline Subscript dim() const
- {
- return n_;
- }
-
- inline Subscript size() const
- {
- return n_;
- }
-
-
- inline reference operator()(Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= n_) ;
-#endif
- return vm1_[i];
- }
-
- inline const_reference operator() (Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= n_) ;
-#endif
- return vm1_[i];
- }
-
- inline reference operator[](Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i < n_) ;
-#endif
- return v_[i];
- }
-
- inline const_reference operator[](Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
-
-
-
-
-
-
- assert(i < n_) ;
-#endif
- return v_[i];
- }
-
-
-
-};
-
-
-/* *************************** I/O ********************************/
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Vector<T> &A)
-{
- Subscript N=A.dim();
-
- s << N << "\n";
-
- for (Subscript i=0; i<N; i++)
- s << A[i] << " " << "\n";
- s << "\n";
-
- return s;
-}
-
-template <class T>
-std::istream & operator>>(std::istream &s, Vector<T> &A)
-{
-
- Subscript N;
-
- s >> N;
-
- if ( !(N == A.size() ))
- {
- A.newsize(N);
- }
-
-
- for (Subscript i=0; i<N; i++)
- s >> A[i];
-
-
- return s;
-}
-
-// *******************[ basic matrix algorithms ]***************************
-
-
-template <class T>
-Vector<T> operator+(const Vector<T> &A,
- const Vector<T> &B)
-{
- Subscript N = A.dim();
-
- assert(N==B.dim());
-
- Vector<T> tmp(N);
- Subscript i;
-
- for (i=0; i<N; i++)
- tmp[i] = A[i] + B[i];
-
- return tmp;
-}
-
-template <class T>
-Vector<T> operator-(const Vector<T> &A,
- const Vector<T> &B)
-{
- Subscript N = A.dim();
-
- assert(N==B.dim());
-
- Vector<T> tmp(N);
- Subscript i;
-
- for (i=0; i<N; i++)
- tmp[i] = A[i] - B[i];
-
- return tmp;
-}
-
-template <class T>
-Vector<T> operator*(const Vector<T> &A,
- const Vector<T> &B)
-{
- Subscript N = A.dim();
-
- assert(N==B.dim());
-
- Vector<T> tmp(N);
- Subscript i;
-
- for (i=0; i<N; i++)
- tmp[i] = A[i] * B[i];
-
- return tmp;
-}
-
-
-template <class T>
-T dot_prod(const Vector<T> &A, const Vector<T> &B)
-{
- Subscript N = A.dim();
- assert(N == B.dim());
-
- Subscript i;
- T sum = 0;
-
- for (i=0; i<N; i++)
- sum += A[i] * B[i];
-
- return sum;
-}
-
-} /* namespace TNT */
-
-#endif
-// TNT_VEC_H
diff --git a/intern/smoke/intern/tnt/tnt_version.h b/intern/smoke/intern/tnt/tnt_version.h
deleted file mode 100644
index d770efb15c7..00000000000
--- a/intern/smoke/intern/tnt/tnt_version.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-#ifndef TNT_VERSION_H
-#define TNT_VERSION_H
-
-
-//---------------------------------------------------------------------
-// current version
-//---------------------------------------------------------------------
-
-
-#define TNT_MAJOR_VERSION '1'
-#define TNT_MINOR_VERSION '2'
-#define TNT_SUBMINOR_VERSION '6'
-#define TNT_VERSION_STRING "1.2.6"
-
-
-
-
-
-#endif
-// TNT_VERSION_H
diff --git a/release/darwin/Blender.app/Contents/Info.plist b/release/darwin/Blender.app/Contents/Info.plist
index b8cd55d2e43..2408cf363b1 100644
--- a/release/darwin/Blender.app/Contents/Info.plist
+++ b/release/darwin/Blender.app/Contents/Info.plist
@@ -49,7 +49,5 @@
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<true/>
- <key>NSSupportsAutomaticGraphicsSwitching</key>
- <true/>
</dict>
</plist>
diff --git a/release/darwin/README.txt b/release/darwin/README.txt
index daef623b321..626ce8820ab 100644
--- a/release/darwin/README.txt
+++ b/release/darwin/README.txt
@@ -6,10 +6,15 @@ Install Code Signing Certificate
--------------------------------
* Go to https://developer.apple.com/account/resources/certificates/list
-* Download the Developer ID Application certifate.
+* Download the Developer ID Application certificate.
* Double click the file and add to key chain (default options).
* Delete the file from the Downloads folder.
+* You will also need to install a .p12 public/private key file for the
+ certificate. This is only available for the owner of the Blender account,
+ or can be exported and copied from another system that already has code
+ signing set up.
+
Find the codesigning identity by running:
$ security find-identity -v -p codesigning
diff --git a/release/darwin/bundle.sh b/release/darwin/bundle.sh
index 91ce4f61d37..d1ef7a180e3 100755
--- a/release/darwin/bundle.sh
+++ b/release/darwin/bundle.sh
@@ -99,7 +99,7 @@ echo
# Create the disk image.
_directory_size=$(du -sh ${_tmp_dir} | awk -F'[^0-9]*' '$0=$1')
-_image_size=$(echo "${_directory_size}" + 200 | bc) # extra 200 need for codesign to work (why on earth?)
+_image_size=$(echo "${_directory_size}" + 400 | bc) # extra 400 need for codesign to work (why on earth?)
echo
echo -n "Creating disk image of size ${_image_size}M.."
@@ -174,10 +174,10 @@ rm "${_tmp_dmg}"
# Notarize
if [ ! -z "${N_USERNAME}" ] && [ ! -z "${N_PASSWORD}" ] && [ ! -z "${N_BUNDLE_ID}" ]; then
# Send to Apple
- echo -n "Sending ${DEST_DMG} for notarization..."
+ echo "Sending ${DEST_DMG} for notarization..."
_tmpout=$(mktemp)
- echo xcrun altool --notarize-app -f "${DEST_DMG}" --primary-bundle-id "${N_BUNDLE_ID}" --username "${N_USERNAME}" --password "${N_PASSWORD}"
- xcrun altool --notarize-app -f "${DEST_DMG}" --primary-bundle-id "${N_BUNDLE_ID}" --username "${N_USERNAME}" --password "${N_PASSWORD}" >${_tmpout} 2>&1
+ echo xcrun altool --notarize-app --verbose -f "${DEST_DMG}" --primary-bundle-id "${N_BUNDLE_ID}" --username "${N_USERNAME}" --password "${N_PASSWORD}"
+ xcrun altool --notarize-app --verbose -f "${DEST_DMG}" --primary-bundle-id "${N_BUNDLE_ID}" --username "${N_USERNAME}" --password "${N_PASSWORD}" >${_tmpout} 2>&1
# Parse request uuid
_requuid=$(cat "${_tmpout}" | grep "RequestUUID" | awk '{ print $3 }')
@@ -202,6 +202,7 @@ if [ ! -z "${N_USERNAME}" ] && [ ! -z "${N_PASSWORD}" ] && [ ! -z "${N_BUNDLE_ID
echo "Notarization in progress, waiting..."
done
else
+ cat ${_tmpout}
echo "Error getting RequestUUID, notarization unsuccessful"
fi
else
diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg
index f317b346eb8..6a87ac0adaa 100644
--- a/release/datafiles/blender_icons.svg
+++ b/release/datafiles/blender_icons.svg
@@ -1048,9 +1048,6 @@
</linearGradient>
- <filter color-interpolation-filters="sRGB" inkscape:collect="always" id="filter15613" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
- <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615"/>
- </filter>
<linearGradient id="linearGradient37542-55">
<stop id="stop37544-61" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
<stop id="stop37546-03" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
@@ -1065,9 +1062,6 @@
</linearGradient>
- <filter color-interpolation-filters="sRGB" inkscape:collect="always" id="filter15613-8" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
- <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615-1"/>
- </filter>
<filter color-interpolation-filters="sRGB" inkscape:label="Greyscale" id="filter15388">
@@ -1327,14 +1321,6 @@
<radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient52883-6-8-3" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-362.22886,-161.73912)" cx="-302.79681" cy="462.0358" fx="-302.79681" fy="462.0358" r="8"/>
- <filter style="color-interpolation-filters:sRGB" inkscape:collect="always" id="filter15613-7" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
- <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615-4"/>
- </filter>
-
-
- <filter style="color-interpolation-filters:sRGB" inkscape:collect="always" id="filter15613-8-8" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
- <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615-1-5"/>
- </filter>
<filter style="color-interpolation-filters:sRGB" inkscape:label="Greyscale" id="filter15388-0">
@@ -3746,14 +3732,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 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>
- </g>
<g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.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"/>
@@ -3831,11 +3809,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: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>
<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 style="display:inline;fill:#ffffff;enable-background:new" id="g14433" transform="rotate(-90,380.52904,134)">
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule: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>
- <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-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"/>
diff --git a/release/datafiles/blender_icons16/icon16_disk.dat b/release/datafiles/blender_icons16/icon16_disc.dat
index 26325c272b2..26325c272b2 100644
--- a/release/datafiles/blender_icons16/icon16_disk.dat
+++ b/release/datafiles/blender_icons16/icon16_disc.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_mod_smoke.dat b/release/datafiles/blender_icons16/icon16_mod_fluid.dat
index 0524059740d..0524059740d 100644
--- a/release/datafiles/blender_icons16/icon16_mod_smoke.dat
+++ b/release/datafiles/blender_icons16/icon16_mod_fluid.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_ndof_dom.dat b/release/datafiles/blender_icons16/icon16_ndof_dom.dat
deleted file mode 100644
index e6ecd80d5a9..00000000000
--- a/release/datafiles/blender_icons16/icon16_ndof_dom.dat
+++ /dev/null
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_ndof_fly.dat b/release/datafiles/blender_icons16/icon16_ndof_fly.dat
deleted file mode 100644
index 84b672bdf9f..00000000000
--- a/release/datafiles/blender_icons16/icon16_ndof_fly.dat
+++ /dev/null
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_ndof_trans.dat b/release/datafiles/blender_icons16/icon16_ndof_trans.dat
deleted file mode 100644
index f74edd6f8b0..00000000000
--- a/release/datafiles/blender_icons16/icon16_ndof_trans.dat
+++ /dev/null
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_ndof_turn.dat b/release/datafiles/blender_icons16/icon16_ndof_turn.dat
deleted file mode 100644
index 5b0cee02b49..00000000000
--- a/release/datafiles/blender_icons16/icon16_ndof_turn.dat
+++ /dev/null
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_disk.dat b/release/datafiles/blender_icons32/icon32_disc.dat
index e0181bb7a8e..e0181bb7a8e 100644
--- a/release/datafiles/blender_icons32/icon32_disk.dat
+++ b/release/datafiles/blender_icons32/icon32_disc.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_mod_smoke.dat b/release/datafiles/blender_icons32/icon32_mod_fluid.dat
index e3390d5f2ce..e3390d5f2ce 100644
--- a/release/datafiles/blender_icons32/icon32_mod_smoke.dat
+++ b/release/datafiles/blender_icons32/icon32_mod_fluid.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_ndof_dom.dat b/release/datafiles/blender_icons32/icon32_ndof_dom.dat
deleted file mode 100644
index 9c7e6fdfc99..00000000000
--- a/release/datafiles/blender_icons32/icon32_ndof_dom.dat
+++ /dev/null
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_ndof_fly.dat b/release/datafiles/blender_icons32/icon32_ndof_fly.dat
deleted file mode 100644
index a328f8dc1ca..00000000000
--- a/release/datafiles/blender_icons32/icon32_ndof_fly.dat
+++ /dev/null
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_ndof_trans.dat b/release/datafiles/blender_icons32/icon32_ndof_trans.dat
deleted file mode 100644
index 553752dda40..00000000000
--- a/release/datafiles/blender_icons32/icon32_ndof_trans.dat
+++ /dev/null
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_ndof_turn.dat b/release/datafiles/blender_icons32/icon32_ndof_turn.dat
deleted file mode 100644
index 3f43546cdbf..00000000000
--- a/release/datafiles/blender_icons32/icon32_ndof_turn.dat
+++ /dev/null
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.multiplane_scrape.dat b/release/datafiles/icons/brush.sculpt.multiplane_scrape.dat
new file mode 100644
index 00000000000..98a5b3be902
--- /dev/null
+++ b/release/datafiles/icons/brush.sculpt.multiplane_scrape.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.topology.dat b/release/datafiles/icons/brush.sculpt.topology.dat
new file mode 100644
index 00000000000..0d455dce556
--- /dev/null
+++ b/release/datafiles/icons/brush.sculpt.topology.dat
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject a2fb7b56b6c99ca14aa1dd09659ad0242c1b158
+Subproject 8a05b618f031582c006c6f62b9e60619ab3eef8
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index d8b87480f29..f6573873dd5 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -62,7 +62,7 @@ const UserDef U_default = {
USER_HIDE_DOT | USER_SHOW_GIZMO_NAVIGATE | USER_SHOW_VIEWPORTNAME | USER_SHOW_FPS |
USER_CONTINUOUS_MOUSE | USER_SAVE_PROMPT),
.uiflag2 = USER_REGION_OVERLAP,
- .gpu_flag = 0,
+ .gpu_flag = USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE,
.app_flag = 0,
.language = 0,
.viewzoom = USER_ZOOM_DOLLY,
@@ -150,11 +150,16 @@ const UserDef U_default = {
.tablet_api = USER_TABLET_AUTOMATIC,
.pressure_threshold_max = 1.0,
.pressure_softness = 0.0,
- .ndof_sensitivity = 1.0,
- .ndof_orbit_sensitivity = 1.0,
+ .ndof_sensitivity = 4.0,
+ .ndof_orbit_sensitivity = 4.0,
.ndof_deadzone = 0.1,
- .ndof_flag = (NDOF_LOCK_HORIZON | NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM | NDOF_SHOULD_ROTATE),
- .ogl_multisamples = 0,
+ .ndof_flag = (NDOF_MODE_ORBIT | NDOF_LOCK_HORIZON | NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM |
+ NDOF_SHOULD_ROTATE |
+ /* Software from the driver authors follows this convention
+ * so invert this by default, see: T67579. */
+ NDOF_ROTX_INVERT_AXIS | NDOF_ROTY_INVERT_AXIS | NDOF_ROTZ_INVERT_AXIS |
+ NDOF_PANX_INVERT_AXIS | NDOF_PANY_INVERT_AXIS | NDOF_PANZ_INVERT_AXIS |
+ NDOF_ZOOM_INVERT),
.image_draw_method = IMAGE_DRAW_METHOD_AUTO,
.glalphaclip = 0.004,
.autokey_mode = (AUTOKEY_MODE_NORMAL & ~AUTOKEY_ON),
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index 383f3542c7f..147b55f60ef 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -327,6 +327,8 @@ const bTheme U_theme_default = {
.face = RGBA(0xffffff12),
.face_select = RGBA(0xffa5526c),
.face_dot = RGBA(0xff8a00ff),
+ .face_back = RGBA(0xff0000b3),
+ .face_front = RGBA(0x0000ffb3),
.extra_edge_len = RGBA(0x150806ff),
.extra_edge_angle = RGBA(0x4d4d00ff),
.extra_face_angle = RGBA(0x0000ccff),
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 52b58daa9759d56e45aa6dabd90ec36910e7084
+Subproject 1470f353c65034db91131d21ab9c782d029a2ee
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject af1d8170e6fb19851fd547fe228bceede3375bf
+Subproject ffbaca558a27bab4716bcd51ca7ea1df8e4f4b1
diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py
index e74b61ced94..534ee7d65be 100644
--- a/release/scripts/freestyle/modules/parameter_editor.py
+++ b/release/scripts/freestyle/modules/parameter_editor.py
@@ -188,7 +188,7 @@ class CurveMappingModifier(ScalarBlendModifier):
# deprecated: return evaluateCurveMappingF(self.curve, 0, t)
curve = self.curve
curve.initialize()
- result = curve.curves[0].evaluate(t)
+ result = curve.evaluate(curve=curve.curves[0], position=t)
# float precision errors in t can give a very weird result for evaluate.
# therefore, bound the result by the curve's min and max values
return bound(curve.clip_min_y, result, curve.clip_max_y)
diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py
index 380b63066ef..19697b25f70 100644
--- a/release/scripts/modules/bpy_extras/io_utils.py
+++ b/release/scripts/modules/bpy_extras/io_utils.py
@@ -465,7 +465,7 @@ def path_reference(
if copy_subdir:
subdir_abs = os.path.join(subdir_abs, copy_subdir)
- filepath_cpy = os.path.join(subdir_abs, os.path.basename(filepath))
+ filepath_cpy = os.path.join(subdir_abs, os.path.basename(filepath_abs))
copy_set.add((filepath_abs, filepath_cpy))
diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py
index 9db86782d02..8c009a77d3d 100644
--- a/release/scripts/modules/bpy_extras/object_utils.py
+++ b/release/scripts/modules/bpy_extras/object_utils.py
@@ -130,7 +130,10 @@ def object_data_add(context, obdata, operator=None, name=None):
obj_new.matrix_world = add_object_align_init(context, operator)
space_data = context.space_data
- if space_data.type == 'VIEW_3D':
+ if space_data and space_data.type != 'VIEW_3D':
+ space_data = None
+
+ if space_data:
if space_data.local_view:
obj_new.local_view_set(space_data, True)
diff --git a/release/scripts/modules/console_python.py b/release/scripts/modules/console_python.py
index f264de5b140..5106010b555 100644
--- a/release/scripts/modules/console_python.py
+++ b/release/scripts/modules/console_python.py
@@ -341,23 +341,20 @@ def banner(context):
sc = context.space_data
version_string = sys.version.strip().replace('\n', ' ')
- add_scrollback("PYTHON INTERACTIVE CONSOLE %s" % version_string, 'OUTPUT')
- add_scrollback("", 'OUTPUT')
- add_scrollback("Command History: Up/Down Arrow", 'OUTPUT')
- add_scrollback("Cursor: Left/Right Home/End", 'OUTPUT')
- add_scrollback("Remove: Backspace/Delete", 'OUTPUT')
- add_scrollback("Execute: Enter", 'OUTPUT')
- add_scrollback("Autocomplete: Ctrl-Space", 'OUTPUT')
- add_scrollback("Zoom: Ctrl +/-, Ctrl-Wheel", 'OUTPUT')
- add_scrollback("Builtin Modules: bpy, bpy.data, bpy.ops, "
- "bpy.props, bpy.types, bpy.context, bpy.utils, "
- "bgl, blf, mathutils",
- 'OUTPUT')
- add_scrollback("Convenience Imports: from mathutils import *; "
- "from math import *", 'OUTPUT')
- add_scrollback("Convenience Variables: C = bpy.context, D = bpy.data",
- 'OUTPUT')
- add_scrollback("", 'OUTPUT')
+ message = (
+ "PYTHON INTERACTIVE CONSOLE %s" % version_string,
+ "",
+ "Builtin Modules: "
+ "bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bpy.utils, bgl, blf, mathutils",
+
+ "Convenience Imports: from mathutils import *; from math import *",
+ "Convenience Variables: C = bpy.context, D = bpy.data",
+ "",
+ )
+
+ for line in message:
+ add_scrollback(line, 'OUTPUT')
+
sc.prompt = PROMPT
return {'FINISHED'}
diff --git a/release/scripts/presets/fluid/honey.py b/release/scripts/presets/fluid/honey.py
index fbeb7f2b286..0ed3658470a 100644
--- a/release/scripts/presets/fluid/honey.py
+++ b/release/scripts/presets/fluid/honey.py
@@ -1,3 +1,3 @@
import bpy
-bpy.context.fluid.settings.viscosity_base = 2.0
-bpy.context.fluid.settings.viscosity_exponent = 3
+bpy.context.fluid.domain_settings.viscosity_base = 2.0
+bpy.context.fluid.domain_settings.viscosity_exponent = 3
diff --git a/release/scripts/presets/fluid/oil.py b/release/scripts/presets/fluid/oil.py
index 3d73de9303a..c33e5d4b6cf 100644
--- a/release/scripts/presets/fluid/oil.py
+++ b/release/scripts/presets/fluid/oil.py
@@ -1,3 +1,3 @@
import bpy
-bpy.context.fluid.settings.viscosity_base = 5.0
-bpy.context.fluid.settings.viscosity_exponent = 5
+bpy.context.fluid.domain_settings.viscosity_base = 5.0
+bpy.context.fluid.domain_settings.viscosity_exponent = 5
diff --git a/release/scripts/presets/fluid/water.py b/release/scripts/presets/fluid/water.py
index 0b68ad28c98..f34ecc834ff 100644
--- a/release/scripts/presets/fluid/water.py
+++ b/release/scripts/presets/fluid/water.py
@@ -1,3 +1,3 @@
import bpy
-bpy.context.fluid.settings.viscosity_base = 1.0
-bpy.context.fluid.settings.viscosity_exponent = 6
+bpy.context.fluid.domain_settings.viscosity_base = 1.0
+bpy.context.fluid.domain_settings.viscosity_exponent = 6
diff --git a/release/scripts/presets/keyconfig/blender.py b/release/scripts/presets/keyconfig/blender.py
index 596b17d734f..11cd76335f1 100644
--- a/release/scripts/presets/keyconfig/blender.py
+++ b/release/scripts/presets/keyconfig/blender.py
@@ -70,6 +70,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
('DRAG', "Drag", "Drag allows click events to pass through to the tool, adding a small delay"),
),
description="Activation event for gizmos that support drag motion",
+ default='DRAG',
update=update_fn,
)
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 3a7a142e310..488df3f6f72 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -161,6 +161,20 @@ def op_tool_cycle(tool, kmi_args):
# ------------------------------------------------------------------------------
# Keymap Templates
+def _template_items_context_menu(menu, key_args_primary):
+ return [
+ op_menu(menu, kmi_args)
+ for kmi_args in (key_args_primary, {"type": 'APP', "value": 'PRESS'})
+ ]
+
+
+def _template_items_context_panel(menu, key_args_primary):
+ return [
+ op_panel(menu, kmi_args)
+ for kmi_args in (key_args_primary, {"type": 'APP', "value": 'PRESS'})
+ ]
+
+
def _template_space_region_type_toggle(*, toolbar_key=None, sidebar_key=None):
items = []
if toolbar_key is not None:
@@ -392,7 +406,7 @@ def km_window(params):
),
# NDOF settings
- op_menu("USERPREF_MT_ndof_settings", {"type": 'NDOF_BUTTON_MENU', "value": 'PRESS'}),
+ op_panel("USERPREF_PT_ndof_settings", {"type": 'NDOF_BUTTON_MENU', "value": 'PRESS'}),
("wm.context_scale_float", {"type": 'NDOF_BUTTON_PLUS', "value": 'PRESS'},
{"properties": [("data_path", 'preferences.inputs.ndof_sensitivity'), ("value", 1.1)]}),
("wm.context_scale_float", {"type": 'NDOF_BUTTON_MINUS', "value": 'PRESS'},
@@ -412,6 +426,8 @@ def km_window(params):
("wm.batch_rename", {"type": 'F2', "value": 'PRESS', "ctrl": True}, None),
("wm.search_menu", {"type": 'F3', "value": 'PRESS'}, None),
op_menu("TOPBAR_MT_file_context_menu", {"type": 'F4', "value": 'PRESS'}),
+ # Pass through when when no tool-system exists or the fallback isn't available.
+ ("wm.toolbar_fallback_pie", {"type": 'W', "value": 'PRESS', "alt": True}, None),
# Alt as "Leader-Key".
("wm.toolbar_prompt", {"type": 'LEFT_ALT', "value": 'CLICK'}, None),
("wm.toolbar_prompt", {"type": 'RIGHT_ALT', "value": 'CLICK'}, None),
@@ -839,7 +855,7 @@ def km_uv_editor(params):
{"properties": [("data_path", 'tool_settings.use_snap')]}),
("wm.context_menu_enum", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True},
{"properties": [("data_path", 'tool_settings.snap_uv_element')]}),
- op_menu("IMAGE_MT_uvs_context_menu", params.context_menu_event),
+ *_template_items_context_menu("IMAGE_MT_uvs_context_menu", params.context_menu_event),
])
# Fallback for MMB emulation
@@ -1477,7 +1493,7 @@ def km_graph_editor(params):
op_menu_pie("GRAPH_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
- op_menu("GRAPH_MT_context_menu", params.context_menu_event),
+ *_template_items_context_menu("GRAPH_MT_context_menu", params.context_menu_event),
])
if params.select_mouse == 'LEFTMOUSE' and not params.legacy:
@@ -1583,7 +1599,7 @@ def km_image(params):
op_menu_pie("IMAGE_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
("image.render_border", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
("image.clear_render_border", {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, None),
- op_menu("IMAGE_MT_mask_context_menu", params.context_menu_event),
+ *_template_items_context_menu("IMAGE_MT_mask_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -1735,7 +1751,7 @@ def km_node_editor(params):
{"properties": [("data_path", 'tool_settings.use_snap')]}),
("wm.context_menu_enum", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True},
{"properties": [("data_path", 'tool_settings.snap_node_element')]}),
- op_menu("NODE_MT_context_menu", params.context_menu_event),
+ *_template_items_context_menu("NODE_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -1761,7 +1777,7 @@ def km_info(params):
("info.report_delete", {"type": 'X', "value": 'PRESS'}, None),
("info.report_delete", {"type": 'DEL', "value": 'PRESS'}, None),
("info.report_copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
- op_menu("INFO_MT_context_menu", params.context_menu_event),
+ *_template_items_context_menu("INFO_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -1809,7 +1825,7 @@ def km_file_browser(params):
{"properties": [("increment", -10)]}),
("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True},
{"properties": [("increment", -100)]}),
- op_menu("FILEBROWSER_MT_context_menu", params.context_menu_event),
+ *_template_items_context_menu("FILEBROWSER_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -2016,7 +2032,7 @@ def km_dopesheet(params):
op_menu_pie("VIEW3D_MT_proportional_editing_falloff_pie", {"type": 'O', "value": 'PRESS', "shift": True}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
- op_menu("DOPESHEET_MT_context_menu", params.context_menu_event),
+ *_template_items_context_menu("DOPESHEET_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -2065,7 +2081,7 @@ def km_nla_channels(params):
{"properties": [("above_selected", True)]}),
("nla.tracks_delete", {"type": 'X', "value": 'PRESS'}, None),
("nla.tracks_delete", {"type": 'DEL', "value": 'PRESS'}, None),
- op_menu("NLA_MT_channel_context_menu", params.context_menu_event),
+ *_template_items_context_menu("NLA_MT_channel_context_menu", params.context_menu_event),
])
return keymap
@@ -2141,7 +2157,7 @@ def km_nla_editor(params):
{"properties": [("mode", 'TIME_SCALE')]}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
- op_menu("NLA_MT_context_menu", params.context_menu_event),
+ *_template_items_context_menu("NLA_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -2441,7 +2457,7 @@ def km_sequencer(params):
{"properties": [("left_right", 'LEFT'), ("linked_time", True)]}),
("sequencer.select", {"type": 'RIGHT_BRACKET', "value": 'PRESS'},
{"properties": [("left_right", 'RIGHT'), ("linked_time", True)]}),
- op_menu("SEQUENCER_MT_context_menu", params.context_menu_event),
+ *_template_items_context_menu("SEQUENCER_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -2479,7 +2495,7 @@ def km_sequencerpreview(params):
return keymap
-def km_console(params):
+def km_console(_params):
items = []
keymap = (
"Console",
@@ -2537,7 +2553,7 @@ def km_console(params):
{"properties": [("text", '\t')]}),
("console.indent_or_autocomplete", {"type": 'TAB', "value": 'PRESS'}, None),
("console.unindent", {"type": 'TAB', "value": 'PRESS', "shift": True}, None),
- op_menu("CONSOLE_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("CONSOLE_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("console.insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None),
])
@@ -2686,7 +2702,7 @@ def km_clip_editor(params):
op_menu_pie("CLIP_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
("clip.copy_tracks", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
("clip.paste_tracks", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
- op_menu("CLIP_MT_tracking_context_menu", params.context_menu_event),
+ *_template_items_context_menu("CLIP_MT_tracking_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -2930,7 +2946,7 @@ def km_animation_channels(params):
("anim.channels_group", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
("anim.channels_ungroup", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None),
# Menus.
- op_menu("DOPESHEET_MT_channel_context_menu", params.context_menu_event),
+ *_template_items_context_menu("DOPESHEET_MT_channel_context_menu", params.context_menu_event),
])
return keymap
@@ -3102,7 +3118,7 @@ def km_grease_pencil_stroke_edit_mode(params):
("gpencil.selectmode_toggle", {"type": 'THREE', "value": 'PRESS'},
{"properties": [("mode", 2)]}),
# Context menu
- op_menu("VIEW3D_MT_gpencil_edit_context_menu", params.context_menu_event),
+ *_template_items_context_menu("VIEW3D_MT_gpencil_edit_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -3145,7 +3161,7 @@ def km_grease_pencil_stroke_paint_mode(params):
("gpencil.hide", {"type": 'H', "value": 'PRESS', "shift": True},
{"properties": [("unselected", True)]}),
# Draw context menu
- op_panel("VIEW3D_PT_gpencil_draw_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_gpencil_draw_context_menu", params.context_menu_event),
])
return keymap
@@ -3228,7 +3244,7 @@ def km_grease_pencil_stroke_paint_erase(params):
return keymap
-def km_grease_pencil_stroke_paint_fill(_params):
+def km_grease_pencil_stroke_paint_fill(params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Fill)",
@@ -3249,7 +3265,7 @@ def km_grease_pencil_stroke_paint_fill(_params):
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
{"properties": [("mode", 'DRAW'), ("wait_for_input", False), ("disable_straight", True), ("disable_fill", True)]}),
# Lasso select
- ("gpencil.select_lasso", {"type": _params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None),
+ ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None),
])
return keymap
@@ -3278,7 +3294,7 @@ def km_grease_pencil_stroke_sculpt_mode(params):
# Display
*_grease_pencil_display(),
# Context menu
- op_panel("VIEW3D_PT_gpencil_sculpt_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_gpencil_sculpt_context_menu", params.context_menu_event),
])
return keymap
@@ -3428,7 +3444,7 @@ def km_pose(params):
for i in range(10)
)
),
- op_menu("VIEW3D_MT_pose_context_menu", params.context_menu_event),
+ *_template_items_context_menu("VIEW3D_MT_pose_context_menu", params.context_menu_event),
])
return keymap
@@ -3507,7 +3523,7 @@ def km_object_mode(params):
for i in range(10)
)
),
- op_menu("VIEW3D_MT_object_context_menu", params.context_menu_event),
+ *_template_items_context_menu("VIEW3D_MT_object_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -3573,7 +3589,7 @@ def km_curve(params):
)
items.extend([
- op_menu("VIEW3D_MT_curve_add", {"type": 'A', "value": 'PRESS', "shift": True}),
+ op_menu("TOPBAR_MT_edit_curve_add", {"type": 'A', "value": 'PRESS', "shift": True}),
("curve.handle_type_set", {"type": 'V', "value": 'PRESS'}, None),
("curve.vertex_add", {"type": params.action_mouse, "value": 'CLICK', "ctrl": True}, None),
*_template_items_select_actions(params, "curve.select_all"),
@@ -3610,7 +3626,7 @@ def km_curve(params):
("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None),
op_menu("VIEW3D_MT_hook", {"type": 'H', "value": 'PRESS', "ctrl": True}),
*_template_items_proportional_editing(connected=True),
- op_menu("VIEW3D_MT_edit_curve_context_menu", params.context_menu_event),
+ *_template_items_context_menu("VIEW3D_MT_edit_curve_context_menu", params.context_menu_event),
])
return keymap
@@ -3706,7 +3722,7 @@ def km_image_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.image_paint.brush.stroke_method')]}),
- op_panel("VIEW3D_PT_paint_texture_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_paint_texture_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -3755,7 +3771,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')]}),
- op_panel("VIEW3D_PT_paint_vertex_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_paint_vertex_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -3801,7 +3817,7 @@ def km_weight_paint(params):
{"properties": [("data_path", 'weight_paint_object.data.use_paint_mask_vertex')]}),
("wm.context_toggle", {"type": 'S', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'tool_settings.weight_paint.brush.use_smooth_stroke')]}),
- op_panel("VIEW3D_PT_paint_weight_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_paint_weight_context_menu", params.context_menu_event),
])
if params.select_mouse == 'LEFTMOUSE':
@@ -3913,7 +3929,7 @@ def km_sculpt(params):
{"properties": [("data_path", 'tool_settings.sculpt.brush.use_smooth_stroke')]}),
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
op_menu_pie("VIEW3D_MT_sculpt_mask_edit_pie", {"type" : 'A', "value": 'PRESS'}),
- op_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -4026,7 +4042,7 @@ def km_mesh(params):
op_menu("VIEW3D_MT_edit_mesh_normals", {"type": 'N', "value": 'PRESS', "alt" : True}),
("object.vertex_group_remove_from", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None),
*_template_items_proportional_editing(connected=True),
- op_menu("VIEW3D_MT_edit_mesh_context_menu", params.context_menu_event),
+ *_template_items_context_menu("VIEW3D_MT_edit_mesh_context_menu", params.context_menu_event),
])
if params.use_mouse_emulate_3_button and params.select_mouse == 'LEFTMOUSE':
@@ -4133,7 +4149,7 @@ def km_armature(params):
("transform.transform", {"type": 'R', "value": 'PRESS', "ctrl": True},
{"properties": [("mode", 'BONE_ROLL')]}),
# Menus.
- op_menu("VIEW3D_MT_armature_context_menu", params.context_menu_event),
+ *_template_items_context_menu("VIEW3D_MT_armature_context_menu", params.context_menu_event),
])
return keymap
@@ -4161,7 +4177,7 @@ def km_metaball(params):
*_template_items_select_actions(params, "mball.select_all"),
("mball.select_similar", {"type": 'G', "value": 'PRESS', "shift": True}, None),
*_template_items_proportional_editing(connected=True),
- op_menu("VIEW3D_MT_edit_metaball_context_menu", params.context_menu_event),
+ *_template_items_context_menu("VIEW3D_MT_edit_metaball_context_menu", params.context_menu_event),
])
return keymap
@@ -4184,7 +4200,7 @@ def km_lattice(params):
("lattice.flip", {"type": 'F', "value": 'PRESS', "alt": True}, None),
op_menu("VIEW3D_MT_hook", {"type": 'H', "value": 'PRESS', "ctrl": True}),
*_template_items_proportional_editing(connected=False),
- op_menu("VIEW3D_MT_edit_lattice_context_menu", params.context_menu_event),
+ *_template_items_context_menu("VIEW3D_MT_edit_lattice_context_menu", params.context_menu_event),
])
return keymap
@@ -4229,7 +4245,7 @@ def km_particle(params):
)
),
*_template_items_proportional_editing(connected=False),
- op_menu("VIEW3D_MT_particle_context_menu", params.context_menu_event),
+ *_template_items_context_menu("VIEW3D_MT_particle_context_menu", params.context_menu_event),
])
return keymap
@@ -4319,7 +4335,7 @@ def km_font(params):
("font.text_insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None),
("font.text_insert", {"type": 'BACK_SPACE', "value": 'PRESS', "alt": True},
{"properties": [("accent", True)]}),
- op_menu("VIEW3D_MT_edit_text_context_menu", params.context_menu_event),
+ *_template_items_context_menu("VIEW3D_MT_edit_text_context_menu", params.context_menu_event),
])
return keymap
@@ -5519,7 +5535,7 @@ def km_3d_view_tool_edit_mesh_smooth(params):
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
("mesh.vertices_smooth", {"type": params.tool_tweak, "value": 'ANY'},
- {"properties": [("factor", 0.0), ("wait_for_input", False)]}),
+ {"properties": [("wait_for_input", False)]}),
]},
)
@@ -5670,7 +5686,7 @@ def km_3d_view_tool_edit_curve_randomize(params):
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
("transform.vertex_random", {"type": params.tool_tweak, "value": 'ANY'},
- {"properties": [("offset", 0.0), ("wait_for_input", False)]}),
+ {"properties": [("wait_for_input", False)]}),
]},
)
@@ -6274,4 +6290,6 @@ def generate_keymaps(params=None):
#
# Command to lint:
#
-# pylint release/scripts/presets/keyconfig/keymap_data/blender_default.py --disable=C0111,C0301,C0302,R0902,R0903,R0913
+# pylint \
+# release/scripts/presets/keyconfig/keymap_data/blender_default.py \
+# --disable=C0111,C0301,C0302,C0415,R1705,R0902,R0903,R0913
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 dc62b6bba68..10ee750f887 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -80,6 +80,17 @@ def op_tool_cycle(tool, kmi_args):
# ------------------------------------------------------------------------------
# Keymap Templates
+def _template_items_context_menu(menu, key_args_primary):
+ return [
+ op_menu(menu, kmi_args)
+ for kmi_args in (key_args_primary, {"type": 'APP', "value": 'PRESS'})
+ ]
+
+def _template_items_context_panel(menu, key_args_primary):
+ return [
+ op_panel(menu, kmi_args)
+ for kmi_args in (key_args_primary, {"type": 'APP', "value": 'PRESS'})
+ ]
def _template_items_object_subdivision_set():
return [
@@ -103,40 +114,19 @@ def _template_items_animation():
]
-# Gizmos
-
-def _template_items_gizmo_tweak_value():
- return [
- ("gizmogroup.gizmo_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
- ]
-
-
-def _template_items_gizmo_tweak_value_click_drag():
- return [
- ("gizmogroup.gizmo_tweak", {"type": 'LEFTMOUSE', "value": 'CLICK'}, None),
- ("gizmogroup.gizmo_tweak", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
- ]
-
-
-def _template_items_gizmo_tweak_value_drag():
- return [
- ("gizmogroup.gizmo_tweak", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
- ]
-
# Tool System Templates
def _template_items_basic_tools(*, connected=False):
return [
- op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
- op_tool("builtin.move", {"type": 'W', "value": 'PRESS'}),
- op_tool("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
- op_tool("builtin.scale", {"type": 'R', "value": 'PRESS'}),
- op_tool("builtin.transform", {"type": 'T', "value": 'PRESS'}),
- op_tool("builtin.scale_cage", {"type": 'R', "value": 'PRESS', "shift": True}),
- op_tool("builtin.annotate", {"type": 'D', "value": 'PRESS'}),
- op_tool("builtin.measure", {"type": 'M', "value": 'PRESS'}),
- op_tool("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
+ op_tool_cycle("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
+ op_tool_cycle("builtin.move", {"type": 'W', "value": 'PRESS'}),
+ op_tool_cycle("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
+ op_tool_cycle("builtin.scale", {"type": 'R', "value": 'PRESS'}),
+ op_tool_cycle("builtin.transform", {"type": 'T', "value": 'PRESS'}),
+ op_tool_cycle("builtin.annotate", {"type": 'D', "value": 'PRESS'}),
+ op_tool_cycle("builtin.measure", {"type": 'M', "value": 'PRESS'}),
+ op_tool_cycle("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
]
def _template_items_tool_select(params, operator, cursor_operator):
@@ -170,6 +160,19 @@ def _template_items_tool_select_actions_simple(operator, *, type, value, propert
]
+def _template_items_editmode_mesh_select_mode(params):
+ return [
+ (
+ "mesh.select_mode",
+ {"type": k, "value": 'PRESS', **key_expand, **key_extend},
+ {"properties": [*prop_extend, *prop_expand, ("type", e)]}
+ )
+ for key_expand, prop_expand in (({}, ()), ({"ctrl": True}, (("use_expand", True),)))
+ for key_extend, prop_extend in (({}, ()), ({"shift": True}, (("use_extend", True),)))
+ for k, e in (('ONE', 'VERT'), ('TWO', 'EDGE'), ('THREE', 'FACE'))
+ ]
+
+
# ------------------------------------------------------------------------------
# Window, Screen, Areas, Regions
@@ -196,7 +199,7 @@ def km_window(params):
op_menu("SCREEN_MT_user_menu", {"type": 'TAB', "value": 'PRESS', "shift": True}),
# NDOF settings
- op_menu("USERPREF_MT_ndof_settings", {"type": 'NDOF_BUTTON_MENU', "value": 'PRESS'}),
+ op_panel("USERPREF_PT_ndof_settings", {"type": 'NDOF_BUTTON_MENU', "value": 'PRESS'}),
("wm.context_scale_float", {"type": 'NDOF_BUTTON_PLUS', "value": 'PRESS'},
{"properties": [("data_path", 'preferences.inputs.ndof_sensitivity'), ("value", 1.1)]}),
("wm.context_scale_float", {"type": 'NDOF_BUTTON_MINUS', "value": 'PRESS'},
@@ -325,6 +328,8 @@ def km_view2d(params):
# Zoom with single step
("view2d.zoom_out", {"type": 'WHEELOUTMOUSE', "value": 'PRESS'}, None),
("view2d.zoom_in", {"type": 'WHEELINMOUSE', "value": 'PRESS'}, None),
+ ("view2d.zoom_out", {"type": 'WHEELOUTMOUSE', "value": 'PRESS', "alt": True}, None),
+ ("view2d.zoom_in", {"type": 'WHEELINMOUSE', "value": 'PRESS', "alt": True}, None),
("view2d.zoom_out", {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, None),
("view2d.zoom_in", {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, None),
("view2d.zoom", {"type": 'TRACKPADPAN', "value": 'ANY', "ctrl": True}, None),
@@ -529,11 +534,22 @@ def km_uv_editor(params):
op_panel("TOPBAR_PT_name", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
# Selection modes.
+ *_template_items_editmode_mesh_select_mode(params),
+ ("wm.context_set_enum", {"type": 'ONE', "value": 'PRESS'},
+ {"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'VERTEX')]}),
+ ("wm.context_set_enum", {"type": 'TWO', "value": 'PRESS'},
+ {"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'EDGE')]}),
+ ("wm.context_set_enum", {"type": 'THREE', "value": 'PRESS'},
+ {"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'FACE')]}),
+ ("wm.context_set_enum", {"type": 'FOUR', "value": 'PRESS'},
+ {"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'ISLAND')]}),
+
("uv.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
{"properties": [("extend", False), ("deselect_all", True)]}),
- ("uv.select", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+ ("uv.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
{"properties": [("extend", True), ("deselect_all", False)]}),
- ("uv.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
+
+ ("transform.translate", {"type": "EVT_TWEAK_L", "value": 'ANY'}, None),
("uv.select_loop", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "shift": True},
{"properties": [("extend", True)]}),
("uv.select_loop", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
@@ -550,20 +566,19 @@ def km_uv_editor(params):
{"properties": [("unselected", True)]}),
("uv.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
op_menu_pie("IMAGE_MT_uvs_snap_pie", {"type": 'X', "value": 'PRESS', "shift": True}),
- op_menu("IMAGE_MT_uvs_select_mode", {"type": 'TAB', "value": 'PRESS', "ctrl": True}),
- op_menu("IMAGE_MT_uvs_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("IMAGE_MT_uvs_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("wm.context_toggle", {"type": 'B', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.use_proportional_edit')]}),
("wm.context_toggle", {"type": 'X', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.use_snap')]}),
# Tools
- op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
- op_tool("builtin.move", {"type": 'W', "value": 'PRESS'}),
- op_tool("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
- op_tool("builtin.scale", {"type": 'R', "value": 'PRESS'}),
- op_tool("builtin.transform", {"type": 'T', "value": 'PRESS'}),
- op_tool("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
- op_tool("builtin.annotate", {"type": 'D', "value": 'PRESS'}),
+ op_tool_cycle("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
+ op_tool_cycle("builtin.move", {"type": 'W', "value": 'PRESS'}),
+ op_tool_cycle("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
+ op_tool_cycle("builtin.scale", {"type": 'R', "value": 'PRESS'}),
+ op_tool_cycle("builtin.transform", {"type": 'T', "value": 'PRESS'}),
+ op_tool_cycle("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
+ op_tool_cycle("builtin.annotate", {"type": 'D', "value": 'PRESS'}),
])
return keymap
@@ -626,6 +641,10 @@ def km_view3d(params):
{"properties": [("delta", 1)]}),
("view3d.zoom", {"type": 'WHEELOUTMOUSE', "value": 'PRESS'},
{"properties": [("delta", -1)]}),
+ ("view3d.zoom", {"type": 'WHEELINMOUSE', "value": 'PRESS', "alt": True},
+ {"properties": [("delta", 1)]}),
+ ("view3d.zoom", {"type": 'WHEELOUTMOUSE', "value": 'PRESS', "alt": True},
+ {"properties": [("delta", -1)]}),
("view3d.dolly", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True},
{"properties": [("delta", 1)]}),
("view3d.dolly", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "shift": True},
@@ -731,7 +750,6 @@ def km_mask_editing(params):
("mask.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
("mask.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True, "shift": True}, {"properties": [("action", 'DESELECT')]}),
("mask.select_all", {"type": 'I', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'INVERT')]}),
- #*_template_items_select_actions(params, "mask.select_all"),
("mask.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
("mask.select_linked_pick", {"type": 'L', "value": 'PRESS'},
{"properties": [("deselect", False)]}),
@@ -874,7 +892,7 @@ def km_graph_editor(params):
("graph.select_linked", {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, None),
op_menu("GRAPH_MT_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}),
op_menu("GRAPH_MT_delete", {"type": 'DEL', "value": 'PRESS'}),
- op_menu("GRAPH_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("GRAPH_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("graph.duplicate_move", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("graph.keyframe_insert", {"type": 'S', "value": 'PRESS'}, None),
("graph.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
@@ -946,6 +964,8 @@ def km_image(params):
("image.view_ndof", {"type": 'NDOF_MOTION', "value": 'ANY'}, None),
("image.view_zoom_in", {"type": 'WHEELINMOUSE', "value": 'PRESS'}, None),
("image.view_zoom_out", {"type": 'WHEELOUTMOUSE', "value": 'PRESS'}, None),
+ ("image.view_zoom_in", {"type": 'WHEELINMOUSE', "value": 'PRESS', "alt": True}, None),
+ ("image.view_zoom_out", {"type": 'WHEELOUTMOUSE', "value": 'PRESS', "alt": True}, None),
("image.view_zoom_in", {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, None),
("image.view_zoom_out", {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, None),
("image.view_zoom", {"type": 'RIGHTMOUSE', "value": 'PRESS', "alt": True}, None),
@@ -978,23 +998,15 @@ def km_image(params):
{"properties": [("point", 'BLACK_POINT')]}),
("image.curves_point_set", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("point", 'WHITE_POINT')]}),
- ("object.mode_set", {"type": 'ONE', "value": 'PRESS'},
- {"properties": [("mode", 'EDIT')]}),
- ("object.mode_set", {"type": 'TWO', "value": 'PRESS'},
- {"properties": [("mode", 'OBJECT')]}),
- ("object.mode_set", {"type": 'THREE', "value": 'PRESS'},
- {"properties": [("mode", 'OBJECT')]}),
- ("object.mode_set", {"type": 'FOUR', "value": 'PRESS'},
- {"properties": [("mode", 'OBJECT')]}),
op_menu_pie("IMAGE_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
# Tools
- op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
- op_tool("builtin.transform", {"type": 'W', "value": 'PRESS'}),
- op_tool("builtin.transform", {"type": 'E', "value": 'PRESS'}),
- op_tool("builtin.transform", {"type": 'R', "value": 'PRESS'}),
- op_tool("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
- op_tool("builtin.annotate", {"type": 'D', "value": 'PRESS'}),
- op_tool("builtin.sample", {"type": 'I', "value": 'PRESS'}),
+ op_tool_cycle("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
+ op_tool_cycle("builtin.transform", {"type": 'W', "value": 'PRESS'}),
+ op_tool_cycle("builtin.transform", {"type": 'E', "value": 'PRESS'}),
+ op_tool_cycle("builtin.transform", {"type": 'R', "value": 'PRESS'}),
+ op_tool_cycle("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
+ op_tool_cycle("builtin.annotate", {"type": 'D', "value": 'PRESS'}),
+ op_tool_cycle("builtin.sample", {"type": 'I', "value": 'PRESS'}),
])
@@ -1066,7 +1078,7 @@ def km_node_editor(params):
("node.select_link_viewer", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("node.backimage_fit", {"type": 'A', "value": 'PRESS', "alt": True}, None),
("node.backimage_sample", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, None),
- op_menu("NODE_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("NODE_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("node.link_make", {"type": 'L', "value": 'PRESS'},
{"properties": [("replace", False)]}),
("node.link_make", {"type": 'L', "value": 'PRESS', "shift": True},
@@ -1151,7 +1163,7 @@ def km_info(params):
("info.report_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
("info.report_delete", {"type": 'DEL', "value": 'PRESS'}, None),
("info.report_copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
- op_menu("INFO_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("INFO_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
return keymap
@@ -1197,7 +1209,7 @@ def km_file_browser(params):
{"properties": [("increment", -10)]}),
("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True},
{"properties": [("increment", -100)]}),
- op_menu("FILEBROWSER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("FILEBROWSER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
return keymap
@@ -1364,7 +1376,7 @@ def km_dopesheet(params):
("wm.context_menu_enum", {"type": 'X', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.auto_snap')]}),
op_menu_pie("DOPESHEET_MT_snap_pie", {"type": 'X', "value": 'PRESS', "shift": True}),
- op_menu("DOPESHEET_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("DOPESHEET_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
op_menu("DOPESHEET_MT_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}),
op_menu("DOPESHEET_MT_delete", {"type": 'DEL', "value": 'PRESS'}),
("action.duplicate_move", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
@@ -1438,7 +1450,7 @@ def km_nla_channels(params):
{"properties": [("extend", True)]}),
("nla.tracks_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
("nla.tracks_delete", {"type": 'DEL', "value": 'PRESS'}, None),
- op_menu("NLA_MT_channel_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("NLA_MT_channel_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
return keymap
@@ -1502,7 +1514,7 @@ def km_nla_editor(params):
{"properties": [("mode", 'TIME_EXTEND')]}),
("transform.transform", {"type": 'R', "value": 'PRESS'},
{"properties": [("mode", 'TIME_SCALE')]}),
- op_menu("NLA_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("NLA_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
op_menu_pie("NLA_MT_snap_pie", {"type": 'X', "value": 'PRESS', "shift": True}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'RET', "value": 'PRESS'}, None),
@@ -1661,7 +1673,7 @@ def km_text(params):
{"properties": [("lines", 1)]}),
("text.line_break", {"type": 'RET', "value": 'PRESS'}, None),
("text.line_break", {"type": 'NUMPAD_ENTER', "value": 'PRESS'}, None),
- op_menu("TEXT_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS', "any": True}),
+ *_template_items_context_menu("TEXT_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS', "any": True}),
("text.line_number", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None),
("text.insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None),
])
@@ -1793,7 +1805,7 @@ def km_sequencer(params):
("transform.seq_slide", {"type": 'EVT_TWEAK_M', "value": 'ANY'}, None),
("transform.transform", {"type": 'E', "value": 'PRESS'},
{"properties": [("mode", 'TIME_EXTEND')]}),
- op_menu("SEQUENCER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("SEQUENCER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'RET', "value": 'PRESS'}, None),
])
@@ -1880,7 +1892,7 @@ def km_console(params):
{"properties": [("text", '\t')]}),
("console.indent_or_autocomplete", {"type": 'TAB', "value": 'PRESS'}, None),
("console.unindent", {"type": 'TAB', "value": 'PRESS', "shift": True}, None),
- op_menu("CONSOLE_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("CONSOLE_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("console.insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None),
])
@@ -1934,6 +1946,8 @@ def km_clip_editor(params):
("clip.view_zoom", {"type": 'TRACKPADPAN', "value": 'ANY', "ctrl": True}, None),
("clip.view_zoom_in", {"type": 'WHEELINMOUSE', "value": 'PRESS'}, None),
("clip.view_zoom_out", {"type": 'WHEELOUTMOUSE', "value": 'PRESS'}, None),
+ ("clip.view_zoom_in", {"type": 'WHEELINMOUSE', "value": 'PRESS', "alt": True}, None),
+ ("clip.view_zoom_out", {"type": 'WHEELOUTMOUSE', "value": 'PRESS', "alt": True}, None),
("clip.view_zoom_in", {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, None),
("clip.view_zoom_out", {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, None),
("clip.view_zoom_ratio", {"type": 'NUMPAD_8', "value": 'PRESS', "ctrl": True},
@@ -1999,7 +2013,7 @@ def km_clip_editor(params):
("clip.keyframe_insert", {"type": 'S', "value": 'PRESS'}, None),
("clip.keyframe_delete", {"type": 'S', "value": 'PRESS', "alt": True}, None),
("clip.join_tracks", {"type": 'J', "value": 'PRESS', "ctrl": True}, None),
- op_menu("CLIP_MT_tracking_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("CLIP_MT_tracking_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("wm.context_toggle", {"type": 'L', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.lock_selection')]}),
("wm.context_toggle", {"type": 'D', "value": 'PRESS', "alt": True},
@@ -2192,7 +2206,7 @@ def km_animation_channels(params):
("anim.channels_group", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
("anim.channels_ungroup", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None),
# Menus.
- op_menu("DOPESHEET_MT_channel_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("DOPESHEET_MT_channel_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
return keymap
@@ -2221,10 +2235,12 @@ def km_grease_pencil(_params):
def _grease_pencil_selection(params):
return [
- # Select all
- ("gpencil.select_box", {"type": 'A', "value": 'PRESS', "ctrl": True}, None),
("gpencil.select", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("extend", True), ("toggle", True)]}),
+ # Select all
+ ("gpencil.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
+ ("gpencil.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True, "shift": True}, {"properties": [("action", 'DESELECT')]}),
+ ("gpencil.select_all", {"type": 'I', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'INVERT')]}),
# Select linked
("gpencil.select_linked", {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, None),
# Select alternate
@@ -2237,14 +2253,6 @@ def _grease_pencil_selection(params):
]
-def _grease_pencil_display():
- return [
- ("wm.context_toggle", {"type": 'Q', "value": 'PRESS', "shift": True},
- {"properties": [("data_path", 'space_data.overlay.use_gpencil_edit_lines')]}),
- ("wm.context_toggle", {"type": 'Q', "value": 'PRESS', "shift": True, "alt": True},
- {"properties": [("data_path", 'space_data.overlay.use_gpencil_multiedit_line_only')]}),
- ]
-
def km_grease_pencil_stroke_edit_mode(params):
items = []
@@ -2255,18 +2263,13 @@ def km_grease_pencil_stroke_edit_mode(params):
)
items.extend([
- # Interpolation
- ("gpencil.interpolate", {"type": 'E', "value": 'PRESS', "ctrl": True, "alt": True}, None),
- ("gpencil.interpolate_sequence", {"type": 'E', "value": 'PRESS', "shift": True, "ctrl": True}, None),
# Normal select
- ("gpencil.select", {"type": 'LEFTMOUSE', "value": 'PRESS'},
+ ("gpencil.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
{"properties": [("deselect_all", True)]}),
# Selection
*_grease_pencil_selection(params),
# Duplicate and move selected points
("gpencil.duplicate_move", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
- # Extrude and move selected points
- ("gpencil.extrude_move", {"type": 'E', "value": 'PRESS'}, None),
# Delete
op_menu("VIEW3D_MT_edit_gpencil_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}),
op_menu("VIEW3D_MT_edit_gpencil_delete", {"type": 'DEL', "value": 'PRESS'}),
@@ -2275,7 +2278,7 @@ def km_grease_pencil_stroke_edit_mode(params):
("gpencil.active_frames_delete_all", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "shift": True}, None),
# Context menu
- op_menu("VIEW3D_MT_gpencil_edit_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("VIEW3D_MT_gpencil_edit_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
# Separate
op_menu("GPENCIL_MT_separate", {"type": 'P', "value": 'PRESS'}),
# Split and joint strokes
@@ -2286,20 +2289,13 @@ def km_grease_pencil_stroke_edit_mode(params):
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
("gpencil.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
# Snap
- op_menu("GPENCIL_MT_snap", {"type": 'S', "value": 'PRESS', "shift": True}),
+ op_menu("GPENCIL_MT_snap", {"type": 'X', "value": 'PRESS', "shift": True}),
# Show/hide
("gpencil.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
("gpencil.hide", {"type": 'H', "value": 'PRESS', "ctrl": True},
{"properties": [("unselected", False)]}),
- ("gpencil.hide", {"type": 'H', "value": 'PRESS', "shift": True},
- {"properties": [("unselected", True)]}),
- ("gpencil.selection_opacity_toggle", {"type": 'H', "value": 'PRESS', "ctrl": True}, None),
- # Display
- *_grease_pencil_display(),
# Isolate layer
("gpencil.layer_isolate", {"type": 'NUMPAD_ASTERIX', "value": 'PRESS'}, None),
- # Move to layer
- ("gpencil.move_to_layer", {"type": 'G', "value": 'PRESS'}, None),
# Transform tools
("transform.translate", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
("wm.context_toggle", {"type": 'B', "value": 'PRESS'},
@@ -2315,6 +2311,9 @@ def km_grease_pencil_stroke_edit_mode(params):
{"properties": [("mode", 2)]}),
# Tools
*_template_items_basic_tools(),
+ op_tool_cycle("builtin.extrude", {"type": 'E', "value": 'PRESS', "ctrl": True}),
+ op_tool_cycle("builtin.radius", {"type": 'R', "value": 'PRESS', "ctrl": True}),
+ op_tool_cycle("builtin.bend", {"type": 'B', "value": 'PRESS', "ctrl": True}),
])
@@ -2337,16 +2336,16 @@ def km_grease_pencil_stroke_paint_mode(params):
("wm.radial_control", {"type": 'S', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_paint.brush.size')]}),
# Draw context menu
- op_panel("VIEW3D_PT_gpencil_draw_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_panel("VIEW3D_PT_gpencil_draw_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
# Draw delete menu
op_menu("GPENCIL_MT_gpencil_draw_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}),
op_menu("GPENCIL_MT_gpencil_draw_delete", {"type": 'DEL', "value": 'PRESS'}),
# Tools
- op_tool("builtin_brush.Draw", {"type": 'D', "value": 'PRESS'}),
- op_tool("builtin_brush.Fill", {"type": 'F', "value": 'PRESS'}),
- op_tool("builtin_brush.Erase", {"type": 'E', "value": 'PRESS'}),
- op_tool("builtin.cutter", {"type": 'K', "value": 'PRESS'}),
- op_tool("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
+ op_tool_cycle("builtin_brush.Draw", {"type": 'D', "value": 'PRESS'}),
+ op_tool_cycle("builtin_brush.Fill", {"type": 'F', "value": 'PRESS'}),
+ op_tool_cycle("builtin_brush.Erase", {"type": 'E', "value": 'PRESS'}),
+ op_tool_cycle("builtin.cutter", {"type": 'K', "value": 'PRESS'}),
+ op_tool_cycle("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
])
return keymap
@@ -2478,9 +2477,7 @@ def km_grease_pencil_stroke_sculpt_mode(params):
("wm.radial_control", {"type": 'S', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.brush.size')]}),
# Context menu
- op_panel("VIEW3D_PT_gpencil_sculpt_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
- # Display
- *_grease_pencil_display(),
+ *_template_items_context_panel("VIEW3D_PT_gpencil_sculpt_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
return keymap
@@ -2508,8 +2505,6 @@ def km_grease_pencil_stroke_weight_mode(params):
# Brush size.
("wm.radial_control", {"type": 'S', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.weight_brush.size')]}),
- # Display
- *_grease_pencil_display(),
])
return keymap
@@ -2607,15 +2602,14 @@ def km_pose(params):
("anim.keyframe_delete_v3d", {"type": 'S', "value": 'PRESS', "alt": True}, None),
("anim.keying_set_active_set", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
- op_menu("VIEW3D_MT_pose_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("VIEW3D_MT_pose_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
# Tools
- op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
- op_tool("builtin.move", {"type": 'W', "value": 'PRESS'}),
- op_tool("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
- op_tool("builtin.scale", {"type": 'R', "value": 'PRESS'}),
- op_tool("builtin.scale_cage", {"type": 'R', "value": 'PRESS', "shift": True}),
- op_tool("builtin.transform", {"type": 'T', "value": 'PRESS'}),
- op_tool("builtin.measure", {"type": 'M', "value": 'PRESS'}),
+ op_tool_cycle("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
+ op_tool_cycle("builtin.move", {"type": 'W', "value": 'PRESS'}),
+ op_tool_cycle("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
+ op_tool_cycle("builtin.scale", {"type": 'R', "value": 'PRESS'}),
+ op_tool_cycle("builtin.transform", {"type": 'T', "value": 'PRESS'}),
+ op_tool_cycle("builtin.measure", {"type": 'M', "value": 'PRESS'}),
])
@@ -2679,7 +2673,7 @@ def km_object_mode(params):
{"properties": [("type", 'Scaling')]}),
("anim.keyframe_delete_v3d", {"type": 'S', "value": 'PRESS', "alt": True}, None),
("anim.keying_set_active_set", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
- op_menu("VIEW3D_MT_object_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("VIEW3D_MT_object_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("object.move_to_collection", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
("object.link_to_collection", {"type": 'G', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("object.hide_view_clear", {"type": 'H', "value": 'PRESS', "alt": True}, None),
@@ -2757,14 +2751,14 @@ def km_curve(params):
{"properties": [("unselected", False)]}),
("curve.hide", {"type": 'H', "value": 'PRESS', "shift": True},
{"properties": [("unselected", True)]}),
- op_menu("VIEW3D_MT_edit_curve_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("VIEW3D_MT_edit_curve_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("wm.context_toggle", {"type": 'B', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.use_proportional_edit')]}),
# Tools
*_template_items_basic_tools(),
- op_tool("builtin.extrude", {"type": 'E', "value": 'PRESS', "ctrl": True}),
- op_tool("builtin.tilt", {"type": 'Y', "value": 'PRESS'}),
- op_tool("builtin.radius", {"type": 'U', "value": 'PRESS'}),
+ op_tool_cycle("builtin.extrude", {"type": 'E', "value": 'PRESS', "ctrl": True}),
+ op_tool_cycle("builtin.tilt", {"type": 'Y', "value": 'PRESS'}),
+ op_tool_cycle("builtin.radius", {"type": 'U', "value": 'PRESS'}),
])
@@ -2859,7 +2853,7 @@ def km_image_paint(params):
("wm.context_toggle", {"type": 'S', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'tool_settings.image_paint.brush.use_smooth_stroke')]}),
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
- op_panel("VIEW3D_PT_paint_texture_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_panel("VIEW3D_PT_paint_texture_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
# Tools
("paint.brush_select", {"type": 'D', "value": 'PRESS'},
{"properties": [("image_tool", 'DRAW')]}),
@@ -2867,7 +2861,7 @@ def km_image_paint(params):
{"properties": [("image_tool", 'SOFTEN')]}),
("paint.brush_select", {"type": 'G', "value": 'PRESS'},
{"properties": [("image_tool", 'FILL')]}),
- op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
+ op_tool_cycle("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
])
return keymap
@@ -2909,13 +2903,13 @@ 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'}),
- op_panel("VIEW3D_PT_paint_vertex_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_panel("VIEW3D_PT_paint_vertex_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
# Tools
("paint.brush_select", {"type": 'D', "value": 'PRESS'},
{"properties": [("vertex_tool", 'DRAW')]}),
("paint.brush_select", {"type": 'B', "value": 'PRESS'},
{"properties": [("vertex_tool", 'BLUR')]}),
- op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
+ op_tool_cycle("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
])
return keymap
@@ -2943,7 +2937,7 @@ def km_weight_paint(params):
{"properties": [("data_path", 'weight_paint_object.data.use_paint_mask_vertex')]}),
("wm.context_toggle", {"type": 'S', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'tool_settings.weight_paint.brush.use_smooth_stroke')]}),
- op_panel("VIEW3D_PT_paint_weight_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_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),
# Tools
@@ -2951,8 +2945,8 @@ def km_weight_paint(params):
{"properties": [("weight_tool", 'DRAW')]}),
("paint.brush_select", {"type": 'B', "value": 'PRESS'},
{"properties": [("weight_tool", 'BLUR')]}),
- op_tool("builtin.sample_weight", {"type": 'I', "value": 'PRESS'}),
- op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
+ op_tool_cycle("builtin.sample_weight", {"type": 'I', "value": 'PRESS'}),
+ op_tool_cycle("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
])
return keymap
@@ -2988,8 +2982,10 @@ def km_sculpt(params):
("object.subdivision_set", {"type": 'PAGE_DOWN', "value": 'PRESS'},
{"properties": [("level", -1), ("relative", True)]}),
# Mask
- ("paint.mask_flood_fill", {"type": 'M', "value": 'PRESS', "alt": True},
+ ("paint.mask_flood_fill", {"type": 'A', "value": 'PRESS', "ctrl": True},
{"properties": [("mode", 'VALUE'), ("value", 0.0)]}),
+ ("paint.mask_flood_fill", {"type": 'A', "value": 'PRESS', "ctrl": True, "shift": True},
+ {"properties": [("mode", 'VALUE'), ("value", 1.0)]}),
("paint.mask_flood_fill", {"type": 'I', "value": 'PRESS', "ctrl": True},
{"properties": [("mode", 'INVERT')]}),
("paint.mask_lasso_gesture", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
@@ -2998,6 +2994,9 @@ def km_sculpt(params):
# Dynamic topology
("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ # Remesh
+ ("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("object.quadriflow_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True, "alt": True}, None),
# Brush properties
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
{"properties": [("scalar", 0.9)]}),
@@ -3050,7 +3049,7 @@ def km_sculpt(params):
{"properties": [("sculpt_tool", 'DRAW')]}),
# Menus
- op_panel("VIEW3D_PT_sculpt_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_panel("VIEW3D_PT_sculpt_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
return keymap
@@ -3090,6 +3089,9 @@ def km_mesh(params):
("mesh.select_more", {"type": 'UP_ARROW', "value": 'PRESS'}, None),
("mesh.select_less", {"type": 'DOWN_ARROW', "value": 'PRESS'}, None),
("mesh.select_linked", {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, None),
+
+ *_template_items_editmode_mesh_select_mode(params),
+
# Hide/reveal.
("mesh.hide", {"type": 'H', "value": 'PRESS', "ctrl": True},
{"properties": [("unselected", False)]}),
@@ -3105,14 +3107,14 @@ def km_mesh(params):
("wm.context_toggle", {"type": 'B', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.use_proportional_edit')]}),
# Menus.
- op_menu("VIEW3D_MT_edit_mesh_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("VIEW3D_MT_edit_mesh_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
#Tools
*_template_items_basic_tools(),
- op_tool("builtin.bevel", {"type": 'B', "value": 'PRESS', "ctrl": True}),
- op_tool("builtin.inset_faces", {"type": 'I', "value": 'PRESS'}),
- op_tool("builtin.extrude_region", {"type": 'E', "value": 'PRESS', "ctrl": True}),
- op_tool("builtin.knife", {"type": 'K', "value": 'PRESS'}),
- op_tool("builtin.loop_cut", {"type": 'C', "value": 'PRESS', "alt": True}),
+ op_tool_cycle("builtin.bevel", {"type": 'B', "value": 'PRESS', "ctrl": True}),
+ op_tool_cycle("builtin.inset_faces", {"type": 'I', "value": 'PRESS'}),
+ op_tool_cycle("builtin.extrude_region", {"type": 'E', "value": 'PRESS', "ctrl": True}),
+ op_tool_cycle("builtin.knife", {"type": 'K', "value": 'PRESS'}),
+ op_tool_cycle("builtin.loop_cut", {"type": 'C', "value": 'PRESS', "alt": True}),
])
@@ -3168,11 +3170,11 @@ def km_armature(params):
("armature.dissolve", {"type": 'BACK_SPACE', "value": 'PRESS', "ctrl": True}, None),
("armature.dissolve", {"type": 'DEL', "value": 'PRESS', "ctrl": True}, None),
# Menus.
- op_menu("VIEW3D_MT_armature_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("VIEW3D_MT_armature_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
# Tools.
*_template_items_basic_tools(),
- op_tool("builtin.roll", {"type": 'Y', "value": 'PRESS'}),
- op_tool("builtin.extrude", {"type": 'E', "value": 'PRESS', "ctrl": True}),
+ op_tool_cycle("builtin.roll", {"type": 'Y', "value": 'PRESS'}),
+ op_tool_cycle("builtin.extrude", {"type": 'E', "value": 'PRESS', "ctrl": True}),
])
@@ -3202,7 +3204,7 @@ def km_metaball(params):
("mball.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True, "shift": True}, {"properties": [("action", 'DESELECT')]}),
("mball.select_all", {"type": 'I', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'INVERT')]}),
("mball.select_similar", {"type": 'G', "value": 'PRESS', "shift": True}, None),
- op_menu("VIEW3D_MT_edit_metaball_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("VIEW3D_MT_edit_metaball_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("wm.context_toggle", {"type": 'B', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.use_proportional_edit')]}),
# Tools
@@ -3228,17 +3230,16 @@ def km_lattice(params):
("lattice.select_more", {"type": 'UP_ARROW', "value": 'PRESS'}, None),
("lattice.select_less", {"type": 'DOWN_ARROW', "value": 'PRESS'}, None),
("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None),
- op_menu("VIEW3D_MT_edit_lattice_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("VIEW3D_MT_edit_lattice_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("wm.context_toggle", {"type": 'B', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.use_proportional_edit')]}),
# Tools
- op_tool("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
- op_tool("builtin.move", {"type": 'W', "value": 'PRESS'}),
- op_tool("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
- op_tool("builtin.scale", {"type": 'R', "value": 'PRESS'}),
- op_tool("builtin.scale_cage", {"type": 'R', "value": 'PRESS', "shift": True}),
- op_tool("builtin.transform", {"type": 'T', "value": 'PRESS'}),
- op_tool("builtin.measure", {"type": 'M', "value": 'PRESS'}),
+ op_tool_cycle("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
+ op_tool_cycle("builtin.move", {"type": 'W', "value": 'PRESS'}),
+ op_tool_cycle("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
+ op_tool_cycle("builtin.scale", {"type": 'R', "value": 'PRESS'}),
+ op_tool_cycle("builtin.transform", {"type": 'T', "value": 'PRESS'}),
+ op_tool_cycle("builtin.measure", {"type": 'M', "value": 'PRESS'}),
])
return keymap
@@ -3278,7 +3279,7 @@ def km_particle(params):
{"properties": [("data_path_primary", 'tool_settings.particle_edit.brush.strength')]}),
("wm.context_toggle", {"type": 'B', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.use_proportional_edit')]}),
- op_menu("VIEW3D_MT_particle_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("VIEW3D_MT_particle_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
return keymap
@@ -3368,7 +3369,7 @@ def km_font(params):
("font.text_insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None),
("font.text_insert", {"type": 'BACK_SPACE', "value": 'PRESS', "alt": True},
{"properties": [("accent", True)]}),
- op_menu("VIEW3D_MT_edit_text_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
+ *_template_items_context_menu("VIEW3D_MT_edit_text_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
@@ -3553,174 +3554,6 @@ def km_transform_modal_map(_params):
# ------------------------------------------------------------------------------
-# Gizmos
-
-# Fallback for gizmos that don't have custom a custom key-map.
-def km_generic_gizmo(_params):
- keymap = (
- "Generic Gizmo",
- {"space_type": 'EMPTY', "region_type": 'WINDOW'},
- {"items": _template_items_gizmo_tweak_value()},
- )
-
- return keymap
-
-
-def km_generic_gizmo_drag(_params):
- keymap = (
- "Generic Gizmo Drag",
- {"space_type": 'EMPTY', "region_type": 'WINDOW'},
- {"items": _template_items_gizmo_tweak_value_drag()},
- )
-
- return keymap
-
-
-def km_generic_gizmo_click_drag(_params):
- keymap = (
- "Generic Gizmo Click Drag",
- {"space_type": 'EMPTY', "region_type": 'WINDOW'},
- {"items": _template_items_gizmo_tweak_value_click_drag()},
- )
-
- return keymap
-
-
-def km_generic_gizmo_maybe_drag(params):
- keymap = (
- "Generic Gizmo Maybe Drag",
- {"space_type": 'EMPTY', "region_type": 'WINDOW'},
- {"items":
- _template_items_gizmo_tweak_value_drag()
- },
- )
-
- return keymap
-
-
-# ------------------------------------------------------------------------------
-# Tool System Keymaps
-
-
-def km_3d_view_tool_transform(params):
- return (
- "3D View Tool: Transform",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("transform.from_gizmo", {"type": 'MIDDLEMOUSE', "value": 'ANY'}, None),
- *_template_items_tool_select_actions("view3d.select_box", type=params.tool_tweak, value='ANY'),
- ]},
- )
-
-
-def km_3d_view_tool_move(params):
- return (
- "3D View Tool: Move",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("transform.translate", {"type": 'MIDDLEMOUSE', "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
- *_template_items_tool_select_actions("view3d.select_box", type=params.tool_tweak, value='ANY'),
- ]},
- )
-
-
-def km_3d_view_tool_rotate(params):
- return (
- "3D View Tool: Rotate",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("transform.rotate", {"type": 'MIDDLEMOUSE', "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
- *_template_items_tool_select_actions("view3d.select_box", type=params.tool_tweak, value='ANY'),
- ]},
- )
-
-
-def km_3d_view_tool_scale(params):
- return (
- "3D View Tool: Scale",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("transform.resize", {"type": 'MIDDLEMOUSE', "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
- *_template_items_tool_select_actions("view3d.select_box", type=params.tool_tweak, value='ANY'),
- ]},
- )
-
-
-def km_3d_view_tool_edit_mesh_extrude_region(params):
- return (
- "3D View Tool: Edit Mesh, Extrude Region",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("mesh.extrude_context_move", {"type": 'MIDDLEMOUSE', "value": 'ANY'},
- {"properties": [("TRANSFORM_OT_translate", [("release_confirm", True)])]}),
- *_template_items_tool_select_actions("view3d.select_box", type=params.tool_tweak, value='ANY'),
- ]},
- )
-
-
-def km_3d_view_tool_edit_mesh_shear(params):
- return (
- "3D View Tool: Edit Mesh, Shear",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("transform.shear", {"type": 'MIDDLEMOUSE', "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
- *_template_items_tool_select_actions("view3d.select_box", type=params.tool_tweak, value='ANY'),
- ]},
- )
-
-
-def km_3d_view_tool_edit_mesh_spin(params):
- return (
- "3D View Tool: Edit Mesh, Spin",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("mesh.spin", {"type": 'MIDDLEMOUSE', "value": 'ANY'}, None),
- *_template_items_tool_select_actions("view3d.select_box", type=params.tool_tweak, value='ANY'),
- ]},
- )
-
-
-def km_3d_view_tool_edit_mesh_spin_duplicate(params):
- return (
- "3D View Tool: Edit Mesh, Spin Duplicates",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("mesh.spin", {"type": 'MIDDLEMOUSE', "value": 'ANY'},
- {"properties": [("dupli", True)]}),
- *_template_items_tool_select_actions("view3d.select_box", type=params.tool_tweak, value='ANY'),
- ]},
- )
-
-
-def km_3d_view_tool_edit_curve_extrude(params):
- return (
- "3D View Tool: Edit Curve, Extrude",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("curve.extrude_move", {"type": 'MIDDLEMOUSE', "value": 'ANY'},
- {"properties": [("TRANSFORM_OT_translate", [("release_confirm", True)])]}),
- *_template_items_tool_select_actions("view3d.select_box", type=params.tool_tweak, value='ANY'),
- ]},
- )
-
-
-def km_3d_view_tool_edit_armature_extrude(params):
- return (
- "3D View Tool: Edit Armature, Extrude",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("armature.extrude_move", {"type": 'MIDDLEMOUSE', "value": 'ANY'},
- {"properties": [("TRANSFORM_OT_translate", [("release_confirm", True)])]}),
- *_template_items_tool_select_actions("view3d.select_box", type=params.tool_tweak, value='ANY'),
- ]},
- )
-
-
-# ------------------------------------------------------------------------------
# Full Configuration
def generate_keymaps(params=None):
@@ -3808,21 +3641,4 @@ def generate_keymaps(params=None):
km_eyedropper_colorramp_pointsampling_map(params),
km_transform_modal_map(params),
- # Gizmos.
- km_generic_gizmo(params),
- km_generic_gizmo_drag(params),
- km_generic_gizmo_maybe_drag(params),
- km_generic_gizmo_click_drag(params),
-
- # Tool System.
- km_3d_view_tool_transform(params),
- km_3d_view_tool_move(params),
- km_3d_view_tool_rotate(params),
- km_3d_view_tool_scale(params),
- km_3d_view_tool_edit_mesh_extrude_region(params),
- km_3d_view_tool_edit_mesh_shear(params),
- km_3d_view_tool_edit_mesh_spin(params),
- km_3d_view_tool_edit_mesh_spin_duplicate(params),
- km_3d_view_tool_edit_curve_extrude(params),
- km_3d_view_tool_edit_armature_extrude(params),
]
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index bb92e070d00..5af2bd22222 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -32,7 +32,6 @@ _modules = [
"constraint",
"file",
"image",
- "mask",
"mesh",
"node",
"object",
diff --git a/release/scripts/startup/bl_operators/freestyle.py b/release/scripts/startup/bl_operators/freestyle.py
index baac3556fb2..393dd467e88 100644
--- a/release/scripts/startup/bl_operators/freestyle.py
+++ b/release/scripts/startup/bl_operators/freestyle.py
@@ -89,16 +89,16 @@ class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator):
min_dist = sys.float_info.max
max_dist = -min_dist
if m.type == 'DISTANCE_FROM_CAMERA':
- ob_to_cam = matrix_to_camera * ob.matrix_world
+ ob_to_cam = matrix_to_camera @ ob.matrix_world
for vert in selected_verts:
# dist in the camera space
- dist = (ob_to_cam * vert.co).length
+ dist = (ob_to_cam @ vert.co).length
min_dist = min(dist, min_dist)
max_dist = max(dist, max_dist)
elif m.type == 'DISTANCE_FROM_OBJECT':
for vert in selected_verts:
# dist in the world space
- dist = (ob.matrix_world * vert.co - target_location).length
+ dist = (ob.matrix_world @ vert.co - target_location).length
min_dist = min(dist, min_dist)
max_dist = max(dist, max_dist)
# Fill the Range Min/Max entries with the computed distances
diff --git a/release/scripts/startup/bl_operators/mask.py b/release/scripts/startup/bl_operators/mask.py
deleted file mode 100644
index 2635f535b0b..00000000000
--- a/release/scripts/startup/bl_operators/mask.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8-80 compliant>
-
-from bpy.types import Menu
-from bpy.app.translations import contexts as i18n_contexts
-
-
-class MASK_MT_add(Menu):
- bl_idname = "MASK_MT_add"
- bl_label = "Add"
- bl_translation_context = i18n_contexts.operator_default
-
- def draw(self, _context):
- layout = self.layout
-
- layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("mask.primitive_circle_add", text="Circle", icon='MESH_CIRCLE')
- layout.operator("mask.primitive_square_add", text="Square", icon='MESH_PLANE')
-
-
-classes = (
- MASK_MT_add,
-)
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 0f6deea71eb..e49ca0320c7 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -349,8 +349,8 @@ class QuickSmoke(ObjectModeOperator, Operator):
)
def execute(self, context):
- if not bpy.app.build_options.mod_smoke:
- self.report({'ERROR'}, "Built without Smoke modifier support")
+ if not bpy.app.build_options.fluid:
+ self.report({'ERROR'}, "Built without Fluid modifier")
return {'CANCELLED'}
fake_context = context.copy()
@@ -366,11 +366,17 @@ class QuickSmoke(ObjectModeOperator, Operator):
for obj in mesh_objects:
fake_context["object"] = obj
# make each selected object a smoke flow
- bpy.ops.object.modifier_add(fake_context, type='SMOKE')
- obj.modifiers[-1].smoke_type = 'FLOW'
+ bpy.ops.object.modifier_add(fake_context, type='FLUID')
+ obj.modifiers[-1].fluid_type = 'FLOW'
# set type
- obj.modifiers[-1].flow_settings.smoke_flow_type = self.style
+ obj.modifiers[-1].flow_settings.flow_type = self.style
+
+ # set flow behavior
+ obj.modifiers[-1].flow_settings.flow_behavior = 'INFLOW'
+
+ # use some surface distance for smoke emission
+ obj.modifiers[-1].flow_settings.surface_distance = 1.5
if not self.show_flows:
obj.display_type = 'WIRE'
@@ -388,10 +394,13 @@ class QuickSmoke(ObjectModeOperator, Operator):
obj.scale = 0.5 * (max_co - min_co) + Vector((1.0, 1.0, 2.0))
# setup smoke domain
- bpy.ops.object.modifier_add(type='SMOKE')
- obj.modifiers[-1].smoke_type = 'DOMAIN'
+ bpy.ops.object.modifier_add(type='FLUID')
+ obj.modifiers[-1].fluid_type = 'DOMAIN'
if self.style == 'FIRE' or self.style == 'BOTH':
- obj.modifiers[-1].domain_settings.use_high_resolution = True
+ obj.modifiers[-1].domain_settings.use_noise = True
+
+ # set correct cache file format for smoke
+ obj.modifiers[-1].domain_settings.cache_data_format = 'UNI'
# Setup material
@@ -431,47 +440,25 @@ class QuickSmoke(ObjectModeOperator, Operator):
return {'FINISHED'}
-class QuickFluid(ObjectModeOperator, Operator):
- """Use selected objects in a fluid simulation"""
- bl_idname = "object.quick_fluid"
- bl_label = "Quick Fluid"
+class QuickLiquid(Operator):
+ bl_idname = "object.quick_liquid"
+ bl_label = "Quick Liquid"
bl_options = {'REGISTER', 'UNDO'}
- style: EnumProperty(
- name="Fluid Style",
- items=(
- ('INFLOW', "Inflow", ""),
- ('BASIC', "Basic", ""),
- ),
- default='BASIC',
- )
- initial_velocity: FloatVectorProperty(
- name="Initial Velocity",
- description="Initial velocity of the fluid",
- min=-100.0, max=100.0,
- default=(0.0, 0.0, 0.0),
- subtype='VELOCITY',
- )
show_flows: BoolProperty(
- name="Render Fluid Objects",
- description="Keep the fluid objects visible during rendering",
- default=False,
- )
- start_baking: BoolProperty(
- name="Start Fluid Bake",
- description=("Start baking the fluid immediately "
- "after creating the domain object"),
- default=False,
- )
+ name="Render Liquid Objects",
+ description="Keep the liquid objects visible during rendering",
+ default=False,
+ )
def execute(self, context):
- if not bpy.app.build_options.mod_fluid:
- self.report({'ERROR'}, "Built without Fluid modifier support")
+ if not bpy.app.build_options.fluid:
+ self.report({'ERROR'}, "Built without Fluid modifier")
return {'CANCELLED'}
fake_context = context.copy()
mesh_objects = [obj for obj in context.selected_objects
- if (obj.type == 'MESH' and 0.0 not in obj.dimensions)]
+ if obj.type == 'MESH']
min_co = Vector((100000.0, 100000.0, 100000.0))
max_co = -min_co
@@ -481,47 +468,51 @@ class QuickFluid(ObjectModeOperator, Operator):
for obj in mesh_objects:
fake_context["object"] = obj
- # make each selected object a fluid
- bpy.ops.object.modifier_add(fake_context, type='FLUID_SIMULATION')
-
- # fluid has to be before constructive modifiers,
- # so it might not be the last modifier
- for mod in obj.modifiers:
- if mod.type == 'FLUID_SIMULATION':
- break
-
- if self.style == 'INFLOW':
- mod.settings.type = 'INFLOW'
- mod.settings.inflow_velocity = self.initial_velocity
- else:
- mod.settings.type = 'FLUID'
- mod.settings.initial_velocity = self.initial_velocity
+ # make each selected object a liquid flow
+ bpy.ops.object.modifier_add(fake_context, type='FLUID')
+ obj.modifiers[-1].fluid_type = 'FLOW'
+
+ # set type
+ obj.modifiers[-1].flow_settings.flow_type = 'LIQUID'
+
+ # set flow behavior
+ obj.modifiers[-1].flow_settings.flow_behavior = 'GEOMETRY'
+
+ # use some surface distance for smoke emission
+ obj.modifiers[-1].flow_settings.surface_distance = 0.0
- obj.hide_render = not self.show_flows
if not self.show_flows:
obj.display_type = 'WIRE'
# store bounding box min/max for the domain object
obj_bb_minmax(obj, min_co, max_co)
- # add the fluid domain object
+ # add the liquid domain object
bpy.ops.mesh.primitive_cube_add()
obj = context.active_object
- obj.name = "Fluid Domain"
-
- # give the fluid some room below the flows
- # and scale with initial velocity
- v = 0.5 * self.initial_velocity
- obj.location = 0.5 * (max_co + min_co) + Vector((0.0, 0.0, -1.0)) + v
- obj.scale = (
- 0.5 * (max_co - min_co) +
- Vector((1.0, 1.0, 2.0)) +
- Vector((abs(v[0]), abs(v[1]), abs(v[2])))
- )
+ obj.name = "Liquid Domain"
- # setup smoke domain
- bpy.ops.object.modifier_add(type='FLUID_SIMULATION')
- obj.modifiers[-1].settings.type = 'DOMAIN'
+ # give the liquid some room above the flows
+ obj.location = 0.5 * (max_co + min_co) + Vector((0.0, 0.0, -1.0))
+ obj.scale = 0.5 * (max_co - min_co) + Vector((1.0, 1.0, 2.0))
+
+ # setup liquid domain
+ bpy.ops.object.modifier_add(type='FLUID')
+ obj.modifiers[-1].fluid_type = 'DOMAIN'
+ obj.modifiers[-1].domain_settings.domain_type = 'LIQUID'
+ # set all domain borders to obstacle
+ obj.modifiers[-1].domain_settings.use_collision_border_front = True
+ obj.modifiers[-1].domain_settings.use_collision_border_back = True
+ obj.modifiers[-1].domain_settings.use_collision_border_right = True
+ obj.modifiers[-1].domain_settings.use_collision_border_left = True
+ obj.modifiers[-1].domain_settings.use_collision_border_top = True
+ obj.modifiers[-1].domain_settings.use_collision_border_bottom = True
+
+ # set correct cache file format for liquid
+ obj.modifiers[-1].domain_settings.cache_mesh_format = 'BOBJECT'
+
+ # allocate and show particle system for FLIP
+ obj.modifiers[-1].domain_settings.use_flip_particles = True
# make the domain smooth so it renders nicely
bpy.ops.object.shade_smooth()
@@ -529,7 +520,7 @@ class QuickFluid(ObjectModeOperator, Operator):
# create a ray-transparent material for the domain
bpy.ops.object.material_slot_add()
- mat = bpy.data.materials.new("Fluid Domain Material")
+ mat = bpy.data.materials.new("Liquid Domain Material")
obj.material_slots[0].material = mat
# Make sure we use nodes
@@ -560,15 +551,12 @@ class QuickFluid(ObjectModeOperator, Operator):
links.new(node_absorption.outputs["Volume"], node_out.inputs["Volume"])
node_absorption.inputs["Color"].default_value = (0.8, 0.9, 1.0, 1.0)
- if self.start_baking:
- bpy.ops.fluid.bake('INVOKE_DEFAULT')
-
return {'FINISHED'}
classes = (
QuickExplode,
- QuickFluid,
QuickFur,
QuickSmoke,
+ QuickLiquid,
)
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index deb33f77050..c811f542a3a 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -382,16 +382,16 @@ class AddPresetFluid(AddPresetBase, Operator):
"""Add or remove a Fluid Preset"""
bl_idname = "fluid.preset_add"
bl_label = "Add Fluid Preset"
- preset_menu = "FLUID_PT_presets"
+ preset_menu = "FLUID_MT_presets"
preset_defines = [
"fluid = bpy.context.fluid"
- ]
+ ]
preset_values = [
- "fluid.settings.viscosity_base",
- "fluid.settings.viscosity_exponent",
- ]
+ "fluid.domain_settings.viscosity_base",
+ "fluidanta.domain_settings.viscosity_exponent",
+ ]
preset_subdir = "fluid"
diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py
index 97149133dec..bc80500c888 100644
--- a/release/scripts/startup/bl_operators/rigidbody.py
+++ b/release/scripts/startup/bl_operators/rigidbody.py
@@ -241,7 +241,8 @@ class ConnectRigidBodies(Operator):
description="Pattern used to connect objects",
items=(
('SELECTED_TO_ACTIVE', "Selected to Active", "Connect selected objects to the active object"),
- ('CHAIN_DISTANCE', "Chain by Distance", "Connect objects as a chain based on distance, starting at the active object"),
+ ('CHAIN_DISTANCE', "Chain by Distance", "Connect objects as a chain based on distance, "
+ "starting at the active object"),
),
default='SELECTED_TO_ACTIVE',
)
diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
index 4e61874b440..1f56cbe6d57 100644
--- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py
+++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
@@ -283,7 +283,16 @@ def mergeUvIslands(islandList):
# UV Edge list used for intersections as well as unique points.
edges, uniqueEdgePoints = island2Edge(islandList[islandIdx])
- decoratedIslandList.append([islandList[islandIdx], totFaceArea, efficiency, islandBoundsArea, w, h, edges, uniqueEdgePoints])
+ decoratedIslandList.append([
+ islandList[islandIdx],
+ totFaceArea,
+ efficiency,
+ islandBoundsArea,
+ w,
+ h,
+ edges,
+ uniqueEdgePoints,
+ ])
# Sort by island bounding box area, smallest face area first.
# no.. chance that to most simple edge loop first.
@@ -389,7 +398,8 @@ def mergeUvIslands(islandList):
# testcount+=1
# print 'Testing intersect'
- Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, Vector((boxLeft, boxBottom)))
+ Intersect = islandIntersectUvIsland(
+ sourceIsland, targetIsland, Vector((boxLeft, boxBottom)))
# print 'Done', Intersect
if Intersect == 1: # Line intersect, don't bother with this any more
pass
diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
index 1f982c331fb..39d792bd557 100644
--- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py
+++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
@@ -176,7 +176,14 @@ class VertexPaintDirt(Operator):
obj = context.object
mesh = obj.data
- ret = applyVertexDirt(mesh, self.blur_iterations, self.blur_strength, self.dirt_angle, self.clean_angle, self.dirt_only)
+ ret = applyVertexDirt(
+ mesh,
+ self.blur_iterations,
+ self.blur_strength,
+ self.dirt_angle,
+ self.clean_angle,
+ self.dirt_only,
+ )
return ret
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 24670b2a37d..335a2a633cd 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1645,6 +1645,12 @@ class WM_OT_tool_set_by_id(Operator):
default=False,
options={'SKIP_SAVE'},
)
+ as_fallback: BoolProperty(
+ name="Set Fallback",
+ description="Set the fallback tool instead of the primary tool",
+ default=False,
+ options={'SKIP_SAVE', 'HIDDEN'},
+ )
space_type: rna_space_type_prop
@@ -1672,7 +1678,10 @@ class WM_OT_tool_set_by_id(Operator):
space_type = context.space_data.type
fn = activate_by_id_or_cycle if self.cycle else activate_by_id
- if fn(context, space_type, self.name):
+ if fn(context, space_type, self.name, as_fallback=self.as_fallback):
+ if self.as_fallback:
+ tool_settings = context.tool_settings
+ tool_settings.workspace_tool_type = 'FALLBACK'
return {'FINISHED'}
else:
self.report({'WARNING'}, f"Tool {self.name!r:s} not found for space {space_type!r:s}.")
@@ -1699,13 +1708,20 @@ class WM_OT_tool_set_by_index(Operator):
default=True,
)
+ as_fallback: BoolProperty(
+ name="Set Fallback",
+ description="Set the fallback tool instead of the primary",
+ default=False,
+ options={'SKIP_SAVE', 'HIDDEN'},
+ )
+
space_type: rna_space_type_prop
def execute(self, context):
from bl_ui.space_toolsystem_common import (
activate_by_id,
activate_by_id_or_cycle,
- item_from_index,
+ item_from_index_active,
item_from_flat_index,
)
@@ -1714,7 +1730,7 @@ class WM_OT_tool_set_by_index(Operator):
else:
space_type = context.space_data.type
- fn = item_from_flat_index if self.expand else item_from_index
+ fn = item_from_flat_index if self.expand else item_from_index_active
item = fn(context, space_type, self.index)
if item is None:
# Don't report, since the number of tools may change.
@@ -1722,7 +1738,10 @@ class WM_OT_tool_set_by_index(Operator):
# Same as: WM_OT_tool_set_by_id
fn = activate_by_id_or_cycle if self.cycle else activate_by_id
- if fn(context, space_type, item.idname):
+ if fn(context, space_type, item.idname, as_fallback=self.as_fallback):
+ if self.as_fallback:
+ tool_settings = context.tool_settings
+ tool_settings.workspace_tool_type = 'FALLBACK'
return {'FINISHED'}
else:
# Since we already have the tool, this can't happen.
@@ -1776,6 +1795,38 @@ class WM_OT_toolbar(Operator):
return {'FINISHED'}
+class WM_OT_toolbar_fallback_pie(Operator):
+ bl_idname = "wm.toolbar_fallback_pie"
+ bl_label = "Fallback Tool Pie Menu"
+
+ @classmethod
+ def poll(cls, context):
+ return context.space_data is not None
+
+ def invoke(self, context, event):
+ from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
+ space_type = context.space_data.type
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is None:
+ return {'PASS_THROUGH'}
+
+ # It's possible we don't have the fallback tool available.
+ # This can happen in the image editor for example when there is no selection
+ # in painting modes.
+ item, _ = cls._tool_get_by_id(context, cls.tool_fallback_id)
+ if item is None:
+ print("Tool", cls.tool_fallback_id, "not active in", cls)
+ return {'PASS_THROUGH'}
+
+ def draw_cb(self, context):
+ from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
+ ToolSelectPanelHelper.draw_fallback_tool_items_for_pie_menu(self.layout, context)
+
+ wm = context.window_manager
+ wm.popup_menu_pie(draw_func=draw_cb, title="Fallback Tool", event=event)
+ return {'FINISHED'}
+
+
class WM_OT_toolbar_prompt(Operator):
"""Leader key like functionality for accessing tools"""
bl_idname = "wm.toolbar_prompt"
@@ -2563,6 +2614,7 @@ classes = (
WM_OT_tool_set_by_id,
WM_OT_tool_set_by_index,
WM_OT_toolbar,
+ WM_OT_toolbar_fallback_pie,
WM_OT_toolbar_prompt,
BatchRenameAction,
WM_OT_batch_rename,
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 5daacbb2e44..c2bcb7d5ea5 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -54,10 +54,9 @@ _modules = [
"properties_physics_common",
"properties_physics_dynamicpaint",
"properties_physics_field",
- "properties_physics_fluid",
"properties_physics_rigidbody",
"properties_physics_rigidbody_constraint",
- "properties_physics_smoke",
+ "properties_physics_fluid",
"properties_physics_softbody",
"properties_render",
"properties_output",
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index b75d67b5350..3fc54ff6d12 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -492,6 +492,8 @@ class ConstraintButtonsPanel:
col.prop(con, "frame_start", text="Start")
col.prop(con, "frame_end", text="End")
+ layout.prop(con, "mix_mode", text="Mix")
+
def LOCKED_TRACK(self, _context, layout, con):
self.target_template(layout, con)
diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py
index e0a43a5fccc..883673ffd7a 100644
--- a/release/scripts/startup/bl_ui/properties_data_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -21,6 +21,12 @@ import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
+from bl_ui.properties_grease_pencil_common import (
+ GreasePencilLayerAdjustmentsPanel,
+ GreasePencilLayerRelationsPanel,
+ GreasePencilLayerDisplayPanel,
+)
+
###############################
# Base-Classes (for shared stuff - e.g. poll, attributes, etc.)
@@ -152,8 +158,8 @@ class DATA_PT_gpencil_layers(DataButtonsPanel, Panel):
col.separator()
sub = col.column(align=True)
- sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
+ sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
# Layer main properties
row = layout.row()
@@ -173,83 +179,23 @@ class DATA_PT_gpencil_layers(DataButtonsPanel, Panel):
col.prop(gpl, "opacity", text="Opacity", slider=True)
-class DATA_PT_gpencil_layer_adjustments(LayerDataButtonsPanel, Panel):
+class DATA_PT_gpencil_layer_adjustments(LayerDataButtonsPanel, GreasePencilLayerAdjustmentsPanel, Panel):
bl_label = "Adjustments"
bl_parent_id = 'DATA_PT_gpencil_layers'
bl_options = {'DEFAULT_CLOSED'}
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- scene = context.scene
-
- gpd = context.gpencil
- gpl = gpd.layers.active
- layout.active = not gpl.lock
- # Layer options
- # Offsets - Color Tint
- layout.enabled = not gpl.lock
- col = layout.column(align=True)
- col.prop(gpl, "tint_color")
- col.prop(gpl, "tint_factor", text="Factor", slider=True)
-
- # Offsets - Thickness
- col = layout.row(align=True)
- col.prop(gpl, "line_change", text="Stroke Thickness")
-
- col = layout.row(align=True)
- col.prop(gpl, "pass_index")
-
- col = layout.row(align=True)
- col.prop_search(gpl, "viewlayer_render", scene, "view_layers", text="View Layer")
-
- col = layout.row(align=True)
- col.prop(gpl, "lock_material")
-
-
-class DATA_PT_gpencil_layer_relations(LayerDataButtonsPanel, Panel):
+class DATA_PT_gpencil_layer_relations(LayerDataButtonsPanel, GreasePencilLayerRelationsPanel, Panel):
bl_label = "Relations"
bl_parent_id = 'DATA_PT_gpencil_layers'
bl_options = {'DEFAULT_CLOSED'}
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- gpd = context.gpencil
- gpl = gpd.layers.active
-
- col = layout.column()
- col.active = not gpl.lock
- col.prop(gpl, "parent")
- col.prop(gpl, "parent_type", text="Type")
- parent = gpl.parent
-
- if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
- col.prop_search(gpl, "parent_bone", parent.data, "bones", text="Bone")
-
-class DATA_PT_gpencil_layer_display(LayerDataButtonsPanel, Panel):
+class DATA_PT_gpencil_layer_display(LayerDataButtonsPanel, GreasePencilLayerDisplayPanel, Panel):
bl_label = "Display"
bl_parent_id = 'DATA_PT_gpencil_layers'
bl_options = {'DEFAULT_CLOSED'}
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- gpd = context.gpencil
- gpl = gpd.layers.active
-
- col = layout.row(align=True)
- col.prop(gpl, "channel_color")
-
- col = layout.row(align=True)
- col.prop(gpl, "use_solo_mode", text="Show Only On Keyframed")
-
class DATA_PT_gpencil_onion_skinning(DataButtonsPanel, Panel):
bl_label = "Onion Skinning"
diff --git a/release/scripts/startup/bl_ui/properties_data_lightprobe.py b/release/scripts/startup/bl_ui/properties_data_lightprobe.py
index d6fd0cb6ec2..e8244c9c107 100644
--- a/release/scripts/startup/bl_ui/properties_data_lightprobe.py
+++ b/release/scripts/startup/bl_ui/properties_data_lightprobe.py
@@ -168,6 +168,7 @@ class DATA_PT_lightprobe_display(DataButtonsPanel, Panel):
if probe.type == 'PLANAR':
col.prop(ob, "empty_display_size", text="Arrow Size")
+ col.prop(probe, "show_influence")
col.prop(probe, "show_data")
if probe.type in {'GRID', 'CUBEMAP'}:
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 581b6be886c..3edce6b3b52 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -400,10 +400,9 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
else:
sub.operator("object.shape_key_retime", icon='RECOVER_LAST', text="")
+ layout.use_property_split = True
if key.use_relative:
if ob.active_shape_key_index != 0:
- layout.use_property_split = True
-
row = layout.row()
row.active = enable_edit_value
row.prop(kb, "value")
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index f576a29a783..d4b2c39bd5e 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -945,7 +945,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "angle")
col.prop(md, "limits", slider=True)
- def SMOKE(self, layout, _ob, _md):
+ def FLUID(self, layout, _ob, _md):
layout.label(text="Settings are inside the Physics tab")
def SMOOTH(self, layout, ob, md):
@@ -1481,6 +1481,11 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "material_offset", text="Material Offset")
+ def WELD(self, layout, ob, md):
+ layout.prop(md, "merge_threshold", text="Distance")
+ layout.prop(md, "max_interactions")
+ layout.prop_search(md, "vertex_group", ob, "vertex_groups")
+
def DATA_TRANSFER(self, layout, ob, md):
row = layout.row(align=True)
row.prop(md, "object")
@@ -2372,7 +2377,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
subcol.enabled = md.duplications > 0
subcol.prop(md, "distance")
subcol.prop(md, "offset", slider=True)
-
+
subcol.separator()
subcol.prop(md, "enable_fading")
@@ -2408,7 +2413,8 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
-
+
+
classes = (
DATA_PT_modifiers,
DATA_PT_gpencil_modifiers,
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 bc76f57fa86..45cb10bb3bd 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -131,122 +131,6 @@ class AnnotationDrawingToolsPanel:
gpencil_stroke_placement_settings(context, col)
-class GreasePencilStrokeEditPanel:
- # subclass must set
- # bl_space_type = 'IMAGE_EDITOR'
- bl_label = "Edit Strokes"
- bl_category = "Tools"
- bl_region_type = 'TOOLS'
-
- @classmethod
- def poll(cls, context):
- if context.gpencil_data is None:
- return False
-
- gpd = context.gpencil_data
- return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
-
- def draw(self, context):
- layout = self.layout
-
- is_3d_view = context.space_data.type == 'VIEW_3D'
-
- if not is_3d_view:
- layout.label(text="Select:")
- col = layout.column(align=True)
- col.operator("gpencil.select_all", text="Select All")
- col.operator("gpencil.select_box")
- col.operator("gpencil.select_circle")
-
- layout.separator()
-
- col = layout.column(align=True)
- col.operator("gpencil.select_linked")
- col.operator("gpencil.select_more")
- col.operator("gpencil.select_less")
- col.operator("gpencil.select_alternate")
-
- layout.label(text="Edit:")
- row = layout.row(align=True)
- row.operator("gpencil.copy", text="Copy")
- row.operator("gpencil.paste", text="Paste").type = 'ACTIVE'
- row.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
-
- col = layout.column(align=True)
- col.operator("gpencil.delete")
- col.operator("gpencil.duplicate_move", text="Duplicate")
- if is_3d_view:
- col.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE'
- col.operator_menu_enum("gpencil.stroke_caps_set", text="Toggle Caps...", property="type")
-
- layout.separator()
-
- if not is_3d_view:
- col = layout.column(align=True)
- col.operator("transform.translate") # icon='MAN_TRANS'
- col.operator("transform.rotate") # icon='MAN_ROT'
- col.operator("transform.resize", text="Scale") # icon='MAN_SCALE'
-
- layout.separator()
-
- layout.separator()
- col = layout.column(align=True)
- col.operator_menu_enum("gpencil.stroke_arrange", text="Arrange Strokes...", property="direction")
- col.operator("gpencil.stroke_change_color", text="Assign Material")
-
- layout.separator()
- col = layout.column(align=True)
- col.operator("gpencil.stroke_subdivide", text="Subdivide")
- row = col.row(align=True)
- row.operator("gpencil.stroke_simplify_fixed", text="Simplify")
- row.operator("gpencil.stroke_simplify", text="Adaptive")
- row.operator("gpencil.stroke_trim", text="Trim")
-
- col.separator()
-
- row = col.row(align=True)
- row.operator("gpencil.stroke_merge", text="Merge")
- row.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
- row.operator("gpencil.stroke_join", text="& Copy").type = 'JOINCOPY'
-
- col.operator("gpencil.stroke_flip", text="Flip Direction")
-
- if is_3d_view:
- layout.separator()
-
- col = layout.column(align=True)
- col.operator_menu_enum("gpencil.stroke_separate", text="Separate...", property="mode")
- col.operator("gpencil.stroke_split", text="Split")
-
- col = layout.column(align=True)
- col.label(text="Cleanup:")
- col.operator_menu_enum("gpencil.reproject", text="Reproject Strokes...", property="type")
- col.operator_menu_enum("gpencil.frame_clean_fill", text="Clean Boundary Strokes...", property="mode")
-
-
-class GreasePencilStrokeSculptPanel:
- # subclass must set
- # bl_space_type = 'IMAGE_EDITOR'
- bl_label = "Sculpt Strokes"
- bl_category = "Tools"
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- settings = context.tool_settings.gpencil_sculpt
- brush = settings.brush
-
- layout.template_icon_view(settings, "sculpt_tool", show_labels=True)
-
- if not self.is_popover:
- from bl_ui.properties_paint_common import (
- brush_basic_gpencil_sculpt_settings,
- )
- brush_basic_gpencil_sculpt_settings(layout, context, brush)
-
-
class GreasePencilSculptOptionsPanel:
bl_label = "Sculpt Strokes"
@@ -278,14 +162,36 @@ class GreasePencilSculptOptionsPanel:
# GP Object Tool Settings
-class GreasePencilAppearancePanel:
- bl_label = "Brush Appearance"
+class GreasePencilDisplayPanel:
+ bl_label = "Brush Tip"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ob = context.active_object
- return ob and ob.type == 'GPENCIL'
+ brush = context.tool_settings.gpencil_paint.brush
+ if ob and ob.type == 'GPENCIL' and brush:
+ if context.mode == 'PAINT_GPENCIL':
+ return brush.gpencil_tool != 'ERASE'
+ else:
+ # GP Sculpt and Weight Paint always have Brush Tip panel.
+ return True
+ return False
+
+ def draw_header(self, context):
+ if self.is_popover:
+ return
+
+ if context.mode == 'PAINT_GPENCIL':
+ brush = context.tool_settings.gpencil_paint.brush
+ gp_settings = brush.gpencil_settings
+
+ self.layout.prop(gp_settings, "use_cursor", text="")
+ elif context.mode in {'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
+ settings = context.tool_settings.gpencil_sculpt
+ brush = settings.brush
+
+ self.layout.prop(brush, "use_cursor", text="")
def draw(self, context):
layout = self.layout
@@ -299,42 +205,36 @@ class GreasePencilAppearancePanel:
brush = tool_settings.gpencil_paint.brush
gp_settings = brush.gpencil_settings
- sub = layout.column(align=True)
- sub.enabled = not brush.use_custom_icon
- sub.prop(gp_settings, "gp_icon", text="Icon")
+ if self.is_popover:
+ row = layout.row(align=True)
+ row.prop(gp_settings, "use_cursor", text="")
+ row.label(text="Display Cursor")
- layout.prop(brush, "use_custom_icon")
- sub = layout.column()
- sub.active = brush.use_custom_icon
- sub.prop(brush, "icon_filepath", text="")
-
- layout.prop(gp_settings, "use_cursor", text="Show Brush")
+ col = layout.column(align=True)
+ col.active = gp_settings.use_cursor
if brush.gpencil_tool == 'DRAW':
- layout.prop(gp_settings, "show_lasso", text="Show Fill Color While Drawing")
+ col.prop(gp_settings, "show_lasso", text="Show Fill Color While Drawing")
if brush.gpencil_tool == 'FILL':
- layout.prop(brush, "cursor_color_add", text="Color")
+ col.prop(brush, "cursor_color_add", text="Cursor Color")
elif ob.mode in {'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
settings = tool_settings.gpencil_sculpt
brush = settings.brush
tool = settings.sculpt_tool
+ if self.is_popover:
+ row = layout.row(align=True)
+ row.prop(brush, "use_cursor", text="")
+ row.label(text="Display Cursor")
+
col = layout.column(align=True)
- col.prop(brush, "use_cursor", text="Show Brush")
-
- if tool in {'THICKNESS', 'STRENGTH'}:
- col.prop(brush, "cursor_color_add", text="Add")
- col.prop(brush, "cursor_color_sub", text="Subtract")
- elif tool == 'PINCH':
- col.prop(brush, "cursor_color_add", text="Pinch")
- col.prop(brush, "cursor_color_sub", text="Inflate")
- elif tool == 'TWIST':
- col.prop(brush, "cursor_color_add", text="CCW")
- col.prop(brush, "cursor_color_sub", text="CW")
- else:
- col.prop(brush, "cursor_color_add", text="")
+ col.active = brush.use_cursor
+
+ col.prop(brush, "cursor_color_add", text="Cursor Color")
+ if tool in {'THICKNESS', 'STRENGTH', 'PINCH', 'TWIST'}:
+ col.prop(brush, "cursor_color_sub", text="Inverse Cursor Color")
class GPENCIL_MT_pie_tool_palette(Menu):
@@ -601,7 +501,7 @@ class GPENCIL_MT_move_to_layer(Menu):
gpl_active = context.active_gpencil_layer
tot_layers = len(gpd.layers)
i = tot_layers - 1
- while(i >= 0):
+ while i >= 0:
gpl = gpd.layers[i]
if gpl.info == gpl_active.info:
icon = 'GREASEPENCIL'
@@ -630,9 +530,9 @@ class GPENCIL_MT_gpencil_draw_delete(Menu):
class GPENCIL_MT_cleanup(Menu):
bl_label = "Clean Up"
- def draw(self, _context):
+ def draw(self, context):
- ob = _context.active_object
+ ob = context.active_object
layout = self.layout
@@ -811,12 +711,11 @@ class GreasePencilToolsPanel:
bl_options = {'DEFAULT_CLOSED'}
@classmethod
- def poll(cls, context):
+ def poll(cls, _context):
# XXX - disabled in 2.8 branch.
+ # return (context.gpencil_data is not None)
return False
- return (context.gpencil_data is not None)
-
def draw(self, context):
layout = self.layout
@@ -871,8 +770,8 @@ class GreasePencilMaterialsPanel:
col.separator()
sub = col.column(align=True)
- sub.operator("gpencil.color_isolate", icon='LOCKED', text="").affect_visibility = False
sub.operator("gpencil.color_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
+ sub.operator("gpencil.color_isolate", icon='LOCKED', text="").affect_visibility = False
if show_full_ui:
row = layout.row()
@@ -935,8 +834,6 @@ class GPENCIL_UL_layer(UIList):
icon='MOD_MASK' if gpl.mask_layer else 'LAYER_ACTIVE',
emboss=False)
- row.prop(gpl, "lock", text="", emboss=False)
- row.prop(gpl, "hide", text="", emboss=False)
subrow = row.row(align=True)
subrow.prop(
gpl,
@@ -945,6 +842,8 @@ class GPENCIL_UL_layer(UIList):
icon='ONIONSKIN_ON' if gpl.use_onion_skinning else 'ONIONSKIN_OFF',
emboss=False,
)
+ row.prop(gpl, "hide", text="", emboss=False)
+ row.prop(gpl, "lock", text="", emboss=False)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(
@@ -981,6 +880,78 @@ class GreasePencilSimplifyPanel:
sub.prop(rd, "simplify_gpencil_remove_lines", text="Lines")
+class GreasePencilLayerAdjustmentsPanel:
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ scene = context.scene
+
+ ob = context.object
+ gpd = ob.data
+ gpl = gpd.layers.active
+ layout.active = not gpl.lock
+
+ # Layer options
+ # Offsets - Color Tint
+ layout.enabled = not gpl.lock
+ col = layout.column(align=True)
+ col.prop(gpl, "tint_color")
+ col.prop(gpl, "tint_factor", text="Factor", slider=True)
+
+ # Offsets - Thickness
+ col = layout.row(align=True)
+ col.prop(gpl, "line_change", text="Stroke Thickness")
+
+ col = layout.row(align=True)
+ col.prop(gpl, "pass_index")
+
+ col = layout.row(align=True)
+ col.prop_search(gpl, "viewlayer_render", scene, "view_layers", text="View Layer")
+
+ col = layout.row(align=True)
+ col.prop(gpl, "lock_material")
+
+
+class GreasePencilLayerRelationsPanel:
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ ob = context.object
+ gpd = ob.data
+ gpl = gpd.layers.active
+
+ col = layout.column()
+ col.active = not gpl.lock
+ col.prop(gpl, "parent")
+ col.prop(gpl, "parent_type", text="Type")
+ parent = gpl.parent
+
+ if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
+ col.prop_search(gpl, "parent_bone", parent.data, "bones", text="Bone")
+
+
+class GreasePencilLayerDisplayPanel:
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ ob = context.object
+ gpd = ob.data
+ gpl = gpd.layers.active
+
+ col = layout.row(align=True)
+ col.prop(gpl, "channel_color")
+
+ col = layout.row(align=True)
+ col.prop(gpl, "use_solo_mode", text="Show Only On Keyframed")
+
+
classes = (
GPENCIL_MT_pie_tool_palette,
GPENCIL_MT_pie_settings_palette,
diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py
index 94d7ac2c91e..3342fe1985a 100644
--- a/release/scripts/startup/bl_ui/properties_mask_common.py
+++ b/release/scripts/startup/bl_ui/properties_mask_common.py
@@ -22,6 +22,33 @@
# menus are referenced `as is`
from bpy.types import Menu, UIList
+from bpy.app.translations import contexts as i18n_contexts
+
+
+# Use by both image & clip context menus.
+def draw_mask_context_menu(layout, context):
+ layout.operator_menu_enum("mask.handle_type_set", "type")
+ layout.operator("mask.switch_direction")
+ layout.operator("mask.cyclic_toggle")
+
+ layout.separator()
+ layout.operator("mask.copy_splines", icon='COPYDOWN')
+ layout.operator("mask.paste_splines", icon='PASTEDOWN')
+
+ layout.separator()
+
+ layout.operator("mask.shape_key_rekey", text="Re-key Shape Points")
+ layout.operator("mask.feather_weight_clear")
+ layout.operator("mask.shape_key_feather_reset", text="Reset Feather Animation")
+
+ layout.separator()
+
+ layout.operator("mask.parent_set")
+ layout.operator("mask.parent_clear")
+
+ layout.separator()
+
+ layout.operator("mask.delete")
class MASK_UL_layers(UIList):
@@ -320,6 +347,19 @@ class MASK_MT_mask(Menu):
layout.menu("MASK_MT_animation")
+class MASK_MT_add(Menu):
+ bl_idname = "MASK_MT_add"
+ bl_label = "Add"
+ bl_translation_context = i18n_contexts.operator_default
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("mask.primitive_circle_add", text="Circle", icon='MESH_CIRCLE')
+ layout.operator("mask.primitive_square_add", text="Square", icon='MESH_PLANE')
+
+
class MASK_MT_visibility(Menu):
bl_label = "Show/Hide"
@@ -383,6 +423,7 @@ class MASK_MT_select(Menu):
classes = (
MASK_UL_layers,
MASK_MT_mask,
+ MASK_MT_add,
MASK_MT_visibility,
MASK_MT_transform,
MASK_MT_animation,
diff --git a/release/scripts/startup/bl_ui/properties_material_gpencil.py b/release/scripts/startup/bl_ui/properties_material_gpencil.py
index 8ce97a88e35..4f419ec1f18 100644
--- a/release/scripts/startup/bl_ui/properties_material_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_material_gpencil.py
@@ -65,13 +65,13 @@ class GPENCIL_UL_matslots(UIList):
row.prop(ma, "name", text="", emboss=False, icon_value=icon)
row = layout.row(align=True)
- row.prop(gpcolor, "lock", text="", emboss=False)
- row.prop(gpcolor, "hide", text="", emboss=False)
if gpcolor.ghost is True:
icon = 'ONIONSKIN_OFF'
else:
icon = 'ONIONSKIN_ON'
row.prop(gpcolor, "ghost", text="", icon=icon, emboss=False)
+ row.prop(gpcolor, "hide", text="", emboss=False)
+ row.prop(gpcolor, "lock", text="", emboss=False)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 98e812cf02d..327df079d3b 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -26,74 +26,487 @@ class UnifiedPaintPanel:
# bl_region_type = 'UI'
@staticmethod
+ def get_brush_mode(context):
+ """ Get the correct mode for this context. For any context where this returns None,
+ no brush options should be displayed."""
+ mode = context.mode
+
+ if mode == 'PARTICLE':
+ # Particle brush settings currently completely do their own thing.
+ return None
+
+ from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
+ tool = ToolSelectPanelHelper.tool_active_from_context(context)
+
+ if not tool:
+ # If there is no active tool, then there can't be an active brush.
+ return None
+
+ if not tool.has_datablock:
+ # tool.has_datablock is always true for tools that use brushes.
+ return None
+
+ space_data = context.space_data
+ tool_settings = context.tool_settings
+
+ if space_data:
+ space_type = space_data.type
+ if space_type == 'IMAGE_EDITOR':
+ if space_data.show_uvedit:
+ return 'UV_SCULPT'
+ return 'PAINT_2D'
+ elif space_type in {'VIEW_3D', 'PROPERTIES'}:
+ if mode == 'PAINT_TEXTURE':
+ if tool_settings.image_paint:
+ return mode
+ else:
+ return None
+ return mode
+ return None
+
+ @staticmethod
def paint_settings(context):
tool_settings = context.tool_settings
- if context.sculpt_object:
+ mode = UnifiedPaintPanel.get_brush_mode(context)
+
+ # 3D paint settings
+ if mode == 'SCULPT':
return tool_settings.sculpt
- elif context.vertex_paint_object:
+ elif mode == 'PAINT_VERTEX':
return tool_settings.vertex_paint
- elif context.weight_paint_object:
+ elif mode == 'PAINT_WEIGHT':
return tool_settings.weight_paint
- elif context.image_paint_object:
- if (tool_settings.image_paint and tool_settings.image_paint.detect_data()):
- return tool_settings.image_paint
-
- return None
- elif context.particle_edit_object:
+ elif mode == 'PAINT_TEXTURE':
+ return tool_settings.image_paint
+ elif mode == 'PARTICLE':
return tool_settings.particle_edit
-
+ # 2D paint settings
+ elif mode == 'PAINT_2D':
+ return tool_settings.image_paint
+ elif mode == 'UV_SCULPT':
+ return tool_settings.uv_sculpt
+ # Grease Pencil settings
+ elif mode == 'PAINT_GPENCIL':
+ return tool_settings.gpencil_paint
+ elif mode in {'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
+ return tool_settings.gpencil_sculpt
return None
@staticmethod
- def unified_paint_settings(parent, context):
+ def prop_unified(
+ layout,
+ context,
+ brush,
+ prop_name,
+ unified_name=None,
+ pressure_name=None,
+ icon='NONE',
+ text=None,
+ slider=False,
+ header=False,
+ ):
+ """ Generalized way of adding brush options to the UI,
+ along with their pen pressure setting and global toggle, if they exist. """
+ row = layout.row(align=True)
ups = context.tool_settings.unified_paint_settings
+ prop_owner = brush
+ if unified_name and getattr(ups, unified_name):
+ prop_owner = ups
- flow = parent.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
- col.prop(ups, "use_unified_size", text="Size")
- col = flow.column()
- col.prop(ups, "use_unified_strength", text="Strength")
- if context.weight_paint_object:
- col = flow.column()
- col.prop(ups, "use_unified_weight", text="Weight")
- elif context.vertex_paint_object or context.image_paint_object:
- col = flow.column()
- col.prop(ups, "use_unified_color", text="Color")
- else:
- col = flow.column()
- col.prop(ups, "use_unified_color", text="Color")
+ row.prop(prop_owner, prop_name, icon=icon, text=text, slider=slider)
- @staticmethod
- def prop_unified_size(parent, context, brush, prop_name, *, icon='NONE', text=None, slider=False):
- ups = context.tool_settings.unified_paint_settings
- ptr = ups if ups.use_unified_size else brush
- parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider)
+ if pressure_name:
+ row.prop(brush, pressure_name, text="")
- @staticmethod
- def prop_unified_strength(parent, context, brush, prop_name, *, icon='NONE', text=None, slider=False):
- ups = context.tool_settings.unified_paint_settings
- ptr = ups if ups.use_unified_strength else brush
- parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider)
+ if unified_name and not header:
+ # NOTE: We don't draw UnifiedPaintSettings in the header to reduce clutter. D5928#136281
+ row.prop(ups, unified_name, text="", icon="WORLD")
- @staticmethod
- def prop_unified_weight(parent, context, brush, prop_name, *, icon='NONE', text=None, slider=False):
- ups = context.tool_settings.unified_paint_settings
- ptr = ups if ups.use_unified_weight else brush
- parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider)
+ return row
@staticmethod
def prop_unified_color(parent, context, brush, prop_name, *, text=None):
ups = context.tool_settings.unified_paint_settings
- ptr = ups if ups.use_unified_color else brush
- parent.prop(ptr, prop_name, text=text)
+ prop_owner = ups if ups.use_unified_color else brush
+ parent.prop(prop_owner, prop_name, text=text)
@staticmethod
def prop_unified_color_picker(parent, context, brush, prop_name, value_slider=True):
ups = context.tool_settings.unified_paint_settings
- ptr = ups if ups.use_unified_color else brush
- parent.template_color_picker(ptr, prop_name, value_slider=value_slider)
+ prop_owner = ups if ups.use_unified_color else brush
+ parent.template_color_picker(prop_owner, prop_name, value_slider=value_slider)
+
+
+### Classes to let various paint modes' panels share code, by sub-classing these classes. ###
+class BrushPanel(UnifiedPaintPanel):
+ @classmethod
+ def poll(cls, context):
+ return cls.get_brush_mode(context) is not None
+
+
+class BrushSelectPanel(BrushPanel):
+ bl_label = "Brushes"
+
+ def draw(self, context):
+ layout = self.layout
+ settings = self.paint_settings(context)
+ brush = settings.brush
+
+ row = layout.row()
+ large_preview = True
+ if large_preview:
+ row.column().template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8, hide_buttons=False)
+ else:
+ row.column().template_ID(settings, "brush", new="brush.add")
+ col = row.column()
+ col.menu("VIEW3D_MT_brush_context_menu", icon='DOWNARROW_HLT', text="")
+
+ if brush is not None:
+ col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="")
+
+ if brush.use_custom_icon:
+ layout.prop(brush, "icon_filepath", text="")
+
+
+class ColorPalettePanel(BrushPanel):
+ bl_label = "Color Palette"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ if not super().poll(context):
+ return False
+
+ settings = cls.paint_settings(context)
+ brush = settings.brush
+
+ if context.space_data.type == 'IMAGE_EDITOR' or context.image_paint_object:
+ capabilities = brush.image_paint_capabilities
+ return capabilities.has_color
+
+ elif context.vertex_paint_object:
+ capabilities = brush.vertex_paint_capabilities
+ return capabilities.has_color
+ return False
+
+ def draw(self, context):
+ layout = self.layout
+ settings = self.paint_settings(context)
+
+ layout.template_ID(settings, "palette", new="palette.new")
+ if settings.palette:
+ layout.template_palette(settings, "palette", color=True)
+
+
+class ClonePanel(BrushPanel):
+ bl_label = "Clone"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ if not super().poll(context):
+ return False
+
+ settings = cls.paint_settings(context)
+
+ mode = cls.get_brush_mode(context)
+ if mode in {'PAINT_TEXTURE', 'PAINT_2D'}:
+ brush = settings.brush
+ return brush.image_tool == 'CLONE'
+ return False
+
+ def draw_header(self, context):
+ settings = self.paint_settings(context)
+ self.layout.prop(settings, "use_clone_layer", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ settings = self.paint_settings(context)
+
+ layout.active = settings.use_clone_layer
+
+ ob = context.active_object
+ col = layout.column()
+
+ if settings.mode == 'MATERIAL':
+ if len(ob.material_slots) > 1:
+ col.label(text="Materials")
+ col.template_list(
+ "MATERIAL_UL_matslots", "",
+ ob, "material_slots",
+ ob, "active_material_index",
+ rows=2,
+ )
+
+ mat = ob.active_material
+ if mat:
+ col.label(text="Source Clone Slot")
+ col.template_list(
+ "TEXTURE_UL_texpaintslots", "",
+ mat, "texture_paint_images",
+ mat, "paint_clone_slot",
+ rows=2,
+ )
+
+ elif settings.mode == 'IMAGE':
+ mesh = ob.data
+
+ clone_text = mesh.uv_layer_clone.name if mesh.uv_layer_clone else ""
+ col.label(text="Source Clone Image")
+ col.template_ID(settings, "clone_image")
+ col.label(text="Source Clone UV Map")
+ col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False)
+
+
+class TextureMaskPanel(BrushPanel):
+ bl_label = "Texture Mask"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ brush = context.tool_settings.image_paint.brush
+
+ col = layout.column()
+ col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
+
+ mask_tex_slot = brush.mask_texture_slot
+
+ # map_mode
+ layout.row().prop(mask_tex_slot, "mask_map_mode", text="Mask Mapping")
+
+ if mask_tex_slot.map_mode == 'STENCIL':
+ if brush.mask_texture and brush.mask_texture.type == 'IMAGE':
+ layout.operator("brush.stencil_fit_image_aspect").mask = True
+ layout.operator("brush.stencil_reset_transform").mask = True
+
+ col = layout.column()
+ col.prop(brush, "use_pressure_masking", text="Pressure Masking")
+ # angle and texture_angle_source
+ if mask_tex_slot.has_texture_angle:
+ col = layout.column()
+ col.prop(mask_tex_slot, "angle", text="Angle")
+ if mask_tex_slot.has_texture_angle_source:
+ col.prop(mask_tex_slot, "use_rake", text="Rake")
+
+ if brush.brush_capabilities.has_random_texture_angle and mask_tex_slot.has_random_texture_angle:
+ col.prop(mask_tex_slot, "use_random", text="Random")
+ if mask_tex_slot.use_random:
+ col.prop(mask_tex_slot, "random_angle", text="Random Angle")
+
+ # scale and offset
+ col.prop(mask_tex_slot, "offset")
+ col.prop(mask_tex_slot, "scale")
+
+
+class StrokePanel(BrushPanel):
+ bl_label = "Stroke"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ mode = self.get_brush_mode(context)
+ settings = self.paint_settings(context)
+ brush = settings.brush
+
+ col = layout.column()
+
+ col.prop(brush, "stroke_method")
+ col.separator()
+
+ if brush.use_anchor:
+ col.prop(brush, "use_edge_to_edge", text="Edge To Edge")
+
+ if brush.use_airbrush:
+ col.prop(brush, "rate", text="Rate", slider=True)
+
+ if brush.use_space:
+ row = col.row(align=True)
+ row.prop(brush, "spacing", text="Spacing")
+ row.prop(brush, "use_pressure_spacing", toggle=True, text="")
+
+ if brush.use_line or brush.use_curve:
+ row = col.row(align=True)
+ row.prop(brush, "spacing", text="Spacing")
+
+ if mode == 'SCULPT':
+ col.row().prop(brush, "use_scene_spacing", text="Spacing Distance", expand=True)
+
+ if mode in {'PAINT_TEXTURE', 'PAINT_2D', 'SCULPT'}:
+ if brush.image_paint_capabilities.has_space_attenuation or brush.sculpt_capabilities.has_space_attenuation:
+ col.prop(brush, "use_space_attenuation")
+
+ if brush.use_curve:
+ col.separator()
+ col.template_ID(brush, "paint_curve", new="paintcurve.new")
+ col.operator("paintcurve.draw")
+ col.separator()
+
+ if brush.use_space:
+ col.separator()
+ row = col.row(align=True)
+ col.prop(brush, "dash_ratio", text="Dash Ratio")
+ col.prop(brush, "dash_samples", text="Dash Length")
+
+ if (mode == 'SCULPT' and brush.sculpt_capabilities.has_jitter) or mode != 'SCULPT':
+ col.separator()
+ row = col.row(align=True)
+ if brush.jitter_unit == 'BRUSH':
+ row.prop(brush, "jitter", slider=True)
+ else:
+ row.prop(brush, "jitter_absolute")
+ row.prop(brush, "use_pressure_jitter", toggle=True, text="")
+ col.row().prop(brush, "jitter_unit", expand=True)
+
+ col.separator()
+ col.prop(settings, "input_samples")
+
+
+class SmoothStrokePanel(BrushPanel):
+ bl_label = "Stabilize Stroke"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ if not super().poll(context):
+ return False
+ settings = cls.paint_settings(context)
+ brush = settings.brush
+ if brush.brush_capabilities.has_smooth_stroke:
+ return True
+ return False
+
+ def draw_header(self, context):
+ settings = self.paint_settings(context)
+ brush = settings.brush
+
+ self.layout.prop(brush, "use_smooth_stroke", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ settings = self.paint_settings(context)
+ brush = settings.brush
+
+ col = layout.column()
+ col.active = brush.use_smooth_stroke
+ col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
+ col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
+
+
+class FalloffPanel(BrushPanel):
+ bl_label = "Falloff"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ if not super().poll(context):
+ return False
+ settings = cls.paint_settings(context)
+ return (settings and settings.brush and settings.brush.curve)
+
+ def draw(self, context):
+ layout = self.layout
+ settings = self.paint_settings(context)
+ mode = self.get_brush_mode(context)
+ brush = settings.brush
+
+ if brush is None:
+ return
+
+ col = layout.column(align=True)
+ row = col.row(align=True)
+ row.prop(brush, "curve_preset", text="")
+
+ if brush.curve_preset == 'CUSTOM':
+ layout.template_curve_mapping(brush, "curve", brush=True)
+
+ col = layout.column(align=True)
+ row = col.row(align=True)
+ row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
+ row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
+ row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
+ row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
+ row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
+ row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
+
+ if mode in {'SCULPT', 'PAINT_VERTEX', 'PAINT_WEIGHT'}:
+ col.separator()
+ row = col.row(align=True)
+ row.use_property_split = True
+ row.use_property_decorate = False
+ row.prop(brush, "falloff_shape", expand=True)
+
+
+class DisplayPanel(BrushPanel):
+ bl_label = "Brush Cursor"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw_header(self, context):
+ settings = self.paint_settings(context)
+ if settings and not self.is_popover:
+ self.layout.prop(settings, "show_brush", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ mode = self.get_brush_mode(context)
+ settings = self.paint_settings(context)
+ brush = settings.brush
+ tex_slot = brush.texture_slot
+ tex_slot_mask = brush.mask_texture_slot
+
+ if self.is_popover:
+ row = layout.row(align=True)
+ row.prop(settings, "show_brush", text="")
+ row.label(text="Display Cursor")
+
+ col = layout.column()
+ col.active = brush.brush_capabilities.has_overlay and settings.show_brush
+
+ col.prop(brush, "cursor_color_add", text="Cursor Color")
+ if mode == 'SCULPT' and brush.sculpt_capabilities.has_secondary_color:
+ col.prop(brush, "cursor_color_subtract", text="Inverse Cursor Color")
+
+ col.separator()
+
+ row = col.row(align=True)
+ row.prop(brush, "cursor_overlay_alpha", text="Falloff Opacity")
+ row.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
+ row.prop(
+ brush, "use_cursor_overlay", text="", toggle=True,
+ icon='HIDE_OFF' if brush.use_cursor_overlay else 'HIDE_ON',
+ )
+
+ if mode in ['PAINT_2D', 'PAINT_TEXTURE', 'PAINT_VERTEX', 'SCULPT']:
+ row = col.row(align=True)
+ row.prop(brush, "texture_overlay_alpha", text="Texture Opacity")
+ row.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
+ if tex_slot.map_mode != 'STENCIL':
+ row.prop(
+ brush, "use_primary_overlay", text="", toggle=True,
+ icon='HIDE_OFF' if brush.use_primary_overlay else 'HIDE_ON',
+ )
+
+ if mode in ['PAINT_TEXTURE', 'PAINT_2D']:
+ row = col.row(align=True)
+ row.prop(brush, "mask_overlay_alpha", text="Mask Texture Opacity")
+ row.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
+ if tex_slot_mask.map_mode != 'STENCIL':
+ row.prop(
+ brush, "use_secondary_overlay", text="", toggle=True,
+ icon='HIDE_OFF' if brush.use_secondary_overlay else 'HIDE_ON',
+ )
class VIEW3D_MT_tools_projectpaint_clone(Menu):
@@ -108,99 +521,363 @@ class VIEW3D_MT_tools_projectpaint_clone(Menu):
props.value = i
-def brush_texpaint_common(panel, context, layout, brush, _settings, *, projpaint=False):
- col = layout.column()
+def brush_settings(layout, context, brush, popover=False):
+ """ Draw simple brush settings for Sculpt,
+ Texture/Vertex/Weight Paint modes, or skip certain settings for the popover """
- if brush.image_tool == 'FILL' and not projpaint:
- col.prop(brush, "fill_threshold", text="Gradient Type", slider=True)
+ mode = UnifiedPaintPanel.get_brush_mode(context)
- elif brush.image_tool == 'SOFTEN':
- col.row().prop(brush, "direction", expand=True)
- col.prop(brush, "sharp_threshold")
- if not projpaint:
- col.prop(brush, "blur_kernel_radius")
- col.prop(brush, "blur_mode")
- elif brush.image_tool == 'MASK':
- col.prop(brush, "weight", text="Mask Value", slider=True)
+ ### Draw simple settings unique to each paint mode. ###
+ brush_shared_settings(layout, context, brush, popover)
- elif brush.image_tool == 'CLONE':
- if not projpaint:
- col.prop(brush, "clone_image", text="Image")
- col.prop(brush, "clone_alpha", text="Alpha")
+ # Sculpt Mode #
+ if mode == 'SCULPT':
+ capabilities = brush.sculpt_capabilities
- if not panel.is_popover:
- brush_basic_texpaint_settings(col, context, brush)
+ # normal_radius_factor
+ layout.prop(brush, "normal_radius_factor", slider=True)
+ # auto_smooth_factor and use_inverse_smooth_pressure
+ if capabilities.has_auto_smooth:
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "auto_smooth_factor",
+ pressure_name="use_inverse_smooth_pressure",
+ slider=True,
+ )
-def brush_texpaint_common_clone(_panel, context, layout, _brush, settings, *, projpaint=False):
- ob = context.active_object
- col = layout.column()
+ # topology_rake_factor
+ if (
+ capabilities.has_topology_rake and
+ context.sculpt_object.use_dynamic_topology_sculpting
+ ):
+ layout.prop(brush, "topology_rake_factor", slider=True)
+
+ # normal_weight
+ if capabilities.has_normal_weight:
+ layout.prop(brush, "normal_weight", slider=True)
+
+ # crease_pinch_factor
+ if capabilities.has_pinch_factor:
+ text = "Pinch"
+ if brush.sculpt_tool in {'BLOB', 'SNAKE_HOOK'}:
+ text = "Magnify"
+ layout.prop(brush, "crease_pinch_factor", slider=True, text=text)
+
+ # rake_factor
+ if capabilities.has_rake_factor:
+ layout.prop(brush, "rake_factor", slider=True)
+
+ # plane_offset, use_offset_pressure, use_plane_trim, plane_trim
+ if capabilities.has_plane_offset:
+ layout.separator()
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "plane_offset",
+ pressure_name="use_offset_pressure",
+ slider=True,
+ )
- if settings.mode == 'MATERIAL':
- if len(ob.material_slots) > 1:
- col.label(text="Materials")
- col.template_list("MATERIAL_UL_matslots", "",
- ob, "material_slots",
- ob, "active_material_index", rows=2)
+ layout.prop(brush, "use_plane_trim", text="Plane Trim")
+ row = layout.row()
+ row.active = brush.use_plane_trim
+ row.prop(brush, "plane_trim", slider=True, text="Distance")
+ layout.separator()
+
+ # height
+ if capabilities.has_height:
+ layout.prop(brush, "height", slider=True, text="Height")
+
+ # use_persistent, set_persistent_base
+ if capabilities.has_persistence:
+ ob = context.sculpt_object
+ do_persistent = True
+
+ # not supported yet for this case
+ for md in ob.modifiers:
+ if md.type == 'MULTIRES':
+ do_persistent = False
+ break
+
+ if do_persistent:
+ layout.separator()
+ layout.prop(brush, "use_persistent")
+ layout.operator("sculpt.set_persistent_base")
+ layout.separator()
+
+ if brush.sculpt_tool == 'ELASTIC_DEFORM':
+ layout.separator()
+ layout.prop(brush, "elastic_deform_type")
+ layout.prop(brush, "elastic_deform_volume_preservation", slider=True)
+ layout.separator()
+
+ if brush.sculpt_tool == 'POSE':
+ row = layout.row()
+ row.prop(brush, "pose_offset")
+
+ if brush.sculpt_tool == 'SCRAPE':
+ row = layout.row()
+ row.prop(brush, "invert_to_scrape_fill", text="Invert to Fill")
+
+ if brush.sculpt_tool == 'FILL':
+ row = layout.row()
+ row.prop(brush, "invert_to_scrape_fill", text="Invert to Scrape")
+
+ if brush.sculpt_tool == 'GRAB':
+ layout.prop(brush, "use_grab_active_vertex")
+
+ if brush.sculpt_tool == 'MULTIPLANE_SCRAPE':
+ col = layout.column()
+ col.prop(brush, "multiplane_scrape_angle")
+ col.prop(brush, "use_multiplane_scrape_dynamic")
+ col.prop(brush, "show_multiplane_scrape_planes_preview")
+
+ if brush.sculpt_tool == 'MASK':
+ layout.row().prop(brush, "mask_tool", expand=True)
+
+ # 3D and 2D Texture Paint Mode.
+ elif mode in {'PAINT_TEXTURE', 'PAINT_2D'}:
+ capabilities = brush.image_paint_capabilities
+
+ if brush.image_tool == 'FILL':
+ # For some reason fill threshold only appears to be implemented in 2D paint.
+ if brush.color_type == 'COLOR':
+ if mode == 'PAINT_2D':
+ layout.prop(brush, "fill_threshold", text="Fill Threshold", slider=True)
+ elif brush.color_type == 'GRADIENT':
+ layout.row().prop(brush, "gradient_fill_mode", expand=True)
+
+
+def brush_shared_settings(layout, context, brush, popover=False):
+ """ Draw simple brush settings that are shared between different paint modes. """
+
+ mode = UnifiedPaintPanel.get_brush_mode(context)
+
+ ### Determine which settings to draw. ###
+ blend_mode = False
+ size = False
+ size_mode = False
+ strength = False
+ strength_pressure = False
+ weight = False
+ direction = False
+
+ # 3D and 2D Texture Paint #
+ if mode in {'PAINT_TEXTURE', 'PAINT_2D'}:
+ if not popover:
+ blend_mode = brush.image_paint_capabilities.has_color
+ size = brush.image_paint_capabilities.has_radius
+ strength = strength_pressure = True
+
+ # Sculpt #
+ if mode == 'SCULPT':
+ size_mode = True
+ if not popover:
+ size = True
+ strength = True
+ strength_pressure = brush.sculpt_capabilities.has_strength_pressure
+ direction = not brush.sculpt_capabilities.has_direction
+
+ # Vertex Paint #
+ if mode == 'PAINT_VERTEX':
+ if not popover:
+ blend_mode = True
+ size = True
+ strength = True
+ strength_pressure = True
+
+ # Weight Paint #
+ if mode == 'PAINT_WEIGHT':
+ if not popover:
+ size = True
+ weight = brush.weight_paint_capabilities.has_weight
+ strength = strength_pressure = True
+ # Only draw blend mode for the Draw tool, because for other tools it is pointless. D5928#137944
+ if brush.weight_tool == 'DRAW':
+ blend_mode = True
+
+ # UV Sculpt #
+ if mode == 'UV_SCULPT':
+ size = True
+ strength = True
+
+ ### Draw settings. ###
+ ups = context.scene.tool_settings.unified_paint_settings
+
+ if blend_mode:
+ layout.prop(brush, "blend", text="Blend")
+ layout.separator()
+
+ if weight:
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "weight",
+ unified_name="use_unified_weight",
+ slider=True,
+ )
+
+ size_owner = ups if ups.use_unified_size else brush
+ size_prop = "size"
+ if size_mode and (size_owner.use_locked_size == 'SCENE'):
+ size_prop = "unprojected_radius"
+ if size or size_mode:
+ if size:
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ size_prop,
+ unified_name="use_unified_size",
+ pressure_name="use_pressure_size",
+ text="Radius",
+ slider=True,
+ )
+ if size_mode:
+ layout.row().prop(size_owner, "use_locked_size", expand=True)
+ layout.separator()
+
+ if strength:
+ pressure_name = "use_pressure_strength" if strength_pressure else None
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "strength",
+ unified_name="use_unified_strength",
+ pressure_name=pressure_name,
+ slider=True,
+ )
+ layout.separator()
+
+ if direction:
+ layout.row().prop(brush, "direction", expand=True)
+
+
+def brush_settings_advanced(layout, context, brush, popover=False):
+ """Draw advanced brush settings for Sculpt, Texture/Vertex/Weight Paint modes."""
+
+ mode = UnifiedPaintPanel.get_brush_mode(context)
+
+ # In the popover we want to combine advanced brush settings with non-advanced brush settings.
+ if popover:
+ brush_settings(layout, context, brush, popover=True)
+ layout.separator()
+ layout.label(text="Advanced:")
+
+ # These options are shared across many modes.
+ use_accumulate = False
+ use_frontface = False
+
+ if mode == 'SCULPT':
+ capabilities = brush.sculpt_capabilities
+ use_accumulate = capabilities.has_accumulate
+ use_frontface = True
+
+ # topology automasking
+ layout.prop(brush, "use_automasking_topology")
+
+ # sculpt plane settings
+ if capabilities.has_sculpt_plane:
+ layout.prop(brush, "sculpt_plane")
+ layout.prop(brush, "use_original_normal")
+ layout.prop(brush, "use_original_plane")
+ layout.separator()
+
+ # 3D and 2D Texture Paint.
+ elif mode in {'PAINT_TEXTURE', 'PAINT_2D'}:
+ capabilities = brush.image_paint_capabilities
+ use_accumulate = capabilities.has_accumulate
+
+ if mode == 'PAINT_2D':
+ layout.prop(brush, "use_paint_antialiasing")
+ else:
+ layout.prop(brush, "use_alpha")
- mat = ob.active_material
- if mat:
- col.label(text="Source Clone Slot")
- col.template_list("TEXTURE_UL_texpaintslots", "",
- mat, "texture_paint_images",
- mat, "paint_clone_slot", rows=2)
+ # Tool specific settings
+ if brush.image_tool == 'SOFTEN':
+ layout.separator()
+ layout.row().prop(brush, "direction", expand=True)
+ layout.prop(brush, "sharp_threshold")
+ if mode == 'PAINT_2D':
+ layout.prop(brush, "blur_kernel_radius")
+ layout.prop(brush, "blur_mode")
- elif settings.mode == 'IMAGE':
- mesh = ob.data
+ elif brush.image_tool == 'MASK':
+ layout.prop(brush, "weight", text="Mask Value", slider=True)
- clone_text = mesh.uv_layer_clone.name if mesh.uv_layer_clone else ""
- col.label(text="Source Clone Image")
- col.template_ID(settings, "clone_image")
- col.label(text="Source Clone UV Map")
- col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False)
+ elif brush.image_tool == 'CLONE':
+ if mode == 'PAINT_2D':
+ layout.prop(brush, "clone_image", text="Image")
+ layout.prop(brush, "clone_alpha", text="Alpha")
+ # Vertex Paint #
+ elif mode == 'PAINT_VERTEX':
+ layout.prop(brush, "use_alpha")
+ if brush.vertex_tool != 'SMEAR':
+ use_accumulate = True
+ use_frontface = True
-def brush_texpaint_common_color(_panel, context, layout, brush, _settings, *, projpaint=False):
- UnifiedPaintPanel.prop_unified_color_picker(layout, context, brush, "color", value_slider=True)
+ # Weight Paint
+ elif mode == 'PAINT_WEIGHT':
+ if brush.weight_tool != 'SMEAR':
+ use_accumulate = True
+ use_frontface = True
- row = layout.row(align=True)
- UnifiedPaintPanel.prop_unified_color(row, context, brush, "color", text="")
- UnifiedPaintPanel.prop_unified_color(row, context, brush, "secondary_color", text="")
- row.separator()
- row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="", emboss=False)
+ # Draw shared settings.
+ if use_accumulate:
+ layout.prop(brush, "use_accumulate")
+ if use_frontface:
+ layout.prop(brush, "use_frontface", text="Front Faces Only")
-def brush_texpaint_common_gradient(_panel, context, layout, brush, _settings, *, projpaint=False):
- layout.template_color_ramp(brush, "gradient", expand=True)
- layout.use_property_split = True
-
- col = layout.column()
+def draw_color_settings(context, layout, brush, color_type=False):
+ """Draw color wheel and gradient settings."""
+ ups = context.scene.tool_settings.unified_paint_settings
- if brush.image_tool == 'DRAW':
- UnifiedPaintPanel.prop_unified_color(col, context, brush, "secondary_color", text="Background Color")
- col.prop(brush, "gradient_stroke_mode", text="Gradient Mapping")
- if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}:
- col.prop(brush, "grad_spacing")
- else: # if brush.image_tool == 'FILL':
- col.prop(brush, "gradient_fill_mode")
+ if color_type:
+ row = layout.row()
+ row.use_property_split = False
+ row.prop(brush, "color_type", expand=True)
+ # Color wheel
+ if brush.color_type == 'COLOR':
+ UnifiedPaintPanel.prop_unified_color_picker(layout, context, brush, "color", value_slider=True)
-def brush_texpaint_common_options(_panel, _context, layout, brush, _settings, *, projpaint=False):
- capabilities = brush.image_paint_capabilities
+ row = layout.row(align=True)
+ UnifiedPaintPanel.prop_unified_color(row, context, brush, "color", text="")
+ UnifiedPaintPanel.prop_unified_color(row, context, brush, "secondary_color", text="")
+ row.separator()
+ row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="", emboss=False)
+ row.prop(ups, "use_unified_color", text="", icon='WORLD')
+ # Gradient
+ elif brush.color_type == 'GRADIENT':
+ layout.template_color_ramp(brush, "gradient", expand=True)
- col = layout.column()
+ layout.use_property_split = True
- if capabilities.has_accumulate:
- col.prop(brush, "use_accumulate")
+ col = layout.column()
- if capabilities.has_space_attenuation:
- col.prop(brush, "use_space_attenuation")
+ if brush.image_tool == 'DRAW':
+ UnifiedPaintPanel.prop_unified(
+ col,
+ context,
+ brush,
+ "secondary_color",
+ unified_name="use_unified_color",
+ text="Background Color",
+ header=True,
+ )
- if projpaint:
- col.prop(brush, "use_alpha")
- else:
- col.prop(brush, "use_paint_antialiasing")
+ col.prop(brush, "gradient_stroke_mode", text="Gradient Mapping")
+ if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}:
+ col.prop(brush, "grad_spacing")
# Used in both the View3D toolbar and texture properties
@@ -282,93 +959,40 @@ def brush_mask_texture_settings(layout, brush):
col.prop(mask_tex_slot, "offset")
col.prop(mask_tex_slot, "scale")
-# Basic Brush Options
-#
-# Share between topbar and brush panel.
-
-
-def brush_basic_wpaint_settings(layout, context, brush, *, compact=False):
- capabilities = brush.weight_paint_capabilities
-
- if capabilities.has_weight:
- row = layout.row(align=True)
- UnifiedPaintPanel.prop_unified_weight(row, context, brush, "weight", slider=True)
-
- row = layout.row(align=True)
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
-
- row = layout.row(align=True)
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength")
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
-
- layout.prop(brush, "blend", text="" if compact else "Blend")
-
-
-def brush_basic_vpaint_settings(layout, context, brush, *, compact=False):
- capabilities = brush.vertex_paint_capabilities
-
- row = layout.row(align=True)
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
-
- row = layout.row(align=True)
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength")
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
-
- if capabilities.has_color:
- layout.prop(brush, "blend", text="" if compact else "Blend")
-
def brush_basic_texpaint_settings(layout, context, brush, *, compact=False):
+ """Draw Tool Settings header for Vertex Paint and 2D and 3D Texture Paint modes."""
capabilities = brush.image_paint_capabilities
- if capabilities.has_radius:
- row = layout.row(align=True)
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
-
- row = layout.row(align=True)
-
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength")
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
-
if capabilities.has_color:
+ UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
layout.prop(brush, "blend", text="" if compact else "Blend")
-
-def brush_basic_sculpt_settings(layout, context, brush, *, compact=False):
- tool_settings = context.tool_settings
- capabilities = brush.sculpt_capabilities
-
- row = layout.row(align=True)
-
- ups = tool_settings.unified_paint_settings
- if (
- (ups.use_unified_size and ups.use_locked_size == 'SCENE') or
- ((not ups.use_unified_size) and brush.use_locked_size == 'SCENE')
- ):
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "unprojected_radius", slider=True, text="Radius")
- else:
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
-
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
-
- # strength, use_strength_pressure, and use_strength_attenuation
- row = layout.row(align=True)
-
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength")
-
- if capabilities.has_strength_pressure:
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
-
- # direction
- if not capabilities.has_direction:
- layout.row().prop(brush, "direction", expand=True, **({"text": ""} if compact else {}))
-
-
-def brush_basic_gpencil_paint_settings(layout, _context, brush, tool, *, compact=True, is_toolbar=False):
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "size",
+ pressure_name="use_pressure_size",
+ unified_name="use_unified_size",
+ slider=True,
+ text="Radius",
+ header=True
+ )
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "strength",
+ pressure_name="use_pressure_strength",
+ unified_name="use_unified_strength",
+ header=True
+ )
+
+
+def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False):
gp_settings = brush.gpencil_settings
+ tool = context.workspace.tools.from_space_view3d_mode(context.mode, create=False)
# Brush details
if brush.gpencil_tool == 'ERASE':
@@ -377,6 +1001,8 @@ def brush_basic_gpencil_paint_settings(layout, _context, brush, tool, *, compact
row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
row.prop(gp_settings, "use_occlude_eraser", text="", icon='XRAY')
+ row = layout.row(align=True)
+ row.prop(gp_settings, "eraser_mode", expand=True)
if gp_settings.eraser_mode == 'SOFT':
row = layout.row(align=True)
row.prop(gp_settings, "pen_strength", slider=True)
@@ -385,6 +1011,11 @@ def brush_basic_gpencil_paint_settings(layout, _context, brush, tool, *, compact
row.prop(gp_settings, "eraser_strength_factor")
row = layout.row(align=True)
row.prop(gp_settings, "eraser_thickness_factor")
+
+ row = layout.row(align=True)
+ row.prop(gp_settings, "use_cursor", text="Display Cursor")
+
+ # FIXME: tools must use their own UI drawing!
elif brush.gpencil_tool == 'FILL':
row = layout.row(align=True)
row.prop(gp_settings, "fill_leak", text="Leak Size")
@@ -392,26 +1023,7 @@ def brush_basic_gpencil_paint_settings(layout, _context, brush, tool, *, compact
row.prop(brush, "size", text="Thickness")
row = layout.row(align=True)
row.prop(gp_settings, "fill_simplify_level", text="Simplify")
- row = layout.row(align=True)
- row.prop(gp_settings, "fill_draw_mode", text="Boundary")
- row.prop(gp_settings, "show_fill_boundary", text="", icon='GRID')
- # Fill options
- if is_toolbar:
- settings = _context.tool_settings.gpencil_sculpt
- row = layout.row(align=True)
- sub = row.row(align=True)
- sub.popover(
- panel="TOPBAR_PT_gpencil_fill",
- text="Fill Options",
- )
- else:
- row = layout.row(align=True)
- row.prop(gp_settings, "fill_factor", text="Resolution")
- if gp_settings.fill_draw_mode != 'STROKE':
- row = layout.row(align=True)
- row.prop(gp_settings, "show_fill", text="Ignore Transparent Strokes")
- row = layout.row(align=True)
- row.prop(gp_settings, "fill_threshold", text="Threshold")
+
else: # brush.gpencil_tool == 'DRAW':
row = layout.row(align=True)
row.prop(brush, "size", text="Radius")
@@ -427,10 +1039,10 @@ def brush_basic_gpencil_paint_settings(layout, _context, brush, tool, *, compact
"builtin.line",
"builtin.box",
"builtin.circle",
- "builtin.polyline",
+ "builtin.polyline"
}:
- settings = _context.tool_settings.gpencil_sculpt
- if is_toolbar:
+ settings = context.tool_settings.gpencil_sculpt
+ if compact:
row = layout.row(align=True)
row.prop(settings, "use_thickness_curve", text="", icon='CURVE_DATA')
sub = row.row(align=True)
@@ -491,10 +1103,8 @@ def brush_basic_gpencil_weight_settings(layout, _context, brush, *, compact=Fals
row = layout.row(align=True)
row.prop(brush, "strength", slider=True)
row.prop(brush, "use_pressure_strength", text="")
-
- layout.prop(brush, "use_falloff")
-
layout.prop(brush, "weight", slider=True)
+ layout.prop(brush, "use_falloff")
classes = (
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index 076b1f2592c..21abf8bb34c 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -55,7 +55,7 @@ def particle_panel_poll(cls, context):
if not settings:
return False
- return settings.is_fluid is False and (engine in cls.COMPAT_ENGINES)
+ return (settings.is_fluid is False) and (engine in cls.COMPAT_ENGINES)
def particle_get_settings(context):
@@ -119,6 +119,7 @@ def find_modifier(ob, psys):
if md.type == 'PARTICLE_SYSTEM':
if md.particle_system == psys:
return md
+ return None
class PARTICLE_UL_particle_systems(bpy.types.UIList):
@@ -159,7 +160,10 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
@classmethod
def poll(cls, context):
engine = context.engine
- return (context.particle_system or context.object or context.space_data.pin_id) and (engine in cls.COMPAT_ENGINES)
+ return (
+ (context.particle_system or context.object or context.space_data.pin_id) and
+ (engine in cls.COMPAT_ENGINES)
+ )
def draw(self, context):
layout = self.layout
@@ -203,7 +207,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
col = layout.column()
- if part.is_fluid is False:
+ if (part.is_fluid is False):
row = col.row()
row.enabled = particle_panel_enabled(context, psys)
row.template_ID(psys, "settings", new="particle.new")
diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py
index 3e87c9cd0c0..d9713cb8608 100644
--- a/release/scripts/startup/bl_ui/properties_physics_cloth.py
+++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py
@@ -161,6 +161,88 @@ class PHYSICS_PT_cloth_damping(PhysicButtonsPanel, Panel):
col.prop(cloth, "bending_damping", text="Bending")
+class PHYSICS_PT_cloth_internal_springs(PhysicButtonsPanel, Panel):
+ bl_label = "Internal Springs"
+ bl_parent_id = 'PHYSICS_PT_cloth_physical_properties'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ def draw_header(self, context):
+ cloth = context.cloth.settings
+
+ self.layout.active = cloth_panel_enabled(context.cloth)
+ self.layout.prop(cloth, "use_internal_springs", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ cloth = context.cloth.settings
+ md = context.cloth
+ ob = context.object
+
+ layout.active = cloth.use_internal_springs and cloth_panel_enabled(md)
+
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
+
+ col = flow.column()
+ col.prop(cloth, "internal_spring_max_length", text="Max Spring Creation Length")
+ col = flow.column()
+ col.prop(cloth, "internal_spring_max_diversion", text="Max Creation Diversion")
+ col = flow.column()
+ col.prop(cloth, "internal_spring_normal_check", text="Check Surface Normals")
+ col = flow.column()
+ col.prop(cloth, "internal_tension_stiffness", text="Tension")
+ col = flow.column()
+ col.prop(cloth, "internal_compression_stiffness", text="Compression")
+
+ col = flow.column()
+ col.prop_search(cloth, "vertex_group_intern", ob, "vertex_groups", text="Vertex Group")
+ col = flow.column()
+ col.prop(cloth, "internal_tension_stiffness_max", text="Max Tension")
+ col = flow.column()
+ col.prop(cloth, "internal_compression_stiffness_max", text="Max Compression")
+
+
+class PHYSICS_PT_cloth_pressure(PhysicButtonsPanel, Panel):
+ bl_label = "Pressure"
+ bl_parent_id = 'PHYSICS_PT_cloth_physical_properties'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ def draw_header(self, context):
+ cloth = context.cloth.settings
+
+ self.layout.active = cloth_panel_enabled(context.cloth)
+ self.layout.prop(cloth, "use_pressure", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ cloth = context.cloth.settings
+ md = context.cloth
+ ob = context.object
+
+ layout.active = cloth.use_pressure and cloth_panel_enabled(md)
+
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
+
+ col = flow.column()
+ col.prop(cloth, "uniform_pressure_force")
+
+ col = flow.column()
+ col.prop(cloth, "use_pressure_volume", text="Custom volume")
+
+ col = flow.column()
+ col.active = cloth.use_pressure_volume
+ col.prop(cloth, "target_volume")
+
+ col = flow.column()
+ col.prop(cloth, "pressure_factor", text="Factor")
+
+ col = flow.column()
+ col.prop_search(cloth, "vertex_group_pressure", ob, "vertex_groups", text="Vertex Group")
+
+
class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel):
bl_label = "Cache"
bl_parent_id = 'PHYSICS_PT_cloth'
@@ -382,6 +464,8 @@ classes = (
PHYSICS_PT_cloth_physical_properties,
PHYSICS_PT_cloth_stiffness,
PHYSICS_PT_cloth_damping,
+ PHYSICS_PT_cloth_internal_springs,
+ PHYSICS_PT_cloth_pressure,
PHYSICS_PT_cloth_cache,
PHYSICS_PT_cloth_shape,
PHYSICS_PT_cloth_collision,
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index b69f2233035..5397020a521 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -99,8 +99,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
physics_add(col, context.soft_body, "Soft Body", 'SOFT_BODY', 'MOD_SOFT', True)
if obj.type == 'MESH':
- physics_add(col, context.fluid, "Fluid", 'FLUID_SIMULATION', 'MOD_FLUIDSIM', True)
- physics_add(col, context.smoke, "Smoke", 'SMOKE', 'MOD_SMOKE', True)
+ physics_add(col, context.fluid, "Fluid", 'FLUID', 'MOD_FLUIDSIM', True)
physics_add_special(
col, obj.rigid_body, "Rigid Body",
@@ -118,7 +117,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
)
-# cache-type can be 'PSYS' 'HAIR' 'SMOKE' etc.
+# cache-type can be 'PSYS' 'HAIR' 'FLUID' etc.
def point_cache_ui(self, cache, enabled, cachetype):
layout = self.layout
@@ -141,10 +140,10 @@ def point_cache_ui(self, cache, enabled, cachetype):
col.operator("ptcache.add", icon='ADD', text="")
col.operator("ptcache.remove", icon='REMOVE', text="")
- if cachetype in {'PSYS', 'HAIR', 'SMOKE'}:
+ if cachetype in {'PSYS', 'HAIR', 'FLUID'}:
col = layout.column()
- if cachetype == 'SMOKE':
+ if cachetype == 'FLUID':
col.prop(cache, "use_library_path", text="Use Library Path")
col.prop(cache, "use_external")
@@ -160,14 +159,14 @@ def point_cache_ui(self, cache, enabled, cachetype):
col.alignment = 'RIGHT'
col.label(text=cache_info)
else:
- if cachetype in {'SMOKE', 'DYNAMIC_PAINT'}:
+ if cachetype in {'FLUID', 'DYNAMIC_PAINT'}:
if not is_saved:
col = layout.column(align=True)
col.alignment = 'RIGHT'
col.label(text="Cache is disabled until the file is saved")
layout.enabled = False
- if not cache.use_external or cachetype == 'SMOKE':
+ if not cache.use_external or cachetype == 'FLUID':
col = layout.column(align=True)
if cachetype not in {'PSYS', 'DYNAMIC_PAINT'}:
@@ -175,18 +174,18 @@ def point_cache_ui(self, cache, enabled, cachetype):
col.prop(cache, "frame_start", text="Simulation Start")
col.prop(cache, "frame_end")
- if cachetype not in {'SMOKE', 'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
+ if cachetype not in {'FLUID', 'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
col.prop(cache, "frame_step")
cache_info = cache.info
- if cachetype != 'SMOKE' and cache_info: # avoid empty space.
+ if cachetype != 'FLUID' and cache_info: # avoid empty space.
col = layout.column(align=True)
col.alignment = 'RIGHT'
col.label(text=cache_info)
can_bake = True
- if cachetype not in {'SMOKE', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
+ if cachetype not in {'FLUID', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
if not is_saved:
col = layout.column(align=True)
col.alignment = 'RIGHT'
@@ -269,7 +268,7 @@ def effector_weights_ui(self, weights, weight_type):
col.prop(weights, "curve_guide", slider=True)
col.prop(weights, "texture", slider=True)
- if weight_type != 'SMOKE':
+ if weight_type != 'FLUID':
col.prop(weights, "smokeflow", slider=True)
col = flow.column()
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
index b9e690629d1..6b0dd7ac36f 100644
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py
@@ -21,16 +21,18 @@
import bpy
from bpy.types import (
Panel,
+ Menu,
+)
+from .properties_physics_common import (
+ effector_weights_ui,
)
-from bpy.app.translations import pgettext_iface as iface_
-from bl_ui.utils import PresetPanel
-class FLUID_PT_presets(PresetPanel, Panel):
+class FLUID_MT_presets(Menu):
bl_label = "Fluid Presets"
preset_subdir = "fluid"
preset_operator = "script.execute_preset"
- preset_add_operator = "fluid.preset_add"
+ draw = Menu.draw_preset
class PhysicButtonsPanel:
@@ -39,28 +41,59 @@ class PhysicButtonsPanel:
bl_context = "physics"
@staticmethod
+ def check_domain_has_unbaked_guide(domain):
+ return (
+ domain.use_guide and not domain.has_cache_baked_guide and
+ ((domain.guide_source == 'EFFECTOR') or
+ (domain.guide_source == 'DOMAIN' and not domain.guide_parent))
+ )
+
+ @staticmethod
def poll_fluid(context):
ob = context.object
if not ((ob and ob.type == 'MESH') and (context.fluid)):
return False
- return (bpy.app.build_options.mod_fluid)
+ md = context.fluid
+ return md and (context.fluid.fluid_type != 'NONE')
+
+ @staticmethod
+ def poll_fluid_domain(context):
+ if not PhysicButtonsPanel.poll_fluid(context):
+ return False
+
+ md = context.fluid
+ return md and (md.fluid_type == 'DOMAIN')
@staticmethod
- def poll_fluid_settings(context):
- if not (PhysicButtonsPanel.poll_fluid(context)):
+ def poll_gas_domain(context):
+ if not PhysicButtonsPanel.poll_fluid(context):
return False
md = context.fluid
- return md and md.settings and (md.settings.type != 'NONE')
+ if md and (md.fluid_type == 'DOMAIN'):
+ domain = md.domain_settings
+ return domain.domain_type in {'GAS'}
+ return False
@staticmethod
- def poll_fluid_domain(context):
+ def poll_liquid_domain(context):
if not PhysicButtonsPanel.poll_fluid(context):
return False
md = context.fluid
- return md and md.settings and (md.settings.type == 'DOMAIN')
+ if md and (md.fluid_type == 'DOMAIN'):
+ domain = md.domain_settings
+ return domain.domain_type in {'LIQUID'}
+ return False
+
+ @staticmethod
+ def poll_fluid_flow(context):
+ if not PhysicButtonsPanel.poll_fluid(context):
+ return False
+
+ md = context.fluid
+ return md and (md.fluid_type == 'FLOW')
class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel):
@@ -70,325 +103,903 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel):
@classmethod
def poll(cls, context):
ob = context.object
- return (ob and ob.type == 'MESH') and context.engine in cls.COMPAT_ENGINES and (context.fluid)
+ return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.fluid)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
- if not bpy.app.build_options.mod_fluid:
- col = layout.column()
+ if not bpy.app.build_options.fluid:
+ col = layout.column(align=True)
col.alignment = 'RIGHT'
- col.label(text="Built without fluids")
+ col.label(text="Built without Fluid modifier")
return
-
md = context.fluid
- fluid = md.settings
- col = layout.column()
- col.prop(fluid, "type")
+ layout.prop(md, "fluid_type")
-class PHYSICS_PT_fluid_flow(PhysicButtonsPanel, Panel):
- bl_label = "Flow"
- bl_parent_id = "PHYSICS_PT_fluid"
+class PHYSICS_PT_settings(PhysicButtonsPanel, Panel):
+ bl_label = "Settings"
+ bl_parent_id = 'PHYSICS_PT_fluid'
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
- md = context.fluid
- fluid = md.settings
-
- if not PhysicButtonsPanel.poll_fluid_settings(context):
+ if not PhysicButtonsPanel.poll_fluid(context):
return False
- return fluid.type in {'INFLOW', 'OUTFLOW', 'CONTROL'} and (context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.fluid
- fluid = md.settings
- self.layout.prop(fluid, "use", text="")
+ return (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
md = context.fluid
- fluid = md.settings
+ ob = context.object
+ scene = context.scene
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
+ if md.fluid_type == 'DOMAIN':
+ domain = md.domain_settings
- flow.active = fluid.use
+ # Deactivate UI if guides are enabled but not baked yet.
+ layout.active = not self.check_domain_has_unbaked_guide(domain)
- if fluid.type == 'INFLOW':
- col = flow.column()
- col.prop(fluid, "volume_initialization", text="Volume Initialization")
- col.prop(fluid, "use_animated_mesh")
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_data = domain.has_cache_baked_data
- row = col.row()
- row.active = not fluid.use_animated_mesh
- row.prop(fluid, "use_local_coords")
+ row = layout.row()
+ row.enabled = not is_baking_any and not has_baked_data
+ row.prop(domain, "domain_type", expand=False)
- col = flow.column()
- col.prop(fluid, "inflow_velocity", text="Inflow Velocity")
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_data
- elif fluid.type == 'OUTFLOW':
col = flow.column()
- col.prop(fluid, "volume_initialization", text="Volume Initialization")
+ col.prop(domain, "resolution_max", text="Resolution Divisions")
+ col.prop(domain, "time_scale", text="Time Scale")
+ col.prop(domain, "cfl_condition", text="CFL Number")
col = flow.column()
- col.prop(fluid, "use_animated_mesh")
+ col.prop(domain, "use_adaptive_timesteps")
+ col1 = col.column(align=True)
+ col1.enabled = domain.use_adaptive_timesteps
+ col1.prop(domain, "timesteps_max", text="Timesteps Maximum")
+ col1.prop(domain, "timesteps_min", text="Minimum")
- elif fluid.type == 'CONTROL':
- col = flow.column()
- col.prop(fluid, "quality", slider=True)
- col.prop(fluid, "use_reverse_frames")
+ col.separator()
col = flow.column()
- col.prop(fluid, "start_time", text="Time Start")
- col.prop(fluid, "end_time", text="End")
+ if scene.use_gravity:
+ sub = col.column()
+ sub.enabled = False
+ sub.prop(domain, "gravity", text="Using Scene Gravity", icon='SCENE_DATA')
+ else:
+ col.prop(domain, "gravity", text="Gravity")
+ # TODO (sebbas): Clipping var useful for manta openvdb caching?
+ # col.prop(domain, "clipping", text="Empty Space")
+
+ if domain.cache_type == 'MODULAR':
+ col.separator()
+ split = layout.split()
- col.separator()
+ bake_incomplete = (domain.cache_frame_pause_data < domain.cache_frame_end)
+ if domain.has_cache_baked_data and not domain.is_cache_baking_data and bake_incomplete:
+ col = split.column()
+ col.operator("fluid.bake_data", text="Resume")
+ col = split.column()
+ col.operator("fluid.free_data", text="Free")
+ elif domain.is_cache_baking_data and not domain.has_cache_baked_data:
+ split.enabled = False
+ split.operator("fluid.pause_bake", text="Baking Data - ESC to pause")
+ elif not domain.has_cache_baked_data and not domain.is_cache_baking_data:
+ split.operator("fluid.bake_data", text="Bake Data")
+ else:
+ split.operator("fluid.free_data", text="Free Data")
+
+ elif md.fluid_type == 'FLOW':
+ flow = md.flow_settings
+
+ row = layout.row()
+ row.prop(flow, "flow_type", expand=False)
+
+ grid = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ col = grid.column()
+ col.prop(flow, "flow_behavior", expand=False)
+ if flow.flow_behavior in {'INFLOW'}:
+ col.prop(flow, "use_inflow", text="Use Inflow")
+
+ col.prop(flow, "subframes", text="Sampling Substeps")
+
+ if not flow.flow_behavior == 'OUTFLOW' and flow.flow_type in {'SMOKE', 'BOTH', 'FIRE'}:
+
+ if flow.flow_type in {'SMOKE', 'BOTH'}:
+ col.prop(flow, "smoke_color", text="Smoke Color")
+
+ col = grid.column(align=True)
+ col.prop(flow, "use_absolute", text="Absolute Density")
+
+ if flow.flow_type in {'SMOKE', 'BOTH'}:
+ col.prop(flow, "temperature", text="Initial Temperature")
+ col.prop(flow, "density", text="Density")
+
+ if flow.flow_type in {'FIRE', 'BOTH'}:
+ col.prop(flow, "fuel_amount", text="Fuel")
+
+ col.separator()
+ col.prop_search(flow, "density_vertex_group", ob, "vertex_groups", text="Vertex Group")
+
+ elif md.fluid_type == 'EFFECTOR':
+ effector_settings = md.effector_settings
+
+ row = layout.row()
+ row.prop(effector_settings, "effector_type")
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
col = flow.column()
- col.prop(fluid, "attraction_strength", text="Attraction Strength")
- col.prop(fluid, "attraction_radius", text="Radius")
- col.separator()
+ col.prop(effector_settings, "use_plane_init", text="Is Planar")
+ col.prop(effector_settings, "surface_distance", text="Surface Thickness")
- col = flow.column(align=True)
- col.prop(fluid, "velocity_strength", text="Velocity Strength")
- col.prop(fluid, "velocity_radius", text="Radius")
+ if effector_settings.effector_type == 'GUIDE':
+ col.prop(effector_settings, "velocity_factor", text="Velocity Factor")
+ col = flow.column()
+ col.prop(effector_settings, "guide_mode", text="Guide Mode")
-class PHYSICS_PT_fluid_settings(PhysicButtonsPanel, Panel):
- bl_label = "Settings"
- bl_parent_id = "PHYSICS_PT_fluid"
+class PHYSICS_PT_borders(PhysicButtonsPanel, Panel):
+ bl_label = "Border Collisions"
+ bl_parent_id = 'PHYSICS_PT_settings'
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
md = context.fluid
- fluid = md.settings
+ domain = md.domain_settings
+
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_data = domain.has_cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_data
+
+ col = flow.column()
+ col.prop(domain, "use_collision_border_front", text="Front")
+ col = flow.column()
+ col.prop(domain, "use_collision_border_back", text="Back")
+ col = flow.column()
+ col.prop(domain, "use_collision_border_right", text="Right")
+ col = flow.column()
+ col.prop(domain, "use_collision_border_left", text="Left")
+ col = flow.column()
+ col.prop(domain, "use_collision_border_top", text="Top")
+ col = flow.column()
+ col.prop(domain, "use_collision_border_bottom", text="Bottom")
+
- if not PhysicButtonsPanel.poll_fluid_settings(context):
+class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
+ bl_label = "Smoke"
+ bl_parent_id = 'PHYSICS_PT_settings'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
return False
- return fluid.type in {'DOMAIN', 'FLUID', 'OBSTACLE', 'PARTICLE'} and (context.engine in cls.COMPAT_ENGINES)
+
+ return (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
md = context.fluid
- fluid = md.settings
+ domain = md.domain_settings
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_data = domain.has_cache_baked_data
- if fluid.type not in {'NONE', 'DOMAIN', 'PARTICLE', 'FLUID', 'OBSTACLE'}:
- flow.active = fluid.use
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_data
- if fluid.type == 'DOMAIN':
- col = flow.column()
+ col = flow.column()
+ col.prop(domain, "alpha")
+ col.prop(domain, "beta", text="Temperature Diff.")
+ col = flow.column()
+ col.prop(domain, "vorticity")
- if bpy.app.build_options.openmp:
- col.prop(fluid, "threads", text="Simulation Threads")
- col.separator()
- col.prop(fluid, "resolution", text="Final Resolution")
- col.prop(fluid, "preview_resolution", text="Preview")
+class PHYSICS_PT_smoke_dissolve(PhysicButtonsPanel, Panel):
+ bl_label = "Dissolve"
+ bl_parent_id = 'PHYSICS_PT_smoke'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
- col.separator()
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
+ return False
- col = flow.column()
- col.prop(fluid, "render_display_mode", text="Render Display")
- col.prop(fluid, "viewport_display_mode", text="Viewport")
+ return (context.engine in cls.COMPAT_ENGINES)
- col.separator()
+ def draw_header(self, context):
+ md = context.fluid
+ domain = md.domain_settings
- col = flow.column()
- sub = col.column(align=True)
- sub.prop(fluid, "start_time", text="Time Start")
- sub.prop(fluid, "end_time", text="End")
- col.prop(fluid, "simulation_rate", text="Speed")
+ self.layout.prop(domain, "use_dissolve_smoke", text="")
- col = flow.column()
- col.prop(fluid, "use_speed_vectors")
- col.prop(fluid, "use_reverse_frames")
- col.prop(fluid, "frame_offset", text="Offset")
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
- elif fluid.type == 'FLUID':
- col = flow.column()
- col.prop(fluid, "volume_initialization", text="Volume Initialization")
- col.prop(fluid, "use_animated_mesh")
+ md = context.fluid
+ domain = md.domain_settings
- col = flow.column()
- col.prop(fluid, "initial_velocity", text="Initial Velocity")
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_data = domain.has_cache_baked_data
- elif fluid.type == 'OBSTACLE':
- col = flow.column()
- col.prop(fluid, "volume_initialization", text="Volume Initialization")
- col.prop(fluid, "use_animated_mesh")
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_data
- col = flow.column()
- subcol = col.column()
- subcol.enabled = not fluid.use_animated_mesh
- subcol.prop(fluid, "slip_type", text="Slip Type")
+ layout.active = domain.use_dissolve_smoke
- if fluid.slip_type == 'PARTIALSLIP':
- subcol.prop(fluid, "partial_slip_factor", text="Amount", slider=True)
+ col = flow.column()
+ col.prop(domain, "dissolve_speed", text="Time")
- col.prop(fluid, "impact_factor", text="Impact Factor")
+ col = flow.column()
+ col.prop(domain, "use_dissolve_smoke_log", text="Slow")
- elif fluid.type == 'PARTICLE':
- col = flow.column()
- col.prop(fluid, "particle_influence", text="Influence Size")
- col.prop(fluid, "alpha_influence", text="Alpha")
- col = flow.column()
- col.prop(fluid, "use_drops")
- col.prop(fluid, "use_floats")
- col.prop(fluid, "show_tracer")
+class PHYSICS_PT_fire(PhysicButtonsPanel, Panel):
+ bl_label = "Fire"
+ bl_parent_id = 'PHYSICS_PT_settings'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
+ return False
-class PHYSICS_PT_fluid_particle_cache(PhysicButtonsPanel, Panel):
- bl_label = "Cache"
- bl_parent_id = "PHYSICS_PT_fluid"
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ md = context.fluid
+ domain = md.domain_settings
+
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_data = domain.has_cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_data
+
+ col = flow.column()
+ col.prop(domain, "burning_rate", text="Reaction Speed")
+ col = flow.column()
+ col.prop(domain, "flame_smoke", text="Flame Smoke")
+ col = flow.column()
+ col.prop(domain, "flame_vorticity", text="Flame Vorticity")
+ col = flow.column()
+ col.prop(domain, "flame_ignition", text="Temperature Ignition")
+ col = flow.column()
+ col.prop(domain, "flame_max_temp", text="Maximum Temperature")
+ col = flow.column()
+ col.prop(domain, "flame_smoke_color", text="Flame Color")
+
+
+class PHYSICS_PT_liquid(PhysicButtonsPanel, Panel):
+ bl_label = "Liquid"
+ bl_parent_id = 'PHYSICS_PT_settings'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_liquid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ md = context.fluid.domain_settings
+ self.layout.prop(md, "use_flip_particles", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ md = context.fluid
+ domain = md.domain_settings
+
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_data = domain.has_cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ col = flow.column()
+ col0 = col.column()
+ col0.enabled = not is_baking_any and not has_baked_data
+ col0.prop(domain, "simulation_method", expand=False)
+ col0.prop(domain, "flip_ratio", text="FLIP Ratio")
+ col0.prop(domain, "particle_radius", text="Particle Radius")
+
+ col1 = flow.column(align=True)
+ col1.enabled = not is_baking_any and not has_baked_data
+ col1.prop(domain, "particle_max", text="Particles Maximum")
+ col1.prop(domain, "particle_min", text="Minimum")
+
+ col1 = flow.column()
+ col1.enabled = not is_baking_any and not has_baked_data
+ col1.prop(domain, "particle_number", text="Particle Sampling")
+ col1.prop(domain, "particle_band_width", text="Narrow Band Width")
+ col1.prop(domain, "particle_randomness", text="Particle Randomness")
+
+ col2 = flow.column()
+ col2.enabled = not is_baking_any and not has_baked_data
+ col2.prop(domain, "use_fractions", text="Fractional Obstacles")
+ col3 = col2.column()
+ col3.enabled = domain.use_fractions and col2.enabled
+ col3.prop(domain, "fractions_threshold", text="Obstacle-Fluid Threshold")
+
+
+class PHYSICS_PT_flow_source(PhysicButtonsPanel, Panel):
+ bl_label = "Flow Source"
+ bl_parent_id = 'PHYSICS_PT_settings'
+ bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
- if not PhysicButtonsPanel.poll_fluid_settings(context):
+ if not PhysicButtonsPanel.poll_fluid_flow(context):
return False
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ob = context.object
+ flow = context.fluid.flow_settings
+
+ col = layout.column()
+ col.prop(flow, "flow_source", expand=False, text="Flow Source")
+ if flow.flow_source == 'PARTICLES':
+ col.prop_search(flow, "particle_system", ob, "particle_systems", text="Particle System")
+
+ grid = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ col = grid.column()
+ if flow.flow_source == 'MESH':
+ col.prop(flow, "use_plane_init", text="Is Planar")
+ col.prop(flow, "surface_distance", text="Surface Thickness")
+ if flow.flow_type in {'SMOKE', 'BOTH', 'FIRE'}:
+ col = grid.column()
+ col.prop(flow, "volume_density", text="Volume Density")
+
+ if flow.flow_source == 'PARTICLES':
+ col.prop(flow, "use_particle_size", text="Set Size")
+ sub = col.column()
+ sub.active = flow.use_particle_size
+ sub.prop(flow, "particle_size")
+
+
+class PHYSICS_PT_flow_initial_velocity(PhysicButtonsPanel, Panel):
+ bl_label = "Initial Velocity"
+ bl_parent_id = 'PHYSICS_PT_settings'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_flow(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
md = context.fluid
- return md and md.settings and (md.settings.type == 'PARTICLE') and (context.engine in cls.COMPAT_ENGINES)
+ flow_smoke = md.flow_settings
+
+ self.layout.prop(flow_smoke, "use_initial_velocity", text="")
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
+
+ md = context.fluid
+ flow_smoke = md.flow_settings
+
+ flow.active = flow_smoke.use_initial_velocity
+
+ col = flow.column()
+ col.prop(flow_smoke, "velocity_factor")
+
+ if flow_smoke.flow_source == 'MESH':
+ col.prop(flow_smoke, "velocity_normal")
+ # col.prop(flow_smoke, "velocity_random")
+ col = flow.column()
+ col.prop(flow_smoke, "velocity_coord")
+
+
+class PHYSICS_PT_flow_texture(PhysicButtonsPanel, Panel):
+ bl_label = "Texture"
+ bl_parent_id = 'PHYSICS_PT_settings'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_flow(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
md = context.fluid
- fluid = md.settings
+ flow_smoke = md.flow_settings
+
+ self.layout.prop(flow_smoke, "use_texture", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ ob = context.object
+ flow_smoke = context.fluid.flow_settings
+
+ sub = flow.column()
+ sub.active = flow_smoke.use_texture
+ sub.prop(flow_smoke, "noise_texture")
+ sub.prop(flow_smoke, "texture_map_type", text="Mapping")
+
+ col = flow.column()
+ sub = col.column()
+ sub.active = flow_smoke.use_texture
+
+ if flow_smoke.texture_map_type == 'UV':
+ sub.prop_search(flow_smoke, "uv_layer", ob.data, "uv_layers")
+
+ if flow_smoke.texture_map_type == 'AUTO':
+ sub.prop(flow_smoke, "texture_size")
+
+ sub.prop(flow_smoke, "texture_offset")
+
+
+class PHYSICS_PT_adaptive_domain(PhysicButtonsPanel, Panel):
+ bl_label = "Adaptive Domain"
+ bl_parent_id = 'PHYSICS_PT_fluid'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ md = context.fluid.domain_settings
+ domain = context.fluid.domain_settings
+
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_any = domain.has_cache_baked_any
- layout.prop(fluid, "filepath", text="")
+ self.layout.enabled = not is_baking_any and not has_baked_any
+ self.layout.prop(md, "use_adaptive_domain", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.fluid.domain_settings
+ layout.active = domain.use_adaptive_domain
+
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_any = domain.has_cache_baked_any
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
+ flow.enabled = not is_baking_any and not has_baked_any
+
+ col = flow.column()
+ col.prop(domain, "additional_res", text="Add Resolution")
+ col.prop(domain, "adapt_margin")
+
+ col.separator()
+
+ col = flow.column()
+ col.prop(domain, "adapt_threshold", text="Threshold")
-class PHYSICS_PT_domain_bake(PhysicButtonsPanel, Panel):
- bl_label = "Bake"
+class PHYSICS_PT_noise(PhysicButtonsPanel, Panel):
+ bl_label = "Noise"
bl_parent_id = 'PHYSICS_PT_fluid'
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
- if not PhysicButtonsPanel.poll_fluid_domain(context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
return False
return (context.engine in cls.COMPAT_ENGINES)
+ def draw_header(self, context):
+ md = context.fluid.domain_settings
+ domain = context.fluid.domain_settings
+ is_baking_any = domain.is_cache_baking_any
+ self.layout.enabled = not is_baking_any
+ self.layout.prop(md, "use_noise", text="")
+
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
- md = context.fluid
- fluid = md.settings
+ domain = context.fluid.domain_settings
- row = layout.row(align=True)
- row.alignment = 'RIGHT'
- row.label(text="Cache Path")
+ # Deactivate UI if guides are enabled but not baked yet.
+ layout.active = domain.use_noise and not self.check_domain_has_unbaked_guide(domain)
- layout.prop(fluid, "filepath", text="")
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_noise = domain.has_cache_baked_noise
- # odd formatting here so translation script can extract string
- layout.operator(
- "fluid.bake", text=iface_("Bake (Req. Memory: %s)") % fluid.memory_estimate,
- translate=False, icon='MOD_FLUIDSIM'
- )
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_noise
+
+ col = flow.column()
+ col.prop(domain, "noise_scale", text="Upres Factor")
+ # TODO (sebbas): Mantaflow only supports wavelet noise. Maybe get rid of noise type field.
+ col.prop(domain, "noise_type", text="Noise Method")
+
+ col = flow.column()
+ col.prop(domain, "noise_strength", text="Strength")
+ col.prop(domain, "noise_pos_scale", text="Scale")
+ col.prop(domain, "noise_time_anim", text="Time")
+ if domain.cache_type == 'MODULAR':
+ col.separator()
-class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel):
- bl_label = "World"
+ split = layout.split()
+ split.enabled = domain.has_cache_baked_data
+
+ bake_incomplete = (domain.cache_frame_pause_noise < domain.cache_frame_end)
+ if domain.has_cache_baked_noise and not domain.is_cache_baking_noise and bake_incomplete:
+ col = split.column()
+ col.operator("fluid.bake_noise", text="Resume")
+ col = split.column()
+ col.operator("fluid.free_noise", text="Free")
+ elif not domain.has_cache_baked_noise and domain.is_cache_baking_noise:
+ split.enabled = False
+ split.operator("fluid.pause_bake", text="Baking Noise - ESC to pause")
+ elif not domain.has_cache_baked_noise and not domain.is_cache_baking_noise:
+ split.operator("fluid.bake_noise", text="Bake Noise")
+ else:
+ split.operator("fluid.free_noise", text="Free Noise")
+
+
+class PHYSICS_PT_mesh(PhysicButtonsPanel, Panel):
+ bl_label = "Mesh"
bl_parent_id = 'PHYSICS_PT_fluid'
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
- if not PhysicButtonsPanel.poll_fluid_domain(context):
+ if not PhysicButtonsPanel.poll_liquid_domain(context):
return False
return (context.engine in cls.COMPAT_ENGINES)
+ def draw_header(self, context):
+ md = context.fluid.domain_settings
+ domain = context.fluid.domain_settings
+ is_baking_any = domain.is_cache_baking_any
+ self.layout.enabled = not is_baking_any
+ self.layout.prop(md, "use_mesh", text="")
+
def draw(self, context):
layout = self.layout
layout.use_property_split = True
- fluid = context.fluid.settings
- scene = context.scene
+ domain = context.fluid.domain_settings
- col = layout.column()
+ # Deactivate UI if guides are enabled but not baked yet.
+ layout.active = domain.use_mesh and not self.check_domain_has_unbaked_guide(domain)
- use_gravity = scene.use_gravity
- use_units = scene.unit_settings.system != 'NONE'
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_mesh = domain.has_cache_baked_mesh
- if use_gravity or use_units:
- s_gravity = " Gravity" if use_gravity else ""
- s_units = " Units" if use_units else ""
- s_and = " and " if use_gravity and use_units else ""
- warn = f"Using {s_gravity}{s_and}{s_units} from Scene"
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_mesh
- sub = col.column()
- sub.alignment = 'RIGHT'
- sub.label(text=warn)
+ col = flow.column()
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
+ col.prop(domain, "mesh_scale", text="Upres Factor")
+ col.prop(domain, "mesh_particle_radius", text="Particle Radius")
col = flow.column()
- sub = col.column()
- sub.enabled = not use_gravity
- sub.prop(fluid, "gravity", text="Gravity")
+ col.prop(domain, "use_speed_vectors", text="Use Speed Vectors")
- sub = col.column()
- sub.enabled = not use_units
- sub.prop(fluid, "simulation_scale", text="Scene Size Meters" if use_units else "World Size Meters")
+ col.separator()
+ col.prop(domain, "mesh_generator", text="Mesh Generator")
+
+ if domain.mesh_generator in {'IMPROVED'}:
+ col = flow.column(align=True)
+ col.prop(domain, "mesh_smoothen_pos", text="Smoothing Positive")
+ col.prop(domain, "mesh_smoothen_neg", text="Negative")
+
+ col = flow.column(align=True)
+ col.prop(domain, "mesh_concave_upper", text="Concavity Upper")
+ col.prop(domain, "mesh_concave_lower", text="Lower")
+
+ # TODO (sebbas): for now just interpolate any upres grids, ie not sampling highres grids
+ #col.prop(domain, "highres_sampling", text="Flow Sampling:")
+
+ if domain.cache_type == 'MODULAR':
+ col.separator()
+
+ split = layout.split()
+ split.enabled = domain.has_cache_baked_data
+
+ bake_incomplete = (domain.cache_frame_pause_mesh < domain.cache_frame_end)
+ if domain.has_cache_baked_mesh and not domain.is_cache_baking_mesh and bake_incomplete:
+ col = split.column()
+ col.operator("fluid.bake_mesh", text="Resume")
+ col = split.column()
+ col.operator("fluid.free_mesh", text="Free")
+ elif not domain.has_cache_baked_mesh and domain.is_cache_baking_mesh:
+ split.enabled = False
+ split.operator("fluid.pause_bake", text="Baking Mesh - ESC to pause")
+ elif not domain.has_cache_baked_mesh and not domain.is_cache_baking_mesh:
+ split.operator("fluid.bake_mesh", text="Bake Mesh")
+ else:
+ split.operator("fluid.free_mesh", text="Free Mesh")
+
+
+class PHYSICS_PT_particles(PhysicButtonsPanel, Panel):
+ bl_label = "Particles"
+ bl_parent_id = 'PHYSICS_PT_fluid'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_liquid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.fluid.domain_settings
+
+ # Deactivate UI if guides are enabled but not baked yet.
+ layout.active = not self.check_domain_has_unbaked_guide(domain)
+
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_particles = domain.has_cache_baked_particles
+ using_particles = domain.use_spray_particles or domain.use_foam_particles or domain.use_bubble_particles
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any
+
+ sndparticle_combined_export = domain.sndparticle_combined_export
+ col = flow.column()
+ col.enabled = sndparticle_combined_export in {'OFF', 'FOAM + BUBBLES'}
+ col.prop(domain, "use_spray_particles", text="Spray")
+ col = flow.column()
+ col.enabled = sndparticle_combined_export in {'OFF', 'SPRAY + BUBBLES'}
+ col.prop(domain, "use_foam_particles", text="Foam")
+ col = flow.column()
+ col.enabled = sndparticle_combined_export in {'OFF', 'SPRAY + FOAM'}
+ col.prop(domain, "use_bubble_particles", text="Bubbles")
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_particles and using_particles
+
+ col = flow.column()
+ col.prop(domain, "sndparticle_combined_export")
+ col.prop(domain, "particle_scale", text="Upres Factor")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_tau_max_wc", text="Wave Crest Potential Maximum")
+ col.prop(domain, "sndparticle_tau_min_wc", text="Minimum")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_tau_max_ta", text="Trapped Air Potential Maximum")
+ col.prop(domain, "sndparticle_tau_min_ta", text="Minimum")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_tau_max_k", text="Kinetic Energy Potential Maximum")
+ col.prop(domain, "sndparticle_tau_min_k", text="Minimum")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_potential_radius", text="Potential Radius")
+ col.prop(domain, "sndparticle_update_radius", text="Particle Update Radius")
+ col.separator()
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_k_wc", text="Wave Crest Particle Sampling")
+ col.prop(domain, "sndparticle_k_ta", text="Trapped Air Particle Sampling")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_l_max", text="Particle Life Maximum")
+ col.prop(domain, "sndparticle_l_min", text="Minimum")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_k_b", text="Bubble Buoyancy")
+ col.prop(domain, "sndparticle_k_d", text="Bubble Drag")
col.separator()
col = flow.column()
- col.prop(fluid, "grid_levels", text="Optimization", slider=True)
- col.prop(fluid, "compressibility", slider=True)
+ col.prop(domain, "sndparticle_boundary", text="Particles in Boundary:")
+ if domain.cache_type == 'MODULAR':
+ col.separator()
-class PHYSICS_PT_domain_viscosity(PhysicButtonsPanel, Panel):
- bl_label = "Viscosity"
+ split = layout.split()
+ split.enabled = (
+ domain.has_cache_baked_data and
+ (domain.use_spray_particles or
+ domain.use_bubble_particles or
+ domain.use_foam_particles or
+ domain.use_tracer_particles)
+ )
+
+ bake_incomplete = (domain.cache_frame_pause_particles < domain.cache_frame_end)
+ if domain.has_cache_baked_particles and not domain.is_cache_baking_particles and bake_incomplete:
+ col = split.column()
+ col.operator("fluid.bake_particles", text="Resume")
+ col = split.column()
+ col.operator("fluid.free_particles", text="Free")
+ elif not domain.has_cache_baked_particles and domain.is_cache_baking_particles:
+ split.enabled = False
+ split.operator("fluid.pause_bake", text="Baking Particles - ESC to pause")
+ elif not domain.has_cache_baked_particles and not domain.is_cache_baking_particles:
+ split.operator("fluid.bake_particles", text="Bake Particles")
+ else:
+ split.operator("fluid.free_particles", text="Free Particles")
+
+
+class PHYSICS_PT_diffusion(PhysicButtonsPanel, Panel):
+ bl_label = "Diffusion"
bl_parent_id = 'PHYSICS_PT_fluid'
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
+ # Fluid diffusion only enabled for liquids (surface tension and viscosity not relevant for smoke)
+ if not PhysicButtonsPanel.poll_liquid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.fluid.domain_settings
+
+ # Deactivate UI if guides are enabled but not baked yet.
+ layout.active = not self.check_domain_has_unbaked_guide(domain)
+
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_any = domain.has_cache_baked_any
+ has_baked_data = domain.has_cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_any and not has_baked_data
+
+ row = flow.row()
+
+ col = row.column()
+ col.label(text="Viscosity Presets:")
+ col.menu("FLUID_MT_presets", text=bpy.types.FLUID_MT_presets.bl_label)
+
+ col = row.column(align=True)
+ col.operator("fluid.preset_add", text="", icon='ADD')
+ col.operator("fluid.preset_add", text="", icon='REMOVE').remove_active = True
+
+ col = flow.column(align=True)
+ col.prop(domain, "viscosity_base", text="Base")
+ col.prop(domain, "viscosity_exponent", text="Exponent", slider=True)
+
+ col = flow.column()
+ col.prop(domain, "domain_size", text="Real World Size")
+ col.prop(domain, "surface_tension", text="Surface Tension")
+
+
+class PHYSICS_PT_guide(PhysicButtonsPanel, Panel):
+ bl_label = "Guides"
+ bl_parent_id = 'PHYSICS_PT_fluid'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+
+ @classmethod
+ def poll(cls, context):
if not PhysicButtonsPanel.poll_fluid_domain(context):
return False
return (context.engine in cls.COMPAT_ENGINES)
- def draw_header_preset(self, _context):
- FLUID_PT_presets.draw_panel_header(self.layout)
+ def draw_header(self, context):
+ md = context.fluid.domain_settings
+ domain = context.fluid.domain_settings
+
+ is_baking_any = domain.is_cache_baking_any
+
+ self.layout.enabled = not is_baking_any
+ self.layout.prop(md, "use_guide", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
- fluid = context.fluid.settings
+ domain = context.fluid.domain_settings
+
+ layout.active = domain.use_guide
+
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_data = domain.has_cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_data
col = flow.column()
- col.prop(fluid, "viscosity_base", text="Base")
+ col.prop(domain, "guide_alpha", text="Weight")
+ col.prop(domain, "guide_beta", text="Size")
+ col.prop(domain, "guide_vel_factor", text="Velocity Factor")
col = flow.column()
- col.prop(fluid, "viscosity_exponent", text="Exponent", slider=True)
+ col.prop(domain, "guide_source", text="Velocity Source")
+ if domain.guide_source == 'DOMAIN':
+ col.prop(domain, "guide_parent", text="Guide Parent")
+ if domain.cache_type == 'MODULAR':
+ col.separator()
-class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel):
- bl_label = "Boundary"
+ if domain.guide_source == 'EFFECTOR':
+ split = layout.split()
+ bake_incomplete = (domain.cache_frame_pause_guide < domain.cache_frame_end)
+ if domain.has_cache_baked_guide and not domain.is_cache_baking_guide and bake_incomplete:
+ col = split.column()
+ col.operator("fluid.bake_guides", text="Resume")
+ col = split.column()
+ col.operator("fluid.free_guides", text="Free")
+ elif not domain.has_cache_baked_guide and domain.is_cache_baking_guide:
+ split.operator("fluid.pause_bake", text="Pause Guides")
+ elif not domain.has_cache_baked_guide and not domain.is_cache_baking_guide:
+ split.operator("fluid.bake_guides", text="Bake Guides")
+ else:
+ split.operator("fluid.free_guides", text="Free Guides")
+
+
+class PHYSICS_PT_collections(PhysicButtonsPanel, Panel):
+ bl_label = "Collections"
bl_parent_id = 'PHYSICS_PT_fluid'
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@@ -403,26 +1014,126 @@ class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
- fluid = context.fluid.settings
+ domain = context.fluid.domain_settings
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ col = flow.column()
+ col.prop(domain, "fluid_group", text="Flow")
+
+ # col.prop(domain, "effector_group", text="Forces")
+ col.prop(domain, "effector_group", text="Effector")
+
+
+class PHYSICS_PT_cache(PhysicButtonsPanel, Panel):
+ bl_label = "Cache"
+ bl_parent_id = 'PHYSICS_PT_fluid'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ md = context.fluid
+ domain = context.fluid.domain_settings
+
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_any = domain.has_cache_baked_any
+
+ col = layout.column()
+ col.prop(domain, "cache_directory", text="")
+ col.enabled = not is_baking_any
+
+ layout.use_property_split = True
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
col = flow.column()
- col.prop(fluid, "slip_type", text="Type")
+ col.prop(domain, "cache_type", expand=False)
+ col.enabled = not is_baking_any
+ col = flow.column(align=True)
col.separator()
- if fluid.slip_type == 'PARTIALSLIP':
- col.prop(fluid, "partial_slip_factor", slider=True, text="Amount")
+ col.prop(domain, "cache_frame_start", text="Frame Start")
+ col.prop(domain, "cache_frame_end", text="End")
+ col.enabled = not is_baking_any
+
+ col.separator()
col = flow.column()
- col.prop(fluid, "surface_smooth", text="Surface Smoothing")
- col.prop(fluid, "surface_subdivisions", text="Subdivisions")
- col.prop(fluid, "use_surface_noobs")
+ col.enabled = not is_baking_any and not has_baked_any
+ col.prop(domain, "cache_data_format", text="Data File Format")
+ if md.domain_settings.domain_type in {'GAS'}:
+ if domain.use_noise:
+ col.prop(domain, "cache_noise_format", text="Noise File Format")
-class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel):
- bl_label = "Particles"
+ if md.domain_settings.domain_type in {'LIQUID'}:
+ # File format for all particle systemes (FLIP and secondary)
+ col.prop(domain, "cache_particle_format", text="Particle File Format")
+
+ if domain.use_mesh:
+ col.prop(domain, "cache_mesh_format", text="Mesh File Format")
+
+ if domain.cache_type == 'FINAL':
+
+ col.separator()
+ split = layout.split()
+
+ bake_incomplete = (domain.cache_frame_pause_data < domain.cache_frame_end)
+ if domain.has_cache_baked_data and not domain.is_cache_baking_data and bake_incomplete:
+ col = split.column()
+ col.operator("fluid.bake_all", text="Resume")
+ col = split.column()
+ col.operator("fluid.free_all", text="Free")
+ elif domain.is_cache_baking_data and not domain.has_cache_baked_data:
+ split.enabled = False
+ split.operator("fluid.pause_bake", text="Baking All - ESC to pause")
+ elif not domain.has_cache_baked_data and not domain.is_cache_baking_data:
+ split.operator("fluid.bake_all", text="Bake All")
+ else:
+ split.operator("fluid.free_all", text="Free All")
+
+
+class PHYSICS_PT_export(PhysicButtonsPanel, Panel):
+ bl_label = "Advanced"
+ bl_parent_id = 'PHYSICS_PT_cache'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.fluid.domain_settings
+
+ is_baking_any = domain.is_cache_baking_any
+ has_baked_any = domain.has_cache_baked_any
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not is_baking_any and not has_baked_any
+
+ col = flow.column()
+ col.prop(domain, "export_manta_script", text="Export Mantaflow Script")
+
+
+class PHYSICS_PT_field_weights(PhysicButtonsPanel, Panel):
+ bl_label = "Field Weights"
bl_parent_id = 'PHYSICS_PT_fluid'
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@@ -435,32 +1146,141 @@ class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel):
return (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
+ domain = context.fluid.domain_settings
+ effector_weights_ui(self, domain.effector_weights, 'SMOKE')
+
+
+class PHYSICS_PT_viewport_display(PhysicButtonsPanel, Panel):
+ bl_label = "Viewport Display"
+ bl_parent_id = 'PHYSICS_PT_fluid'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return (PhysicButtonsPanel.poll_gas_domain(context))
+
+ def draw(self, context):
layout = self.layout
layout.use_property_split = True
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
- fluid = context.fluid.settings
+ domain = context.fluid.domain_settings
col = flow.column()
- col.prop(fluid, "tracer_particles", text="Tracer")
+ col.prop(domain, "display_thickness")
+
+ col.separator()
+
+ col.prop(domain, "slice_method", text="Slicing")
+
+ slice_method = domain.slice_method
+ axis_slice_method = domain.axis_slice_method
+
+ do_axis_slicing = (slice_method == 'AXIS_ALIGNED')
+ do_full_slicing = (axis_slice_method == 'FULL')
+
+ col = col.column()
+ col.enabled = do_axis_slicing
+ col.prop(domain, "axis_slice_method")
col = flow.column()
- col.prop(fluid, "generate_particles", text="Generate")
+ sub = col.column()
+ sub.enabled = not do_full_slicing and do_axis_slicing
+ sub.prop(domain, "slice_axis")
+ sub.prop(domain, "slice_depth")
+
+ row = col.row()
+ row.enabled = do_full_slicing or not do_axis_slicing
+ row.prop(domain, "slice_per_voxel")
+
+ col.prop(domain, "display_interpolation")
+
+
+class PHYSICS_PT_viewport_display_color(PhysicButtonsPanel, Panel):
+ bl_label = "Color Mapping"
+ bl_parent_id = 'PHYSICS_PT_viewport_display'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return (PhysicButtonsPanel.poll_gas_domain(context))
+
+ def draw_header(self, context):
+ md = context.fluid.domain_settings
+
+ self.layout.prop(md, "use_color_ramp", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.fluid.domain_settings
+ col = layout.column()
+ col.enabled = domain.use_color_ramp
+
+ col.prop(domain, "coba_field")
+
+ col.use_property_split = False
+
+ col = col.column()
+ col.template_color_ramp(domain, "color_ramp", expand=True)
+
+
+class PHYSICS_PT_viewport_display_debug(PhysicButtonsPanel, Panel):
+ bl_label = "Debug Velocity"
+ bl_parent_id = 'PHYSICS_PT_viewport_display'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return (PhysicButtonsPanel.poll_gas_domain(context))
+
+ def draw_header(self, context):
+ md = context.fluid.domain_settings
+
+ self.layout.prop(md, "show_velocity", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
+
+ domain = context.fluid.domain_settings
+
+ col = flow.column()
+ col.enabled = domain.show_velocity
+ col.prop(domain, "vector_display_type", text="Display As")
+ col.prop(domain, "vector_scale")
classes = (
- FLUID_PT_presets,
+ FLUID_MT_presets,
PHYSICS_PT_fluid,
- PHYSICS_PT_fluid_settings,
- PHYSICS_PT_fluid_flow,
- PHYSICS_PT_fluid_particle_cache,
- PHYSICS_PT_domain_bake,
- PHYSICS_PT_domain_boundary,
- PHYSICS_PT_domain_particles,
- PHYSICS_PT_domain_gravity,
- PHYSICS_PT_domain_viscosity,
+ PHYSICS_PT_settings,
+ PHYSICS_PT_borders,
+ PHYSICS_PT_smoke,
+ PHYSICS_PT_smoke_dissolve,
+ PHYSICS_PT_fire,
+ PHYSICS_PT_liquid,
+ PHYSICS_PT_flow_source,
+ PHYSICS_PT_flow_initial_velocity,
+ PHYSICS_PT_flow_texture,
+ PHYSICS_PT_adaptive_domain,
+ PHYSICS_PT_noise,
+ PHYSICS_PT_mesh,
+ PHYSICS_PT_particles,
+ PHYSICS_PT_diffusion,
+ PHYSICS_PT_guide,
+ PHYSICS_PT_collections,
+ PHYSICS_PT_cache,
+ PHYSICS_PT_export,
+ PHYSICS_PT_field_weights,
+ PHYSICS_PT_viewport_display,
+ PHYSICS_PT_viewport_display_color,
+ PHYSICS_PT_viewport_display_debug,
)
+
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py
deleted file mode 100644
index 057e7ddf211..00000000000
--- a/release/scripts/startup/bl_ui/properties_physics_smoke.py
+++ /dev/null
@@ -1,692 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-
-import bpy
-from bpy.types import (
- Panel,
-)
-from bl_ui.properties_physics_common import (
- point_cache_ui,
- effector_weights_ui,
-)
-
-
-class PhysicButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "physics"
-
- @staticmethod
- def poll_smoke(context):
- ob = context.object
- if not ((ob and ob.type == 'MESH') and (context.smoke)):
- return False
-
- md = context.smoke
- return md and (context.smoke.smoke_type != 'NONE') and (bpy.app.build_options.mod_smoke)
-
- @staticmethod
- def poll_smoke_domain(context):
- if not PhysicButtonsPanel.poll_smoke(context):
- return False
-
- md = context.smoke
- return md and (md.smoke_type == 'DOMAIN')
-
-
-class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
- bl_label = "Smoke"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- ob = context.object
- return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.smoke)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- if not bpy.app.build_options.mod_smoke:
- col = layout.column(align=True)
- col.alignment = 'RIGHT'
- col.label(text="Built without Smoke modifier")
- return
-
- md = context.smoke
-
- layout.prop(md, "smoke_type")
-
-
-class PHYSICS_PT_smoke_settings(PhysicButtonsPanel, Panel):
- bl_label = "Settings"
- bl_parent_id = 'PHYSICS_PT_smoke'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.smoke
- ob = context.object
-
- if md.smoke_type == 'DOMAIN':
- domain = md.domain_settings
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
- col.enabled = (not domain.point_cache.is_baked)
- col.prop(domain, "resolution_max", text="Resolution Divisions")
- col.prop(domain, "time_scale", text="Time Scale")
-
- col.separator()
-
- col = flow.column()
- sub = col.row()
- sub.enabled = (not domain.point_cache.is_baked)
- sub.prop(domain, "collision_extents", text="Border Collisions")
-
- # This can be tweaked after baking, for render.
- col.prop(domain, "clipping", text="Empty Space")
-
- elif md.smoke_type == 'FLOW':
- flow_smoke = md.flow_settings
-
- col = layout.column()
- col.prop(flow_smoke, "smoke_flow_type", expand=False)
-
- col.separator()
-
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
- col = flow.column()
-
- if flow_smoke.smoke_flow_type != 'OUTFLOW':
- col.prop(flow_smoke, "smoke_flow_source", expand=False, text="Flow Source")
-
- if flow_smoke.smoke_flow_source == 'PARTICLES':
- col.prop_search(
- flow_smoke, "particle_system", ob, "particle_systems",
- text="Particle System"
- )
- else:
- col.prop(flow_smoke, "surface_distance")
- col.prop(flow_smoke, "volume_density")
-
- col = flow.column()
- col.prop(flow_smoke, "use_absolute")
-
- if flow_smoke.smoke_flow_type in {'SMOKE', 'BOTH'}:
- col.prop(flow_smoke, "density")
- col.prop(flow_smoke, "temperature", text="Temperature Diff.")
-
- col.separator()
-
- col = flow.column()
- col.prop(flow_smoke, "smoke_color")
-
- if flow_smoke.smoke_flow_type in {'FIRE', 'BOTH'}:
- col.prop(flow_smoke, "fuel_amount")
-
- col.prop(flow_smoke, "subframes", text="Sampling Subframes")
-
- col.separator()
-
- col.prop_search(flow_smoke, "density_vertex_group", ob, "vertex_groups", text="Vertex Group")
-
- elif md.smoke_type == 'COLLISION':
- coll = md.coll_settings
-
- col = layout.column()
- col.prop(coll, "collision_type")
-
-
-class PHYSICS_PT_smoke_settings_initial_velocity(PhysicButtonsPanel, Panel):
- bl_label = "Initial Velocity"
- bl_parent_id = 'PHYSICS_PT_smoke_settings'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke(context):
- return False
-
- md = context.smoke
- return (md and (md.smoke_type == 'FLOW')
- and md.flow_settings and md.flow_settings.smoke_flow_type != 'OUTFLOW'
- and context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.smoke
- flow_smoke = md.flow_settings
-
- self.layout.prop(flow_smoke, "use_initial_velocity", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
-
- md = context.smoke
- flow_smoke = md.flow_settings
-
- flow.active = flow_smoke.use_initial_velocity
-
- col = flow.column(align=True)
- col.prop(flow_smoke, "velocity_factor")
-
- if flow_smoke.smoke_flow_source == 'MESH':
- col = flow.column()
- col.prop(flow_smoke, "velocity_normal")
- # sub.prop(flow_smoke, "velocity_random")
-
-
-class PHYSICS_PT_smoke_settings_particle_size(PhysicButtonsPanel, Panel):
- bl_label = "Particle Size"
- bl_parent_id = 'PHYSICS_PT_smoke_settings'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke(context):
- return False
-
- md = context.smoke
- return (md and (md.smoke_type == 'FLOW')
- and md.flow_settings and md.flow_settings.smoke_flow_type != 'OUTFLOW'
- and md.flow_settings.smoke_flow_source == 'PARTICLES'
- and context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.smoke
- flow_smoke = md.flow_settings
-
- self.layout.prop(flow_smoke, "use_particle_size", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.smoke
- flow_smoke = md.flow_settings
-
- layout.active = flow_smoke.use_particle_size
-
- layout.prop(flow_smoke, "particle_size")
-
-
-class PHYSICS_PT_smoke_behavior(PhysicButtonsPanel, Panel):
- bl_label = "Behavior"
- bl_parent_id = 'PHYSICS_PT_smoke_settings'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.smoke
- domain = md.domain_settings
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- flow.enabled = (not domain.point_cache.is_baked)
-
- col = flow.column()
- col.prop(domain, "alpha")
- col.prop(domain, "beta", text="Temperature Diff.")
- col = flow.column()
- col.prop(domain, "vorticity")
-
-
-class PHYSICS_PT_smoke_behavior_dissolve(PhysicButtonsPanel, Panel):
- bl_label = "Dissolve"
- bl_parent_id = 'PHYSICS_PT_smoke_behavior'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.smoke
- domain = md.domain_settings
-
- self.layout.prop(domain, "use_dissolve_smoke", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.smoke
- domain = md.domain_settings
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- flow.enabled = (not domain.point_cache.is_baked)
-
- layout.active = domain.use_dissolve_smoke
-
- col = flow.column()
- col.prop(domain, "dissolve_speed", text="Time")
-
- col = flow.column()
- col.prop(domain, "use_dissolve_smoke_log", text="Slow")
-
-
-class PHYSICS_PT_smoke_flow_texture(PhysicButtonsPanel, Panel):
- bl_label = "Texture"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke(context):
- return False
-
- md = context.smoke
- return (md and (md.smoke_type == 'FLOW')
- and (md.flow_settings.smoke_flow_source == 'MESH')
- and (context.engine in cls.COMPAT_ENGINES))
-
- def draw_header(self, context):
- md = context.smoke
- flow_smoke = md.flow_settings
-
- self.layout.prop(flow_smoke, "use_texture", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- ob = context.object
- flow_smoke = context.smoke.flow_settings
-
- sub = flow.column()
- sub.active = flow_smoke.use_texture
- sub.prop(flow_smoke, "noise_texture")
- sub.prop(flow_smoke, "texture_map_type", text="Mapping")
-
- col = flow.column()
- sub = col.column()
- sub.active = flow_smoke.use_texture
-
- if flow_smoke.texture_map_type == 'UV':
- sub.prop_search(flow_smoke, "uv_layer", ob.data, "uv_layers")
-
- if flow_smoke.texture_map_type == 'AUTO':
- sub.prop(flow_smoke, "texture_size")
-
- sub.prop(flow_smoke, "texture_offset")
-
-
-class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel):
- bl_label = "Flames"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- domain = context.smoke.domain_settings
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- flow.enabled = (not domain.point_cache.is_baked)
-
- col = flow.column()
- col.prop(domain, "burning_rate", text="Reaction Speed")
- col.prop(domain, "flame_smoke")
- col.prop(domain, "flame_vorticity")
-
- col.separator()
-
- col = flow.column(align=True)
- col.prop(domain, "flame_ignition", text="Temperature Ignition")
- col.prop(domain, "flame_max_temp")
-
- col.separator()
-
- sub = col.column()
- sub.prop(domain, "flame_smoke_color")
-
-
-class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
- bl_label = "Adaptive Domain"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.smoke.domain_settings
-
- self.layout.prop(md, "use_adaptive_domain", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- domain = context.smoke.domain_settings
- layout.active = domain.use_adaptive_domain
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
- flow.enabled = (not domain.point_cache.is_baked)
-
- col = flow.column()
- col.prop(domain, "additional_res", text="Add Resolution")
- col.prop(domain, "adapt_margin")
-
- col.separator()
-
- col = flow.column()
- col.prop(domain, "adapt_threshold", text="Threshold")
-
-
-class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
- bl_label = "High Resolution"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.smoke.domain_settings
-
- self.layout.prop(md, "use_high_resolution", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.smoke.domain_settings
- layout.active = md.use_high_resolution
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- col = flow.column()
- col.enabled = not md.point_cache.is_baked
- col.prop(md, "amplify", text="Resolution Divisions")
- col.prop(md, "highres_sampling", text="Flow Sampling")
-
- col.separator()
-
- col = flow.column()
- col.enabled = not md.point_cache.is_baked
- col.prop(md, "noise_type", text="Noise Method")
- col.prop(md, "strength")
-
- layout.prop(md, "show_high_resolution")
-
-
-class PHYSICS_PT_smoke_collections(PhysicButtonsPanel, Panel):
- bl_label = "Collections"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- domain = context.smoke.domain_settings
-
- col = layout.column()
- col.prop(domain, "fluid_collection", text="Flow")
-
- # col = layout.column()
- # col.prop(domain, "effector_collection", text="Effector")
- col.prop(domain, "collision_collection", text="Collision")
-
-
-class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
- bl_label = "Cache"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- domain = context.smoke.domain_settings
- cache_file_format = domain.cache_file_format
-
- col = flow.column()
- col.prop(domain, "cache_file_format")
-
- if cache_file_format == 'POINTCACHE':
- col = flow.column()
- col.prop(domain, "point_cache_compress_type", text="Compression")
- col.separator()
-
- elif cache_file_format == 'OPENVDB':
- if not bpy.app.build_options.openvdb:
- row = layout.row(align=True)
- row.alignment = 'RIGHT'
- row.label(text="Built without OpenVDB support")
- return
-
- col = flow.column()
- col.prop(domain, "openvdb_cache_compress_type", text="Compression")
- col.prop(domain, "data_depth", text="Data Depth")
- col.separator()
-
- cache = domain.point_cache
- point_cache_ui(self, cache, (cache.is_baked is False), 'SMOKE')
-
-
-class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel):
- bl_label = "Field Weights"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- domain = context.smoke.domain_settings
- effector_weights_ui(self, domain.effector_weights, 'SMOKE')
-
-
-class PHYSICS_PT_smoke_viewport_display(PhysicButtonsPanel, Panel):
- bl_label = "Viewport Display"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- return (PhysicButtonsPanel.poll_smoke_domain(context))
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- domain = context.smoke.domain_settings
-
- col = flow.column()
- col.prop(domain, "display_thickness")
-
- col.separator()
-
- col.prop(domain, "slice_method", text="Slicing")
-
- slice_method = domain.slice_method
- axis_slice_method = domain.axis_slice_method
-
- do_axis_slicing = (slice_method == 'AXIS_ALIGNED')
- do_full_slicing = (axis_slice_method == 'FULL')
-
- col = col.column()
- col.enabled = do_axis_slicing
- col.prop(domain, "axis_slice_method")
-
- col = flow.column()
- sub = col.column()
- sub.enabled = not do_full_slicing and do_axis_slicing
- sub.prop(domain, "slice_axis")
- sub.prop(domain, "slice_depth")
-
- row = col.row()
- row.enabled = do_full_slicing or not do_axis_slicing
- row.prop(domain, "slice_per_voxel")
-
- col.prop(domain, "display_interpolation")
-
-
-class PHYSICS_PT_smoke_viewport_display_color(PhysicButtonsPanel, Panel):
- bl_label = "Color Mapping"
- bl_parent_id = 'PHYSICS_PT_smoke_viewport_display'
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- return (PhysicButtonsPanel.poll_smoke_domain(context))
-
- def draw_header(self, context):
- md = context.smoke.domain_settings
-
- self.layout.prop(md, "use_color_ramp", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- domain = context.smoke.domain_settings
- col = layout.column()
- col.enabled = domain.use_color_ramp
-
- col.prop(domain, "coba_field")
-
- col.use_property_split = False
-
- col = col.column()
- col.template_color_ramp(domain, "color_ramp", expand=True)
-
-
-class PHYSICS_PT_smoke_viewport_display_debug(PhysicButtonsPanel, Panel):
- bl_label = "Debug Velocity"
- bl_parent_id = 'PHYSICS_PT_smoke_viewport_display'
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- return (PhysicButtonsPanel.poll_smoke_domain(context))
-
- def draw_header(self, context):
- md = context.smoke.domain_settings
-
- self.layout.prop(md, "show_velocity", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- domain = context.smoke.domain_settings
-
- col = flow.column()
- col.enabled = domain.show_velocity
- col.prop(domain, "vector_display_type", text="Display As")
- col.prop(domain, "vector_scale")
-
-
-classes = (
- PHYSICS_PT_smoke,
- PHYSICS_PT_smoke_settings,
- PHYSICS_PT_smoke_settings_initial_velocity,
- PHYSICS_PT_smoke_settings_particle_size,
- PHYSICS_PT_smoke_behavior,
- PHYSICS_PT_smoke_behavior_dissolve,
- PHYSICS_PT_smoke_adaptive_domain,
- PHYSICS_PT_smoke_cache,
- PHYSICS_PT_smoke_field_weights,
- PHYSICS_PT_smoke_fire,
- PHYSICS_PT_smoke_flow_texture,
- PHYSICS_PT_smoke_collections,
- PHYSICS_PT_smoke_highres,
- PHYSICS_PT_smoke_viewport_display,
- PHYSICS_PT_smoke_viewport_display_color,
- PHYSICS_PT_smoke_viewport_display_debug,
-)
-
-
-if __name__ == "__main__": # only for live edit.
- from bpy.utils import register_class
- for cls in classes:
- register_class(cls)
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index 9afdcdff9a5..f93629a4f03 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -1445,15 +1445,6 @@ class CLIP_MT_select_grouped(Menu):
layout.operator_enum("clip.select_grouped", "group")
-class CLIP_MT_mask_handle_type_menu(Menu):
- bl_label = "Set Handle Type"
-
- def draw(self, _context):
- layout = self.layout
-
- layout.operator_enum("mask.handle_type_set", "type")
-
-
class CLIP_MT_tracking_context_menu(Menu):
bl_label = "Context Menu"
@@ -1507,30 +1498,8 @@ class CLIP_MT_tracking_context_menu(Menu):
layout.operator("clip.delete_track")
elif mode == 'MASK':
-
- layout.menu("CLIP_MT_mask_handle_type_menu")
- layout.operator("mask.switch_direction")
- layout.operator("mask.cyclic_toggle")
-
- layout.separator()
-
- layout.operator("mask.copy_splines", icon='COPYDOWN')
- layout.operator("mask.paste_splines", icon='PASTEDOWN')
-
- layout.separator()
-
- layout.operator("mask.shape_key_rekey", text="Re-key Shape Points")
- layout.operator("mask.feather_weight_clear")
- layout.operator("mask.shape_key_feather_reset", text="Reset Feather Animation")
-
- layout.separator()
-
- layout.operator("mask.parent_set")
- layout.operator("mask.parent_clear")
-
- layout.separator()
-
- layout.operator("mask.delete")
+ from .properties_mask_common import draw_mask_context_menu
+ draw_mask_context_menu(layout, context)
class CLIP_PT_camera_presets(PresetPanel, Panel):
@@ -1801,7 +1770,6 @@ classes = (
CLIP_MT_tracking_pie,
CLIP_MT_reconstruction_pie,
CLIP_MT_solving_pie,
- CLIP_MT_mask_handle_type_menu
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index fac8ff238c0..a09e263fd87 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -25,6 +25,12 @@ from bpy.types import (
Panel,
)
+from bl_ui.properties_grease_pencil_common import (
+ GreasePencilLayerAdjustmentsPanel,
+ GreasePencilLayerRelationsPanel,
+ GreasePencilLayerDisplayPanel,
+)
+
#######################################
# DopeSheet Filtering - Header Buttons
@@ -243,6 +249,18 @@ class DOPESHEET_HT_editor_buttons(Header):
layout.template_ID(st, "action", new="action.new", unlink="action.unlink")
+ # Layer management
+ if st.mode == 'GPENCIL':
+ row = layout.row(align=True)
+ row.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
+ row.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+
+ row = layout.row(align=True)
+ row.operator("gpencil.layer_add", icon='ADD', text="")
+ row.operator("gpencil.layer_remove", icon='REMOVE', text="")
+
+ layout.separator_spacer()
+
layout.separator_spacer()
if st.mode == 'DOPESHEET':
@@ -288,7 +306,8 @@ class DOPESHEET_MT_editor_menus(Menu):
layout.menu("DOPESHEET_MT_view")
layout.menu("DOPESHEET_MT_select")
- layout.menu("DOPESHEET_MT_marker")
+ if st.show_markers:
+ layout.menu("DOPESHEET_MT_marker")
if st.mode == 'DOPESHEET' or (st.mode == 'ACTION' and st.action is not None):
layout.menu("DOPESHEET_MT_channel")
@@ -322,9 +341,12 @@ class DOPESHEET_MT_view(Menu):
layout.prop(st, "show_group_colors")
layout.prop(st, "show_interpolation")
layout.prop(st, "show_extremes")
- layout.prop(st, "show_marker_lines")
layout.prop(st, "use_auto_merge_keyframes")
+ layout.separator()
+ layout.prop(st, "show_markers")
+
+ layout.separator()
layout.prop(st, "show_seconds")
layout.prop(st, "show_locked_time")
@@ -520,8 +542,8 @@ class DOPESHEET_MT_gpencil_channel(Menu):
# layout.operator("anim.channels_expand")
# layout.operator("anim.channels_collapse")
- # layout.separator()
- #layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
+ layout.separator()
+ layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
class DOPESHEET_MT_gpencil_frame(Menu):
@@ -636,6 +658,66 @@ class DOPESHEET_MT_snap_pie(Menu):
pie.operator("action.snap", text="Nearest Marker").type = 'NEAREST_MARKER'
+class LayersDopeSheetPanel:
+ bl_space_type = 'DOPESHEET_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "View"
+
+ @classmethod
+ def poll(cls, context):
+ st = context.space_data
+ ob = context.object
+ if st.mode != 'GPENCIL' or ob is None or ob.type != 'GPENCIL':
+ return False
+
+ gpd = ob.data
+ gpl = gpd.layers.active
+ if gpl:
+ return True
+
+ return False
+
+
+class DOPESHEET_PT_gpencil_mode(LayersDopeSheetPanel, Panel):
+ # bl_space_type = 'DOPESHEET_EDITOR'
+ # bl_region_type = 'UI'
+ # bl_category = "View"
+ bl_label = "Layer"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ ob = context.object
+ gpd = ob.data
+ gpl = gpd.layers.active
+ if gpl:
+ row = layout.row(align=True)
+ row.prop(gpl, "blend_mode", text="Blend")
+
+ row = layout.row(align=True)
+ row.prop(gpl, "opacity", text="Opacity", slider=True)
+
+
+class DOPESHEET_PT_gpencil_layer_adjustments(LayersDopeSheetPanel, GreasePencilLayerAdjustmentsPanel, Panel):
+ bl_label = "Adjustments"
+ bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
+ bl_options = {'DEFAULT_CLOSED'}
+
+
+class DOPESHEET_PT_gpencil_layer_relations(LayersDopeSheetPanel, GreasePencilLayerRelationsPanel, Panel):
+ bl_label = "Relations"
+ bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
+ bl_options = {'DEFAULT_CLOSED'}
+
+
+class DOPESHEET_PT_gpencil_layer_display(LayersDopeSheetPanel, GreasePencilLayerDisplayPanel, Panel):
+ bl_label = "Display"
+ bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
+ bl_options = {'DEFAULT_CLOSED'}
+
+
classes = (
DOPESHEET_HT_header,
DOPESHEET_HT_editor_buttons,
@@ -653,6 +735,10 @@ classes = (
DOPESHEET_MT_channel_context_menu,
DOPESHEET_MT_snap_pie,
DOPESHEET_PT_filters,
+ DOPESHEET_PT_gpencil_mode,
+ DOPESHEET_PT_gpencil_layer_adjustments,
+ DOPESHEET_PT_gpencil_layer_relations,
+ DOPESHEET_PT_gpencil_layer_display,
)
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 958052c8f25..8dd0eaf5445 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -162,27 +162,18 @@ def panel_poll_is_upper_region(region):
class FILEBROWSER_UL_dir(UIList):
- def draw_item(self, _context, layout, _data, item, icon, _active_data, active_propname, _index):
+ def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
direntry = item
# space = context.space_data
- icon = 'NONE'
- if active_propname == "system_folders_active":
- icon = 'DISK_DRIVE'
- if active_propname == "system_bookmarks_active":
- icon = 'BOOKMARKS'
- if active_propname == "bookmarks_active":
- icon = 'BOOKMARKS'
- if active_propname == "recent_folders_active":
- icon = 'FILE_FOLDER'
if self.layout_type in {'DEFAULT', 'COMPACT'}:
row = layout.row(align=True)
row.enabled = direntry.is_valid
# Non-editable entries would show grayed-out, which is bad in this specific case, so switch to mere label.
if direntry.is_property_readonly("name"):
- row.label(text=direntry.name, icon=icon)
+ row.label(text=direntry.name, icon_value=icon)
else:
- row.prop(direntry, "name", text="", emboss=False, icon=icon)
+ row.prop(direntry, "name", text="", emboss=False, icon_value=icon)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 15ef7b0ef82..2e853a287ea 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -93,11 +93,13 @@ class GRAPH_MT_editor_menus(Menu):
bl_idname = "GRAPH_MT_editor_menus"
bl_label = ""
- def draw(self, _context):
+ def draw(self, context):
+ st = context.space_data
layout = self.layout
layout.menu("GRAPH_MT_view")
layout.menu("GRAPH_MT_select")
- layout.menu("GRAPH_MT_marker")
+ if st.mode != 'DRIVERS' and st.show_markers:
+ layout.menu("GRAPH_MT_marker")
layout.menu("GRAPH_MT_channel")
layout.menu("GRAPH_MT_key")
@@ -111,15 +113,19 @@ class GRAPH_MT_view(Menu):
st = context.space_data
layout.prop(st, "show_region_ui")
+ layout.prop(st, "show_region_hud")
layout.separator()
layout.prop(st, "use_realtime_update")
layout.prop(st, "show_cursor")
layout.prop(st, "show_sliders")
layout.prop(st, "show_group_colors")
- layout.prop(st, "show_marker_lines")
layout.prop(st, "use_auto_merge_keyframes")
+ if st.mode != 'DRIVERS':
+ layout.separator()
+ layout.prop(st, "show_markers")
+
layout.separator()
layout.prop(st, "use_beauty_drawing")
@@ -285,7 +291,16 @@ class GRAPH_MT_key(Menu):
layout.operator_menu_enum("graph.easing_type", "type", text="Easing Type")
layout.separator()
- layout.operator("graph.decimate")
+ operator_context = layout.operator_context
+
+ layout.operator("graph.decimate", text="Decimate (Ratio)").mode = 'RATIO'
+
+ # Using the modal operation doesn't make sense for this variant
+ # as we do not have a modal mode for it, so just execute it.
+ layout.operator_context = 'EXEC_DEFAULT'
+ layout.operator("graph.decimate", text="Decimate (Allowed Change)").mode = 'ERROR'
+ layout.operator_context = operator_context
+
layout.operator("graph.clean").channels = False
layout.operator("graph.clean", text="Clean Channels").channels = True
layout.operator("graph.smooth")
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 8de12f759fc..c6f490f9d26 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -27,12 +27,18 @@ from bpy.types import (
from bl_ui.properties_paint_common import (
UnifiedPaintPanel,
brush_texture_settings,
- brush_texpaint_common,
- brush_texpaint_common_color,
- brush_texpaint_common_gradient,
- brush_texpaint_common_clone,
- brush_texpaint_common_options,
- brush_mask_texture_settings,
+ brush_basic_texpaint_settings,
+ brush_settings,
+ brush_settings_advanced,
+ draw_color_settings,
+ ClonePanel,
+ BrushSelectPanel,
+ TextureMaskPanel,
+ ColorPalettePanel,
+ StrokePanel,
+ SmoothStrokePanel,
+ FalloffPanel,
+ DisplayPanel,
)
from bl_ui.properties_grease_pencil_common import (
AnnotationDataPanel,
@@ -44,7 +50,7 @@ from bl_ui.space_toolsystem_common import (
from bpy.app.translations import pgettext_iface as iface_
-class ImagePaintPanel(UnifiedPaintPanel):
+class ImagePaintPanel:
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
@@ -59,7 +65,7 @@ class BrushButtonsPanel(UnifiedPaintPanel):
return tool_settings.brush
-class IMAGE_PT_active_tool(ToolActivePanelHelper, Panel):
+class IMAGE_PT_active_tool(Panel, ToolActivePanelHelper):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_category = "Tool"
@@ -181,25 +187,6 @@ class IMAGE_MT_select(Menu):
layout.operator("uv.select_overlap")
-class IMAGE_MT_brush(Menu):
- bl_label = "Brush"
-
- def draw(self, context):
- layout = self.layout
- tool_settings = context.tool_settings
- settings = tool_settings.image_paint
- brush = settings.brush
-
- ups = context.tool_settings.unified_paint_settings
- layout.prop(ups, "use_unified_size", text="Unified Size")
- layout.prop(ups, "use_unified_strength", text="Unified Strength")
- layout.prop(ups, "use_unified_color", text="Unified Color")
- layout.separator()
-
- # Brush tool.
- layout.prop_menu_enum(brush, "image_tool")
-
-
class IMAGE_MT_image(Menu):
bl_label = "Image"
@@ -244,7 +231,7 @@ class IMAGE_MT_image(Menu):
if ima and not show_render:
if ima.packed_file:
- if len(ima.filepath):
+ if ima.filepath:
layout.separator()
layout.operator("image.unpack", text="Unpack")
else:
@@ -569,15 +556,16 @@ class IMAGE_HT_tool_header(Header):
if tool_mode == 'PAINT':
if (tool is not None) and tool.has_datablock:
- layout.popover_group(
- space_type='IMAGE_EDITOR',
- region_type='UI',
- context=".paint_common_2d",
- category="",
- )
+ layout.popover("IMAGE_PT_paint_settings_advanced")
+ layout.popover("IMAGE_PT_paint_stroke")
+ layout.popover("IMAGE_PT_paint_curve")
+ layout.popover("IMAGE_PT_tools_brush_display")
+ layout.popover("IMAGE_PT_tools_brush_texture")
+ layout.popover("IMAGE_PT_tools_mask_texture")
elif tool_mode == 'UV':
if (tool is not None) and tool.has_datablock:
- layout.popover_group(space_type='IMAGE_EDITOR', region_type='UI', context=".uv_sculpt", category="")
+ layout.popover("IMAGE_PT_uv_sculpt_curve")
+ layout.popover("IMAGE_PT_uv_sculpt_options")
def draw_mode_settings(self, context):
layout = self.layout
@@ -601,15 +589,26 @@ class _draw_tool_settings_context_mode:
uv_sculpt = tool_settings.uv_sculpt
brush = uv_sculpt.brush
if brush:
- from bl_ui.properties_paint_common import UnifiedPaintPanel
-
- row = layout.row(align=True)
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
-
- row = layout.row(align=True)
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength", slider=True)
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "size",
+ pressure_name="use_pressure_size",
+ unified_name="use_unified_size",
+ slider=True,
+ header=True
+ )
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "strength",
+ pressure_name="use_pressure_strength",
+ unified_name="use_unified_strength",
+ slider=True,
+ header=True
+ )
@staticmethod
def PAINT(context, layout, tool):
@@ -623,13 +622,6 @@ class _draw_tool_settings_context_mode:
if brush is None:
return
- from bl_ui.properties_paint_common import (
- UnifiedPaintPanel,
- brush_basic_texpaint_settings,
- )
- capabilities = brush.image_paint_capabilities
- if capabilities.has_color:
- UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
brush_basic_texpaint_settings(layout, context, brush, compact=True)
@@ -763,7 +755,6 @@ class MASK_MT_editor_menus(Menu):
show_uvedit = sima.show_uvedit
show_maskedit = sima.show_maskedit
- show_paint = sima.show_paint
layout.menu("IMAGE_MT_view")
@@ -771,8 +762,6 @@ class MASK_MT_editor_menus(Menu):
layout.menu("IMAGE_MT_select")
if show_maskedit:
layout.menu("MASK_MT_select")
- if show_paint:
- layout.menu("IMAGE_MT_brush")
if ima and ima.is_dirty:
layout.menu("IMAGE_MT_image", text="Image*")
@@ -792,44 +781,13 @@ class IMAGE_MT_mask_context_menu(Menu):
@classmethod
def poll(cls, context):
sima = context.space_data
- return (sima.show_maskedit)
+ return sima.show_maskedit
def draw(self, context):
layout = self.layout
- sima = context.space_data
-
- if not sima.mask:
- layout.operator("mask.new")
- layout.separator()
- layout.operator("mask.primitive_circle_add", icon='MESH_CIRCLE')
- layout.operator("mask.primitive_square_add", icon='MESH_PLANE')
- else:
- layout.operator_menu_enum("mask.handle_type_set", "type")
- layout.operator("mask.switch_direction")
- layout.operator("mask.cyclic_toggle")
-
- layout.separator()
- layout.operator("mask.primitive_circle_add", icon='MESH_CIRCLE')
- layout.operator("mask.primitive_square_add", icon='MESH_PLANE')
-
- layout.separator()
- layout.operator("mask.copy_splines", icon='COPYDOWN')
- layout.operator("mask.paste_splines", icon='PASTEDOWN')
-
- layout.separator()
+ from .properties_mask_common import draw_mask_context_menu
+ draw_mask_context_menu(layout, context)
- layout.operator("mask.shape_key_rekey", text="Re-key Shape Points")
- layout.operator("mask.feather_weight_clear")
- layout.operator("mask.shape_key_feather_reset", text="Reset Feather Animation")
-
- layout.separator()
-
- layout.operator("mask.parent_set")
- layout.operator("mask.parent_clear")
-
- layout.separator()
-
- layout.operator("mask.delete")
# -----------------------------------------------------------------------------
# Mask (similar code in space_clip.py, keep in sync)
@@ -1063,112 +1021,91 @@ class IMAGE_PT_render_slots(Panel):
col.operator("image.clear_render_slot", icon='X', text="")
-class IMAGE_PT_paint(Panel, ImagePaintPanel):
- bl_label = "Brush"
- bl_context = ".paint_common_2d"
- bl_category = "Tool"
-
- def draw(self, context):
- layout = self.layout
-
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- settings = context.tool_settings.image_paint
- brush = settings.brush
-
- col = layout.column()
- col.template_ID_preview(settings, "brush", new="brush.add", rows=2, cols=6)
-
- if brush:
- brush_texpaint_common(self, context, layout, brush, settings)
+class IMAGE_UL_udim_tiles(UIList):
+ def draw_item(self, _context, layout, _data, item, _icon, _active_data, _active_propname, _index):
+ tile = item
+ layout.prop(tile, "label", text="", emboss=False)
-class IMAGE_PT_paint_color(Panel, ImagePaintPanel):
- bl_category = "Tool"
- bl_context = ".paint_common_2d"
- bl_parent_id = "IMAGE_PT_paint"
- bl_label = "Color Picker"
+class IMAGE_PT_udim_tiles(Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "Image"
+ bl_label = "UDIM Tiles"
@classmethod
def poll(cls, context):
- settings = context.tool_settings.image_paint
- brush = settings.brush
- capabilities = brush.image_paint_capabilities
-
- return capabilities.has_color
+ sima = context.space_data
+ return (sima and sima.image and sima.image.source == 'TILED')
def draw(self, context):
layout = self.layout
- settings = context.tool_settings.image_paint
- brush = settings.brush
- layout.prop(brush, "color_type", expand=True)
+ sima = context.space_data
+ ima = sima.image
+
+ row = layout.row()
+ col = row.column()
+ col.template_list("IMAGE_UL_udim_tiles", "", ima, "tiles", ima.tiles, "active_index", rows=4)
+
+ col = row.column()
+ sub = col.column(align=True)
+ sub.operator("image.tile_add", icon='ADD', text="")
+ sub.operator("image.tile_remove", icon='REMOVE', text="")
- if brush.color_type == 'COLOR':
- brush_texpaint_common_color(self, context, layout, brush, settings)
- elif brush.color_type == 'GRADIENT':
- brush_texpaint_common_gradient(self, context, layout, brush, settings)
+ tile = ima.tiles.active
+ if tile:
+ col = layout.column(align=True)
+ col.operator("image.tile_fill")
-class IMAGE_PT_paint_swatches(Panel, ImagePaintPanel):
- bl_category = "Tool"
+class IMAGE_PT_paint_select(Panel, ImagePaintPanel, BrushSelectPanel):
+ bl_label = "Brushes"
bl_context = ".paint_common_2d"
- bl_parent_id = "IMAGE_PT_paint"
- bl_label = "Color Palette"
- bl_options = {'DEFAULT_CLOSED'}
+ bl_category = "Tool"
- @classmethod
- def poll(cls, context):
- settings = context.tool_settings.image_paint
- brush = settings.brush
- capabilities = brush.image_paint_capabilities
- return capabilities.has_color
+class IMAGE_PT_paint_settings(Panel, ImagePaintPanel):
+ bl_context = ".paint_common_2d"
+ bl_category = "Tool"
+ bl_label = "Brush Settings"
def draw(self, context):
layout = self.layout
- settings = context.tool_settings.image_paint
-
- layout.template_ID(settings, "palette", new="palette.new")
- if settings.palette:
- layout.template_palette(settings, "palette", color=True)
+ layout.use_property_split = True
+ layout.use_property_decorate = False
-class IMAGE_PT_paint_clone(Panel, ImagePaintPanel):
- bl_category = "Tool"
- bl_context = ".paint_common_2d"
- bl_parent_id = "IMAGE_PT_paint"
- bl_label = "Clone from Image/UV Map"
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
settings = context.tool_settings.image_paint
brush = settings.brush
- return brush.image_tool == 'CLONE'
+ if brush:
+ brush_settings(layout.column(), context, brush, popover=self.is_popover)
- def draw_header(self, context):
- settings = context.tool_settings.image_paint
- self.layout.prop(settings, "use_clone_layer", text="")
+
+class IMAGE_PT_paint_settings_advanced(Panel, ImagePaintPanel):
+ bl_context = ".paint_common_2d"
+ bl_parent_id = "IMAGE_PT_paint_settings"
+ bl_category = "Tool"
+ bl_label = "Advanced"
def draw(self, context):
layout = self.layout
+
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
+
settings = context.tool_settings.image_paint
brush = settings.brush
- layout.active = settings.use_clone_layer
-
- brush_texpaint_common_clone(self, context, layout, brush, settings)
+ brush_settings_advanced(layout.column(), context, brush, self.is_popover)
-class IMAGE_PT_paint_options(Panel, ImagePaintPanel):
- bl_category = "Tool"
+class IMAGE_PT_paint_color(Panel, ImagePaintPanel):
bl_context = ".paint_common_2d"
- bl_parent_id = "IMAGE_PT_paint"
- bl_label = "Options"
- bl_options = {'DEFAULT_CLOSED'}
+ bl_parent_id = "IMAGE_PT_paint_settings"
+ bl_category = "Tool"
+ bl_label = "Color Picker"
@classmethod
def poll(cls, context):
@@ -1183,130 +1120,36 @@ class IMAGE_PT_paint_options(Panel, ImagePaintPanel):
settings = context.tool_settings.image_paint
brush = settings.brush
- layout.use_property_split = True
- layout.use_property_decorate = False # No animation.
-
- brush_texpaint_common_options(self, context, layout, brush, settings)
+ draw_color_settings(context, layout, brush, color_type=True)
-class IMAGE_PT_tools_brush_display(BrushButtonsPanel, Panel):
- bl_label = "Display"
+class IMAGE_PT_paint_swatches(Panel, ImagePaintPanel, ColorPalettePanel):
+ bl_category = "Tool"
bl_context = ".paint_common_2d"
+ bl_parent_id = "IMAGE_PT_paint_settings"
+ bl_label = "Color Palette"
bl_options = {'DEFAULT_CLOSED'}
- bl_category = "Tool"
-
- def draw(self, context):
- layout = self.layout
-
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- tool_settings = context.tool_settings.image_paint
- brush = tool_settings.brush
- tex_slot = brush.texture_slot
- tex_slot_mask = brush.mask_texture_slot
-
- col = layout.column()
-
- row = col.row(align=True)
-
- sub = row.row(align=True)
- sub.prop(brush, "cursor_overlay_alpha", text="Curve Alpha")
- sub.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
- row.prop(
- brush, "use_cursor_overlay", text="", toggle=True,
- icon='HIDE_OFF' if brush.use_cursor_overlay else 'HIDE_ON',
- )
- col.active = brush.brush_capabilities.has_overlay
- row = col.row(align=True)
-
- sub = row.row(align=True)
- sub.prop(brush, "texture_overlay_alpha", text="Texture Alpha")
- sub.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
- if tex_slot.map_mode != 'STENCIL':
- row.prop(
- brush, "use_primary_overlay", text="", toggle=True,
- icon='HIDE_OFF' if brush.use_primary_overlay else 'HIDE_ON',
- )
-
- row = col.row(align=True)
-
- sub = row.row(align=True)
- sub.prop(brush, "mask_overlay_alpha", text="Mask Texture Alpha")
- sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
- if tex_slot_mask.map_mode != 'STENCIL':
- row.prop(
- brush, "use_secondary_overlay", text="", toggle=True,
- icon='HIDE_OFF' if brush.use_secondary_overlay else 'HIDE_ON',
- )
-
-
-class IMAGE_PT_tools_brush_display_show_brush(BrushButtonsPanel, Panel):
- bl_context = ".paint_common_2d" # dot on purpose (access from topbar)
- bl_label = "Show Brush"
- bl_parent_id = "IMAGE_PT_tools_brush_display"
+class IMAGE_PT_paint_clone(Panel, ImagePaintPanel, ClonePanel):
bl_category = "Tool"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, context):
- settings = context.tool_settings.image_paint
-
- self.layout.prop(settings, "show_brush", text="")
-
- def draw(self, context):
- layout = self.layout
-
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- settings = context.tool_settings.image_paint
- brush = settings.brush
-
- col = layout.column()
- col.active = settings.show_brush
-
- if context.sculpt_object and context.tool_settings.sculpt:
- if brush.sculpt_capabilities.has_secondary_color:
- col.prop(brush, "cursor_color_add", text="Add")
- col.prop(brush, "cursor_color_subtract", text="Subtract")
- else:
- col.prop(brush, "cursor_color_add", text="Color")
- else:
- col.prop(brush, "cursor_color_add", text="Color")
+ bl_context = ".paint_common_2d"
+ bl_parent_id = "IMAGE_PT_paint_settings"
+ bl_label = "Clone from Image/UV Map"
-class IMAGE_PT_tools_brush_display_custom_icon(BrushButtonsPanel, Panel):
- bl_context = ".paint_common_2d" # dot on purpose (access from topbar)
- bl_label = "Custom Icon"
- bl_parent_id = "IMAGE_PT_tools_brush_display"
+class IMAGE_PT_tools_brush_display(Panel, BrushButtonsPanel, DisplayPanel):
+ bl_context = ".paint_common_2d"
+ bl_parent_id = "IMAGE_PT_paint_settings"
bl_category = "Tool"
+ bl_label = "Brush Tip"
bl_options = {'DEFAULT_CLOSED'}
- def draw_header(self, context):
- settings = context.tool_settings.image_paint
- brush = settings.brush
-
- self.layout.prop(brush, "use_custom_icon", text="")
-
- def draw(self, context):
- layout = self.layout
-
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- settings = context.tool_settings.image_paint
- brush = settings.brush
-
- col = layout.column()
- col.active = brush.use_custom_icon
- col.prop(brush, "icon_filepath", text="")
-
class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
bl_label = "Texture"
bl_context = ".paint_common_2d"
+ bl_parent_id = "IMAGE_PT_paint_settings"
bl_category = "Tool"
bl_options = {'DEFAULT_CLOSED'}
@@ -1322,135 +1165,36 @@ class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
brush_texture_settings(col, brush, 0)
-class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
- bl_label = "Texture Mask"
+class IMAGE_PT_tools_mask_texture(Panel, BrushButtonsPanel, TextureMaskPanel):
bl_context = ".paint_common_2d"
+ bl_parent_id = "IMAGE_PT_paint_settings"
bl_category = "Tool"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw(self, context):
- layout = self.layout
-
- brush = context.tool_settings.image_paint.brush
-
- col = layout.column()
-
- col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
-
- brush_mask_texture_settings(col, brush)
+ bl_label = "Texture Mask"
-class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel):
+class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel, StrokePanel):
bl_label = "Stroke"
bl_context = ".paint_common_2d"
+ bl_parent_id = "IMAGE_PT_paint_settings"
bl_category = "Tool"
bl_options = {'DEFAULT_CLOSED'}
- def draw(self, context):
- layout = self.layout
-
- tool_settings = context.tool_settings.image_paint
- brush = tool_settings.brush
-
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- col = layout.column()
-
- col.prop(brush, "stroke_method")
-
- if brush.use_anchor:
- col.prop(brush, "use_edge_to_edge", text="Edge To Edge")
-
- if brush.use_airbrush:
- col.prop(brush, "rate", text="Rate", slider=True)
-
- if brush.use_space:
- row = col.row(align=True)
- row.prop(brush, "spacing", text="Spacing")
- row.prop(brush, "use_pressure_spacing", toggle=True, text="")
-
- if brush.use_line or brush.use_curve:
- row = col.row(align=True)
- row.prop(brush, "spacing", text="Spacing")
- if brush.use_curve:
- col.template_ID(brush, "paint_curve", new="paintcurve.new")
- col.operator("paintcurve.draw")
-
- row = col.row(align=True)
- if brush.use_relative_jitter:
- row.prop(brush, "jitter", slider=True)
- else:
- row.prop(brush, "jitter_absolute")
- row.prop(brush, "use_relative_jitter", icon_only=True)
- row.prop(brush, "use_pressure_jitter", toggle=True, text="")
-
- col.prop(tool_settings, "input_samples")
-
-
-class IMAGE_PT_paint_stroke_smooth_stroke(BrushButtonsPanel, Panel):
- bl_context = ".paint_common_2d" # dot on purpose (access from topbar)
- bl_label = "Smooth Stroke"
+class IMAGE_PT_paint_stroke_smooth_stroke(Panel, BrushButtonsPanel, SmoothStrokePanel):
+ bl_context = ".paint_common_2d"
+ bl_label = "Stabilize Stroke"
bl_parent_id = "IMAGE_PT_paint_stroke"
bl_category = "Tool"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- settings = context.tool_settings.image_paint
- brush = settings.brush
- if brush.brush_capabilities.has_smooth_stroke:
- return True
-
- def draw_header(self, context):
- settings = context.tool_settings.image_paint
- brush = settings.brush
-
- self.layout.prop(brush, "use_smooth_stroke", text="")
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- settings = context.tool_settings.image_paint
- brush = settings.brush
-
- col = layout.column()
- col.active = brush.use_smooth_stroke
- col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
- col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
-
-
-class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
+class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel, FalloffPanel):
bl_label = "Falloff"
bl_context = ".paint_common_2d"
+ bl_parent_id = "IMAGE_PT_paint_settings"
bl_category = "Tool"
bl_options = {'DEFAULT_CLOSED'}
- def draw(self, context):
- layout = self.layout
-
- tool_settings = context.tool_settings.image_paint
- brush = tool_settings.brush
-
- col = layout.column(align=True)
- row = col.row(align=True)
- row.prop(brush, "curve_preset", text="")
-
- if brush.curve_preset == 'CUSTOM':
- layout.template_curve_mapping(brush, "curve")
-
- col = layout.column(align=True)
- row = col.row(align=True)
- row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
- row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
- row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
- row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
- row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
- row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
-
class IMAGE_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel):
bl_context = ".imagepaint_2d"
@@ -1470,90 +1214,64 @@ class IMAGE_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel):
row.prop(ipaint, "tile_y", text="Y", toggle=True)
-class IMAGE_PT_uv_sculpt_brush(Panel):
- bl_space_type = 'IMAGE_EDITOR'
- bl_region_type = 'UI'
- bl_context = ".uv_sculpt" # dot on purpose (access from topbar)
- bl_category = "Tool"
- bl_label = "Brush"
-
+class UVSculptPanel(UnifiedPaintPanel):
@classmethod
def poll(cls, context):
- sima = context.space_data
- # TODO(campbell): nicer way to check if we're in uv sculpt mode.
- if sima and sima.show_uvedit:
- from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
- tool = ToolSelectPanelHelper.tool_active_from_context(context)
- if tool.has_datablock:
- return True
- return False
+ return cls.get_brush_mode(context) == 'UV_SCULPT'
+
+
+class IMAGE_PT_uv_sculpt_brush_select(Panel, BrushSelectPanel, ImagePaintPanel, UVSculptPanel):
+ bl_context = ".uv_sculpt"
+ bl_category = "Tool"
+ bl_label = "Brushes"
+
+
+class IMAGE_PT_uv_sculpt_brush_settings(Panel, ImagePaintPanel, UVSculptPanel):
+ bl_context = ".uv_sculpt"
+ bl_category = "Tool"
+ bl_label = "Brush Settings"
def draw(self, context):
- from bl_ui.properties_paint_common import UnifiedPaintPanel
layout = self.layout
tool_settings = context.tool_settings
uvsculpt = tool_settings.uv_sculpt
- layout.template_ID(uvsculpt, "brush")
-
brush = uvsculpt.brush
- if not self.is_popover:
- if brush:
- col = layout.column()
-
- row = col.row(align=True)
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
- UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
-
- row = col.row(align=True)
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength", slider=True)
- UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
-
- col = layout.column()
- col.prop(tool_settings, "uv_sculpt_lock_borders")
- col.prop(tool_settings, "uv_sculpt_all_islands")
+ brush_settings(layout.column(), context, brush)
if brush:
if brush.uv_sculpt_tool == 'RELAX':
- col.prop(tool_settings, "uv_relax_method")
-
- col.prop(uvsculpt, "show_brush")
+ # Although this settings is stored in the scene,
+ # it is only used by a single tool,
+ # so it doesn't make sense from a user perspective to move it to the Options panel.
+ layout.prop(tool_settings, "uv_relax_method")
-class IMAGE_PT_uv_sculpt_curve(Panel):
- bl_space_type = 'IMAGE_EDITOR'
- bl_region_type = 'UI'
+class IMAGE_PT_uv_sculpt_curve(Panel, FalloffPanel, ImagePaintPanel, UVSculptPanel):
bl_context = ".uv_sculpt" # dot on purpose (access from topbar)
+ bl_parent_id = "IMAGE_PT_uv_sculpt_brush_settings"
bl_category = "Tool"
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
- poll = IMAGE_PT_uv_sculpt_brush.poll
+
+class IMAGE_PT_uv_sculpt_options(Panel, ImagePaintPanel, UVSculptPanel):
+ bl_context = ".uv_sculpt" # dot on purpose (access from topbar)
+ bl_category = "Tool"
+ bl_label = "Options"
def draw(self, context):
layout = self.layout
tool_settings = context.tool_settings
uvsculpt = tool_settings.uv_sculpt
- brush = uvsculpt.brush
-
- if brush is not None:
- col = layout.column(align=True)
- row = col.row(align=True)
- row.prop(brush, "curve_preset", text="")
- if brush.curve_preset == 'CUSTOM':
- layout.template_curve_mapping(brush, "curve")
-
- row = layout.row(align=True)
- row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
- row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
- row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
- row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
- row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
- row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
+ col = layout.column()
+ col.prop(tool_settings, "uv_sculpt_lock_borders")
+ col.prop(tool_settings, "uv_sculpt_all_islands")
+ col.prop(uvsculpt, "show_brush", text="Display Cursor")
class ImageScopesPanel:
@@ -1690,6 +1408,28 @@ class IMAGE_PT_uv_cursor(Panel):
col.prop(sima, "cursor_location", text="Cursor Location")
+class IMAGE_PT_udim_grid(Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "View"
+ bl_label = "UDIM Grid"
+
+ @classmethod
+ def poll(cls, context):
+ sima = context.space_data
+
+ return sima.show_uvedit and sima.image is None
+
+ def draw(self, context):
+ layout = self.layout
+
+ sima = context.space_data
+ uvedit = sima.uv_editor
+
+ col = layout.column()
+ col.prop(uvedit, "tile_grid_shape", text="Grid Shape")
+
+
# Grease Pencil properties
class IMAGE_PT_annotation(AnnotationDataPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
@@ -1705,7 +1445,6 @@ classes = (
IMAGE_MT_view,
IMAGE_MT_view_zoom,
IMAGE_MT_select,
- IMAGE_MT_brush,
IMAGE_MT_image,
IMAGE_MT_image_invert,
IMAGE_MT_uvs,
@@ -1732,24 +1471,27 @@ classes = (
IMAGE_PT_image_properties,
IMAGE_UL_render_slots,
IMAGE_PT_render_slots,
+ IMAGE_UL_udim_tiles,
+ IMAGE_PT_udim_tiles,
IMAGE_PT_view_display,
IMAGE_PT_view_display_uv_edit_overlays,
IMAGE_PT_view_display_uv_edit_overlays_stretch,
- IMAGE_PT_paint,
+ IMAGE_PT_paint_select,
+ IMAGE_PT_paint_settings,
IMAGE_PT_paint_color,
IMAGE_PT_paint_swatches,
+ IMAGE_PT_paint_settings_advanced,
IMAGE_PT_paint_clone,
- IMAGE_PT_paint_options,
IMAGE_PT_tools_brush_texture,
IMAGE_PT_tools_mask_texture,
IMAGE_PT_paint_stroke,
IMAGE_PT_paint_stroke_smooth_stroke,
IMAGE_PT_paint_curve,
IMAGE_PT_tools_brush_display,
- IMAGE_PT_tools_brush_display_show_brush,
- IMAGE_PT_tools_brush_display_custom_icon,
IMAGE_PT_tools_imagepaint_symmetry,
- IMAGE_PT_uv_sculpt_brush,
+ IMAGE_PT_uv_sculpt_brush_select,
+ IMAGE_PT_uv_sculpt_brush_settings,
+ IMAGE_PT_uv_sculpt_options,
IMAGE_PT_uv_sculpt_curve,
IMAGE_PT_view_histogram,
IMAGE_PT_view_waveform,
@@ -1758,6 +1500,7 @@ classes = (
IMAGE_PT_scope_sample,
IMAGE_PT_uv_cursor,
IMAGE_PT_annotation,
+ IMAGE_PT_udim_grid,
)
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index 825e4b41609..28b67c93666 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -70,11 +70,13 @@ class NLA_MT_editor_menus(Menu):
bl_idname = "NLA_MT_editor_menus"
bl_label = ""
- def draw(self, _context):
+ def draw(self, context):
+ st = context.space_data
layout = self.layout
layout.menu("NLA_MT_view")
layout.menu("NLA_MT_select")
- layout.menu("NLA_MT_marker")
+ if st.show_markers:
+ layout.menu("NLA_MT_marker")
layout.menu("NLA_MT_edit")
layout.menu("NLA_MT_add")
@@ -96,8 +98,10 @@ class NLA_MT_view(Menu):
layout.prop(st, "show_locked_time")
layout.prop(st, "show_strip_curves")
+
+ layout.separator()
+ layout.prop(st, "show_markers")
layout.prop(st, "show_local_markers")
- layout.prop(st, "show_marker_lines")
layout.separator()
layout.operator("anim.previewrange_set")
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index 7bf203d8e39..11fb20d8b38 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -48,7 +48,7 @@ class OUTLINER_HT_header(Header):
if display_mode == 'SEQUENCE':
row = layout.row(align=True)
- row.prop(space, "use_sync_select", icon="UV_SYNC_SELECT", text="")
+ row.prop(space, "use_sync_select", icon='UV_SYNC_SELECT', text="")
row = layout.row(align=True)
if display_mode in {'SCENES', 'VIEW_LAYER'}:
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 4d9a4646f5f..097564444d0 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -134,7 +134,8 @@ class SEQUENCER_MT_editor_menus(Menu):
if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
layout.menu("SEQUENCER_MT_select")
- layout.menu("SEQUENCER_MT_marker")
+ if st.show_markers:
+ layout.menu("SEQUENCER_MT_marker")
layout.menu("SEQUENCER_MT_add")
layout.menu("SEQUENCER_MT_strip")
@@ -268,7 +269,8 @@ class SEQUENCER_MT_view(Menu):
layout.prop(st, "show_seconds")
layout.prop(st, "show_strip_offset")
- layout.prop(st, "show_marker_lines")
+ layout.separator()
+ layout.prop(st, "show_markers")
if is_preview:
layout.separator()
@@ -508,7 +510,7 @@ class SEQUENCER_MT_add(Menu):
col.enabled = selected_sequences_len(context) >= 2
col = layout.column()
- col.operator_menu_enum("sequencer.fades_add", "type", text="Fade", icon="IPO_EASE_IN_OUT")
+ col.operator_menu_enum("sequencer.fades_add", "type", text="Fade", icon='IPO_EASE_IN_OUT')
col.enabled = selected_sequences_len(context) >= 1
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 04a904edde3..629958a783e 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -87,9 +87,10 @@ class TIME_MT_editor_menus(Menu):
bl_idname = "TIME_MT_editor_menus"
bl_label = ""
- def draw(self, _context):
+ def draw(self, context):
layout = self.layout
horizontal = (layout.direction == 'VERTICAL')
+ st = context.space_data
if horizontal:
row = layout.row()
sub = row.row(align=True)
@@ -109,7 +110,8 @@ class TIME_MT_editor_menus(Menu):
sub = row.row(align=True)
sub.menu("TIME_MT_view")
- sub.menu("TIME_MT_marker")
+ if st.show_markers:
+ sub.menu("TIME_MT_marker")
class TIME_MT_marker(Menu):
@@ -135,7 +137,10 @@ class TIME_MT_view(Menu):
layout.separator()
- layout.prop(st, "show_marker_lines")
+ layout.prop(st, "show_markers")
+
+ layout.separator()
+
layout.prop(scene, "show_keys_from_selected_only")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
index 7c7825403a9..05785b85dfc 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_common.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -162,7 +162,7 @@ class ToolActivePanelHelper:
layout.use_property_decorate = False
ToolSelectPanelHelper.draw_active_tool_header(
context,
- layout,
+ layout.column(),
show_tool_name=True,
tool_key=ToolSelectPanelHelper._tool_key_from_context(context, space_type=self.bl_space_type),
)
@@ -218,124 +218,155 @@ class ToolSelectPanelHelper:
@staticmethod
def _tools_flatten(tools):
- """
- Flattens, skips None and calls generators.
- """
for item in tools:
- if item is None:
- yield None
- elif type(item) is tuple:
- for sub_item in item:
- if sub_item is None:
- yield None
- elif _item_is_fn(sub_item):
- yield from sub_item(context)
- else:
- yield sub_item
+ if type(item) is tuple:
+ yield from item
else:
- if _item_is_fn(item):
- yield from item(context)
- else:
- yield item
+ # May be None.
+ yield item
@staticmethod
def _tools_flatten_with_tool_index(tools):
for item in tools:
- if item is None:
- yield None, -1
- elif type(item) is tuple:
+ if type(item) is tuple:
i = 0
for sub_item in item:
if sub_item is None:
yield None, -1
- elif _item_is_fn(sub_item):
- for item_dyn in sub_item(context):
- yield item_dyn, i
- i += 1
else:
yield sub_item, i
i += 1
else:
- if _item_is_fn(item):
- for item_dyn in item(context):
- yield item_dyn, -1
- else:
- yield item, -1
+ # May be None.
+ yield item, -1
- @staticmethod
- def _tool_get_active(context, space_type, mode, with_icon=False):
+ @classmethod
+ def _tool_get_active(cls, context, space_type, mode, with_icon=False):
"""
Return the active Python tool definition and icon name.
"""
- cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
- if cls is not None:
- tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type, mode)
- tool_active_id = getattr(tool_active, "idname", None)
- for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context, mode)):
- if item is not None:
- if item.idname == tool_active_id:
- if with_icon:
- icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon)
- else:
- icon_value = 0
- return (item, tool_active, icon_value)
+ tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type, mode)
+ tool_active_id = getattr(tool_active, "idname", None)
+ for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context, mode)):
+ if item is not None:
+ if item.idname == tool_active_id:
+ if with_icon:
+ icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon)
+ else:
+ icon_value = 0
+ return (item, tool_active, icon_value)
return None, None, 0
- @staticmethod
- def _tool_get_by_id(context, space_type, idname):
+ @classmethod
+ def _tool_get_by_id(cls, context, idname):
"""
Return the active Python tool definition and index (if in sub-group, else -1).
"""
- cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
- if cls is not None:
- for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)):
- if item is not None:
+ for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)):
+ if item is not None:
+ if item.idname == idname:
+ return (item, index)
+ return None, -1
+
+ @classmethod
+ def _tool_get_by_id_active(cls, context, idname):
+ """
+ Return the active Python tool definition and index (if in sub-group, else -1).
+ """
+ for item in cls.tools_from_context(context):
+ if item is not None:
+ if type(item) is tuple:
+ if item[0].idname == idname:
+ index = cls._tool_group_active.get(item[0].idname, 0)
+ return (item[index], index)
+ else:
if item.idname == idname:
- return (cls, item, index)
- return None, None, -1
+ return (item, -1)
+ return None, -1
- @staticmethod
- def _tool_get_by_flat_index(context, space_type, tool_index):
+ @classmethod
+ def _tool_get_by_id_active_with_group(cls, context, idname):
+ """
+ Return the active Python tool definition and index (if in sub-group, else -1).
+ """
+ for item in cls.tools_from_context(context):
+ if item is not None:
+ if type(item) is tuple:
+ if item[0].idname == idname:
+ index = cls._tool_group_active.get(item[0].idname, 0)
+ return (item[index], index, item)
+ else:
+ if item.idname == idname:
+ return (item, -1, None)
+ return None, -1, None
+
+ @classmethod
+ def _tool_get_group_by_id(cls, context, idname, *, coerce=False):
+ """
+ Return the group which contains idname, or None.
+ """
+ for item in cls.tools_from_context(context):
+ if item is not None:
+ if type(item) is tuple:
+ for subitem in item:
+ if subitem.idname == idname:
+ return item
+ else:
+ if item.idname == idname:
+ if coerce:
+ return (item,)
+ else:
+ return None
+ return None
+
+ @classmethod
+ def _tool_get_by_flat_index(cls, context, tool_index):
"""
Return the active Python tool definition and index (if in sub-group, else -1).
Return the index of the expanded list.
"""
- cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
- if cls is not None:
- i = 0
- for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)):
- if item is not None:
- if i == tool_index:
- return (cls, item, index)
- i += 1
- return None, None, -1
+ i = 0
+ for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)):
+ if item is not None:
+ if i == tool_index:
+ return (item, index)
+ i += 1
+ return None, -1
- @staticmethod
- def _tool_get_by_index(context, space_type, tool_index):
+ @classmethod
+ def _tool_get_active_by_index(cls, context, tool_index):
"""
Return the active Python tool definition and index (if in sub-group, else -1).
Return the index of the list without expanding.
"""
- cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
- if cls is not None:
- i = 0
- for item in cls.tools_from_context(context):
- if item is not None:
- if i == tool_index:
- if type(item) is tuple:
- index = cls._tool_group_active.get(item[0].idname, 0)
- item = item[index]
- else:
- index = -1
- return (cls, item, index)
- i += 1
- return None, None, -1
+ i = 0
+ for item in cls.tools_from_context(context):
+ if item is not None:
+ if i == tool_index:
+ if type(item) is tuple:
+ index = cls._tool_group_active.get(item[0].idname, 0)
+ item = item[index]
+ else:
+ index = -1
+ return (item, index)
+ i += 1
+ return None, -1
+
+ @classmethod
+ def _tool_group_active_set_by_id(cls, context, idname_group, idname):
+ item_group = cls._tool_get_group_by_id(context, idname_group, coerce=True)
+ if item_group:
+ for i, item in enumerate(item_group):
+ if item and item.idname == idname:
+ cls._tool_group_active[item_group[0].idname] = i
+ return True
+ return False
@staticmethod
def _tool_active_from_context(context, space_type, mode=None, create=False):
- if space_type == 'VIEW_3D':
+ if space_type in {'VIEW_3D', 'PROPERTIES'}:
if mode is None:
mode = context.mode
tool = context.workspace.tools.from_space_view3d_mode(mode, create=create)
@@ -634,6 +665,23 @@ class ToolSelectPanelHelper:
return ToolSelectPanelHelper._tool_active_from_context(context, space_type)
@staticmethod
+ def draw_active_tool_fallback(
+ context, layout, tool,
+ *,
+ is_horizontal_layout=False,
+ ):
+ idname_fallback = tool.idname_fallback
+ space_type = tool.space_type
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ item_fallback, _index = cls._tool_get_by_id(context, idname_fallback)
+ if item_fallback is not None:
+ draw_settings = item_fallback.draw_settings
+ if draw_settings is not None:
+ if not is_horizontal_layout:
+ layout.separator()
+ draw_settings(context, layout, tool)
+
+ @staticmethod
def draw_active_tool_header(
context, layout,
*,
@@ -647,7 +695,9 @@ class ToolSelectPanelHelper:
if space_type is None:
return None
- item, tool, icon_value = ToolSelectPanelHelper._tool_get_active(context, space_type, mode, with_icon=True)
+
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ item, tool, icon_value = cls._tool_get_active(context, space_type, mode, with_icon=True)
if item is None:
return None
# Note: we could show 'item.text' here but it makes the layout jitter when switching tools.
@@ -658,8 +708,123 @@ class ToolSelectPanelHelper:
draw_settings = item.draw_settings
if draw_settings is not None:
draw_settings(context, layout, tool)
+
+ idname_fallback = tool.idname_fallback
+ if idname_fallback and idname_fallback != item.idname:
+ tool_settings = context.tool_settings
+
+ # Show popover which looks like an enum but isn't one.
+ if tool_settings.workspace_tool_type == 'FALLBACK':
+ tool_fallback_id = cls.tool_fallback_id
+ item, _select_index = cls._tool_get_by_id_active(context, tool_fallback_id)
+ label = item.label
+ else:
+ label = "Active Tool"
+
+ split = layout.split(factor=0.33)
+ row = split.row()
+ row.alignment = 'RIGHT'
+ row.label(text="Drag:")
+ row = split.row()
+ row.context_pointer_set("tool", tool)
+ row.popover(panel="TOPBAR_PT_tool_fallback", text=label)
+
return tool
+ # Show a list of tools in the popover.
+ @staticmethod
+ def draw_fallback_tool_items(layout, context):
+ space_type = context.space_data.type
+ if space_type == 'PROPERTIES':
+ space_type = 'VIEW_3D'
+
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ tool_fallback_id = cls.tool_fallback_id
+
+ _item, _select_index, item_group = cls._tool_get_by_id_active_with_group(context, tool_fallback_id)
+
+ if item_group is None:
+ # Could print comprehensive message - listing available items.
+ raise Exception("Fallback tool doesn't exist")
+
+ col = layout.column(align=True)
+ tool_settings = context.tool_settings
+ col.prop_enum(
+ tool_settings,
+ "workspace_tool_type",
+ value='DEFAULT',
+ text="Active Tool",
+ )
+ is_active_tool = (tool_settings.workspace_tool_type == 'DEFAULT')
+
+ col = layout.column(align=True)
+ if is_active_tool:
+ index_current = -1
+ else:
+ index_current = cls._tool_group_active.get(item_group[0].idname, 0)
+ for i, sub_item in enumerate(item_group):
+ is_active = (i == index_current)
+
+ props = col.operator(
+ "wm.tool_set_by_id",
+ text=sub_item.label,
+ depress=is_active,
+ )
+ props.name = sub_item.idname
+ props.as_fallback = True
+ props.space_type = space_type
+
+ @staticmethod
+ def draw_fallback_tool_items_for_pie_menu(layout, context):
+ space_type = context.space_data.type
+ if space_type == 'PROPERTIES':
+ space_type = 'VIEW_3D'
+
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ tool_fallback_id = cls.tool_fallback_id
+
+ _item, _select_index, item_group = cls._tool_get_by_id_active_with_group(context, tool_fallback_id)
+
+ if item_group is None:
+ # Could print comprehensive message - listing available items.
+ raise Exception("Fallback tool doesn't exist")
+
+ # Allow changing the active tool,
+ # even though this isn't the purpose of the pie menu
+ # it's confusing from a user perspective if we don't allow it.
+ is_fallback_group_active = getattr(
+ ToolSelectPanelHelper._tool_active_from_context(context, space_type),
+ "idname", None,
+ ) in (item.idname for item in item_group)
+
+ pie = layout.menu_pie()
+ tool_settings = context.tool_settings
+ pie.prop_enum(
+ tool_settings,
+ "workspace_tool_type",
+ value='DEFAULT',
+ text="Active Tool",
+ icon='TOOL_SETTINGS', # Could use a less generic icon.
+ )
+ is_active_tool = (tool_settings.workspace_tool_type == 'DEFAULT')
+
+ if is_active_tool:
+ index_current = -1
+ else:
+ index_current = cls._tool_group_active.get(item_group[0].idname, 0)
+ for i, sub_item in enumerate(item_group):
+ is_active = (i == index_current)
+ props = pie.operator(
+ "wm.tool_set_by_id",
+ text=sub_item.label,
+ depress=is_active,
+ icon_value=ToolSelectPanelHelper._icon_value_from_icon_handle(sub_item.icon),
+ )
+ props.name = sub_item.idname
+ props.space_type = space_type
+ if not is_fallback_group_active:
+ props.as_fallback = True
+
# The purpose of this menu is to be a generic popup to select between tools
# in cases when a single tool allows to select alternative tools.
@@ -701,8 +866,50 @@ class WM_MT_toolsystem_submenu(Menu):
).name = item.idname
-def _activate_by_item(context, space_type, item, index):
+def _activate_by_item(context, space_type, item, index, *, as_fallback=False):
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
tool = ToolSelectPanelHelper._tool_active_from_context(context, space_type, create=True)
+ tool_fallback_id = cls.tool_fallback_id
+
+ if as_fallback:
+ # To avoid complicating logic too much, isolate all fallback logic to this block.
+ # This will set the tool again, using the item for the fallback instead of the primary tool.
+ #
+ # If this ends up needing to be more complicated,
+ # it would be better to split it into a separate function.
+
+ _item, _select_index, item_group = cls._tool_get_by_id_active_with_group(context, tool_fallback_id)
+
+ if item_group is None:
+ # Could print comprehensive message - listing available items.
+ raise Exception("Fallback tool doesn't exist")
+ index_new = -1
+ for i, sub_item in enumerate(item_group):
+ if sub_item.idname == item.idname:
+ index_new = i
+ break
+ if index_new == -1:
+ raise Exception("Fallback tool not found in group")
+
+ cls._tool_group_active[tool_fallback_id] = index_new
+
+ # Done, now get the current tool to replace the item & index.
+ tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type)
+ item, index = cls._tool_get_by_id(context, getattr(tool_active, "idname", None))
+ else:
+ # Ensure the active fallback tool is read from saved state (even if the fallback tool is not in use).
+ stored_idname_fallback = tool.idname_fallback
+ if stored_idname_fallback:
+ cls._tool_group_active_set_by_id(context, tool_fallback_id, stored_idname_fallback)
+ del stored_idname_fallback
+
+ # Find fallback keymap.
+ item_fallback = None
+ _item, select_index = cls._tool_get_by_id(context, tool_fallback_id)
+ if select_index != -1:
+ item_fallback, _index = cls._tool_get_active_by_index(context, select_index)
+ # End calculating fallback.
+
tool.setup(
idname=item.idname,
keymap=item.keymap[0] if item.keymap is not None else "",
@@ -711,6 +918,8 @@ def _activate_by_item(context, space_type, item, index):
data_block=item.data_block or "",
operator=item.operator or "",
index=index,
+ idname_fallback=(item_fallback and item_fallback.idname) or "",
+ keymap_fallback=(item_fallback and item_fallback.keymap and item_fallback.keymap[0]) or "",
)
WindowManager = bpy.types.WindowManager
@@ -729,18 +938,22 @@ def _activate_by_item(context, space_type, item, index):
_activate_by_item._cursor_draw_handle = {}
-def activate_by_id(context, space_type, text):
- _cls, item, index = ToolSelectPanelHelper._tool_get_by_id(context, space_type, text)
+def activate_by_id(context, space_type, idname, *, as_fallback=False):
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is None:
+ return False
+ item, index = cls._tool_get_by_id(context, idname)
if item is None:
return False
- _activate_by_item(context, space_type, item, index)
+ _activate_by_item(context, space_type, item, index, as_fallback=as_fallback)
return True
-def activate_by_id_or_cycle(context, space_type, idname, offset=1):
+def activate_by_id_or_cycle(context, space_type, idname, *, offset=1, as_fallback=False):
# Only cycle when the active tool is activated again.
- cls, item, _index = ToolSelectPanelHelper._tool_get_by_id(context, space_type, idname)
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ item, _index = cls._tool_get_by_id(context, idname)
if item is None:
return False
@@ -774,7 +987,8 @@ def activate_by_id_or_cycle(context, space_type, idname, offset=1):
def description_from_id(context, space_type, idname, *, use_operator=True):
# Used directly for tooltips.
- _cls, item, _index = ToolSelectPanelHelper._tool_get_by_id(context, space_type, idname)
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ item, _index = cls._tool_get_by_id(context, idname)
if item is None:
return False
@@ -806,23 +1020,59 @@ def description_from_id(context, space_type, idname, *, use_operator=True):
def item_from_id(context, space_type, idname):
# Used directly for tooltips.
- _cls, item, _index = ToolSelectPanelHelper._tool_get_by_id(context, space_type, idname)
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is None:
+ return None
+ item, _index = cls._tool_get_by_id(context, idname)
return item
+def item_from_id_active(context, space_type, idname):
+ # Used directly for tooltips.
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is None:
+ return None
+ item, _index = cls._tool_get_by_id_active(context, idname)
+ return item
+
+
+def item_from_id_active_with_group(context, space_type, idname):
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is None:
+ return None
+ cls, item, _index = cls._tool_get_by_id_active_with_group(context, idname)
+ return item
+
+
+def item_group_from_id(context, space_type, idname, *, coerce=False):
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is None:
+ return None
+ return cls._tool_get_group_by_id(context, idname, coerce=coerce)
+
+
def item_from_flat_index(context, space_type, index):
- _cls, item, _index = ToolSelectPanelHelper._tool_get_by_flat_index(context, space_type, index)
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is None:
+ return None
+ item, _index = cls._tool_get_by_flat_index(context, index)
return item
-def item_from_index(context, space_type, index):
- _cls, item, _index = ToolSelectPanelHelper._tool_get_by_index(context, space_type, index)
+def item_from_index_active(context, space_type, index):
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is None:
+ return None
+ item, _index = cls._tool_get_active_by_index(context, index)
return item
def keymap_from_id(context, space_type, idname):
# Used directly for tooltips.
- _cls, item, _index = ToolSelectPanelHelper._tool_get_by_id(context, space_type, idname)
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is None:
+ return None
+ item, _index = cls._tool_get_by_id(context, idname)
if item is None:
return False
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 9a5df62da46..e0f3a03733e 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -297,8 +297,14 @@ class _defs_transform:
if layout.use_property_split:
layout.label(text="Gizmos:")
- props = tool.gizmo_group_properties("VIEW3D_GGT_xform_gizmo")
- layout.prop(props, "drag_action")
+ show_drag = True
+ tool_settings = context.tool_settings
+ if tool_settings.workspace_tool_type == 'FALLBACK':
+ show_drag = False
+
+ if show_drag:
+ props = tool.gizmo_group_properties("VIEW3D_GGT_xform_gizmo")
+ layout.prop(props, "drag_action")
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 1)
@@ -319,15 +325,12 @@ class _defs_view3d_select:
@ToolDef.from_fn
def select():
- def draw_settings(_context, _layout, _tool):
- pass
return dict(
idname="builtin.select",
label="Tweak",
icon="ops.generic.select",
widget=None,
keymap="3D View Tool: Tweak",
- draw_settings=draw_settings,
)
@ToolDef.from_fn
@@ -400,7 +403,7 @@ class _defs_edit_armature:
idname="builtin.roll",
label="Roll",
icon="ops.armature.bone.roll",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -410,7 +413,7 @@ class _defs_edit_armature:
idname="builtin.bone_envelope",
label="Bone Envelope",
icon="ops.transform.bone_envelope",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -420,7 +423,7 @@ class _defs_edit_armature:
idname="builtin.bone_size",
label="Bone Size",
icon="ops.transform.bone_size",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -472,7 +475,7 @@ class _defs_edit_mesh:
idname="builtin.rip_region",
label="Rip Region",
icon="ops.mesh.rip",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
draw_settings=draw_settings,
)
@@ -483,7 +486,7 @@ class _defs_edit_mesh:
idname="builtin.rip_edge",
label="Rip Edge",
icon="ops.mesh.rip_edge",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -512,7 +515,7 @@ class _defs_edit_mesh:
idname="builtin.edge_slide",
label="Edge Slide",
icon="ops.transform.edge_slide",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
keymap=(),
draw_settings=draw_settings,
)
@@ -527,7 +530,7 @@ class _defs_edit_mesh:
idname="builtin.vertex_slide",
label="Vertex Slide",
icon="ops.transform.vert_slide",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
draw_settings=draw_settings,
)
@@ -579,25 +582,65 @@ class _defs_edit_mesh:
idname="builtin.inset_faces",
label="Inset Faces",
icon="ops.mesh.inset",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
keymap=(),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def bevel():
- def draw_settings(_context, layout, tool):
+ def draw_settings(context, layout, tool, *, extra=False):
props = tool.operator_properties("mesh.bevel")
- layout.prop(props, "offset_type")
- layout.prop(props, "segments")
- layout.prop(props, "profile", slider=True)
- layout.prop(props, "vertex_only")
+ region_type = context.region.type
+
+ if not extra:
+ if props.offset_type == 'PERCENT':
+ layout.prop(props, "offset_pct")
+ else:
+ offset_text = "Width"
+ if props.offset_type == 'DEPTH':
+ offset_text = "Depth"
+ elif props.offset_type == 'OFFSET':
+ offset_text = "Offset"
+ layout.prop(props, "offset", text=offset_text)
+ if region_type == 'TOOL_HEADER':
+ layout.prop(props, "offset_type", text="")
+ else:
+ layout.prop(props, "offset_type")
+
+ layout.prop(props, "segments")
+ layout.prop(props, "profile", slider=True)
+
+ if region_type == 'TOOL_HEADER':
+ layout.popover("TOPBAR_PT_tool_settings_extra", text="...")
+ else:
+ extra = True
+
+ if extra or region_type != 'TOOL_HEADER':
+ layout.prop(props, "vertex_only")
+ layout.prop(props, "clamp_overlap")
+ layout.prop(props, "loop_slide")
+ layout.prop(props, "mark_seam")
+ layout.prop(props, "mark_sharp")
+ layout.prop(props, "harden_normals")
+
+ layout.prop(props, "material")
+
+ layout.prop(props, "miter_outer", text="Outer Miter")
+ layout.prop(props, "miter_inner", text="Inner Miter")
+ if props.miter_inner == 'ARC':
+ layout.prop(props, "spread")
+
+ layout.prop(props, "use_custom_profile")
+ if props.use_custom_profile:
+ tool_settings = context.tool_settings
+ layout.template_curveprofile(tool_settings, "custom_bevel_profile_preset")
return dict(
idname="builtin.bevel",
label="Bevel",
icon="ops.mesh.bevel",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
keymap=(),
draw_settings=draw_settings,
)
@@ -629,7 +672,7 @@ class _defs_edit_mesh:
idname="builtin.extrude_along_normals",
label="Extrude Along Normals",
icon="ops.mesh.extrude_region_shrink_fatten",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
operator="mesh.extrude_region_shrink_fatten",
keymap=(),
draw_settings=draw_settings,
@@ -641,7 +684,7 @@ class _defs_edit_mesh:
idname="builtin.extrude_individual",
label="Extrude Individual",
icon="ops.mesh.extrude_faces_move",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
keymap=(),
)
@@ -698,7 +741,7 @@ class _defs_edit_mesh:
idname="builtin.smooth",
label="Smooth",
icon="ops.mesh.vertices_smooth",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
keymap=(),
draw_settings=draw_settings,
)
@@ -714,7 +757,7 @@ class _defs_edit_mesh:
idname="builtin.randomize",
label="Randomize",
icon="ops.transform.vertex_random",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
keymap=(),
draw_settings=draw_settings,
)
@@ -753,7 +796,7 @@ class _defs_edit_mesh:
idname="builtin.shrink_fatten",
label="Shrink/Fatten",
icon="ops.transform.shrink_fatten",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
keymap=(),
draw_settings=draw_settings,
)
@@ -764,7 +807,7 @@ class _defs_edit_mesh:
idname="builtin.push_pull",
label="Push/Pull",
icon="ops.transform.push_pull",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
keymap=(),
)
@@ -862,7 +905,7 @@ class _defs_edit_curve:
idname="builtin.tilt",
label="Tilt",
icon="ops.transform.tilt",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -875,7 +918,7 @@ class _defs_edit_curve:
"Expand or contract the radius of the selected curve points"
),
icon="ops.curve.radius",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -890,7 +933,7 @@ class _defs_edit_curve:
idname="builtin.randomize",
label="Randomize",
icon="ops.curve.vertex_random",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_normal",
keymap=(),
draw_settings=draw_settings,
)
@@ -1091,11 +1134,10 @@ class _defs_weight_paint:
def draw_settings(context, layout, tool):
brush = context.tool_settings.weight_paint.brush
if brush is not None:
- from bl_ui.properties_paint_common import UnifiedPaintPanel
- UnifiedPaintPanel.prop_unified_weight(layout, context, brush, "weight", slider=True)
- UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength", slider=True)
+ layout.prop(brush, "weight", slider=True)
+ layout.prop(brush, "strength", slider=True)
props = tool.operator_properties("paint.weight_gradient")
- layout.prop(props, "type")
+ layout.prop(props, "type", expand=True)
return dict(
idname="builtin.gradient",
@@ -1159,7 +1201,7 @@ class _defs_image_uv_transform:
idname="builtin.move",
label="Move",
icon="ops.transform.translate",
- # widget="VIEW3D_GGT_xform_gizmo",
+ widget="IMAGE_GGT_gizmo2d_translate",
operator="transform.translate",
keymap="Image Editor Tool: Uv, Move",
)
@@ -1170,7 +1212,7 @@ class _defs_image_uv_transform:
idname="builtin.rotate",
label="Rotate",
icon="ops.transform.rotate",
- # widget="VIEW3D_GGT_xform_gizmo",
+ widget="IMAGE_GGT_gizmo2d_rotate",
operator="transform.rotate",
keymap="Image Editor Tool: Uv, Rotate",
)
@@ -1181,7 +1223,7 @@ class _defs_image_uv_transform:
idname="builtin.scale",
label="Scale",
icon="ops.transform.resize",
- # widget="VIEW3D_GGT_xform_gizmo",
+ widget="IMAGE_GGT_gizmo2d_resize",
operator="transform.resize",
keymap="Image Editor Tool: Uv, Scale",
)
@@ -1204,15 +1246,12 @@ class _defs_image_uv_select:
@ToolDef.from_fn
def select():
- def draw_settings(_context, _layout, _tool):
- pass
return dict(
idname="builtin.select",
label="Tweak",
icon="ops.generic.select",
widget=None,
keymap=(),
- draw_settings=draw_settings,
)
@ToolDef.from_fn
@@ -1590,15 +1629,12 @@ class _defs_node_select:
@ToolDef.from_fn
def select():
- def draw_settings(_context, _layout, _tool):
- pass
return dict(
idname="builtin.select",
label="Tweak",
icon="ops.generic.select",
widget=None,
keymap="Node Tool: Tweak",
- draw_settings=draw_settings,
)
@ToolDef.from_fn
@@ -1608,7 +1644,6 @@ class _defs_node_select:
row = layout.row()
row.use_property_split = False
row.prop(props, "mode", text="", expand=True, icon_only=True)
- pass
return dict(
idname="builtin.select_box",
label="Select Box",
@@ -1682,6 +1717,9 @@ class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
# Satisfy the 'ToolSelectPanelHelper' API.
keymap_prefix = "Image Editor Tool:"
+ # Default group to use as a fallback.
+ tool_fallback_id = "builtin.select"
+
@classmethod
def tools_from_context(cls, context, mode=None):
if mode is None:
@@ -1766,6 +1804,9 @@ class NODE_PT_tools_active(ToolSelectPanelHelper, Panel):
# Satisfy the 'ToolSelectPanelHelper' API.
keymap_prefix = "Node Editor Tool:"
+ # Default group to use as a fallback.
+ tool_fallback_id = "builtin.select"
+
@classmethod
def tools_from_context(cls, context, mode=None):
if mode is None:
@@ -1822,6 +1863,9 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
# Satisfy the 'ToolSelectPanelHelper' API.
keymap_prefix = "3D View Tool:"
+ # Default group to use as a fallback.
+ tool_fallback_id = "builtin.select"
+
@classmethod
def tools_from_context(cls, context, mode=None):
if mode is None:
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index fef0e095099..fd46bd53cd2 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -68,7 +68,8 @@ class TOPBAR_HT_upper_bar(Header):
layout.template_running_jobs()
# Active workspace view-layer is retrieved through window, not through workspace.
- layout.template_ID(window, "scene", new="scene.new", unlink="scene.delete")
+ layout.template_ID(window, "scene", new="scene.new",
+ unlink="scene.delete")
row = layout.row(align=True)
row.template_search(
@@ -78,6 +79,50 @@ class TOPBAR_HT_upper_bar(Header):
unlink="scene.view_layer_remove")
+class TOPBAR_PT_tool_settings_extra(Panel):
+ """
+ Popover panel for adding extra options that don't fit in the tool settings header
+ """
+ bl_idname = "TOPBAR_PT_tool_settings_extra"
+ bl_region_type = 'HEADER'
+ bl_space_type = 'TOPBAR'
+ bl_label = "Extra Options"
+
+ def draw(self, context):
+ from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
+ layout = self.layout
+
+ # Get the active tool
+ space_type, mode = ToolSelectPanelHelper._tool_key_from_context(
+ context)
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ item, tool, _ = cls._tool_get_active(
+ context, space_type, mode, with_icon=True)
+ if item is None:
+ return
+
+ # Draw the extra settings
+ item.draw_settings(context, layout, tool, extra=True)
+
+
+class TOPBAR_PT_tool_fallback(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Layers"
+ bl_ui_units_x = 8
+
+ def draw(self, context):
+ from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
+ layout = self.layout
+
+ tool_settings = context.tool_settings
+ ToolSelectPanelHelper.draw_fallback_tool_items(layout, context)
+ if tool_settings.workspace_tool_type == 'FALLBACK':
+ tool = context.tool
+ ToolSelectPanelHelper.draw_active_tool_fallback(
+ context, layout, tool)
+
+
class TOPBAR_PT_gpencil_layers(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
@@ -134,20 +179,25 @@ class TOPBAR_PT_gpencil_layers(Panel):
gpl = context.active_gpencil_layer
if gpl:
- sub.menu("GPENCIL_MT_layer_context_menu", icon='DOWNARROW_HLT', text="")
+ sub.menu("GPENCIL_MT_layer_context_menu",
+ icon='DOWNARROW_HLT', text="")
if len(gpd.layers) > 1:
col.separator()
sub = col.column(align=True)
- sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
- sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+ sub.operator("gpencil.layer_move",
+ icon='TRIA_UP', text="").type = 'UP'
+ sub.operator("gpencil.layer_move",
+ icon='TRIA_DOWN', text="").type = 'DOWN'
col.separator()
sub = col.column(align=True)
- sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
- sub.operator("gpencil.layer_isolate", icon='HIDE_OFF', text="").affect_visibility = True
+ sub.operator("gpencil.layer_isolate", icon='HIDE_OFF',
+ text="").affect_visibility = True
+ sub.operator("gpencil.layer_isolate", icon='LOCKED',
+ text="").affect_visibility = False
class TOPBAR_MT_editor_menus(Menu):
@@ -189,7 +239,18 @@ class TOPBAR_MT_app(Menu):
layout.separator()
- layout.operator("preferences.app_template_install", text="Install Application Template...")
+ layout.operator("preferences.app_template_install",
+ text="Install Application Template...")
+
+
+class TOPBAR_MT_file_cleanup(Menu):
+ bl_label = "Clean Up"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.separator()
+
+ layout.operator("outliner.orphans_purge")
class TOPBAR_MT_file(Menu):
@@ -230,6 +291,7 @@ class TOPBAR_MT_file(Menu):
layout.separator()
layout.menu("TOPBAR_MT_file_external_data")
+ layout.menu("TOPBAR_MT_file_cleanup")
layout.separator()
@@ -285,7 +347,8 @@ class TOPBAR_MT_file_new(Menu):
# Draw application templates.
if not use_more:
- props = layout.operator("wm.read_homefile", text="General", icon=icon)
+ props = layout.operator(
+ "wm.read_homefile", text="General", icon=icon)
props.app_template = ""
for d in paths:
@@ -330,7 +393,8 @@ class TOPBAR_MT_file_defaults(Menu):
app_template = None
if app_template:
- layout.label(text=bpy.path.display_name(app_template, has_ext=False))
+ layout.label(text=bpy.path.display_name(
+ app_template, has_ext=False))
layout.operator("wm.save_homefile")
props = layout.operator("wm.read_factory_settings")
@@ -344,12 +408,15 @@ class TOPBAR_MT_app_about(Menu):
def draw(self, _context):
layout = self.layout
- layout.operator("wm.url_open_preset", text="Release Notes", icon='URL').type = 'RELEASE_NOTES'
+ layout.operator("wm.url_open_preset", text="Release Notes",
+ icon='URL').type = 'RELEASE_NOTES'
layout.separator()
- layout.operator("wm.url_open_preset", text="Blender Website", icon='URL').type = 'BLENDER'
- layout.operator("wm.url_open_preset", text="Credits", icon='URL').type = 'CREDITS'
+ layout.operator("wm.url_open_preset",
+ text="Blender Website", icon='URL').type = 'BLENDER'
+ layout.operator("wm.url_open_preset", text="Credits",
+ icon='URL').type = 'CREDITS'
layout.separator()
@@ -364,7 +431,8 @@ class TOPBAR_MT_app_support(Menu):
def draw(self, _context):
layout = self.layout
- layout.operator("wm.url_open_preset", text="Development Fund", icon='FUND').type = 'FUND'
+ layout.operator("wm.url_open_preset",
+ text="Development Fund", icon='FUND').type = 'FUND'
layout.separator()
@@ -377,7 +445,8 @@ class TOPBAR_MT_templates_more(Menu):
bl_label = "Templates"
def draw(self, context):
- bpy.types.TOPBAR_MT_file_new.draw_ex(self.layout, context, use_more=True)
+ bpy.types.TOPBAR_MT_file_new.draw_ex(
+ self.layout, context, use_more=True)
class TOPBAR_MT_file_import(Menu):
@@ -386,7 +455,8 @@ class TOPBAR_MT_file_import(Menu):
def draw(self, _context):
if bpy.app.build_options.collada:
- self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)")
+ self.layout.operator("wm.collada_import",
+ text="Collada (Default) (.dae)")
if bpy.app.build_options.alembic:
self.layout.operator("wm.alembic_import", text="Alembic (.abc)")
@@ -395,11 +465,15 @@ class TOPBAR_MT_file_export(Menu):
bl_idname = "TOPBAR_MT_file_export"
bl_label = "Export"
- def draw(self, _context):
+ def draw(self, context):
if bpy.app.build_options.collada:
- self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)")
+ self.layout.operator("wm.collada_export",
+ text="Collada (Default) (.dae)")
if bpy.app.build_options.alembic:
self.layout.operator("wm.alembic_export", text="Alembic (.abc)")
+ if bpy.app.build_options.usd:
+ self.layout.operator(
+ "wm.usd_export", text="Universal Scene Description (.usd, .usdc, .usda)")
class TOPBAR_MT_file_external_data(Menu):
@@ -452,8 +526,10 @@ class TOPBAR_MT_render(Menu):
rd = context.scene.render
- layout.operator("render.render", text="Render Image", icon='RENDER_STILL').use_viewport = True
- props = layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION')
+ layout.operator("render.render", text="Render Image",
+ icon='RENDER_STILL').use_viewport = True
+ props = layout.operator(
+ "render.render", text="Render Animation", icon='RENDER_ANIMATION')
props.animation = True
props.use_viewport = True
@@ -495,7 +571,8 @@ class TOPBAR_MT_edit(Menu):
layout.separator()
- layout.operator("wm.search_menu", text="Operator Search...", icon='VIEWZOOM')
+ layout.operator("wm.search_menu",
+ text="Operator Search...", icon='VIEWZOOM')
layout.separator()
@@ -514,7 +591,8 @@ class TOPBAR_MT_edit(Menu):
layout.separator()
- layout.operator("screen.userpref_show", text="Preferences...", icon='PREFERENCES')
+ layout.operator("screen.userpref_show",
+ text="Preferences...", icon='PREFERENCES')
class TOPBAR_MT_window(Menu):
@@ -534,8 +612,10 @@ class TOPBAR_MT_window(Menu):
layout.separator()
- layout.operator("screen.workspace_cycle", text="Next Workspace").direction = 'NEXT'
- layout.operator("screen.workspace_cycle", text="Previous Workspace").direction = 'PREV'
+ layout.operator("screen.workspace_cycle",
+ text="Next Workspace").direction = 'NEXT'
+ layout.operator("screen.workspace_cycle",
+ text="Previous Workspace").direction = 'PREV'
layout.separator()
@@ -562,7 +642,8 @@ class TOPBAR_MT_help(Menu):
show_developer = context.preferences.view.show_developer_ui
- layout.operator("wm.url_open_preset", text="Manual", icon='HELP').type = 'MANUAL'
+ layout.operator("wm.url_open_preset", text="Manual",
+ icon='HELP').type = 'MANUAL'
layout.operator(
"wm.url_open", text="Tutorials", icon='URL',
@@ -595,7 +676,8 @@ class TOPBAR_MT_help(Menu):
layout.separator()
- layout.operator("wm.url_open_preset", text="Report a Bug", icon='URL').type = 'BUG'
+ layout.operator("wm.url_open_preset",
+ text="Report a Bug", icon='URL').type = 'BUG'
layout.separator()
@@ -624,7 +706,8 @@ class TOPBAR_MT_file_context_menu(Menu):
layout.separator()
- layout.operator("screen.userpref_show", text="Preferences...", icon='PREFERENCES')
+ layout.operator("screen.userpref_show",
+ text="Preferences...", icon='PREFERENCES')
class TOPBAR_MT_workspace_menu(Menu):
@@ -633,21 +716,26 @@ class TOPBAR_MT_workspace_menu(Menu):
def draw(self, _context):
layout = self.layout
- layout.operator("workspace.duplicate", text="Duplicate", icon='DUPLICATE')
+ layout.operator("workspace.duplicate",
+ text="Duplicate", icon='DUPLICATE')
if len(bpy.data.workspaces) > 1:
layout.operator("workspace.delete", text="Delete", icon='REMOVE')
layout.separator()
- layout.operator("workspace.reorder_to_front", text="Reorder to Front", icon='TRIA_LEFT_BAR')
- layout.operator("workspace.reorder_to_back", text="Reorder to Back", icon='TRIA_RIGHT_BAR')
+ layout.operator("workspace.reorder_to_front",
+ text="Reorder to Front", icon='TRIA_LEFT_BAR')
+ layout.operator("workspace.reorder_to_back",
+ text="Reorder to Back", icon='TRIA_RIGHT_BAR')
layout.separator()
# For key binding discoverability.
- props = layout.operator("screen.workspace_cycle", text="Previous Workspace")
+ props = layout.operator("screen.workspace_cycle",
+ text="Previous Workspace")
props.direction = 'PREV'
- props = layout.operator("screen.workspace_cycle", text="Next Workspace")
+ props = layout.operator(
+ "screen.workspace_cycle", text="Next Workspace")
props.direction = 'NEXT'
@@ -662,29 +750,8 @@ class TOPBAR_PT_gpencil_primitive(Panel):
layout = self.layout
# Curve
- layout.template_curve_mapping(settings, "thickness_primitive_curve", brush=True)
-
-
-# Grease Pencil Fill
-class TOPBAR_PT_gpencil_fill(Panel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'HEADER'
- bl_label = "Advanced"
-
- def draw(self, context):
- paint = context.tool_settings.gpencil_paint
- brush = paint.brush
- gp_settings = brush.gpencil_settings
-
- layout = self.layout
- # Fill
- row = layout.row(align=True)
- row.prop(gp_settings, "fill_factor", text="Resolution")
- if gp_settings.fill_draw_mode != 'STROKE':
- row = layout.row(align=True)
- row.prop(gp_settings, "show_fill", text="Ignore Transparent Strokes")
- row = layout.row(align=True)
- row.prop(gp_settings, "fill_threshold", text="Threshold")
+ layout.template_curve_mapping(
+ settings, "thickness_primitive_curve", brush=True)
# Only a popover
@@ -767,14 +834,16 @@ classes = (
TOPBAR_MT_file_import,
TOPBAR_MT_file_export,
TOPBAR_MT_file_external_data,
+ TOPBAR_MT_file_cleanup,
TOPBAR_MT_file_previews,
TOPBAR_MT_edit,
TOPBAR_MT_render,
TOPBAR_MT_window,
TOPBAR_MT_help,
+ TOPBAR_PT_tool_fallback,
+ TOPBAR_PT_tool_settings_extra,
TOPBAR_PT_gpencil_layers,
TOPBAR_PT_gpencil_primitive,
- TOPBAR_PT_gpencil_fill,
TOPBAR_PT_name,
)
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 7c6a7ecbcee..4f35bcc29df 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -27,6 +27,9 @@ from bpy.app.translations import pgettext_iface as iface_
from bpy.app.translations import contexts as i18n_contexts
+# -----------------------------------------------------------------------------
+# Main Header
+
class USERPREF_HT_header(Header):
bl_space_type = 'PREFERENCES'
@@ -60,6 +63,9 @@ class USERPREF_HT_header(Header):
self.draw_buttons(layout, context)
+# -----------------------------------------------------------------------------
+# Main Navigation Bar
+
class USERPREF_PT_navigation_bar(Panel):
bl_label = "Preferences Navigation"
bl_space_type = 'PREFERENCES'
@@ -128,47 +134,53 @@ class USERPREF_PT_save_preferences(Panel):
USERPREF_HT_header.draw_buttons(layout, context)
+# -----------------------------------------------------------------------------
+# Min-In Helpers
+
# Panel mix-in.
-class PreferencePanel:
+class CenterAlignMixIn:
"""
Base class for panels to center align contents with some horizontal margin.
- Deriving classes need to implement a ``draw_props(context, layout)`` function.
+ Deriving classes need to implement a ``draw_centered(context, layout)`` function.
"""
- bl_space_type = 'PREFERENCES'
- bl_region_type = 'WINDOW'
-
def draw(self, context):
layout = self.layout
width = context.region.width
ui_scale = context.preferences.system.ui_scale
+ # No horizontal margin if region is rather small.
+ is_wide = width > (350 * ui_scale)
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
row = layout.row()
- if width > (350 * ui_scale): # No horizontal margin if region is rather small.
+ if is_wide:
row.label() # Needed so col below is centered.
col = row.column()
col.ui_units_x = 50
- # draw_props implemented by deriving classes.
- self.draw_props(context, col)
+ # Implemented by sub-classes.
+ self.draw_centered(context, col)
- if width > (350 * ui_scale): # No horizontal margin if region is rather small.
+ if is_wide:
row.label() # Needed so col above is centered.
-class USERPREF_PT_interface_display(PreferencePanel, Panel):
- bl_label = "Display"
+# -----------------------------------------------------------------------------
+# Interface Panels
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'INTERFACE')
+class InterfacePanel:
+ bl_space_type = 'PREFERENCES'
+ bl_region_type = 'WINDOW'
+ bl_context = "interface"
+
+
+class USERPREF_PT_interface_display(InterfacePanel, CenterAlignMixIn, Panel):
+ bl_label = "Display"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
view = prefs.view
@@ -188,16 +200,11 @@ class USERPREF_PT_interface_display(PreferencePanel, Panel):
flow.prop(view, "show_large_cursors")
-class USERPREF_PT_interface_text(PreferencePanel, Panel):
+class USERPREF_PT_interface_text(InterfacePanel, CenterAlignMixIn, Panel):
bl_label = "Text Rendering"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'INTERFACE')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
view = prefs.view
@@ -212,14 +219,13 @@ class USERPREF_PT_interface_text(PreferencePanel, Panel):
flow.prop(view, "font_path_ui_mono")
-class USERPREF_PT_interface_translation(PreferencePanel, Panel):
+class USERPREF_PT_interface_translation(InterfacePanel, CenterAlignMixIn, Panel):
bl_label = "Translation"
bl_translation_context = i18n_contexts.id_windowmanager
@classmethod
def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'INTERFACE') and bpy.app.build_options.international
+ return bpy.app.build_options.international
def draw_header(self, context):
prefs = context.preferences
@@ -227,7 +233,7 @@ class USERPREF_PT_interface_translation(PreferencePanel, Panel):
self.layout.prop(view, "use_international_fonts", text="")
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
view = prefs.view
@@ -242,15 +248,10 @@ class USERPREF_PT_interface_translation(PreferencePanel, Panel):
flow.prop(view, "use_translate_new_dataname", text="New Data")
-class USERPREF_PT_interface_editors(PreferencePanel, Panel):
+class USERPREF_PT_interface_editors(InterfacePanel, CenterAlignMixIn, Panel):
bl_label = "Editors"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'INTERFACE')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
view = prefs.view
system = prefs.system
@@ -265,17 +266,12 @@ class USERPREF_PT_interface_editors(PreferencePanel, Panel):
flow.prop(view, "factor_display_type")
-class USERPREF_PT_interface_temporary_windows(PreferencePanel, Panel):
+class USERPREF_PT_interface_temporary_windows(InterfacePanel, CenterAlignMixIn, Panel):
bl_label = "Temporary Windows"
bl_parent_id = "USERPREF_PT_interface_editors"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'INTERFACE')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
view = prefs.view
@@ -285,22 +281,15 @@ class USERPREF_PT_interface_temporary_windows(PreferencePanel, Panel):
flow.prop(view, "filebrowser_display_type", text="File Browser")
-class USERPREF_PT_interface_menus(Panel):
- bl_space_type = 'PREFERENCES'
- bl_region_type = 'WINDOW'
+class USERPREF_PT_interface_menus(InterfacePanel, Panel):
bl_label = "Menus"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'INTERFACE')
-
def draw(self, context):
pass
-class USERPREF_PT_interface_menus_mouse_over(PreferencePanel, Panel):
+class USERPREF_PT_interface_menus_mouse_over(InterfacePanel, CenterAlignMixIn, Panel):
bl_label = "Open on Mouse Over"
bl_parent_id = "USERPREF_PT_interface_menus"
@@ -310,7 +299,7 @@ class USERPREF_PT_interface_menus_mouse_over(PreferencePanel, Panel):
self.layout.prop(view, "use_mouse_over_open", text="")
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
view = prefs.view
@@ -322,11 +311,11 @@ class USERPREF_PT_interface_menus_mouse_over(PreferencePanel, Panel):
flow.prop(view, "open_sublevel_delay", text="Sub Level")
-class USERPREF_PT_interface_menus_pie(PreferencePanel, Panel):
+class USERPREF_PT_interface_menus_pie(InterfacePanel, CenterAlignMixIn, Panel):
bl_label = "Pie Menus"
bl_parent_id = "USERPREF_PT_interface_menus"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
view = prefs.view
@@ -340,25 +329,27 @@ class USERPREF_PT_interface_menus_pie(PreferencePanel, Panel):
flow.prop(view, "pie_menu_confirm")
-class USERPREF_PT_edit_objects(Panel):
- bl_label = "Objects"
+# -----------------------------------------------------------------------------
+# Editing Panels
+
+class EditingPanel:
bl_space_type = 'PREFERENCES'
bl_region_type = 'WINDOW'
+ bl_context = "editing"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'EDITING')
+
+class USERPREF_PT_edit_objects(EditingPanel, Panel):
+ bl_label = "Objects"
def draw(self, context):
pass
-class USERPREF_PT_edit_objects_new(PreferencePanel, Panel):
+class USERPREF_PT_edit_objects_new(EditingPanel, CenterAlignMixIn, Panel):
bl_label = "New Objects"
bl_parent_id = "USERPREF_PT_edit_objects"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
edit = prefs.edit
@@ -369,11 +360,11 @@ class USERPREF_PT_edit_objects_new(PreferencePanel, Panel):
flow.prop(edit, "use_enter_edit_mode", text="Enter Edit Mode")
-class USERPREF_PT_edit_objects_duplicate_data(PreferencePanel, Panel):
+class USERPREF_PT_edit_objects_duplicate_data(EditingPanel, CenterAlignMixIn, Panel):
bl_label = "Duplicate Data"
bl_parent_id = "USERPREF_PT_edit_objects"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
edit = prefs.edit
@@ -398,15 +389,10 @@ class USERPREF_PT_edit_objects_duplicate_data(PreferencePanel, Panel):
col.prop(edit, "use_duplicate_grease_pencil", text="Grease Pencil")
-class USERPREF_PT_edit_cursor(PreferencePanel, Panel):
+class USERPREF_PT_edit_cursor(EditingPanel, CenterAlignMixIn, Panel):
bl_label = "3D Cursor"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'EDITING')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
edit = prefs.edit
@@ -416,16 +402,11 @@ class USERPREF_PT_edit_cursor(PreferencePanel, Panel):
flow.prop(edit, "use_cursor_lock_adjust")
-class USERPREF_PT_edit_gpencil(PreferencePanel, Panel):
+class USERPREF_PT_edit_gpencil(EditingPanel, CenterAlignMixIn, Panel):
bl_label = "Grease Pencil"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'EDITING')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
edit = prefs.edit
@@ -435,15 +416,10 @@ class USERPREF_PT_edit_gpencil(PreferencePanel, Panel):
flow.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance")
-class USERPREF_PT_edit_annotations(PreferencePanel, Panel):
+class USERPREF_PT_edit_annotations(EditingPanel, CenterAlignMixIn, Panel):
bl_label = "Annotations"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'EDITING')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
edit = prefs.edit
@@ -453,16 +429,11 @@ class USERPREF_PT_edit_annotations(PreferencePanel, Panel):
flow.prop(edit, "grease_pencil_eraser_radius", text="Eraser Radius")
-class USERPREF_PT_edit_weight_paint(PreferencePanel, Panel):
+class USERPREF_PT_edit_weight_paint(EditingPanel, CenterAlignMixIn, Panel):
bl_label = "Weight Paint"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'EDITING')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
view = prefs.view
@@ -473,16 +444,11 @@ class USERPREF_PT_edit_weight_paint(PreferencePanel, Panel):
col.template_color_ramp(view, "weight_color_range", expand=True)
-class USERPREF_PT_edit_misc(PreferencePanel, Panel):
+class USERPREF_PT_edit_misc(EditingPanel, CenterAlignMixIn, Panel):
bl_label = "Miscellaneous"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'EDITING')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
edit = prefs.edit
@@ -492,15 +458,19 @@ class USERPREF_PT_edit_misc(PreferencePanel, Panel):
flow.prop(edit, "node_margin", text="Node Auto-offset Margin")
-class USERPREF_PT_animation_timeline(PreferencePanel, Panel):
- bl_label = "Timeline"
+# -----------------------------------------------------------------------------
+# Animation Panels
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'ANIMATION')
+class AnimationPanel:
+ bl_space_type = 'PREFERENCES'
+ bl_region_type = 'WINDOW'
+ bl_context = "animation"
- def draw_props(self, context, layout):
+
+class USERPREF_PT_animation_timeline(AnimationPanel, CenterAlignMixIn, Panel):
+ bl_label = "Timeline"
+
+ def draw_centered(self, context, layout):
prefs = context.preferences
view = prefs.view
edit = prefs.edit
@@ -521,15 +491,10 @@ class USERPREF_PT_animation_timeline(PreferencePanel, Panel):
flow.prop(view, "view_frame_keyframes")
-class USERPREF_PT_animation_keyframes(PreferencePanel, Panel):
+class USERPREF_PT_animation_keyframes(AnimationPanel, CenterAlignMixIn, Panel):
bl_label = "Keyframes"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'ANIMATION')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
edit = prefs.edit
@@ -539,11 +504,11 @@ class USERPREF_PT_animation_keyframes(PreferencePanel, Panel):
flow.prop(edit, "use_keyframe_insert_needed", text="Only Insert Needed")
-class USERPREF_PT_animation_autokey(PreferencePanel, Panel):
+class USERPREF_PT_animation_autokey(AnimationPanel, CenterAlignMixIn, Panel):
bl_label = "Auto-Keyframing"
bl_parent_id = "USERPREF_PT_animation_keyframes"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
edit = prefs.edit
@@ -554,15 +519,10 @@ class USERPREF_PT_animation_autokey(PreferencePanel, Panel):
flow.prop(edit, "use_auto_keying", text="Enable in New Scenes")
-class USERPREF_PT_animation_fcurves(PreferencePanel, Panel):
+class USERPREF_PT_animation_fcurves(AnimationPanel, CenterAlignMixIn, Panel):
bl_label = "F-Curves"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'ANIMATION')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
edit = prefs.edit
@@ -575,15 +535,19 @@ class USERPREF_PT_animation_fcurves(PreferencePanel, Panel):
flow.prop(edit, "use_insertkey_xyz_to_rgb", text="XYZ to RGB")
-class USERPREF_PT_system_sound(PreferencePanel, Panel):
- bl_label = "Sound"
+# -----------------------------------------------------------------------------
+# System Panels
+
+class SystemPanel:
+ bl_space_type = 'PREFERENCES'
+ bl_region_type = 'WINDOW'
+ bl_context = "system"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'SYSTEM')
- def draw_props(self, context, layout):
+class USERPREF_PT_system_sound(SystemPanel, CenterAlignMixIn, Panel):
+ bl_label = "Sound"
+
+ def draw_centered(self, context, layout):
prefs = context.preferences
system = prefs.system
@@ -597,15 +561,10 @@ class USERPREF_PT_system_sound(PreferencePanel, Panel):
sub.prop(system, "audio_sample_format", text="Sample Format")
-class USERPREF_PT_system_cycles_devices(PreferencePanel, Panel):
+class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "Cycles Render Devices"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'SYSTEM')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
col = layout.column()
@@ -624,15 +583,55 @@ class USERPREF_PT_system_cycles_devices(PreferencePanel, Panel):
# col.row().prop(system, "opensubdiv_compute_type", text="")
-class USERPREF_PT_viewport_display(PreferencePanel, Panel):
- bl_label = "Display"
+class USERPREF_PT_system_memory(SystemPanel, CenterAlignMixIn, Panel):
+ bl_label = "Memory & Limits"
- @classmethod
- def poll(cls, context):
+ def draw_centered(self, context, layout):
prefs = context.preferences
- return (prefs.active_section == 'VIEWPORT')
+ system = prefs.system
+ edit = prefs.edit
+
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+
+ flow.prop(edit, "undo_steps", text="Undo Steps")
+ flow.prop(edit, "undo_memory_limit", text="Undo Memory Limit")
+ flow.prop(edit, "use_global_undo")
+
+ layout.separator()
+
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+
+ flow.prop(system, "memory_cache_limit", text="Sequencer Cache Limit")
+ flow.prop(system, "scrollback", text="Console Scrollback Lines")
+
+ layout.separator()
+
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
- def draw_props(self, context, layout):
+ flow.prop(system, "texture_time_out", text="Texture Time Out")
+ flow.prop(system, "texture_collection_rate", text="Garbage Collection Rate")
+
+ layout.separator()
+
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+
+ flow.prop(system, "vbo_time_out", text="Vbo Time Out")
+ flow.prop(system, "vbo_collection_rate", text="Garbage Collection Rate")
+
+
+# -----------------------------------------------------------------------------
+# Viewport Panels
+
+class ViewportPanel:
+ bl_space_type = 'PREFERENCES'
+ bl_region_type = 'WINDOW'
+ bl_context = "viewport"
+
+
+class USERPREF_PT_viewport_display(ViewportPanel, CenterAlignMixIn, Panel):
+ bl_label = "Display"
+
+ def draw_centered(self, context, layout):
prefs = context.preferences
view = prefs.view
@@ -660,35 +659,25 @@ class USERPREF_PT_viewport_display(PreferencePanel, Panel):
col.prop(view, "mini_axis_brightness", text="Brightness")
-class USERPREF_PT_viewport_quality(PreferencePanel, Panel):
+class USERPREF_PT_viewport_quality(ViewportPanel, CenterAlignMixIn, Panel):
bl_label = "Quality"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'VIEWPORT')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
system = prefs.system
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
flow.prop(system, "viewport_aa")
- flow.prop(system, "multi_sample", text="Multisampling")
flow.prop(system, "gpencil_multi_sample", text="Grease Pencil Multisampling")
+ flow.prop(system, "use_overlay_smooth_wire")
flow.prop(system, "use_edit_mode_smooth_wire")
-class USERPREF_PT_viewport_textures(PreferencePanel, Panel):
+class USERPREF_PT_viewport_textures(ViewportPanel, CenterAlignMixIn, Panel):
bl_label = "Textures"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'VIEWPORT')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
system = prefs.system
@@ -700,16 +689,11 @@ class USERPREF_PT_viewport_textures(PreferencePanel, Panel):
flow.prop(system, "image_draw_method", text="Image Display Method")
-class USERPREF_PT_viewport_selection(PreferencePanel, Panel):
+class USERPREF_PT_viewport_selection(ViewportPanel, CenterAlignMixIn, Panel):
bl_label = "Selection"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'VIEWPORT')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
system = prefs.system
@@ -718,45 +702,13 @@ class USERPREF_PT_viewport_selection(PreferencePanel, Panel):
flow.prop(system, "use_select_pick_depth")
-class USERPREF_PT_system_memory(PreferencePanel, Panel):
- bl_label = "Memory & Limits"
-
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'SYSTEM')
-
- def draw_props(self, context, layout):
- prefs = context.preferences
- system = prefs.system
- edit = prefs.edit
-
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(edit, "undo_steps", text="Undo Steps")
- flow.prop(edit, "undo_memory_limit", text="Undo Memory Limit")
- flow.prop(edit, "use_global_undo")
-
- layout.separator()
-
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(system, "memory_cache_limit", text="Sequencer Cache Limit")
- flow.prop(system, "scrollback", text="Console Scrollback Lines")
-
- layout.separator()
+# -----------------------------------------------------------------------------
+# Theme Panels
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(system, "texture_time_out", text="Texture Time Out")
- flow.prop(system, "texture_collection_rate", text="Garbage Collection Rate")
-
- layout.separator()
-
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
-
- flow.prop(system, "vbo_time_out", text="Vbo Time Out")
- flow.prop(system, "vbo_collection_rate", text="Garbage Collection Rate")
+class ThemePanel:
+ bl_space_type = 'PREFERENCES'
+ bl_region_type = 'WINDOW'
+ bl_context = "themes"
class USERPREF_MT_interface_theme_presets(Menu):
@@ -775,17 +727,10 @@ class USERPREF_MT_interface_theme_presets(Menu):
bpy.ops.preferences.reset_default_theme()
-class USERPREF_PT_theme(Panel):
- bl_space_type = 'PREFERENCES'
+class USERPREF_PT_theme(ThemePanel, Panel):
bl_label = "Themes"
- bl_region_type = 'WINDOW'
bl_options = {'HIDE_HEADER'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'THEMES')
-
def draw(self, _context):
layout = self.layout
@@ -801,17 +746,10 @@ class USERPREF_PT_theme(Panel):
row.operator("preferences.reset_default_theme", text="Reset", icon='LOOP_BACK')
-class USERPREF_PT_theme_user_interface(PreferencePanel, Panel):
- bl_space_type = 'PREFERENCES'
- bl_region_type = 'WINDOW'
+class USERPREF_PT_theme_user_interface(ThemePanel, CenterAlignMixIn, Panel):
bl_label = "User Interface"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'THEMES')
-
def draw_header(self, _context):
layout = self.layout
@@ -822,9 +760,8 @@ class USERPREF_PT_theme_user_interface(PreferencePanel, Panel):
# Base class for dynamically defined widget color panels.
+# This is not registered.
class PreferenceThemeWidgetColorPanel:
- bl_space_type = 'PREFERENCES'
- bl_region_type = 'WINDOW'
bl_parent_id = "USERPREF_PT_theme_user_interface"
def draw(self, context):
@@ -851,15 +788,10 @@ class PreferenceThemeWidgetColorPanel:
col.prop(widget_style, "roundness")
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'THEMES')
-
+# Base class for dynamically defined widget color panels.
+# This is not registered.
class PreferenceThemeWidgetShadePanel:
- bl_space_type = 'PREFERENCES'
- bl_region_type = 'WINDOW'
def draw(self, context):
theme = context.preferences.themes[0]
@@ -882,12 +814,12 @@ class PreferenceThemeWidgetShadePanel:
self.layout.prop(widget_style, "show_shaded", text="")
-class USERPREF_PT_theme_interface_state(PreferencePanel, Panel):
+class USERPREF_PT_theme_interface_state(ThemePanel, CenterAlignMixIn, Panel):
bl_label = "State"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "USERPREF_PT_theme_user_interface"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
theme = context.preferences.themes[0]
ui_state = theme.user_interface.wcol_state
@@ -917,12 +849,12 @@ class USERPREF_PT_theme_interface_state(PreferencePanel, Panel):
col.prop(ui_state, "blend")
-class USERPREF_PT_theme_interface_styles(PreferencePanel, Panel):
+class USERPREF_PT_theme_interface_styles(ThemePanel, CenterAlignMixIn, Panel):
bl_label = "Styles"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "USERPREF_PT_theme_user_interface"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
theme = context.preferences.themes[0]
ui = theme.user_interface
@@ -937,12 +869,12 @@ class USERPREF_PT_theme_interface_styles(PreferencePanel, Panel):
flow.prop(ui, "widget_emboss")
-class USERPREF_PT_theme_interface_gizmos(PreferencePanel, Panel):
+class USERPREF_PT_theme_interface_gizmos(ThemePanel, CenterAlignMixIn, Panel):
bl_label = "Axis & Gizmo Colors"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "USERPREF_PT_theme_user_interface"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
theme = context.preferences.themes[0]
ui = theme.user_interface
@@ -962,12 +894,12 @@ class USERPREF_PT_theme_interface_gizmos(PreferencePanel, Panel):
col.prop(ui, "gizmo_b")
-class USERPREF_PT_theme_interface_icons(PreferencePanel, Panel):
+class USERPREF_PT_theme_interface_icons(ThemePanel, CenterAlignMixIn, Panel):
bl_label = "Icon Colors"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "USERPREF_PT_theme_user_interface"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
theme = context.preferences.themes[0]
ui = theme.user_interface
@@ -983,15 +915,10 @@ class USERPREF_PT_theme_interface_icons(PreferencePanel, Panel):
flow.prop(ui, "icon_border_intensity")
-class USERPREF_PT_theme_text_style(PreferencePanel, Panel):
+class USERPREF_PT_theme_text_style(ThemePanel, CenterAlignMixIn, Panel):
bl_label = "Text Style"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'THEMES')
-
@staticmethod
def _ui_font_style(layout, font_style):
layout.use_property_split = True
@@ -1015,7 +942,7 @@ class USERPREF_PT_theme_text_style(PreferencePanel, Panel):
layout.label(icon='FONTPREVIEW')
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
style = context.preferences.ui_styles[0]
layout.label(text="Panel Title")
@@ -1032,21 +959,16 @@ class USERPREF_PT_theme_text_style(PreferencePanel, Panel):
self._ui_font_style(layout, style.widget_label)
-class USERPREF_PT_theme_bone_color_sets(PreferencePanel, Panel):
+class USERPREF_PT_theme_bone_color_sets(ThemePanel, CenterAlignMixIn, Panel):
bl_label = "Bone Color Sets"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'THEMES')
-
def draw_header(self, _context):
layout = self.layout
layout.label(icon='COLOR')
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
theme = context.preferences.themes[0]
layout.use_property_split = True
@@ -1063,9 +985,8 @@ class USERPREF_PT_theme_bone_color_sets(PreferencePanel, Panel):
# Base class for dynamically defined theme-space panels.
+# This is not registered.
class PreferenceThemeSpacePanel:
- bl_space_type = 'PREFERENCES'
- bl_region_type = 'WINDOW'
# not essential, hard-coded UI delimiters for the theme layout
ui_delimiters = {
@@ -1137,11 +1058,6 @@ class PreferenceThemeSpacePanel:
data = getattr(data, datapath_item)
PreferenceThemeSpacePanel._theme_generic(layout, data, self.theme_area)
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'THEMES')
-
class ThemeGenericClassGenerator():
@@ -1172,7 +1088,7 @@ class ThemeGenericClassGenerator():
for (name, wcol) in wcols:
panel_id = "USERPREF_PT_theme_interface_" + wcol
- yield type(panel_id, (PreferenceThemeWidgetColorPanel, Panel), {
+ yield type(panel_id, (PreferenceThemeWidgetColorPanel, ThemePanel, Panel), {
"bl_label": name,
"bl_options": {'DEFAULT_CLOSED'},
"draw": PreferenceThemeWidgetColorPanel.draw,
@@ -1180,7 +1096,7 @@ class ThemeGenericClassGenerator():
})
panel_shade_id = "USERPREF_PT_theme_interface_shade_" + wcol
- yield type(panel_shade_id, (PreferenceThemeWidgetShadePanel, Panel), {
+ yield type(panel_shade_id, (PreferenceThemeWidgetShadePanel, ThemePanel, Panel), {
"bl_label": "Shaded",
"bl_options": {'DEFAULT_CLOSED'},
"bl_parent_id": panel_id,
@@ -1204,7 +1120,7 @@ class ThemeGenericClassGenerator():
for prop in props_ls:
new_datapath = datapath + "." + prop.identifier if datapath else prop.identifier
panel_id = parent_id + "_" + prop.identifier
- yield type(panel_id, (PreferenceThemeSpacePanel, Panel), {
+ yield type(panel_id, (PreferenceThemeSpacePanel, ThemePanel, Panel), {
"bl_label": rna_type.properties[prop.identifier].name,
"bl_parent_id": parent_id,
"bl_options": {'DEFAULT_CLOSED'},
@@ -1213,7 +1129,12 @@ class ThemeGenericClassGenerator():
"datapath": new_datapath,
})
- yield from generate_child_panel_classes_recurse(panel_id, prop.fixed_type, theme_area, new_datapath)
+ yield from generate_child_panel_classes_recurse(
+ panel_id,
+ prop.fixed_type,
+ theme_area,
+ new_datapath,
+ )
yield from generate_child_panel_classes_recurse(parent_id, rna_type, theme_area, datapath)
@@ -1227,7 +1148,7 @@ class ThemeGenericClassGenerator():
panel_id = "USERPREF_PT_theme_" + theme_area.identifier.lower()
# Generate panel-class from theme_area
- yield type(panel_id, (PreferenceThemeSpacePanel, Panel), {
+ yield type(panel_id, (PreferenceThemeSpacePanel, ThemePanel, Panel), {
"bl_label": theme_area.name,
"bl_options": {'DEFAULT_CLOSED'},
"draw_header": PreferenceThemeSpacePanel.draw_header,
@@ -1242,29 +1163,24 @@ class ThemeGenericClassGenerator():
theme_area, theme_area.identifier.lower())
+# -----------------------------------------------------------------------------
+# File Paths Panels
+
# Panel mix-in.
class FilePathsPanel:
bl_space_type = 'PREFERENCES'
bl_region_type = 'WINDOW'
+ bl_context = "file_paths"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'FILE_PATHS')
+
+class USERPREF_PT_file_paths_data(FilePathsPanel, Panel):
+ bl_label = "Data"
def draw(self, context):
layout = self.layout
-
layout.use_property_split = True
layout.use_property_decorate = False
- self.draw_props(context, layout)
-
-
-class USERPREF_PT_file_paths_data(FilePathsPanel, Panel):
- bl_label = "Data"
-
- def draw_props(self, context, _layout):
paths = context.preferences.filepaths
col = self.layout.column()
@@ -1278,7 +1194,11 @@ class USERPREF_PT_file_paths_data(FilePathsPanel, Panel):
class USERPREF_PT_file_paths_render(FilePathsPanel, Panel):
bl_label = "Render"
- def draw_props(self, context, _layout):
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
paths = context.preferences.filepaths
col = self.layout.column()
@@ -1289,7 +1209,11 @@ class USERPREF_PT_file_paths_render(FilePathsPanel, Panel):
class USERPREF_PT_file_paths_applications(FilePathsPanel, Panel):
bl_label = "Applications"
- def draw_props(self, context, layout):
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
paths = context.preferences.filepaths
col = layout.column()
@@ -1305,14 +1229,18 @@ class USERPREF_PT_file_paths_development(FilePathsPanel, Panel):
@classmethod
def poll(cls, context):
prefs = context.preferences
- return (prefs.active_section == 'FILE_PATHS') and prefs.view.show_developer_ui
+ return prefs.view.show_developer_ui
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
- def draw_props(self, context, layout):
paths = context.preferences.filepaths
layout.prop(paths, "i18n_branches_directory", text="I18n Branches")
-class USERPREF_PT_saveload_autorun(PreferencePanel, Panel):
+class USERPREF_PT_saveload_autorun(FilePathsPanel, Panel):
bl_label = "Auto Run Python Scripts"
bl_parent_id = "USERPREF_PT_saveload_blend"
@@ -1343,15 +1271,19 @@ class USERPREF_PT_saveload_autorun(PreferencePanel, Panel):
row.operator("wm.userpref_autoexec_path_remove", text="", icon='X', emboss=False).index = i
-class USERPREF_PT_saveload_blend(PreferencePanel, Panel):
- bl_label = "Blend Files"
+# -----------------------------------------------------------------------------
+# Save/Load Panels
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'SAVE_LOAD')
+class SaveLoadPanel:
+ bl_space_type = 'PREFERENCES'
+ bl_region_type = 'WINDOW'
+ bl_context = "save_load"
+
+
+class USERPREF_PT_saveload_blend(SaveLoadPanel, CenterAlignMixIn, Panel):
+ bl_label = "Blend Files"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
paths = prefs.filepaths
view = prefs.view
@@ -1373,11 +1305,11 @@ class USERPREF_PT_saveload_blend(PreferencePanel, Panel):
flow.prop(paths, "recent_files")
-class USERPREF_PT_saveload_blend_autosave(PreferencePanel, Panel):
+class USERPREF_PT_saveload_blend_autosave(SaveLoadPanel, CenterAlignMixIn, Panel):
bl_label = "Auto Save"
bl_parent_id = "USERPREF_PT_saveload_blend"
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
paths = prefs.filepaths
@@ -1389,15 +1321,10 @@ class USERPREF_PT_saveload_blend_autosave(PreferencePanel, Panel):
sub.prop(paths, "auto_save_time", text="Timer (mins)")
-class USERPREF_PT_saveload_file_browser(PreferencePanel, Panel):
+class USERPREF_PT_saveload_file_browser(SaveLoadPanel, CenterAlignMixIn, Panel):
bl_label = "File Browser"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'SAVE_LOAD')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
paths = prefs.filepaths
@@ -1409,62 +1336,19 @@ class USERPREF_PT_saveload_file_browser(PreferencePanel, Panel):
flow.prop(paths, "hide_system_bookmarks")
-class USERPREF_MT_ndof_settings(Menu):
- # accessed from the window key-bindings in C (only)
- bl_label = "3D Mouse Settings"
-
- def draw(self, context):
- layout = self.layout
-
- input_prefs = context.preferences.inputs
-
- is_view3d = context.space_data.type == 'VIEW_3D'
-
- layout.prop(input_prefs, "ndof_sensitivity")
- layout.prop(input_prefs, "ndof_orbit_sensitivity")
- layout.prop(input_prefs, "ndof_deadzone")
-
- if is_view3d:
- layout.separator()
- layout.prop(input_prefs, "ndof_show_guide")
-
- layout.separator()
- layout.label(text="Orbit Style")
- layout.row().prop(input_prefs, "ndof_view_navigate_method", text="")
- layout.row().prop(input_prefs, "ndof_view_rotate_method", text="")
- layout.separator()
- layout.label(text="Orbit Options")
- layout.prop(input_prefs, "ndof_rotx_invert_axis")
- layout.prop(input_prefs, "ndof_roty_invert_axis")
- layout.prop(input_prefs, "ndof_rotz_invert_axis")
-
- # view2d use pan/zoom
- layout.separator()
- layout.label(text="Pan Options")
- layout.prop(input_prefs, "ndof_panx_invert_axis")
- layout.prop(input_prefs, "ndof_pany_invert_axis")
- layout.prop(input_prefs, "ndof_panz_invert_axis")
- layout.prop(input_prefs, "ndof_pan_yz_swap_axis")
-
- layout.label(text="Zoom Options")
- layout.prop(input_prefs, "ndof_zoom_invert")
+# -----------------------------------------------------------------------------
+# Input Panels
- if is_view3d:
- layout.separator()
- layout.label(text="Fly/Walk Options")
- layout.prop(input_prefs, "ndof_fly_helicopter", icon='NDOF_FLY')
- layout.prop(input_prefs, "ndof_lock_horizon", icon='NDOF_DOM')
+class InputPanel:
+ bl_space_type = 'PREFERENCES'
+ bl_region_type = 'WINDOW'
+ bl_context = "input"
-class USERPREF_PT_input_keyboard(PreferencePanel, Panel):
+class USERPREF_PT_input_keyboard(InputPanel, CenterAlignMixIn, Panel):
bl_label = "Keyboard"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'INPUT')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
inputs = prefs.inputs
@@ -1472,15 +1356,10 @@ class USERPREF_PT_input_keyboard(PreferencePanel, Panel):
layout.prop(inputs, "use_numeric_input_advanced")
-class USERPREF_PT_input_mouse(PreferencePanel, Panel):
+class USERPREF_PT_input_mouse(InputPanel, CenterAlignMixIn, Panel):
bl_label = "Mouse"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'INPUT')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
import sys
prefs = context.preferences
inputs = prefs.inputs
@@ -1501,15 +1380,63 @@ class USERPREF_PT_input_mouse(PreferencePanel, Panel):
flow.prop(inputs, "move_threshold")
-class USERPREF_PT_navigation_orbit(PreferencePanel, Panel):
- bl_label = "Orbit & Pan"
+class USERPREF_PT_input_tablet(InputPanel, CenterAlignMixIn, Panel):
+ bl_label = "Tablet"
+
+ def draw_centered(self, context, layout):
+ prefs = context.preferences
+ inputs = prefs.inputs
+
+ import sys
+ if sys.platform[:3] == "win":
+ layout.prop(inputs, "tablet_api")
+ layout.separator()
+
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+
+ flow.prop(inputs, "pressure_threshold_max")
+ flow.prop(inputs, "pressure_softness")
+
+
+class USERPREF_PT_input_ndof(InputPanel, CenterAlignMixIn, Panel):
+ bl_label = "NDOF"
+ bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
prefs = context.preferences
- return (prefs.active_section == 'NAVIGATION')
+ inputs = prefs.inputs
+ return inputs.use_ndof
+
+ def draw_centered(self, context, layout):
+ prefs = context.preferences
+ inputs = prefs.inputs
+
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+
+ flow.prop(inputs, "ndof_sensitivity", text="Pan Sensitivity")
+ flow.prop(inputs, "ndof_orbit_sensitivity", text="Orbit Sensitivity")
+ flow.prop(inputs, "ndof_deadzone", text="Deadzone")
+
+ layout.separator()
- def draw_props(self, context, layout):
+ flow.row().prop(inputs, "ndof_view_navigate_method", expand=True)
+ flow.row().prop(inputs, "ndof_view_rotate_method", expand=True)
+
+
+# -----------------------------------------------------------------------------
+# Navigation Panels
+
+class NavigationPanel:
+ bl_space_type = 'PREFERENCES'
+ bl_region_type = 'WINDOW'
+ bl_context = "navigation"
+
+
+class USERPREF_PT_navigation_orbit(NavigationPanel, CenterAlignMixIn, Panel):
+ bl_label = "Orbit & Pan"
+
+ def draw_centered(self, context, layout):
import sys
prefs = context.preferences
inputs = prefs.inputs
@@ -1535,15 +1462,10 @@ class USERPREF_PT_navigation_orbit(PreferencePanel, Panel):
flow.prop(view, "rotation_angle")
-class USERPREF_PT_navigation_zoom(PreferencePanel, Panel):
+class USERPREF_PT_navigation_zoom(NavigationPanel, CenterAlignMixIn, Panel):
bl_label = "Zoom"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'NAVIGATION')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
inputs = prefs.inputs
@@ -1559,15 +1481,10 @@ class USERPREF_PT_navigation_zoom(PreferencePanel, Panel):
flow.prop(inputs, "use_zoom_to_mouse")
-class USERPREF_PT_navigation_fly_walk(PreferencePanel, Panel):
+class USERPREF_PT_navigation_fly_walk(NavigationPanel, CenterAlignMixIn, Panel):
bl_label = "Fly & Walk"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'NAVIGATION')
-
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
inputs = prefs.inputs
@@ -1577,7 +1494,7 @@ class USERPREF_PT_navigation_fly_walk(PreferencePanel, Panel):
flow.prop(inputs, "use_camera_lock_parent")
-class USERPREF_PT_navigation_fly_walk_navigation(PreferencePanel, Panel):
+class USERPREF_PT_navigation_fly_walk_navigation(NavigationPanel, CenterAlignMixIn, Panel):
bl_label = "Walk"
bl_parent_id = "USERPREF_PT_navigation_fly_walk"
bl_options = {'DEFAULT_CLOSED'}
@@ -1587,7 +1504,7 @@ class USERPREF_PT_navigation_fly_walk_navigation(PreferencePanel, Panel):
prefs = context.preferences
return prefs.inputs.navigation_mode == 'WALK'
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
inputs = prefs.inputs
walk = inputs.walk_navigation
@@ -1603,7 +1520,7 @@ class USERPREF_PT_navigation_fly_walk_navigation(PreferencePanel, Panel):
sub.prop(walk, "walk_speed_factor")
-class USERPREF_PT_navigation_fly_walk_gravity(PreferencePanel, Panel):
+class USERPREF_PT_navigation_fly_walk_gravity(NavigationPanel, CenterAlignMixIn, Panel):
bl_label = "Gravity"
bl_parent_id = "USERPREF_PT_navigation_fly_walk"
bl_options = {'DEFAULT_CLOSED'}
@@ -1620,7 +1537,7 @@ class USERPREF_PT_navigation_fly_walk_gravity(PreferencePanel, Panel):
self.layout.prop(walk, "use_gravity", text="")
- def draw_props(self, context, layout):
+ def draw_centered(self, context, layout):
prefs = context.preferences
inputs = prefs.inputs
walk = inputs.walk_navigation
@@ -1633,53 +1550,84 @@ class USERPREF_PT_navigation_fly_walk_gravity(PreferencePanel, Panel):
flow.prop(walk, "jump_height")
-class USERPREF_PT_input_tablet(PreferencePanel, Panel):
- bl_label = "Tablet"
+# Special case, this is only exposed as a popover.
+class USERPREF_PT_ndof_settings(Panel):
+ bl_label = "3D Mouse Settings"
+ bl_space_type = 'TOPBAR' # dummy.
+ bl_region_type = 'HEADER'
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return prefs.active_section == 'INPUT'
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
- def draw_props(self, context, layout):
- prefs = context.preferences
- inputs = prefs.inputs
+ input_prefs = context.preferences.inputs
- import sys
- if sys.platform[:3] == "win":
- layout.prop(inputs, "tablet_api")
+ is_view3d = context.space_data.type == 'VIEW_3D'
+
+ col = layout.column(align=True)
+ col.prop(input_prefs, "ndof_sensitivity")
+ col.prop(input_prefs, "ndof_orbit_sensitivity")
+ col.prop(input_prefs, "ndof_deadzone")
+
+ if is_view3d:
layout.separator()
+ layout.prop(input_prefs, "ndof_show_guide")
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ layout.separator()
+ layout.label(text="Orbit Style")
+ layout.row().prop(input_prefs, "ndof_view_navigate_method", text="Navigate")
+ layout.row().prop(input_prefs, "ndof_view_rotate_method", text="Orbit")
+ layout.separator()
- flow.prop(inputs, "pressure_threshold_max")
- flow.prop(inputs, "pressure_softness")
+ layout.label(text="Orbit Options")
+ split = layout.split(factor=0.6)
+ row = split.row()
+ row.alignment = 'RIGHT'
+ row.label(text="Invert Axis")
+ row = split.row(align=True)
+ for text, attr in (
+ ("X", "ndof_rotx_invert_axis"),
+ ("Y", "ndof_roty_invert_axis"),
+ ("Z", "ndof_rotz_invert_axis"),
+ ):
+ row.prop(input_prefs, attr, text=text, toggle=True)
+ # view2d use pan/zoom
+ layout.separator()
+ layout.label(text="Pan Options")
-class USERPREF_PT_input_ndof(PreferencePanel, Panel):
- bl_label = "NDOF"
- bl_options = {'DEFAULT_CLOSED'}
+ split = layout.split(factor=0.6)
+ row = split.row()
+ row.alignment = 'RIGHT'
+ row.label(text="Invert Axis")
+ row = split.row(align=True)
+ for text, attr in (
+ ("X", "ndof_panx_invert_axis"),
+ ("Y", "ndof_pany_invert_axis"),
+ ("Z", "ndof_panz_invert_axis"),
+ ):
+ row.prop(input_prefs, attr, text=text, toggle=True)
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- inputs = prefs.inputs
- return prefs.active_section == 'INPUT' and inputs.use_ndof
+ layout.prop(input_prefs, "ndof_pan_yz_swap_axis")
- def draw_props(self, context, layout):
- prefs = context.preferences
- inputs = prefs.inputs
+ layout.label(text="Zoom Options")
+ layout.prop(input_prefs, "ndof_zoom_invert")
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+ if is_view3d:
+ layout.separator()
+ layout.label(text="Fly/Walk Options")
+ layout.prop(input_prefs, "ndof_fly_helicopter")
+ layout.prop(input_prefs, "ndof_lock_horizon")
- flow.prop(inputs, "ndof_sensitivity", text="Pan Sensitivity")
- flow.prop(inputs, "ndof_orbit_sensitivity", text="Orbit Sensitivity")
- flow.prop(inputs, "ndof_deadzone", text="Deadzone")
- layout.separator()
+# -----------------------------------------------------------------------------
+# Key-Map Editor Panels
- flow.row().prop(inputs, "ndof_view_navigate_method", expand=True)
- flow.row().prop(inputs, "ndof_view_rotate_method", expand=True)
+class KeymapPanel:
+ bl_space_type = 'PREFERENCES'
+ bl_region_type = 'WINDOW'
+ bl_context = "keymap"
class USERPREF_MT_keyconfigs(Menu):
@@ -1691,17 +1639,10 @@ class USERPREF_MT_keyconfigs(Menu):
Menu.draw_preset(self, context)
-class USERPREF_PT_keymap(Panel):
- bl_space_type = 'PREFERENCES'
+class USERPREF_PT_keymap(KeymapPanel, Panel):
bl_label = "Keymap"
- bl_region_type = 'WINDOW'
bl_options = {'HIDE_HEADER'}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'KEYMAP')
-
def draw(self, context):
from rna_keymap_ui import draw_keymaps
@@ -1717,10 +1658,17 @@ class USERPREF_PT_keymap(Panel):
# print("runtime", time.time() - start)
-class USERPREF_PT_addons(Panel):
+# -----------------------------------------------------------------------------
+# Add-On Panels
+
+class AddOnPanel:
bl_space_type = 'PREFERENCES'
- bl_label = "Add-ons"
bl_region_type = 'WINDOW'
+ bl_context = "addons"
+
+
+class USERPREF_PT_addons(AddOnPanel, Panel):
+ bl_label = "Add-ons"
bl_options = {'HIDE_HEADER'}
_support_icon_mapping = {
@@ -1729,11 +1677,6 @@ class USERPREF_PT_addons(Panel):
'TESTING': 'EXPERIMENTAL',
}
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'ADDONS')
-
@staticmethod
def is_user_addon(mod, user_addon_paths):
import os
@@ -2004,14 +1947,16 @@ class USERPREF_PT_addons(Panel):
row.label(text=module_name, translate=False)
-class StudioLightPanelMixin():
+# -----------------------------------------------------------------------------
+# Studio Light Panels
+
+class StudioLightPanel:
bl_space_type = 'PREFERENCES'
bl_region_type = 'WINDOW'
+ bl_context = "lights"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'LIGHTS')
+
+class StudioLightPanelMixin:
def _get_lights(self, prefs):
return [light for light in prefs.studio_lights if light.is_user_defined and light.type == self.sl_type]
@@ -2047,7 +1992,7 @@ class StudioLightPanelMixin():
box.label(text=studio_light.name)
-class USERPREF_PT_studiolight_matcaps(Panel, StudioLightPanelMixin):
+class USERPREF_PT_studiolight_matcaps(StudioLightPanel, StudioLightPanelMixin, Panel):
bl_label = "MatCaps"
sl_type = 'MATCAP'
@@ -2057,8 +2002,8 @@ class USERPREF_PT_studiolight_matcaps(Panel, StudioLightPanelMixin):
layout.separator()
-class USERPREF_PT_studiolight_world(Panel, StudioLightPanelMixin):
- bl_label = "LookDev HDRIs"
+class USERPREF_PT_studiolight_world(StudioLightPanel, StudioLightPanelMixin, Panel):
+ bl_label = "HDRIs"
sl_type = 'WORLD'
def draw_header_preset(self, _context):
@@ -2067,7 +2012,7 @@ class USERPREF_PT_studiolight_world(Panel, StudioLightPanelMixin):
layout.separator()
-class USERPREF_PT_studiolight_lights(Panel, StudioLightPanelMixin):
+class USERPREF_PT_studiolight_lights(StudioLightPanel, StudioLightPanelMixin, Panel):
bl_label = "Studio Lights"
sl_type = 'STUDIO'
@@ -2079,14 +2024,13 @@ class USERPREF_PT_studiolight_lights(Panel, StudioLightPanelMixin):
layout.separator()
-class USERPREF_PT_studiolight_light_editor(Panel):
+class USERPREF_PT_studiolight_light_editor(StudioLightPanel, Panel):
bl_label = "Editor"
bl_parent_id = "USERPREF_PT_studiolight_lights"
- bl_space_type = 'PREFERENCES'
- bl_region_type = 'WINDOW'
bl_options = {'DEFAULT_CLOSED'}
- def opengl_light_buttons(self, layout, light):
+ @staticmethod
+ def opengl_light_buttons(layout, light):
col = layout.column()
col.active = light.use
@@ -2133,38 +2077,15 @@ class USERPREF_PT_studiolight_light_editor(Panel):
layout.prop(system, "light_ambient")
+# -----------------------------------------------------------------------------
+# Experimental Panels
+
class ExperimentalPanel:
bl_space_type = 'PREFERENCES'
bl_region_type = 'WINDOW'
+ bl_context = "experimental"
- @classmethod
- def poll(cls, context):
- prefs = context.preferences
- return (prefs.active_section == 'EXPERIMENTAL')
-
- def draw(self, context):
- layout = self.layout
-
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- self.draw_props(context, layout)
-
-
-class USERPREF_PT_experimental_all(ExperimentalPanel, Panel):
- bl_label = "All"
- bl_options = {'HIDE_HEADER'}
-
- def draw_props(self, context, layout):
- prefs = context.preferences
- experimental = prefs.experimental
-
- col = layout.column()
- col.prop(experimental, "use_experimental_all")
-
- # For the other settings create new panels
- # and make sure they are disabled if use_experimental_all is True
-
+ url_prefix = "https://developer.blender.org/"
"""
# Example panel, leave it here so we always have a template to follow even
@@ -2173,27 +2094,33 @@ class USERPREF_PT_experimental_all(ExperimentalPanel, Panel):
class USERPREF_PT_experimental_virtual_reality(ExperimentalPanel, Panel):
bl_label = "Virtual Reality"
- def draw_props(self, context, layout):
+ def draw(self, context):
prefs = context.preferences
experimental = prefs.experimental
- layout.active = not experimental.use_experimental_all
+
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
task = "T71347"
split = layout.split(factor=0.66)
col = split.split()
col.prop(experimental, "use_virtual_reality_scene_inspection", text="Scene Inspection")
col = split.split()
- col.operator("wm.url_open", text=task, icon='URL').url = "https://developer.blender.org/" + task
+ col.operator("wm.url_open", text=task, icon='URL').url = self.url_prefix + task
task = "T71348"
split = layout.split(factor=0.66)
col = split.column()
col.prop(experimental, "use_virtual_reality_immersive_drawing", text="Continuous Immersive Drawing")
col = split.column()
- col.operator("wm.url_open", text=task, icon='URL').url = "https://developer.blender.org/" + task
+ col.operator("wm.url_open", text=task, icon='URL').url = self.url_prefix + task
"""
+# -----------------------------------------------------------------------------
+# Class Registration
+
# Order of registration defines order in UI,
# so dynamically generated classes are 'injected' in the intended order.
classes = (
@@ -2255,7 +2182,6 @@ classes = (
USERPREF_PT_saveload_autorun,
USERPREF_PT_saveload_file_browser,
- USERPREF_MT_ndof_settings,
USERPREF_MT_keyconfigs,
USERPREF_PT_input_keyboard,
@@ -2276,7 +2202,8 @@ classes = (
USERPREF_PT_studiolight_matcaps,
USERPREF_PT_studiolight_world,
- USERPREF_PT_experimental_all,
+ # Popovers.
+ USERPREF_PT_ndof_settings,
# Add dynamically generated editor theme panels last,
# so they show up last in the theme section.
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 113274ce166..02dc03be127 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -25,6 +25,7 @@ from bpy.types import (
)
from bl_ui.properties_paint_common import (
UnifiedPaintPanel,
+ brush_basic_texpaint_settings,
)
from bl_ui.properties_grease_pencil_common import (
AnnotationDataPanel,
@@ -67,7 +68,6 @@ class VIEW3D_HT_tool_header(Header):
context, layout,
tool_key=('VIEW_3D', tool_mode),
)
-
# Object Mode Options
# -------------------
@@ -77,23 +77,31 @@ class VIEW3D_HT_tool_header(Header):
# (obviously separated for from the users POV)
draw_fn = getattr(_draw_tool_settings_context_mode, tool_mode, None)
if draw_fn is not None:
- draw_fn(context, layout, tool)
-
- popover_kw = {"space_type": 'VIEW_3D', "region_type": 'UI', "category": "Tool"}
+ is_valid_context = draw_fn(context, layout, tool)
+
+ def draw_3d_brush_settings(layout, tool_mode):
+ layout.popover("VIEW3D_PT_tools_brush_settings_advanced", text="Brush")
+ if tool_mode != 'PAINT_WEIGHT':
+ layout.popover("VIEW3D_PT_tools_brush_texture")
+ if tool_mode == 'PAINT_TEXTURE':
+ layout.popover("VIEW3D_PT_tools_mask_texture")
+ layout.popover("VIEW3D_PT_tools_brush_stroke")
+ layout.popover("VIEW3D_PT_tools_brush_falloff")
+ layout.popover("VIEW3D_PT_tools_brush_display")
# Note: general mode options should be added to 'draw_mode_settings'.
if tool_mode == 'SCULPT':
- if (tool is not None) and tool.has_datablock:
- layout.popover_group(context=".paint_common", **popover_kw)
+ if is_valid_context:
+ draw_3d_brush_settings(layout, tool_mode)
elif tool_mode == 'PAINT_VERTEX':
- if (tool is not None) and tool.has_datablock:
- layout.popover_group(context=".paint_common", **popover_kw)
+ if is_valid_context:
+ draw_3d_brush_settings(layout, tool_mode)
elif tool_mode == 'PAINT_WEIGHT':
- if (tool is not None) and tool.has_datablock:
- layout.popover_group(context=".paint_common", **popover_kw)
+ if is_valid_context:
+ draw_3d_brush_settings(layout, tool_mode)
elif tool_mode == 'PAINT_TEXTURE':
- if (tool is not None) and tool.has_datablock:
- layout.popover_group(context=".paint_common", **popover_kw)
+ if is_valid_context:
+ draw_3d_brush_settings(layout, tool_mode)
elif tool_mode == 'EDIT_ARMATURE':
pass
elif tool_mode == 'EDIT_CURVE':
@@ -108,12 +116,24 @@ class VIEW3D_HT_tool_header(Header):
# layout.popover_group(context=".paint_common", **popover_kw)
pass
elif tool_mode == 'PAINT_GPENCIL':
- if (tool is not None) and tool.has_datablock:
- layout.popover_group(context=".greasepencil_paint", **popover_kw)
+ if is_valid_context:
+ brush = context.tool_settings.gpencil_paint.brush
+ if brush.gpencil_tool != 'ERASE':
+ layout.popover("VIEW3D_PT_tools_grease_pencil_brush_advanced")
+
+ if brush.gpencil_tool != 'FILL':
+ layout.popover("VIEW3D_PT_tools_grease_pencil_brush_stroke")
+ layout.popover("VIEW3D_PT_tools_grease_pencil_brushcurves")
+
+ layout.popover("VIEW3D_PT_tools_grease_pencil_paint_appearance")
elif tool_mode == 'SCULPT_GPENCIL':
- layout.popover_group(context=".greasepencil_sculpt", **popover_kw)
+ settings = context.tool_settings.gpencil_sculpt
+ tool = settings.sculpt_tool
+ if tool in {'SMOOTH', 'RANDOMIZE', 'SMOOTH'}:
+ layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_options")
+ layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
elif tool_mode == 'WEIGHT_GPENCIL':
- layout.popover_group(context=".greasepencil_weight", **popover_kw)
+ layout.popover("VIEW3D_PT_tools_grease_pencil_weight_appearance")
def draw_mode_settings(self, context):
layout = self.layout
@@ -221,80 +241,138 @@ class _draw_tool_settings_context_mode:
@staticmethod
def SCULPT(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
- return
+ return False
paint = context.tool_settings.sculpt
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
brush = paint.brush
if brush is None:
- return
+ return False
- from bl_ui.properties_paint_common import (
- brush_basic_sculpt_settings,
+ tool_settings = context.tool_settings
+ capabilities = brush.sculpt_capabilities
+
+ ups = tool_settings.unified_paint_settings
+
+ size = "size"
+ size_owner = ups if ups.use_unified_size else brush
+ if size_owner.use_locked_size == 'SCENE':
+ size = "unprojected_radius"
+
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ size,
+ pressure_name="use_pressure_size",
+ unified_name="use_unified_size",
+ text="Radius",
+ slider=True,
+ header=True
)
- brush_basic_sculpt_settings(layout, context, brush, compact=True)
+
+ # strength, use_strength_pressure
+ pressure_name = "use_pressure_strength" if capabilities.has_strength_pressure else None
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "strength",
+ pressure_name=pressure_name,
+ unified_name="use_unified_strength",
+ text="Strength",
+ header=True
+ )
+
+ # direction
+ if not capabilities.has_direction:
+ layout.row().prop(brush, "direction", expand=True, text="")
+
+ return True
@staticmethod
def PAINT_TEXTURE(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
- return
+ return False
paint = context.tool_settings.image_paint
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
brush = paint.brush
if brush is None:
- return
+ return False
- from bl_ui.properties_paint_common import (
- UnifiedPaintPanel,
- brush_basic_texpaint_settings,
- )
- capabilities = brush.image_paint_capabilities
- if capabilities.has_color:
- UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
brush_basic_texpaint_settings(layout, context, brush, compact=True)
+ return True
+
@staticmethod
def PAINT_VERTEX(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
- return
+ return False
paint = context.tool_settings.vertex_paint
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
brush = paint.brush
if brush is None:
- return
+ return False
- from bl_ui.properties_paint_common import (
- UnifiedPaintPanel,
- brush_basic_vpaint_settings,
- )
- capabilities = brush.vertex_paint_capabilities
- if capabilities.has_color:
- UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
- brush_basic_vpaint_settings(layout, context, brush, compact=True)
+ brush_basic_texpaint_settings(layout, context, brush, compact=True)
+
+ return True
@staticmethod
def PAINT_WEIGHT(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
- return
+ return False
paint = context.tool_settings.weight_paint
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
brush = paint.brush
if brush is None:
- return
+ return False
+
+ capabilities = brush.weight_paint_capabilities
+ if capabilities.has_weight:
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "weight",
+ unified_name="use_unified_weight",
+ slider=True,
+ header=True
+ )
+
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "size",
+ pressure_name="use_pressure_size",
+ unified_name="use_unified_size",
+ slider=True,
+ text="Radius",
+ header=True
+ )
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "strength",
+ pressure_name="use_pressure_strength",
+ unified_name="use_unified_strength",
+ header=True
+ )
- from bl_ui.properties_paint_common import brush_basic_wpaint_settings
- brush_basic_wpaint_settings(layout, context, brush, compact=True)
+ return True
@staticmethod
def PAINT_GPENCIL(context, layout, tool):
if tool is None:
- return
+ return False
# is_paint = True
# FIXME: tools must use their own UI drawing!
@@ -311,14 +389,14 @@ class _draw_tool_settings_context_mode:
elif tool.idname == "Cutter":
row = layout.row(align=True)
row.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
- return
+ return False
elif not tool.has_datablock:
- return
+ return False
paint = context.tool_settings.gpencil_paint
brush = paint.brush
if brush is None:
- return
+ return False
gp_settings = brush.gpencil_settings
@@ -358,12 +436,14 @@ class _draw_tool_settings_context_mode:
from bl_ui.properties_paint_common import (
brush_basic_gpencil_paint_settings,
)
- brush_basic_gpencil_paint_settings(layout, context, brush, tool, compact=True, is_toolbar=True)
+ brush_basic_gpencil_paint_settings(layout, context, brush, compact=True)
+
+ return True
@staticmethod
def SCULPT_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
- return
+ return False
tool_settings = context.tool_settings
settings = tool_settings.gpencil_sculpt
brush = settings.brush
@@ -373,10 +453,12 @@ class _draw_tool_settings_context_mode:
)
brush_basic_gpencil_sculpt_settings(layout, context, brush, compact=True)
+ return True
+
@staticmethod
def WEIGHT_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
- return
+ return False
tool_settings = context.tool_settings
settings = tool_settings.gpencil_sculpt
brush = settings.brush
@@ -386,38 +468,44 @@ class _draw_tool_settings_context_mode:
)
brush_basic_gpencil_weight_settings(layout, context, brush, compact=True)
+ return True
+
@staticmethod
def PARTICLE(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
- return
+ return False
# See: 'VIEW3D_PT_tools_brush', basically a duplicate
settings = context.tool_settings.particle_edit
brush = settings.brush
tool = settings.tool
- if tool != 'NONE':
- layout.prop(brush, "size", slider=True)
- if tool == 'ADD':
- layout.prop(brush, "count")
+ if tool == 'NONE':
+ return False
- layout.prop(settings, "use_default_interpolate")
- layout.prop(brush, "steps", slider=True)
- layout.prop(settings, "default_key_count", slider=True)
- else:
- layout.prop(brush, "strength", slider=True)
-
- if tool == 'LENGTH':
- layout.row().prop(brush, "length_mode", expand=True)
- elif tool == 'PUFF':
- layout.row().prop(brush, "puff_mode", expand=True)
- layout.prop(brush, "use_puff_volume")
- elif tool == 'COMB':
- row = layout.row()
- row.active = settings.is_editable
- row.prop(settings, "use_emitter_deflect", text="Deflect Emitter")
- sub = row.row(align=True)
- sub.active = settings.use_emitter_deflect
- sub.prop(settings, "emitter_distance", text="Distance")
+ layout.prop(brush, "size", slider=True)
+ if tool == 'ADD':
+ layout.prop(brush, "count")
+
+ layout.prop(settings, "use_default_interpolate")
+ layout.prop(brush, "steps", slider=True)
+ layout.prop(settings, "default_key_count", slider=True)
+ else:
+ layout.prop(brush, "strength", slider=True)
+
+ if tool == 'LENGTH':
+ layout.row().prop(brush, "length_mode", expand=True)
+ elif tool == 'PUFF':
+ layout.row().prop(brush, "puff_mode", expand=True)
+ layout.prop(brush, "use_puff_volume")
+ elif tool == 'COMB':
+ row = layout.row()
+ row.active = settings.is_editable
+ row.prop(settings, "use_emitter_deflect", text="Deflect Emitter")
+ sub = row.row(align=True)
+ sub.active = settings.use_emitter_deflect
+ sub.prop(settings, "emitter_distance", text="Distance")
+
+ return True
class VIEW3D_HT_header(Header):
@@ -467,12 +555,11 @@ class VIEW3D_HT_header(Header):
show_snap = True
else:
- from bl_ui.properties_paint_common import UnifiedPaintPanel
paint_settings = UnifiedPaintPanel.paint_settings(context)
if paint_settings:
brush = paint_settings.brush
- if brush and brush.stroke_method == 'CURVE':
+ if brush and hasattr(brush, "stroke_method") and brush.stroke_method == 'CURVE':
show_snap = True
if show_snap:
@@ -831,7 +918,7 @@ class VIEW3D_MT_transform_base(Menu):
if context.mode != 'OBJECT':
layout.operator("transform.vertex_warp", text="Warp")
layout.operator_context = 'EXEC_DEFAULT'
- layout.operator("transform.vertex_random", text="Randomize")
+ layout.operator("transform.vertex_random", text="Randomize").offset = 0.1
layout.operator_context = 'INVOKE_REGION_WIN'
@@ -1042,6 +1129,12 @@ class VIEW3D_MT_view(Menu):
layout.operator("render.opengl", text="Viewport Render Image", icon='RENDER_STILL')
layout.operator("render.opengl", text="Viewport Render Animation", icon='RENDER_ANIMATION').animation = True
+ props = layout.operator("render.opengl",
+ text="Viewport Render Keyframes",
+ icon='RENDER_ANIMATION',
+ )
+ props.animation = True
+ props.render_keyed_only = True
layout.separator()
@@ -2591,7 +2684,7 @@ class VIEW3D_MT_object_quick_effects(Menu):
layout.operator("object.quick_fur")
layout.operator("object.quick_explode")
layout.operator("object.quick_smoke")
- layout.operator("object.quick_fluid")
+ layout.operator("object.quick_liquid")
class VIEW3D_MT_object_showhide(Menu):
@@ -3437,8 +3530,8 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu):
col.operator("transform.shear", text="Shear")
col.operator("transform.vert_slide", text="Slide Vertices")
col.operator_context = 'EXEC_DEFAULT'
- col.operator("transform.vertex_random", text="Randomize Vertices")
- col.operator("mesh.vertices_smooth", text="Smooth Vertices")
+ col.operator("transform.vertex_random", text="Randomize Vertices").offset = 0.1
+ col.operator("mesh.vertices_smooth", text="Smooth Vertices").factor = 0.5
col.operator_context = 'INVOKE_REGION_WIN'
col.operator("mesh.vertices_smooth_laplacian", text="Smooth Laplacian")
@@ -3654,7 +3747,7 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.operator("transform.vert_slide", text="Slide Vertices")
layout.operator_context = 'EXEC_DEFAULT'
- layout.operator("mesh.vertices_smooth", text="Smooth Vertices")
+ layout.operator("mesh.vertices_smooth", text="Smooth Vertices").factor = 0.5
layout.operator_context = 'INVOKE_REGION_WIN'
layout.separator()
@@ -5466,6 +5559,27 @@ class VIEW3D_PT_shading_options_ssao(Panel):
col.prop(scene.display, "matcap_ssao_attenuation")
+class VIEW3D_PT_shading_render_pass(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Render Pass"
+ bl_parent_id = 'VIEW3D_PT_shading'
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (
+ (context.space_data.shading.type == 'MATERIAL') or
+ (context.engine in cls.COMPAT_ENGINES and context.space_data.shading.type == 'RENDERED')
+ )
+
+ def draw(self, context):
+ shading = context.space_data.shading
+
+ layout = self.layout
+ layout.prop(shading, "render_pass", text="")
+
+
class VIEW3D_PT_gizmo_display(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
@@ -5547,7 +5661,7 @@ class VIEW3D_PT_overlay_guides(Panel):
row = sub.row()
row_el = row.column()
row_el.prop(overlay, "show_ortho_grid", text="Grid")
- grid_active = (
+ grid_active = bool(
view.region_quadviews or
(view.region_3d.is_orthographic_side_view and not view.region_3d.is_perspective)
)
@@ -6633,6 +6747,7 @@ class VIEW3D_PT_paint_vertex_context_menu(Panel):
def draw(self, context):
layout = self.layout
+
brush = context.tool_settings.vertex_paint.brush
capabilities = brush.vertex_paint_capabilities
@@ -6642,8 +6757,24 @@ class VIEW3D_PT_paint_vertex_context_menu(Panel):
UnifiedPaintPanel.prop_unified_color_picker(split, context, brush, "color", value_slider=True)
layout.prop(brush, "blend", text="")
- UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True)
- UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength")
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "size",
+ unified_name="use_unified_size",
+ pressure_name="use_pressure_size",
+ slider=True,
+ )
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "strength",
+ unified_name="use_unified_strength",
+ pressure_name="use_pressure_strength",
+ slider=True,
+ )
class VIEW3D_PT_paint_texture_context_menu(Panel):
@@ -6654,6 +6785,7 @@ class VIEW3D_PT_paint_texture_context_menu(Panel):
def draw(self, context):
layout = self.layout
+
brush = context.tool_settings.image_paint.brush
capabilities = brush.image_paint_capabilities
@@ -6664,8 +6796,24 @@ class VIEW3D_PT_paint_texture_context_menu(Panel):
layout.prop(brush, "blend", text="")
if capabilities.has_radius:
- UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True)
- UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength")
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "size",
+ unified_name="use_unified_size",
+ pressure_name="use_pressure_size",
+ slider=True,
+ )
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "strength",
+ unified_name="use_unified_strength",
+ pressure_name="use_pressure_strength",
+ slider=True,
+ )
class VIEW3D_PT_paint_weight_context_menu(Panel):
@@ -6678,9 +6826,32 @@ class VIEW3D_PT_paint_weight_context_menu(Panel):
layout = self.layout
brush = context.tool_settings.weight_paint.brush
- UnifiedPaintPanel.prop_unified_weight(layout, context, brush, "weight", slider=True)
- UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True)
- UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength")
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "weight",
+ unified_name="use_unified_weight",
+ slider=True,
+ )
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "size",
+ unified_name="use_unified_size",
+ pressure_name="use_pressure_size",
+ slider=True,
+ )
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "strength",
+ unified_name="use_unified_strength",
+ pressure_name="use_pressure_strength",
+ slider=True,
+ )
class VIEW3D_PT_sculpt_context_menu(Panel):
@@ -6695,8 +6866,24 @@ class VIEW3D_PT_sculpt_context_menu(Panel):
brush = context.tool_settings.sculpt.brush
capabilities = brush.sculpt_capabilities
- UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True)
- UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength")
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "size",
+ unified_name="use_unified_size",
+ pressure_name="use_pressure_size",
+ slider=True,
+ )
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "strength",
+ unified_name="use_unified_strength",
+ pressure_name="use_pressure_strength",
+ slider=True,
+ )
if capabilities.has_auto_smooth:
layout.prop(brush, "auto_smooth_factor", slider=True)
@@ -6909,6 +7096,7 @@ classes = (
VIEW3D_PT_shading_options,
VIEW3D_PT_shading_options_shadow,
VIEW3D_PT_shading_options_ssao,
+ VIEW3D_PT_shading_render_pass,
VIEW3D_PT_gizmo_display,
VIEW3D_PT_overlay,
VIEW3D_PT_overlay_guides,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 724264fe494..011c2a8b39a 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -19,26 +19,30 @@
# <pep8 compliant>
from bpy.types import Menu, Panel, UIList
from bl_ui.properties_grease_pencil_common import (
- GreasePencilStrokeEditPanel,
- GreasePencilStrokeSculptPanel,
GreasePencilSculptOptionsPanel,
- GreasePencilAppearancePanel,
+ GreasePencilDisplayPanel,
)
from bl_ui.properties_paint_common import (
UnifiedPaintPanel,
- brush_mask_texture_settings,
- brush_texpaint_common,
- brush_texpaint_common_color,
- brush_texpaint_common_gradient,
- brush_texpaint_common_clone,
- brush_texpaint_common_options,
+ BrushSelectPanel,
+ ClonePanel,
+ TextureMaskPanel,
+ ColorPalettePanel,
+ StrokePanel,
+ SmoothStrokePanel,
+ FalloffPanel,
+ DisplayPanel,
brush_texture_settings,
+ brush_mask_texture_settings,
+ brush_settings,
+ brush_settings_advanced,
+ draw_color_settings,
)
from bl_ui.utils import PresetPanel
class VIEW3D_MT_brush_context_menu(Menu):
- bl_label = "Material Specials"
+ bl_label = "Brush Specials"
def draw(self, context):
layout = self.layout
@@ -110,9 +114,8 @@ def draw_vpaint_symmetry(layout, vpaint):
col.use_property_decorate = False
col.prop(vpaint, "radial_symmetry", text="Radial")
-# Most of these panels should not be visible in GP edit modes
-
+# Most of these panels should not be visible in GP edit modes
def is_not_gpencil_edit_mode(context):
is_gpmode = (
context.active_object and
@@ -310,7 +313,7 @@ class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel):
layout.prop(pose, "use_auto_ik")
layout.prop(pose, "use_mirror_x")
col = layout.column()
- col.active = pose.use_mirror_x
+ col.active = pose.use_mirror_x and not pose.use_auto_ik
col.prop(pose, "use_mirror_relative")
layout.label(text="Affect Only")
@@ -319,26 +322,42 @@ class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel):
# ********** default tools for paint modes ****************
-class View3DPaintPanel(UnifiedPaintPanel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
+class TEXTURE_UL_texpaintslots(UIList):
+ def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
+ # mat = data
+
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ layout.prop(item, "name", text="", emboss=False, icon_value=icon)
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label(text="")
+
+
+class View3DPaintPanel(View3DPanel, UnifiedPaintPanel):
bl_category = "Tool"
+class View3DPaintBrushPanel(View3DPaintPanel):
+ @classmethod
+ def poll(cls, context):
+ mode = cls.get_brush_mode(context)
+ return mode is not None
+
+
class VIEW3D_PT_tools_particlemode(Panel, View3DPaintPanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
- bl_label = "Particle tools"
+ bl_label = "Particle Tool"
bl_options = {'HIDE_HEADER'}
@classmethod
def poll(cls, context):
- settings = cls.paint_settings(context)
+ settings = context.tool_settings.particle_edit
return (settings and settings.brush and context.particle_edit_object)
def draw(self, context):
layout = self.layout
- settings = self.paint_settings(context)
+ settings = context.tool_settings.particle_edit
brush = settings.brush
tool = settings.tool
@@ -371,19 +390,20 @@ class VIEW3D_PT_tools_particlemode(Panel, View3DPaintPanel):
# TODO, move to space_view3d.py
-class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
- bl_context = ".paint_common" # dot on purpose (access from topbar)
- bl_label = "Brush"
+class VIEW3D_PT_tools_brush_select(Panel, View3DPaintBrushPanel, BrushSelectPanel):
+ bl_context = ".paint_common"
+ bl_label = "Brushes"
+
+
+# TODO, move to space_view3d.py
+class VIEW3D_PT_tools_brush_settings(Panel, View3DPaintBrushPanel):
+ bl_context = ".paint_common"
+ bl_label = "Brush Settings"
@classmethod
def poll(cls, context):
settings = cls.paint_settings(context)
- return (settings and
- settings.brush and
- (context.sculpt_object or
- context.vertex_paint_object or
- context.weight_paint_object or
- context.image_paint_object))
+ return settings and settings.brush is not None
def draw(self, context):
layout = self.layout
@@ -394,309 +414,67 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
settings = self.paint_settings(context)
brush = settings.brush
- if not self.is_popover:
- row = layout.row()
- row.column().template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
- row.menu("VIEW3D_MT_brush_context_menu", icon='DOWNARROW_HLT', text="")
-
- # Sculpt Mode #
- if context.sculpt_object and brush:
- from bl_ui.properties_paint_common import (
- brush_basic_sculpt_settings,
- )
-
- capabilities = brush.sculpt_capabilities
-
- col = layout.column()
-
- if not self.is_popover:
- brush_basic_sculpt_settings(col, context, brush)
-
- # normal_radius_factor
- col.separator()
- row = col.row()
- row.prop(brush, "normal_radius_factor", slider=True)
-
- if brush.sculpt_tool == 'ELASTIC_DEFORM':
- col.separator()
- row = col.row()
- row.prop(brush, "elastic_deform_type")
- row = col.row()
- row.prop(brush, "elastic_deform_volume_preservation", slider=True)
- elif brush.sculpt_tool == 'POSE':
- row = col.row()
- row.prop(brush, "pose_offset")
- row = col.row()
- row.prop(brush, "pose_smooth_iterations")
- elif brush.sculpt_tool == 'SCRAPE':
- row = col.row()
- row.prop(brush, "invert_to_scrape_fill", text = "Invert to Fill")
- elif brush.sculpt_tool == 'FILL':
- row = col.row()
- row.prop(brush, "invert_to_scrape_fill", text = "Invert to Scrape")
- elif brush.sculpt_tool == 'GRAB':
- col.separator()
- row = col.row()
- row.prop(brush, "use_grab_active_vertex")
- elif brush.sculpt_tool == 'MULTIPLANE_SCRAPE':
- row = col.row()
- row.prop(brush, "multiplane_scrape_angle")
- row = col.row()
- row.prop(brush, "use_multiplane_scrape_dynamic")
- row = col.row()
- row.prop(brush, "show_multiplane_scrape_planes_preview")
-
- # topology_rake_factor
- if (
- capabilities.has_topology_rake and
- context.sculpt_object.use_dynamic_topology_sculpting
- ):
- row = col.row()
- row.prop(brush, "topology_rake_factor", slider=True)
-
- # auto_smooth_factor and use_inverse_smooth_pressure
- if capabilities.has_auto_smooth:
- row = col.row(align=True)
- row.prop(brush, "auto_smooth_factor", slider=True)
- row.prop(brush, "use_inverse_smooth_pressure", toggle=True, text="")
-
- # normal_weight
- if capabilities.has_normal_weight:
- row = col.row(align=True)
- row.prop(brush, "normal_weight", slider=True)
-
- # crease_pinch_factor
- if capabilities.has_pinch_factor:
- row = col.row(align=True)
- if brush.sculpt_tool in {'BLOB', 'SNAKE_HOOK'}:
- row.prop(brush, "crease_pinch_factor", slider=True, text="Magnify")
- else:
- row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
-
- # rake_factor
- if capabilities.has_rake_factor:
- row = col.row(align=True)
- row.prop(brush, "rake_factor", slider=True)
-
- if brush.sculpt_tool == 'MASK':
- col.prop(brush, "mask_tool")
-
- # plane_offset, use_offset_pressure, use_plane_trim, plane_trim
- if capabilities.has_plane_offset:
- row = col.row(align=True)
- row.prop(brush, "plane_offset", slider=True)
- row.prop(brush, "use_offset_pressure", text="")
-
- col.separator()
-
- row = col.row()
- row.prop(brush, "use_plane_trim", text="Plane Trim")
- row = col.row()
- row.active = brush.use_plane_trim
- row.prop(brush, "plane_trim", slider=True, text="Distance")
-
- # height
- if capabilities.has_height:
- row = col.row()
- row.prop(brush, "height", slider=True, text="Height")
-
- # use_persistent, set_persistent_base
- if capabilities.has_persistence:
- ob = context.sculpt_object
- do_persistent = True
-
- # not supported yet for this case
- for md in ob.modifiers:
- if md.type == 'MULTIRES':
- do_persistent = False
- break
-
- if do_persistent:
- col.prop(brush, "use_persistent")
- col.operator("sculpt.set_persistent_base")
-
- # Texture Paint Mode #
+ brush_settings(layout.column(), context, brush, popover=self.is_popover)
- elif context.image_paint_object and brush:
- brush_texpaint_common(self, context, layout, brush, settings, projpaint=True)
- # Weight Paint Mode #
- elif context.weight_paint_object and brush:
- from bl_ui.properties_paint_common import (
- brush_basic_wpaint_settings,
- )
-
- col = layout.column()
+class VIEW3D_PT_tools_brush_settings_advanced(Panel, View3DPaintBrushPanel):
+ bl_context = ".paint_common"
+ bl_parent_id = "VIEW3D_PT_tools_brush_settings"
+ bl_label = "Advanced"
+ bl_options = {'DEFAULT_CLOSED'}
- if not self.is_popover:
- brush_basic_wpaint_settings(col, context, brush)
+ def draw(self, context):
+ layout = self.layout
- # Vertex Paint Mode #
- elif context.vertex_paint_object and brush:
- from bl_ui.properties_paint_common import (
- brush_basic_vpaint_settings,
- )
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
- col = layout.column()
+ settings = UnifiedPaintPanel.paint_settings(context)
+ brush = settings.brush
- if not self.is_popover:
- brush_basic_vpaint_settings(col, context, brush)
+ brush_settings_advanced(layout.column(), context, brush, self.is_popover)
class VIEW3D_PT_tools_brush_color(Panel, View3DPaintPanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
- bl_parent_id = "VIEW3D_PT_tools_brush"
+ bl_parent_id = "VIEW3D_PT_tools_brush_settings"
bl_label = "Color Picker"
@classmethod
def poll(cls, context):
settings = cls.paint_settings(context)
brush = settings.brush
+
if context.image_paint_object:
capabilities = brush.image_paint_capabilities
return capabilities.has_color
-
elif context.vertex_paint_object:
capabilities = brush.vertex_paint_capabilities
return capabilities.has_color
+ return False
+
def draw(self, context):
layout = self.layout
settings = self.paint_settings(context)
brush = settings.brush
- if context.vertex_paint_object:
- brush_texpaint_common_color(self, context, layout, brush, settings, projpaint=True)
-
- else:
- layout.prop(brush, "color_type", expand=True)
-
- if brush.color_type == 'COLOR':
- brush_texpaint_common_color(self, context, layout, brush, settings, projpaint=True)
- elif brush.color_type == 'GRADIENT':
- brush_texpaint_common_gradient(self, context, layout, brush, settings, projpaint=True)
+ draw_color_settings(context, layout, brush, color_type=not context.vertex_paint_object)
-class VIEW3D_PT_tools_brush_swatches(Panel, View3DPaintPanel):
- bl_context = ".paint_common" # dot on purpose (access from topbar)
- bl_parent_id = "VIEW3D_PT_tools_brush"
+class VIEW3D_PT_tools_brush_swatches(Panel, View3DPaintPanel, ColorPalettePanel):
+ bl_context = ".paint_common"
+ bl_parent_id = "VIEW3D_PT_tools_brush_settings"
bl_label = "Color Palette"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- settings = cls.paint_settings(context)
- brush = settings.brush
- if context.image_paint_object:
- capabilities = brush.image_paint_capabilities
- return capabilities.has_color
-
- elif context.vertex_paint_object:
- capabilities = brush.vertex_paint_capabilities
- return capabilities.has_color
-
- def draw(self, context):
- layout = self.layout
- settings = self.paint_settings(context)
-
- layout.template_ID(settings, "palette", new="palette.new")
- if settings.palette:
- layout.template_palette(settings, "palette", color=True)
-
-class VIEW3D_PT_tools_brush_clone(Panel, View3DPaintPanel):
- bl_context = ".paint_common" # dot on purpose (access from topbar)
- bl_parent_id = "VIEW3D_PT_tools_brush"
+class VIEW3D_PT_tools_brush_clone(Panel, View3DPaintPanel, ClonePanel):
+ bl_context = ".paint_common"
+ bl_parent_id = "VIEW3D_PT_tools_brush_settings"
bl_label = "Clone from Paint Slot"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- settings = cls.paint_settings(context)
- brush = settings.brush
-
- return brush.image_tool == 'CLONE'
-
- def draw_header(self, context):
- settings = self.paint_settings(context)
- self.layout.prop(settings, "use_clone_layer", text="")
-
- def draw(self, context):
- layout = self.layout
- settings = self.paint_settings(context)
- brush = settings.brush
-
- layout.active = settings.use_clone_layer
-
- brush_texpaint_common_clone(self, context, layout, brush, settings, projpaint=True)
-
-
-class VIEW3D_PT_tools_brush_options(Panel, View3DPaintPanel):
- bl_context = ".paint_common" # dot on purpose (access from topbar)
- bl_parent_id = "VIEW3D_PT_tools_brush"
- bl_label = "Options"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw(self, context):
- layout = self.layout
- tool_settings = context.tool_settings
- settings = self.paint_settings(context)
- brush = settings.brush
- capabilities = brush.sculpt_capabilities
-
- layout.use_property_split = True
- layout.use_property_decorate = False # No animation.
-
- col = layout.column()
-
- if context.image_paint_object and brush:
- brush_texpaint_common_options(self, context, layout, brush, settings, projpaint=True)
-
- elif context.sculpt_object and brush:
- col.prop(brush, "use_automasking_topology")
- if capabilities.has_accumulate:
- col.prop(brush, "use_accumulate")
-
- UnifiedPaintPanel.prop_unified_size(col, context, brush, "use_locked_size")
-
- if capabilities.has_sculpt_plane:
- col.prop(brush, "sculpt_plane")
- col.prop(brush, "use_original_normal")
- col.prop(brush, "use_original_plane")
-
- col.prop(brush, "use_frontface", text="Front Faces Only")
- col.prop(brush, "use_projected")
-
- elif context.weight_paint_object and brush:
-
- if brush.weight_tool != 'SMEAR':
- col.prop(brush, "use_accumulate")
-
- col.prop(brush, "use_frontface", text="Front Faces Only")
- col.prop(brush, "use_projected")
- col.prop(tool_settings, "use_auto_normalize", text="Auto Normalize")
- col.prop(tool_settings, "use_multipaint", text="Multi-Paint")
-
- elif context.vertex_paint_object and brush:
-
- if brush.vertex_tool != 'SMEAR':
- col.prop(brush, "use_accumulate")
-
- col.prop(brush, "use_alpha")
- col.prop(brush, "use_frontface", text="Front Faces Only")
- col.prop(brush, "use_projected")
-
-
-class TEXTURE_UL_texpaintslots(UIList):
- def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
- # mat = data
-
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- layout.prop(item, "name", text="", emboss=False, icon_value=icon)
- elif self.layout_type == 'GRID':
- layout.alignment = 'CENTER'
- layout.label(text="")
-
class VIEW3D_MT_tools_projectpaint_uvlayer(Menu):
bl_label = "Clone Layer"
@@ -718,8 +496,7 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
@classmethod
def poll(cls, context):
brush = context.tool_settings.image_paint.brush
- ob = context.active_object
- return (brush is not None and ob is not None)
+ return (brush is not None and context.active_object is not None)
def draw(self, context):
layout = self.layout
@@ -782,9 +559,8 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
layout.separator()
layout.operator("image.save_all_modified", text="Save All Images", icon='FILE_TICK')
-# TODO, move to space_view3d.py
-
+# TODO, move to space_view3d.py
class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
bl_category = "Tool"
bl_context = ".imagepaint" # dot on purpose (access from topbar)
@@ -836,73 +612,17 @@ class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
# TODO, move to space_view3d.py
-class VIEW3D_PT_tools_brush_display(Panel, View3DPaintPanel):
- bl_context = ".paint_common" # dot on purpose (access from topbar)
- bl_label = "Display"
+class VIEW3D_PT_tools_brush_display(Panel, View3DPaintBrushPanel, DisplayPanel):
+ bl_context = ".paint_common"
+ bl_parent_id = "VIEW3D_PT_tools_brush_settings"
+ bl_label = "Cursor"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- settings = cls.paint_settings(context)
- return (settings and
- settings.brush and
- (context.sculpt_object or
- context.vertex_paint_object or
- context.weight_paint_object or
- context.image_paint_object))
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- settings = self.paint_settings(context)
- brush = settings.brush
- tex_slot = brush.texture_slot
- tex_slot_mask = brush.mask_texture_slot
-
- col = layout.column()
-
- row = col.row(align=True)
-
- sub = row.row(align=True)
- sub.prop(brush, "cursor_overlay_alpha", text="Curve Alpha")
- sub.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
- row.prop(
- brush, "use_cursor_overlay", text="", toggle=True,
- icon='HIDE_OFF' if brush.use_cursor_overlay else 'HIDE_ON',
- )
-
- col.active = brush.brush_capabilities.has_overlay
-
- if context.image_paint_object or context.sculpt_object or context.vertex_paint_object:
- row = col.row(align=True)
-
- sub = row.row(align=True)
- sub.prop(brush, "texture_overlay_alpha", text="Texture Alpha")
- sub.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
- if tex_slot.map_mode != 'STENCIL':
- row.prop(
- brush, "use_primary_overlay", text="", toggle=True,
- icon='HIDE_OFF' if brush.use_primary_overlay else 'HIDE_ON',
- )
-
- if context.image_paint_object:
- row = col.row(align=True)
-
- sub = row.row(align=True)
- sub.prop(brush, "mask_overlay_alpha", text="Mask Texture Alpha")
- sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
- if tex_slot_mask.map_mode != 'STENCIL':
- row.prop(
- brush, "use_secondary_overlay", text="", toggle=True,
- icon='HIDE_OFF' if brush.use_secondary_overlay else 'HIDE_ON',
- )
-
# TODO, move to space_view3d.py
class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
- bl_context = ".paint_common" # dot on purpose (access from topbar)
+ bl_context = ".paint_common"
+ bl_parent_id = "VIEW3D_PT_tools_brush_settings"
bl_label = "Texture"
bl_options = {'DEFAULT_CLOSED'}
@@ -926,9 +646,10 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
# TODO, move to space_view3d.py
-class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel):
+class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel, TextureMaskPanel):
bl_category = "Tool"
bl_context = ".imagepaint" # dot on purpose (access from topbar)
+ bl_parent_id = "VIEW3D_PT_tools_brush_settings"
bl_label = "Texture Mask"
bl_options = {'DEFAULT_CLOSED'}
@@ -950,151 +671,27 @@ class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel):
# TODO, move to space_view3d.py
-class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
+class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel, StrokePanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_label = "Stroke"
+ bl_parent_id = "VIEW3D_PT_tools_brush_settings"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- settings = cls.paint_settings(context)
- return (settings and
- settings.brush and
- (context.sculpt_object or
- context.vertex_paint_object or
- context.weight_paint_object or
- context.image_paint_object))
-
- def draw(self, context):
- layout = self.layout
-
- settings = self.paint_settings(context)
- brush = settings.brush
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- col = layout.column()
-
- col.prop(brush, "stroke_method")
-
- if brush.use_anchor:
- col.prop(brush, "use_edge_to_edge", text="Edge To Edge")
-
- if brush.use_airbrush:
- col.prop(brush, "rate", text="Rate", slider=True)
-
- if brush.use_space:
- row = col.row(align=True)
- row.prop(brush, "spacing", text="Spacing")
- row.prop(brush, "use_pressure_spacing", toggle=True, text="")
- col.prop(brush, "dash_ratio")
- col.prop(brush, "dash_samples")
-
- if brush.use_line or brush.use_curve:
- row = col.row(align=True)
- row.prop(brush, "spacing", text="Spacing")
- col.prop(brush, "dash_ratio")
- col.prop(brush, "dash_samples")
-
- if brush.use_curve:
- col.template_ID(brush, "paint_curve", new="paintcurve.new")
- col.operator("paintcurve.draw")
-
- if context.sculpt_object:
-
- if brush.sculpt_capabilities.has_space_attenuation:
- col.prop(brush, "use_space_attenuation")
-
- col.prop(brush, "use_scene_spacing")
-
- if brush.sculpt_capabilities.has_jitter:
-
- row = col.row(align=True)
- if brush.use_relative_jitter:
- row.prop(brush, "jitter", slider=True)
- else:
- row.prop(brush, "jitter_absolute")
- row.prop(brush, "use_relative_jitter", icon_only=True)
- row.prop(brush, "use_pressure_jitter", toggle=True, text="")
-
- else:
-
- row = col.row(align=True)
- if brush.use_relative_jitter:
- row.prop(brush, "jitter", slider=True)
- else:
- row.prop(brush, "jitter_absolute")
- row.prop(brush, "use_relative_jitter", icon_only=True)
- row.prop(brush, "use_pressure_jitter", toggle=True, text="")
-
- col.prop(settings, "input_samples")
-
-class VIEW3D_PT_tools_brush_stroke_smooth_stroke(Panel, View3DPaintPanel):
+class VIEW3D_PT_tools_brush_stroke_smooth_stroke(Panel, View3DPaintPanel, SmoothStrokePanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
- bl_label = "Smooth Stroke"
+ bl_label = "Stabilize Stroke"
bl_parent_id = "VIEW3D_PT_tools_brush_stroke"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- settings = cls.paint_settings(context)
- brush = settings.brush
- if brush.brush_capabilities.has_smooth_stroke:
- return True
-
- def draw_header(self, context):
- settings = self.paint_settings(context)
- brush = settings.brush
-
- self.layout.prop(brush, "use_smooth_stroke", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- settings = self.paint_settings(context)
- brush = settings.brush
-
- col = layout.column()
- col.active = brush.use_smooth_stroke
- col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
- col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
-
# TODO, move to space_view3d.py
-class VIEW3D_PT_tools_brush_falloff(Panel, View3DPaintPanel):
+class VIEW3D_PT_tools_brush_falloff(Panel, View3DPaintPanel, FalloffPanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
+ bl_parent_id = "VIEW3D_PT_tools_brush_settings"
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- settings = cls.paint_settings(context)
- return (settings and settings.brush and settings.brush.curve)
-
- def draw(self, context):
- layout = self.layout
- settings = self.paint_settings(context)
- brush = settings.brush
-
- col = layout.column(align=True)
- row = col.row(align=True)
- row.prop(brush, "curve_preset", text="")
-
- if brush.curve_preset == 'CUSTOM':
- layout.template_curve_mapping(brush, "curve", brush=True)
-
- col = layout.column(align=True)
- row = col.row(align=True)
- row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
- row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
- row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
- row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
- row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
- row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
-
class VIEW3D_PT_tools_brush_falloff_frontface(View3DPaintPanel, Panel):
bl_context = ".imagepaint" # dot on purpose (access from topbar)
@@ -1193,7 +790,8 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
row = sub.row(align=True)
row.prop(sculpt, "constant_detail_resolution")
- row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER')
+ props = row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER')
+ props.mode = 'DYNTOPO'
elif (sculpt.detail_type_method == 'BRUSH'):
sub.prop(sculpt, "detail_percent")
else:
@@ -1252,7 +850,10 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
col = layout.column()
mesh = context.active_object.data
- col.prop(mesh, "remesh_voxel_size")
+ row = col.row(align=True)
+ row.prop(mesh, "remesh_voxel_size")
+ props = row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER')
+ props.mode = 'VOXEL'
col.prop(mesh, "remesh_voxel_adaptivity")
col.prop(mesh, "use_remesh_fix_poles")
col.prop(mesh, "use_remesh_smooth_normals")
@@ -1260,9 +861,8 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
col.prop(mesh, "use_remesh_preserve_paint_mask")
col.operator("object.voxel_remesh", text="Remesh")
-# TODO, move to space_view3d.py
-
+# TODO, move to space_view3d.py
class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
bl_label = "Options"
@@ -1290,23 +890,6 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
col.prop(sculpt, "use_deform_only")
-class VIEW3D_PT_sculpt_options_unified(Panel, View3DPaintPanel):
- bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
- bl_parent_id = "VIEW3D_PT_sculpt_options"
- bl_label = "Unified Brush"
-
- @classmethod
- def poll(cls, context):
- return (context.sculpt_object and context.tool_settings.sculpt)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- self.unified_paint_settings(layout, context)
-
-
class VIEW3D_PT_sculpt_options_gravity(Panel, View3DPaintPanel):
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
bl_parent_id = "VIEW3D_PT_sculpt_options"
@@ -1405,64 +988,6 @@ class VIEW3D_PT_sculpt_symmetry_for_topbar(Panel):
draw = VIEW3D_PT_sculpt_symmetry.draw
-class VIEW3D_PT_tools_brush_display_show_brush(Panel, View3DPaintPanel):
- bl_context = ".paint_common" # dot on purpose (access from topbar)
- bl_label = "Show Brush"
- bl_parent_id = "VIEW3D_PT_tools_brush_display"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, context):
- settings = self.paint_settings(context)
-
- self.layout.prop(settings, "show_brush", text="")
-
- def draw(self, context):
- layout = self.layout
-
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- settings = self.paint_settings(context)
- brush = settings.brush
-
- col = layout.column()
- col.active = settings.show_brush
-
- if context.sculpt_object and context.tool_settings.sculpt:
- if brush.sculpt_capabilities.has_secondary_color:
- col.prop(brush, "cursor_color_add", text="Add")
- col.prop(brush, "cursor_color_subtract", text="Subtract")
- else:
- col.prop(brush, "cursor_color_add", text="Color")
- else:
- col.prop(brush, "cursor_color_add", text="Color")
-
-
-class VIEW3D_PT_tools_brush_display_custom_icon(Panel, View3DPaintPanel):
- bl_context = ".paint_common" # dot on purpose (access from topbar)
- bl_label = "Custom Icon"
- bl_parent_id = "VIEW3D_PT_tools_brush_display"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, context):
- settings = self.paint_settings(context)
- brush = settings.brush
-
- self.layout.prop(brush, "use_custom_icon", text="")
-
- def draw(self, context):
- layout = self.layout
-
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- settings = self.paint_settings(context)
- brush = settings.brush
-
- col = layout.column()
- col.active = brush.use_custom_icon
- col.prop(brush, "icon_filepath", text="")
-
# ********** default tools for weight-paint ****************
@@ -1508,6 +1033,10 @@ class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
wpaint = tool_settings.weight_paint
col = layout.column()
+
+ col.prop(tool_settings, "use_auto_normalize", text="Auto Normalize")
+ col.prop(tool_settings, "use_multipaint", text="Multi-Paint")
+
col.prop(wpaint, "use_group_restrict")
obj = context.weight_paint_object
@@ -1519,19 +1048,6 @@ class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
row.prop(mesh, "use_mirror_topology")
-class VIEW3D_PT_tools_weightpaint_options_unified(Panel, View3DPaintPanel):
- bl_context = ".weightpaint"
- bl_label = "Unified Brush"
- bl_parent_id = "VIEW3D_PT_tools_weightpaint_options"
-
- def draw(self, context):
- layout = self.layout
-
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- self.unified_paint_settings(layout, context)
-
# ********** default tools for vertex-paint ****************
@@ -1541,16 +1057,16 @@ class VIEW3D_PT_tools_vertexpaint_options(Panel, View3DPaintPanel):
bl_label = "Options"
bl_options = {'DEFAULT_CLOSED'}
- def draw(self, context):
- layout = self.layout
-
- layout.label(text="Unified Brush")
+ @classmethod
+ def poll(self, _context):
+ # This is currently unused, since there aren't any Vertex Paint mode specific options.
+ return False
+ def draw(self, _context):
+ layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
- self.unified_paint_settings(layout, context)
-
# TODO, move to space_view3d.py
class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel):
@@ -1672,19 +1188,6 @@ class VIEW3D_PT_tools_imagepaint_options(View3DPaintPanel, Panel):
col.prop(ipaint, "use_backface_culling", text="Backface Culling")
-class VIEW3D_PT_tools_imagepaint_options_unified(Panel, View3DPaintPanel):
- bl_context = ".imagepaint" # dot on purpose (access from topbar)
- bl_parent_id = "VIEW3D_PT_tools_imagepaint_options"
- bl_label = "Unified Brush"
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
-
- self.unified_paint_settings(layout, context)
-
-
class VIEW3D_PT_tools_imagepaint_options_cavity(View3DPaintPanel, Panel):
bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Cavity Mask"
@@ -1714,14 +1217,15 @@ class VIEW3D_PT_imagepaint_options(View3DPaintPanel):
bl_label = "Options"
@classmethod
- def poll(cls, context):
- return (context.image_paint_object and context.tool_settings.image_paint)
+ def poll(cls, _context):
+ # This is currently unused, since there aren't any Vertex Paint mode specific options.
+ return False
+ # return (context.image_paint_object and context.tool_settings.image_paint)
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
-
- col = layout.column()
- self.unified_paint_settings(col, context)
+ layout.use_property_split = True
+ layout.use_property_decorate = False
class VIEW3D_MT_tools_projectpaint_stencil(Menu):
@@ -1779,6 +1283,8 @@ class VIEW3D_PT_tools_particlemode_options(View3DPanel, Panel):
col = layout.column(align=True)
col.active = pe.is_editable
col.prop(ob.data, "use_mirror_x")
+ if pe.tool == 'ADD':
+ col.prop(ob.data, "use_mirror_topology")
col.separator()
col.prop(pe, "use_preserve_length", text="Preserve Strand Lengths")
col.prop(pe, "use_preserve_root", text="Preserve Root Positions")
@@ -1838,15 +1344,13 @@ class VIEW3D_PT_tools_particlemode_options_display(View3DPanel, Panel):
# Grease Pencil drawing brushes
-class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
+class GreasePencilPanel:
bl_context = ".greasepencil_paint"
- bl_label = "Brush"
bl_category = "Tool"
@classmethod
def poll(cls, context):
- is_3d_view = context.space_data.type == 'VIEW_3D'
- if is_3d_view:
+ if context.space_data.type in {'VIEW_3D', 'PROPERTIES'}:
if context.gpencil_data is None:
return False
@@ -1855,6 +1359,10 @@ class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
else:
return True
+
+class VIEW3D_PT_tools_grease_pencil_brush_select(Panel, View3DPanel, GreasePencilPanel):
+ bl_label = "Brushes"
+
def draw(self, context):
layout = self.layout
layout.use_property_split = True
@@ -1864,14 +1372,38 @@ class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
gpencil_paint = tool_settings.gpencil_paint
row = layout.row()
- col = row.column()
- col.template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8)
+ row.column().template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8)
col = row.column()
- brush = gpencil_paint.brush
+ col.operator("gpencil.brush_presets_create", icon='PRESET_NEW', text="")
+
+ if context.mode == 'PAINT_GPENCIL':
+ brush = tool_settings.gpencil_paint.brush
+ if brush is not None:
+ gp_settings = brush.gpencil_settings
+
+ col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="")
+
+ if brush.use_custom_icon:
+ layout.row().prop(brush, "icon_filepath", text="")
- sub = col.column(align=True)
- sub.operator("gpencil.brush_presets_create", icon='PRESET_NEW', text="")
+
+class VIEW3D_PT_tools_grease_pencil_brush_settings(Panel, View3DPanel, GreasePencilPanel):
+ bl_label = "Brush Settings"
+
+ # What is the point of brush presets? Seems to serve the exact same purpose as brushes themselves??
+ def draw_header_preset(self, _context):
+ VIEW3D_PT_gpencil_brush_presets.draw_panel_header(self.layout)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ tool_settings = context.scene.tool_settings
+ gpencil_paint = tool_settings.gpencil_paint
+
+ brush = gpencil_paint.brush
if brush is not None:
gp_settings = brush.gpencil_settings
@@ -1891,63 +1423,87 @@ class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
from bl_ui.properties_paint_common import (
brush_basic_gpencil_paint_settings,
)
- tool = context.workspace.tools.from_space_view3d_mode(context.mode, create=False)
- brush_basic_gpencil_paint_settings(layout, context, brush, tool, compact=True, is_toolbar=False)
+ brush_basic_gpencil_paint_settings(layout, context, brush, compact=False)
-# Grease Pencil drawing brushes options
-class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel):
+class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
- bl_label = "Options"
+ bl_label = "Advanced"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_settings'
bl_category = "Tool"
+ bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
brush = context.tool_settings.gpencil_paint.brush
- return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL'}
-
- def draw_header_preset(self, _context):
- VIEW3D_PT_gpencil_brush_presets.draw_panel_header(self.layout)
+ return brush is not None and brush.gpencil_tool != 'ERASE'
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
- brush = context.tool_settings.gpencil_paint.brush
+ tool_settings = context.scene.tool_settings
+ gpencil_paint = tool_settings.gpencil_paint
+ brush = gpencil_paint.brush
+ gp_settings = brush.gpencil_settings
+ col = layout.column(align=True)
if brush is not None:
- gp_settings = brush.gpencil_settings
- col = layout.column(align=True)
- col.prop(gp_settings, "input_samples")
- col.separator()
+ if brush.gpencil_tool != 'FILL':
+ col.prop(gp_settings, "input_samples")
+ col.separator()
- col.prop(gp_settings, "active_smooth_factor")
- col.separator()
+ col.prop(gp_settings, "active_smooth_factor")
+ col.separator()
- col.prop(gp_settings, "angle", slider=True)
- col.prop(gp_settings, "angle_factor", text="Factor", slider=True)
+ col.prop(gp_settings, "angle", slider=True)
+ col.prop(gp_settings, "angle_factor", text="Factor", slider=True)
- ob = context.object
- if ob and brush.gpencil_settings.use_material_pin is False:
- ma = ob.active_material
- elif brush.gpencil_settings.material:
- ma = brush.gpencil_settings.material
- else:
+ ob = context.object
ma = None
+ if ob and brush.gpencil_settings.use_material_pin is False:
+ ma = ob.active_material
+ elif brush.gpencil_settings.material:
+ ma = brush.gpencil_settings.material
+
+ col.separator()
+ subcol = col.column(align=True)
+ if ma and ma.grease_pencil.mode == 'LINE':
+ subcol.enabled = False
+ subcol.prop(gp_settings, "gradient_factor", slider=True)
+ subcol.prop(gp_settings, "gradient_shape")
+
+ elif brush.gpencil_tool == 'FILL':
+ row = col.row(align=True)
+ row.prop(gp_settings, "fill_draw_mode", text="Boundary")
+ row.prop(gp_settings, "show_fill_boundary", text="", icon='GRID')
+ col.separator()
+ col.prop(gp_settings, "fill_factor", text="Resolution")
+ if gp_settings.fill_draw_mode != 'STROKE':
+ col.prop(gp_settings, "show_fill", text="Ignore Transparent Strokes")
+ col.prop(gp_settings, "fill_threshold", text="Threshold")
+
+class VIEW3D_PT_tools_grease_pencil_brush_stroke(Panel, View3DPanel):
+ bl_context = ".greasepencil_paint"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_settings'
+ bl_label = "Stroke"
+ bl_category = "Tool"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ brush = context.tool_settings.gpencil_paint.brush
+ return brush is not None and brush.gpencil_tool == 'DRAW'
- col.separator()
- subcol = col.column(align=True)
- if ma and ma.grease_pencil.mode == 'LINE':
- subcol.enabled = False
- subcol.prop(gp_settings, "gradient_factor", slider=True)
- subcol.prop(gp_settings, "gradient_shape")
+ def draw(self, context):
+ layout = self.layout
-class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel):
+class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(Panel, View3DPanel):
bl_context = ".greasepencil_paint"
- bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
- bl_label = "Stabilize"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_stroke'
+ bl_label = "Stabilize Stroke"
bl_category = "Tool"
bl_options = {'DEFAULT_CLOSED'}
@@ -1957,6 +1513,9 @@ class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel):
return brush is not None and brush.gpencil_tool == 'DRAW'
def draw_header(self, context):
+ if self.is_popover:
+ return
+
brush = context.tool_settings.gpencil_paint.brush
gp_settings = brush.gpencil_settings
self.layout.prop(gp_settings, "use_settings_stabilizer", text="")
@@ -1968,24 +1527,35 @@ class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel):
brush = context.tool_settings.gpencil_paint.brush
gp_settings = brush.gpencil_settings
- layout.active = gp_settings.use_settings_stabilizer
- layout.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
- layout.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
+ if self.is_popover:
+ row = layout.row()
+ row.prop(gp_settings, "use_settings_stabilizer", text="")
+ row.label(text=self.bl_label)
+
+ col = layout.column()
+ col.active = gp_settings.use_settings_stabilizer
+
+ col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
+ col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
-class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel):
+class VIEW3D_PT_tools_grease_pencil_brush_post_processing(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
- bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_stroke'
bl_label = "Post-Processing"
bl_category = "Tool"
+ bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
brush = context.tool_settings.gpencil_paint.brush
- return brush is not None and brush.gpencil_tool != 'ERASE'
+ return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL'}
def draw_header(self, context):
+ if self.is_popover:
+ return
+
brush = context.tool_settings.gpencil_paint.brush
gp_settings = brush.gpencil_settings
self.layout.prop(gp_settings, "use_settings_postprocess", text="")
@@ -1997,30 +1567,37 @@ class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel):
brush = context.tool_settings.gpencil_paint.brush
gp_settings = brush.gpencil_settings
- layout.active = gp_settings.use_settings_postprocess
- col = layout.column(align=True)
- col.prop(gp_settings, "pen_smooth_factor")
- col.prop(gp_settings, "pen_smooth_steps")
+ if self.is_popover:
+ row = layout.row()
+ row.prop(gp_settings, "use_settings_postprocess", text="")
+ row.label(text=self.bl_label)
- col = layout.column(align=True)
- col.prop(gp_settings, "pen_thick_smooth_factor")
- col.prop(gp_settings, "pen_thick_smooth_steps", text="Iterations")
+ col = layout.column()
+ col.active = gp_settings.use_settings_postprocess
- col = layout.column(align=True)
- col.prop(gp_settings, "pen_subdivision_steps")
- col.prop(gp_settings, "random_subdiv", text="Randomness", slider=True)
+ col1 = col.column(align=True)
+ col1.prop(gp_settings, "pen_smooth_factor")
+ col1.prop(gp_settings, "pen_smooth_steps")
- col = layout.column(align=True)
- col.prop(gp_settings, "simplify_factor")
+ col1 = col.column(align=True)
+ col1.prop(gp_settings, "pen_thick_smooth_factor")
+ col1.prop(gp_settings, "pen_thick_smooth_steps", text="Iterations")
- col = layout.column(align=True)
- col.prop(gp_settings, "trim")
+ col1 = col.column(align=True)
+ col1.prop(gp_settings, "pen_subdivision_steps")
+ col1.prop(gp_settings, "random_subdiv", text="Randomness", slider=True)
+
+ col1 = col.column(align=True)
+ col1.prop(gp_settings, "simplify_factor")
+
+ col1 = col.column(align=True)
+ col1.prop(gp_settings, "trim")
class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
- bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_stroke'
bl_label = "Randomize"
bl_category = "Tool"
bl_options = {'DEFAULT_CLOSED'}
@@ -2028,9 +1605,12 @@ class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
@classmethod
def poll(cls, context):
brush = context.tool_settings.gpencil_paint.brush
- return brush is not None and brush.gpencil_tool != 'ERASE'
+ return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL'}
def draw_header(self, context):
+ if self.is_popover:
+ return
+
brush = context.tool_settings.gpencil_paint.brush
gp_settings = brush.gpencil_settings
self.layout.prop(gp_settings, "use_settings_random", text="")
@@ -2042,13 +1622,20 @@ class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
brush = context.tool_settings.gpencil_paint.brush
gp_settings = brush.gpencil_settings
- layout.active = gp_settings.use_settings_random
- layout.prop(gp_settings, "random_pressure", text="Pressure", slider=True)
- layout.prop(gp_settings, "random_strength", text="Strength", slider=True)
- layout.prop(gp_settings, "uv_random", text="UV", slider=True)
+ if self.is_popover:
+ row = layout.row()
+ row.prop(gp_settings, "use_settings_random", text="")
+ row.label(text=self.bl_label)
- row = layout.row(align=True)
+ col = layout.column()
+ col.active = gp_settings.use_settings_random
+
+ col.prop(gp_settings, "random_pressure", text="Pressure", slider=True)
+ col.prop(gp_settings, "random_strength", text="Strength", slider=True)
+ col.prop(gp_settings, "uv_random", text="UV", slider=True)
+
+ row = col.row(align=True)
row.prop(gp_settings, "pen_jitter", slider=True)
row.prop(gp_settings, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE')
@@ -2056,6 +1643,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
# Grease Pencil drawingcurves
class VIEW3D_PT_tools_grease_pencil_brushcurves(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_settings'
bl_label = "Curves"
bl_category = "Tool"
bl_options = {'DEFAULT_CLOSED'}
@@ -2120,12 +1708,6 @@ class VIEW3D_PT_tools_grease_pencil_brushcurves_jitter(View3DPanel, Panel):
use_negative_slope=True)
-# Grease Pencil stroke editing tools
-class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
- bl_space_type = 'VIEW_3D'
- bl_category = "Tool"
-
-
# Grease Pencil stroke interpolation tools
class VIEW3D_PT_tools_grease_pencil_interpolate(Panel):
bl_space_type = 'VIEW_3D'
@@ -2174,18 +1756,47 @@ class VIEW3D_PT_tools_grease_pencil_interpolate(Panel):
# Grease Pencil stroke sculpting tools
-class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, View3DPanel, Panel):
+
+class VIEW3D_PT_tools_grease_pencil_sculpt_select(Panel, View3DPanel):
bl_context = ".greasepencil_sculpt"
- bl_category = "Tools"
- bl_label = "Brush"
+ bl_label = "Brushes"
bl_category = "Tool"
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ settings = context.tool_settings.gpencil_sculpt
+
+ layout.template_icon_view(settings, "sculpt_tool", show_labels=True)
+
+
+class VIEW3D_PT_tools_grease_pencil_sculpt_settings(Panel, View3DPanel):
+ bl_context = ".greasepencil_sculpt"
+ bl_category = "Tool"
+ bl_label = "Brush Settings"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ settings = context.tool_settings.gpencil_sculpt
+ brush = settings.brush
+
+ if not self.is_popover:
+ from bl_ui.properties_paint_common import (
+ brush_basic_gpencil_sculpt_settings,
+ )
+ brush_basic_gpencil_sculpt_settings(layout, context, brush)
# Grease Pencil weight painting tools
-class VIEW3D_PT_tools_grease_pencil_weight_paint(View3DPanel, Panel):
+
+
+class VIEW3D_PT_tools_grease_pencil_weight_paint_select(View3DPanel, Panel):
bl_context = ".greasepencil_weight"
- bl_category = "Tools"
- bl_label = "Brush"
+ bl_label = "Brushes"
bl_category = "Tool"
def draw(self, context):
@@ -2194,46 +1805,60 @@ class VIEW3D_PT_tools_grease_pencil_weight_paint(View3DPanel, Panel):
layout.use_property_decorate = False
settings = context.tool_settings.gpencil_sculpt
- brush = settings.brush
layout.template_icon_view(settings, "weight_tool", show_labels=True)
- col = layout.column()
+
+class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel):
+ bl_context = ".greasepencil_weight"
+ bl_category = "Tool"
+ bl_label = "Brush Settings"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ settings = context.tool_settings.gpencil_sculpt
+ brush = settings.brush
if not self.is_popover:
from bl_ui.properties_paint_common import (
brush_basic_gpencil_weight_settings,
)
- brush_basic_gpencil_weight_settings(col, context, brush)
+ brush_basic_gpencil_weight_settings(layout, context, brush)
-# Grease Pencil Brush Appearance (one for each mode)
-class VIEW3D_PT_tools_grease_pencil_paint_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
- bl_context = ".greasepencil_paint"
- bl_label = "Display"
+class VIEW3D_PT_tools_grease_pencil_sculpt_options(GreasePencilSculptOptionsPanel, Panel, View3DPanel):
+ bl_context = ".greasepencil_sculpt"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_sculpt_settings'
bl_category = "Tool"
+ bl_label = "Sculpt Strokes"
-class VIEW3D_PT_tools_grease_pencil_sculpt_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
- bl_context = ".greasepencil_sculpt"
- bl_label = "Display"
+# Grease Pencil Brush Appearance (one for each mode)
+class VIEW3D_PT_tools_grease_pencil_paint_appearance(GreasePencilDisplayPanel, Panel, View3DPanel):
+ bl_context = ".greasepencil_paint"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_settings'
+ bl_label = "Cursor"
bl_category = "Tool"
-class VIEW3D_PT_tools_grease_pencil_sculpt_options(GreasePencilSculptOptionsPanel, View3DPanel, Panel):
+class VIEW3D_PT_tools_grease_pencil_sculpt_appearance(GreasePencilDisplayPanel, Panel, View3DPanel):
bl_context = ".greasepencil_sculpt"
- bl_label = "Sculpt Strokes"
- bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_sculpt'
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_sculpt_settings'
+ bl_label = "Cursor"
bl_category = "Tool"
-class VIEW3D_PT_tools_grease_pencil_weight_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
+class VIEW3D_PT_tools_grease_pencil_weight_appearance(GreasePencilDisplayPanel, Panel, View3DPanel):
bl_context = ".greasepencil_weight"
- bl_label = "Display"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_weight_paint_settings'
bl_category = "Tool"
+ bl_label = "Cursor"
-class VIEW3D_PT_gpencil_brush_presets(PresetPanel, Panel):
+class VIEW3D_PT_gpencil_brush_presets(Panel, PresetPanel):
"""Brush settings"""
bl_label = "Brush Presets"
preset_subdir = "gpencil_brush"
@@ -2251,12 +1876,14 @@ classes = (
VIEW3D_PT_tools_curveedit_options_stroke,
VIEW3D_PT_tools_armatureedit_options,
VIEW3D_PT_tools_posemode_options,
+
VIEW3D_PT_slots_projectpaint,
- VIEW3D_PT_tools_brush,
+ VIEW3D_PT_tools_brush_select,
+ VIEW3D_PT_tools_brush_settings,
VIEW3D_PT_tools_brush_color,
VIEW3D_PT_tools_brush_swatches,
+ VIEW3D_PT_tools_brush_settings_advanced,
VIEW3D_PT_tools_brush_clone,
- VIEW3D_PT_tools_brush_options,
TEXTURE_UL_texpaintslots,
VIEW3D_MT_tools_projectpaint_uvlayer,
VIEW3D_PT_stencil_projectpaint,
@@ -2268,49 +1895,53 @@ classes = (
VIEW3D_PT_tools_brush_falloff_frontface,
VIEW3D_PT_tools_brush_falloff_normal,
VIEW3D_PT_tools_brush_display,
- VIEW3D_PT_tools_brush_display_show_brush,
- VIEW3D_PT_tools_brush_display_custom_icon,
+
VIEW3D_PT_sculpt_dyntopo,
VIEW3D_PT_sculpt_dyntopo_remesh,
VIEW3D_PT_sculpt_voxel_remesh,
VIEW3D_PT_sculpt_symmetry,
VIEW3D_PT_sculpt_symmetry_for_topbar,
VIEW3D_PT_sculpt_options,
- VIEW3D_PT_sculpt_options_unified,
VIEW3D_PT_sculpt_options_gravity,
+
VIEW3D_PT_tools_weightpaint_symmetry,
VIEW3D_PT_tools_weightpaint_symmetry_for_topbar,
VIEW3D_PT_tools_weightpaint_options,
- VIEW3D_PT_tools_weightpaint_options_unified,
+
VIEW3D_PT_tools_vertexpaint_symmetry,
VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar,
VIEW3D_PT_tools_vertexpaint_options,
+
VIEW3D_PT_tools_imagepaint_symmetry,
VIEW3D_PT_tools_imagepaint_options,
VIEW3D_PT_tools_imagepaint_options_cavity,
- VIEW3D_PT_tools_imagepaint_options_unified,
VIEW3D_PT_tools_imagepaint_options_external,
VIEW3D_MT_tools_projectpaint_stencil,
+
VIEW3D_PT_tools_particlemode,
VIEW3D_PT_tools_particlemode_options,
VIEW3D_PT_tools_particlemode_options_shapecut,
VIEW3D_PT_tools_particlemode_options_display,
VIEW3D_PT_gpencil_brush_presets,
- VIEW3D_PT_tools_grease_pencil_brush,
- VIEW3D_PT_tools_grease_pencil_brush_option,
+ VIEW3D_PT_tools_grease_pencil_brush_select,
VIEW3D_PT_tools_grease_pencil_brush_settings,
- VIEW3D_PT_tools_grease_pencil_brush_stabilizer,
+ VIEW3D_PT_tools_grease_pencil_brush_advanced,
+ VIEW3D_PT_tools_grease_pencil_brush_stroke,
+ VIEW3D_PT_tools_grease_pencil_brush_post_processing,
VIEW3D_PT_tools_grease_pencil_brush_random,
+ VIEW3D_PT_tools_grease_pencil_brush_stabilizer,
VIEW3D_PT_tools_grease_pencil_brushcurves,
VIEW3D_PT_tools_grease_pencil_brushcurves_sensitivity,
VIEW3D_PT_tools_grease_pencil_brushcurves_strength,
VIEW3D_PT_tools_grease_pencil_brushcurves_jitter,
- VIEW3D_PT_tools_grease_pencil_sculpt,
- VIEW3D_PT_tools_grease_pencil_weight_paint,
VIEW3D_PT_tools_grease_pencil_paint_appearance,
+ VIEW3D_PT_tools_grease_pencil_sculpt_select,
+ VIEW3D_PT_tools_grease_pencil_sculpt_settings,
VIEW3D_PT_tools_grease_pencil_sculpt_options,
VIEW3D_PT_tools_grease_pencil_sculpt_appearance,
+ VIEW3D_PT_tools_grease_pencil_weight_paint_select,
+ VIEW3D_PT_tools_grease_pencil_weight_paint_settings,
VIEW3D_PT_tools_grease_pencil_weight_appearance,
VIEW3D_PT_tools_grease_pencil_interpolate,
)
diff --git a/release/scripts/startup/keyingsets_builtins.py b/release/scripts/startup/keyingsets_builtins.py
index e24cbcfd18e..bebd10edde3 100644
--- a/release/scripts/startup/keyingsets_builtins.py
+++ b/release/scripts/startup/keyingsets_builtins.py
@@ -521,7 +521,13 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
prop_rna = type(bone).bl_rna.properties.get(prop, None)
if prop_rna is None:
prop_path = '["%s"]' % prop
- if bone.path_resolve(prop_path, False).rna_type in prop_type_compat:
+ try:
+ rna_property = bone.path_resolve(prop_path, False)
+ except ValueError as ex:
+ # This happens when a custom property is set to None. In that case it cannot
+ # be converted to an FCurve-compatible value, so we can't keyframe it anyway.
+ continue
+ if rna_property.rna_type in prop_type_compat:
ksi.addProp(ks, bone, prop_path)
elif prop_rna.is_animatable:
ksi.addProp(ks, bone, prop)
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index f0f1baba642..d9a374503b3 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -157,6 +157,11 @@ def object_cycles_shader_nodes_poll(context):
cycles_shader_nodes_poll(context))
+def cycles_aov_node_poll(context):
+ return (object_cycles_shader_nodes_poll(context) or
+ world_shader_nodes_poll(context))
+
+
def object_eevee_shader_nodes_poll(context):
return (object_shader_nodes_poll(context) and
eevee_shader_nodes_poll(context))
@@ -197,6 +202,7 @@ shader_node_categories = [
ShaderNodeCategory("SH_NEW_OUTPUT", "Output", items=[
NodeItem("ShaderNodeOutputMaterial", poll=object_eevee_cycles_shader_nodes_poll),
NodeItem("ShaderNodeOutputLight", poll=object_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeOutputAOV", poll=cycles_aov_node_poll),
NodeItem("ShaderNodeOutputWorld", poll=world_shader_nodes_poll),
NodeItem("ShaderNodeOutputLineStyle", poll=line_style_shader_nodes_poll),
NodeItem("NodeGroupOutput", poll=group_input_output_item_poll),
diff --git a/release/windows/icons/blender.exe.manifest b/release/windows/icons/blender.exe.manifest
deleted file mode 100644
index a43d11b21a0..00000000000
--- a/release/windows/icons/blender.exe.manifest
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
- <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
- <security>
- <requestedPrivileges>
- <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
- </requestedPrivileges>
- </security>
- </trustInfo>
-</assembly>
diff --git a/release/windows/icons/winblender.rc b/release/windows/icons/winblender.rc
index ba3363aacc5..a0dff81b711 100644
--- a/release/windows/icons/winblender.rc
+++ b/release/windows/icons/winblender.rc
@@ -7,7 +7,6 @@
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
#define BLEN_VER_RC_STR STRINGIFY(BLEN_VER_RC_STR_M)
- 1 RT_MANIFEST "blender.exe.manifest"
#endif
APPICON ICON DISCARDABLE "winblender.ico"
diff --git a/release/windows/manifest/Blender.CRT.MANIFEST.in b/release/windows/manifest/Blender.CRT.MANIFEST.in
new file mode 100644
index 00000000000..27c4a6bce56
--- /dev/null
+++ b/release/windows/manifest/Blender.CRT.MANIFEST.in
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity type="win32" name="Blender.CRT" version="1.0.0.0" />
+@CRTLIBS@</assembly> \ No newline at end of file
diff --git a/release/windows/manifest/blender.exe.manifest.in b/release/windows/manifest/blender.exe.manifest.in
new file mode 100644
index 00000000000..e73ddf3267b
--- /dev/null
+++ b/release/windows/manifest/blender.exe.manifest.in
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows 10 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ <!-- Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!-- Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ <!-- Windows Vista -->
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+ </application>
+ </compatibility>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.0.0"
+ processorArchitecture="*"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+ </dependency>
+ @BUNDLECRT@
+</assembly> \ No newline at end of file
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 1a070d84e4f..1722ebc91e4 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -32,12 +32,14 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_color_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_constraint_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curve_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curveprofile_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_customdata_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_defs.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_documentation.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_dynamicpaint_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_effect_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fileglobal_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fluid_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_freestyle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_genfile.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_types.h
@@ -68,14 +70,12 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_outliner_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_packedFile_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_particle_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curveprofile_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_rigidbody_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_screen_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sdna_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sequence_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_shader_fx_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_smoke_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sound_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_space_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_speaker_types.h
@@ -159,3 +159,6 @@ endif()
if(WIN32)
add_subdirectory(blendthumb)
endif()
+if(WITH_USD)
+ add_subdirectory(usd)
+endif()
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
index 7c5efaf309d..878dbfc2a53 100644
--- a/source/blender/alembic/ABC_alembic.h
+++ b/source/blender/alembic/ABC_alembic.h
@@ -59,7 +59,7 @@ struct AlembicExportParams {
bool apply_subdiv;
bool curves_as_mesh;
bool flatten_hierarchy;
- bool visible_layers_only;
+ bool visible_objects_only;
bool renderable_only;
bool face_sets;
bool use_subdiv_schema;
diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h
index 52f55a41628..6107e230627 100644
--- a/source/blender/alembic/intern/abc_customdata.h
+++ b/source/blender/alembic/intern/abc_customdata.h
@@ -59,8 +59,7 @@ struct CDStreamConfig {
bool pack_uvs;
/* TODO(kevin): might need a better way to handle adding and/or updating
- * custom datas such that it updates the custom data holder and its pointers
- * properly. */
+ * custom data such that it updates the custom data holder and its pointers properly. */
Mesh *mesh;
void *(*add_customdata_cb)(Mesh *mesh, const char *name, int data_type);
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index cbc8fd769b7..cacf0676481 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -42,6 +42,7 @@ extern "C" {
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h" /* for FILE_MAX */
+#include "DNA_fluid_types.h"
#include "BLI_string.h"
@@ -74,7 +75,7 @@ ExportSettings::ExportSettings()
depsgraph(NULL),
logger(),
selected_only(false),
- visible_layers_only(false),
+ visible_objects_only(false),
renderable_only(false),
frame_start(1),
frame_end(1),
@@ -105,11 +106,12 @@ ExportSettings::ExportSettings()
static bool object_is_smoke_sim(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid);
if (md) {
- SmokeModifierData *smd = reinterpret_cast<SmokeModifierData *>(md);
- return (smd->type == MOD_SMOKE_TYPE_DOMAIN);
+ FluidModifierData *smd = reinterpret_cast<FluidModifierData *>(md);
+ return (smd->type == MOD_FLUID_TYPE_DOMAIN && smd->domain &&
+ smd->domain->type == FLUID_DOMAIN_TYPE_GAS);
}
return false;
@@ -161,7 +163,7 @@ static bool export_object(const ExportSettings *const settings,
}
// FIXME Sybren: handle these cleanly (maybe just remove code),
// now using active scene layer instead.
- if (settings->visible_layers_only && !BASE_VISIBLE(v3d, base)) {
+ if (settings->visible_objects_only && !BASE_VISIBLE(v3d, base)) {
return false;
}
}
@@ -553,7 +555,10 @@ void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *x
m_settings.export_child_hairs = true;
m_shapes.push_back(new AbcHairWriter(ob, xform, m_shape_sampling_index, m_settings, psys));
}
- else if (m_settings.export_particles && psys->part->type == PART_EMITTER) {
+ else if (m_settings.export_particles &&
+ (psys->part->type == PART_EMITTER || psys->part->type == PART_FLUID_FLIP ||
+ psys->part->type == PART_FLUID_SPRAY || psys->part->type == PART_FLUID_BUBBLE ||
+ psys->part->type == PART_FLUID_FOAM || psys->part->type == PART_FLUID_TRACER)) {
m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys));
}
}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
index a73289fcf95..923fe0ca29f 100644
--- a/source/blender/alembic/intern/abc_exporter.h
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -49,7 +49,7 @@ struct ExportSettings {
SimpleLogger logger;
bool selected_only;
- bool visible_layers_only;
+ bool visible_objects_only;
bool renderable_only;
double frame_start, frame_end;
diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
index 9b12fe86d59..585d4178e41 100644
--- a/source/blender/alembic/intern/abc_transform.cc
+++ b/source/blender/alembic/intern/abc_transform.cc
@@ -27,6 +27,7 @@
extern "C" {
#include "DNA_object_types.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_animsys.h"
@@ -131,9 +132,9 @@ Imath::Box3d AbcTransformWriter::bounds()
return Imath::transform(bounds, m_matrix);
}
-bool AbcTransformWriter::hasAnimation(Object *ob) const
+bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const
{
- return BKE_animdata_id_is_animated(&ob->id);
+ return true;
}
/* ************************************************************************** */
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index 1034c5b319f..5efa8c8a446 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -365,7 +365,7 @@ bool ABC_export(Scene *scene,
/* TODO(Sybren): visible_layer & renderable only is ignored for now,
* to be replaced with collections later in the 2.8 dev process
* (also see note above). */
- job->settings.visible_layers_only = params->visible_layers_only;
+ job->settings.visible_objects_only = params->visible_objects_only;
job->settings.renderable_only = params->renderable_only;
job->settings.use_subdiv_schema = params->use_subdiv_schema;
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index bf0aa96df84..40abf93e944 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -67,6 +67,8 @@ void BLF_size(int fontid, int size, int dpi);
void BLF_color4ubv(int fontid, const unsigned char rgba[4]);
void BLF_color3ubv(int fontid, const unsigned char rgb[3]);
void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha);
+void BLF_color4ub(
+ int fontid, unsigned char r, unsigned char g, unsigned char b, unsigned char alpha);
void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b);
void BLF_color4f(int fontid, float r, float g, float b, float a);
void BLF_color4fv(int fontid, const float rgba[4]);
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 8e1ff77b1c7..10bb1bd3c9c 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -475,6 +475,19 @@ void BLF_color3ubv(int fontid, const unsigned char rgb[3])
BLF_color3ubv_alpha(fontid, rgb, 255);
}
+void BLF_color4ub(
+ int fontid, unsigned char r, unsigned char g, unsigned char b, unsigned char alpha)
+{
+ FontBLF *font = blf_get(fontid);
+
+ if (font) {
+ font->color[0] = r;
+ font->color[1] = g;
+ font->color[2] = b;
+ font->color[3] = alpha;
+ }
+}
+
void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b)
{
FontBLF *font = blf_get(fontid);
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 1c06dfd3f70..25ea0770f8b 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -96,7 +96,13 @@ static void blf_batch_draw_init(void)
GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
g_batch.glyph_len = 0;
- g_batch.batch = GPU_batch_create_ex(GPU_PRIM_POINTS, g_batch.verts, NULL, GPU_BATCH_OWNS_VBO);
+ /* A dummy vbo containing 4 points, attribs are not used. */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 4);
+
+ /* We render a quad as a triangle strip and instance it for each glyph. */
+ g_batch.batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_instbuf_set(g_batch.batch, g_batch.verts, true);
}
static void blf_batch_draw_exit(void)
@@ -188,8 +194,7 @@ void blf_batch_draw(void)
GPU_vertbuf_data_len_set(g_batch.verts, g_batch.glyph_len);
GPU_vertbuf_use(g_batch.verts); /* send data */
- eGPUBuiltinShader shader = (g_batch.simple_shader) ? GPU_SHADER_TEXT_SIMPLE : GPU_SHADER_TEXT;
- GPU_batch_program_set_builtin(g_batch.batch, shader);
+ GPU_batch_program_set_builtin(g_batch.batch, GPU_SHADER_TEXT);
GPU_batch_uniform_1i(g_batch.batch, "glyph", 0);
GPU_batch_draw(g_batch.batch);
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index b7139d5bbf6..60d988ab21e 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -25,6 +25,10 @@
* \brief Blender kernel action and pose functionality.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "DNA_listBase.h"
/* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h */
@@ -38,11 +42,6 @@ struct bPose;
struct bPoseChannel;
struct bPoseChannel_Runtime;
-/* Kernel prototypes */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* Action Lib Stuff ----------------- */
/* Allocate a new bAction with the given name */
@@ -123,6 +122,9 @@ void action_groups_add_channel(struct bAction *act,
/* Remove the given channel from all groups */
void action_groups_remove_channel(struct bAction *act, struct FCurve *fcu);
+/* Reconstruct group channel pointers. */
+void BKE_action_groups_reconstruct(struct bAction *act);
+
/* Find a group with the given name */
struct bActionGroup *BKE_action_group_find_name(struct bAction *act, const char name[]);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index d0249cb2b38..963e3158d46 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -24,6 +24,10 @@
* \ingroup bke
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct Depsgraph;
struct FCurve;
@@ -33,6 +37,7 @@ struct KeyingSet;
struct ListBase;
struct Main;
struct NlaKeyframingContext;
+struct PathResolvedRNA;
struct PointerRNA;
struct PropertyRNA;
struct ReportList;
@@ -244,6 +249,9 @@ typedef enum eAnimData_Recalc {
ADT_RECALC_ALL = (ADT_RECALC_DRIVERS | ADT_RECALC_ANIM),
} eAnimData_Recalc;
+bool BKE_animsys_read_rna_setting(struct PathResolvedRNA *anim_rna, float *r_value);
+bool BKE_animsys_write_rna_setting(struct PathResolvedRNA *anim_rna, const float value);
+
/* Evaluation loop for evaluating animation data */
void BKE_animsys_evaluate_animdata(struct Scene *scene,
struct ID *id,
@@ -258,9 +266,6 @@ void BKE_animsys_evaluate_all_animation(struct Main *main,
struct Scene *scene,
float ctime);
-/* TODO(sergey): This is mainly a temp public function. */
-bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct FCurve *fcu, float curval);
-
/* ------------ Specialized API --------------- */
/* There are a few special tools which require these following functions. They are NOT to be used
* for standard animation evaluation UNDER ANY CIRCUMSTANCES!
@@ -297,4 +302,8 @@ void BKE_animsys_update_driver_array(struct ID *id);
/* ************************************* */
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BKE_ANIMSYS_H__*/
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index dd1fff9ce47..9855c2202cc 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,7 +27,7 @@
* \note Use #STRINGIFY() rather than defining with quotes.
*/
#define BLENDER_VERSION 282
-#define BLENDER_SUBVERSION 1
+#define BLENDER_SUBVERSION 6
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 70741831727..c7f6c09b886 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -111,8 +111,8 @@ float BKE_brush_weight_get(const struct Scene *scene, const struct Brush *brush)
void BKE_brush_weight_set(const struct Scene *scene, struct Brush *brush, float value);
bool BKE_brush_use_locked_size(const struct Scene *scene, const struct Brush *brush);
-bool BKE_brush_use_alpha_pressure(const struct Scene *scene, const struct Brush *brush);
-bool BKE_brush_use_size_pressure(const struct Scene *scene, const struct Brush *brush);
+bool BKE_brush_use_alpha_pressure(const struct Brush *brush);
+bool BKE_brush_use_size_pressure(const struct Brush *brush);
bool BKE_brush_sculpt_has_secondary_color(const struct Brush *brush);
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 01f94c39215..17de53be42a 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -87,7 +87,8 @@ typedef struct Cloth {
struct MVertTri *tri;
struct Implicit_Data *implicit; /* our implicit solver connects to this pointer */
struct EdgeSet *edgeset; /* used for selfcollisions */
- int last_frame, pad4;
+ int last_frame;
+ float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */
} Cloth;
/**
@@ -112,8 +113,10 @@ typedef struct ClothVertex {
float struct_stiff;
float bend_stiff;
float shear_stiff;
- int spring_count; /* how many springs attached? */
- float shrink_factor; /* how much to shrink this cloth */
+ int spring_count; /* how many springs attached? */
+ float shrink_factor; /* how much to shrink this cloth */
+ float internal_stiff; /* internal spring stiffness scaling */
+ float pressure_factor; /* how much pressure should affect this vertex */
} ClothVertex;
/**
@@ -192,8 +195,16 @@ typedef enum {
CLOTH_SIMSETTINGS_FLAG_GOAL = (1 << 3),
/** True if tearing is enabled. */
CLOTH_SIMSETTINGS_FLAG_TEARING = (1 << 4),
+ /** True if pressure sim is enabled. */
+ CLOTH_SIMSETTINGS_FLAG_PRESSURE = (1 << 5),
+ /** Use the user defined target volume. */
+ CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL = (1 << 6),
+ /** True if internal spring generation is enabled. */
+ CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS = (1 << 7),
/** DEPRECATED, for versioning only. */
CLOTH_SIMSETTINGS_FLAG_SCALING = (1 << 8),
+ /** Require internal springs to be created between points with opposite normals. */
+ CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS_NORMAL = (1 << 9),
/** Edit cache in edit-mode. */
CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12),
/** Don't allow spring compression. */
@@ -224,6 +235,7 @@ typedef enum {
CLOTH_SPRING_TYPE_GOAL = (1 << 4),
CLOTH_SPRING_TYPE_SEWING = (1 << 5),
CLOTH_SPRING_TYPE_BENDING_HAIR = (1 << 6),
+ CLOTH_SPRING_TYPE_INTERNAL = (1 << 7),
} CLOTH_SPRING_TYPES;
/* SPRING FLAGS */
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 643073b3470..e4ea1dad086 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -68,7 +68,9 @@ void BKE_curvemapping_initialize(struct CurveMapping *cumap);
/* keep these (const CurveMap) - to help with thread safety */
/* single curve, no table check */
-float BKE_curvemap_evaluateF(const struct CurveMap *cuma, float value);
+float BKE_curvemap_evaluateF(const struct CurveMapping *cumap,
+ const struct CurveMap *cuma,
+ float value);
/* single curve, with table check */
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value);
void BKE_curvemapping_evaluate3F(const struct CurveMapping *cumap,
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 105f8e82343..88a27b67963 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -198,6 +198,9 @@ enum {
PointerRNA CTX_data_pointer_get(const bContext *C, const char *member);
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type);
+PointerRNA CTX_data_pointer_get_type_silent(const bContext *C,
+ const char *member,
+ StructRNA *type);
ListBase CTX_data_collection_get(const bContext *C, const char *member);
ListBase CTX_data_dir_get_ex(const bContext *C,
const bool use_store,
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 1b9e318146e..7c27362e244 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -65,10 +65,6 @@ typedef struct BMEditMesh {
/*derivedmesh stuff*/
CustomData_MeshMasks lastDataMask;
- unsigned char (*derivedVertColor)[4];
- int derivedVertColorLen;
- unsigned char (*derivedFaceColor)[4];
- int derivedFaceColorLen;
/*selection mode*/
short selectmode;
@@ -96,20 +92,11 @@ BMEditMesh *BKE_editmesh_from_object(struct Object *ob);
void BKE_editmesh_free_derivedmesh(BMEditMesh *em);
void BKE_editmesh_free(BMEditMesh *em);
-void BKE_editmesh_color_free(BMEditMesh *em);
-void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
+float (*BKE_editmesh_vert_coords_alloc(
+ struct Depsgraph *depsgraph, struct BMEditMesh *em, struct Scene *scene, int *r_vert_len))[3];
float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3];
void BKE_editmesh_lnorspace_update(BMEditMesh *em);
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em);
struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em);
-/* editderivedmesh.c */
-/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
-void BKE_editmesh_statvis_calc(BMEditMesh *em,
- struct EditMeshData *emd,
- const struct MeshStatVis *statvis);
-
-float (*BKE_editmesh_vert_coords_alloc(
- struct Depsgraph *depsgraph, struct BMEditMesh *em, struct Scene *scene, int *r_vert_len))[3];
-
#endif /* __BKE_EDITMESH_H__ */
diff --git a/source/blender/blenkernel/BKE_fluid.h b/source/blender/blenkernel/BKE_fluid.h
new file mode 100644
index 00000000000..0f64dd262cc
--- /dev/null
+++ b/source/blender/blenkernel/BKE_fluid.h
@@ -0,0 +1,92 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation.
+ * All rights reserved.
+ */
+
+#ifndef __BKE_FLUID_H__
+#define __BKE_FLUID_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+struct Depsgraph;
+struct FluidDomainSettings;
+struct FluidEffectorSettings;
+struct FluidFlowSettings;
+struct FluidModifierData;
+struct Main;
+struct Scene;
+
+typedef float (*BKE_Fluid_BresenhamFn)(
+ float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
+
+struct Mesh *BKE_fluid_modifier_do(struct FluidModifierData *mmd,
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ struct Mesh *me);
+
+void BKE_fluid_modifier_free(struct FluidModifierData *mmd);
+void BKE_fluid_modifier_reset(struct FluidModifierData *mmd);
+void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd);
+void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd,
+ struct FluidModifierData *tmmd,
+ const int flag);
+
+void BKE_fluid_reallocate_fluid(struct FluidDomainSettings *mds, int res[3], int free_old);
+void BKE_fluid_reallocate_copy_fluid(struct FluidDomainSettings *mds,
+ int o_res[3],
+ int n_res[3],
+ int o_min[3],
+ int n_min[3],
+ int o_max[3],
+ int o_shift[3],
+ int n_shift[3]);
+void BKE_fluid_cache_free(struct FluidDomainSettings *mds, struct Object *ob, int cache_map);
+
+float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
+int BKE_fluid_get_data_flags(struct FluidDomainSettings *mds);
+
+void BKE_fluid_particle_system_create(struct Main *bmain,
+ struct Object *ob,
+ const char *pset_name,
+ const char *parts_name,
+ const char *psys_name,
+ const int psys_type);
+void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type);
+
+void BKE_fluid_cachetype_mesh_set(struct FluidDomainSettings *settings, int cache_mesh_format);
+void BKE_fluid_cachetype_data_set(struct FluidDomainSettings *settings, int cache_data_format);
+void BKE_fluid_cachetype_particle_set(struct FluidDomainSettings *settings,
+ int cache_particle_format);
+void BKE_fluid_cachetype_noise_set(struct FluidDomainSettings *settings, int cache_noise_format);
+void BKE_fluid_collisionextents_set(struct FluidDomainSettings *settings, int value, bool clear);
+void BKE_fluid_particles_set(struct FluidDomainSettings *settings, int value, bool clear);
+
+void BKE_fluid_domain_type_set(struct Object *object,
+ struct FluidDomainSettings *settings,
+ int type);
+void BKE_fluid_flow_type_set(struct Object *object, struct FluidFlowSettings *settings, int type);
+void BKE_fluid_effector_type_set(struct Object *object,
+ struct FluidEffectorSettings *settings,
+ int type);
+void BKE_fluid_flow_behavior_set(struct Object *object,
+ struct FluidFlowSettings *settings,
+ int behavior);
+
+#endif /* __BKE_FLUID_H__ */
diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h
deleted file mode 100644
index d44c88c30a9..00000000000
--- a/source/blender/blenkernel/BKE_fluidsim.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation
- * All rights reserved.
- */
-
-#ifndef __BKE_FLUIDSIM_H__
-#define __BKE_FLUIDSIM_H__
-
-/** \file
- * \ingroup bke
- */
-
-struct Depsgraph;
-struct FluidsimSettings;
-struct MVert;
-struct Object;
-struct Scene;
-
-/* old interface */
-
-void initElbeemMesh(struct Depsgraph *depsgraph,
- struct Scene *scene,
- struct Object *ob,
- int *numVertices,
- float **vertices,
- int *numTriangles,
- int **triangles,
- int useGlobalCoords,
- int modifierIndex);
-
-/* bounding box & memory estimate */
-void fluid_get_bb(
- struct MVert *mvert, int totvert, float obmat[4][4], float start[3], float size[3]);
-
-void fluid_estimate_memory(struct Object *ob, struct FluidsimSettings *fss, char *value);
-
-#endif
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 21356db8abf..6400a4f959e 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -233,6 +233,7 @@ void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points,
float (*points2d)[2],
const float scale,
int *r_direction);
+void BKE_gpencil_triangulate_stroke_fill(struct bGPdata *gpd, struct bGPDstroke *gps);
void BKE_gpencil_transform(struct bGPdata *gpd, float mat[4][4]);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 82c831ae8e0..e2bb1f988ca 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -33,6 +33,7 @@ struct ImBuf;
struct Image;
struct ImageFormatData;
struct ImagePool;
+struct ImageTile;
struct ImbFormatOptions;
struct Main;
struct Object;
@@ -43,6 +44,7 @@ struct StampData;
struct anim;
#define IMA_MAX_SPACE 64
+#define IMA_UDIM_MAX 1999
void BKE_images_init(void);
void BKE_images_exit(void);
@@ -206,7 +208,8 @@ struct Image *BKE_image_add_generated(struct Main *bmain,
short gen_type,
const float color[4],
const bool stereo3d,
- const bool is_data);
+ const bool is_data,
+ const bool tiled);
/* adds image from imbuf, owns imbuf */
struct Image *BKE_image_add_from_imbuf(struct Main *bmain, struct ImBuf *ibuf, const char *name);
@@ -302,6 +305,32 @@ bool BKE_image_has_alpha(struct Image *image);
/* check if texture has gpu texture code */
bool BKE_image_has_opengl_texture(struct Image *ima);
+/* get tile index for tiled images */
+void BKE_image_get_tile_label(struct Image *ima,
+ struct ImageTile *tile,
+ char *label,
+ int len_label);
+
+struct ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label);
+bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile);
+
+bool BKE_image_fill_tile(struct Image *ima,
+ struct ImageTile *tile,
+ int width,
+ int height,
+ const float color[4],
+ int gen_type,
+ int planes,
+ bool is_float);
+
+struct ImageTile *BKE_image_get_tile(struct Image *ima, int tile_number);
+struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, struct ImageUser *iuser);
+
+int BKE_image_get_tile_from_pos(struct Image *ima,
+ const float uv[2],
+ float new_uv[2],
+ float ofs[2]);
+
void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *width, int *height);
void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float size[2]);
void BKE_image_get_aspect(struct Image *image, float *aspx, float *aspy);
@@ -316,8 +345,8 @@ void BKE_image_buf_fill_checker_color(unsigned char *rect,
int height);
/* Cycles hookup */
-unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame);
-float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame);
+unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame, int tile);
+float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int tile);
/* Image modifications */
bool BKE_image_is_dirty(struct Image *image);
@@ -331,6 +360,7 @@ bool BKE_image_has_anim(struct Image *image);
bool BKE_image_has_packedfile(struct Image *image);
bool BKE_image_has_filepath(struct Image *ima);
bool BKE_image_is_animated(struct Image *image);
+bool BKE_image_has_multiple_ibufs(struct Image *image);
void BKE_image_file_format_set(struct Image *image,
int ftype,
const struct ImbFormatOptions *options);
diff --git a/source/blender/blenkernel/BKE_kelvinlet.h b/source/blender/blenkernel/BKE_kelvinlet.h
new file mode 100644
index 00000000000..fbf7d3ede1f
--- /dev/null
+++ b/source/blender/blenkernel/BKE_kelvinlet.h
@@ -0,0 +1,77 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __BKE_KELVINLET_H__
+#define __BKE_KELVINLET_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_math.h"
+
+/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
+ * Pixar Technical Memo #17-03 */
+
+#define KELVINLET_MAX_ITERATIONS 3
+
+typedef struct KelvinletParams {
+ float a;
+ float b;
+ float c;
+
+ float f;
+
+ float radius_scaled[KELVINLET_MAX_ITERATIONS];
+} KelvinletParams;
+
+/* Initialize KelvinletParams to store the parameters that will affect the deformation produced by
+ * a Kelvinlet */
+void BKE_kelvinlet_init_params(
+ KelvinletParams *params, float radius, float force, float shear_modulus, float poisson_ratio);
+
+/* Regularized Kelvinlets */
+/* All these functions output the displacement that should be applied to each element. */
+/* The initial coordinates of that element should not be modified during the transformation */
+void BKE_kelvinlet_grab(float r_elem_disp[3],
+ const KelvinletParams *params,
+ const float elem_orig_co[3],
+ const float brush_location[3],
+ const float brush_delta[3]);
+void BKE_kelvinlet_grab_biscale(float r_elem_disp[3],
+ const KelvinletParams *params,
+ const float elem_orig_co[3],
+ const float brush_location[3],
+ const float brush_delta[3]);
+void BKE_kelvinlet_grab_triscale(float r_elem_disp[3],
+ const KelvinletParams *params,
+ const float elem_orig_co[3],
+ const float brush_location[3],
+ const float brush_delta[3]);
+void BKE_kelvinlet_scale(float r_elem_disp[3],
+ const KelvinletParams *params,
+ const float elem_orig_co[3],
+ const float brush_location[3],
+ const float surface_normal[3]);
+void BKE_kelvinlet_twist(float r_elem_disp[3],
+ const KelvinletParams *params,
+ const float elem_orig_co[3],
+ const float brush_location[3],
+ const float surface_normal[3]);
+
+#endif
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 71799bf74f6..c41cd50eba5 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -199,7 +199,7 @@ bool BKE_id_copy_is_allowed(const struct ID *id);
bool BKE_id_copy(struct Main *bmain, const struct ID *id, struct ID **newid);
bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag);
void BKE_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
-void id_sort_by_name(struct ListBase *lb, struct ID *id);
+void id_sort_by_name(struct ListBase *lb, struct ID *id, struct ID *id_sorting_hint);
void BKE_id_expand_local(struct Main *bmain, struct ID *id);
void BKE_id_copy_ensure_local(struct Main *bmain, const struct ID *old_id, struct ID *new_id);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 7ff9c4e6376..d7b037a8189 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -95,6 +95,7 @@ bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_used(struct ID *id, short actcol);
struct Material *BKE_material_gpencil_get(struct Object *ob, short act);
+struct Material *BKE_material_gpencil_default_get(void);
struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act);
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 07dee83e5ca..1e549849989 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -20,6 +20,10 @@
* \ingroup bke
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "DNA_modifier_types.h" /* needed for all enum typdefs */
#include "BLI_compiler_attrs.h"
#include "BKE_customdata.h"
@@ -461,4 +465,8 @@ void modwrap_deformVertsEM(ModifierData *md,
struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval,
const bool get_cage_mesh);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 9501d3f8ec9..11f151af44d 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -990,6 +990,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_TEX_WHITE_NOISE 704
#define SH_NODE_VOLUME_INFO 705
#define SH_NODE_VERTEX_COLOR 706
+#define SH_NODE_OUTPUT_AOV 707
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 48f9e1fd95e..fdd3bd7cd86 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -134,7 +134,7 @@ void BKE_paint_curve_copy_data(struct Main *bmain,
struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, const struct PaintCurve *pc);
void BKE_paint_curve_make_local(struct Main *bmain, struct PaintCurve *pc, const bool lib_local);
-bool BKE_paint_ensure(const struct ToolSettings *ts, struct Paint **r_paint);
+bool BKE_paint_ensure(struct ToolSettings *ts, struct Paint **r_paint);
void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const char col[3]);
void BKE_paint_free(struct Paint *p);
void BKE_paint_copy(struct Paint *src, struct Paint *tar, const int flag);
@@ -265,7 +265,10 @@ typedef struct SculptSession {
float cursor_location[3];
float cursor_normal[3];
float cursor_view_normal[3];
+
+ /* TODO(jbakker): Replace rv3d adn v3d with ViewContext */
struct RegionView3D *rv3d;
+ struct View3D *v3d;
/* Dynamic mesh preview */
int *preview_vert_index_list;
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 570203081fe..9eb10d296de 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -40,15 +40,14 @@ struct CustomData;
struct DMFlagMat;
struct GPU_PBVH_Buffers;
struct IsectRayPrecalc;
-struct Mesh;
struct MLoop;
struct MLoopTri;
struct MPoly;
struct MVert;
+struct Mesh;
struct PBVH;
struct PBVHNode;
struct SubdivCCG;
-struct TaskParallelSettings;
struct TaskParallelTLS;
typedef struct PBVH PBVH;
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 6ce60081f5b..fd29480cac7 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -75,6 +75,7 @@
/* Structs */
struct ClothModifierData;
+struct FluidModifierData;
struct ListBase;
struct Main;
struct Object;
@@ -83,7 +84,6 @@ struct ParticleSystem;
struct PointCache;
struct RigidBodyWorld;
struct Scene;
-struct SmokeModifierData;
struct SoftBody;
struct ViewLayer;
@@ -286,7 +286,7 @@ void BKE_ptcache_make_particle_key(struct ParticleKey *key, int index, void **da
void BKE_ptcache_id_from_softbody(PTCacheID *pid, struct Object *ob, struct SoftBody *sb);
void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys);
void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd);
-void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd);
+void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *mmd);
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid,
struct Object *ob,
struct DynamicPaintSurface *surface);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index c1bb60737ff..770318883c0 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -24,6 +24,10 @@
* \ingroup bke
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct Depsgraph;
struct Editing;
struct GPUOffScreen;
@@ -527,7 +531,6 @@ typedef struct ImBuf *(*SequencerDrawView)(struct Depsgraph *depsgraph,
unsigned int flag,
unsigned int draw_flags,
int alpha_mode,
- int samples,
const char *viewname,
struct GPUOffScreen *ofs,
char err_out[256]);
@@ -599,4 +602,8 @@ void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb,
void BKE_sequencer_all_free_anim_ibufs(struct Scene *scene, int cfra);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BKE_SEQUENCER_H__ */
diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h
deleted file mode 100644
index 10632d47203..00000000000
--- a/source/blender/blenkernel/BKE_smoke.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation.
- * All rights reserved.
- */
-
-#ifndef __BKE_SMOKE_H__
-#define __BKE_SMOKE_H__
-
-/** \file
- * \ingroup bke
- */
-
-struct Scene;
-struct SmokeDomainSettings;
-struct SmokeModifierData;
-
-typedef float (*bresenham_callback)(
- float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-
-struct Mesh *smokeModifier_do(struct SmokeModifierData *smd,
- struct Depsgraph *depsgraph,
- struct Scene *scene,
- struct Object *ob,
- struct Mesh *me);
-
-void smokeModifier_free(struct SmokeModifierData *smd);
-void smokeModifier_reset(struct SmokeModifierData *smd);
-void smokeModifier_reset_turbulence(struct SmokeModifierData *smd);
-void smokeModifier_createType(struct SmokeModifierData *smd);
-void smokeModifier_copy(const struct SmokeModifierData *smd,
- struct SmokeModifierData *tsmd,
- const int flag);
-
-void BKE_smoke_reallocate_fluid(struct SmokeDomainSettings *sds,
- float dx,
- int res[3],
- int free_old);
-void BKE_smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds,
- float dx,
- int res[3],
- int free_old);
-
-float BKE_smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
-int BKE_smoke_get_data_flags(struct SmokeDomainSettings *sds);
-
-bool BKE_smoke_show_highres(struct Scene *scene, struct SmokeDomainSettings *sds);
-
-#endif /* __BKE_SMOKE_H__ */
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 1567985bd53..6807d81daa3 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -23,6 +23,10 @@
* \ingroup bke
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define SOUND_WAVE_SAMPLES_PER_SECOND 250
#if defined(WITH_AUDASPACE)
@@ -190,4 +194,8 @@ struct Depsgraph;
void BKE_sound_evaluate(struct Depsgraph *depsgraph, struct Main *bmain, struct bSound *sound);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BKE_SOUND_H__ */
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index cd48e4d7f3b..70aa028a2c7 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -58,7 +58,7 @@ typedef enum {
struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
- struct Scene *scene,
+ const struct Scene *scene,
float (*vertCos)[3],
SubsurfFlags flags);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index f62369cfa2a..73bb16df9fa 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -45,11 +45,11 @@ set(INC
../../../intern/atomic
../../../intern/clog
../../../intern/libmv
+ ../../../intern/mantaflow/extern
../../../intern/memutil
../../../intern/mikktspace
../../../intern/opensubdiv
../../../extern/curve_fit_nd
- ../../../intern/smoke/extern
# dna_type_offsets.h
${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
@@ -106,7 +106,6 @@ set(SRC
intern/deform.c
intern/displist.c
intern/dynamicpaint.c
- intern/editderivedmesh.c
intern/editlattice.c
intern/editmesh.c
intern/editmesh_bvh.c
@@ -114,7 +113,7 @@ set(SRC
intern/editmesh_tangent.c
intern/effect.c
intern/fcurve.c
- intern/fluidsim.c
+ intern/fluid.c
intern/fmodifier.c
intern/font.c
intern/freestyle.c
@@ -129,6 +128,7 @@ set(SRC
intern/image_gen.c
intern/image_save.c
intern/ipo.c
+ intern/kelvinlet.c
intern/key.c
intern/keyconfig.c
intern/lattice.c
@@ -197,7 +197,6 @@ set(SRC
intern/sequencer.c
intern/shader_fx.c
intern/shrinkwrap.c
- intern/smoke.c
intern/softbody.c
intern/sound.c
intern/speaker.c
@@ -280,7 +279,7 @@ set(SRC
BKE_editmesh_tangent.h
BKE_effect.h
BKE_fcurve.h
- BKE_fluidsim.h
+ BKE_fluid.h
BKE_font.h
BKE_freestyle.h
BKE_global.h
@@ -292,6 +291,7 @@ set(SRC
BKE_image.h
BKE_image_save.h
BKE_ipo.h
+ BKE_kelvinlet.h
BKE_key.h
BKE_keyconfig.h
BKE_lattice.h
@@ -339,7 +339,6 @@ set(SRC
BKE_sequencer.h
BKE_shader_fx.h
BKE_shrinkwrap.h
- BKE_smoke.h
BKE_softbody.h
BKE_sound.h
BKE_speaker.h
@@ -524,20 +523,10 @@ if(WITH_PYTHON)
endif()
if(WITH_MOD_FLUID)
- list(APPEND INC
- ../../../intern/elbeem/extern
- )
- list(APPEND LIB
- bf_intern_elbeem
- )
- add_definitions(-DWITH_MOD_FLUID)
-endif()
-
-if(WITH_MOD_SMOKE)
list(APPEND LIB
- bf_intern_smoke
+ bf_intern_mantaflow
)
- add_definitions(-DWITH_SMOKE)
+ add_definitions(-DWITH_FLUID)
endif()
if(WITH_MOD_OCEANSIM)
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 8be7a947a67..df4582267b5 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -789,14 +789,6 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc
}
}
-static void editmesh_update_statvis_color(const Scene *scene, Object *ob)
-{
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- Mesh *me = ob->data;
- BKE_mesh_runtime_ensure_edit_data(me);
- BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis);
-}
-
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
const CustomData_MeshMasks *final_datamask,
const bool sculpt_dyntopo,
@@ -1494,7 +1486,6 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Modifier evaluation modes. */
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
- const bool do_init_statvis = false; /* FIXME: use V3D_OVERLAY_EDIT_STATVIS. */
/* Modifier evaluation contexts for different types of modifiers. */
const ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE};
@@ -1703,22 +1694,12 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
else if (!deformed_verts && mesh_cage) {
/* cage should already have up to date normals */
mesh_final = mesh_cage;
-
- /* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_statvis) {
- editmesh_update_statvis_color(scene, ob);
- }
}
else {
/* this is just a copy of the editmesh, no need to calc normals */
mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(
em_input, &final_datamask, deformed_verts, mesh_input);
deformed_verts = NULL;
-
- /* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_statvis) {
- editmesh_update_statvis_color(scene, ob);
- }
}
if (deformed_verts) {
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index ad6c696b655..b474e3f5ec5 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -343,6 +343,43 @@ void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
fcurve->grp = agrp;
}
+/* Reconstruct group channel pointers.
+ * Assumes that the channels are still in the proper order, i.e. that channels of the same group
+ * are adjacent in the act->channels list. It also assumes that the groups
+ * referred to by the FCurves are already in act->groups.
+ */
+void BKE_action_groups_reconstruct(bAction *act)
+{
+ /* Sanity check. */
+ if (ELEM(NULL, act, act->groups.first)) {
+ return;
+ }
+
+ /* Clear out all group channels. Channels that are actually in use are
+ * reconstructed below; this step is necessary to clear out unused groups. */
+ LISTBASE_FOREACH (bActionGroup *, group, &act->groups) {
+ BLI_listbase_clear(&group->channels);
+ }
+
+ bActionGroup *grp;
+ bActionGroup *last_grp = NULL;
+ LISTBASE_FOREACH (FCurve *, fcurve, &act->curves) {
+ if (fcurve->grp == NULL) {
+ continue;
+ }
+
+ grp = fcurve->grp;
+ if (last_grp != grp) {
+ /* If this is the first time we see this group, this must be the first channel. */
+ grp->channels.first = fcurve;
+ }
+
+ /* This is the last channel, until it's overwritten by a later iteration. */
+ grp->channels.last = fcurve;
+ last_grp = grp;
+ }
+}
+
/* Remove the given channel from all groups */
void action_groups_remove_channel(bAction *act, FCurve *fcu)
{
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index eea71d52ab6..32420e2e894 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1717,7 +1717,7 @@ static bool animsys_store_rna_setting(PointerRNA *ptr,
/* less than 1.0 evaluates to false, use epsilon to avoid float error */
#define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON)))
-static bool animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value)
+bool BKE_animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value)
{
PropertyRNA *prop = anim_rna->prop;
PointerRNA *ptr = &anim_rna->ptr;
@@ -1780,7 +1780,7 @@ static bool animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value)
}
/* Write the given value to a setting using RNA, and return success */
-static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value)
+bool BKE_animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value)
{
PropertyRNA *prop = anim_rna->prop;
PointerRNA *ptr = &anim_rna->ptr;
@@ -1791,7 +1791,7 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
/* Check whether value is new. Otherwise we skip all the updates. */
float old_value;
- if (!animsys_read_rna_setting(anim_rna, &old_value)) {
+ if (!BKE_animsys_read_rna_setting(anim_rna, &old_value)) {
return false;
}
if (old_value == value) {
@@ -1845,20 +1845,6 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
return true;
}
-/* Simple replacement based data-setting of the FCurve using RNA */
-bool BKE_animsys_execute_fcurve(PointerRNA *ptr, FCurve *fcu, float curval)
-{
- PathResolvedRNA anim_rna;
- bool ok = false;
-
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
- ok = animsys_write_rna_setting(&anim_rna, curval);
- }
-
- /* return whether we were successful */
- return ok;
-}
-
static bool animsys_construct_orig_pointer_rna(const PointerRNA *ptr, PointerRNA *ptr_orig)
{
*ptr_orig = *ptr;
@@ -1895,7 +1881,7 @@ static void animsys_write_orig_anim_rna(PointerRNA *ptr,
PathResolvedRNA orig_anim_rna;
/* TODO(sergey): Should be possible to cache resolved path in dependency graph somehow. */
if (animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) {
- animsys_write_rna_setting(&orig_anim_rna, value);
+ BKE_animsys_write_rna_setting(&orig_anim_rna, value);
}
}
@@ -1926,7 +1912,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr,
PathResolvedRNA anim_rna;
if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
- animsys_write_rna_setting(&anim_rna, curval);
+ BKE_animsys_write_rna_setting(&anim_rna, curval);
if (flush_to_original) {
animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval);
}
@@ -1960,7 +1946,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
PathResolvedRNA anim_rna;
if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
- ok = animsys_write_rna_setting(&anim_rna, curval);
+ ok = BKE_animsys_write_rna_setting(&anim_rna, curval);
}
/* set error-flag if evaluation failed */
@@ -2039,7 +2025,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
PathResolvedRNA anim_rna;
if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
- animsys_write_rna_setting(&anim_rna, curval);
+ BKE_animsys_write_rna_setting(&anim_rna, curval);
}
}
}
@@ -3333,7 +3319,7 @@ void nladata_flush_channels(PointerRNA *ptr,
if (nec->is_array) {
rna.prop_index = i;
}
- animsys_write_rna_setting(&rna, value);
+ BKE_animsys_write_rna_setting(&rna, value);
if (flush_to_original) {
animsys_write_orig_anim_rna(ptr, nec->rna_path, rna.prop_index, value);
}
@@ -3818,7 +3804,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
for (aor = adt->overrides.first; aor; aor = aor->next) {
PathResolvedRNA anim_rna;
if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) {
- animsys_write_rna_setting(&anim_rna, aor->value);
+ BKE_animsys_write_rna_setting(&anim_rna, aor->value);
}
}
}
@@ -4143,7 +4129,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCu
/* Evaluate driver, and write results to COW-domain destination */
const float ctime = DEG_get_ctime(depsgraph);
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
- ok = animsys_write_rna_setting(&anim_rna, curval);
+ ok = BKE_animsys_write_rna_setting(&anim_rna, curval);
/* Flush results & status codes to original data for UI (T59984) */
if (ok && DEG_is_active(depsgraph)) {
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 58b0c9b41ea..c588ee80c78 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -281,22 +281,22 @@ static void armature_transform_recurse(ListBase *bonebase,
{
for (Bone *bone = bonebase->first; bone; bone = bone->next) {
- /* Transform the bone's roll. */
- if (bone_parent == NULL) {
-
- float roll_mat[3][3];
- {
- float delta[3];
- sub_v3_v3v3(delta, bone->tail, bone->head);
- vec_roll_to_mat3(delta, bone->roll, roll_mat);
+ /* Store the initial bone roll in a matrix, this is needed even for child bones
+ * so any change in head/tail doesn't cause the roll to change.
+ *
+ * Logic here is different to edit-mode because
+ * this is calculated in relative to the parent. */
+ float roll_mat3_pre[3][3];
+ {
+ float delta[3];
+ sub_v3_v3v3(delta, bone->tail, bone->head);
+ vec_roll_to_mat3(delta, bone->roll, roll_mat3_pre);
+ if (bone->parent == NULL) {
+ mul_m3_m3m3(roll_mat3_pre, mat3, roll_mat3_pre);
}
-
- /* Transform the roll matrix. */
- mul_m3_m3m3(roll_mat, mat3, roll_mat);
-
- /* Apply the transformed roll back. */
- mat3_to_vec_roll(roll_mat, NULL, &bone->roll);
}
+ /* Optional, use this for predictable results since the roll is re-calculated below anyway. */
+ bone->roll = 0.0f;
mul_m4_v3(mat, bone->arm_head);
mul_m4_v3(mat, bone->arm_tail);
@@ -314,6 +314,17 @@ static void armature_transform_recurse(ListBase *bonebase,
copy_v3_v3(bone->tail, bone->arm_tail);
}
+ /* Now the head/tail have been updated, set the roll back, matching 'roll_mat3_pre'. */
+ {
+ float roll_mat3_post[3][3], delta_mat3[3][3];
+ float delta[3];
+ sub_v3_v3v3(delta, bone->tail, bone->head);
+ vec_roll_to_mat3(delta, 0.0f, roll_mat3_post);
+ invert_m3(roll_mat3_post);
+ mul_m3_m3m3(delta_mat3, roll_mat3_post, roll_mat3_pre);
+ bone->roll = atan2f(delta_mat3[2][0], delta_mat3[2][2]);
+ }
+
BKE_armature_where_is_bone(bone, bone_parent, false);
{
@@ -1550,7 +1561,6 @@ static void armature_vert_task(void *__restrict userdata,
MDeformWeight *dw = dvert->dw;
int deformed = 0;
unsigned int j;
- float acum_weight = 0;
for (j = dvert->totweight; j != 0; j--, dw++) {
const int index = dw->def_nr;
if (index >= 0 && index < data->defbase_tot && (pchan = data->defnrToPC[index])) {
@@ -1564,20 +1574,7 @@ static void armature_vert_task(void *__restrict userdata,
co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
}
- /* check limit of weight */
- if (data->target->type == OB_GPENCIL) {
- if (acum_weight + weight >= 1.0f) {
- weight = 1.0f - acum_weight;
- }
- acum_weight += weight;
- }
-
pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib);
-
- /* if acumulated weight limit exceed, exit loop */
- if ((data->target->type == OB_GPENCIL) && (acum_weight >= 1.0f)) {
- break;
- }
}
}
/* if there are vertexgroups but not groups with bones
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 0d94fbe648f..62173393256 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -154,7 +154,7 @@ static void setup_app_data(bContext *C,
else if (BLI_listbase_is_empty(&bfd->main->screens)) {
mode = LOAD_UNDO;
}
- else if ((G.fileflags & G_FILE_NO_UI) && (is_startup == false)) {
+ else if (G.fileflags & G_FILE_NO_UI) {
mode = LOAD_UI_OFF;
}
else {
@@ -873,7 +873,7 @@ bool BKE_blendfile_write_partial(Main *bmain_src,
while ((id = BLI_pophead(lb_src))) {
BLI_addtail(lb_dst, id);
- id_sort_by_name(lb_dst, id);
+ id_sort_by_name(lb_dst, id, NULL);
}
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index fa7af53df2d..90b26f8c288 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -59,7 +59,7 @@
#include "DNA_texture_types.h"
#include "DNA_vfont_types.h"
#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_freestyle_types.h"
#include "BLI_blenlib.h"
@@ -453,7 +453,8 @@ void BKE_bpath_traverse_id(
/* Skip empty file paths, these are typically from generated images and
* don't make sense to add directories to until the image has been saved
* once to give it a meaningful value. */
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE) && ima->name[0]) {
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) &&
+ ima->name[0]) {
if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) {
if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
if (!BKE_image_has_packedfile(ima) &&
@@ -497,10 +498,10 @@ void BKE_bpath_traverse_id(
rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data);
}
}
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]);
+ else if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) {
+ rewrite_path_fixed(mmd->domain->cache_directory, visit_cb, absbase, bpath_user_data);
}
}
else if (md->type == eModifierType_Cloth) {
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 4d496fe758b..e9760f76cfc 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -893,9 +893,11 @@ void BKE_brush_debug_print_state(Brush *br)
BR_TEST(add_col[0], f);
BR_TEST(add_col[1], f);
BR_TEST(add_col[2], f);
+ BR_TEST(add_col[3], f);
BR_TEST(sub_col[0], f);
BR_TEST(sub_col[1], f);
BR_TEST(sub_col[2], f);
+ BR_TEST(sub_col[3], f);
printf("\n");
@@ -931,7 +933,9 @@ void BKE_brush_sculpt_reset(Brush *br)
br->alpha = 1.0f;
break;
case SCULPT_TOOL_CLAY:
- br->spacing = 6;
+ br->flag |= BRUSH_SIZE_PRESSURE;
+ br->spacing = 3;
+ br->autosmooth_factor = 0.25f;
br->normal_radius_factor = 0.75f;
break;
case SCULPT_TOOL_CLAY_STRIPS:
@@ -1004,6 +1008,11 @@ void BKE_brush_sculpt_reset(Brush *br)
}
/* Cursor colors */
+
+ /* Default Alpha */
+ br->add_col[3] = 0.90f;
+ br->sub_col[3] = 0.90f;
+
switch (br->sculpt_tool) {
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_DRAW_SHARP:
@@ -1013,12 +1022,12 @@ void BKE_brush_sculpt_reset(Brush *br)
case SCULPT_TOOL_INFLATE:
case SCULPT_TOOL_BLOB:
case SCULPT_TOOL_CREASE:
- br->add_col[0] = 0.5f;
- br->add_col[1] = 0.7f;
- br->add_col[2] = 0.875f;
- br->sub_col[0] = 0.5f;
- br->sub_col[1] = 0.7f;
- br->sub_col[2] = 0.875f;
+ br->add_col[0] = 0.0f;
+ br->add_col[1] = 0.5f;
+ br->add_col[2] = 1.0f;
+ br->sub_col[0] = 0.0f;
+ br->sub_col[1] = 0.5f;
+ br->sub_col[2] = 1.0f;
break;
case SCULPT_TOOL_SMOOTH:
@@ -1027,11 +1036,11 @@ void BKE_brush_sculpt_reset(Brush *br)
case SCULPT_TOOL_SCRAPE:
case SCULPT_TOOL_MULTIPLANE_SCRAPE:
br->add_col[0] = 1.0f;
- br->add_col[1] = 0.39f;
- br->add_col[2] = 0.39f;
+ br->add_col[1] = 0.05f;
+ br->add_col[2] = 0.01f;
br->sub_col[0] = 1.0f;
- br->sub_col[1] = 0.39f;
- br->sub_col[2] = 0.39f;
+ br->sub_col[1] = 0.05f;
+ br->sub_col[2] = 0.01f;
break;
case SCULPT_TOOL_PINCH:
@@ -1043,11 +1052,11 @@ void BKE_brush_sculpt_reset(Brush *br)
case SCULPT_TOOL_ELASTIC_DEFORM:
case SCULPT_TOOL_POSE:
br->add_col[0] = 1.0f;
- br->add_col[1] = 1.0f;
- br->add_col[2] = 0.39f;
+ br->add_col[1] = 0.95f;
+ br->add_col[2] = 0.005f;
br->sub_col[0] = 1.0f;
- br->sub_col[1] = 1.0f;
- br->sub_col[2] = 0.39f;
+ br->sub_col[1] = 0.95f;
+ br->sub_col[2] = 0.005f;
break;
case SCULPT_TOOL_SIMPLIFY:
@@ -1069,18 +1078,19 @@ void BKE_brush_sculpt_reset(Brush *br)
*/
void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
{
- CurveMap *cm = NULL;
+ CurveMapping *cumap = NULL;
+ CurveMap *cuma = NULL;
if (!b->curve) {
b->curve = BKE_curvemapping_add(1, 0, 0, 1, 1);
}
+ cumap = b->curve;
+ cumap->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
+ cumap->preset = preset;
- cm = b->curve->cm;
- cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
-
- b->curve->preset = preset;
- BKE_curvemap_reset(cm, &b->curve->clipr, b->curve->preset, CURVEMAP_SLOPE_NEGATIVE);
- BKE_curvemapping_changed(b->curve, false);
+ cuma = b->curve->cm;
+ BKE_curvemap_reset(cuma, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_NEGATIVE);
+ BKE_curvemapping_changed(cumap, false);
}
/* Generic texture sampler for 3D painting systems. point has to be either in
@@ -1398,20 +1408,14 @@ bool BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
(brush->flag & BRUSH_LOCK_SIZE);
}
-bool BKE_brush_use_size_pressure(const Scene *scene, const Brush *brush)
+bool BKE_brush_use_size_pressure(const Brush *brush)
{
- const short us_flag = scene->toolsettings->unified_paint_settings.flag;
-
- return (us_flag & UNIFIED_PAINT_SIZE) ? (us_flag & UNIFIED_PAINT_BRUSH_SIZE_PRESSURE) :
- (brush->flag & BRUSH_SIZE_PRESSURE);
+ return brush->flag & BRUSH_SIZE_PRESSURE;
}
-bool BKE_brush_use_alpha_pressure(const Scene *scene, const Brush *brush)
+bool BKE_brush_use_alpha_pressure(const Brush *brush)
{
- const short us_flag = scene->toolsettings->unified_paint_settings.flag;
-
- return (us_flag & UNIFIED_PAINT_ALPHA) ? (us_flag & UNIFIED_PAINT_BRUSH_ALPHA_PRESSURE) :
- (brush->flag & BRUSH_ALPHA_PRESSURE);
+ return brush->flag & BRUSH_ALPHA_PRESSURE;
}
bool BKE_brush_sculpt_has_secondary_color(const Brush *brush)
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 463cbd4f378..c26800aefba 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -31,6 +31,7 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_edgehash.h"
#include "BLI_linklist.h"
@@ -130,6 +131,22 @@ void cloth_init(ClothModifierData *clmd)
clmd->sim_parms->eff_force_scale = 1000.0;
clmd->sim_parms->eff_wind_scale = 250.0;
+ /* Internal spring settings */
+ clmd->sim_parms->internal_spring_max_length = 0.0f;
+ clmd->sim_parms->internal_spring_max_diversion = M_PI / 4.0f;
+ clmd->sim_parms->internal_tension = 15.0f;
+ clmd->sim_parms->max_internal_tension = 15.0f;
+ clmd->sim_parms->internal_compression = 15.0f;
+ clmd->sim_parms->max_internal_compression = 15.0f;
+ clmd->sim_parms->vgroup_intern = 0;
+ clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS_NORMAL;
+
+ /* Pressure settings */
+ clmd->sim_parms->uniform_pressure_force = 0.0f;
+ clmd->sim_parms->target_volume = 0.0f;
+ clmd->sim_parms->pressure_factor = 1.0f;
+ clmd->sim_parms->vgroup_pressure = 0;
+
// also from softbodies
clmd->sim_parms->maxgoal = 1.0f;
clmd->sim_parms->mingoal = 0.0f;
@@ -291,6 +308,12 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int
BKE_cloth_solver_set_positions(clmd);
+ ClothSimSettings *parms = clmd->sim_parms;
+ if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE &&
+ !(parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL)) {
+ BKE_cloth_solver_set_volume(clmd);
+ }
+
clmd->clothObject->last_frame = MINFRAME - 1;
clmd->sim_parms->dt = 1.0f / clmd->sim_parms->stepsPerFrame;
}
@@ -640,8 +663,9 @@ int cloth_uses_vgroup(ClothModifierData *clmd)
{
return (((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) &&
(clmd->coll_parms->vgroup_selfcol > 0)) ||
- (clmd->sim_parms->vgroup_struct > 0) || (clmd->sim_parms->vgroup_bend > 0) ||
- (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->vgroup_mass > 0));
+ (clmd->sim_parms->vgroup_pressure > 0) || (clmd->sim_parms->vgroup_struct > 0) ||
+ (clmd->sim_parms->vgroup_bend > 0) || (clmd->sim_parms->vgroup_shrink > 0) ||
+ (clmd->sim_parms->vgroup_intern > 0) || (clmd->sim_parms->vgroup_mass > 0));
}
/**
@@ -649,27 +673,16 @@ int cloth_uses_vgroup(ClothModifierData *clmd)
*/
static void cloth_apply_vgroup(ClothModifierData *clmd, Mesh *mesh)
{
- /* Can be optimized to do all groups in one loop. */
- int i = 0;
- int j = 0;
- MDeformVert *dvert = NULL;
- Cloth *clothObj = NULL;
- int mvert_num;
- /* float goalfac = 0; */ /* UNUSED */
- ClothVertex *verts = NULL;
-
if (!clmd || !mesh) {
return;
}
- clothObj = clmd->clothObject;
+ int mvert_num = mesh->totvert;
- mvert_num = mesh->totvert;
-
- verts = clothObj->verts;
+ ClothVertex *verts = clmd->clothObject->verts;
if (cloth_uses_vgroup(clmd)) {
- for (i = 0; i < mvert_num; i++, verts++) {
+ for (int i = 0; i < mvert_num; i++, verts++) {
/* Reset Goal values to standard */
if (clmd->sim_parms->vgroup_mass > 0) {
@@ -686,9 +699,9 @@ static void cloth_apply_vgroup(ClothModifierData *clmd, Mesh *mesh)
verts->flags &= ~CLOTH_VERT_FLAG_PINNED;
verts->flags &= ~CLOTH_VERT_FLAG_NOSELFCOLL;
- dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
+ MDeformVert *dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
if (dvert) {
- for (j = 0; j < dvert->totweight; j++) {
+ for (int j = 0; j < dvert->totweight; j++) {
if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass - 1)) {
verts->goal = dvert->dw[j].weight;
@@ -715,19 +728,27 @@ static void cloth_apply_vgroup(ClothModifierData *clmd, Mesh *mesh)
verts->bend_stiff = dvert->dw[j].weight;
}
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
- if (dvert->dw[j].def_nr == (clmd->coll_parms->vgroup_selfcol - 1)) {
- if (dvert->dw[j].weight > 0.0f) {
- verts->flags |= CLOTH_VERT_FLAG_NOSELFCOLL;
- }
+ if (dvert->dw[j].def_nr == (clmd->coll_parms->vgroup_selfcol - 1)) {
+ if (dvert->dw[j].weight > 0.0f) {
+ verts->flags |= CLOTH_VERT_FLAG_NOSELFCOLL;
}
}
- if (clmd->sim_parms->vgroup_shrink > 0) {
- if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
- /* Used for linear interpolation between min and max
- * shrink factor based on weight. */
- verts->shrink_factor = dvert->dw[j].weight;
- }
+
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
+ /* Used for linear interpolation between min and max
+ * shrink factor based on weight. */
+ verts->shrink_factor = dvert->dw[j].weight;
+ }
+
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_intern - 1)) {
+ /* Used to define the stiffness weight on the internal spring connected to this vertex.
+ */
+ verts->internal_stiff = dvert->dw[j].weight;
+ }
+
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_pressure - 1)) {
+ /* Used to define how much the pressure settings should affect the given vertex. */
+ verts->pressure_factor = dvert->dw[j].weight;
}
}
}
@@ -739,10 +760,10 @@ static float cloth_shrink_factor(ClothModifierData *clmd, ClothVertex *verts, in
{
/* Linear interpolation between min and max shrink factor based on weight. */
float base = 1.0f - clmd->sim_parms->shrink_min;
- float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
+ float shrink_factor_delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
- float k1 = base + delta * verts[i1].shrink_factor;
- float k2 = base + delta * verts[i2].shrink_factor;
+ float k1 = base + shrink_factor_delta * verts[i1].shrink_factor;
+ float k2 = base + shrink_factor_delta * verts[i2].shrink_factor;
/* Use geometrical mean to average two factors since it behaves better
* for diagonals when a rectangle transforms into a trapezoid. */
@@ -897,9 +918,9 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh)
}
}
-/***************************************************************************************
- * SPRING NETWORK GPU_BATCH_BUILDING IMPLEMENTATION BEGIN
- ***************************************************************************************/
+/* -------------------------------------------------------------------- */
+/** \name Spring Network Building Implementation
+ * \{ */
BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1)
{
@@ -1140,6 +1161,11 @@ static void cloth_update_springs(ClothModifierData *clmd)
cloth->verts[spring->ij].bend_stiff) /
2.0f;
}
+ else if (spring->type & CLOTH_SPRING_TYPE_INTERNAL) {
+ spring->lin_stiffness = (cloth->verts[spring->kl].internal_stiff +
+ cloth->verts[spring->ij].internal_stiff) /
+ 2.0f;
+ }
else if (spring->type == CLOTH_SPRING_TYPE_BENDING_HAIR) {
ClothVertex *v1 = &cloth->verts[spring->ij];
ClothVertex *v2 = &cloth->verts[spring->kl];
@@ -1204,8 +1230,8 @@ static void cloth_update_spring_lengths(ClothModifierData *clmd, Mesh *mesh)
ClothSpring *spring = search->link;
if (spring->type != CLOTH_SPRING_TYPE_SEWING) {
- if (spring->type &
- (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING)) {
+ if (spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR |
+ CLOTH_SPRING_TYPE_BENDING | CLOTH_SPRING_TYPE_INTERNAL)) {
shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
}
else {
@@ -1381,6 +1407,85 @@ BLI_INLINE bool cloth_bend_set_poly_vert_array(int **poly, int len, const MLoop
return true;
}
+static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata,
+ unsigned int v_idx,
+ RNG *rng,
+ float max_length,
+ float max_diversion,
+ bool check_normal,
+ unsigned int *r_tar_v_idx)
+{
+ float co[3], no[3], new_co[3];
+ float radius;
+
+ copy_v3_v3(co, treedata->vert[v_idx].co);
+ normal_short_to_float_v3(no, treedata->vert[v_idx].no);
+ negate_v3(no);
+
+ float vec_len = sin(max_diversion);
+ float offset[3];
+
+ offset[0] = 0.5f - BLI_rng_get_float(rng);
+ offset[1] = 0.5f - BLI_rng_get_float(rng);
+ offset[2] = 0.5f - BLI_rng_get_float(rng);
+
+ normalize_v3(offset);
+ mul_v3_fl(offset, vec_len);
+ add_v3_v3(no, offset);
+ normalize_v3(no);
+
+ /* Nudge the start point so we do not hit it with the ray. */
+ copy_v3_v3(new_co, no);
+ mul_v3_fl(new_co, FLT_EPSILON);
+ add_v3_v3(new_co, co);
+
+ radius = 0.0f;
+ if (max_length == 0.0f) {
+ max_length = FLT_MAX;
+ }
+
+ BVHTreeRayHit rayhit = {0};
+ rayhit.index = -1;
+ rayhit.dist = max_length;
+
+ BLI_bvhtree_ray_cast(
+ treedata->tree, new_co, no, radius, &rayhit, treedata->raycast_callback, treedata);
+
+ unsigned int vert_idx = -1;
+ const MLoop *mloop = treedata->loop;
+ const MLoopTri *lt = NULL;
+
+ if (rayhit.index != -1 && rayhit.dist <= max_length) {
+ if (check_normal && dot_v3v3(rayhit.no, no) < 0.0f) {
+ /* We hit a point that points in the same direction as our starting point. */
+ return false;
+ }
+
+ float min_len = FLT_MAX;
+ lt = &treedata->looptri[rayhit.index];
+
+ for (int i = 0; i < 3; i++) {
+ unsigned int tmp_vert_idx = mloop[lt->tri[i]].v;
+ if (tmp_vert_idx == v_idx) {
+ /* We managed to hit ourselves. */
+ return false;
+ }
+
+ float len = len_v3v3(co, rayhit.co);
+ if (len < min_len) {
+ min_len = len;
+ vert_idx = tmp_vert_idx;
+ }
+ }
+
+ *r_tar_v_idx = vert_idx;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
{
Cloth *cloth = clmd->clothObject;
@@ -1427,6 +1532,69 @@ static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
}
}
+ bool use_internal_springs = (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS);
+
+ if (use_internal_springs) {
+ BVHTreeFromMesh treedata = {NULL};
+ unsigned int tar_v_idx;
+ BLI_bitmap *verts_used = NULL;
+ RNG *rng;
+
+ verts_used = BLI_BITMAP_NEW(mvert_num * mvert_num, __func__);
+ BKE_bvhtree_from_mesh_get(&treedata, mesh, BVHTREE_FROM_LOOPTRI, 2);
+ rng = BLI_rng_new_srandom(0);
+
+ for (int i = 0; i < mvert_num; i++) {
+ if (find_internal_spring_target_vertex(
+ &treedata,
+ i,
+ rng,
+ clmd->sim_parms->internal_spring_max_length,
+ clmd->sim_parms->internal_spring_max_diversion,
+ (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS_NORMAL),
+ &tar_v_idx)) {
+ if (BLI_BITMAP_TEST_BOOL(verts_used, i * mvert_num + tar_v_idx)) {
+ continue;
+ }
+
+ BLI_BITMAP_ENABLE(verts_used, i * mvert_num + tar_v_idx);
+ BLI_BITMAP_ENABLE(verts_used, tar_v_idx * mvert_num + i);
+
+ spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+
+ if (spring) {
+ spring_verts_ordered_set(spring, i, tar_v_idx);
+
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest,
+ cloth->verts[spring->ij].xrest) *
+ shrink_factor;
+ spring->lin_stiffness = (cloth->verts[spring->kl].internal_stiff +
+ cloth->verts[spring->ij].internal_stiff) /
+ 2.0f;
+ spring->type = CLOTH_SPRING_TYPE_INTERNAL;
+
+ spring->flags = 0;
+
+ BLI_linklist_prepend(&cloth->springs, spring);
+
+ if (spring_ref) {
+ spring_ref[i].spring = spring;
+ }
+ }
+ else {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ MEM_freeN(verts_used);
+ free_bvhtree_from_mesh(&treedata);
+ return 0;
+ }
+ }
+ }
+ MEM_freeN(verts_used);
+ free_bvhtree_from_mesh(&treedata);
+ BLI_rng_free(rng);
+ }
+
clmd->sim_parms->avg_spring_len = 0.0f;
for (int i = 0; i < mvert_num; i++) {
cloth->verts[i].avg_spring_len = 0.0f;
@@ -1740,8 +1908,6 @@ static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
#endif
return 1;
+}
-} /* cloth_build_springs */
-/***************************************************************************************
- * SPRING NETWORK GPU_BATCH_BUILDING IMPLEMENTATION END
- ***************************************************************************************/
+/** \} */
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 8166bbea962..2ec04ee2747 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -54,7 +54,7 @@ void BKE_curvemapping_set_defaults(
int a;
float clipminx, clipminy, clipmaxx, clipmaxy;
- cumap->flag = CUMA_DO_CLIP;
+ cumap->flag = CUMA_DO_CLIP | CUMA_EXTEND_EXTRAPOLATE;
if (tot == 4) {
cumap->cur = 3; /* rhms, hack for 'col' curve? */
}
@@ -71,7 +71,6 @@ void BKE_curvemapping_set_defaults(
cumap->bwmul[0] = cumap->bwmul[1] = cumap->bwmul[2] = 1.0f;
for (a = 0; a < tot; a++) {
- cumap->cm[a].flag = CUMA_EXTEND_EXTRAPOLATE;
cumap->cm[a].totpoint = 2;
cumap->cm[a].curve = MEM_callocN(2 * sizeof(CurveMapPoint), "curve points");
@@ -591,14 +590,15 @@ static void calchandle_curvemap(BezTriple *bezt, const BezTriple *prev, const Be
/* in X, out Y.
* X is presumed to be outside first or last */
-static float curvemap_calc_extend(const CurveMap *cuma,
+static float curvemap_calc_extend(const CurveMapping *cumap,
+ const CurveMap *cuma,
float x,
const float first[2],
const float last[2])
{
if (x <= first[0]) {
- if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
- /* no extrapolate */
+ if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
+ /* extrapolate horizontally */
return first[1];
}
else {
@@ -611,8 +611,8 @@ static float curvemap_calc_extend(const CurveMap *cuma,
}
}
else if (x >= last[0]) {
- if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
- /* no extrapolate */
+ if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
+ /* extrapolate horizontally */
return last[1];
}
else {
@@ -628,8 +628,9 @@ static float curvemap_calc_extend(const CurveMap *cuma,
}
/* only creates a table for a single channel in CurveMapping */
-static void curvemap_make_table(CurveMap *cuma, const rctf *clipr)
+static void curvemap_make_table(const CurveMapping *cumap, CurveMap *cuma)
{
+ const rctf *clipr = &cumap->clipr;
CurveMapPoint *cmp = cuma->curve;
BezTriple *bezt;
@@ -782,7 +783,7 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr)
}
else {
/* Extrapolate values that lie outside the start and end point. */
- cmp[a].y = curvemap_calc_extend(cuma, cur_x, firstpoint, lastpoint);
+ cmp[a].y = curvemap_calc_extend(cumap, cuma, cur_x, firstpoint, lastpoint);
}
}
else {
@@ -829,7 +830,7 @@ void BKE_curvemapping_premultiply(CurveMapping *cumap, int restore)
/* verify and copy */
for (a = 0; a < 3; a++) {
if (cumap->cm[a].table == NULL) {
- curvemap_make_table(cumap->cm + a, &cumap->clipr);
+ curvemap_make_table(cumap, cumap->cm + a);
}
cumap->cm[a].premultable = cumap->cm[a].table;
cumap->cm[a].table = MEM_mallocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "premul table");
@@ -838,14 +839,15 @@ void BKE_curvemapping_premultiply(CurveMapping *cumap, int restore)
}
if (cumap->cm[3].table == NULL) {
- curvemap_make_table(cumap->cm + 3, &cumap->clipr);
+ curvemap_make_table(cumap, cumap->cm + 3);
}
/* premul */
for (a = 0; a < 3; a++) {
int b;
for (b = 0; b <= CM_TABLE; b++) {
- cumap->cm[a].table[b].y = BKE_curvemap_evaluateF(cumap->cm + 3, cumap->cm[a].table[b].y);
+ cumap->cm[a].table[b].y = BKE_curvemap_evaluateF(
+ cumap, cumap->cm + 3, cumap->cm[a].table[b].y);
}
copy_v2_v2(cumap->cm[a].premul_ext_in, cumap->cm[a].ext_in);
@@ -949,7 +951,7 @@ void BKE_curvemapping_changed(CurveMapping *cumap, const bool rem_doubles)
BKE_curvemap_remove(cuma, 2);
}
}
- curvemap_make_table(cuma, clipr);
+ curvemap_make_table(cumap, cuma);
}
void BKE_curvemapping_changed_all(CurveMapping *cumap)
@@ -967,7 +969,7 @@ void BKE_curvemapping_changed_all(CurveMapping *cumap)
}
/* table should be verified */
-float BKE_curvemap_evaluateF(const CurveMap *cuma, float value)
+float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, float value)
{
float fi;
int i;
@@ -978,7 +980,7 @@ float BKE_curvemap_evaluateF(const CurveMap *cuma, float value)
/* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
if (fi < 0.0f || fi > CM_TABLE) {
- return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
+ return curvemap_calc_extend(cumap, cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
}
else {
if (i < 0) {
@@ -997,7 +999,7 @@ float BKE_curvemap_evaluateF(const CurveMap *cuma, float value)
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
{
const CurveMap *cuma = cumap->cm + cur;
- float val = BKE_curvemap_evaluateF(cuma, value);
+ float val = BKE_curvemap_evaluateF(cumap, cuma, value);
/* account for clipping */
if (cumap->flag & CUMA_DO_CLIP) {
@@ -1015,9 +1017,9 @@ float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value
/* vector case */
void BKE_curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], const float vecin[3])
{
- vecout[0] = BKE_curvemap_evaluateF(&cumap->cm[0], vecin[0]);
- vecout[1] = BKE_curvemap_evaluateF(&cumap->cm[1], vecin[1]);
- vecout[2] = BKE_curvemap_evaluateF(&cumap->cm[2], vecin[2]);
+ vecout[0] = BKE_curvemap_evaluateF(cumap, &cumap->cm[0], vecin[0]);
+ vecout[1] = BKE_curvemap_evaluateF(cumap, &cumap->cm[1], vecin[1]);
+ vecout[2] = BKE_curvemap_evaluateF(cumap, &cumap->cm[2], vecin[2]);
}
/* RGB case, no black/white points, no premult */
@@ -1025,12 +1027,12 @@ void BKE_curvemapping_evaluateRGBF(const CurveMapping *cumap,
float vecout[3],
const float vecin[3])
{
- vecout[0] = BKE_curvemap_evaluateF(&cumap->cm[0],
- BKE_curvemap_evaluateF(&cumap->cm[3], vecin[0]));
- vecout[1] = BKE_curvemap_evaluateF(&cumap->cm[1],
- BKE_curvemap_evaluateF(&cumap->cm[3], vecin[1]));
- vecout[2] = BKE_curvemap_evaluateF(&cumap->cm[2],
- BKE_curvemap_evaluateF(&cumap->cm[3], vecin[2]));
+ vecout[0] = BKE_curvemap_evaluateF(
+ cumap, &cumap->cm[0], BKE_curvemap_evaluateF(cumap, &cumap->cm[3], vecin[0]));
+ vecout[1] = BKE_curvemap_evaluateF(
+ cumap, &cumap->cm[1], BKE_curvemap_evaluateF(cumap, &cumap->cm[3], vecin[1]));
+ vecout[2] = BKE_curvemap_evaluateF(
+ cumap, &cumap->cm[2], BKE_curvemap_evaluateF(cumap, &cumap->cm[3], vecin[2]));
}
static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap,
@@ -1042,8 +1044,8 @@ static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap,
const float v1in = vecin[channel_offset[1]];
const float v2in = vecin[channel_offset[2]];
- const float v0 = BKE_curvemap_evaluateF(&cumap->cm[channel_offset[0]], v0in);
- const float v2 = BKE_curvemap_evaluateF(&cumap->cm[channel_offset[2]], v2in);
+ const float v0 = BKE_curvemap_evaluateF(cumap, &cumap->cm[channel_offset[0]], v0in);
+ const float v2 = BKE_curvemap_evaluateF(cumap, &cumap->cm[channel_offset[2]], v2in);
const float v1 = v2 + ((v0 - v2) * (v1in - v2in) / (v0in - v2in));
vecout[channel_offset[0]] = v0;
@@ -1074,9 +1076,9 @@ void BKE_curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap,
switch (cumap->tone) {
default:
case CURVE_TONE_STANDARD: {
- vecout[0] = BKE_curvemap_evaluateF(&cumap->cm[0], r);
- vecout[1] = BKE_curvemap_evaluateF(&cumap->cm[1], g);
- vecout[2] = BKE_curvemap_evaluateF(&cumap->cm[2], b);
+ vecout[0] = BKE_curvemap_evaluateF(cumap, &cumap->cm[0], r);
+ vecout[1] = BKE_curvemap_evaluateF(cumap, &cumap->cm[1], g);
+ vecout[2] = BKE_curvemap_evaluateF(cumap, &cumap->cm[2], b);
break;
}
case CURVE_TONE_FILMLIKE: {
@@ -1099,8 +1101,8 @@ void BKE_curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap,
else {
/* Case 4: r >= g == b */
copy_v2_fl2(vecout,
- BKE_curvemap_evaluateF(&cumap->cm[0], r),
- BKE_curvemap_evaluateF(&cumap->cm[1], g));
+ BKE_curvemap_evaluateF(cumap, &cumap->cm[0], r),
+ BKE_curvemap_evaluateF(cumap, &cumap->cm[1], g));
vecout[2] = vecout[1];
}
}
@@ -1208,7 +1210,7 @@ void BKE_curvemapping_initialize(CurveMapping *cumap)
for (a = 0; a < CM_TOT; a++) {
if (cumap->cm[a].table == NULL) {
- curvemap_make_table(cumap->cm + a, &cumap->clipr);
+ curvemap_make_table(cumap, cumap->cm + a);
}
}
}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index c397fbcf115..a17a09297c5 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -2062,36 +2062,21 @@ static void translike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
- if (data->mix_mode == TRANSLIKE_MIX_REPLACE) {
- /* just copy the entire transform matrix of the target */
- copy_m4_m4(cob->matrix, ct->matrix);
- }
- else {
- float old_loc[3], old_rot[3][3], old_size[3];
- float new_loc[3], new_rot[3][3], new_size[3];
-
- /* Separate matrices so they can be combined in a way that avoids shear. */
- mat4_to_loc_rot_size(old_loc, old_rot, old_size, cob->matrix);
- mat4_to_loc_rot_size(new_loc, new_rot, new_size, ct->matrix);
-
- switch (data->mix_mode) {
- case TRANSLIKE_MIX_BEFORE:
- mul_v3_m4v3(new_loc, ct->matrix, old_loc);
- mul_m3_m3m3(new_rot, new_rot, old_rot);
- mul_v3_v3(new_size, old_size);
- break;
+ switch (data->mix_mode) {
+ case TRANSLIKE_MIX_REPLACE:
+ copy_m4_m4(cob->matrix, ct->matrix);
+ break;
- case TRANSLIKE_MIX_AFTER:
- mul_v3_m4v3(new_loc, cob->matrix, new_loc);
- mul_m3_m3m3(new_rot, old_rot, new_rot);
- mul_v3_v3(new_size, old_size);
- break;
+ case TRANSLIKE_MIX_BEFORE:
+ mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix);
+ break;
- default:
- BLI_assert(false);
- }
+ case TRANSLIKE_MIX_AFTER:
+ mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, ct->matrix);
+ break;
- loc_rot_size_to_mat4(cob->matrix, new_loc, new_rot, new_size);
+ default:
+ BLI_assert(!"Unknown Copy Transforms mix mode");
}
}
}
@@ -2555,6 +2540,9 @@ static void actcon_new_data(void *cdata)
/* set type to 20 (Loc X), as 0 is Rot X for backwards compatibility */
data->type = 20;
+
+ /* Set the mix mode to After Original with anti-shear scale handling. */
+ data->mix_mode = ACTCON_MIX_AFTER;
}
static void actcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -2695,18 +2683,28 @@ static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
}
}
-static void actcon_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets)
+static void actcon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
+ bActionConstraint *data = con->data;
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
- float temp[4][4];
+ switch (data->mix_mode) {
+ case ACTCON_MIX_BEFORE:
+ mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix);
+ break;
- /* Nice and simple... we just need to multiply the matrices, as the get_target_matrix
- * function has already taken care of everything else.
- */
- copy_m4_m4(temp, cob->matrix);
- mul_m4_m4m4(cob->matrix, temp, ct->matrix);
+ case ACTCON_MIX_AFTER:
+ mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, ct->matrix);
+ break;
+
+ case ACTCON_MIX_AFTER_FULL:
+ mul_m4_m4m4(cob->matrix, cob->matrix, ct->matrix);
+ break;
+
+ default:
+ BLI_assert(!"Unknown Action mix mode");
+ }
}
}
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 2e4f756ce68..e3d95bb660f 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -466,6 +466,18 @@ PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, Stru
return PointerRNA_NULL;
}
+PointerRNA CTX_data_pointer_get_type_silent(const bContext *C, const char *member, StructRNA *type)
+{
+ PointerRNA ptr = CTX_data_pointer_get(C, member);
+
+ if (ptr.data && RNA_struct_is_a(ptr.type, type)) {
+ return ptr;
+ }
+ else {
+ return PointerRNA_NULL;
+ }
+}
+
ListBase CTX_data_collection_get(const bContext *C, const char *member)
{
bContextDataResult result;
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 9618ef8c78e..33f9b5b1012 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -417,12 +417,12 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, me_eval->totvert);
}
else {
+ /* More complex handling will continue in BKE_crazyspace_build_sculpt.
+ * Exiting the loop on a non-deform modifier causes issues - T71213. */
+ BLI_assert(crazyspace_modifier_supports_deform(md));
break;
}
}
- else {
- break;
- }
}
for (; md; md = md->next) {
diff --git a/source/blender/blenkernel/intern/curve_decimate.c b/source/blender/blenkernel/intern/curve_decimate.c
index cccdf830854..d569684d55c 100644
--- a/source/blender/blenkernel/intern/curve_decimate.c
+++ b/source/blender/blenkernel/intern/curve_decimate.c
@@ -269,11 +269,11 @@ uint BKE_curve_decimate_bezt_array(BezTriple *bezt_array,
if (a == HD_VECT) { \
a = HD_FREE; \
} \
- else if (a == HD_AUTO) { \
+ else if (a == HD_AUTO || a == HD_AUTO_ANIM) { \
a = HD_ALIGN; \
} \
/* opposite handle */ \
- if (b == HD_AUTO) { \
+ if (b == HD_AUTO || b == HD_AUTO_ANIM) { \
b = HD_ALIGN; \
} \
} \
diff --git a/source/blender/blenkernel/intern/curveprofile.c b/source/blender/blenkernel/intern/curveprofile.c
index 2b253d439e0..cd25d616454 100644
--- a/source/blender/blenkernel/intern/curveprofile.c
+++ b/source/blender/blenkernel/intern/curveprofile.c
@@ -308,7 +308,7 @@ static void CurveProfile_build_supports(CurveProfile *profile)
}
/**
- * Puts the widget's control points in a step pattern.
+ * Puts the widgets control points in a step pattern.
* Uses vector handles for each point.
*/
static void CurveProfile_build_steps(CurveProfile *profile)
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 91b169590ac..74a523bfbdc 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -6278,7 +6278,14 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph,
/* Apply brush on the surface depending on it's collision type */
if (brush->psys && brush->psys->part &&
- ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
+ ELEM(brush->psys->part->type,
+ PART_EMITTER,
+ PART_FLUID,
+ PART_FLUID_FLIP,
+ PART_FLUID_SPRAY,
+ PART_FLUID_BUBBLE,
+ PART_FLUID_FOAM,
+ PART_FLUID_TRACER) &&
psys_check_enabled(brushObj, brush->psys, for_render)) {
/* Paint a particle system */
dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
deleted file mode 100644
index 2df3d2f0fe9..00000000000
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup bke
- *
- * basic design:
- *
- * the bmesh derivedmesh exposes the mesh as triangles. it stores pointers
- * to three loops per triangle. the derivedmesh stores a cache of tessellations
- * for each face. this cache will smartly update as needed (though at first
- * it'll simply be more brute force). keeping track of face/edge counts may
- * be a small problem.
- *
- * this won't be the most efficient thing, considering that internal edges and
- * faces of tessellations are exposed. looking up an edge by index in particular
- * is likely to be a little slow.
- */
-
-#include "atomic_ops.h"
-
-#include "BLI_math.h"
-#include "BLI_jitter_2d.h"
-#include "BLI_bitmap.h"
-#include "BLI_task.h"
-
-#include "BKE_cdderivedmesh.h"
-#include "BKE_deform.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_iterators.h"
-#include "BKE_editmesh.h"
-#include "BKE_editmesh_bvh.h"
-#include "BKE_editmesh_cache.h"
-#include "BKE_editmesh_tangent.h"
-
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-#include "DNA_mesh_types.h"
-
-#include "MEM_guardedalloc.h"
-
-/* -------------------------------------------------------------------- */
-/* StatVis Functions */
-
-static void axis_from_enum_v3(float v[3], const char axis)
-{
- zero_v3(v);
- if (axis < 3) {
- v[axis] = 1.0f;
- }
- else {
- v[axis - 3] = -1.0f;
- }
-}
-
-static void statvis_calc_overhang(BMEditMesh *em,
- const float (*polyNos)[3],
- /* values for calculating */
- const float min,
- const float max,
- const char axis,
- /* result */
- unsigned char (*r_face_colors)[4])
-{
- BMIter iter;
- BMesh *bm = em->bm;
- BMFace *f;
- float dir[3];
- int index;
- const float minmax_irange = 1.0f / (max - min);
- bool is_max;
-
- /* fallback */
- unsigned char col_fallback[4] = {64, 64, 64, 255}; /* gray */
- unsigned char col_fallback_max[4] = {0, 0, 0, 255}; /* max color */
-
- BLI_assert(min <= max);
-
- axis_from_enum_v3(dir, axis);
-
- if (LIKELY(em->ob)) {
- mul_transposed_mat3_m4_v3(em->ob->obmat, dir);
- normalize_v3(dir);
- }
-
- /* fallback max */
- {
- float fcol[3];
- BKE_defvert_weight_to_rgb(fcol, 1.0f);
- rgb_float_to_uchar(col_fallback_max, fcol);
- }
-
- /* now convert into global space */
- BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) {
- float fac = angle_normalized_v3v3(polyNos ? polyNos[index] : f->no, dir) / (float)M_PI;
-
- /* remap */
- if ((is_max = (fac <= max)) && (fac >= min)) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- fac = 1.0f - fac;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_face_colors[index], fcol);
- }
- else {
- const unsigned char *fallback = is_max ? col_fallback_max : col_fallback;
- copy_v4_v4_uchar(r_face_colors[index], fallback);
- }
- }
-}
-
-/* so we can use jitter values for face interpolation */
-static void uv_from_jitter_v2(float uv[2])
-{
- uv[0] += 0.5f;
- uv[1] += 0.5f;
- if (uv[0] + uv[1] > 1.0f) {
- uv[0] = 1.0f - uv[0];
- uv[1] = 1.0f - uv[1];
- }
-
- CLAMP(uv[0], 0.0f, 1.0f);
- CLAMP(uv[1], 0.0f, 1.0f);
-}
-
-static void statvis_calc_thickness(BMEditMesh *em,
- const float (*vertexCos)[3],
- /* values for calculating */
- const float min,
- const float max,
- const int samples,
- /* result */
- unsigned char (*r_face_colors)[4])
-{
- const float eps_offset = 0.00002f; /* values <= 0.00001 give errors */
- float *face_dists = (float *)r_face_colors; /* cheating */
- const bool use_jit = samples < 32;
- float jit_ofs[32][2];
- BMesh *bm = em->bm;
- const int tottri = em->tottri;
- const float minmax_irange = 1.0f / (max - min);
- int i;
-
- struct BMLoop *(*looptris)[3] = em->looptris;
-
- /* fallback */
- const unsigned char col_fallback[4] = {64, 64, 64, 255};
-
- struct BMBVHTree *bmtree;
-
- BLI_assert(min <= max);
-
- copy_vn_fl(face_dists, em->bm->totface, max);
-
- if (use_jit) {
- int j;
- BLI_assert(samples < 32);
- BLI_jitter_init(jit_ofs, samples);
-
- for (j = 0; j < samples; j++) {
- uv_from_jitter_v2(jit_ofs[j]);
- }
- }
-
- BM_mesh_elem_index_ensure(bm, BM_FACE);
- if (vertexCos) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
-
- bmtree = BKE_bmbvh_new_from_editmesh(em, 0, vertexCos, false);
-
- for (i = 0; i < tottri; i++) {
- BMFace *f_hit;
- BMLoop **ltri = looptris[i];
- const int index = BM_elem_index_get(ltri[0]->f);
- const float *cos[3];
- float ray_co[3];
- float ray_no[3];
-
- if (vertexCos) {
- cos[0] = vertexCos[BM_elem_index_get(ltri[0]->v)];
- cos[1] = vertexCos[BM_elem_index_get(ltri[1]->v)];
- cos[2] = vertexCos[BM_elem_index_get(ltri[2]->v)];
- }
- else {
- cos[0] = ltri[0]->v->co;
- cos[1] = ltri[1]->v->co;
- cos[2] = ltri[2]->v->co;
- }
-
- normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
-
-#define FACE_RAY_TEST_ANGLE \
- f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL); \
- if (f_hit && dist < face_dists[index]) { \
- float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no)); \
- angle_fac = 1.0f - angle_fac; \
- angle_fac = angle_fac * angle_fac * angle_fac; \
- angle_fac = 1.0f - angle_fac; \
- dist /= angle_fac; \
- if (dist < face_dists[index]) { \
- face_dists[index] = dist; \
- } \
- } \
- (void)0
-
- if (use_jit) {
- int j;
- for (j = 0; j < samples; j++) {
- float dist = face_dists[index];
- interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]);
- madd_v3_v3fl(ray_co, ray_no, eps_offset);
-
- FACE_RAY_TEST_ANGLE;
- }
- }
- else {
- float dist = face_dists[index];
- mid_v3_v3v3v3(ray_co, cos[0], cos[1], cos[2]);
- madd_v3_v3fl(ray_co, ray_no, eps_offset);
-
- FACE_RAY_TEST_ANGLE;
- }
- }
-
- BKE_bmbvh_free(bmtree);
-
- /* convert floats into color! */
- for (i = 0; i < bm->totface; i++) {
- float fac = face_dists[i];
-
- /* important not '<=' */
- if (fac < max) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- fac = 1.0f - fac;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_face_colors[i], fcol);
- }
- else {
- copy_v4_v4_uchar(r_face_colors[i], col_fallback);
- }
- }
-}
-
-static void statvis_calc_intersect(BMEditMesh *em,
- const float (*vertexCos)[3],
- /* result */
- unsigned char (*r_face_colors)[4])
-{
- BMesh *bm = em->bm;
- int i;
-
- /* fallback */
- // const char col_fallback[4] = {64, 64, 64, 255};
- float fcol[3];
- unsigned char col[3];
-
- struct BMBVHTree *bmtree;
- BVHTreeOverlap *overlap;
- unsigned int overlap_len;
-
- memset(r_face_colors, 64, sizeof(int) * em->bm->totface);
-
- BM_mesh_elem_index_ensure(bm, BM_FACE);
- if (vertexCos) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
-
- bmtree = BKE_bmbvh_new_from_editmesh(em, 0, vertexCos, false);
-
- overlap = BKE_bmbvh_overlap(bmtree, bmtree, &overlap_len);
-
- /* same for all faces */
- BKE_defvert_weight_to_rgb(fcol, 1.0f);
- rgb_float_to_uchar(col, fcol);
-
- if (overlap) {
- for (i = 0; i < overlap_len; i++) {
- BMFace *f_hit_pair[2] = {
- em->looptris[overlap[i].indexA][0]->f,
- em->looptris[overlap[i].indexB][0]->f,
- };
- int j;
-
- for (j = 0; j < 2; j++) {
- BMFace *f_hit = f_hit_pair[j];
- int index;
-
- index = BM_elem_index_get(f_hit);
-
- copy_v3_v3_uchar(r_face_colors[index], col);
- }
- }
- MEM_freeN(overlap);
- }
-
- BKE_bmbvh_free(bmtree);
-}
-
-static void statvis_calc_distort(BMEditMesh *em,
- const float (*vertexCos)[3],
- const float (*polyNos)[3],
- /* values for calculating */
- const float min,
- const float max,
- /* result */
- unsigned char (*r_face_colors)[4])
-{
- BMIter iter;
- BMesh *bm = em->bm;
- BMFace *f;
- const float *f_no;
- int index;
- const float minmax_irange = 1.0f / (max - min);
-
- /* fallback */
- const unsigned char col_fallback[4] = {64, 64, 64, 255};
-
- /* now convert into global space */
- BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) {
- float fac;
-
- if (f->len == 3) {
- fac = -1.0f;
- }
- else {
- BMLoop *l_iter, *l_first;
- if (vertexCos) {
- f_no = polyNos[index];
- }
- else {
- f_no = f->no;
- }
-
- fac = 0.0f;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- float no_corner[3];
- if (vertexCos) {
- normal_tri_v3(no_corner,
- vertexCos[BM_elem_index_get(l_iter->prev->v)],
- vertexCos[BM_elem_index_get(l_iter->v)],
- vertexCos[BM_elem_index_get(l_iter->next->v)]);
- }
- else {
- BM_loop_calc_face_normal_safe(l_iter, no_corner);
- }
- /* simple way to detect (what is most likely) concave */
- if (dot_v3v3(f_no, no_corner) < 0.0f) {
- negate_v3(no_corner);
- }
- fac = max_ff(fac, angle_normalized_v3v3(f_no, no_corner));
- } while ((l_iter = l_iter->next) != l_first);
- fac *= 2.0f;
- }
-
- /* remap */
- if (fac >= min) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_face_colors[index], fcol);
- }
- else {
- copy_v4_v4_uchar(r_face_colors[index], col_fallback);
- }
- }
-}
-
-static void statvis_calc_sharp(BMEditMesh *em,
- const float (*vertexCos)[3],
- /* values for calculating */
- const float min,
- const float max,
- /* result */
- unsigned char (*r_vert_colors)[4])
-{
- float *vert_angles = (float *)r_vert_colors; /* cheating */
- BMIter iter;
- BMesh *bm = em->bm;
- BMEdge *e;
- // float f_no[3];
- const float minmax_irange = 1.0f / (max - min);
- int i;
-
- /* fallback */
- const unsigned char col_fallback[4] = {64, 64, 64, 255};
-
- (void)vertexCos; /* TODO */
-
- copy_vn_fl(vert_angles, em->bm->totvert, -M_PI);
-
- /* first assign float values to verts */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- float angle = BM_edge_calc_face_angle_signed(e);
- float *col1 = &vert_angles[BM_elem_index_get(e->v1)];
- float *col2 = &vert_angles[BM_elem_index_get(e->v2)];
- *col1 = max_ff(*col1, angle);
- *col2 = max_ff(*col2, angle);
- }
-
- /* convert floats into color! */
- for (i = 0; i < bm->totvert; i++) {
- float fac = vert_angles[i];
-
- /* important not '<=' */
- if (fac > min) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_vert_colors[i], fcol);
- }
- else {
- copy_v4_v4_uchar(r_vert_colors[i], col_fallback);
- }
- }
-}
-
-void BKE_editmesh_statvis_calc(BMEditMesh *em, EditMeshData *emd, const MeshStatVis *statvis)
-{
- switch (statvis->type) {
- case SCE_STATVIS_OVERHANG: {
- BKE_editmesh_color_ensure(em, BM_FACE);
- statvis_calc_overhang(em,
- emd ? emd->polyNos : NULL,
- statvis->overhang_min / (float)M_PI,
- statvis->overhang_max / (float)M_PI,
- statvis->overhang_axis,
- em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_THICKNESS: {
- const float scale = 1.0f / mat4_to_scale(em->ob->obmat);
- BKE_editmesh_color_ensure(em, BM_FACE);
- statvis_calc_thickness(em,
- emd ? emd->vertexCos : NULL,
- statvis->thickness_min * scale,
- statvis->thickness_max * scale,
- statvis->thickness_samples,
- em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_INTERSECT: {
- BKE_editmesh_color_ensure(em, BM_FACE);
- statvis_calc_intersect(em, emd ? emd->vertexCos : NULL, em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_DISTORT: {
- BKE_editmesh_color_ensure(em, BM_FACE);
-
- if (emd) {
- BKE_editmesh_cache_ensure_poly_normals(em, emd);
- }
-
- statvis_calc_distort(em,
- emd ? emd->vertexCos : NULL,
- emd ? emd->polyNos : NULL,
- statvis->distort_min,
- statvis->distort_max,
- em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_SHARP: {
- BKE_editmesh_color_ensure(em, BM_VERT);
- statvis_calc_sharp(em,
- emd ? emd->vertexCos : NULL,
- statvis->sharp_min,
- statvis->sharp_max,
- /* in this case they are vertex colors */
- em->derivedVertColor);
- break;
- }
- }
-}
-
-/* -------------------------------------------------------------------- */
-/* Editmesh Vert Coords */
-
-struct CageUserData {
- int totvert;
- float (*cos_cage)[3];
- BLI_bitmap *visit_bitmap;
-};
-
-static void cage_mapped_verts_callback(void *userData,
- int index,
- const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
-{
- struct CageUserData *data = userData;
-
- if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_TEST(data->visit_bitmap, index))) {
- BLI_BITMAP_ENABLE(data->visit_bitmap, index);
- copy_v3_v3(data->cos_cage[index], co);
- }
-}
-
-float (*BKE_editmesh_vert_coords_alloc(
- struct Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, int *r_vert_len))[3]
-{
- Mesh *cage;
- BLI_bitmap *visit_bitmap;
- struct CageUserData data;
- float(*cos_cage)[3];
-
- cage = editbmesh_get_eval_cage(depsgraph, scene, em->ob, em, &CD_MASK_BAREMESH);
- cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
-
- /* when initializing cage verts, we only want the first cage coordinate for each vertex,
- * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate */
- visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__);
-
- data.totvert = em->bm->totvert;
- data.cos_cage = cos_cage;
- data.visit_bitmap = visit_bitmap;
-
- BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
-
- MEM_freeN(visit_bitmap);
-
- if (r_vert_len) {
- *r_vert_len = em->bm->totvert;
- }
-
- return cos_cage;
-}
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index b135574a650..1065f11a521 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -33,6 +33,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
#include "BKE_object.h"
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
@@ -55,11 +56,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
em_copy->bb_cage = NULL;
- em_copy->derivedVertColor = NULL;
- em_copy->derivedVertColorLen = 0;
- em_copy->derivedFaceColor = NULL;
- em_copy->derivedFaceColorLen = 0;
-
em_copy->bm = BM_mesh_copy(em->bm);
/* The tessellation is NOT calculated on the copy here,
@@ -163,8 +159,6 @@ void BKE_editmesh_free(BMEditMesh *em)
{
BKE_editmesh_free_derivedmesh(em);
- BKE_editmesh_color_free(em);
-
if (em->looptris) {
MEM_freeN(em->looptris);
}
@@ -174,44 +168,54 @@ void BKE_editmesh_free(BMEditMesh *em)
}
}
-void BKE_editmesh_color_free(BMEditMesh *em)
+struct CageUserData {
+ int totvert;
+ float (*cos_cage)[3];
+ BLI_bitmap *visit_bitmap;
+};
+
+static void cage_mapped_verts_callback(void *userData,
+ int index,
+ const float co[3],
+ const float UNUSED(no_f[3]),
+ const short UNUSED(no_s[3]))
{
- if (em->derivedVertColor) {
- MEM_freeN(em->derivedVertColor);
- }
- if (em->derivedFaceColor) {
- MEM_freeN(em->derivedFaceColor);
- }
- em->derivedVertColor = NULL;
- em->derivedFaceColor = NULL;
+ struct CageUserData *data = userData;
- em->derivedVertColorLen = 0;
- em->derivedFaceColorLen = 0;
+ if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_TEST(data->visit_bitmap, index))) {
+ BLI_BITMAP_ENABLE(data->visit_bitmap, index);
+ copy_v3_v3(data->cos_cage[index], co);
+ }
}
-void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype)
+float (*BKE_editmesh_vert_coords_alloc(
+ struct Depsgraph *depsgraph, BMEditMesh *em, struct Scene *scene, int *r_vert_len))[3]
{
- switch (htype) {
- case BM_VERT:
- if (em->derivedVertColorLen != em->bm->totvert) {
- BKE_editmesh_color_free(em);
- em->derivedVertColor = MEM_mallocN(sizeof(*em->derivedVertColor) * em->bm->totvert,
- __func__);
- em->derivedVertColorLen = em->bm->totvert;
- }
- break;
- case BM_FACE:
- if (em->derivedFaceColorLen != em->bm->totface) {
- BKE_editmesh_color_free(em);
- em->derivedFaceColor = MEM_mallocN(sizeof(*em->derivedFaceColor) * em->bm->totface,
- __func__);
- em->derivedFaceColorLen = em->bm->totface;
- }
- break;
- default:
- BLI_assert(0);
- break;
+ Mesh *cage;
+ BLI_bitmap *visit_bitmap;
+ struct CageUserData data;
+ float(*cos_cage)[3];
+
+ cage = editbmesh_get_eval_cage(depsgraph, scene, em->ob, em, &CD_MASK_BAREMESH);
+ cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
+
+ /* when initializing cage verts, we only want the first cage coordinate for each vertex,
+ * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate */
+ visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+
+ data.totvert = em->bm->totvert;
+ data.cos_cage = cos_cage;
+ data.visit_bitmap = visit_bitmap;
+
+ BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
+
+ MEM_freeN(visit_bitmap);
+
+ if (r_vert_len) {
+ *r_vert_len = em->bm->totvert;
}
+
+ return cos_cage;
}
float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index ffab82b75af..8971021329a 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -62,7 +62,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
-#include "BKE_smoke.h"
+#include "BKE_fluid.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_physics.h"
@@ -71,13 +71,6 @@
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
-/* fluid sim particle import */
-#ifdef WITH_MOD_FLUID
-# include "LBM_fluidsim.h"
-# include <zlib.h>
-# include <string.h>
-#endif // WITH_MOD_FLUID
-
EffectorWeights *BKE_effector_add_weights(Collection *collection)
{
EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights");
@@ -1031,9 +1024,10 @@ static void do_physical_effector(EffectorCache *eff,
break;
case PFIELD_SMOKEFLOW:
zero_v3(force);
+#ifdef WITH_FLUID
if (pd->f_source) {
float density;
- if ((density = BKE_smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
+ if ((density = BKE_fluid_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
float influence = strength * efd->falloff;
if (pd->flag & PFIELD_SMOKE_DENSITY) {
influence *= density;
@@ -1043,6 +1037,7 @@ static void do_physical_effector(EffectorCache *eff,
madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence);
}
}
+#endif
break;
}
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
new file mode 100644
index 00000000000..96be64dea75
--- /dev/null
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -0,0 +1,4966 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+
+#include "BLI_fileops.h"
+#include "BLI_math.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_fluid_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_effect.h"
+#include "BKE_fluid.h"
+#include "BKE_library.h"
+#include "BKE_modifier.h"
+#include "BKE_pointcache.h"
+
+#ifdef WITH_FLUID
+
+# include <float.h>
+# include <math.h>
+# include <stdio.h>
+# include <string.h> /* memset */
+
+# include "DNA_customdata_types.h"
+# include "DNA_light_types.h"
+# include "DNA_mesh_types.h"
+# include "DNA_meshdata_types.h"
+# include "DNA_particle_types.h"
+# include "DNA_scene_types.h"
+
+# include "BLI_kdopbvh.h"
+# include "BLI_threads.h"
+# include "BLI_kdtree.h"
+# include "BLI_voxel.h"
+
+# include "BKE_bvhutils.h"
+# include "BKE_collision.h"
+# include "BKE_colortools.h"
+# include "BKE_customdata.h"
+# include "BKE_deform.h"
+# include "BKE_mesh.h"
+# include "BKE_mesh_runtime.h"
+# include "BKE_object.h"
+# include "BKE_particle.h"
+# include "BKE_scene.h"
+# include "BKE_texture.h"
+
+# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_query.h"
+
+# include "RE_shader_ext.h"
+
+# include "manta_fluid_API.h"
+
+#endif /* WITH_FLUID */
+
+/** Time step default value for nice appearance. */
+#define DT_DEFAULT 0.1f
+
+static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need_lock);
+
+#ifdef WITH_FLUID
+// #define DEBUG_PRINT
+
+/* -------------------------------------------------------------------- */
+/** \name Fluid API
+ * \{ */
+
+static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
+
+struct FluidModifierData;
+struct Mesh;
+struct Object;
+struct Scene;
+
+# define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
+# define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
+# define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
+
+void BKE_fluid_reallocate_fluid(FluidDomainSettings *mds, int res[3], int free_old)
+{
+ if (free_old && mds->fluid) {
+ manta_free(mds->fluid);
+ }
+ if (!min_iii(res[0], res[1], res[2])) {
+ mds->fluid = NULL;
+ return;
+ }
+
+ mds->fluid = manta_init(res, mds->mmd);
+
+ mds->res_noise[0] = res[0] * mds->noise_scale;
+ mds->res_noise[1] = res[1] * mds->noise_scale;
+ mds->res_noise[2] = res[2] * mds->noise_scale;
+}
+
+void BKE_fluid_reallocate_copy_fluid(FluidDomainSettings *mds,
+ int o_res[3],
+ int n_res[3],
+ int o_min[3],
+ int n_min[3],
+ int o_max[3],
+ int o_shift[3],
+ int n_shift[3])
+{
+ int x, y, z;
+ struct MANTA *fluid_old = mds->fluid;
+ const int block_size = mds->noise_scale;
+ int new_shift[3] = {0};
+ sub_v3_v3v3_int(new_shift, n_shift, o_shift);
+
+ /* allocate new fluid data */
+ BKE_fluid_reallocate_fluid(mds, n_res, 0);
+
+ int o_total_cells = o_res[0] * o_res[1] * o_res[2];
+ int n_total_cells = n_res[0] * n_res[1] * n_res[2];
+
+ /* boundary cells will be skipped when copying data */
+ int bwidth = mds->boundary_width;
+
+ /* copy values from old fluid to new */
+ if (o_total_cells > 1 && n_total_cells > 1) {
+ /* base smoke */
+ float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_vx, *o_vy, *o_vz, *o_r, *o_g, *o_b;
+ float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_vx, *n_vy, *n_vz, *n_r, *n_g, *n_b;
+ float dummy, *dummy_s;
+ int *dummy_p;
+ /* noise smoke */
+ int wt_res_old[3];
+ float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw,
+ *o_wt_tcu2, *o_wt_tcv2, *o_wt_tcw2, *o_wt_r, *o_wt_g, *o_wt_b;
+ float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw,
+ *n_wt_tcu2, *n_wt_tcv2, *n_wt_tcw2, *n_wt_r, *n_wt_g, *n_wt_b;
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ manta_smoke_turbulence_export(fluid_old,
+ &o_wt_dens,
+ &o_wt_react,
+ &o_wt_flame,
+ &o_wt_fuel,
+ &o_wt_r,
+ &o_wt_g,
+ &o_wt_b,
+ &o_wt_tcu,
+ &o_wt_tcv,
+ &o_wt_tcw,
+ &o_wt_tcu2,
+ &o_wt_tcv2,
+ &o_wt_tcw2);
+ manta_smoke_turbulence_get_res(fluid_old, wt_res_old);
+ manta_smoke_turbulence_export(mds->fluid,
+ &n_wt_dens,
+ &n_wt_react,
+ &n_wt_flame,
+ &n_wt_fuel,
+ &n_wt_r,
+ &n_wt_g,
+ &n_wt_b,
+ &n_wt_tcu,
+ &n_wt_tcv,
+ &n_wt_tcw,
+ &n_wt_tcu2,
+ &n_wt_tcv2,
+ &n_wt_tcw2);
+ }
+
+ manta_smoke_export(fluid_old,
+ &dummy,
+ &dummy,
+ &o_dens,
+ &o_react,
+ &o_flame,
+ &o_fuel,
+ &o_heat,
+ &o_vx,
+ &o_vy,
+ &o_vz,
+ &o_r,
+ &o_g,
+ &o_b,
+ &dummy_p,
+ &dummy_s);
+ manta_smoke_export(mds->fluid,
+ &dummy,
+ &dummy,
+ &n_dens,
+ &n_react,
+ &n_flame,
+ &n_fuel,
+ &n_heat,
+ &n_vx,
+ &n_vy,
+ &n_vz,
+ &n_r,
+ &n_g,
+ &n_b,
+ &dummy_p,
+ &dummy_s);
+
+ for (x = o_min[0]; x < o_max[0]; x++) {
+ for (y = o_min[1]; y < o_max[1]; y++) {
+ for (z = o_min[2]; z < o_max[2]; z++) {
+ /* old grid index */
+ int xo = x - o_min[0];
+ int yo = y - o_min[1];
+ int zo = z - o_min[2];
+ int index_old = manta_get_index(xo, o_res[0], yo, o_res[1], zo);
+ /* new grid index */
+ int xn = x - n_min[0] - new_shift[0];
+ int yn = y - n_min[1] - new_shift[1];
+ int zn = z - n_min[2] - new_shift[2];
+ int index_new = manta_get_index(xn, n_res[0], yn, n_res[1], zn);
+
+ /* skip if outside new domain */
+ if (xn < 0 || xn >= n_res[0] || yn < 0 || yn >= n_res[1] || zn < 0 || zn >= n_res[2]) {
+ continue;
+ }
+ /* skip if trying to copy from old boundary cell */
+ if (xo < bwidth || yo < bwidth || zo < bwidth || xo >= o_res[0] - bwidth ||
+ yo >= o_res[1] - bwidth || zo >= o_res[2] - bwidth) {
+ continue;
+ }
+ /* skip if trying to copy into new boundary cell */
+ if (xn < bwidth || yn < bwidth || zn < bwidth || xn >= n_res[0] - bwidth ||
+ yn >= n_res[1] - bwidth || zn >= n_res[2] - bwidth) {
+ continue;
+ }
+
+ /* copy data */
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ int i, j, k;
+ /* old grid index */
+ int xx_o = xo * block_size;
+ int yy_o = yo * block_size;
+ int zz_o = zo * block_size;
+ /* new grid index */
+ int xx_n = xn * block_size;
+ int yy_n = yn * block_size;
+ int zz_n = zn * block_size;
+
+ /* insert old texture values into new texture grids */
+ n_wt_tcu[index_new] = o_wt_tcu[index_old];
+ n_wt_tcv[index_new] = o_wt_tcv[index_old];
+ n_wt_tcw[index_new] = o_wt_tcw[index_old];
+
+ n_wt_tcu2[index_new] = o_wt_tcu2[index_old];
+ n_wt_tcv2[index_new] = o_wt_tcv2[index_old];
+ n_wt_tcw2[index_new] = o_wt_tcw2[index_old];
+
+ for (i = 0; i < block_size; i++) {
+ for (j = 0; j < block_size; j++) {
+ for (k = 0; k < block_size; k++) {
+ int big_index_old = manta_get_index(
+ xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
+ int big_index_new = manta_get_index(
+ xx_n + i, mds->res_noise[0], yy_n + j, mds->res_noise[1], zz_n + k);
+ /* copy data */
+ n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
+ if (n_wt_flame && o_wt_flame) {
+ n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
+ n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
+ n_wt_react[big_index_new] = o_wt_react[big_index_old];
+ }
+ if (n_wt_r && o_wt_r) {
+ n_wt_r[big_index_new] = o_wt_r[big_index_old];
+ n_wt_g[big_index_new] = o_wt_g[big_index_old];
+ n_wt_b[big_index_new] = o_wt_b[big_index_old];
+ }
+ }
+ }
+ }
+ }
+
+ n_dens[index_new] = o_dens[index_old];
+ /* heat */
+ if (n_heat && o_heat) {
+ n_heat[index_new] = o_heat[index_old];
+ }
+ /* fuel */
+ if (n_fuel && o_fuel) {
+ n_flame[index_new] = o_flame[index_old];
+ n_fuel[index_new] = o_fuel[index_old];
+ n_react[index_new] = o_react[index_old];
+ }
+ /* color */
+ if (o_r && n_r) {
+ n_r[index_new] = o_r[index_old];
+ n_g[index_new] = o_g[index_old];
+ n_b[index_new] = o_b[index_old];
+ }
+ n_vx[index_new] = o_vx[index_old];
+ n_vy[index_new] = o_vy[index_old];
+ n_vz[index_new] = o_vz[index_old];
+ }
+ }
+ }
+ }
+ manta_free(fluid_old);
+}
+
+void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map)
+{
+ char temp_dir[FILE_MAX];
+ int flags = mds->cache_flag;
+
+ /* Ensure cache directory is not relative */
+ const char *relbase = modifier_path_relbase_from_global(ob);
+ BLI_path_abs(mds->cache_directory, relbase);
+
+ if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) {
+ flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ if (BLI_exists(temp_dir)) {
+ BLI_delete(temp_dir, true, true);
+ }
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ if (BLI_exists(temp_dir)) {
+ BLI_delete(temp_dir, true, true);
+ }
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ if (BLI_exists(temp_dir)) {
+ BLI_delete(temp_dir, true, true);
+ }
+ mds->cache_frame_pause_data = 0;
+ }
+ if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) {
+ flags &= ~(FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ if (BLI_exists(temp_dir)) {
+ BLI_delete(temp_dir, true, true);
+ }
+ mds->cache_frame_pause_noise = 0;
+ }
+ if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) {
+ flags &= ~(FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ if (BLI_exists(temp_dir)) {
+ BLI_delete(temp_dir, true, true);
+ }
+ mds->cache_frame_pause_mesh = 0;
+ }
+ if (cache_map & FLUID_DOMAIN_OUTDATED_PARTICLES) {
+ flags &= ~(FLUID_DOMAIN_BAKING_PARTICLES | FLUID_DOMAIN_BAKED_PARTICLES |
+ FLUID_DOMAIN_OUTDATED_PARTICLES);
+ BLI_path_join(
+ temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ if (BLI_exists(temp_dir)) {
+ BLI_delete(temp_dir, true, true);
+ }
+ mds->cache_frame_pause_particles = 0;
+ }
+
+ if (cache_map & FLUID_DOMAIN_OUTDATED_GUIDE) {
+ flags &= ~(FLUID_DOMAIN_BAKING_GUIDE | FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
+ if (BLI_exists(temp_dir)) {
+ BLI_delete(temp_dir, true, true);
+ }
+ mds->cache_frame_pause_guide = 0;
+ }
+ mds->cache_flag = flags;
+}
+
+/* convert global position to domain cell space */
+static void manta_pos_to_cell(FluidDomainSettings *mds, float pos[3])
+{
+ mul_m4_v3(mds->imat, pos);
+ sub_v3_v3(pos, mds->p0);
+ pos[0] *= 1.0f / mds->cell_size[0];
+ pos[1] *= 1.0f / mds->cell_size[1];
+ pos[2] *= 1.0f / mds->cell_size[2];
+}
+
+/* Set domain transformations and base resolution from object mesh. */
+static void manta_set_domain_from_mesh(FluidDomainSettings *mds,
+ Object *ob,
+ Mesh *me,
+ bool init_resolution)
+{
+ size_t i;
+ float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+ float size[3];
+ MVert *verts = me->mvert;
+ float scale = 0.0;
+ int res;
+
+ res = mds->maxres;
+
+ /* Set minimum and maximum coordinates of BB. */
+ for (i = 0; i < me->totvert; i++) {
+ minmax_v3v3_v3(min, max, verts[i].co);
+ }
+
+ /* Set domain bounds. */
+ copy_v3_v3(mds->p0, min);
+ copy_v3_v3(mds->p1, max);
+ mds->dx = 1.0f / res;
+
+ /* Calculate domain dimensions. */
+ sub_v3_v3v3(size, max, min);
+ if (init_resolution) {
+ zero_v3_int(mds->base_res);
+ copy_v3_v3(mds->cell_size, size);
+ }
+ /* Apply object scale. */
+ for (i = 0; i < 3; i++) {
+ size[i] = fabsf(size[i] * ob->scale[i]);
+ }
+ copy_v3_v3(mds->global_size, size);
+ copy_v3_v3(mds->dp0, min);
+
+ invert_m4_m4(mds->imat, ob->obmat);
+
+ /* Prevent crash when initializing a plane as domain. */
+ if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) ||
+ (size[2] < FLT_EPSILON)) {
+ return;
+ }
+
+ /* Define grid resolutions from longest domain side. */
+ if (size[0] >= MAX2(size[1], size[2])) {
+ scale = res / size[0];
+ mds->scale = size[0] / fabsf(ob->scale[0]);
+ mds->base_res[0] = res;
+ mds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
+ mds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
+ }
+ else if (size[1] >= MAX2(size[0], size[2])) {
+ scale = res / size[1];
+ mds->scale = size[1] / fabsf(ob->scale[1]);
+ mds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
+ mds->base_res[1] = res;
+ mds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
+ }
+ else {
+ scale = res / size[2];
+ mds->scale = size[2] / fabsf(ob->scale[2]);
+ mds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
+ mds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
+ mds->base_res[2] = res;
+ }
+
+ /* Set cell size. */
+ mds->cell_size[0] /= (float)mds->base_res[0];
+ mds->cell_size[1] /= (float)mds->base_res[1];
+ mds->cell_size[2] /= (float)mds->base_res[2];
+}
+
+static void manta_set_domain_gravity(Scene *scene, FluidDomainSettings *mds)
+{
+ float gravity[3] = {0.0f, 0.0f, -1.0f};
+ float gravity_mag;
+
+ /* Use global gravity if enabled. */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(gravity, scene->physics_settings.gravity);
+ /* Map default value to 1.0. */
+ mul_v3_fl(gravity, 1.0f / 9.810f);
+
+ /* Convert gravity to domain space. */
+ gravity_mag = len_v3(gravity);
+ mul_mat3_m4_v3(mds->imat, gravity);
+ normalize_v3(gravity);
+ mul_v3_fl(gravity, gravity_mag);
+
+ copy_v3_v3(mds->gravity, gravity);
+ }
+}
+
+static bool BKE_fluid_modifier_init(
+ FluidModifierData *mmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me)
+{
+ int scene_framenr = (int)DEG_get_ctime(depsgraph);
+
+ if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain && !mmd->domain->fluid) {
+ FluidDomainSettings *mds = mmd->domain;
+ int res[3];
+ /* Set domain dimensions from mesh. */
+ manta_set_domain_from_mesh(mds, ob, me, true);
+ /* Set domain gravity. */
+ manta_set_domain_gravity(scene, mds);
+ /* Reset domain values. */
+ zero_v3_int(mds->shift);
+ zero_v3(mds->shift_f);
+ add_v3_fl(mds->shift_f, 0.5f);
+ zero_v3(mds->prev_loc);
+ mul_m4_v3(ob->obmat, mds->prev_loc);
+ copy_m4_m4(mds->obmat, ob->obmat);
+
+ /* Set resolutions. */
+ if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS &&
+ mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
+ res[0] = res[1] = res[2] = 1; /* Use minimum res for adaptive init. */
+ }
+ else {
+ copy_v3_v3_int(res, mds->base_res);
+ }
+ copy_v3_v3_int(mds->res, res);
+ mds->total_cells = mds->res[0] * mds->res[1] * mds->res[2];
+ mds->res_min[0] = mds->res_min[1] = mds->res_min[2] = 0;
+ copy_v3_v3_int(mds->res_max, res);
+
+ /* Set time, frame length = 0.1 is at 25fps. */
+ float fps = scene->r.frs_sec / scene->r.frs_sec_base;
+ mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale;
+ /* Initially dt is equal to frame length (dt can change with adaptive-time stepping though). */
+ mds->dt = mds->frame_length;
+ mds->time_per_frame = 0;
+ mds->time_total = (scene_framenr - 1) * mds->frame_length;
+
+ /* Allocate fluid. */
+ BKE_fluid_reallocate_fluid(mds, mds->res, 0);
+
+ mmd->time = scene_framenr;
+
+ return true;
+ }
+ else if (mmd->type & MOD_FLUID_TYPE_FLOW) {
+ if (!mmd->flow) {
+ BKE_fluid_modifier_create_type_data(mmd);
+ }
+ mmd->time = scene_framenr;
+ return true;
+ }
+ else if (mmd->type & MOD_FLUID_TYPE_EFFEC) {
+ if (!mmd->effector) {
+ BKE_fluid_modifier_create_type_data(mmd);
+ }
+ mmd->time = scene_framenr;
+ return true;
+ }
+ return false;
+}
+
+// forward declaration
+static void manta_smoke_calc_transparency(FluidDomainSettings *mds, ViewLayer *view_layer);
+static float calc_voxel_transp(
+ float *result, float *input, int res[3], int *pixel, float *t_ray, float correct);
+static void update_mesh_distances(int index,
+ float *mesh_distances,
+ BVHTreeFromMesh *tree_data,
+ const float ray_start[3],
+ float surface_thickness,
+ int use_plane_init);
+
+static int get_light(ViewLayer *view_layer, float *light)
+{
+ Base *base_tmp = NULL;
+ int found_light = 0;
+
+ // try to find a lamp, preferably local
+ for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
+ if (base_tmp->object->type == OB_LAMP) {
+ Light *la = base_tmp->object->data;
+
+ if (la->type == LA_LOCAL) {
+ copy_v3_v3(light, base_tmp->object->obmat[3]);
+ return 1;
+ }
+ else if (!found_light) {
+ copy_v3_v3(light, base_tmp->object->obmat[3]);
+ found_light = 1;
+ }
+ }
+ }
+
+ return found_light;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Obstacles
+ * \{ */
+
+typedef struct ObstaclesFromDMData {
+ FluidDomainSettings *mds;
+ FluidEffectorSettings *mes;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *looptri;
+ BVHTreeFromMesh *tree;
+
+ bool has_velocity;
+ float *vert_vel;
+ float *velocity_x, *velocity_y, *velocity_z;
+ int *num_objects;
+ float *distances_map;
+} ObstaclesFromDMData;
+
+static void obstacles_from_mesh_task_cb(void *__restrict userdata,
+ const int z,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ ObstaclesFromDMData *data = userdata;
+ FluidDomainSettings *mds = data->mds;
+
+ /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
+ const float surface_distance = 2.0f; // 0.867f;
+ /* Note: Use larger surface distance to cover larger area with obvel. Manta will use these obvels
+ * and extrapolate them (inside and outside obstacle) */
+
+ for (int x = mds->res_min[0]; x < mds->res_max[0]; x++) {
+ for (int y = mds->res_min[1]; y < mds->res_max[1]; y++) {
+ const int index = manta_get_index(
+ x - mds->res_min[0], mds->res[0], y - mds->res_min[1], mds->res[1], z - mds->res_min[2]);
+
+ float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
+ BVHTreeNearest nearest = {0};
+ nearest.index = -1;
+ nearest.dist_sq = surface_distance *
+ surface_distance; /* find_nearest uses squared distance */
+ bool has_inc_obj = false;
+
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(
+ data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) !=
+ -1) {
+ const MLoopTri *lt = &data->looptri[nearest.index];
+ float weights[3];
+ int v1, v2, v3;
+
+ /* calculate barycentric weights for nearest point */
+ v1 = data->mloop[lt->tri[0]].v;
+ v2 = data->mloop[lt->tri[1]].v;
+ v3 = data->mloop[lt->tri[2]].v;
+ interp_weights_tri_v3(
+ weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
+
+ if (data->has_velocity) {
+ /* increase object count */
+ data->num_objects[index]++;
+ has_inc_obj = true;
+
+ /* apply object velocity */
+ float hit_vel[3];
+ interp_v3_v3v3v3(hit_vel,
+ &data->vert_vel[v1 * 3],
+ &data->vert_vel[v2 * 3],
+ &data->vert_vel[v3 * 3],
+ weights);
+
+ /* Guiding has additional velocity multiplier */
+ if (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
+ mul_v3_fl(hit_vel, data->mes->vel_multi);
+
+ switch (data->mes->guide_mode) {
+ case FLUID_EFFECTOR_GUIDE_AVERAGED:
+ data->velocity_x[index] = (data->velocity_x[index] + hit_vel[0]) * 0.5f;
+ data->velocity_y[index] = (data->velocity_y[index] + hit_vel[1]) * 0.5f;
+ data->velocity_z[index] = (data->velocity_z[index] + hit_vel[2]) * 0.5f;
+ break;
+ case FLUID_EFFECTOR_GUIDE_OVERRIDE:
+ data->velocity_x[index] = hit_vel[0];
+ data->velocity_y[index] = hit_vel[1];
+ data->velocity_z[index] = hit_vel[2];
+ break;
+ case FLUID_EFFECTOR_GUIDE_MIN:
+ data->velocity_x[index] = MIN2(fabsf(hit_vel[0]), fabsf(data->velocity_x[index]));
+ data->velocity_y[index] = MIN2(fabsf(hit_vel[1]), fabsf(data->velocity_y[index]));
+ data->velocity_z[index] = MIN2(fabsf(hit_vel[2]), fabsf(data->velocity_z[index]));
+ break;
+ case FLUID_EFFECTOR_GUIDE_MAX:
+ default:
+ data->velocity_x[index] = MAX2(fabsf(hit_vel[0]), fabsf(data->velocity_x[index]));
+ data->velocity_y[index] = MAX2(fabsf(hit_vel[1]), fabsf(data->velocity_y[index]));
+ data->velocity_z[index] = MAX2(fabsf(hit_vel[2]), fabsf(data->velocity_z[index]));
+ break;
+ }
+ }
+ else {
+ /* Apply (i.e. add) effector object velocity */
+ data->velocity_x[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ?
+ hit_vel[0] * data->mes->vel_multi :
+ hit_vel[0];
+ data->velocity_y[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ?
+ hit_vel[1] * data->mes->vel_multi :
+ hit_vel[1];
+ data->velocity_z[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ?
+ hit_vel[2] * data->mes->vel_multi :
+ hit_vel[2];
+# ifdef DEBUG_PRINT
+ /* Debugging: Print object velocities. */
+ printf("adding effector object vel: [%f, %f, %f], dx is: %f\n",
+ hit_vel[0],
+ hit_vel[1],
+ hit_vel[2],
+ mds->dx);
+# endif
+ }
+ }
+ }
+
+ /* Get distance to mesh surface from both within and outside grid (mantaflow phi grid). */
+ if (data->distances_map) {
+ update_mesh_distances(index,
+ data->distances_map,
+ data->tree,
+ ray_start,
+ data->mes->surface_distance,
+ data->mes->flags & FLUID_FLOW_USE_PLANE_INIT);
+
+ /* Ensure that num objects are also counted inside object.
+ * But don't count twice (see object inc for nearest point). */
+ if (data->distances_map[index] < 0 && !has_inc_obj) {
+ data->num_objects[index]++;
+ }
+ }
+ }
+ }
+}
+
+static void obstacles_from_mesh(Object *coll_ob,
+ FluidDomainSettings *mds,
+ FluidEffectorSettings *mes,
+ float *distances_map,
+ float *velocity_x,
+ float *velocity_y,
+ float *velocity_z,
+ int *num_objects,
+ float dt)
+{
+ if (!mes->mesh) {
+ return;
+ }
+ {
+ Mesh *me = NULL;
+ MVert *mvert = NULL;
+ const MLoopTri *looptri;
+ const MLoop *mloop;
+ BVHTreeFromMesh tree_data = {NULL};
+ int numverts, i;
+
+ float *vert_vel = NULL;
+ bool has_velocity = false;
+
+ me = BKE_mesh_copy_for_eval(mes->mesh, true);
+
+ /* Duplicate vertices to modify. */
+ if (me->mvert) {
+ me->mvert = MEM_dupallocN(me->mvert);
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ }
+
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ mloop = me->mloop;
+ looptri = BKE_mesh_runtime_looptri_ensure(me);
+ numverts = me->totvert;
+
+ /* TODO (sebbas):
+ * Make vert_vel init optional?
+ * code is in trouble if the object moves but is declared as "does not move" */
+ {
+ vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "manta_obs_velocity");
+
+ if (mes->numverts != numverts || !mes->verts_old) {
+ if (mes->verts_old) {
+ MEM_freeN(mes->verts_old);
+ }
+
+ mes->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "manta_obs_verts_old");
+ mes->numverts = numverts;
+ }
+ else {
+ has_velocity = true;
+ }
+ }
+
+ /* Transform collider vertices to
+ * domain grid space for fast lookups */
+ for (i = 0; i < numverts; i++) {
+ float n[3];
+ float co[3];
+
+ /* vert pos */
+ mul_m4_v3(coll_ob->obmat, mvert[i].co);
+ manta_pos_to_cell(mds, mvert[i].co);
+
+ /* vert normal */
+ normal_short_to_float_v3(n, mvert[i].no);
+ mul_mat3_m4_v3(coll_ob->obmat, n);
+ mul_mat3_m4_v3(mds->imat, n);
+ normalize_v3(n);
+ normal_float_to_short_v3(mvert[i].no, n);
+
+ /* vert velocity */
+ add_v3fl_v3fl_v3i(co, mvert[i].co, mds->shift);
+ if (has_velocity) {
+ sub_v3_v3v3(&vert_vel[i * 3], co, &mes->verts_old[i * 3]);
+ mul_v3_fl(&vert_vel[i * 3], mds->dx / dt);
+ }
+ copy_v3_v3(&mes->verts_old[i * 3], co);
+ }
+
+ if (BKE_bvhtree_from_mesh_get(&tree_data, me, BVHTREE_FROM_LOOPTRI, 4)) {
+ ObstaclesFromDMData data = {.mds = mds,
+ .mes = mes,
+ .mvert = mvert,
+ .mloop = mloop,
+ .looptri = looptri,
+ .tree = &tree_data,
+ .has_velocity = has_velocity,
+ .vert_vel = vert_vel,
+ .velocity_x = velocity_x,
+ .velocity_y = velocity_y,
+ .velocity_z = velocity_z,
+ .num_objects = num_objects,
+ .distances_map = distances_map};
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 2;
+ BLI_task_parallel_range(
+ mds->res_min[2], mds->res_max[2], &data, obstacles_from_mesh_task_cb, &settings);
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&tree_data);
+
+ if (vert_vel) {
+ MEM_freeN(vert_vel);
+ }
+ if (me->mvert) {
+ MEM_freeN(me->mvert);
+ }
+ BKE_id_free(NULL, me);
+ }
+}
+
+static void update_obstacleflags(FluidDomainSettings *mds,
+ Object **coll_ob_array,
+ int coll_ob_array_len)
+{
+ int active_fields = mds->active_fields;
+ uint coll_index;
+
+ /* First, remove all flags that we want to update. */
+ int prev_flags = (FLUID_DOMAIN_ACTIVE_OBSTACLE | FLUID_DOMAIN_ACTIVE_GUIDE);
+ active_fields &= ~prev_flags;
+
+ /* Monitor active fields based on flow settings */
+ for (coll_index = 0; coll_index < coll_ob_array_len; coll_index++) {
+ Object *coll_ob = coll_ob_array[coll_index];
+ FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob,
+ eModifierType_Fluid);
+
+ if ((mmd2->type & MOD_FLUID_TYPE_EFFEC) && mmd2->effector) {
+ FluidEffectorSettings *mes = mmd2->effector;
+ if (!mes) {
+ break;
+ }
+ if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_OBSTACLE;
+ }
+ if (mes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_GUIDE;
+ }
+ }
+ }
+ /* Finally, initialize new data fields if any */
+ if (active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) {
+ manta_ensure_obstacle(mds->fluid, mds->mmd);
+ }
+ if (active_fields & FLUID_DOMAIN_ACTIVE_GUIDE) {
+ manta_ensure_guiding(mds->fluid, mds->mmd);
+ }
+ mds->active_fields = active_fields;
+}
+
+static void update_obstacles(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ FluidDomainSettings *mds,
+ float time_per_frame,
+ float frame_length,
+ int frame,
+ float dt)
+{
+ Object **coll_ob_array = NULL;
+ uint coll_ob_array_len = 0, coll_index = 0;
+
+ coll_ob_array = BKE_collision_objects_create(
+ depsgraph, ob, mds->effector_group, &coll_ob_array_len, eModifierType_Fluid);
+
+ /* Update all flow related flags and ensure that corresponding grids get initialized. */
+ update_obstacleflags(mds, coll_ob_array, coll_ob_array_len);
+
+ float *vel_x = manta_get_ob_velocity_x(mds->fluid);
+ float *vel_y = manta_get_ob_velocity_y(mds->fluid);
+ float *vel_z = manta_get_ob_velocity_z(mds->fluid);
+ float *vel_x_guide = manta_get_guide_velocity_x(mds->fluid);
+ float *vel_y_guide = manta_get_guide_velocity_y(mds->fluid);
+ float *vel_z_guide = manta_get_guide_velocity_z(mds->fluid);
+ float *vel_x_orig = manta_get_velocity_x(mds->fluid);
+ float *vel_y_orig = manta_get_velocity_y(mds->fluid);
+ float *vel_z_orig = manta_get_velocity_z(mds->fluid);
+ float *density = manta_smoke_get_density(mds->fluid);
+ float *fuel = manta_smoke_get_fuel(mds->fluid);
+ float *flame = manta_smoke_get_flame(mds->fluid);
+ float *r = manta_smoke_get_color_r(mds->fluid);
+ float *g = manta_smoke_get_color_g(mds->fluid);
+ float *b = manta_smoke_get_color_b(mds->fluid);
+ float *phi_obs_in = manta_get_phiobs_in(mds->fluid);
+ float *phi_guide_in = manta_get_phiguide_in(mds->fluid);
+ int *obstacles = manta_smoke_get_obstacle(mds->fluid);
+ int *num_obstacles = manta_get_num_obstacle(mds->fluid);
+ int *num_guides = manta_get_num_guide(mds->fluid);
+ uint z;
+ float tmp = 0;
+
+ /* Grid reset before writing again. */
+ for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
+
+ /* Use big value that's not inf to initialize levelset grids. */
+ if (phi_obs_in) {
+ phi_obs_in[z] = FLT_MAX;
+ }
+ if (phi_guide_in) {
+ phi_guide_in[z] = FLT_MAX;
+ }
+ if (num_obstacles) {
+ num_obstacles[z] = 0;
+ }
+ if (num_guides) {
+ num_guides[z] = 0;
+ }
+ if (vel_x && vel_y && vel_z) {
+ vel_x[z] = 0.0f;
+ vel_y[z] = 0.0f;
+ vel_z[z] = 0.0f;
+ }
+ if (vel_x_guide && vel_y_guide && vel_z_guide) {
+ vel_x_guide[z] = 0.0f;
+ vel_y_guide[z] = 0.0f;
+ vel_z_guide[z] = 0.0f;
+ }
+ }
+
+ /* Prepare grids from effector objects. */
+ for (coll_index = 0; coll_index < coll_ob_array_len; coll_index++) {
+ Object *coll_ob = coll_ob_array[coll_index];
+ FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob,
+ eModifierType_Fluid);
+
+ /* TODO (sebbas): check if modifier is active? */
+ if ((mmd2->type & MOD_FLUID_TYPE_EFFEC) && mmd2->effector) {
+ FluidEffectorSettings *mes = mmd2->effector;
+
+ /* Length of one frame. If using adaptive stepping, length is smaller than actual frame
+ * length. */
+ float adaptframe_length = time_per_frame / frame_length;
+
+ /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene subframe
+ * parameter. */
+ if (time_per_frame < frame_length) {
+ scene->r.subframe = adaptframe_length;
+ scene->r.cfra = frame - 1;
+ }
+ /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe
+ * parameter to 0 and advance current scene frame. */
+ else {
+ scene->r.subframe = 0.0f;
+ scene->r.cfra = frame;
+ }
+# ifdef DEBUG_PRINT
+ /* Debugging: Print subframe information. */
+ printf("effector: frame: %d // scene current frame: %d // scene current subframe: %f\n",
+ frame,
+ scene->r.cfra,
+ scene->r.subframe);
+# endif
+ /* TODO (sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph) as
+ * subframes don't work with the latter yet. */
+ BKE_object_modifier_update_subframe(
+ depsgraph, scene, coll_ob, true, 5, BKE_scene_frame_get(scene), eModifierType_Fluid);
+
+ if (mes && (mes->type == FLUID_EFFECTOR_TYPE_COLLISION)) {
+ obstacles_from_mesh(coll_ob, mds, mes, phi_obs_in, vel_x, vel_y, vel_z, num_obstacles, dt);
+ }
+ if (mes && (mes->type == FLUID_EFFECTOR_TYPE_GUIDE)) {
+ obstacles_from_mesh(coll_ob,
+ mds,
+ mes,
+ phi_guide_in,
+ vel_x_guide,
+ vel_y_guide,
+ vel_z_guide,
+ num_guides,
+ dt);
+ }
+ }
+ }
+
+ BKE_collision_objects_free(coll_ob_array);
+
+ /* Obstacle cells should not contain any velocity from the smoke simulation. */
+ for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
+ if (obstacles[z] & 2) /* Mantaflow convention: FlagObstacle. */
+ {
+ if (vel_x_orig && vel_y_orig && vel_z_orig) {
+ vel_x_orig[z] = 0.0f;
+ vel_y_orig[z] = 0.0f;
+ vel_z_orig[z] = 0.0f;
+ }
+ if (density) {
+ density[z] = 0.0f;
+ }
+ if (fuel) {
+ fuel[z] = 0.0f;
+ flame[z] = 0.0f;
+ }
+ if (r) {
+ r[z] = 0.0f;
+ g[z] = 0.0f;
+ b[z] = 0.0f;
+ }
+ }
+ /* Average velocities from multiple obstacles in one cell. */
+ if (num_obstacles && num_obstacles[z]) {
+ tmp = 1.0f / num_obstacles[z];
+ vel_x[z] *= tmp;
+ vel_y[z] *= tmp;
+ vel_z[z] *= tmp;
+ }
+ /* Average velocities from multiple guides in one cell. */
+ if (num_guides && num_guides[z]) {
+ tmp = 1.0f / num_guides[z];
+ vel_x_guide[z] *= tmp;
+ vel_y_guide[z] *= tmp;
+ vel_z_guide[z] *= tmp;
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flow Emission
+ * \{ */
+
+typedef struct EmissionMap {
+ float *influence;
+ float *influence_high;
+ float *velocity;
+ float *distances;
+ float *distances_high;
+ int min[3], max[3], res[3];
+ int hmin[3], hmax[3], hres[3];
+ int total_cells, valid;
+} EmissionMap;
+
+static void em_boundInsert(EmissionMap *em, float point[3])
+{
+ int i = 0;
+ if (!em->valid) {
+ for (; i < 3; i++) {
+ em->min[i] = (int)floor(point[i]);
+ em->max[i] = (int)ceil(point[i]);
+ }
+ em->valid = 1;
+ }
+ else {
+ for (; i < 3; i++) {
+ if (point[i] < em->min[i]) {
+ em->min[i] = (int)floor(point[i]);
+ }
+ if (point[i] > em->max[i]) {
+ em->max[i] = (int)ceil(point[i]);
+ }
+ }
+ }
+}
+
+static void clamp_bounds_in_domain(FluidDomainSettings *mds,
+ int min[3],
+ int max[3],
+ float *min_vel,
+ float *max_vel,
+ int margin,
+ float dt)
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ int adapt = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) ? mds->adapt_res : 0;
+ /* add margin */
+ min[i] -= margin;
+ max[i] += margin;
+
+ /* adapt to velocity */
+ if (min_vel && min_vel[i] < 0.0f) {
+ min[i] += (int)floor(min_vel[i] * dt);
+ }
+ if (max_vel && max_vel[i] > 0.0f) {
+ max[i] += (int)ceil(max_vel[i] * dt);
+ }
+
+ /* clamp within domain max size */
+ CLAMP(min[i], -adapt, mds->base_res[i] + adapt);
+ CLAMP(max[i], -adapt, mds->base_res[i] + adapt);
+ }
+}
+
+static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
+{
+ int i, res[3];
+
+ for (i = 0; i < 3; i++) {
+ res[i] = em->max[i] - em->min[i];
+ if (res[i] <= 0) {
+ return;
+ }
+ }
+ em->total_cells = res[0] * res[1] * res[2];
+ copy_v3_v3_int(em->res, res);
+
+ em->influence = MEM_calloc_arrayN(em->total_cells, sizeof(float), "manta_flow_influence");
+ if (use_velocity) {
+ em->velocity = MEM_calloc_arrayN(em->total_cells * 3, sizeof(float), "manta_flow_velocity");
+ }
+
+ em->distances = MEM_malloc_arrayN(em->total_cells, sizeof(float), "fluid_flow_distances");
+ /* Initialize to infinity. */
+ memset(em->distances, 0x7f7f7f7f, sizeof(float) * em->total_cells);
+
+ /* Allocate high resolution map if required. */
+ if (hires_mul > 1) {
+ int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul);
+
+ for (i = 0; i < 3; i++) {
+ em->hmin[i] = em->min[i] * hires_mul;
+ em->hmax[i] = em->max[i] * hires_mul;
+ em->hres[i] = em->res[i] * hires_mul;
+ }
+
+ em->influence_high = MEM_calloc_arrayN(
+ total_cells_high, sizeof(float), "manta_flow_influence_high");
+ em->distances_high = MEM_malloc_arrayN(
+ total_cells_high, sizeof(float), "manta_flow_distances_high");
+ /* Initialize to infinity. */
+ memset(em->distances_high, 0x7f7f7f7f, sizeof(float) * total_cells_high);
+ }
+ em->valid = true;
+}
+
+static void em_freeData(EmissionMap *em)
+{
+ if (em->influence) {
+ MEM_freeN(em->influence);
+ }
+ if (em->influence_high) {
+ MEM_freeN(em->influence_high);
+ }
+ if (em->velocity) {
+ MEM_freeN(em->velocity);
+ }
+ if (em->distances) {
+ MEM_freeN(em->distances);
+ }
+ if (em->distances_high) {
+ MEM_freeN(em->distances_high);
+ }
+}
+
+static void em_combineMaps(
+ EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
+{
+ int i, x, y, z;
+
+ /* copyfill input 1 struct and clear output for new allocation */
+ EmissionMap em1;
+ memcpy(&em1, output, sizeof(EmissionMap));
+ memset(output, 0, sizeof(EmissionMap));
+
+ for (i = 0; i < 3; i++) {
+ if (em1.valid) {
+ output->min[i] = MIN2(em1.min[i], em2->min[i]);
+ output->max[i] = MAX2(em1.max[i], em2->max[i]);
+ }
+ else {
+ output->min[i] = em2->min[i];
+ output->max[i] = em2->max[i];
+ }
+ }
+ /* allocate output map */
+ em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
+
+ /* base resolution inputs */
+ for (x = output->min[0]; x < output->max[0]; x++) {
+ for (y = output->min[1]; y < output->max[1]; y++) {
+ for (z = output->min[2]; z < output->max[2]; z++) {
+ int index_out = manta_get_index(x - output->min[0],
+ output->res[0],
+ y - output->min[1],
+ output->res[1],
+ z - output->min[2]);
+
+ /* initialize with first input if in range */
+ if (x >= em1.min[0] && x < em1.max[0] && y >= em1.min[1] && y < em1.max[1] &&
+ z >= em1.min[2] && z < em1.max[2]) {
+ int index_in = manta_get_index(
+ x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]);
+
+ /* values */
+ output->influence[index_out] = em1.influence[index_in];
+ output->distances[index_out] = em1.distances[index_in];
+ if (output->velocity && em1.velocity) {
+ copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]);
+ }
+ }
+
+ /* apply second input if in range */
+ if (x >= em2->min[0] && x < em2->max[0] && y >= em2->min[1] && y < em2->max[1] &&
+ z >= em2->min[2] && z < em2->max[2]) {
+ int index_in = manta_get_index(
+ x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]);
+
+ /* values */
+ if (additive) {
+ output->influence[index_out] += em2->influence[index_in] * sample_size;
+ }
+ else {
+ output->influence[index_out] = MAX2(em2->influence[index_in],
+ output->influence[index_out]);
+ }
+ output->distances[index_out] = MIN2(em2->distances[index_in],
+ output->distances[index_out]);
+ if (output->velocity && em2->velocity) {
+ /* last sample replaces the velocity */
+ output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3],
+ em2->velocity[index_in * 3]);
+ output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1],
+ em2->velocity[index_in * 3 + 1]);
+ output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2],
+ em2->velocity[index_in * 3 + 2]);
+ }
+ }
+ } // low res loop
+ }
+ }
+
+ /* initialize high resolution input if available */
+ if (output->influence_high) {
+ for (x = output->hmin[0]; x < output->hmax[0]; x++) {
+ for (y = output->hmin[1]; y < output->hmax[1]; y++) {
+ for (z = output->hmin[2]; z < output->hmax[2]; z++) {
+ int index_out = manta_get_index(x - output->hmin[0],
+ output->hres[0],
+ y - output->hmin[1],
+ output->hres[1],
+ z - output->hmin[2]);
+
+ /* initialize with first input if in range */
+ if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] &&
+ z >= em1.hmin[2] && z < em1.hmax[2]) {
+ int index_in = manta_get_index(
+ x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]);
+ /* values */
+ output->influence_high[index_out] = em1.influence_high[index_in];
+ }
+
+ /* apply second input if in range */
+ if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] &&
+ z >= em2->hmin[2] && z < em2->hmax[2]) {
+ int index_in = manta_get_index(
+ x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]);
+
+ /* values */
+ if (additive) {
+ output->influence_high[index_out] += em2->distances_high[index_in] * sample_size;
+ }
+ else {
+ output->distances_high[index_out] = MAX2(em2->distances_high[index_in],
+ output->distances_high[index_out]);
+ }
+ output->distances_high[index_out] = MIN2(em2->distances_high[index_in],
+ output->distances_high[index_out]);
+ }
+ } // high res loop
+ }
+ }
+ }
+
+ /* free original data */
+ em_freeData(&em1);
+}
+
+typedef struct EmitFromParticlesData {
+ FluidFlowSettings *mfs;
+ KDTree_3d *tree;
+ int hires_multiplier;
+
+ EmissionMap *em;
+ float *particle_vel;
+ float hr;
+
+ int *min, *max, *res;
+
+ float solid;
+ float smooth;
+ float hr_smooth;
+} EmitFromParticlesData;
+
+static void emit_from_particles_task_cb(void *__restrict userdata,
+ const int z,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ EmitFromParticlesData *data = userdata;
+ FluidFlowSettings *mfs = data->mfs;
+ EmissionMap *em = data->em;
+ const int hires_multiplier = data->hires_multiplier;
+
+ for (int x = data->min[0]; x < data->max[0]; x++) {
+ for (int y = data->min[1]; y < data->max[1]; y++) {
+ /* Take low res samples where possible. */
+ if (hires_multiplier <= 1 ||
+ !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
+ /* Get low res space coordinates. */
+ float inv_multiplier = 1.0f / hires_multiplier;
+ const int lx = x * inv_multiplier;
+ const int ly = y * inv_multiplier;
+ const int lz = z * inv_multiplier;
+
+ const int index = manta_get_index(
+ lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
+ const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
+
+ /* Find particle distance from the kdtree. */
+ KDTreeNearest_3d nearest;
+ const float range = data->solid + data->smooth;
+ BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence[index] = (nearest.dist < data->solid) ?
+ 1.0f :
+ (1.0f - (nearest.dist - data->solid) / data->smooth);
+ /* Uses particle velocity as initial velocity for smoke. */
+ if (mfs->flags & FLUID_FLOW_INITVELOCITY &&
+ (mfs->psys->part->phystype != PART_PHYS_NO)) {
+ madd_v3_v3fl(
+ &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], mfs->vel_multi);
+ }
+ }
+ }
+
+ /* Take high res samples if required. */
+ if (hires_multiplier > 1) {
+ /* get low res space coordinates */
+ const float lx = ((float)x) * data->hr;
+ const float ly = ((float)y) * data->hr;
+ const float lz = ((float)z) * data->hr;
+
+ const int index = manta_get_index(
+ x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
+ const float ray_start[3] = {
+ lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
+
+ /* Find particle distance from the kdtree. */
+ KDTreeNearest_3d nearest;
+ const float range = data->solid + data->hr_smooth;
+ BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence_high[index] = (nearest.dist < data->solid) ?
+ 1.0f :
+ (1.0f - (nearest.dist - data->solid) / data->smooth);
+ }
+ }
+ }
+ }
+}
+
+static void emit_from_particles(Object *flow_ob,
+ FluidDomainSettings *mds,
+ FluidFlowSettings *mfs,
+ EmissionMap *em,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ float dt)
+{
+ if (mfs && mfs->psys && mfs->psys->part &&
+ ELEM(mfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
+ {
+ ParticleSimulationData sim;
+ ParticleSystem *psys = mfs->psys;
+ float *particle_pos;
+ float *particle_vel;
+ int totpart = psys->totpart, totchild;
+ int p = 0;
+ int valid_particles = 0;
+ int bounds_margin = 1;
+
+ /* radius based flow */
+ const float solid = mfs->particle_size * 0.5f;
+ const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
+ int hires_multiplier = 1;
+ KDTree_3d *tree = NULL;
+
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = flow_ob;
+ sim.psys = psys;
+ sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+
+ /* prepare curvemapping tables */
+ if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) {
+ BKE_curvemapping_changed_all(psys->part->clumpcurve);
+ }
+ if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) {
+ BKE_curvemapping_changed_all(psys->part->roughcurve);
+ }
+ if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) {
+ BKE_curvemapping_changed_all(psys->part->twistcurve);
+ }
+
+ /* initialize particle cache */
+ if (psys->part->type == PART_HAIR) {
+ // TODO: PART_HAIR not supported whatsoever
+ totchild = 0;
+ }
+ else {
+ totchild = psys->totchild * psys->part->disp / 100;
+ }
+
+ particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3,
+ "manta_flow_particles_pos");
+ particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3,
+ "manta_flow_particles_vel");
+
+ /* setup particle radius emission if enabled */
+ if (mfs->flags & FLUID_FLOW_USE_PART_SIZE) {
+ tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
+
+ /* check need for high resolution map */
+ if ((mds->flags & FLUID_DOMAIN_USE_NOISE) && (mds->highres_sampling == SM_HRES_FULLSAMPLE)) {
+ hires_multiplier = mds->noise_scale;
+ }
+
+ bounds_margin = (int)ceil(solid + smooth);
+ }
+
+ /* calculate local position for each particle */
+ for (p = 0; p < totpart + totchild; p++) {
+ ParticleKey state;
+ float *pos, *vel;
+ if (p < totpart) {
+ if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
+ continue;
+ }
+ }
+ else {
+ /* handle child particle */
+ ChildParticle *cpa = &psys->child[p - totpart];
+ if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
+ continue;
+ }
+ }
+
+ state.time = BKE_scene_frame_get(
+ scene); /* DEG_get_ctime(depsgraph) does not give subframe time */
+ if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
+ continue;
+ }
+
+ /* location */
+ pos = &particle_pos[valid_particles * 3];
+ copy_v3_v3(pos, state.co);
+ manta_pos_to_cell(mds, pos);
+
+ /* velocity */
+ vel = &particle_vel[valid_particles * 3];
+ copy_v3_v3(vel, state.vel);
+ mul_mat3_m4_v3(mds->imat, &particle_vel[valid_particles * 3]);
+
+ if (mfs->flags & FLUID_FLOW_USE_PART_SIZE) {
+ BLI_kdtree_3d_insert(tree, valid_particles, pos);
+ }
+
+ /* calculate emission map bounds */
+ em_boundInsert(em, pos);
+ valid_particles++;
+ }
+
+ /* set emission map */
+ clamp_bounds_in_domain(mds, em->min, em->max, NULL, NULL, bounds_margin, dt);
+ em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY, hires_multiplier);
+
+ if (!(mfs->flags & FLUID_FLOW_USE_PART_SIZE)) {
+ for (p = 0; p < valid_particles; p++) {
+ int cell[3];
+ size_t i = 0;
+ size_t index = 0;
+ int badcell = 0;
+
+ /* 1. get corresponding cell */
+ cell[0] = floor(particle_pos[p * 3]) - em->min[0];
+ cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1];
+ cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2];
+ /* check if cell is valid (in the domain boundary) */
+ for (i = 0; i < 3; i++) {
+ if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) {
+ badcell = 1;
+ break;
+ }
+ }
+ if (badcell) {
+ continue;
+ }
+ /* get cell index */
+ index = manta_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]);
+ /* Add influence to emission map */
+ em->influence[index] = 1.0f;
+ /* Uses particle velocity as initial velocity for smoke */
+ if (mfs->flags & FLUID_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) {
+ madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], mfs->vel_multi);
+ }
+ } // particles loop
+ }
+ else if (valid_particles > 0) { // FLUID_FLOW_USE_PART_SIZE
+ int min[3], max[3], res[3];
+ const float hr = 1.0f / ((float)hires_multiplier);
+ /* Slightly adjust high res anti-alias smoothness based on number of divisions
+ * to allow smaller details but yet not differing too much from the low res size. */
+ const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f);
+
+ /* setup loop bounds */
+ for (int i = 0; i < 3; i++) {
+ min[i] = em->min[i] * hires_multiplier;
+ max[i] = em->max[i] * hires_multiplier;
+ res[i] = em->res[i] * hires_multiplier;
+ }
+
+ BLI_kdtree_3d_balance(tree);
+
+ EmitFromParticlesData data = {
+ .mfs = mfs,
+ .tree = tree,
+ .hires_multiplier = hires_multiplier,
+ .hr = hr,
+ .em = em,
+ .particle_vel = particle_vel,
+ .min = min,
+ .max = max,
+ .res = res,
+ .solid = solid,
+ .smooth = smooth,
+ .hr_smooth = hr_smooth,
+ };
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 2;
+ BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings);
+ }
+
+ if (mfs->flags & FLUID_FLOW_USE_PART_SIZE) {
+ BLI_kdtree_3d_free(tree);
+ }
+
+ /* free data */
+ if (particle_pos) {
+ MEM_freeN(particle_pos);
+ }
+ if (particle_vel) {
+ MEM_freeN(particle_vel);
+ }
+ }
+}
+
+/* Calculate map of (minimum) distances to flow/obstacle surface. Distances outside mesh are
+ * positive, inside negative. */
+static void update_mesh_distances(int index,
+ float *mesh_distances,
+ BVHTreeFromMesh *tree_data,
+ const float ray_start[3],
+ float surface_thickness,
+ int use_plane_init)
+{
+ float min_dist = FLT_MAX;
+
+ /* Ensure that planes get initialized correctly. */
+ if (use_plane_init) {
+ BVHTreeNearest nearest = {0};
+ nearest.index = -1;
+ nearest.dist_sq = surface_thickness;
+
+ if (BLI_bvhtree_find_nearest(
+ tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
+ float ray[3] = {0};
+ sub_v3_v3v3(ray, ray_start, nearest.co);
+ min_dist = len_v3(ray);
+ min_dist = (-1.0f) * fabsf(min_dist);
+ mesh_distances[index] = MIN2(mesh_distances[index], min_dist);
+ }
+ return;
+ }
+
+ /* First pass: Ray-casts in 26 directions
+ * (6 main axis + 12 quadrant diagonals (2D) + 8 octant diagonals (3D)). */
+ float ray_dirs[26][3] = {
+ {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f},
+ {-1.0f, 1.0f, 0.0f}, {-1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f},
+ {-1.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 1.0f, -1.0f},
+ {0.0f, -1.0f, 1.0f}, {0.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {1.0f, -1.0f, -1.0f},
+ {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}};
+ size_t ray_cnt = sizeof ray_dirs / sizeof ray_dirs[0];
+
+ /* Count for ray misses (no face hit) and cases where ray direction matches face normal
+ * direction. */
+ int miss_cnt = 0, dir_cnt = 0;
+ min_dist = FLT_MAX;
+
+ for (int i = 0; i < ray_cnt; i++) {
+ BVHTreeRayHit hit_tree = {0};
+ hit_tree.index = -1;
+ hit_tree.dist = FLT_MAX;
+
+ normalize_v3(ray_dirs[i]);
+ BLI_bvhtree_ray_cast(tree_data->tree,
+ ray_start,
+ ray_dirs[i],
+ 0.0f,
+ &hit_tree,
+ tree_data->raycast_callback,
+ tree_data);
+
+ /* Ray did not hit mesh. Current point definitely not inside mesh. Inside mesh all rays have to
+ * hit. */
+ if (hit_tree.index == -1) {
+ miss_cnt++;
+ continue;
+ }
+
+ /* Ray and normal are in pointing opposite directions. */
+ if (dot_v3v3(ray_dirs[i], hit_tree.no) <= 0) {
+ dir_cnt++;
+ }
+
+ if (hit_tree.dist < min_dist) {
+ min_dist = hit_tree.dist;
+ }
+ }
+
+ /* Point lies inside mesh. Use negative sign for distance value. */
+ if (!(miss_cnt > 0 || dir_cnt == ray_cnt)) {
+ min_dist = (-1.0f) * fabsf(min_dist);
+ }
+
+ /* Update global distance array but ensure that older entries are not overridden. */
+ mesh_distances[index] = MIN2(mesh_distances[index], min_dist);
+
+ /* Second pass: Use nearest neighbor search on mesh surface. */
+ BVHTreeNearest nearest = {0};
+ nearest.index = -1;
+ nearest.dist_sq = 5;
+
+ if (BLI_bvhtree_find_nearest(
+ tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
+ float ray[3] = {0};
+ sub_v3_v3v3(ray, nearest.co, ray_start);
+ min_dist = len_v3(ray);
+ // CLAMP(min_dist, 0.5, min_dist);
+
+ BVHTreeRayHit hit_tree = {0};
+ hit_tree.index = -1;
+ hit_tree.dist = FLT_MAX;
+
+ normalize_v3(ray);
+ BLI_bvhtree_ray_cast(
+ tree_data->tree, ray_start, ray, 0.0f, &hit_tree, tree_data->raycast_callback, tree_data);
+
+ /* Only proceed if casted ray hit the mesh surface. */
+ if (hit_tree.index != -1) {
+
+ /* Ray and normal are in pointing same directions: Point must lie inside mesh. */
+ if (dot_v3v3(ray, hit_tree.no) > 0) {
+ min_dist = (-1.0f) * fabsf(min_dist);
+ }
+
+ /* Update distance value with more accurate one from this nearest neighbor search.
+ * Skip if new value would be outside and current value has inside value already. */
+ if (!(min_dist > 0 && mesh_distances[index] <= 0)) {
+ mesh_distances[index] = min_dist;
+ }
+ }
+ }
+
+ if (surface_thickness) {
+ mesh_distances[index] -= surface_thickness;
+ }
+}
+
+static void sample_mesh(FluidFlowSettings *mfs,
+ const MVert *mvert,
+ const MLoop *mloop,
+ const MLoopTri *mlooptri,
+ const MLoopUV *mloopuv,
+ float *influence_map,
+ float *velocity_map,
+ int index,
+ const int base_res[3],
+ float flow_center[3],
+ BVHTreeFromMesh *tree_data,
+ const float ray_start[3],
+ const float *vert_vel,
+ bool has_velocity,
+ int defgrp_index,
+ MDeformVert *dvert,
+ float x,
+ float y,
+ float z)
+{
+ float ray_dir[3] = {1.0f, 0.0f, 0.0f};
+ BVHTreeRayHit hit = {0};
+ BVHTreeNearest nearest = {0};
+
+ float volume_factor = 0.0f;
+ float sample_str = 0.0f;
+
+ hit.index = -1;
+ hit.dist = FLT_MAX;
+ nearest.index = -1;
+ nearest.dist_sq = mfs->surface_distance *
+ mfs->surface_distance; /* find_nearest uses squared distance */
+
+ /* Check volume collision */
+ if (mfs->volume_density) {
+ if (BLI_bvhtree_ray_cast(tree_data->tree,
+ ray_start,
+ ray_dir,
+ 0.0f,
+ &hit,
+ tree_data->raycast_callback,
+ tree_data) != -1) {
+ float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
+ /* If ray and hit face normal are facing same direction
+ * hit point is inside a closed mesh. */
+ if (dot >= 0) {
+ /* Also cast a ray in opposite direction to make sure
+ * point is at least surrounded by two faces */
+ negate_v3(ray_dir);
+ hit.index = -1;
+ hit.dist = FLT_MAX;
+
+ BLI_bvhtree_ray_cast(tree_data->tree,
+ ray_start,
+ ray_dir,
+ 0.0f,
+ &hit,
+ tree_data->raycast_callback,
+ tree_data);
+ if (hit.index != -1) {
+ volume_factor = mfs->volume_density;
+ }
+ }
+ }
+ }
+
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(
+ tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
+ float weights[3];
+ int v1, v2, v3, f_index = nearest.index;
+ float n1[3], n2[3], n3[3], hit_normal[3];
+
+ /* emit from surface based on distance */
+ if (mfs->surface_distance) {
+ sample_str = sqrtf(nearest.dist_sq) / mfs->surface_distance;
+ CLAMP(sample_str, 0.0f, 1.0f);
+ sample_str = pow(1.0f - sample_str, 0.5f);
+ }
+ else {
+ sample_str = 0.0f;
+ }
+
+ /* calculate barycentric weights for nearest point */
+ v1 = mloop[mlooptri[f_index].tri[0]].v;
+ v2 = mloop[mlooptri[f_index].tri[1]].v;
+ v3 = mloop[mlooptri[f_index].tri[2]].v;
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
+
+ if (mfs->flags & FLUID_FLOW_INITVELOCITY && velocity_map) {
+ /* apply normal directional velocity */
+ if (mfs->vel_normal) {
+ /* interpolate vertex normal vectors to get nearest point normal */
+ normal_short_to_float_v3(n1, mvert[v1].no);
+ normal_short_to_float_v3(n2, mvert[v2].no);
+ normal_short_to_float_v3(n3, mvert[v3].no);
+ interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
+ normalize_v3(hit_normal);
+ /* apply normal directional and random velocity
+ * - TODO: random disabled for now since it doesn't really work well
+ * as pressure calc smoothens it out. */
+ velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal * 0.25f;
+ velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal * 0.25f;
+ velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal * 0.25f;
+ /* TODO: for fire emitted from mesh surface we can use
+ * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
+ }
+ /* apply object velocity */
+ if (has_velocity && mfs->vel_multi) {
+ float hit_vel[3];
+ interp_v3_v3v3v3(
+ hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
+ velocity_map[index * 3] += hit_vel[0] * mfs->vel_multi;
+ velocity_map[index * 3 + 1] += hit_vel[1] * mfs->vel_multi;
+ velocity_map[index * 3 + 2] += hit_vel[2] * mfs->vel_multi;
+# ifdef DEBUG_PRINT
+ /* Debugging: Print flow object velocities. */
+ printf("adding flow object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]);
+# endif
+ }
+ velocity_map[index * 3] += mfs->vel_coord[0];
+ velocity_map[index * 3 + 1] += mfs->vel_coord[1];
+ velocity_map[index * 3 + 2] += mfs->vel_coord[2];
+ }
+
+ /* apply vertex group influence if used */
+ if (defgrp_index != -1 && dvert) {
+ float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
+ defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
+ defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
+ sample_str *= weight_mask;
+ }
+
+ /* apply emission texture */
+ if ((mfs->flags & FLUID_FLOW_TEXTUREEMIT) && mfs->noise_texture) {
+ float tex_co[3] = {0};
+ TexResult texres;
+
+ if (mfs->texture_type == FLUID_FLOW_TEXTURE_MAP_AUTO) {
+ tex_co[0] = ((x - flow_center[0]) / base_res[0]) / mfs->texture_size;
+ tex_co[1] = ((y - flow_center[1]) / base_res[1]) / mfs->texture_size;
+ tex_co[2] = ((z - flow_center[2]) / base_res[2] - mfs->texture_offset) / mfs->texture_size;
+ }
+ else if (mloopuv) {
+ const float *uv[3];
+ uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
+ uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
+ uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
+
+ interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
+
+ /* map between -1.0f and 1.0f */
+ tex_co[0] = tex_co[0] * 2.0f - 1.0f;
+ tex_co[1] = tex_co[1] * 2.0f - 1.0f;
+ tex_co[2] = mfs->texture_offset;
+ }
+ texres.nor = NULL;
+ BKE_texture_get_value(NULL, mfs->noise_texture, tex_co, &texres, false);
+ sample_str *= texres.tin;
+ }
+ }
+
+ /* multiply initial velocity by emitter influence */
+ if (mfs->flags & FLUID_FLOW_INITVELOCITY && velocity_map) {
+ mul_v3_fl(&velocity_map[index * 3], sample_str);
+ }
+
+ /* apply final influence based on volume factor */
+ influence_map[index] = MAX2(volume_factor, sample_str);
+}
+
+typedef struct EmitFromDMData {
+ FluidDomainSettings *mds;
+ FluidFlowSettings *mfs;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ MDeformVert *dvert;
+ int defgrp_index;
+
+ BVHTreeFromMesh *tree;
+ int hires_multiplier;
+ float hr;
+
+ EmissionMap *em;
+ bool has_velocity;
+ float *vert_vel;
+
+ float *flow_center;
+ int *min, *max, *res;
+} EmitFromDMData;
+
+static void emit_from_mesh_task_cb(void *__restrict userdata,
+ const int z,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ EmitFromDMData *data = userdata;
+ EmissionMap *em = data->em;
+ const int hires_multiplier = data->hires_multiplier;
+
+ for (int x = data->min[0]; x < data->max[0]; x++) {
+ for (int y = data->min[1]; y < data->max[1]; y++) {
+ /* take low res samples where possible */
+ if (hires_multiplier <= 1 ||
+ !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
+ /* get low res space coordinates */
+ const int lx = x / hires_multiplier;
+ const int ly = y / hires_multiplier;
+ const int lz = z / hires_multiplier;
+
+ const int index = manta_get_index(
+ lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
+ const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
+
+ /* Emission for smoke and fire. Result in em->influence. Also, calculate invels */
+ sample_mesh(data->mfs,
+ data->mvert,
+ data->mloop,
+ data->mlooptri,
+ data->mloopuv,
+ em->influence,
+ em->velocity,
+ index,
+ data->mds->base_res,
+ data->flow_center,
+ data->tree,
+ ray_start,
+ data->vert_vel,
+ data->has_velocity,
+ data->defgrp_index,
+ data->dvert,
+ (float)lx,
+ (float)ly,
+ (float)lz);
+
+ /* Calculate levelset from meshes. Result in em->distances */
+ update_mesh_distances(index,
+ em->distances,
+ data->tree,
+ ray_start,
+ data->mfs->surface_distance,
+ data->mfs->flags & FLUID_FLOW_USE_PLANE_INIT);
+ }
+
+ /* take high res samples if required */
+ if (hires_multiplier > 1) {
+ /* get low res space coordinates */
+ const float lx = ((float)x) * data->hr;
+ const float ly = ((float)y) * data->hr;
+ const float lz = ((float)z) * data->hr;
+
+ const int index = manta_get_index(
+ x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
+ const float ray_start[3] = {
+ lx + 0.5f * data->hr,
+ ly + 0.5f * data->hr,
+ lz + 0.5f * data->hr,
+ };
+
+ /* Emission for smoke and fire high. Result in em->influence_high */
+ if (data->mfs->type == FLUID_FLOW_TYPE_SMOKE || data->mfs->type == FLUID_FLOW_TYPE_FIRE ||
+ data->mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE) {
+ sample_mesh(data->mfs,
+ data->mvert,
+ data->mloop,
+ data->mlooptri,
+ data->mloopuv,
+ em->influence_high,
+ NULL,
+ index,
+ data->mds->base_res,
+ data->flow_center,
+ data->tree,
+ ray_start,
+ data->vert_vel,
+ data->has_velocity,
+ data->defgrp_index,
+ data->dvert,
+ /* x,y,z needs to be always lowres */
+ lx,
+ ly,
+ lz);
+ }
+ }
+ }
+ }
+}
+
+static void emit_from_mesh(
+ Object *flow_ob, FluidDomainSettings *mds, FluidFlowSettings *mfs, EmissionMap *em, float dt)
+{
+ if (mfs->mesh) {
+ Mesh *me = NULL;
+ MVert *mvert = NULL;
+ const MLoopTri *mlooptri = NULL;
+ const MLoop *mloop = NULL;
+ const MLoopUV *mloopuv = NULL;
+ MDeformVert *dvert = NULL;
+ BVHTreeFromMesh tree_data = {NULL};
+ int numverts, i;
+
+ float *vert_vel = NULL;
+ bool has_velocity = false;
+
+ int defgrp_index = mfs->vgroup_density - 1;
+ float flow_center[3] = {0};
+ int min[3], max[3], res[3];
+ int hires_multiplier = 1;
+
+ /* copy mesh for thread safety because we modify it,
+ * main issue is its VertArray being modified, then replaced and freed
+ */
+ me = BKE_mesh_copy_for_eval(mfs->mesh, true);
+
+ /* Duplicate vertices to modify. */
+ if (me->mvert) {
+ me->mvert = MEM_dupallocN(me->mvert);
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ }
+
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ mloop = me->mloop;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(me);
+ numverts = me->totvert;
+ dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, mfs->uvlayer_name);
+
+ if (mfs->flags & FLUID_FLOW_INITVELOCITY) {
+ vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "manta_flow_velocity");
+
+ if (mfs->numverts != numverts || !mfs->verts_old) {
+ if (mfs->verts_old) {
+ MEM_freeN(mfs->verts_old);
+ }
+ mfs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "manta_flow_verts_old");
+ mfs->numverts = numverts;
+ }
+ else {
+ has_velocity = true;
+ }
+ }
+
+ /* Transform mesh vertices to
+ * domain grid space for fast lookups */
+ for (i = 0; i < numverts; i++) {
+ float n[3];
+
+ /* vert pos */
+ mul_m4_v3(flow_ob->obmat, mvert[i].co);
+ manta_pos_to_cell(mds, mvert[i].co);
+
+ /* vert normal */
+ normal_short_to_float_v3(n, mvert[i].no);
+ mul_mat3_m4_v3(flow_ob->obmat, n);
+ mul_mat3_m4_v3(mds->imat, n);
+ normalize_v3(n);
+ normal_float_to_short_v3(mvert[i].no, n);
+
+ /* vert velocity */
+ if (mfs->flags & FLUID_FLOW_INITVELOCITY) {
+ float co[3];
+ add_v3fl_v3fl_v3i(co, mvert[i].co, mds->shift);
+ if (has_velocity) {
+ sub_v3_v3v3(&vert_vel[i * 3], co, &mfs->verts_old[i * 3]);
+ mul_v3_fl(&vert_vel[i * 3], mds->dx / dt);
+ }
+ copy_v3_v3(&mfs->verts_old[i * 3], co);
+ }
+
+ /* calculate emission map bounds */
+ em_boundInsert(em, mvert[i].co);
+ }
+ mul_m4_v3(flow_ob->obmat, flow_center);
+ manta_pos_to_cell(mds, flow_center);
+
+ /* check need for high resolution map */
+ if ((mds->flags & FLUID_DOMAIN_USE_NOISE) && (mds->highres_sampling == SM_HRES_FULLSAMPLE)) {
+ hires_multiplier = mds->noise_scale;
+ }
+
+ /* set emission map */
+ clamp_bounds_in_domain(
+ mds, em->min, em->max, NULL, NULL, (int)ceil(mfs->surface_distance), dt);
+ em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY, hires_multiplier);
+
+ /* setup loop bounds */
+ for (i = 0; i < 3; i++) {
+ min[i] = em->min[i] * hires_multiplier;
+ max[i] = em->max[i] * hires_multiplier;
+ res[i] = em->res[i] * hires_multiplier;
+ }
+
+ if (BKE_bvhtree_from_mesh_get(&tree_data, me, BVHTREE_FROM_LOOPTRI, 4)) {
+ const float hr = 1.0f / ((float)hires_multiplier);
+
+ EmitFromDMData data = {
+ .mds = mds,
+ .mfs = mfs,
+ .mvert = mvert,
+ .mloop = mloop,
+ .mlooptri = mlooptri,
+ .mloopuv = mloopuv,
+ .dvert = dvert,
+ .defgrp_index = defgrp_index,
+ .tree = &tree_data,
+ .hires_multiplier = hires_multiplier,
+ .hr = hr,
+ .em = em,
+ .has_velocity = has_velocity,
+ .vert_vel = vert_vel,
+ .flow_center = flow_center,
+ .min = min,
+ .max = max,
+ .res = res,
+ };
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 2;
+ BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings);
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&tree_data);
+
+ if (vert_vel) {
+ MEM_freeN(vert_vel);
+ }
+ if (me->mvert) {
+ MEM_freeN(me->mvert);
+ }
+ BKE_id_free(NULL, me);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smoke Step
+ * \{ */
+
+static void adaptive_domain_adjust(
+ FluidDomainSettings *mds, Object *ob, EmissionMap *emaps, uint numflowobj, float dt)
+{
+ /* calculate domain shift for current frame */
+ int new_shift[3] = {0};
+ int total_shift[3];
+ float frame_shift_f[3];
+ float ob_loc[3] = {0};
+
+ mul_m4_v3(ob->obmat, ob_loc);
+
+ sub_v3_v3v3(frame_shift_f, ob_loc, mds->prev_loc);
+ copy_v3_v3(mds->prev_loc, ob_loc);
+ /* convert global space shift to local "cell" space */
+ mul_mat3_m4_v3(mds->imat, frame_shift_f);
+ frame_shift_f[0] = frame_shift_f[0] / mds->cell_size[0];
+ frame_shift_f[1] = frame_shift_f[1] / mds->cell_size[1];
+ frame_shift_f[2] = frame_shift_f[2] / mds->cell_size[2];
+ /* add to total shift */
+ add_v3_v3(mds->shift_f, frame_shift_f);
+ /* convert to integer */
+ total_shift[0] = (int)(floorf(mds->shift_f[0]));
+ total_shift[1] = (int)(floorf(mds->shift_f[1]));
+ total_shift[2] = (int)(floorf(mds->shift_f[2]));
+ int temp_shift[3];
+ copy_v3_v3_int(temp_shift, mds->shift);
+ sub_v3_v3v3_int(new_shift, total_shift, mds->shift);
+ copy_v3_v3_int(mds->shift, total_shift);
+
+ /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */
+ mds->p0[0] = mds->dp0[0] - mds->cell_size[0] * (mds->shift_f[0] - total_shift[0] - 0.5f);
+ mds->p0[1] = mds->dp0[1] - mds->cell_size[1] * (mds->shift_f[1] - total_shift[1] - 0.5f);
+ mds->p0[2] = mds->dp0[2] - mds->cell_size[2] * (mds->shift_f[2] - total_shift[2] - 0.5f);
+ mds->p1[0] = mds->p0[0] + mds->cell_size[0] * mds->base_res[0];
+ mds->p1[1] = mds->p0[1] + mds->cell_size[1] * mds->base_res[1];
+ mds->p1[2] = mds->p0[2] + mds->cell_size[2] * mds->base_res[2];
+
+ /* adjust domain resolution */
+ const int block_size = mds->noise_scale;
+ int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
+ int total_cells = 1, res_changed = 0, shift_changed = 0;
+ float min_vel[3], max_vel[3];
+ int x, y, z;
+ float *density = manta_smoke_get_density(mds->fluid);
+ float *fuel = manta_smoke_get_fuel(mds->fluid);
+ float *bigdensity = manta_smoke_turbulence_get_density(mds->fluid);
+ float *bigfuel = manta_smoke_turbulence_get_fuel(mds->fluid);
+ float *vx = manta_get_velocity_x(mds->fluid);
+ float *vy = manta_get_velocity_y(mds->fluid);
+ float *vz = manta_get_velocity_z(mds->fluid);
+ int wt_res[3];
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) {
+ manta_smoke_turbulence_get_res(mds->fluid, wt_res);
+ }
+
+ INIT_MINMAX(min_vel, max_vel);
+
+ /* Calculate bounds for current domain content */
+ for (x = mds->res_min[0]; x < mds->res_max[0]; x++) {
+ for (y = mds->res_min[1]; y < mds->res_max[1]; y++) {
+ for (z = mds->res_min[2]; z < mds->res_max[2]; z++) {
+ int xn = x - new_shift[0];
+ int yn = y - new_shift[1];
+ int zn = z - new_shift[2];
+ int index;
+ float max_den;
+
+ /* skip if cell already belongs to new area */
+ if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] &&
+ zn <= max[2]) {
+ continue;
+ }
+
+ index = manta_get_index(x - mds->res_min[0],
+ mds->res[0],
+ y - mds->res_min[1],
+ mds->res[1],
+ z - mds->res_min[2]);
+ max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
+
+ /* check high resolution bounds if max density isnt already high enough */
+ if (max_den < mds->adapt_threshold && mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) {
+ int i, j, k;
+ /* high res grid index */
+ int xx = (x - mds->res_min[0]) * block_size;
+ int yy = (y - mds->res_min[1]) * block_size;
+ int zz = (z - mds->res_min[2]) * block_size;
+
+ for (i = 0; i < block_size; i++) {
+ for (j = 0; j < block_size; j++) {
+ for (k = 0; k < block_size; k++) {
+ int big_index = manta_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
+ float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) :
+ bigdensity[big_index];
+ if (den > max_den) {
+ max_den = den;
+ }
+ }
+ }
+ }
+ }
+
+ /* content bounds (use shifted coordinates) */
+ if (max_den >= mds->adapt_threshold) {
+ if (min[0] > xn) {
+ min[0] = xn;
+ }
+ if (min[1] > yn) {
+ min[1] = yn;
+ }
+ if (min[2] > zn) {
+ min[2] = zn;
+ }
+ if (max[0] < xn) {
+ max[0] = xn;
+ }
+ if (max[1] < yn) {
+ max[1] = yn;
+ }
+ if (max[2] < zn) {
+ max[2] = zn;
+ }
+ }
+
+ /* velocity bounds */
+ if (min_vel[0] > vx[index]) {
+ min_vel[0] = vx[index];
+ }
+ if (min_vel[1] > vy[index]) {
+ min_vel[1] = vy[index];
+ }
+ if (min_vel[2] > vz[index]) {
+ min_vel[2] = vz[index];
+ }
+ if (max_vel[0] < vx[index]) {
+ max_vel[0] = vx[index];
+ }
+ if (max_vel[1] < vy[index]) {
+ max_vel[1] = vy[index];
+ }
+ if (max_vel[2] < vz[index]) {
+ max_vel[2] = vz[index];
+ }
+ }
+ }
+ }
+
+ /* also apply emission maps */
+ for (int i = 0; i < numflowobj; i++) {
+ EmissionMap *em = &emaps[i];
+
+ for (x = em->min[0]; x < em->max[0]; x++) {
+ for (y = em->min[1]; y < em->max[1]; y++) {
+ for (z = em->min[2]; z < em->max[2]; z++) {
+ int index = manta_get_index(
+ x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]);
+ float max_den = em->influence[index];
+
+ /* density bounds */
+ if (max_den >= mds->adapt_threshold) {
+ if (min[0] > x) {
+ min[0] = x;
+ }
+ if (min[1] > y) {
+ min[1] = y;
+ }
+ if (min[2] > z) {
+ min[2] = z;
+ }
+ if (max[0] < x) {
+ max[0] = x;
+ }
+ if (max[1] < y) {
+ max[1] = y;
+ }
+ if (max[2] < z) {
+ max[2] = z;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* calculate new bounds based on these values */
+ clamp_bounds_in_domain(mds, min, max, min_vel, max_vel, mds->adapt_margin + 1, dt);
+
+ for (int i = 0; i < 3; i++) {
+ /* calculate new resolution */
+ res[i] = max[i] - min[i];
+ total_cells *= res[i];
+
+ if (new_shift[i]) {
+ shift_changed = 1;
+ }
+
+ /* if no content set minimum dimensions */
+ if (res[i] <= 0) {
+ int j;
+ for (j = 0; j < 3; j++) {
+ min[j] = 0;
+ max[j] = 1;
+ res[j] = 1;
+ }
+ res_changed = 1;
+ total_cells = 1;
+ break;
+ }
+ if (min[i] != mds->res_min[i] || max[i] != mds->res_max[i]) {
+ res_changed = 1;
+ }
+ }
+
+ if (res_changed || shift_changed) {
+ BKE_fluid_reallocate_copy_fluid(
+ mds, mds->res, res, mds->res_min, min, mds->res_max, temp_shift, total_shift);
+
+ /* set new domain dimensions */
+ copy_v3_v3_int(mds->res_min, min);
+ copy_v3_v3_int(mds->res_max, max);
+ copy_v3_v3_int(mds->res, res);
+ mds->total_cells = total_cells;
+
+ /* Redo adapt time step in manta to refresh solver state (ie time variables) */
+ manta_adapt_timestep(mds->fluid);
+ }
+
+ /* update global size field with new bbox size */
+ /* volume bounds */
+ float minf[3], maxf[3], size[3];
+ madd_v3fl_v3fl_v3fl_v3i(minf, mds->p0, mds->cell_size, mds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(maxf, mds->p0, mds->cell_size, mds->res_max);
+ /* calculate domain dimensions */
+ sub_v3_v3v3(size, maxf, minf);
+ /* apply object scale */
+ for (int i = 0; i < 3; i++) {
+ size[i] = fabsf(size[i] * ob->scale[i]);
+ }
+ copy_v3_v3(mds->global_size, size);
+}
+
+BLI_INLINE void apply_outflow_fields(int index,
+ float distance_value,
+ float *density,
+ float *heat,
+ float *fuel,
+ float *react,
+ float *color_r,
+ float *color_g,
+ float *color_b,
+ float *phiout)
+{
+ /* determine outflow cells - phiout used in smoke and liquids */
+ if (phiout) {
+ phiout[index] = distance_value;
+ }
+
+ /* set smoke outflow */
+ if (density) {
+ density[index] = 0.0f;
+ }
+ if (heat) {
+ heat[index] = 0.0f;
+ }
+ if (fuel) {
+ fuel[index] = 0.0f;
+ react[index] = 0.0f;
+ }
+ if (color_r) {
+ color_r[index] = 0.0f;
+ color_g[index] = 0.0f;
+ color_b[index] = 0.0f;
+ }
+}
+
+BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs,
+ float emission_value,
+ float distance_value,
+ int index,
+ float *density_in,
+ const float *density,
+ float *heat_in,
+ const float *heat,
+ float *fuel_in,
+ const float *fuel,
+ float *react_in,
+ const float *react,
+ float *color_r_in,
+ const float *color_r,
+ float *color_g_in,
+ const float *color_g,
+ float *color_b_in,
+ const float *color_b,
+ float *phi_in,
+ float *emission_in)
+{
+ /* add inflow */
+ if (phi_in) {
+ phi_in[index] = distance_value;
+ }
+
+ /* save emission value for manta inflow */
+ if (emission_in) {
+ emission_in[index] = emission_value;
+ }
+
+ /* add smoke inflow */
+ int absolute_flow = (mfs->flags & FLUID_FLOW_ABSOLUTE);
+ float dens_old = (density) ? density[index] : 0.0;
+ // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
+ float dens_flow = (mfs->type == FLUID_FLOW_TYPE_FIRE) ? 0.0f : emission_value * mfs->density;
+ float fuel_flow = (fuel) ? emission_value * mfs->fuel_amount : 0.0f;
+ /* add heat */
+ if (heat && heat_in) {
+ if (emission_value > 0.0f) {
+ heat_in[index] = ADD_IF_LOWER(heat[index], mfs->temperature);
+ /* Scale inflow by dt/frame-length.
+ * This is to ensure that adaptive steps don't apply too much emission. */
+ }
+ else {
+ heat_in[index] = heat[index];
+ }
+ }
+
+ /* set density and fuel - absolute mode */
+ if (absolute_flow) {
+ if (density && density_in) {
+ density_in[index] = density[index];
+ if (mfs->type != FLUID_FLOW_TYPE_FIRE && dens_flow > density[index]) {
+ density_in[index] = dens_flow;
+ }
+ }
+ if (fuel && fuel_in) {
+ fuel_in[index] = fuel[index];
+ if (mfs->type != FLUID_FLOW_TYPE_SMOKE && fuel_flow && fuel_flow > fuel[index]) {
+ fuel_in[index] = fuel_flow;
+ }
+ }
+ }
+ /* set density and fuel - additive mode */
+ else {
+ if (density && density_in) {
+ density_in[index] = density[index];
+ if (mfs->type != FLUID_FLOW_TYPE_FIRE) {
+ density_in[index] += dens_flow;
+ CLAMP(density_in[index], 0.0f, 1.0f);
+ }
+ }
+ if (fuel && fuel_in) {
+ fuel_in[index] = fuel[index];
+ if (mfs->type != FLUID_FLOW_TYPE_SMOKE && mfs->fuel_amount) {
+ fuel_in[index] += fuel_flow;
+ CLAMP(fuel_in[index], 0.0f, 10.0f);
+ }
+ }
+ }
+
+ /* set color */
+ if (color_r && color_r_in) {
+ color_r_in[index] = color_r[index];
+ color_g_in[index] = color_g[index];
+ color_b_in[index] = color_b[index];
+
+ if (dens_flow) {
+ float total_dens = density[index] / (dens_old + dens_flow);
+ color_r_in[index] = (color_r[index] + mfs->color[0] * dens_flow) * total_dens;
+ color_g_in[index] = (color_g[index] + mfs->color[1] * dens_flow) * total_dens;
+ color_b_in[index] = (color_b[index] + mfs->color[2] * dens_flow) * total_dens;
+ }
+ }
+
+ /* set fire reaction coordinate */
+ if (fuel && fuel_in) {
+ /* Instead of using 1.0 for all new fuel add slight falloff to reduce flow blocky-ness. */
+ float value = 1.0f - pow2f(1.0f - emission_value);
+
+ if (fuel[index] > FLT_EPSILON && value > react[index]) {
+ float f = fuel_flow / fuel[index];
+ react_in[index] = value * f + (1.0f - f) * react[index];
+ CLAMP(react_in[index], 0.0f, value);
+ }
+ else {
+ react_in[index] = react[index];
+ }
+ }
+}
+
+static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int numflowobj)
+{
+ int active_fields = mds->active_fields;
+ uint flow_index;
+
+ /* First, remove all flags that we want to update. */
+ int prev_flags = (FLUID_DOMAIN_ACTIVE_INVEL | FLUID_DOMAIN_ACTIVE_OUTFLOW |
+ FLUID_DOMAIN_ACTIVE_HEAT | FLUID_DOMAIN_ACTIVE_FIRE |
+ FLUID_DOMAIN_ACTIVE_COLOR_SET | FLUID_DOMAIN_ACTIVE_COLORS);
+ active_fields &= ~prev_flags;
+
+ /* Monitor active fields based on flow settings */
+ for (flow_index = 0; flow_index < numflowobj; flow_index++) {
+ Object *coll_ob = flowobjs[flow_index];
+ FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob,
+ eModifierType_Fluid);
+
+ // Sanity check
+ if (!mmd2) {
+ continue;
+ }
+
+ if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) {
+ FluidFlowSettings *mfs = mmd2->flow;
+ if (!mfs) {
+ break;
+ }
+ if (mfs->flags & FLUID_FLOW_INITVELOCITY) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_INVEL;
+ }
+ if (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_OUTFLOW;
+ }
+ /* liquids done from here */
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ continue;
+ }
+
+ /* activate heat field if flow produces any heat */
+ if (mfs->temperature) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_HEAT;
+ }
+ /* activate fuel field if flow adds any fuel */
+ if (mfs->fuel_amount &&
+ (mfs->type == FLUID_FLOW_TYPE_FIRE || mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE)) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_FIRE;
+ }
+ /* activate color field if flows add smoke with varying colors */
+ if (mfs->density &&
+ (mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE)) {
+ if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) {
+ copy_v3_v3(mds->active_color, mfs->color);
+ active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET;
+ }
+ else if (!equals_v3v3(mds->active_color, mfs->color)) {
+ copy_v3_v3(mds->active_color, mfs->color);
+ active_fields |= FLUID_DOMAIN_ACTIVE_COLORS;
+ }
+ }
+ }
+ }
+ /* Monitor active fields based on domain settings */
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS && active_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ /* heat is always needed for fire */
+ active_fields |= FLUID_DOMAIN_ACTIVE_HEAT;
+ /* also activate colors if domain smoke color differs from active color */
+ if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) {
+ copy_v3_v3(mds->active_color, mds->flame_smoke_color);
+ active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET;
+ }
+ else if (!equals_v3v3(mds->active_color, mds->flame_smoke_color)) {
+ copy_v3_v3(mds->active_color, mds->flame_smoke_color);
+ active_fields |= FLUID_DOMAIN_ACTIVE_COLORS;
+ }
+ }
+ /* Finally, initialize new data fields if any */
+ if (active_fields & FLUID_DOMAIN_ACTIVE_INVEL) {
+ manta_ensure_invelocity(mds->fluid, mds->mmd);
+ }
+ if (active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) {
+ manta_ensure_outflow(mds->fluid, mds->mmd);
+ }
+ if (active_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
+ manta_smoke_ensure_heat(mds->fluid, mds->mmd);
+ }
+ if (active_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ manta_smoke_ensure_fire(mds->fluid, mds->mmd);
+ }
+ if (active_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
+ /* initialize all smoke with "active_color" */
+ manta_smoke_ensure_colors(mds->fluid, mds->mmd);
+ }
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY ||
+ mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM ||
+ mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER)) {
+ manta_liquid_ensure_sndparts(mds->fluid, mds->mmd);
+ }
+ mds->active_fields = active_fields;
+}
+
+static void update_flowsfluids(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ FluidDomainSettings *mds,
+ float time_per_frame,
+ float frame_length,
+ int frame,
+ float dt)
+{
+ EmissionMap *emaps = NULL;
+ Object **flowobjs = NULL;
+ uint numflowobj = 0, flow_index = 0;
+ bool is_first_frame = (frame == mds->cache_frame_start);
+
+ flowobjs = BKE_collision_objects_create(
+ depsgraph, ob, mds->fluid_group, &numflowobj, eModifierType_Fluid);
+
+ /* Update all flow related flags and ensure that corresponding grids get initialized */
+ update_flowsflags(mds, flowobjs, numflowobj);
+
+ /* init emission maps for each flow */
+ emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "manta_flow_maps");
+
+ /* Prepare flow emission maps */
+ for (flow_index = 0; flow_index < numflowobj; flow_index++) {
+ Object *flowobj = flowobjs[flow_index];
+ FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj,
+ eModifierType_Fluid);
+
+ /* Check for initialized smoke object */
+ if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) {
+ FluidFlowSettings *mfs = mmd2->flow;
+ int subframes = mfs->subframes;
+ EmissionMap *em = &emaps[flow_index];
+
+ /* Length of one adaptive frame. If using adaptive stepping, length is smaller than actual
+ * frame length */
+ float adaptframe_length = time_per_frame / frame_length;
+ /* Adaptive frame length as percentage */
+ CLAMP(adaptframe_length, 0.0f, 1.0f);
+
+ /* Further splitting because of emission subframe: If no subframes present, sample_size is 1
+ */
+ float sample_size = 1.0f / (float)(subframes + 1);
+ int hires_multiplier = 1;
+
+ /* First frame cannot have any subframes because there is (obviously) no previous frame from
+ * where subframes could come from */
+ if (is_first_frame) {
+ subframes = 0;
+ }
+
+ int subframe;
+ float subframe_dt = dt * sample_size;
+
+ /* Emission loop. When not using subframes this will loop only once. */
+ for (subframe = subframes; subframe >= 0; subframe--) {
+
+ /* Temporary emission map used when subframes are enabled, i.e. at least one subframe */
+ EmissionMap em_temp = {NULL};
+
+ /* Set scene time */
+ /* Handle emission subframe */
+ if (subframe > 0 && !is_first_frame) {
+ scene->r.subframe = adaptframe_length -
+ sample_size * (float)(subframe) * (dt / frame_length);
+ scene->r.cfra = frame - 1;
+ }
+ /* Last frame in this loop (subframe == suframes). Can be real end frame or in between
+ * frames (adaptive frame) */
+ else {
+ /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene
+ * subframe parameter */
+ if (time_per_frame < frame_length) {
+ scene->r.subframe = adaptframe_length;
+ scene->r.cfra = frame - 1;
+ }
+ /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe
+ * parameter to 0 and advance current scene frame */
+ else {
+ scene->r.subframe = 0.0f;
+ scene->r.cfra = frame;
+ }
+ }
+ /* Sanity check: subframe portion must be between 0 and 1 */
+ CLAMP(scene->r.subframe, 0.0f, 1.0f);
+# ifdef DEBUG_PRINT
+ /* Debugging: Print subframe information. */
+ printf(
+ "flow: frame (is first: %d): %d // scene current frame: %d // scene current subframe: "
+ "%f\n",
+ is_first_frame,
+ frame,
+ scene->r.cfra,
+ scene->r.subframe);
+# endif
+ /* Update frame time, this is considering current subframe fraction
+ * BLI_mutex_lock() called in manta_step(), so safe to update subframe here
+ * TODO (sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph)
+ * as subframes don't work with the latter yet */
+ BKE_object_modifier_update_subframe(
+ depsgraph, scene, flowobj, true, 5, BKE_scene_frame_get(scene), eModifierType_Fluid);
+
+ /* Emission from particles */
+ if (mfs->source == FLUID_FLOW_SOURCE_PARTICLES) {
+ if (subframes) {
+ emit_from_particles(flowobj, mds, mfs, &em_temp, depsgraph, scene, subframe_dt);
+ }
+ else {
+ emit_from_particles(flowobj, mds, mfs, em, depsgraph, scene, subframe_dt);
+ }
+
+ if (!(mfs->flags & FLUID_FLOW_USE_PART_SIZE)) {
+ hires_multiplier = 1;
+ }
+ }
+ /* Emission from mesh */
+ else if (mfs->source == FLUID_FLOW_SOURCE_MESH) {
+ if (subframes) {
+ emit_from_mesh(flowobj, mds, mfs, &em_temp, subframe_dt);
+ }
+ else {
+ emit_from_mesh(flowobj, mds, mfs, em, subframe_dt);
+ }
+ }
+ else {
+ printf("Error: unknown flow emission source\n");
+ }
+
+ /* If this we emitted with temp emission map in this loop (subframe emission), we combine
+ * the temp map with the original emission map */
+ if (subframes) {
+ /* Combine emission maps */
+ em_combineMaps(
+ em, &em_temp, hires_multiplier, !(mfs->flags & FLUID_FLOW_ABSOLUTE), sample_size);
+ em_freeData(&em_temp);
+ }
+ }
+ }
+ }
+# ifdef DEBUG_PRINT
+ /* Debugging: Print time information. */
+ printf("flow: frame: %d // time per frame: %f // frame length: %f // dt: %f\n",
+ frame,
+ time_per_frame,
+ frame_length,
+ dt);
+# endif
+
+ /* Adjust domain size if needed. Only do this once for every frame */
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
+ adaptive_domain_adjust(mds, ob, emaps, numflowobj, dt);
+ }
+
+ float *phi_in = manta_get_phi_in(mds->fluid);
+ float *phiout_in = manta_get_phiout_in(mds->fluid);
+ float *density = manta_smoke_get_density(mds->fluid);
+ float *color_r = manta_smoke_get_color_r(mds->fluid);
+ float *color_g = manta_smoke_get_color_g(mds->fluid);
+ float *color_b = manta_smoke_get_color_b(mds->fluid);
+ float *fuel = manta_smoke_get_fuel(mds->fluid);
+ float *heat = manta_smoke_get_heat(mds->fluid);
+ float *react = manta_smoke_get_react(mds->fluid);
+
+ float *density_in = manta_smoke_get_density_in(mds->fluid);
+ float *heat_in = manta_smoke_get_heat_in(mds->fluid);
+ float *color_r_in = manta_smoke_get_color_r_in(mds->fluid);
+ float *color_g_in = manta_smoke_get_color_g_in(mds->fluid);
+ float *color_b_in = manta_smoke_get_color_b_in(mds->fluid);
+ float *fuel_in = manta_smoke_get_fuel_in(mds->fluid);
+ float *react_in = manta_smoke_get_react_in(mds->fluid);
+ float *emission_in = manta_smoke_get_emission_in(mds->fluid);
+
+ float *velx_initial = manta_get_in_velocity_x(mds->fluid);
+ float *vely_initial = manta_get_in_velocity_y(mds->fluid);
+ float *velz_initial = manta_get_in_velocity_z(mds->fluid);
+ uint z;
+
+ /* Grid reset before writing again */
+ for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
+ if (phi_in) {
+ phi_in[z] = FLT_MAX;
+ }
+ if (phiout_in) {
+ phiout_in[z] = FLT_MAX;
+ }
+ if (density_in) {
+ density_in[z] = 0.0f;
+ }
+ if (heat_in) {
+ heat_in[z] = 0.0f;
+ }
+ if (color_r_in) {
+ color_r_in[z] = 0.0f;
+ color_g_in[z] = 0.0f;
+ color_b_in[z] = 0.0f;
+ }
+ if (fuel_in) {
+ fuel_in[z] = 0.0f;
+ react_in[z] = 0.0f;
+ }
+ if (emission_in) {
+ emission_in[z] = 0.0f;
+ }
+ if (velx_initial) {
+ velx_initial[z] = 0.0f;
+ vely_initial[z] = 0.0f;
+ velz_initial[z] = 0.0f;
+ }
+ }
+
+ /* Apply emission data */
+ for (flow_index = 0; flow_index < numflowobj; flow_index++) {
+ Object *flowobj = flowobjs[flow_index];
+ FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj,
+ eModifierType_Fluid);
+
+ // check for initialized flow object
+ if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) {
+ FluidFlowSettings *mfs = mmd2->flow;
+ EmissionMap *em = &emaps[flow_index];
+ float *velocity_map = em->velocity;
+ float *emission_map = em->influence;
+ float *distance_map = em->distances;
+
+ int gx, gy, gz, ex, ey, ez, dx, dy, dz;
+ size_t e_index, d_index;
+
+ // loop through every emission map cell
+ for (gx = em->min[0]; gx < em->max[0]; gx++) {
+ for (gy = em->min[1]; gy < em->max[1]; gy++) {
+ for (gz = em->min[2]; gz < em->max[2]; gz++) {
+ /* get emission map index */
+ ex = gx - em->min[0];
+ ey = gy - em->min[1];
+ ez = gz - em->min[2];
+ e_index = manta_get_index(ex, em->res[0], ey, em->res[1], ez);
+
+ /* get domain index */
+ dx = gx - mds->res_min[0];
+ dy = gy - mds->res_min[1];
+ dz = gz - mds->res_min[2];
+ d_index = manta_get_index(dx, mds->res[0], dy, mds->res[1], dz);
+ /* make sure emission cell is inside the new domain boundary */
+ if (dx < 0 || dy < 0 || dz < 0 || dx >= mds->res[0] || dy >= mds->res[1] ||
+ dz >= mds->res[2]) {
+ continue;
+ }
+
+ if (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) { // outflow
+ apply_outflow_fields(d_index,
+ distance_map[e_index],
+ density_in,
+ heat_in,
+ fuel_in,
+ react_in,
+ color_r_in,
+ color_g_in,
+ color_b_in,
+ phiout_in);
+ }
+ else if (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && mmd2->time > 2) {
+ apply_inflow_fields(mfs,
+ 0.0f,
+ FLT_MAX,
+ d_index,
+ density_in,
+ density,
+ heat_in,
+ heat,
+ fuel_in,
+ fuel,
+ react_in,
+ react,
+ color_r_in,
+ color_r,
+ color_g_in,
+ color_g,
+ color_b_in,
+ color_b,
+ phi_in,
+ emission_in);
+ }
+ else if (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW ||
+ mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY) { // inflow
+ /* only apply inflow if enabled */
+ if (mfs->flags & FLUID_FLOW_USE_INFLOW) {
+ apply_inflow_fields(mfs,
+ emission_map[e_index],
+ distance_map[e_index],
+ d_index,
+ density_in,
+ density,
+ heat_in,
+ heat,
+ fuel_in,
+ fuel,
+ react_in,
+ react,
+ color_r_in,
+ color_r,
+ color_g_in,
+ color_g,
+ color_b_in,
+ color_b,
+ phi_in,
+ emission_in);
+ /* initial velocity */
+ if (mfs->flags & FLUID_FLOW_INITVELOCITY) {
+ velx_initial[d_index] = velocity_map[e_index * 3];
+ vely_initial[d_index] = velocity_map[e_index * 3 + 1];
+ velz_initial[d_index] = velocity_map[e_index * 3 + 2];
+ }
+ }
+ }
+ } // low res loop
+ }
+ }
+
+ // free emission maps
+ em_freeData(em);
+
+ } // end emission
+ }
+
+ BKE_collision_objects_free(flowobjs);
+ if (emaps) {
+ MEM_freeN(emaps);
+ }
+}
+
+typedef struct UpdateEffectorsData {
+ Scene *scene;
+ FluidDomainSettings *mds;
+ ListBase *effectors;
+
+ float *density;
+ float *fuel;
+ float *force_x;
+ float *force_y;
+ float *force_z;
+ float *velocity_x;
+ float *velocity_y;
+ float *velocity_z;
+ int *flags;
+ float *phi_obs_in;
+} UpdateEffectorsData;
+
+static void update_effectors_task_cb(void *__restrict userdata,
+ const int x,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ UpdateEffectorsData *data = userdata;
+ FluidDomainSettings *mds = data->mds;
+
+ for (int y = 0; y < mds->res[1]; y++) {
+ for (int z = 0; z < mds->res[2]; z++) {
+ EffectedPoint epoint;
+ float mag;
+ float voxel_center[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
+ const uint index = manta_get_index(x, mds->res[0], y, mds->res[1], z);
+
+ if ((data->fuel && MAX2(data->density[index], data->fuel[index]) < FLT_EPSILON) ||
+ (data->density && data->density[index] < FLT_EPSILON) ||
+ (data->phi_obs_in && data->phi_obs_in[index] < 0.0f) ||
+ data->flags[index] & 2) // mantaflow convention: 2 == FlagObstacle
+ {
+ continue;
+ }
+
+ /* get velocities from manta grid space and convert to blender units */
+ vel[0] = data->velocity_x[index];
+ vel[1] = data->velocity_y[index];
+ vel[2] = data->velocity_z[index];
+ mul_v3_fl(vel, mds->dx);
+
+ /* convert vel to global space */
+ mag = len_v3(vel);
+ mul_mat3_m4_v3(mds->obmat, vel);
+ normalize_v3(vel);
+ mul_v3_fl(vel, mag);
+
+ voxel_center[0] = mds->p0[0] + mds->cell_size[0] * ((float)(x + mds->res_min[0]) + 0.5f);
+ voxel_center[1] = mds->p0[1] + mds->cell_size[1] * ((float)(y + mds->res_min[1]) + 0.5f);
+ voxel_center[2] = mds->p0[2] + mds->cell_size[2] * ((float)(z + mds->res_min[2]) + 0.5f);
+ mul_m4_v3(mds->obmat, voxel_center);
+
+ /* do effectors */
+ pd_point_from_loc(data->scene, voxel_center, vel, index, &epoint);
+ BKE_effectors_apply(data->effectors, NULL, mds->effector_weights, &epoint, retvel, NULL);
+
+ /* convert retvel to local space */
+ mag = len_v3(retvel);
+ mul_mat3_m4_v3(mds->imat, retvel);
+ normalize_v3(retvel);
+ mul_v3_fl(retvel, mag);
+
+ /* constrain forces to interval -1 to 1 */
+ data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
+ data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
+ data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
+ }
+ }
+}
+
+static void update_effectors(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, FluidDomainSettings *mds, float UNUSED(dt))
+{
+ ListBase *effectors;
+ /* make sure smoke flow influence is 0.0f */
+ mds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, mds->effector_weights);
+
+ if (effectors) {
+ // precalculate wind forces
+ UpdateEffectorsData data;
+ data.scene = scene;
+ data.mds = mds;
+ data.effectors = effectors;
+ data.density = manta_smoke_get_density(mds->fluid);
+ data.fuel = manta_smoke_get_fuel(mds->fluid);
+ data.force_x = manta_get_force_x(mds->fluid);
+ data.force_y = manta_get_force_y(mds->fluid);
+ data.force_z = manta_get_force_z(mds->fluid);
+ data.velocity_x = manta_get_velocity_x(mds->fluid);
+ data.velocity_y = manta_get_velocity_y(mds->fluid);
+ data.velocity_z = manta_get_velocity_z(mds->fluid);
+ data.flags = manta_smoke_get_obstacle(mds->fluid);
+ data.phi_obs_in = manta_get_phiobs_in(mds->fluid);
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 2;
+ BLI_task_parallel_range(0, mds->res[0], &data, update_effectors_task_cb, &settings);
+ }
+
+ BKE_effectors_free(effectors);
+}
+
+static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Object *ob)
+{
+ Mesh *me;
+ MVert *mverts;
+ MPoly *mpolys;
+ MLoop *mloops;
+ short *normals, *no_s;
+ float no[3];
+ float min[3];
+ float max[3];
+ float size[3];
+ float cell_size_scaled[3];
+
+ /* assign material + flags to new dm
+ * if there's no faces in original dm, keep materials and flags unchanged */
+ MPoly *mpoly;
+ MPoly mp_example = {0};
+ mpoly = orgmesh->mpoly;
+ if (mpoly) {
+ mp_example = *mpoly;
+ }
+ /* else leave NULL'd */
+
+ const short mp_mat_nr = mp_example.mat_nr;
+ const char mp_flag = mp_example.flag;
+
+ int i;
+ int num_verts, num_normals, num_faces;
+
+ if (!mds->fluid) {
+ return NULL;
+ }
+
+ num_verts = manta_liquid_get_num_verts(mds->fluid);
+ num_normals = manta_liquid_get_num_normals(mds->fluid);
+ num_faces = manta_liquid_get_num_triangles(mds->fluid);
+
+# ifdef DEBUG_PRINT
+ /* Debugging: Print number of vertices, normals, and faces. */
+ printf("num_verts: %d, num_normals: %d, num_faces: %d\n", num_verts, num_normals, num_faces);
+# endif
+
+ if (!num_verts || !num_faces) {
+ return NULL;
+ }
+
+ me = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 3, num_faces);
+ mverts = me->mvert;
+ mpolys = me->mpoly;
+ mloops = me->mloop;
+ if (!me) {
+ return NULL;
+ }
+
+ // Get size (dimension) but considering scaling scaling
+ copy_v3_v3(cell_size_scaled, mds->cell_size);
+ mul_v3_v3(cell_size_scaled, ob->scale);
+ madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, cell_size_scaled, mds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(max, mds->p0, cell_size_scaled, mds->res_max);
+ sub_v3_v3v3(size, max, min);
+
+ // Biggest dimension will be used for upscaling
+ float max_size = MAX3(size[0], size[1], size[2]);
+
+ // Vertices
+ for (i = 0; i < num_verts; i++, mverts++) {
+ // read raw data. is normalized cube around domain origin
+ mverts->co[0] = manta_liquid_get_vertex_x_at(mds->fluid, i);
+ mverts->co[1] = manta_liquid_get_vertex_y_at(mds->fluid, i);
+ mverts->co[2] = manta_liquid_get_vertex_z_at(mds->fluid, i);
+
+ // if reading raw data directly from manta, normalize now, otherwise omit this, ie when reading
+ // from files
+ {
+ // normalize to unit cube around 0
+ mverts->co[0] -= ((float)mds->res[0] * mds->mesh_scale) * 0.5f;
+ mverts->co[1] -= ((float)mds->res[1] * mds->mesh_scale) * 0.5f;
+ mverts->co[2] -= ((float)mds->res[2] * mds->mesh_scale) * 0.5f;
+ mverts->co[0] *= mds->dx / mds->mesh_scale;
+ mverts->co[1] *= mds->dx / mds->mesh_scale;
+ mverts->co[2] *= mds->dx / mds->mesh_scale;
+ }
+
+ mverts->co[0] *= max_size / fabsf(ob->scale[0]);
+ mverts->co[1] *= max_size / fabsf(ob->scale[1]);
+ mverts->co[2] *= max_size / fabsf(ob->scale[2]);
+# ifdef DEBUG_PRINT
+ /* Debugging: Print coordinates of vertices. */
+ printf("mverts->co[0]: %f, mverts->co[1]: %f, mverts->co[2]: %f\n",
+ mverts->co[0],
+ mverts->co[1],
+ mverts->co[2]);
+# endif
+ }
+
+ // Normals
+ normals = MEM_callocN(sizeof(short) * num_normals * 3, "Fluidmesh_tmp_normals");
+
+ for (i = 0, no_s = normals; i < num_normals; no_s += 3, i++) {
+ no[0] = manta_liquid_get_normal_x_at(mds->fluid, i);
+ no[1] = manta_liquid_get_normal_y_at(mds->fluid, i);
+ no[2] = manta_liquid_get_normal_z_at(mds->fluid, i);
+
+ normal_float_to_short_v3(no_s, no);
+# ifdef DEBUG_PRINT
+ /* Debugging: Print coordinates of normals. */
+ printf("no_s[0]: %d, no_s[1]: %d, no_s[2]: %d\n", no_s[0], no_s[1], no_s[2]);
+# endif
+ }
+
+ // Triangles
+ for (i = 0; i < num_faces; i++, mpolys++, mloops += 3) {
+ /* initialize from existing face */
+ mpolys->mat_nr = mp_mat_nr;
+ mpolys->flag = mp_flag;
+
+ mpolys->loopstart = i * 3;
+ mpolys->totloop = 3;
+
+ mloops[0].v = manta_liquid_get_triangle_x_at(mds->fluid, i);
+ mloops[1].v = manta_liquid_get_triangle_y_at(mds->fluid, i);
+ mloops[2].v = manta_liquid_get_triangle_z_at(mds->fluid, i);
+# ifdef DEBUG_PRINT
+ /* Debugging: Print mesh faces. */
+ printf("mloops[0].v: %d, mloops[1].v: %d, mloops[2].v: %d\n",
+ mloops[0].v,
+ mloops[1].v,
+ mloops[2].v);
+# endif
+ }
+
+ BKE_mesh_ensure_normals(me);
+ BKE_mesh_calc_edges(me, false, false);
+ BKE_mesh_vert_normals_apply(me, (short(*)[3])normals);
+
+ MEM_freeN(normals);
+
+ /* return early if no mesh vert velocities required */
+ if ((mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) == 0) {
+ return me;
+ }
+
+ if (mds->mesh_velocities) {
+ MEM_freeN(mds->mesh_velocities);
+ }
+
+ mds->mesh_velocities = MEM_calloc_arrayN(
+ num_verts, sizeof(FluidDomainVertexVelocity), "Fluidmesh_vertvelocities");
+ mds->totvert = num_verts;
+
+ FluidDomainVertexVelocity *velarray = NULL;
+ velarray = mds->mesh_velocities;
+
+ float time_mult = 25.f * DT_DEFAULT;
+
+ for (i = 0; i < num_verts; i++, mverts++) {
+ velarray[i].vel[0] = manta_liquid_get_vertvel_x_at(mds->fluid, i) * (mds->dx / time_mult);
+ velarray[i].vel[1] = manta_liquid_get_vertvel_y_at(mds->fluid, i) * (mds->dx / time_mult);
+ velarray[i].vel[2] = manta_liquid_get_vertvel_z_at(mds->fluid, i) * (mds->dx / time_mult);
+# ifdef DEBUG_PRINT
+ /* Debugging: Print velocities of vertices. */
+ printf("velarray[%d].vel[0]: %f, velarray[%d].vel[1]: %f, velarray[%d].vel[2]: %f\n",
+ i,
+ velarray[i].vel[0],
+ i,
+ velarray[i].vel[1],
+ i,
+ velarray[i].vel[2]);
+# endif
+ }
+
+ return me;
+}
+
+static Mesh *create_smoke_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Object *ob)
+{
+ Mesh *result;
+ MVert *mverts;
+ MPoly *mpolys;
+ MLoop *mloops;
+ float min[3];
+ float max[3];
+ float *co;
+ MPoly *mp;
+ MLoop *ml;
+
+ int num_verts = 8;
+ int num_faces = 6;
+ int i;
+ float ob_loc[3] = {0};
+ float ob_cache_loc[3] = {0};
+
+ /* Just copy existing mesh if there is no content or if the adaptive domain is not being used. */
+ if (mds->total_cells <= 1 || (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0) {
+ return BKE_mesh_copy_for_eval(orgmesh, false);
+ }
+
+ result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
+ mverts = result->mvert;
+ mpolys = result->mpoly;
+ mloops = result->mloop;
+
+ if (num_verts) {
+ /* Volume bounds. */
+ madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, mds->cell_size, mds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(max, mds->p0, mds->cell_size, mds->res_max);
+
+ /* Set vertices of smoke BB. Especially important, when BB changes (adaptive domain). */
+ /* Top slab */
+ co = mverts[0].co;
+ co[0] = min[0];
+ co[1] = min[1];
+ co[2] = max[2];
+ co = mverts[1].co;
+ co[0] = max[0];
+ co[1] = min[1];
+ co[2] = max[2];
+ co = mverts[2].co;
+ co[0] = max[0];
+ co[1] = max[1];
+ co[2] = max[2];
+ co = mverts[3].co;
+ co[0] = min[0];
+ co[1] = max[1];
+ co[2] = max[2];
+ /* Bottom slab. */
+ co = mverts[4].co;
+ co[0] = min[0];
+ co[1] = min[1];
+ co[2] = min[2];
+ co = mverts[5].co;
+ co[0] = max[0];
+ co[1] = min[1];
+ co[2] = min[2];
+ co = mverts[6].co;
+ co[0] = max[0];
+ co[1] = max[1];
+ co[2] = min[2];
+ co = mverts[7].co;
+ co[0] = min[0];
+ co[1] = max[1];
+ co[2] = min[2];
+
+ /* Create faces. */
+ /* Top side. */
+ mp = &mpolys[0];
+ ml = &mloops[0 * 4];
+ mp->loopstart = 0 * 4;
+ mp->totloop = 4;
+ ml[0].v = 0;
+ ml[1].v = 1;
+ ml[2].v = 2;
+ ml[3].v = 3;
+ /* Right side. */
+ mp = &mpolys[1];
+ ml = &mloops[1 * 4];
+ mp->loopstart = 1 * 4;
+ mp->totloop = 4;
+ ml[0].v = 2;
+ ml[1].v = 1;
+ ml[2].v = 5;
+ ml[3].v = 6;
+ /* Bottom side. */
+ mp = &mpolys[2];
+ ml = &mloops[2 * 4];
+ mp->loopstart = 2 * 4;
+ mp->totloop = 4;
+ ml[0].v = 7;
+ ml[1].v = 6;
+ ml[2].v = 5;
+ ml[3].v = 4;
+ /* Left side. */
+ mp = &mpolys[3];
+ ml = &mloops[3 * 4];
+ mp->loopstart = 3 * 4;
+ mp->totloop = 4;
+ ml[0].v = 0;
+ ml[1].v = 3;
+ ml[2].v = 7;
+ ml[3].v = 4;
+ /* Front side. */
+ mp = &mpolys[4];
+ ml = &mloops[4 * 4];
+ mp->loopstart = 4 * 4;
+ mp->totloop = 4;
+ ml[0].v = 3;
+ ml[1].v = 2;
+ ml[2].v = 6;
+ ml[3].v = 7;
+ /* Back side. */
+ mp = &mpolys[5];
+ ml = &mloops[5 * 4];
+ mp->loopstart = 5 * 4;
+ mp->totloop = 4;
+ ml[0].v = 1;
+ ml[1].v = 0;
+ ml[2].v = 4;
+ ml[3].v = 5;
+
+ /* Calculate required shift to match domain's global position
+ * it was originally simulated at (if object moves without manta step). */
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->obmat, ob_loc);
+ mul_m4_v3(mds->obmat, ob_cache_loc);
+ sub_v3_v3v3(mds->obj_shift_f, ob_cache_loc, ob_loc);
+ /* Convert shift to local space and apply to vertices. */
+ mul_mat3_m4_v3(ob->imat, mds->obj_shift_f);
+ /* Apply shift to vertices. */
+ for (i = 0; i < num_verts; i++) {
+ add_v3_v3(mverts[i].co, mds->obj_shift_f);
+ }
+ }
+
+ BKE_mesh_calc_edges(result, false, false);
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ return result;
+}
+
+static void manta_step(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, FluidModifierData *mmd, int frame)
+{
+ FluidDomainSettings *mds = mmd->domain;
+ float dt, frame_length, time_total;
+ float time_per_frame;
+ bool init_resolution = true;
+
+ /* update object state */
+ invert_m4_m4(mds->imat, ob->obmat);
+ copy_m4_m4(mds->obmat, ob->obmat);
+
+ /* gas domain might use adaptive domain */
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS) {
+ init_resolution = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) != 0;
+ }
+ manta_set_domain_from_mesh(mds, ob, me, init_resolution);
+
+ /* use local variables for adaptive loop, dt can change */
+ frame_length = mds->frame_length;
+ dt = mds->dt;
+ time_per_frame = 0;
+ time_total = mds->time_total;
+
+ BLI_mutex_lock(&object_update_lock);
+
+ /* loop as long as time_per_frame (sum of sub dt's) does not exceed actual framelength */
+ while (time_per_frame < frame_length) {
+ manta_adapt_timestep(mds->fluid);
+ dt = manta_get_timestep(mds->fluid);
+
+ /* save adapted dt so that MANTA object can access it (important when adaptive domain creates
+ * new MANTA object) */
+ mds->dt = dt;
+
+ /* count for how long this while loop is running */
+ time_per_frame += dt;
+ time_total += dt;
+
+ /* Calculate inflow geometry */
+ update_flowsfluids(depsgraph, scene, ob, mds, time_per_frame, frame_length, frame, dt);
+
+ manta_update_variables(mds->fluid, mmd);
+
+ /* Calculate obstacle geometry */
+ update_obstacles(depsgraph, scene, ob, mds, time_per_frame, frame_length, frame, dt);
+
+ if (mds->total_cells > 1) {
+ update_effectors(depsgraph, scene, ob, mds, dt);
+ manta_bake_data(mds->fluid, mmd, frame);
+
+ mds->time_per_frame = time_per_frame;
+ mds->time_total = time_total;
+ }
+ }
+
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS) {
+ manta_smoke_calc_transparency(mds, DEG_get_evaluated_view_layer(depsgraph));
+ }
+ BLI_mutex_unlock(&object_update_lock);
+}
+
+static void manta_guiding(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, FluidModifierData *mmd, int frame)
+{
+ FluidDomainSettings *mds = mmd->domain;
+ float fps = scene->r.frs_sec / scene->r.frs_sec_base;
+ float dt = DT_DEFAULT * (25.0f / fps) * mds->time_scale;
+ ;
+
+ BLI_mutex_lock(&object_update_lock);
+
+ update_obstacles(depsgraph, scene, ob, mds, dt, dt, frame, dt);
+ manta_bake_guiding(mds->fluid, mmd, frame);
+
+ BLI_mutex_unlock(&object_update_lock);
+}
+
+static void BKE_fluid_modifier_processFlow(FluidModifierData *mmd,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *me,
+ const int scene_framenr)
+{
+ if (scene_framenr >= mmd->time) {
+ BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me);
+ }
+
+ if (mmd->flow) {
+ if (mmd->flow->mesh) {
+ BKE_id_free(NULL, mmd->flow->mesh);
+ }
+ mmd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
+ }
+
+ if (scene_framenr > mmd->time) {
+ mmd->time = scene_framenr;
+ }
+ else if (scene_framenr < mmd->time) {
+ mmd->time = scene_framenr;
+ BKE_fluid_modifier_reset_ex(mmd, false);
+ }
+}
+
+static void BKE_fluid_modifier_processEffector(FluidModifierData *mmd,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *me,
+ const int scene_framenr)
+{
+ if (scene_framenr >= mmd->time) {
+ BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me);
+ }
+
+ if (mmd->effector) {
+ if (mmd->effector->mesh) {
+ BKE_id_free(NULL, mmd->effector->mesh);
+ }
+ mmd->effector->mesh = BKE_mesh_copy_for_eval(me, false);
+ }
+
+ if (scene_framenr > mmd->time) {
+ mmd->time = scene_framenr;
+ }
+ else if (scene_framenr < mmd->time) {
+ mmd->time = scene_framenr;
+ BKE_fluid_modifier_reset_ex(mmd, false);
+ }
+}
+
+static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *me,
+ const int scene_framenr)
+{
+ FluidDomainSettings *mds = mmd->domain;
+ Object *guide_parent = NULL;
+ Object **objs = NULL;
+ uint numobj = 0;
+ FluidModifierData *mmd_parent = NULL;
+
+ bool is_startframe;
+ is_startframe = (scene_framenr == mds->cache_frame_start);
+
+ /* Reset fluid if no fluid present (obviously)
+ * or if timeline gets reset to startframe */
+ if (!mds->fluid || is_startframe) {
+ BKE_fluid_modifier_reset_ex(mmd, false);
+ }
+
+ BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me);
+
+ /* ensure that time parameters are initialized correctly before every step */
+ float fps = scene->r.frs_sec / scene->r.frs_sec_base;
+ mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale;
+ mds->dt = mds->frame_length;
+ mds->time_per_frame = 0;
+ mds->time_total = (scene_framenr - 1) * mds->frame_length;
+
+ /* Guiding parent res pointer needs initialization */
+ guide_parent = mds->guide_parent;
+ if (guide_parent) {
+ mmd_parent = (FluidModifierData *)modifiers_findByType(guide_parent, eModifierType_Fluid);
+ if (mmd_parent->domain) {
+ copy_v3_v3_int(mds->guide_res, mmd_parent->domain->res);
+ }
+ }
+
+ objs = BKE_collision_objects_create(
+ depsgraph, ob, mds->fluid_group, &numobj, eModifierType_Fluid);
+ update_flowsflags(mds, objs, numobj);
+ if (objs) {
+ MEM_freeN(objs);
+ }
+
+ objs = BKE_collision_objects_create(
+ depsgraph, ob, mds->effector_group, &numobj, eModifierType_Fluid);
+ update_obstacleflags(mds, objs, numobj);
+ if (objs) {
+ MEM_freeN(objs);
+ }
+
+ /* Ensure cache directory is not relative */
+ const char *relbase = modifier_path_relbase_from_global(ob);
+ BLI_path_abs(mds->cache_directory, relbase);
+
+ int data_frame = scene_framenr, noise_frame = scene_framenr;
+ int mesh_frame = scene_framenr, particles_frame = scene_framenr, guide_frame = scene_framenr;
+
+ bool with_smoke, with_liquid;
+ with_smoke = mds->type == FLUID_DOMAIN_TYPE_GAS;
+ with_liquid = mds->type == FLUID_DOMAIN_TYPE_LIQUID;
+
+ bool drops, bubble, floater;
+ drops = mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY;
+ bubble = mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE;
+ floater = mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
+
+ bool with_script, with_adaptive, with_noise, with_mesh, with_particles, with_guide;
+ with_script = mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT;
+ with_adaptive = mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN;
+ with_noise = mds->flags & FLUID_DOMAIN_USE_NOISE;
+ with_mesh = mds->flags & FLUID_DOMAIN_USE_MESH;
+ with_guide = mds->flags & FLUID_DOMAIN_USE_GUIDE;
+ with_particles = drops || bubble || floater;
+
+ bool has_data, has_noise, has_mesh, has_particles, has_guide;
+ has_data = has_noise = has_mesh = has_particles = has_guide = false;
+
+ bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide, bake_outdated;
+ baking_data = mds->cache_flag & FLUID_DOMAIN_BAKING_DATA;
+ baking_noise = mds->cache_flag & FLUID_DOMAIN_BAKING_NOISE;
+ baking_mesh = mds->cache_flag & FLUID_DOMAIN_BAKING_MESH;
+ baking_particles = mds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES;
+ baking_guide = mds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE;
+ bake_outdated = mds->cache_flag &
+ (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
+ FLUID_DOMAIN_OUTDATED_NOISE | FLUID_DOMAIN_OUTDATED_MESH |
+ FLUID_DOMAIN_OUTDATED_PARTICLES | FLUID_DOMAIN_OUTDATED_GUIDE);
+
+ bool resume_data, resume_noise, resume_mesh, resume_particles, resume_guide;
+ resume_data = (!is_startframe) && (mds->cache_frame_pause_data == scene_framenr);
+ resume_noise = (!is_startframe) && (mds->cache_frame_pause_noise == scene_framenr);
+ resume_mesh = (!is_startframe) && (mds->cache_frame_pause_mesh == scene_framenr);
+ resume_particles = (!is_startframe) && (mds->cache_frame_pause_particles == scene_framenr);
+ resume_guide = (!is_startframe) && (mds->cache_frame_pause_guide == scene_framenr);
+
+ bool read_cache, bake_cache;
+ read_cache = false, bake_cache = baking_data || baking_noise || baking_mesh || baking_particles;
+
+ bool with_gdomain;
+ with_gdomain = (mds->guide_source == FLUID_DOMAIN_GUIDE_SRC_DOMAIN);
+
+ int o_res[3], o_min[3], o_max[3], o_shift[3];
+ int mode = mds->cache_type;
+ int prev_frame = scene_framenr - 1;
+
+ /* Ensure positivity of previous frame. */
+ CLAMP(prev_frame, 1, prev_frame);
+
+ /* Cache mode specific settings */
+ switch (mode) {
+ case FLUID_DOMAIN_CACHE_FINAL:
+ /* Just load the data that has already been baked */
+ if (!baking_data && !baking_noise && !baking_mesh && !baking_particles) {
+ read_cache = true;
+ bake_cache = false;
+ }
+ break;
+ case FLUID_DOMAIN_CACHE_MODULAR:
+ /* Just load the data that has already been baked */
+ if (!baking_data && !baking_noise && !baking_mesh && !baking_particles) {
+ read_cache = true;
+ bake_cache = false;
+ break;
+ }
+
+ /* Set to previous frame if the bake was resumed
+ * ie don't read all of the already baked frames, just the one before bake resumes */
+ if (baking_data && resume_data) {
+ data_frame = prev_frame;
+ }
+ if (baking_noise && resume_noise) {
+ noise_frame = prev_frame;
+ }
+ if (baking_mesh && resume_mesh) {
+ mesh_frame = prev_frame;
+ }
+ if (baking_particles && resume_particles) {
+ particles_frame = prev_frame;
+ }
+ if (baking_guide && resume_guide) {
+ guide_frame = prev_frame;
+ }
+
+ /* Noise, mesh and particles can never be baked more than data. */
+ CLAMP(noise_frame, noise_frame, data_frame);
+ CLAMP(mesh_frame, mesh_frame, data_frame);
+ CLAMP(particles_frame, particles_frame, data_frame);
+ CLAMP(guide_frame, guide_frame, mds->cache_frame_end);
+
+ /* Force to read cache as we're resuming the bake */
+ read_cache = true;
+ break;
+ case FLUID_DOMAIN_CACHE_REPLAY:
+ default:
+ /* Always trying to read the cache in replay mode. */
+ read_cache = true;
+ break;
+ }
+
+ /* Cache outdated? If so reset, don't read, and then just rebake.
+ * Note: Only do this in replay mode! */
+ bool mode_replay = (mode == FLUID_DOMAIN_CACHE_REPLAY);
+ if (bake_outdated && mode_replay) {
+ read_cache = false;
+ bake_cache = true;
+ BKE_fluid_cache_free(mds, ob, mds->cache_flag);
+ }
+
+ /* Try to read from cache and keep track of read success. */
+ if (read_cache) {
+
+ /* Read mesh cache. */
+ if (with_liquid && with_mesh) {
+ has_mesh = manta_read_mesh(mds->fluid, mmd, mesh_frame);
+ }
+
+ /* Read particles cache. */
+ if (with_liquid && with_particles) {
+ has_particles = manta_read_particles(mds->fluid, mmd, particles_frame);
+ }
+
+ /* Read guide cache. */
+ if (with_guide) {
+ FluidModifierData *mmd2 = (with_gdomain) ? mmd_parent : mmd;
+ has_guide = manta_read_guiding(mds->fluid, mmd2, scene_framenr, with_gdomain);
+ }
+
+ /* Read noise and data cache */
+ if (with_smoke && with_noise) {
+
+ /* Only reallocate when just reading cache or when resuming during bake. */
+ if ((!baking_noise || (baking_noise && resume_noise)) &&
+ manta_read_config(mds->fluid, mmd, noise_frame) &&
+ manta_needs_realloc(mds->fluid, mmd)) {
+ BKE_fluid_reallocate_fluid(mds, mds->res, 1);
+ }
+ has_noise = manta_read_noise(mds->fluid, mmd, noise_frame);
+
+ /* In case of using the adaptive domain, copy all data that was read to a new fluid object.
+ */
+ if (with_adaptive && baking_noise) {
+ /* Adaptive domain needs to know about current state, so save it, then copy. */
+ copy_v3_v3_int(o_res, mds->res);
+ copy_v3_v3_int(o_min, mds->res_min);
+ copy_v3_v3_int(o_max, mds->res_max);
+ copy_v3_v3_int(o_shift, mds->shift);
+ if (manta_read_config(mds->fluid, mmd, data_frame) &&
+ manta_needs_realloc(mds->fluid, mmd)) {
+ BKE_fluid_reallocate_copy_fluid(
+ mds, o_res, mds->res, o_min, mds->res_min, o_max, o_shift, mds->shift);
+ }
+ }
+ has_data = manta_read_data(mds->fluid, mmd, data_frame);
+ }
+ /* Read data cache only */
+ else {
+ /* Read config and realloc fluid object if needed. */
+ if (manta_read_config(mds->fluid, mmd, data_frame) && manta_needs_realloc(mds->fluid, mmd)) {
+ BKE_fluid_reallocate_fluid(mds, mds->res, 1);
+ }
+ /* Read data cache */
+ has_data = manta_read_data(mds->fluid, mmd, data_frame);
+ }
+ }
+
+ /* Cache mode specific settings */
+ switch (mode) {
+ case FLUID_DOMAIN_CACHE_FINAL:
+ case FLUID_DOMAIN_CACHE_MODULAR:
+ break;
+ case FLUID_DOMAIN_CACHE_REPLAY:
+ default:
+ baking_data = !has_data;
+ if (with_smoke && with_noise) {
+ baking_noise = !has_noise;
+ }
+ if (with_liquid && with_mesh) {
+ baking_mesh = !has_mesh;
+ }
+ if (with_liquid && with_particles) {
+ baking_particles = !has_particles;
+ }
+
+ bake_cache = baking_data || baking_noise || baking_mesh || baking_particles;
+ break;
+ }
+
+ /* Trigger bake calls individually */
+ if (bake_cache) {
+ /* Ensure fresh variables at every animation step */
+ manta_update_variables(mds->fluid, mmd);
+
+ /* Export mantaflow python script on first frame (once only) and for any bake type */
+ if (with_script && is_startframe) {
+ if (with_smoke) {
+ manta_smoke_export_script(mmd->domain->fluid, mmd);
+ }
+ if (with_liquid) {
+ manta_liquid_export_script(mmd->domain->fluid, mmd);
+ }
+ }
+
+ if (baking_guide && with_guide) {
+ manta_guiding(depsgraph, scene, ob, mmd, scene_framenr);
+ }
+ if (baking_data) {
+ manta_step(depsgraph, scene, ob, me, mmd, scene_framenr);
+ manta_write_config(mds->fluid, mmd, scene_framenr);
+ manta_write_data(mds->fluid, mmd, scene_framenr);
+ }
+ if (has_data || baking_data) {
+ if (baking_noise && with_smoke && with_noise) {
+ manta_bake_noise(mds->fluid, mmd, scene_framenr);
+ }
+ if (baking_mesh && with_liquid && with_mesh) {
+ manta_bake_mesh(mds->fluid, mmd, scene_framenr);
+ }
+ if (baking_particles && with_liquid && with_particles) {
+ manta_bake_particles(mds->fluid, mmd, scene_framenr);
+ }
+ }
+ }
+ mmd->time = scene_framenr;
+}
+
+static void BKE_fluid_modifier_process(
+ FluidModifierData *mmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
+{
+ const int scene_framenr = (int)DEG_get_ctime(depsgraph);
+
+ if ((mmd->type & MOD_FLUID_TYPE_FLOW)) {
+ BKE_fluid_modifier_processFlow(mmd, depsgraph, scene, ob, me, scene_framenr);
+ }
+ else if (mmd->type & MOD_FLUID_TYPE_EFFEC) {
+ BKE_fluid_modifier_processEffector(mmd, depsgraph, scene, ob, me, scene_framenr);
+ }
+ else if (mmd->type & MOD_FLUID_TYPE_DOMAIN) {
+ BKE_fluid_modifier_processDomain(mmd, depsgraph, scene, ob, me, scene_framenr);
+ }
+}
+
+struct Mesh *BKE_fluid_modifier_do(
+ FluidModifierData *mmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
+{
+ /* Lock so preview render does not read smoke data while it gets modified. */
+ if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) {
+ BLI_rw_mutex_lock(mmd->domain->fluid_mutex, THREAD_LOCK_WRITE);
+ }
+
+ BKE_fluid_modifier_process(mmd, depsgraph, scene, ob, me);
+
+ if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) {
+ BLI_rw_mutex_unlock(mmd->domain->fluid_mutex);
+ }
+
+ Mesh *result = NULL;
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) {
+ /* Return generated geometry depending on domain type. */
+ if (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ result = create_liquid_geometry(mmd->domain, me, ob);
+ }
+ if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
+ result = create_smoke_geometry(mmd->domain, me, ob);
+ }
+ /* Clear flag outside of locked block (above). */
+ mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_DATA;
+ mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_NOISE;
+ mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_MESH;
+ mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES;
+ mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDE;
+ }
+ if (!result) {
+ result = BKE_mesh_copy_for_eval(me, false);
+ }
+ else {
+ BKE_mesh_copy_settings(result, me);
+ }
+
+ /* Liquid simulation has a texture space that based on the bounds of the fluid mesh.
+ * This does not seem particularly useful, but it's backwards compatible.
+ *
+ * Smoke simulation needs a texture space relative to the adaptive domain bounds, not the
+ * original mesh. So recompute it at this point in the modifier stack. See T58492. */
+ BKE_mesh_texspace_calc(result);
+
+ return result;
+}
+
+static float calc_voxel_transp(
+ float *result, float *input, int res[3], int *pixel, float *t_ray, float correct)
+{
+ const size_t index = manta_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
+
+ // T_ray *= T_vox
+ *t_ray *= expf(input[index] * correct);
+
+ if (result[index] < 0.0f) {
+ result[index] = *t_ray;
+ }
+
+ return *t_ray;
+}
+
+static void bresenham_linie_3D(int x1,
+ int y1,
+ int z1,
+ int x2,
+ int y2,
+ int z2,
+ float *t_ray,
+ BKE_Fluid_BresenhamFn cb,
+ float *result,
+ float *input,
+ int res[3],
+ float correct)
+{
+ int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
+ int pixel[3];
+
+ pixel[0] = x1;
+ pixel[1] = y1;
+ pixel[2] = z1;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dz = z2 - z1;
+
+ x_inc = (dx < 0) ? -1 : 1;
+ l = abs(dx);
+ y_inc = (dy < 0) ? -1 : 1;
+ m = abs(dy);
+ z_inc = (dz < 0) ? -1 : 1;
+ n = abs(dz);
+ dx2 = l << 1;
+ dy2 = m << 1;
+ dz2 = n << 1;
+
+ if ((l >= m) && (l >= n)) {
+ err_1 = dy2 - l;
+ err_2 = dz2 - l;
+ for (i = 0; i < l; i++) {
+ if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) {
+ break;
+ }
+ if (err_1 > 0) {
+ pixel[1] += y_inc;
+ err_1 -= dx2;
+ }
+ if (err_2 > 0) {
+ pixel[2] += z_inc;
+ err_2 -= dx2;
+ }
+ err_1 += dy2;
+ err_2 += dz2;
+ pixel[0] += x_inc;
+ }
+ }
+ else if ((m >= l) && (m >= n)) {
+ err_1 = dx2 - m;
+ err_2 = dz2 - m;
+ for (i = 0; i < m; i++) {
+ if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) {
+ break;
+ }
+ if (err_1 > 0) {
+ pixel[0] += x_inc;
+ err_1 -= dy2;
+ }
+ if (err_2 > 0) {
+ pixel[2] += z_inc;
+ err_2 -= dy2;
+ }
+ err_1 += dx2;
+ err_2 += dz2;
+ pixel[1] += y_inc;
+ }
+ }
+ else {
+ err_1 = dy2 - n;
+ err_2 = dx2 - n;
+ for (i = 0; i < n; i++) {
+ if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) {
+ break;
+ }
+ if (err_1 > 0) {
+ pixel[1] += y_inc;
+ err_1 -= dz2;
+ }
+ if (err_2 > 0) {
+ pixel[0] += x_inc;
+ err_2 -= dz2;
+ }
+ err_1 += dy2;
+ err_2 += dx2;
+ pixel[2] += z_inc;
+ }
+ }
+ cb(result, input, res, pixel, t_ray, correct);
+}
+
+static void manta_smoke_calc_transparency(FluidDomainSettings *mds, ViewLayer *view_layer)
+{
+ float bv[6] = {0};
+ float light[3];
+ int a, z, slabsize = mds->res[0] * mds->res[1], size = mds->res[0] * mds->res[1] * mds->res[2];
+ float *density = manta_smoke_get_density(mds->fluid);
+ float *shadow = manta_smoke_get_shadow(mds->fluid);
+ float correct = -7.0f * mds->dx;
+
+ if (!get_light(view_layer, light)) {
+ return;
+ }
+
+ /* convert light pos to sim cell space */
+ mul_m4_v3(mds->imat, light);
+ light[0] = (light[0] - mds->p0[0]) / mds->cell_size[0] - 0.5f - (float)mds->res_min[0];
+ light[1] = (light[1] - mds->p0[1]) / mds->cell_size[1] - 0.5f - (float)mds->res_min[1];
+ light[2] = (light[2] - mds->p0[2]) / mds->cell_size[2] - 0.5f - (float)mds->res_min[2];
+
+ for (a = 0; a < size; a++) {
+ shadow[a] = -1.0f;
+ }
+
+ /* calculate domain bounds in sim cell space */
+ // 0,2,4 = 0.0f
+ bv[1] = (float)mds->res[0]; // x
+ bv[3] = (float)mds->res[1]; // y
+ bv[5] = (float)mds->res[2]; // z
+
+ for (z = 0; z < mds->res[2]; z++) {
+ size_t index = z * slabsize;
+ int x, y;
+
+ for (y = 0; y < mds->res[1]; y++) {
+ for (x = 0; x < mds->res[0]; x++, index++) {
+ float voxel_center[3];
+ float pos[3];
+ int cell[3];
+ float t_ray = 1.0;
+
+ if (shadow[index] >= 0.0f) {
+ continue;
+ }
+ voxel_center[0] = (float)x;
+ voxel_center[1] = (float)y;
+ voxel_center[2] = (float)z;
+
+ // get starting cell (light pos)
+ if (BLI_bvhtree_bb_raycast(bv, light, voxel_center, pos) > FLT_EPSILON) {
+ // we're ouside -> use point on side of domain
+ cell[0] = (int)floor(pos[0]);
+ cell[1] = (int)floor(pos[1]);
+ cell[2] = (int)floor(pos[2]);
+ }
+ else {
+ // we're inside -> use light itself
+ cell[0] = (int)floor(light[0]);
+ cell[1] = (int)floor(light[1]);
+ cell[2] = (int)floor(light[2]);
+ }
+ /* clamp within grid bounds */
+ CLAMP(cell[0], 0, mds->res[0] - 1);
+ CLAMP(cell[1], 0, mds->res[1] - 1);
+ CLAMP(cell[2], 0, mds->res[2] - 1);
+
+ bresenham_linie_3D(cell[0],
+ cell[1],
+ cell[2],
+ x,
+ y,
+ z,
+ &t_ray,
+ calc_voxel_transp,
+ shadow,
+ density,
+ mds->res,
+ correct);
+
+ // convention -> from a RGBA float array, use G value for t_ray
+ shadow[index] = t_ray;
+ }
+ }
+ }
+}
+
+/* get smoke velocity and density at given coordinates
+ * returns fluid density or -1.0f if outside domain. */
+float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
+{
+ FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ zero_v3(velocity);
+
+ if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain && mmd->domain->fluid) {
+ FluidDomainSettings *mds = mmd->domain;
+ float time_mult = 25.f * DT_DEFAULT;
+ float vel_mag;
+ float *velX = manta_get_velocity_x(mds->fluid);
+ float *velY = manta_get_velocity_y(mds->fluid);
+ float *velZ = manta_get_velocity_z(mds->fluid);
+ float density = 0.0f, fuel = 0.0f;
+ float pos[3];
+ copy_v3_v3(pos, position);
+ manta_pos_to_cell(mds, pos);
+
+ /* check if point is outside domain max bounds */
+ if (pos[0] < mds->res_min[0] || pos[1] < mds->res_min[1] || pos[2] < mds->res_min[2]) {
+ return -1.0f;
+ }
+ if (pos[0] > mds->res_max[0] || pos[1] > mds->res_max[1] || pos[2] > mds->res_max[2]) {
+ return -1.0f;
+ }
+
+ /* map pos between 0.0 - 1.0 */
+ pos[0] = (pos[0] - mds->res_min[0]) / ((float)mds->res[0]);
+ pos[1] = (pos[1] - mds->res_min[1]) / ((float)mds->res[1]);
+ pos[2] = (pos[2] - mds->res_min[2]) / ((float)mds->res[2]);
+
+ /* check if point is outside active area */
+ if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS &&
+ mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
+ if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) {
+ return 0.0f;
+ }
+ if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) {
+ return 0.0f;
+ }
+ }
+
+ /* get interpolated velocity */
+ velocity[0] = BLI_voxel_sample_trilinear(velX, mds->res, pos) * mds->global_size[0] *
+ time_mult;
+ velocity[1] = BLI_voxel_sample_trilinear(velY, mds->res, pos) * mds->global_size[1] *
+ time_mult;
+ velocity[2] = BLI_voxel_sample_trilinear(velZ, mds->res, pos) * mds->global_size[2] *
+ time_mult;
+
+ /* convert velocity direction to global space */
+ vel_mag = len_v3(velocity);
+ mul_mat3_m4_v3(mds->obmat, velocity);
+ normalize_v3(velocity);
+ mul_v3_fl(velocity, vel_mag);
+
+ /* use max value of fuel or smoke density */
+ density = BLI_voxel_sample_trilinear(manta_smoke_get_density(mds->fluid), mds->res, pos);
+ if (manta_smoke_has_fuel(mds->fluid)) {
+ fuel = BLI_voxel_sample_trilinear(manta_smoke_get_fuel(mds->fluid), mds->res, pos);
+ }
+ return MAX2(density, fuel);
+ }
+ return -1.0f;
+}
+
+int BKE_fluid_get_data_flags(FluidDomainSettings *mds)
+{
+ int flags = 0;
+
+ if (mds->fluid) {
+ if (manta_smoke_has_heat(mds->fluid)) {
+ flags |= FLUID_DOMAIN_ACTIVE_HEAT;
+ }
+ if (manta_smoke_has_fuel(mds->fluid)) {
+ flags |= FLUID_DOMAIN_ACTIVE_FIRE;
+ }
+ if (manta_smoke_has_colors(mds->fluid)) {
+ flags |= FLUID_DOMAIN_ACTIVE_COLORS;
+ }
+ }
+
+ return flags;
+}
+
+void BKE_fluid_particle_system_create(struct Main *bmain,
+ struct Object *ob,
+ const char *pset_name,
+ const char *parts_name,
+ const char *psys_name,
+ const int psys_type)
+{
+ ParticleSystem *psys;
+ ParticleSettings *part;
+ ParticleSystemModifierData *pmmd;
+
+ /* add particle system */
+ part = BKE_particlesettings_add(bmain, pset_name);
+ psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
+
+ part->type = psys_type;
+ part->totpart = 0;
+ part->draw_size = 0.01f; // make fluid particles more subtle in viewport
+ part->draw_col = PART_DRAW_COL_VEL;
+ psys->part = part;
+ psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
+ BLI_strncpy(psys->name, parts_name, sizeof(psys->name));
+ BLI_addtail(&ob->particlesystem, psys);
+
+ /* add modifier */
+ pmmd = (ParticleSystemModifierData *)modifier_new(eModifierType_ParticleSystem);
+ BLI_strncpy(pmmd->modifier.name, psys_name, sizeof(pmmd->modifier.name));
+ pmmd->psys = psys;
+ BLI_addtail(&ob->modifiers, pmmd);
+ modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd);
+}
+
+void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type)
+{
+ ParticleSystemModifierData *pmmd;
+ ParticleSystem *psys, *next_psys;
+
+ for (psys = ob->particlesystem.first; psys; psys = next_psys) {
+ next_psys = psys->next;
+ if (psys->part->type & particle_type) {
+ /* clear modifier */
+ pmmd = psys_get_modifier(ob, psys);
+ BLI_remlink(&ob->modifiers, pmmd);
+ modifier_free((ModifierData *)pmmd);
+
+ /* clear particle system */
+ BLI_remlink(&ob->particlesystem, psys);
+ psys_free(ob, psys);
+ }
+ }
+}
+
+#endif /* WITH_FLUID */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Data Access API
+ *
+ * Use for versioning, even when fluids are disabled.
+ * \{ */
+
+void BKE_fluid_cachetype_mesh_set(FluidDomainSettings *settings, int cache_mesh_format)
+{
+ if (cache_mesh_format == settings->cache_mesh_format) {
+ return;
+ }
+ /* TODO(sebbas): Clear old caches. */
+ settings->cache_mesh_format = cache_mesh_format;
+}
+
+void BKE_fluid_cachetype_data_set(FluidDomainSettings *settings, int cache_data_format)
+{
+ if (cache_data_format == settings->cache_data_format) {
+ return;
+ }
+ /* TODO(sebbas): Clear old caches. */
+ settings->cache_data_format = cache_data_format;
+}
+
+void BKE_fluid_cachetype_particle_set(FluidDomainSettings *settings, int cache_particle_format)
+{
+ if (cache_particle_format == settings->cache_particle_format) {
+ return;
+ }
+ /* TODO(sebbas): Clear old caches. */
+ settings->cache_particle_format = cache_particle_format;
+}
+
+void BKE_fluid_cachetype_noise_set(FluidDomainSettings *settings, int cache_noise_format)
+{
+ if (cache_noise_format == settings->cache_noise_format) {
+ return;
+ }
+ /* TODO(sebbas): Clear old caches. */
+ settings->cache_noise_format = cache_noise_format;
+}
+
+void BKE_fluid_collisionextents_set(FluidDomainSettings *settings, int value, bool clear)
+{
+ if (clear) {
+ settings->border_collisions &= value;
+ }
+ else {
+ settings->border_collisions |= value;
+ }
+}
+
+void BKE_fluid_particles_set(FluidDomainSettings *settings, int value, bool clear)
+{
+ if (clear) {
+ settings->particle_type &= ~value;
+ }
+ else {
+ settings->particle_type |= value;
+ }
+}
+
+void BKE_fluid_domain_type_set(Object *object, FluidDomainSettings *settings, int type)
+{
+ /* Set common values for liquid/smoke domain: cache type,
+ * border collision and viewport draw-type. */
+ if (type == FLUID_DOMAIN_TYPE_GAS) {
+ BKE_fluid_cachetype_mesh_set(settings, FLUID_DOMAIN_FILE_BIN_OBJECT);
+ BKE_fluid_cachetype_data_set(settings, FLUID_DOMAIN_FILE_UNI);
+ BKE_fluid_cachetype_particle_set(settings, FLUID_DOMAIN_FILE_UNI);
+ BKE_fluid_cachetype_noise_set(settings, FLUID_DOMAIN_FILE_UNI);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_FRONT, 1);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_BACK, 1);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_RIGHT, 1);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_LEFT, 1);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_TOP, 1);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_BOTTOM, 1);
+ object->dt = OB_WIRE;
+ }
+ else if (type == FLUID_DOMAIN_TYPE_LIQUID) {
+ BKE_fluid_cachetype_mesh_set(settings, FLUID_DOMAIN_FILE_BIN_OBJECT);
+ BKE_fluid_cachetype_data_set(settings, FLUID_DOMAIN_FILE_UNI);
+ BKE_fluid_cachetype_particle_set(settings, FLUID_DOMAIN_FILE_UNI);
+ BKE_fluid_cachetype_noise_set(settings, FLUID_DOMAIN_FILE_UNI);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_FRONT, 0);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_BACK, 0);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_RIGHT, 0);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_LEFT, 0);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_TOP, 0);
+ BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_BOTTOM, 0);
+ BKE_fluid_particles_set(settings, FLUID_DOMAIN_PARTICLE_FLIP, 0);
+ object->dt = OB_SOLID;
+ }
+
+ /* Set actual domain type. */
+ settings->type = type;
+}
+
+void BKE_fluid_flow_behavior_set(Object *UNUSED(object), FluidFlowSettings *settings, int behavior)
+{
+ settings->behavior = behavior;
+}
+
+void BKE_fluid_flow_type_set(Object *object, FluidFlowSettings *settings, int type)
+{
+ /* By default, liquid flow objects should behave like their geometry (geometry behavior),
+ * gas flow objects should continuously produce smoke (inflow behavior). */
+ if (type == FLUID_FLOW_TYPE_LIQUID) {
+ BKE_fluid_flow_behavior_set(object, settings, FLUID_FLOW_BEHAVIOR_GEOMETRY);
+ }
+ else {
+ BKE_fluid_flow_behavior_set(object, settings, FLUID_FLOW_BEHAVIOR_INFLOW);
+ }
+
+ /* Set actual flow type. */
+ settings->type = type;
+}
+
+void BKE_fluid_effector_type_set(Object *UNUSED(object), FluidEffectorSettings *settings, int type)
+{
+ settings->type = type;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Modifier API
+ *
+ * Use for versioning, even when fluids are disabled.
+ * \{ */
+
+static void BKE_fluid_modifier_freeDomain(FluidModifierData *mmd)
+{
+ if (mmd->domain) {
+ if (mmd->domain->fluid) {
+#ifdef WITH_FLUID
+ manta_free(mmd->domain->fluid);
+#endif
+ }
+
+ if (mmd->domain->fluid_mutex) {
+ BLI_rw_mutex_free(mmd->domain->fluid_mutex);
+ }
+
+ if (mmd->domain->effector_weights) {
+ MEM_freeN(mmd->domain->effector_weights);
+ }
+ mmd->domain->effector_weights = NULL;
+
+ if (!(mmd->modifier.flag & eModifierFlag_SharedCaches)) {
+ BKE_ptcache_free_list(&(mmd->domain->ptcaches[0]));
+ mmd->domain->point_cache[0] = NULL;
+ }
+
+ if (mmd->domain->mesh_velocities) {
+ MEM_freeN(mmd->domain->mesh_velocities);
+ }
+ mmd->domain->mesh_velocities = NULL;
+
+ if (mmd->domain->coba) {
+ MEM_freeN(mmd->domain->coba);
+ }
+
+ MEM_freeN(mmd->domain);
+ mmd->domain = NULL;
+ }
+}
+
+static void BKE_fluid_modifier_freeFlow(FluidModifierData *mmd)
+{
+ if (mmd->flow) {
+ if (mmd->flow->mesh) {
+ BKE_id_free(NULL, mmd->flow->mesh);
+ }
+ mmd->flow->mesh = NULL;
+
+ if (mmd->flow->verts_old) {
+ MEM_freeN(mmd->flow->verts_old);
+ }
+ mmd->flow->verts_old = NULL;
+ mmd->flow->numverts = 0;
+
+ MEM_freeN(mmd->flow);
+ mmd->flow = NULL;
+ }
+}
+
+static void BKE_fluid_modifier_freeEffector(FluidModifierData *mmd)
+{
+ if (mmd->effector) {
+ if (mmd->effector->mesh) {
+ BKE_id_free(NULL, mmd->effector->mesh);
+ }
+ mmd->effector->mesh = NULL;
+
+ if (mmd->effector->verts_old) {
+ MEM_freeN(mmd->effector->verts_old);
+ }
+ mmd->effector->verts_old = NULL;
+ mmd->effector->numverts = 0;
+
+ MEM_freeN(mmd->effector);
+ mmd->effector = NULL;
+ }
+}
+
+static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need_lock)
+{
+ if (!mmd) {
+ return;
+ }
+
+ if (mmd->domain) {
+ if (mmd->domain->fluid) {
+ if (need_lock) {
+ BLI_rw_mutex_lock(mmd->domain->fluid_mutex, THREAD_LOCK_WRITE);
+ }
+
+#ifdef WITH_FLUID
+ manta_free(mmd->domain->fluid);
+#endif
+ mmd->domain->fluid = NULL;
+
+ if (need_lock) {
+ BLI_rw_mutex_unlock(mmd->domain->fluid_mutex);
+ }
+ }
+
+ mmd->time = -1;
+ mmd->domain->total_cells = 0;
+ mmd->domain->active_fields = 0;
+ }
+ else if (mmd->flow) {
+ if (mmd->flow->verts_old) {
+ MEM_freeN(mmd->flow->verts_old);
+ }
+ mmd->flow->verts_old = NULL;
+ mmd->flow->numverts = 0;
+ }
+ else if (mmd->effector) {
+ if (mmd->effector->verts_old) {
+ MEM_freeN(mmd->effector->verts_old);
+ }
+ mmd->effector->verts_old = NULL;
+ mmd->effector->numverts = 0;
+ }
+}
+
+void BKE_fluid_modifier_reset(struct FluidModifierData *mmd)
+{
+ BKE_fluid_modifier_reset_ex(mmd, true);
+}
+
+void BKE_fluid_modifier_free(FluidModifierData *mmd)
+{
+ if (!mmd) {
+ return;
+ }
+
+ BKE_fluid_modifier_freeDomain(mmd);
+ BKE_fluid_modifier_freeFlow(mmd);
+ BKE_fluid_modifier_freeEffector(mmd);
+}
+
+void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
+{
+ if (!mmd) {
+ return;
+ }
+
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN) {
+ if (mmd->domain) {
+ BKE_fluid_modifier_freeDomain(mmd);
+ }
+
+ /* domain object data */
+ mmd->domain = MEM_callocN(sizeof(FluidDomainSettings), "FluidDomain");
+ mmd->domain->mmd = mmd;
+ mmd->domain->effector_weights = BKE_effector_add_weights(NULL);
+ mmd->domain->fluid = NULL;
+ mmd->domain->fluid_mutex = BLI_rw_mutex_alloc();
+ mmd->domain->force_group = NULL;
+ mmd->domain->fluid_group = NULL;
+ mmd->domain->effector_group = NULL;
+
+ /* adaptive domain options */
+ mmd->domain->adapt_margin = 4;
+ mmd->domain->adapt_res = 0;
+ mmd->domain->adapt_threshold = 0.02f;
+
+ /* fluid domain options */
+ mmd->domain->maxres = 64;
+ mmd->domain->solver_res = 3;
+ mmd->domain->border_collisions = 0; // open domain
+ mmd->domain->flags = FLUID_DOMAIN_USE_DISSOLVE_LOG | FLUID_DOMAIN_USE_ADAPTIVE_TIME;
+ mmd->domain->gravity[0] = 0.0f;
+ mmd->domain->gravity[1] = 0.0f;
+ mmd->domain->gravity[2] = -1.0f;
+ mmd->domain->active_fields = 0;
+ mmd->domain->type = FLUID_DOMAIN_TYPE_GAS;
+ mmd->domain->boundary_width = 1;
+
+ /* smoke domain options */
+ mmd->domain->alpha = 1.0f;
+ mmd->domain->beta = 1.0f;
+ mmd->domain->diss_speed = 5;
+ mmd->domain->vorticity = 0;
+ mmd->domain->active_color[0] = 0.0f;
+ mmd->domain->active_color[1] = 0.0f;
+ mmd->domain->active_color[2] = 0.0f;
+ mmd->domain->highres_sampling = SM_HRES_FULLSAMPLE;
+
+ /* flame options */
+ mmd->domain->burning_rate = 0.75f;
+ mmd->domain->flame_smoke = 1.0f;
+ mmd->domain->flame_vorticity = 0.5f;
+ mmd->domain->flame_ignition = 1.5f;
+ mmd->domain->flame_max_temp = 3.0f;
+ mmd->domain->flame_smoke_color[0] = 0.7f;
+ mmd->domain->flame_smoke_color[1] = 0.7f;
+ mmd->domain->flame_smoke_color[2] = 0.7f;
+
+ /* noise options */
+ mmd->domain->noise_strength = 1.0;
+ mmd->domain->noise_pos_scale = 2.0f;
+ mmd->domain->noise_time_anim = 0.1f;
+ mmd->domain->noise_scale = 2;
+ mmd->domain->noise_type = FLUID_NOISE_TYPE_WAVELET;
+
+ /* liquid domain options */
+ mmd->domain->simulation_method = FLUID_DOMAIN_METHOD_FLIP;
+ mmd->domain->flip_ratio = 0.97f;
+ mmd->domain->particle_randomness = 0.1f;
+ mmd->domain->particle_number = 2;
+ mmd->domain->particle_minimum = 8;
+ mmd->domain->particle_maximum = 16;
+ mmd->domain->particle_radius = 1.5f;
+ mmd->domain->particle_band_width = 3.0f;
+ mmd->domain->fractions_threshold = 0.05f;
+
+ /* diffusion options*/
+ mmd->domain->surface_tension = 0.0f;
+ mmd->domain->viscosity_base = 1.0f;
+ mmd->domain->viscosity_exponent = 6.0f;
+ mmd->domain->domain_size = 0.5f;
+
+ /* mesh options */
+ mmd->domain->mesh_velocities = NULL;
+ mmd->domain->mesh_concave_upper = 3.5f;
+ mmd->domain->mesh_concave_lower = 0.4f;
+ mmd->domain->mesh_particle_radius = 2.0;
+ mmd->domain->mesh_smoothen_pos = 1;
+ mmd->domain->mesh_smoothen_neg = 1;
+ mmd->domain->mesh_scale = 2;
+ mmd->domain->totvert = 0;
+ mmd->domain->mesh_generator = FLUID_DOMAIN_MESH_IMPROVED;
+
+ /* secondary particle options */
+ mmd->domain->sndparticle_tau_min_wc = 2.0;
+ mmd->domain->sndparticle_tau_max_wc = 8.0;
+ mmd->domain->sndparticle_tau_min_ta = 5.0;
+ mmd->domain->sndparticle_tau_max_ta = 20.0;
+ mmd->domain->sndparticle_tau_min_k = 1.0;
+ mmd->domain->sndparticle_tau_max_k = 5.0;
+ mmd->domain->sndparticle_k_wc = 200;
+ mmd->domain->sndparticle_k_ta = 40;
+ mmd->domain->sndparticle_k_b = 0.5;
+ mmd->domain->sndparticle_k_d = 0.6;
+ mmd->domain->sndparticle_l_min = 10.0;
+ mmd->domain->sndparticle_l_max = 25.0;
+ mmd->domain->sndparticle_boundary = SNDPARTICLE_BOUNDARY_DELETE;
+ mmd->domain->sndparticle_combined_export = SNDPARTICLE_COMBINED_EXPORT_OFF;
+ mmd->domain->sndparticle_potential_radius = 2;
+ mmd->domain->sndparticle_update_radius = 2;
+ mmd->domain->particle_type = 0;
+ mmd->domain->particle_scale = 1;
+
+ /* fluid guide options */
+ mmd->domain->guide_parent = NULL;
+ mmd->domain->guide_alpha = 2.0f;
+ mmd->domain->guide_beta = 5;
+ mmd->domain->guide_vel_factor = 2.0f;
+ mmd->domain->guide_source = FLUID_DOMAIN_GUIDE_SRC_DOMAIN;
+
+ /* cache options */
+ mmd->domain->cache_frame_start = 1;
+ mmd->domain->cache_frame_end = 50;
+ mmd->domain->cache_frame_pause_data = 0;
+ mmd->domain->cache_frame_pause_noise = 0;
+ mmd->domain->cache_frame_pause_mesh = 0;
+ mmd->domain->cache_frame_pause_particles = 0;
+ mmd->domain->cache_frame_pause_guide = 0;
+ mmd->domain->cache_flag = 0;
+ mmd->domain->cache_type = FLUID_DOMAIN_CACHE_MODULAR;
+ mmd->domain->cache_mesh_format = FLUID_DOMAIN_FILE_BIN_OBJECT;
+ mmd->domain->cache_data_format = FLUID_DOMAIN_FILE_UNI;
+ mmd->domain->cache_particle_format = FLUID_DOMAIN_FILE_UNI;
+ mmd->domain->cache_noise_format = FLUID_DOMAIN_FILE_UNI;
+ modifier_path_init(mmd->domain->cache_directory,
+ sizeof(mmd->domain->cache_directory),
+ FLUID_DOMAIN_DIR_DEFAULT);
+
+ /* time options */
+ mmd->domain->time_scale = 1.0;
+ mmd->domain->cfl_condition = 4.0;
+ mmd->domain->timesteps_minimum = 1;
+ mmd->domain->timesteps_maximum = 4;
+
+ /* display options */
+ mmd->domain->slice_method = FLUID_DOMAIN_SLICE_VIEW_ALIGNED;
+ mmd->domain->axis_slice_method = AXIS_SLICE_FULL;
+ mmd->domain->slice_axis = 0;
+ mmd->domain->interp_method = 0;
+ mmd->domain->draw_velocity = false;
+ mmd->domain->slice_per_voxel = 5.0f;
+ mmd->domain->slice_depth = 0.5f;
+ mmd->domain->display_thickness = 1.0f;
+ mmd->domain->coba = NULL;
+ mmd->domain->vector_scale = 1.0f;
+ mmd->domain->vector_draw_type = VECTOR_DRAW_NEEDLE;
+ mmd->domain->use_coba = false;
+ mmd->domain->coba_field = FLUID_DOMAIN_FIELD_DENSITY;
+
+ /* -- Deprecated / unsed options (below)-- */
+
+ /* pointcache options */
+ BLI_listbase_clear(&mmd->domain->ptcaches[1]);
+ mmd->domain->point_cache[0] = BKE_ptcache_add(&(mmd->domain->ptcaches[0]));
+ mmd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE;
+ mmd->domain->point_cache[0]->step = 1;
+ mmd->domain->point_cache[1] = NULL; /* Deprecated */
+ mmd->domain->cache_comp = SM_CACHE_LIGHT;
+ mmd->domain->cache_high_comp = SM_CACHE_LIGHT;
+
+ /* OpenVDB cache options */
+#ifdef WITH_OPENVDB_BLOSC
+ mmd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
+#else
+ mmd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
+#endif
+ mmd->domain->clipping = 1e-3f;
+ mmd->domain->data_depth = 0;
+ }
+ else if (mmd->type & MOD_FLUID_TYPE_FLOW) {
+ if (mmd->flow) {
+ BKE_fluid_modifier_freeFlow(mmd);
+ }
+
+ /* flow object data */
+ mmd->flow = MEM_callocN(sizeof(FluidFlowSettings), "MantaFlow");
+ mmd->flow->mmd = mmd;
+ mmd->flow->mesh = NULL;
+ mmd->flow->psys = NULL;
+ mmd->flow->noise_texture = NULL;
+
+ /* initial velocity */
+ mmd->flow->verts_old = NULL;
+ mmd->flow->numverts = 0;
+ mmd->flow->vel_multi = 1.0f;
+ mmd->flow->vel_normal = 0.0f;
+ mmd->flow->vel_random = 0.0f;
+ mmd->flow->vel_coord[0] = 0.0f;
+ mmd->flow->vel_coord[1] = 0.0f;
+ mmd->flow->vel_coord[2] = 0.0f;
+
+ /* emission */
+ mmd->flow->density = 1.0f;
+ mmd->flow->color[0] = 0.7f;
+ mmd->flow->color[1] = 0.7f;
+ mmd->flow->color[2] = 0.7f;
+ mmd->flow->fuel_amount = 1.0f;
+ mmd->flow->temperature = 1.0f;
+ mmd->flow->volume_density = 0.0f;
+ mmd->flow->surface_distance = 1.5f;
+ mmd->flow->particle_size = 1.0f;
+ mmd->flow->subframes = 0;
+
+ /* texture control */
+ mmd->flow->source = FLUID_FLOW_SOURCE_MESH;
+ mmd->flow->texture_size = 1.0f;
+
+ mmd->flow->type = FLUID_FLOW_TYPE_SMOKE;
+ mmd->flow->behavior = FLUID_FLOW_BEHAVIOR_GEOMETRY;
+ mmd->flow->type = FLUID_FLOW_TYPE_SMOKE;
+ mmd->flow->flags = FLUID_FLOW_ABSOLUTE | FLUID_FLOW_USE_PART_SIZE | FLUID_FLOW_USE_INFLOW;
+ }
+ else if (mmd->type & MOD_FLUID_TYPE_EFFEC) {
+ if (mmd->effector) {
+ BKE_fluid_modifier_freeEffector(mmd);
+ }
+
+ /* effector object data */
+ mmd->effector = MEM_callocN(sizeof(FluidEffectorSettings), "MantaEffector");
+ mmd->effector->mmd = mmd;
+ mmd->effector->mesh = NULL;
+ mmd->effector->verts_old = NULL;
+ mmd->effector->numverts = 0;
+ mmd->effector->surface_distance = 0.0f;
+ mmd->effector->type = FLUID_EFFECTOR_TYPE_COLLISION;
+ mmd->effector->flags = 0;
+
+ /* guide options */
+ mmd->effector->guide_mode = FLUID_EFFECTOR_GUIDE_MAX;
+ mmd->effector->vel_multi = 1.0f;
+ }
+}
+
+void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd,
+ struct FluidModifierData *tmmd,
+ const int flag)
+{
+ tmmd->type = mmd->type;
+ tmmd->time = mmd->time;
+
+ BKE_fluid_modifier_create_type_data(tmmd);
+
+ if (tmmd->domain) {
+ FluidDomainSettings *tmds = tmmd->domain;
+ FluidDomainSettings *mds = mmd->domain;
+
+ /* domain object data */
+ tmds->fluid_group = mds->fluid_group;
+ tmds->force_group = mds->force_group;
+ tmds->effector_group = mds->effector_group;
+ if (tmds->effector_weights) {
+ MEM_freeN(tmds->effector_weights);
+ }
+ tmds->effector_weights = MEM_dupallocN(mds->effector_weights);
+
+ /* adaptive domain options */
+ tmds->adapt_margin = mds->adapt_margin;
+ tmds->adapt_res = mds->adapt_res;
+ tmds->adapt_threshold = mds->adapt_threshold;
+
+ /* fluid domain options */
+ tmds->maxres = mds->maxres;
+ tmds->solver_res = mds->solver_res;
+ tmds->border_collisions = mds->border_collisions;
+ tmds->flags = mds->flags;
+ tmds->gravity[0] = mds->gravity[0];
+ tmds->gravity[1] = mds->gravity[1];
+ tmds->gravity[2] = mds->gravity[2];
+ tmds->active_fields = mds->active_fields;
+ tmds->type = mds->type;
+ tmds->boundary_width = mds->boundary_width;
+
+ /* smoke domain options */
+ tmds->alpha = mds->alpha;
+ tmds->beta = mds->beta;
+ tmds->diss_speed = mds->diss_speed;
+ tmds->vorticity = mds->vorticity;
+ tmds->highres_sampling = mds->highres_sampling;
+
+ /* flame options */
+ tmds->burning_rate = mds->burning_rate;
+ tmds->flame_smoke = mds->flame_smoke;
+ tmds->flame_vorticity = mds->flame_vorticity;
+ tmds->flame_ignition = mds->flame_ignition;
+ tmds->flame_max_temp = mds->flame_max_temp;
+ copy_v3_v3(tmds->flame_smoke_color, mds->flame_smoke_color);
+
+ /* noise options */
+ tmds->noise_strength = mds->noise_strength;
+ tmds->noise_pos_scale = mds->noise_pos_scale;
+ tmds->noise_time_anim = mds->noise_time_anim;
+ tmds->noise_scale = mds->noise_scale;
+ tmds->noise_type = mds->noise_type;
+
+ /* liquid domain options */
+ tmds->flip_ratio = mds->flip_ratio;
+ tmds->particle_randomness = mds->particle_randomness;
+ tmds->particle_number = mds->particle_number;
+ tmds->particle_minimum = mds->particle_minimum;
+ tmds->particle_maximum = mds->particle_maximum;
+ tmds->particle_radius = mds->particle_radius;
+ tmds->particle_band_width = mds->particle_band_width;
+ tmds->fractions_threshold = mds->fractions_threshold;
+
+ /* diffusion options*/
+ tmds->surface_tension = mds->surface_tension;
+ tmds->viscosity_base = mds->viscosity_base;
+ tmds->viscosity_exponent = mds->viscosity_exponent;
+ tmds->domain_size = mds->domain_size;
+
+ /* mesh options */
+ if (mds->mesh_velocities) {
+ tmds->mesh_velocities = MEM_dupallocN(mds->mesh_velocities);
+ }
+ tmds->mesh_concave_upper = mds->mesh_concave_upper;
+ tmds->mesh_concave_lower = mds->mesh_concave_lower;
+ tmds->mesh_particle_radius = mds->mesh_particle_radius;
+ tmds->mesh_smoothen_pos = mds->mesh_smoothen_pos;
+ tmds->mesh_smoothen_neg = mds->mesh_smoothen_neg;
+ tmds->mesh_scale = mds->mesh_scale;
+ tmds->totvert = mds->totvert;
+ tmds->mesh_generator = mds->mesh_generator;
+
+ /* secondary particle options */
+ tmds->sndparticle_k_b = mds->sndparticle_k_b;
+ tmds->sndparticle_k_d = mds->sndparticle_k_d;
+ tmds->sndparticle_k_ta = mds->sndparticle_k_ta;
+ tmds->sndparticle_k_wc = mds->sndparticle_k_wc;
+ tmds->sndparticle_l_max = mds->sndparticle_l_max;
+ tmds->sndparticle_l_min = mds->sndparticle_l_min;
+ tmds->sndparticle_tau_max_k = mds->sndparticle_tau_max_k;
+ tmds->sndparticle_tau_max_ta = mds->sndparticle_tau_max_ta;
+ tmds->sndparticle_tau_max_wc = mds->sndparticle_tau_max_wc;
+ tmds->sndparticle_tau_min_k = mds->sndparticle_tau_min_k;
+ tmds->sndparticle_tau_min_ta = mds->sndparticle_tau_min_ta;
+ tmds->sndparticle_tau_min_wc = mds->sndparticle_tau_min_wc;
+ tmds->sndparticle_boundary = mds->sndparticle_boundary;
+ tmds->sndparticle_combined_export = mds->sndparticle_combined_export;
+ tmds->sndparticle_potential_radius = mds->sndparticle_potential_radius;
+ tmds->sndparticle_update_radius = mds->sndparticle_update_radius;
+ tmds->particle_type = mds->particle_type;
+ tmds->particle_scale = mds->particle_scale;
+
+ /* fluid guide options */
+ tmds->guide_parent = mds->guide_parent;
+ tmds->guide_alpha = mds->guide_alpha;
+ tmds->guide_beta = mds->guide_beta;
+ tmds->guide_vel_factor = mds->guide_vel_factor;
+ copy_v3_v3_int(tmds->guide_res, mds->guide_res);
+ tmds->guide_source = mds->guide_source;
+
+ /* cache options */
+ tmds->cache_frame_start = mds->cache_frame_start;
+ tmds->cache_frame_end = mds->cache_frame_end;
+ tmds->cache_frame_pause_data = mds->cache_frame_pause_data;
+ tmds->cache_frame_pause_noise = mds->cache_frame_pause_noise;
+ tmds->cache_frame_pause_mesh = mds->cache_frame_pause_mesh;
+ tmds->cache_frame_pause_particles = mds->cache_frame_pause_particles;
+ tmds->cache_frame_pause_guide = mds->cache_frame_pause_guide;
+ tmds->cache_flag = mds->cache_flag;
+ tmds->cache_type = mds->cache_type;
+ tmds->cache_mesh_format = mds->cache_mesh_format;
+ tmds->cache_data_format = mds->cache_data_format;
+ tmds->cache_particle_format = mds->cache_particle_format;
+ tmds->cache_noise_format = mds->cache_noise_format;
+ BLI_strncpy(tmds->cache_directory, mds->cache_directory, sizeof(tmds->cache_directory));
+
+ /* time options */
+ tmds->time_scale = mds->time_scale;
+ tmds->cfl_condition = mds->cfl_condition;
+ tmds->timesteps_minimum = mds->timesteps_minimum;
+ tmds->timesteps_maximum = mds->timesteps_maximum;
+
+ /* display options */
+ tmds->slice_method = mds->slice_method;
+ tmds->axis_slice_method = mds->axis_slice_method;
+ tmds->slice_axis = mds->slice_axis;
+ tmds->interp_method = mds->interp_method;
+ tmds->draw_velocity = mds->draw_velocity;
+ tmds->slice_per_voxel = mds->slice_per_voxel;
+ tmds->slice_depth = mds->slice_depth;
+ tmds->display_thickness = mds->display_thickness;
+ if (mds->coba) {
+ tmds->coba = MEM_dupallocN(mds->coba);
+ }
+ tmds->vector_scale = mds->vector_scale;
+ tmds->vector_draw_type = mds->vector_draw_type;
+ tmds->use_coba = mds->use_coba;
+ tmds->coba_field = mds->coba_field;
+
+ /* -- Deprecated / unsed options (below)-- */
+
+ /* pointcache options */
+ BKE_ptcache_free_list(&(tmds->ptcaches[0]));
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ /* Share the cache with the original object's modifier. */
+ tmmd->modifier.flag |= eModifierFlag_SharedCaches;
+ tmds->point_cache[0] = mds->point_cache[0];
+ tmds->ptcaches[0] = mds->ptcaches[0];
+ }
+ else {
+ tmds->point_cache[0] = BKE_ptcache_copy_list(
+ &(tmds->ptcaches[0]), &(mds->ptcaches[0]), flag);
+ }
+
+ /* OpenVDB cache options */
+ tmds->openvdb_comp = mds->openvdb_comp;
+ tmds->clipping = mds->clipping;
+ tmds->data_depth = mds->data_depth;
+ }
+ else if (tmmd->flow) {
+ FluidFlowSettings *tmfs = tmmd->flow;
+ FluidFlowSettings *mfs = mmd->flow;
+
+ tmfs->psys = mfs->psys;
+ tmfs->noise_texture = mfs->noise_texture;
+
+ /* initial velocity */
+ tmfs->vel_multi = mfs->vel_multi;
+ tmfs->vel_normal = mfs->vel_normal;
+ tmfs->vel_random = mfs->vel_random;
+ tmfs->vel_coord[0] = mfs->vel_coord[0];
+ tmfs->vel_coord[1] = mfs->vel_coord[1];
+ tmfs->vel_coord[2] = mfs->vel_coord[2];
+
+ /* emission */
+ tmfs->density = mfs->density;
+ copy_v3_v3(tmfs->color, mfs->color);
+ tmfs->fuel_amount = mfs->fuel_amount;
+ tmfs->temperature = mfs->temperature;
+ tmfs->volume_density = mfs->volume_density;
+ tmfs->surface_distance = mfs->surface_distance;
+ tmfs->particle_size = mfs->particle_size;
+ tmfs->subframes = mfs->subframes;
+
+ /* texture control */
+ tmfs->texture_size = mfs->texture_size;
+ tmfs->texture_offset = mfs->texture_offset;
+ BLI_strncpy(tmfs->uvlayer_name, mfs->uvlayer_name, sizeof(tmfs->uvlayer_name));
+ tmfs->vgroup_density = mfs->vgroup_density;
+
+ tmfs->type = mfs->type;
+ tmfs->behavior = mfs->behavior;
+ tmfs->source = mfs->source;
+ tmfs->texture_type = mfs->texture_type;
+ tmfs->flags = mfs->flags;
+ }
+ else if (tmmd->effector) {
+ FluidEffectorSettings *tmes = tmmd->effector;
+ FluidEffectorSettings *mes = mmd->effector;
+
+ tmes->surface_distance = mes->surface_distance;
+ tmes->type = mes->type;
+
+ /* guide options */
+ tmes->guide_mode = mes->guide_mode;
+ tmes->vel_multi = mes->vel_multi;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
deleted file mode 100644
index 994e00f227a..00000000000
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation
- * All rights reserved.
- */
-
-/** \file
- * \ingroup bke
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_math.h"
-
-#include "BKE_customdata.h"
-#include "BKE_fluidsim.h"
-#include "BKE_library.h"
-#include "BKE_mesh_runtime.h"
-
-/* ************************* fluidsim bobj file handling **************************** */
-
-//-------------------------------------------------------------------------------
-// file handling
-//-------------------------------------------------------------------------------
-
-void initElbeemMesh(struct Depsgraph *depsgraph,
- struct Scene *scene,
- struct Object *ob,
- int *numVertices,
- float **vertices,
- int *numTriangles,
- int **triangles,
- int useGlobalCoords,
- int modifierIndex)
-{
- Mesh *mesh;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *looptri, *lt;
- int i, mvert_num, looptri_num;
- float *verts;
- int *tris;
-
- mesh = mesh_create_eval_final_index_render(
- depsgraph, scene, ob, &CD_MASK_BAREMESH, modifierIndex);
-
- mvert = mesh->mvert;
- mloop = mesh->mloop;
- looptri = BKE_mesh_runtime_looptri_ensure(mesh);
- mvert_num = mesh->totvert;
- looptri_num = mesh->runtime.looptris.len;
-
- *numVertices = mvert_num;
- verts = MEM_mallocN(mvert_num * sizeof(float[3]), "elbeemmesh_vertices");
- for (i = 0; i < mvert_num; i++) {
- copy_v3_v3(&verts[i * 3], mvert[i].co);
- if (useGlobalCoords) {
- mul_m4_v3(ob->obmat, &verts[i * 3]);
- }
- }
- *vertices = verts;
-
- *numTriangles = looptri_num;
- tris = MEM_mallocN(looptri_num * sizeof(int[3]), "elbeemmesh_triangles");
- for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
- tris[(i * 3) + 0] = mloop[lt->tri[0]].v;
- tris[(i * 3) + 1] = mloop[lt->tri[1]].v;
- tris[(i * 3) + 2] = mloop[lt->tri[2]].v;
- }
- *triangles = tris;
-
- BKE_id_free(NULL, mesh);
-}
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index d0da5c6c0f1..4744d2cf1c0 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -34,6 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_polyfill_2d.h"
#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -2517,6 +2518,134 @@ void BKE_gpencil_stroke_2d_flat_ref(const bGPDspoint *ref_points,
*r_direction = (int)locy[2];
}
+/* calc bounding box in 2d using flat projection data */
+static void gpencil_calc_2d_bounding_box(const float (*points2d)[2],
+ int totpoints,
+ float minv[2],
+ float maxv[2])
+{
+ minv[0] = points2d[0][0];
+ minv[1] = points2d[0][1];
+ maxv[0] = points2d[0][0];
+ maxv[1] = points2d[0][1];
+
+ for (int i = 1; i < totpoints; i++) {
+ /* min */
+ if (points2d[i][0] < minv[0]) {
+ minv[0] = points2d[i][0];
+ }
+ if (points2d[i][1] < minv[1]) {
+ minv[1] = points2d[i][1];
+ }
+ /* max */
+ if (points2d[i][0] > maxv[0]) {
+ maxv[0] = points2d[i][0];
+ }
+ if (points2d[i][1] > maxv[1]) {
+ maxv[1] = points2d[i][1];
+ }
+ }
+ /* use a perfect square */
+ if (maxv[0] > maxv[1]) {
+ maxv[1] = maxv[0];
+ }
+ else {
+ maxv[0] = maxv[1];
+ }
+}
+
+/* calc texture coordinates using flat projected points */
+static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2],
+ int totpoints,
+ const float minv[2],
+ float maxv[2],
+ float (*r_uv)[2])
+{
+ float d[2];
+ d[0] = maxv[0] - minv[0];
+ d[1] = maxv[1] - minv[1];
+ for (int i = 0; i < totpoints; i++) {
+ r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0];
+ r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1];
+ }
+}
+
+/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was
+ * modified) */
+void BKE_gpencil_triangulate_stroke_fill(bGPdata *gpd, bGPDstroke *gps)
+{
+ BLI_assert(gps->totpoints >= 3);
+
+ /* allocate memory for temporary areas */
+ gps->tot_triangles = gps->totpoints - 2;
+ uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles,
+ "GP Stroke temp triangulation");
+ float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints,
+ "GP Stroke temp 2d points");
+ float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
+
+ int direction = 0;
+
+ /* convert to 2d and triangulate */
+ BKE_gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
+ BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
+
+ /* calc texture coordinates automatically */
+ float minv[2];
+ float maxv[2];
+ /* first needs bounding box data */
+ if (gpd->flag & GP_DATA_UV_ADAPTIVE) {
+ gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv);
+ }
+ else {
+ ARRAY_SET_ITEMS(minv, -1.0f, -1.0f);
+ ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f);
+ }
+
+ /* calc uv data */
+ gpencil_calc_stroke_fill_uv(points2d, gps->totpoints, minv, maxv, uv);
+
+ /* Number of triangles */
+ gps->tot_triangles = gps->totpoints - 2;
+ /* save triangulation data in stroke cache */
+ if (gps->tot_triangles > 0) {
+ if (gps->triangles == NULL) {
+ gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles,
+ "GP Stroke triangulation");
+ }
+ else {
+ gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
+ }
+
+ for (int i = 0; i < gps->tot_triangles; i++) {
+ bGPDtriangle *stroke_triangle = &gps->triangles[i];
+ memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3]));
+ /* copy texture coordinates */
+ copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]);
+ copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]);
+ copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]);
+ }
+ }
+ else {
+ /* No triangles needed - Free anything allocated previously */
+ if (gps->triangles) {
+ MEM_freeN(gps->triangles);
+ }
+
+ gps->triangles = NULL;
+ }
+
+ /* disable recalculation flag */
+ if (gps->flag & GP_STROKE_RECALC_GEOMETRY) {
+ gps->flag &= ~GP_STROKE_RECALC_GEOMETRY;
+ }
+
+ /* clear memory */
+ MEM_SAFE_FREE(tmp_triangles);
+ MEM_SAFE_FREE(points2d);
+ MEM_SAFE_FREE(uv);
+}
+
float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
{
if (!gps->points || gps->totpoints < 2) {
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 4c81bd4b019..6d6e5166e1c 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -87,6 +87,7 @@
#include "RE_pipeline.h"
#include "GPU_draw.h"
+#include "GPU_texture.h"
#include "BLI_sys_types.h" // for intptr_t support
@@ -111,9 +112,9 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat
/* max int, to indicate we don't store sequences in ibuf */
#define IMA_NO_INDEX 0x7FEFEFEF
-/* quick lookup: supports 1 million frames, thousand passes */
-#define IMA_MAKE_INDEX(frame, index) (((frame) << 10) + (index))
-#define IMA_INDEX_FRAME(index) ((index) >> 10)
+/* quick lookup: supports 1 million entries, thousand passes */
+#define IMA_MAKE_INDEX(entry, index) (((entry) << 10) + (index))
+#define IMA_INDEX_ENTRY(index) ((index) >> 10)
#if 0
# define IMA_INDEX_PASS(index) (index & ~1023)
#endif
@@ -142,7 +143,7 @@ static void imagecache_keydata(void *userkey, int *framenr, int *proxy, int *ren
{
ImageCacheKey *key = userkey;
- *framenr = IMA_INDEX_FRAME(key->index);
+ *framenr = IMA_INDEX_ENTRY(key->index);
*proxy = IMB_PROXY_NONE;
*render_flags = 0;
}
@@ -165,6 +166,17 @@ static void imagecache_put(Image *image, int index, ImBuf *ibuf)
IMB_moviecache_put(image->cache, &key, ibuf);
}
+static void imagecache_remove(Image *image, int index)
+{
+ if (image->cache == NULL) {
+ return;
+ }
+
+ ImageCacheKey key;
+ key.index = index;
+ IMB_moviecache_remove(image->cache, &key);
+}
+
static struct ImBuf *imagecache_get(Image *image, int index)
{
if (image->cache) {
@@ -257,7 +269,9 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
GPU_free_image(ima);
}
- ima->ok = IMA_OK;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ tile->ok = IMA_OK;
+ }
if (do_lock) {
BLI_mutex_unlock(image_mutex);
@@ -290,6 +304,8 @@ void BKE_image_free(Image *ima)
BKE_icon_id_delete(&ima->id);
BKE_previewimg_free(&ima->preview);
+
+ BLI_freelistN(&ima->tiles);
}
/* only image block itself */
@@ -299,8 +315,6 @@ static void image_init(Image *ima, short source, short type)
MEMCPY_STRUCT_AFTER(ima, DNA_struct_default_get(Image), id);
- ima->ok = IMA_OK;
-
ima->source = source;
ima->type = type;
@@ -308,6 +322,11 @@ static void image_init(Image *ima, short source, short type)
ima->flag |= IMA_VIEW_AS_RENDER;
}
+ ImageTile *tile = MEM_callocN(sizeof(ImageTile), "Image Tiles");
+ tile->ok = IMA_OK;
+ tile->tile_number = 1001;
+ BLI_addtail(&ima->tiles, tile);
+
if (type == IMA_TYPE_R_RESULT) {
for (int i = 0; i < 8; i++) {
BKE_image_add_renderslot(ima, NULL);
@@ -337,34 +356,42 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ
return ima;
}
-/* Get the ibuf from an image cache by it's index and frame.
+/* Get the ibuf from an image cache by it's index and entry.
* Local use here only.
*
* Returns referenced image buffer if it exists, callee is to
* call IMB_freeImBuf to de-reference the image buffer after
* it's done handling it.
*/
-static ImBuf *image_get_cached_ibuf_for_index_frame(Image *ima, int index, int frame)
+static ImBuf *image_get_cached_ibuf_for_index_entry(Image *ima, int index, int entry)
{
if (index != IMA_NO_INDEX) {
- index = IMA_MAKE_INDEX(frame, index);
+ index = IMA_MAKE_INDEX(entry, index);
}
return imagecache_get(ima, index);
}
/* no ima->ibuf anymore, but listbase */
-static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame)
+static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int entry)
{
if (ibuf) {
if (index != IMA_NO_INDEX) {
- index = IMA_MAKE_INDEX(frame, index);
+ index = IMA_MAKE_INDEX(entry, index);
}
imagecache_put(ima, index, ibuf);
}
}
+static void image_remove_ibuf(Image *ima, int index, int entry)
+{
+ if (index != IMA_NO_INDEX) {
+ index = IMA_MAKE_INDEX(entry, index);
+ }
+ imagecache_remove(ima, index);
+}
+
static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
{
const ImagePackedFile *imapf_src;
@@ -413,8 +440,11 @@ void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_s
BLI_listbase_clear(&ima_dst->anims);
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- ima_dst->gputexture[i] = NULL;
+ BLI_duplicatelist(&ima_dst->tiles, &ima_src->tiles);
+ LISTBASE_FOREACH (ImageTile *, tile, &ima_dst->tiles) {
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ tile->gputexture[i] = NULL;
+ }
}
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
@@ -480,14 +510,82 @@ bool BKE_image_scale(Image *image, int width, int height)
bool BKE_image_has_opengl_texture(Image *ima)
{
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i]) {
- return true;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ if (tile->gputexture[i] != NULL) {
+ return true;
+ }
}
}
return false;
}
+ImageTile *BKE_image_get_tile(Image *ima, int tile_number)
+{
+ if (ima == NULL) {
+ return NULL;
+ }
+
+ /* Verify valid tile range. */
+ if ((tile_number != 0) && (tile_number < 1001 || tile_number > IMA_UDIM_MAX)) {
+ return NULL;
+ }
+
+ /* Tile number 0 is a special case and refers to the first tile, typically
+ * coming from non-UDIM-aware code. */
+ if (tile_number == 0 || tile_number == 1001) {
+ return ima->tiles.first;
+ }
+
+ if (ima->source != IMA_SRC_TILED) {
+ return NULL;
+ }
+
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ if (tile->tile_number == tile_number) {
+ return tile;
+ }
+ }
+
+ return NULL;
+}
+
+ImageTile *BKE_image_get_tile_from_iuser(Image *ima, ImageUser *iuser)
+{
+ return BKE_image_get_tile(ima, (iuser && iuser->tile) ? iuser->tile : 1001);
+}
+
+int BKE_image_get_tile_from_pos(struct Image *ima,
+ const float uv[2],
+ float new_uv[2],
+ float ofs[2])
+{
+ float local_ofs[2];
+ if (ofs == NULL) {
+ ofs = local_ofs;
+ }
+
+ copy_v2_v2(new_uv, uv);
+ zero_v2(ofs);
+
+ if ((ima->source != IMA_SRC_TILED) || uv[0] < 0.0f || uv[1] < 0.0f || uv[0] >= 10.0f) {
+ return 0;
+ }
+
+ int ix = (int)uv[0];
+ int iy = (int)uv[1];
+ int tile_number = 1001 + 10 * iy + ix;
+
+ if (BKE_image_get_tile(ima, tile_number) == NULL) {
+ return 0;
+ }
+ ofs[0] = ix;
+ ofs[1] = iy;
+ sub_v2_v2(new_uv, ofs);
+
+ return tile_number;
+}
+
static void image_init_color_management(Image *ima)
{
ImBuf *ibuf;
@@ -580,8 +678,10 @@ Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exist
if (BLI_path_cmp(strtest, str) == 0) {
if ((BKE_image_has_anim(ima) == false) || (ima->id.us == 0)) {
id_us_plus(&ima->id); /* officially should not, it doesn't link here! */
- if (ima->ok == 0) {
- ima->ok = IMA_OK;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ if (tile->ok == 0) {
+ tile->ok = IMA_OK;
+ }
}
if (r_exists) {
*r_exists = true;
@@ -690,10 +790,17 @@ Image *BKE_image_add_generated(Main *bmain,
short gen_type,
const float color[4],
const bool stereo3d,
- const bool is_data)
+ const bool is_data,
+ const bool tiled)
{
/* on save, type is changed to FILE in editsima.c */
- Image *ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
+ Image *ima;
+ if (tiled) {
+ ima = image_alloc(bmain, name, IMA_SRC_TILED, IMA_TYPE_IMAGE);
+ }
+ else {
+ ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
+ }
if (ima == NULL) {
return NULL;
}
@@ -718,7 +825,9 @@ Image *BKE_image_add_generated(Main *bmain,
ImBuf *ibuf;
ibuf = add_ibuf_size(
width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
- image_assign_ibuf(ima, ibuf, stereo3d ? view_id : IMA_NO_INDEX, 0);
+ int index = tiled ? 0 : IMA_NO_INDEX;
+ int entry = tiled ? 1001 : 0;
+ image_assign_ibuf(ima, ibuf, stereo3d ? view_id : index, entry);
/* image_assign_ibuf puts buffer to the cache, which increments user counter. */
IMB_freeImBuf(ibuf);
@@ -729,7 +838,8 @@ Image *BKE_image_add_generated(Main *bmain,
image_add_view(ima, names[view_id], "");
}
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
return ima;
}
@@ -751,7 +861,8 @@ Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
if (ima) {
STRNCPY(ima->name, ibuf->name);
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
}
return ima;
@@ -802,7 +913,7 @@ bool BKE_image_memorypack(Image *ima)
int i;
for (i = 0, iv = ima->views.first; iv; iv = iv->next, i++) {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, i, 0);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, 0);
if (!ibuf) {
ok = false;
@@ -822,7 +933,7 @@ bool BKE_image_memorypack(Image *ima)
ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
}
else {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0);
if (ibuf) {
ok = ok && image_memorypack_imbuf(ima, ibuf, ibuf->name);
@@ -1009,7 +1120,7 @@ static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void
{
int except_frame = *(int *)userdata;
return (ibuf->userflags & IB_BITMAPDIRTY) == 0 && (ibuf->index != IMA_NO_INDEX) &&
- (except_frame != IMA_INDEX_FRAME(ibuf->index));
+ (except_frame != IMA_INDEX_ENTRY(ibuf->index));
}
/* except_frame is weak, only works for seqs without offset... */
@@ -3162,7 +3273,7 @@ static void image_tag_reload(Image *ima, ID *iuser_id, ImageUser *iuser, void *c
void BKE_imageuser_default(ImageUser *iuser)
{
memset(iuser, 0, sizeof(ImageUser));
- iuser->ok = true;
+ iuser->ok = 1;
iuser->frames = 100;
iuser->sfra = 1;
}
@@ -3179,6 +3290,26 @@ void BKE_image_init_imageuser(Image *ima, ImageUser *iuser)
}
}
+static void image_free_tile(Image *ima, ImageTile *tile)
+{
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ if (tile->gputexture[i] != NULL) {
+ GPU_texture_free(tile->gputexture[i]);
+ tile->gputexture[i] = NULL;
+ }
+ }
+
+ if (BKE_image_is_multiview(ima)) {
+ const int totviews = BLI_listbase_count(&ima->views);
+ for (int i = 0; i < totviews; i++) {
+ image_remove_ibuf(ima, i, tile->tile_number);
+ }
+ }
+ else {
+ image_remove_ibuf(ima, 0, tile->tile_number);
+ }
+}
+
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
{
if (ima == NULL) {
@@ -3207,7 +3338,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
if (ima->source == IMA_SRC_GENERATED) {
if (ima->gen_x == 0 || ima->gen_y == 0) {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0);
if (ibuf) {
ima->gen_x = ibuf->x;
ima->gen_y = ibuf->y;
@@ -3225,6 +3356,17 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
ima->name[0] = '\0';
}
+ if (ima->source != IMA_SRC_TILED) {
+ /* Free all but the first tile. */
+ ImageTile *base_tile = BKE_image_get_tile(ima, 0);
+ for (ImageTile *tile = base_tile->next; tile; tile = tile->next) {
+ image_free_tile(ima, tile);
+ MEM_freeN(tile);
+ }
+ base_tile->next = NULL;
+ ima->tiles.last = base_tile;
+ }
+
/* image buffers for non-sequence multilayer will share buffers with RenderResult,
* however sequence multilayer will own buffers. Such logic makes switching from
* single multilayer file to sequence completely unstable
@@ -3234,7 +3376,10 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
*/
BKE_image_free_buffers(ima);
- ima->ok = 1;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ tile->ok = 1;
+ }
+
if (iuser) {
image_tag_frame_recalc(ima, NULL, iuser, ima);
}
@@ -3283,7 +3428,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
case IMA_SIGNAL_USER_NEW_IMAGE:
if (iuser) {
iuser->ok = 1;
- if (ima->source == IMA_SRC_FILE || ima->source == IMA_SRC_SEQUENCE) {
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
if (ima->type == IMA_TYPE_MULTILAYER) {
BKE_image_init_imageuser(ima, iuser);
}
@@ -3293,7 +3438,9 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
case IMA_SIGNAL_COLORMANAGE:
BKE_image_free_buffers(ima);
- ima->ok = 1;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ tile->ok = 1;
+ }
if (iuser) {
iuser->ok = 1;
@@ -3360,6 +3507,107 @@ static RenderPass *image_render_pass_get(RenderLayer *rl,
return rpass_ret;
}
+void BKE_image_get_tile_label(Image *ima, ImageTile *tile, char *label, int len_label)
+{
+ label[0] = '\0';
+ if (ima == NULL || tile == NULL) {
+ return;
+ }
+
+ if (tile->label[0]) {
+ BLI_strncpy(label, tile->label, len_label);
+ }
+ else {
+ BLI_snprintf(label, len_label, "%d", tile->tile_number);
+ }
+}
+
+ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label)
+{
+ if (ima->source != IMA_SRC_TILED) {
+ return NULL;
+ }
+
+ if (tile_number < 1001 || tile_number > IMA_UDIM_MAX) {
+ return NULL;
+ }
+
+ /* Search the first tile that has a higher number.
+ * We then insert before that to keep the list sorted. */
+ ImageTile *next_tile;
+ for (next_tile = ima->tiles.first; next_tile; next_tile = next_tile->next) {
+ if (next_tile->tile_number == tile_number) {
+ /* Tile already exists. */
+ return NULL;
+ }
+ if (next_tile->tile_number > tile_number) {
+ break;
+ }
+ }
+
+ ImageTile *tile = MEM_callocN(sizeof(ImageTile), "image new tile");
+ tile->ok = 1;
+ tile->tile_number = tile_number;
+
+ if (next_tile) {
+ BLI_insertlinkbefore(&ima->tiles, next_tile, tile);
+ }
+ else {
+ BLI_addtail(&ima->tiles, tile);
+ }
+
+ if (label) {
+ BLI_strncpy(tile->label, label, sizeof(tile->label));
+ }
+
+ return tile;
+}
+
+bool BKE_image_remove_tile(struct Image *ima, ImageTile *tile)
+{
+ if (ima == NULL || tile == NULL || ima->source != IMA_SRC_TILED) {
+ return false;
+ }
+
+ if (tile == ima->tiles.first) {
+ /* Can't remove first tile. */
+ return false;
+ }
+
+ image_free_tile(ima, tile);
+ BLI_remlink(&ima->tiles, tile);
+ MEM_freeN(tile);
+
+ return true;
+}
+
+bool BKE_image_fill_tile(struct Image *ima,
+ ImageTile *tile,
+ int width,
+ int height,
+ const float color[4],
+ int gen_type,
+ int planes,
+ bool is_float)
+{
+ if (ima == NULL || tile == NULL || ima->source != IMA_SRC_TILED) {
+ return false;
+ }
+
+ image_free_tile(ima, tile);
+
+ ImBuf *tile_ibuf = add_ibuf_size(
+ width, height, ima->name, planes, is_float, gen_type, color, &ima->colorspace_settings);
+
+ if (tile_ibuf != NULL) {
+ image_assign_ibuf(ima, tile_ibuf, 0, tile->tile_number);
+ BKE_image_release_ibuf(ima, tile_ibuf, NULL);
+ tile->ok = 1;
+ return true;
+ }
+ return false;
+}
+
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesn't use the index! */
/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
@@ -3421,7 +3669,7 @@ void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
bool BKE_image_is_multilayer(Image *ima)
{
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
if (ima->type == IMA_TYPE_MULTILAYER) {
return true;
}
@@ -3512,7 +3760,7 @@ void BKE_image_release_renderresult(Scene *scene, Image *ima)
bool BKE_image_is_openexr(struct Image *ima)
{
#ifdef WITH_OPENEXR
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
return BLI_path_extension_check(ima->name, ".exr");
}
#else
@@ -3617,7 +3865,7 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
#endif /* WITH_OPENEXR */
/* common stuff to do with images after loading */
-static void image_initialize_after_load(Image *ima, ImBuf *UNUSED(ibuf))
+static void image_initialize_after_load(Image *ima, ImageUser *iuser, ImBuf *UNUSED(ibuf))
{
/* Preview is NULL when it has never been used as an icon before.
* Never handle previews/icons outside of main thread. */
@@ -3628,7 +3876,8 @@ static void image_initialize_after_load(Image *ima, ImBuf *UNUSED(ibuf))
/* timer */
BKE_image_tag_time(ima);
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+ tile->ok = IMA_OK_LOADED;
}
static int imbuf_alpha_flags_for_image(Image *ima)
@@ -3712,19 +3961,25 @@ static ImBuf *load_sequence_single(
}
}
else {
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, iuser, ibuf);
*r_assign = true;
}
#else
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, iuser, ibuf);
*r_assign = true;
#endif
}
+ else {
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+ if (tile != NULL) {
+ tile->ok = 0;
+ }
+ }
return ibuf;
}
-static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
+static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry, int frame)
{
struct ImBuf *ibuf = NULL;
const bool is_multiview = BKE_image_is_multiview(ima);
@@ -3734,7 +3989,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
if (!is_multiview) {
ibuf = load_sequence_single(ima, iuser, frame, 0, &assign);
if (assign) {
- image_assign_ibuf(ima, ibuf, 0, frame);
+ image_assign_ibuf(ima, ibuf, 0, entry);
}
}
else {
@@ -3757,7 +4012,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
if (assign) {
for (i = 0; i < totviews; i++) {
- image_assign_ibuf(ima, ibuf_arr[i], i, frame);
+ image_assign_ibuf(ima, ibuf_arr[i], i, entry);
}
}
@@ -3775,9 +4030,10 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
return ibuf;
}
-static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int frame)
+static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int entry, int frame)
{
struct ImBuf *ibuf = NULL;
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
/* either we load from RenderResult, or we have to load a new one */
@@ -3793,7 +4049,7 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f
ima->rr = NULL;
}
- ibuf = image_load_sequence_file(ima, iuser, frame);
+ ibuf = image_load_sequence_file(ima, iuser, entry, frame);
if (ibuf) { /* actually an error */
ima->type = IMA_TYPE_IMAGE;
@@ -3814,17 +4070,17 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f
BKE_imbuf_stamp_info(ima->rr, ibuf);
- image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : 0, frame);
+ image_initialize_after_load(ima, iuser, ibuf);
+ image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : 0, entry);
}
// else printf("pass not found\n");
}
else {
- ima->ok = 0;
+ tile->ok = 0;
}
if (iuser) {
- iuser->ok = ima->ok;
+ iuser->ok = tile->ok;
}
return ibuf;
@@ -3837,6 +4093,8 @@ static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const i
ia = BLI_findlink(&ima->anims, view_id);
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+
if (ia->anim == NULL) {
char str[FILE_MAX];
int flags = IB_rect;
@@ -3876,14 +4134,14 @@ static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const i
ibuf = IMB_makeSingleUser(IMB_anim_absolute(ia->anim, fra, IMB_TC_RECORD_RUN, IMB_PROXY_NONE));
if (ibuf) {
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, iuser, ibuf);
}
else {
- ima->ok = 0;
+ tile->ok = 0;
}
}
else {
- ima->ok = 0;
+ tile->ok = 0;
}
return ibuf;
@@ -3894,6 +4152,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
struct ImBuf *ibuf = NULL;
const bool is_multiview = BKE_image_is_multiview(ima);
const int totfiles = image_num_files(ima);
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
int i;
if (totfiles != BLI_listbase_count_at_most(&ima->anims, totfiles + 1)) {
@@ -3929,7 +4188,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
image_assign_ibuf(ima, ibuf_arr[i], i, frame);
}
else {
- ima->ok = 0;
+ tile->ok = 0;
}
}
@@ -3948,7 +4207,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
}
if (iuser) {
- iuser->ok = ima->ok;
+ iuser->ok = tile->ok;
}
return ibuf;
@@ -4020,7 +4279,7 @@ static ImBuf *load_image_single(Image *ima,
else
#endif
{
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, iuser, ibuf);
*r_assign = true;
/* make packed file for autopack */
@@ -4035,7 +4294,8 @@ static ImBuf *load_image_single(Image *ima,
}
}
else {
- ima->ok = 0;
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+ tile->ok = 0;
}
return ibuf;
@@ -4109,7 +4369,8 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
}
if (iuser) {
- iuser->ok = ima->ok;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ iuser->ok = tile->ok;
}
return ibuf;
@@ -4132,7 +4393,7 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
if (rpass) {
ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0);
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, iuser, ibuf);
ibuf->rect_float = rpass->rect;
ibuf->flags |= IB_rectfloat;
@@ -4144,11 +4405,12 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
}
}
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
if (ibuf == NULL) {
- ima->ok = 0;
+ tile->ok = 0;
}
if (iuser) {
- iuser->ok = ima->ok;
+ iuser->ok = tile->ok;
}
return ibuf;
@@ -4268,7 +4530,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
}
}
- ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0);
/* make ibuf if needed, and initialize it */
if (ibuf == NULL) {
@@ -4345,7 +4607,8 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
ibuf->dither = dither;
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
return ibuf;
}
@@ -4355,7 +4618,7 @@ static int image_get_multiview_index(Image *ima, ImageUser *iuser)
const bool is_multilayer = BKE_image_is_multilayer(ima);
const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) &&
(iuser == NULL);
- int index = BKE_image_is_animated(ima) ? 0 : IMA_NO_INDEX;
+ int index = BKE_image_has_multiple_ibufs(ima) ? 0 : IMA_NO_INDEX;
if (is_multilayer) {
return iuser ? iuser->multi_index : index;
@@ -4373,7 +4636,7 @@ static int image_get_multiview_index(Image *ima, ImageUser *iuser)
return index;
}
-static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
+static void image_get_entry_and_index(Image *ima, ImageUser *iuser, int *r_entry, int *r_index)
{
int frame = 0, index = image_get_multiview_index(ima, iuser);
@@ -4389,8 +4652,11 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
frame = iuser ? iuser->framenr : ima->lastframe;
}
}
+ else if (ima->source == IMA_SRC_TILED) {
+ frame = (iuser && iuser->tile) ? iuser->tile : 1001;
+ }
- *r_frame = frame;
+ *r_entry = frame;
*r_index = index;
}
@@ -4400,58 +4666,75 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
* call IMB_freeImBuf to de-reference the image buffer after
* it's done handling it.
*/
-static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
+static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry, int *r_index)
{
ImBuf *ibuf = NULL;
- int frame = 0, index = image_get_multiview_index(ima, iuser);
+ int entry = 0, index = image_get_multiview_index(ima, iuser);
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
- ima->lastframe = frame;
+ entry = iuser ? iuser->framenr : ima->lastframe;
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
+ ima->lastframe = entry;
}
else if (ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_IMAGE) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
- ima->lastframe = frame;
+ entry = iuser ? iuser->framenr : ima->lastframe;
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
+ ima->lastframe = entry;
/* counter the fact that image is set as invalid when loading a frame
* that is not in the cache (through image_acquire_ibuf for instance),
* yet we have valid frames in the cache loaded */
if (ibuf) {
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
if (iuser) {
- iuser->ok = ima->ok;
+ iuser->ok = tile->ok;
}
}
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
+ entry = iuser ? iuser->framenr : ima->lastframe;
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
}
}
else if (ima->source == IMA_SRC_FILE) {
if (ima->type == IMA_TYPE_IMAGE) {
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0);
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0);
}
}
else if (ima->source == IMA_SRC_GENERATED) {
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0);
}
else if (ima->source == IMA_SRC_VIEWER) {
/* always verify entirely, not that this shouldn't happen
* as part of texture sampling in rendering anyway, so not
* a big bottleneck */
}
+ else if (ima->source == IMA_SRC_TILED) {
+ if (ELEM(ima->type, IMA_TYPE_IMAGE, IMA_TYPE_MULTILAYER)) {
+ entry = (iuser && iuser->tile) ? iuser->tile : 1001;
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
+
+ if ((ima->type == IMA_TYPE_IMAGE) && ibuf != NULL) {
+ ImageTile *tile = BKE_image_get_tile(ima, entry);
+ tile->ok = IMA_OK_LOADED;
+
+ /* iuser->ok is useless for tiled images because iuser->tile changes all the time. */
+ if (iuser != NULL) {
+ iuser->ok = 1;
+ }
+ }
+ }
+ }
- if (r_frame) {
- *r_frame = frame;
+ if (r_entry) {
+ *r_entry = entry;
}
if (r_index) {
@@ -4467,12 +4750,17 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
return false;
}
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+
if (iuser) {
if (iuser->ok == 0) {
return false;
}
}
- else if (ima->ok == 0) {
+ else if (tile == NULL) {
+ return false;
+ }
+ else if (tile->ok == 0) {
return false;
}
@@ -4486,7 +4774,7 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
ImBuf *ibuf = NULL;
- int frame = 0, index = 0;
+ int entry = 0, index = 0;
if (r_lock) {
*r_lock = NULL;
@@ -4497,29 +4785,40 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
return NULL;
}
- ibuf = image_get_cached_ibuf(ima, iuser, &frame, &index);
+ ibuf = image_get_cached_ibuf(ima, iuser, &entry, &index);
if (ibuf == NULL) {
/* we are sure we have to load the ibuf, using source and type */
if (ima->source == IMA_SRC_MOVIE) {
/* source is from single file, use flipbook to store ibuf */
- ibuf = image_load_movie_file(ima, iuser, frame);
+ ibuf = image_load_movie_file(ima, iuser, entry);
}
else if (ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_IMAGE) {
/* regular files, ibufs in flipbook, allows saving */
- ibuf = image_load_sequence_file(ima, iuser, frame);
+ ibuf = image_load_sequence_file(ima, iuser, entry, entry);
}
/* no else; on load the ima type can change */
if (ima->type == IMA_TYPE_MULTILAYER) {
/* only 1 layer/pass stored in imbufs, no exrhandle anim storage, no saving */
- ibuf = image_load_sequence_multilayer(ima, iuser, frame);
+ ibuf = image_load_sequence_multilayer(ima, iuser, entry, entry);
+ }
+ }
+ else if (ima->source == IMA_SRC_TILED) {
+ if (ima->type == IMA_TYPE_IMAGE) {
+ /* regular files, ibufs in flipbook, allows saving */
+ ibuf = image_load_sequence_file(ima, iuser, entry, 0);
+ }
+ /* no else; on load the ima type can change */
+ if (ima->type == IMA_TYPE_MULTILAYER) {
+ /* only 1 layer/pass stored in imbufs, no exrhandle anim storage, no saving */
+ ibuf = image_load_sequence_multilayer(ima, iuser, entry, 0);
}
}
else if (ima->source == IMA_SRC_FILE) {
if (ima->type == IMA_TYPE_IMAGE) {
- ibuf = image_load_image_file(ima, iuser, frame); /* cfra only for '#', this global is OK */
+ ibuf = image_load_image_file(ima, iuser, entry); /* cfra only for '#', this global is OK */
}
/* no else; on load the ima type can change */
if (ima->type == IMA_TYPE_MULTILAYER) {
@@ -4548,7 +4847,8 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
ima->gen_color,
&ima->colorspace_settings);
image_assign_ibuf(ima, ibuf, index, 0);
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
}
else if (ima->source == IMA_SRC_VIEWER) {
if (ima->type == IMA_TYPE_R_RESULT) {
@@ -4564,14 +4864,14 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
*r_lock = ima;
/* XXX anim play for viewer nodes not yet supported */
- frame = 0; // XXX iuser ? iuser->framenr : 0;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
+ entry = 0; // XXX iuser ? iuser->framenr : 0;
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
if (!ibuf) {
/* Composite Viewer, all handled in compositor */
/* fake ibuf, will be filled in compositor */
ibuf = IMB_allocImBuf(256, 256, 32, IB_rect | IB_rectfloat);
- image_assign_ibuf(ima, ibuf, index, frame);
+ image_assign_ibuf(ima, ibuf, index, entry);
}
}
}
@@ -4655,13 +4955,13 @@ bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
/* ******** Pool for image buffers ******** */
-typedef struct ImagePoolEntry {
- struct ImagePoolEntry *next, *prev;
+typedef struct ImagePoolItem {
+ struct ImagePoolItem *next, *prev;
Image *image;
ImBuf *ibuf;
int index;
- int frame;
-} ImagePoolEntry;
+ int entry;
+} ImagePoolItem;
typedef struct ImagePool {
ListBase image_buffers;
@@ -4671,7 +4971,7 @@ typedef struct ImagePool {
ImagePool *BKE_image_pool_new(void)
{
ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool");
- pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolEntry), 0, 128, BLI_MEMPOOL_NOP);
+ pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolItem), 0, 128, BLI_MEMPOOL_NOP);
return pool;
}
@@ -4680,9 +4980,9 @@ void BKE_image_pool_free(ImagePool *pool)
{
/* Use single lock to dereference all the image buffers. */
BLI_mutex_lock(image_mutex);
- for (ImagePoolEntry *entry = pool->image_buffers.first; entry != NULL; entry = entry->next) {
- if (entry->ibuf) {
- IMB_freeImBuf(entry->ibuf);
+ for (ImagePoolItem *item = pool->image_buffers.first; item != NULL; item = item->next) {
+ if (item->ibuf != NULL) {
+ IMB_freeImBuf(item->ibuf);
}
}
BLI_mutex_unlock(image_mutex);
@@ -4691,17 +4991,17 @@ void BKE_image_pool_free(ImagePool *pool)
MEM_freeN(pool);
}
-BLI_INLINE ImBuf *image_pool_find_entry(
- ImagePool *pool, Image *image, int frame, int index, bool *found)
+BLI_INLINE ImBuf *image_pool_find_item(
+ ImagePool *pool, Image *image, int entry, int index, bool *found)
{
- ImagePoolEntry *entry;
+ ImagePoolItem *item;
*found = false;
- for (entry = pool->image_buffers.first; entry; entry = entry->next) {
- if (entry->image == image && entry->frame == frame && entry->index == index) {
+ for (item = pool->image_buffers.first; item; item = item->next) {
+ if (item->image == image && item->entry == entry && item->index == index) {
*found = true;
- return entry->ibuf;
+ return item->ibuf;
}
}
@@ -4711,7 +5011,7 @@ BLI_INLINE ImBuf *image_pool_find_entry(
ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool)
{
ImBuf *ibuf;
- int index, frame;
+ int index, entry;
bool found;
if (!image_quick_test(ima, iuser)) {
@@ -4723,32 +5023,32 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool
return BKE_image_acquire_ibuf(ima, iuser, NULL);
}
- image_get_frame_and_index(ima, iuser, &frame, &index);
+ image_get_entry_and_index(ima, iuser, &entry, &index);
- ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
+ ibuf = image_pool_find_item(pool, ima, entry, index, &found);
if (found) {
return ibuf;
}
BLI_mutex_lock(image_mutex);
- ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
+ ibuf = image_pool_find_item(pool, ima, entry, index, &found);
- /* will also create entry even in cases image buffer failed to load,
+ /* will also create item even in cases image buffer failed to load,
* prevents trying to load the same buggy file multiple times
*/
if (!found) {
- ImagePoolEntry *entry;
+ ImagePoolItem *item;
ibuf = image_acquire_ibuf(ima, iuser, NULL);
- entry = BLI_mempool_alloc(pool->memory_pool);
- entry->image = ima;
- entry->frame = frame;
- entry->index = index;
- entry->ibuf = ibuf;
+ item = BLI_mempool_alloc(pool->memory_pool);
+ item->image = ima;
+ item->entry = entry;
+ item->index = index;
+ item->ibuf = ibuf;
- BLI_addtail(&pool->image_buffers, entry);
+ BLI_addtail(&pool->image_buffers, item);
}
BLI_mutex_unlock(image_mutex);
@@ -4946,13 +5246,20 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
BLI_strncpy(filepath, ima->name, FILE_MAX);
}
- if (ima->source == IMA_SRC_SEQUENCE) {
+ if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
char head[FILE_MAX], tail[FILE_MAX];
unsigned short numlen;
- int frame = iuser ? iuser->framenr : ima->lastframe;
+
+ int index;
+ if (ima->source == IMA_SRC_SEQUENCE) {
+ index = iuser ? iuser->framenr : ima->lastframe;
+ }
+ else {
+ index = (iuser && iuser->tile) ? iuser->tile : 1001;
+ }
BLI_stringdec(filepath, head, tail, &numlen);
- BLI_stringenc(filepath, head, tail, numlen, frame);
+ BLI_stringenc(filepath, head, tail, numlen, index);
}
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
@@ -5031,15 +5338,16 @@ void BKE_image_get_aspect(Image *image, float *aspx, float *aspy)
}
}
-unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame)
+unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame, int tile)
{
- ImageUser iuser = {NULL};
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
void *lock;
ImBuf *ibuf;
unsigned char *pixels = NULL;
iuser.framenr = frame;
- iuser.ok = true;
+ iuser.tile = tile;
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
@@ -5060,15 +5368,16 @@ unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame)
return pixels;
}
-float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame)
+float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int tile)
{
- ImageUser iuser = {NULL};
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
void *lock;
ImBuf *ibuf;
float *pixels = NULL;
iuser.framenr = frame;
- iuser.ok = true;
+ iuser.tile = tile;
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
@@ -5117,6 +5426,12 @@ bool BKE_image_is_animated(Image *image)
return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE);
}
+/* Checks whether the image consists of multiple buffers. */
+bool BKE_image_has_multiple_ibufs(Image *image)
+{
+ return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED);
+}
+
/* Image modifications */
bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable)
{
@@ -5233,7 +5548,7 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
* References the result, #BKE_image_release_ibuf is to be called to de-reference.
* Use lock=NULL when calling #BKE_image_release_ibuf().
*
- * TODO(sergey): This is actually "get first entry from the cache", which is
+ * TODO(sergey): This is actually "get first item from the cache", which is
* not so much predictable. But using first loaded image buffer
* was also malicious logic and all the areas which uses this
* function are to be re-considered.
diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c
index cc621e8468c..eba6a1c9174 100644
--- a/source/blender/blenkernel/intern/image_save.c
+++ b/source/blender/blenkernel/intern/image_save.c
@@ -1,6 +1,4 @@
/*
- * ***** 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
@@ -17,13 +15,9 @@
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
- *
- * Contributor(s): Blender Foundation, 2019
- *
- * ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/blenkernel/intern/image_save.c
+/** \file
* \ingroup bke
*/
@@ -144,7 +138,7 @@ static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
* \note ``ima->name`` and ``ibuf->name`` should end up the same.
* \note for multiview the first ``ibuf`` is important to get the settings.
*/
-bool BKE_image_save(
+static bool image_save_single(
ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts)
{
void *lock;
@@ -392,3 +386,55 @@ cleanup:
return ok;
}
+
+bool BKE_image_save(
+ ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts)
+{
+ ImageUser save_iuser;
+ BKE_imageuser_default(&save_iuser);
+
+ if (ima->source == IMA_SRC_TILED) {
+ /* Verify filepath for tiles images. */
+ if (BLI_stringdec(opts->filepath, NULL, NULL, NULL) != 1001) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "When saving a tiled image, the path '%s' must contain the UDIM tag 1001",
+ opts->filepath);
+ return false;
+ }
+
+ /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
+ if (iuser == NULL) {
+ iuser = &save_iuser;
+ }
+ }
+
+ /* Save image - or, for tiled images, the first tile. */
+ bool ok = image_save_single(reports, bmain, ima, iuser, opts);
+
+ if (ok && ima->source == IMA_SRC_TILED) {
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, opts->filepath, sizeof(filepath));
+
+ char head[FILE_MAX], tail[FILE_MAX];
+ unsigned short numlen;
+ BLI_stringdec(filepath, head, tail, &numlen);
+
+ /* Save all other tiles. */
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ /* Tile 1001 was already saved before the loop. */
+ if (tile->tile_number == 1001 || !ok) {
+ continue;
+ }
+
+ /* Build filepath of the tile. */
+ BLI_stringenc(opts->filepath, head, tail, numlen, tile->tile_number);
+
+ iuser->tile = tile->tile_number;
+ ok = ok && image_save_single(reports, bmain, ima, iuser, opts);
+ }
+ BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath));
+ }
+
+ return ok;
+}
diff --git a/source/blender/blenkernel/intern/kelvinlet.c b/source/blender/blenkernel/intern/kelvinlet.c
new file mode 100644
index 00000000000..a7b48107873
--- /dev/null
+++ b/source/blender/blenkernel/intern/kelvinlet.c
@@ -0,0 +1,215 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_kelvinlet.h"
+
+/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
+ * Pixar Technical Memo #17-03 */
+
+void BKE_kelvinlet_init_params(
+ KelvinletParams *params, float radius, float force, float shear_modulus, float poisson_ratio)
+{
+ params->a = 1.0f / (4.0f * (float)M_PI * shear_modulus);
+ params->b = params->a / (4.0f * (1.0f - poisson_ratio));
+ params->c = 2 * (3.0f * params->a - 2.0f * params->b);
+
+ /* Used in scale and twist. */
+ params->f = force;
+
+ /* This can be exposed if needed */
+ const float radius_e[KELVINLET_MAX_ITERATIONS] = {1.0f, 2.0f, 2.0f};
+ params->radius_scaled[0] = radius * radius_e[0];
+ params->radius_scaled[1] = params->radius_scaled[0] * radius_e[1];
+ params->radius_scaled[2] = params->radius_scaled[1] * radius_e[2];
+}
+
+static void init_kelvinlet_grab(float radius_e[3],
+ float kelvinlet[3],
+ const float radius,
+ const KelvinletParams *params,
+ const int num_iterations)
+{
+ const float a = params->a;
+ const float b = params->b;
+ const float *radius_scaled = params->radius_scaled;
+
+ for (int i = 0; i < num_iterations; i++) {
+ radius_e[i] = sqrtf(pow2f(radius) + pow2f(params->radius_scaled[i]));
+ }
+
+ /* Regularized Kelvinlets: Formula (6) */
+ for (int i = 0; i < num_iterations; i++) {
+ kelvinlet[i] = ((a - b) / radius_e[i]) + ((b * pow2f(radius)) / pow3f(radius_e[i])) +
+ ((a * pow2f(radius_scaled[i])) / (2.0f * pow3f(radius_e[i])));
+ }
+}
+
+void BKE_kelvinlet_grab(float radius_elem_disp[3],
+ const KelvinletParams *params,
+ const float elem_orig_co[3],
+ const float brush_location[3],
+ const float brush_delta[3])
+{
+ float radius_e[3], kelvinlet[3];
+ const float c = params->c;
+ const float radius = len_v3v3(brush_location, elem_orig_co);
+
+ init_kelvinlet_grab(radius_e, kelvinlet, radius, params, 1);
+
+ const float fade = kelvinlet[0] * c;
+
+ mul_v3_v3fl(radius_elem_disp, brush_delta, fade);
+}
+
+void BKE_kelvinlet_grab_biscale(float radius_elem_disp[3],
+ const KelvinletParams *params,
+ const float elem_orig_co[3],
+ const float brush_location[3],
+ const float brush_delta[3])
+{
+ float radius_e[3], kelvinlet[3];
+ const float c = params->c;
+ const float *radius_scaled = params->radius_scaled;
+ float radius = len_v3v3(brush_location, elem_orig_co);
+
+ init_kelvinlet_grab(radius_e, kelvinlet, radius, params, 2);
+
+ const float u = kelvinlet[0] - kelvinlet[1];
+ const float fade = u * c / ((1.0f / radius_scaled[0]) - (1.0f / radius_scaled[1]));
+
+ mul_v3_v3fl(radius_elem_disp, brush_delta, fade);
+}
+
+void BKE_kelvinlet_grab_triscale(float radius_elem_disp[3],
+ const KelvinletParams *params,
+ const float elem_orig_co[3],
+ const float brush_location[3],
+ const float brush_delta[3])
+{
+ float radius_e[3], kelvinlet[3], weights[3];
+ const float c = params->c;
+ const float *radius_scaled = params->radius_scaled;
+ const float radius = len_v3v3(brush_location, elem_orig_co);
+
+ init_kelvinlet_grab(radius_e, kelvinlet, radius, params, 3);
+
+ weights[0] = 1.0f;
+ weights[1] = -((pow2f(radius_scaled[2]) - pow2f(radius_scaled[0])) /
+ (pow2f(radius_scaled[2]) - pow2f(radius_scaled[1])));
+ weights[2] = ((pow2f(radius_scaled[1]) - pow2f(radius_scaled[0])) /
+ (pow2f(radius_scaled[2]) - pow2f(radius_scaled[1])));
+
+ const float u = weights[0] * kelvinlet[0] + weights[1] * kelvinlet[1] +
+ weights[2] * kelvinlet[2];
+ const float fade = u * c /
+ (weights[0] / radius_scaled[0] + weights[1] / radius_scaled[1] +
+ weights[2] / radius_scaled[2]);
+
+ mul_v3_v3fl(radius_elem_disp, brush_delta, fade);
+}
+
+typedef void (*kelvinlet_fn)(
+ float[3], const float *, const float *, const float *, const KelvinletParams *);
+
+static void sculpt_kelvinet_integrate(kelvinlet_fn kelvinlet,
+ float r_disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ const float normal[3],
+ const KelvinletParams *p)
+{
+ float k[4][3], k_it[4][3];
+ kelvinlet(k[0], vertex_co, location, normal, p);
+ copy_v3_v3(k_it[0], k[0]);
+ mul_v3_fl(k_it[0], 0.5f);
+ add_v3_v3v3(k_it[0], vertex_co, k_it[0]);
+ kelvinlet(k[1], k_it[0], location, normal, p);
+ copy_v3_v3(k_it[1], k[1]);
+ mul_v3_fl(k_it[1], 0.5f);
+ add_v3_v3v3(k_it[1], vertex_co, k_it[1]);
+ kelvinlet(k[2], k_it[1], location, normal, p);
+ copy_v3_v3(k_it[2], k[2]);
+ add_v3_v3v3(k_it[2], vertex_co, k_it[2]);
+ sub_v3_v3v3(k_it[2], k_it[2], location);
+ kelvinlet(k[3], k_it[2], location, normal, p);
+ copy_v3_v3(r_disp, k[0]);
+ madd_v3_v3fl(r_disp, k[1], 2.0f);
+ madd_v3_v3fl(r_disp, k[2], 2.0f);
+ add_v3_v3(r_disp, k[3]);
+ mul_v3_fl(r_disp, 1.0f / 6.0f);
+}
+
+/* Regularized Kelvinlets: Formula (16) */
+static void kelvinlet_scale(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ const float UNUSED(normal[3]),
+ const KelvinletParams *p)
+{
+ float radius_vertex[3];
+ sub_v3_v3v3(radius_vertex, vertex_co, location);
+ const float radius = len_v3(radius_vertex);
+ const float radius_e = sqrtf(pow2f(radius) + pow2f(p->radius_scaled[0]));
+ const float u = (2.0f * p->b - p->a) * ((1.0f / pow3f(radius_e))) +
+ ((3.0f * pow2f(p->radius_scaled[0])) / (2.0f * pow5f(radius_e)));
+ const float fade = u * p->c;
+ mul_v3_v3fl(disp, radius_vertex, fade * p->f);
+}
+
+void BKE_kelvinlet_scale(float radius_elem_disp[3],
+ const KelvinletParams *params,
+ const float elem_orig_co[3],
+ const float brush_location[3],
+ const float surface_normal[3])
+{
+ sculpt_kelvinet_integrate(
+ kelvinlet_scale, radius_elem_disp, elem_orig_co, brush_location, surface_normal, params);
+}
+
+/* Regularized Kelvinlets: Formula (15) */
+static void kelvinlet_twist(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ const float normal[3],
+ const KelvinletParams *p)
+{
+ float radius_vertex[3], q_r[3];
+ sub_v3_v3v3(radius_vertex, vertex_co, location);
+ const float radius = len_v3(radius_vertex);
+ const float radius_e = sqrtf(pow2f(radius) + pow2f(p->radius_scaled[0]));
+ const float u = -p->a * ((1.0f / pow3f(radius_e))) +
+ ((3.0f * pow2f(p->radius_scaled[0])) / (2.0f * pow5f(radius_e)));
+ const float fade = u * p->c;
+ cross_v3_v3v3(q_r, normal, radius_vertex);
+ mul_v3_v3fl(disp, q_r, fade * p->f);
+}
+
+void BKE_kelvinlet_twist(float radius_elem_disp[3],
+ const KelvinletParams *params,
+ const float elem_orig_co[3],
+ const float brush_location[3],
+ const float surface_normal[3])
+{
+ sculpt_kelvinet_integrate(
+ kelvinlet_twist, radius_elem_disp, elem_orig_co, brush_location, surface_normal, params);
+}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index e312522b508..e051dc946cb 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -68,8 +68,10 @@
#include "DNA_world_types.h"
#include "DNA_workspace_types.h"
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_memarena.h"
@@ -1545,179 +1547,347 @@ ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *nam
return BLI_findstring(lb, name, offsetof(ID, name) + 2);
}
-void id_sort_by_name(ListBase *lb, ID *id)
+/**
+ * Sort given \a id into given \a lb list, using case-insensitive comparison of the id names.
+ *
+ * \note All other IDs beside given one are assumed already properly sorted in the list.
+ *
+ * \param id_sorting_hint Ignored if NULL. Otherwise, used to check if we can insert \a id
+ * immediately before or after that pointer. It must always be into given \a lb list.
+ */
+void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
{
+#define ID_SORT_STEP_SIZE 512
+
ID *idtest;
/* insert alphabetically */
- if (lb->first != lb->last) {
- BLI_remlink(lb, id);
+ if (lb->first == lb->last) {
+ return;
+ }
- idtest = lb->first;
- while (idtest) {
- if (BLI_strcasecmp(idtest->name, id->name) > 0 || (idtest->lib && !id->lib)) {
- BLI_insertlinkbefore(lb, idtest, id);
+ BLI_remlink(lb, id);
+
+ /* Check if we can actually insert id before or after id_sorting_hint, if given. */
+ if (id_sorting_hint != NULL && id_sorting_hint != id) {
+ BLI_assert(BLI_findindex(lb, id_sorting_hint) >= 0);
+
+ ID *id_sorting_hint_next = id_sorting_hint->next;
+ if (BLI_strcasecmp(id_sorting_hint->name, id->name) < 0 &&
+ (id_sorting_hint_next == NULL ||
+ BLI_strcasecmp(id_sorting_hint_next->name, id->name) > 0)) {
+ BLI_insertlinkafter(lb, id_sorting_hint, id);
+ return;
+ }
+
+ ID *id_sorting_hint_prev = id_sorting_hint->prev;
+ if (BLI_strcasecmp(id_sorting_hint->name, id->name) > 0 &&
+ (id_sorting_hint_prev == NULL ||
+ BLI_strcasecmp(id_sorting_hint_prev->name, id->name) < 0)) {
+ BLI_insertlinkbefore(lb, id_sorting_hint, id);
+ return;
+ }
+ }
+
+ void *item_array[ID_SORT_STEP_SIZE];
+ int item_array_index;
+
+ /* Step one: We go backward over a whole chunk of items at once, until we find a limit item
+ * that is lower than, or equal (should never happen!) to the one we want to insert. */
+ /* Note: We start from the end, because in typical 'heavy' case (insertion of lots of IDs at
+ * once using the same base name), newly inserted items will generally be towards the end
+ * (higher extension numbers). */
+ for (idtest = lb->last, item_array_index = ID_SORT_STEP_SIZE - 1; idtest != NULL;
+ idtest = idtest->prev, item_array_index--) {
+ item_array[item_array_index] = idtest;
+ if (item_array_index == 0) {
+ if ((idtest->lib == NULL && id->lib != NULL) ||
+ BLI_strcasecmp(idtest->name, id->name) <= 0) {
break;
}
- idtest = idtest->next;
+ item_array_index = ID_SORT_STEP_SIZE;
}
- /* as last */
+ }
+
+ /* Step two: we go forward in the selected chunk of items and check all of them, as we know
+ * that our target is in there. */
+
+ /* If we reached start of the list, current item_array_index is off-by-one.
+ * Otherwise, we already know that it points to an item lower-or-equal-than the one we want to
+ * insert, no need to redo the check for that one.
+ * So we can increment that index in any case. */
+ for (item_array_index++; item_array_index < ID_SORT_STEP_SIZE; item_array_index++) {
+ idtest = item_array[item_array_index];
+ if ((idtest->lib != NULL && id->lib == NULL) || BLI_strcasecmp(idtest->name, id->name) > 0) {
+ BLI_insertlinkbefore(lb, idtest, id);
+ break;
+ }
+ }
+ if (item_array_index == ID_SORT_STEP_SIZE) {
if (idtest == NULL) {
- BLI_addtail(lb, id);
+ /* If idtest is NULL here, it means that in the first loop, the last comparison was
+ * performed exactly on the first item of the list, and that it also failed. In other
+ * words, all items in the list are greater than inserted one, so we can put it at the
+ * start of the list. */
+ /* Note that BLI_insertlinkafter() would have same behavior in that case, but better be
+ * explicit here. */
+ BLI_addhead(lb, id);
+ }
+ else {
+ BLI_insertlinkafter(lb, idtest, id);
}
}
+
+#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
+
/**
- * Check to see if there is an ID with the same name as 'name'.
- * Returns the ID if so, if not, returns NULL
+ * 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 ID *is_dupid(ListBase *lb, ID *id, const char *name)
-{
- ID *idtest = NULL;
-
- for (idtest = lb->first; idtest; idtest = idtest->next) {
- /* if idtest is not a lib */
- if (id != idtest && !ID_IS_LINKED(idtest)) {
- /* do not test alphabetic! */
- /* optimized */
- if (idtest->name[2] == name[0]) {
- if (STREQ(name, idtest->name + 2)) {
- break;
- }
- }
+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_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;
}
- return idtest;
+ /* 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 created a new name (returned in name).
+ * Return true if a new name was created (returned in name).
*
- * Normally the ID that's being check 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
- * id is NULL
+ * 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_IS_LINKED(id_test)) {
+ 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;
+ }
+ }
+ }
-static bool check_for_dupid(ListBase *lb, ID *id, char *name)
-{
- ID *idtest;
- int nr = 0, a;
- size_t left_len;
-#define MAX_IN_USE 64
- bool in_use[MAX_IN_USE];
- /* to speed up finding unused numbers within [1 .. MAX_IN_USE - 1] */
-
- char left[MAX_ID_NAME + 8], leftest[MAX_ID_NAME + 8];
-
- while (true) {
-
- /* phase 1: id already exists? */
- idtest = is_dupid(lb, id, name);
+ if (is_valid) {
+ /* Only the number changed, prev_orig_base_name, prev_final_base_name and prev_id_type
+ * remain the same. */
+ prev_number++;
- /* if there is no double, done */
- if (idtest == NULL) {
- return false;
+ strcpy(name, final_name);
+ return true;
+ }
+ }
}
+ }
- /* we have a dup; need to make a new name */
- /* quick check so we can reuse one of first MAX_IN_USE - 1 ids if vacant */
- memset(in_use, false, sizeof(in_use));
-
- /* get name portion, number portion ("name.number") */
- left_len = BLI_split_name_num(left, &nr, name, '.');
+ /* 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};
- /* if new name will be too long, truncate it */
- if (nr > 999 && left_len > (MAX_ID_NAME - 8)) { /* assumption: won't go beyond 9999 */
- left[MAX_ID_NAME - 8] = '\0';
- left_len = MAX_ID_NAME - 8;
+ 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;
}
- else if (left_len > (MAX_ID_NAME - 7)) {
- left[MAX_ID_NAME - 7] = '\0';
- left_len = MAX_ID_NAME - 7;
+
+ /* 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;
}
- /* Code above may have generated invalid utf-8 string, due to raw truncation.
- * Ensure we get a valid one now! */
- left_len -= (size_t)BLI_utf8_invalid_strip(left, left_len);
-
- for (idtest = lb->first; idtest; idtest = idtest->next) {
- int nrtest;
- if ((id != idtest) && !ID_IS_LINKED(idtest) && (*name == *(idtest->name + 2)) &&
- STREQLEN(name, idtest->name + 2, left_len) &&
- (BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len)) {
- /* will get here at least once, otherwise is_dupid call above would have returned NULL */
- if (nrtest < MAX_IN_USE) {
- in_use[nrtest] = true; /* mark as used */
+ 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_IS_LINKED(id_test) && (name[0] == id_test->name[2]) &&
+ (id_test->name[base_name_len + 2] == '.' || 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;
}
- if (nr <= nrtest) {
- nr = nrtest + 1; /* track largest unused */
+ /* Keep track of first largest unused number. */
+ if (number <= number_test) {
+ *r_id_sorting_hint = id_test;
+ number = number_test + 1;
}
}
}
- /* At this point, 'nr' will typically be at least 1. (but not always) */
- // BLI_assert(nr >= 1);
- /* decide which value of nr to use */
- for (a = 0; a < MAX_IN_USE; a++) {
- if (a >= nr) {
- break; /* stop when we've checked up to biggest */ /* redundant check */
- }
- if (!in_use[a]) { /* found an unused value */
- nr = a;
- /* can only be zero if all potential duplicate names had
- * nonzero numeric suffixes, which means name itself has
- * nonzero numeric suffix (else no name conflict and wouldn't
- * have got here), which means name[left_len] is not a null */
- break;
- }
- }
- /* At this point, nr is either the lowest unused number within [0 .. MAX_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_IN_USE - 1). */
-
- /* If the original name has no numeric suffix,
- * rather than just chopping and adding numbers,
- * shave off the end chars until we have a unique name.
- * Check the null terminators match as well so we don't get Cube.000 -> Cube.00 */
- if (nr == 0 && name[left_len] == '\0') {
- size_t len;
- /* FIXME: this code will never be executed, because either nr will be
- * at least 1, or name will not end at left_len! */
- BLI_assert(0);
+ /* 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;
- len = left_len - 1;
- idtest = is_dupid(lb, id, name);
+ /* Value set previously is meaningless in that case. */
+ *r_id_sorting_hint = NULL;
- while (idtest && len > 1) {
- name[len--] = '\0';
- idtest = is_dupid(lb, id, name);
- }
- if (idtest == NULL) {
- return true;
+ 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;
}
- /* otherwise just continue and use a number suffix */
}
+ /* 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));
- if (nr > 999 && left_len > (MAX_ID_NAME - 8)) {
- /* this would overflow name buffer */
- left[MAX_ID_NAME - 8] = 0;
- /* left_len = MAX_ID_NAME - 8; */ /* for now this isn't used again */
- memcpy(name, left, sizeof(char) * (MAX_ID_NAME - 7));
continue;
}
- /* this format specifier is from hell... */
- BLI_snprintf(name, sizeof(id->name) - 2, "%s.%.3d", left, nr);
- return true;
+ /* 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_IN_USE
+#undef MAX_NUMBERS_IN_USE
}
+#undef MIN_NUMBER
+#undef MAX_NUMBER
+
/**
* Ensures given ID has a unique name in given listbase.
*
@@ -1753,7 +1923,8 @@ bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname)
BLI_utf8_invalid_strip(name, strlen(name));
}
- result = check_for_dupid(lb, id, 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
@@ -1762,11 +1933,11 @@ bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname)
* functions work, so sort every time. */
#if 0
if (result) {
- id_sort_by_name(lb, id);
+ id_sort_by_name(lb, id, id_sorting_hint);
}
#endif
- id_sort_by_name(lb, id);
+ id_sort_by_name(lb, id, id_sorting_hint);
return result;
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 73c278a0ab6..54432c8da74 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -598,6 +598,11 @@ Material *BKE_material_gpencil_get(Object *ob, short act)
}
}
+struct Material *BKE_material_gpencil_default_get(void)
+{
+ return &defgpencil_material;
+}
+
MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
{
Material *ma = give_current_material(ob, act);
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 2b3051b766a..7b655b2d8fc 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -2392,9 +2392,7 @@ static float mesh_calc_poly_volume_centroid(const MPoly *mpoly,
/* Calculate the 6x volume of the tetrahedron formed by the 3 vertices
* of the triangle and the origin as the fourth vertex */
- float v_cross[3];
- cross_v3_v3v3(v_cross, v_pivot, v_step1);
- const float tetra_volume = dot_v3v3(v_cross, v_step2);
+ const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2);
total_volume += tetra_volume;
/* Calculate the centroid of the tetrahedron formed by the 3 vertices
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index fa03aec3e08..4aa5bfa04ab 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -866,7 +866,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
tot_elem = mesh->totedge;
break;
case ME_FSEL:
- tot_elem = mesh->totface;
+ tot_elem = mesh->totpoly;
break;
}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index fd7d2fd4a03..a784be9c645 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -108,7 +108,7 @@ void BKE_modifier_init(void)
const ModifierTypeInfo *modifierType_getInfo(ModifierType type)
{
/* type unsigned, no need to check < 0 */
- if (type < NUM_MODIFIER_TYPES && modifier_types[type]->name[0] != '\0') {
+ if (type < NUM_MODIFIER_TYPES && modifier_types[type] && modifier_types[type]->name[0] != '\0') {
return modifier_types[type];
}
else {
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 09581debd99..7aa8837d139 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -1499,6 +1499,10 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
fcu->bezt->vec[1][0] = strip->start;
fcu->bezt->vec[1][1] = strip->influence;
+
+ /* Respect User Preferences for default interpolation and handles. */
+ fcu->bezt->h1 = fcu->bezt->h2 = U.keyhandles_new;
+ fcu->bezt->ipo = U.ipo_new;
}
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 779728cb037..13169d9ace8 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -1146,8 +1146,9 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree, const bNode *node_src, const int flag)
node_dst->new_node = NULL;
- bool do_copy_api = !((flag & LIB_ID_CREATE_NO_MAIN) || (flag & LIB_ID_COPY_LOCALIZE));
- if (node_dst->typeinfo->copyfunc_api && do_copy_api) {
+ /* Only call copy function when a copy is made for the main database, not
+ * for cases like the dependency graph and localization. */
+ if (node_dst->typeinfo->copyfunc_api && !(flag & LIB_ID_CREATE_NO_MAIN)) {
PointerRNA ptr;
RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr);
@@ -1594,7 +1595,7 @@ void BKE_node_tree_copy_data(Main *UNUSED(bmain),
bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user)
{
bNodeTree *ntree_copy;
- const int flag = do_id_user ? LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN : 0;
+ const int flag = do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN;
BKE_id_copy_ex(bmain, (ID *)ntree, (ID **)&ntree_copy, flag);
return ntree_copy;
}
@@ -4006,6 +4007,7 @@ static void registerShaderNodes(void)
register_node_type_sh_output_material();
register_node_type_sh_output_world();
register_node_type_sh_output_linestyle();
+ register_node_type_sh_output_aov();
register_node_type_sh_tex_image();
register_node_type_sh_tex_environment();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 08890965ece..10553e73d8d 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -39,6 +39,7 @@
#include "DNA_key_types.h"
#include "DNA_light_types.h"
#include "DNA_lattice_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_material_types.h"
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
@@ -48,7 +49,6 @@
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
-#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
@@ -123,10 +123,6 @@
#include "DRW_engine.h"
-#ifdef WITH_MOD_FLUID
-# include "LBM_fluidsim.h"
-#endif
-
#ifdef WITH_PYTHON
# include "BPY_extern.h"
#endif
@@ -1130,13 +1126,13 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const
}
}
}
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ else if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
- if (smd->type == MOD_SMOKE_TYPE_FLOW) {
- if (smd->flow) {
- if (smd->flow->psys == psys) {
- smd->flow->psys = npsys;
+ if (mmd->type == MOD_FLUID_TYPE_FLOW) {
+ if (mmd->flow) {
+ if (mmd->flow->psys == psys) {
+ mmd->flow->psys = npsys;
}
}
}
@@ -4380,10 +4376,10 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
return true;
}
}
- else if (type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ else if (type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) != 0) {
+ if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) != 0) {
return true;
}
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 5fa3352d497..d69527e8626 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -242,10 +242,10 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot++;
}
- else if (BKE_image_is_animated(ima) && verbose) {
+ else if (BKE_image_has_multiple_ibufs(ima) && verbose) {
BKE_reportf(reports,
RPT_WARNING,
- "Image '%s' skipped, movies and image sequences not supported",
+ "Image '%s' skipped, movies, image sequences and packed files not supported",
ima->id.name + 2);
}
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 46ef24be5e9..584f1ab1b0c 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -152,6 +152,9 @@ bool BKE_paint_ensure_from_paintmode(Scene *sce, ePaintMode mode)
{
ToolSettings *ts = sce->toolsettings;
Paint **paint_ptr = NULL;
+ /* Some paint modes don't store paint settings as pointer, for these this can be set and
+ * referenced by paint_ptr. */
+ Paint *paint_tmp = NULL;
switch (mode) {
case PAINT_MODE_SCULPT:
@@ -165,6 +168,8 @@ bool BKE_paint_ensure_from_paintmode(Scene *sce, ePaintMode mode)
break;
case PAINT_MODE_TEXTURE_2D:
case PAINT_MODE_TEXTURE_3D:
+ paint_tmp = (Paint *)&ts->imapaint;
+ paint_ptr = &paint_tmp;
break;
case PAINT_MODE_SCULPT_UV:
paint_ptr = (Paint **)&ts->uvsculpt;
@@ -175,7 +180,7 @@ bool BKE_paint_ensure_from_paintmode(Scene *sce, ePaintMode mode)
case PAINT_MODE_INVALID:
break;
}
- if (paint_ptr && (*paint_ptr == NULL)) {
+ if (paint_ptr) {
BKE_paint_ensure(ts, paint_ptr);
return true;
}
@@ -655,19 +660,19 @@ bool BKE_paint_select_elem_test(Object *ob)
void BKE_paint_cavity_curve_preset(Paint *p, int preset)
{
- CurveMap *cm = NULL;
+ CurveMapping *cumap = NULL;
+ CurveMap *cuma = NULL;
if (!p->cavity_curve) {
p->cavity_curve = BKE_curvemapping_add(1, 0, 0, 1, 1);
}
+ cumap = p->cavity_curve;
+ cumap->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
+ cumap->preset = preset;
- cm = p->cavity_curve->cm;
- cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
-
- p->cavity_curve->preset = preset;
- BKE_curvemap_reset(
- cm, &p->cavity_curve->clipr, p->cavity_curve->preset, CURVEMAP_SLOPE_POSITIVE);
- BKE_curvemapping_changed(p->cavity_curve, false);
+ cuma = cumap->cm;
+ BKE_curvemap_reset(cuma, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
+ BKE_curvemapping_changed(cumap, false);
}
eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
@@ -693,26 +698,36 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
/**
* Call when entering each respective paint mode.
*/
-bool BKE_paint_ensure(const ToolSettings *ts, struct Paint **r_paint)
+bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
{
Paint *paint = NULL;
if (*r_paint) {
- /* Note: 'ts->imapaint' is ignored, it's not allocated. */
- BLI_assert(ELEM(*r_paint,
- &ts->gp_paint->paint,
- &ts->sculpt->paint,
- &ts->vpaint->paint,
- &ts->wpaint->paint,
- &ts->uvsculpt->paint));
+ /* Tool offset should never be 0 for initialized paint settings, so it's a reliable way to
+ * check if already initialized. */
+ if ((*r_paint)->runtime.tool_offset == 0) {
+ /* Currently only image painting is initialized this way, others have to be allocated. */
+ BLI_assert(ELEM(*r_paint, (Paint *)&ts->imapaint));
+ BKE_paint_runtime_init(ts, *r_paint);
+ }
+ else {
+ BLI_assert(ELEM(*r_paint,
+ /* Cast is annoying, but prevent NULL-pointer access. */
+ (Paint *)ts->gp_paint,
+ (Paint *)ts->sculpt,
+ (Paint *)ts->vpaint,
+ (Paint *)ts->wpaint,
+ (Paint *)ts->uvsculpt,
+ (Paint *)&ts->imapaint));
#ifdef DEBUG
- struct Paint paint_test = **r_paint;
- BKE_paint_runtime_init(ts, *r_paint);
- /* Swap so debug doesn't hide errors when release fails. */
- SWAP(Paint, **r_paint, paint_test);
- BLI_assert(paint_test.runtime.ob_mode == (*r_paint)->runtime.ob_mode);
- BLI_assert(paint_test.runtime.tool_offset == (*r_paint)->runtime.tool_offset);
+ struct Paint paint_test = **r_paint;
+ BKE_paint_runtime_init(ts, *r_paint);
+ /* Swap so debug doesn't hide errors when release fails. */
+ SWAP(Paint, **r_paint, paint_test);
+ BLI_assert(paint_test.runtime.ob_mode == (*r_paint)->runtime.ob_mode);
+ BLI_assert(paint_test.runtime.tool_offset == (*r_paint)->runtime.tool_offset);
#endif
+ }
return true;
}
@@ -738,6 +753,9 @@ bool BKE_paint_ensure(const ToolSettings *ts, struct Paint **r_paint)
UvSculpt *data = MEM_callocN(sizeof(*data), __func__);
paint = &data->paint;
}
+ else if (*r_paint == &ts->imapaint.paint) {
+ paint = &ts->imapaint.paint;
+ }
paint->flags |= PAINT_SHOW_BRUSH;
diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c
index a252329b635..1d10db06139 100644
--- a/source/blender/blenkernel/intern/paint_toolslots.c
+++ b/source/blender/blenkernel/intern/paint_toolslots.c
@@ -94,7 +94,9 @@ void BKE_paint_toolslots_brush_update_ex(Paint *paint, Brush *brush)
BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
PaintToolSlot *tslot = &paint->tool_slots[slot_index];
id_us_plus(&brush->id);
- id_us_min(&tslot->brush->id);
+ if (tslot->brush) {
+ id_us_min(&tslot->brush->id);
+ }
tslot->brush = brush;
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 096142b9889..ded38cf562f 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -34,7 +34,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_particle_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_scene_types.h"
#include "DNA_dynamicpaint_types.h"
@@ -360,6 +360,11 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_
}
psmd = psys_get_modifier(ob, psys);
+
+ if (!psmd) {
+ return 0;
+ }
+
if (use_render_params) {
if (!(psmd->modifier.mode & eModifierMode_Render)) {
return 0;
@@ -3577,12 +3582,12 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
return;
}
- /* clear all other appearances of this pointer (like on smoke flow modifier) */
- if ((md = modifiers_findByType(ob, eModifierType_Smoke))) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type == MOD_SMOKE_TYPE_FLOW) && smd->flow && smd->flow->psys) {
- if (smd->flow->psys == psys) {
- smd->flow->psys = NULL;
+ /* clear all other appearances of this pointer (like on manta flow modifier) */
+ if ((md = modifiers_findByType(ob, eModifierType_Fluid))) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if ((mmd->type == MOD_FLUID_TYPE_FLOW) && mmd->flow && mmd->flow->psys) {
+ if (mmd->flow->psys == psys) {
+ mmd->flow->psys = NULL;
}
}
}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 5985d498606..34f2aa73817 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -85,14 +85,11 @@
#include "RE_shader_ext.h"
-/* fluid sim particle import */
-#ifdef WITH_MOD_FLUID
-# include "DNA_object_fluidsim_types.h"
-# include "LBM_fluidsim.h"
-# include <zlib.h>
-# include <string.h>
-
-#endif // WITH_MOD_FLUID
+/* FLUID sim particle import */
+#ifdef WITH_FLUID
+# include "DNA_fluid_types.h"
+# include "manta_fluid_API.h"
+#endif // WITH_FLUID
static ThreadRWMutex psys_bvhtree_rwlock = BLI_RWLOCK_INITIALIZER;
@@ -594,8 +591,6 @@ static void initialize_particle_texture(ParticleSimulationData *sim, ParticleDat
}
pa->time = 0.f;
break;
- case PART_FLUID:
- break;
}
}
@@ -4143,7 +4138,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_
}
static void particles_fluid_step(ParticleSimulationData *sim,
- int UNUSED(cfra),
+ int cfra,
const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
@@ -4153,80 +4148,237 @@ static void particles_fluid_step(ParticleSimulationData *sim,
psys->totpart = 0;
}
- /* fluid sim particle import handling, actual loading of particles from file */
-#ifdef WITH_MOD_FLUID
+#ifndef WITH_FLUID
+ UNUSED_VARS(use_render_params, cfra);
+#else
{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- sim->ob, eModifierType_Fluidsim);
+ Object *ob = sim->ob;
+ FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+
+ if (mmd && mmd->domain && mmd->domain->fluid) {
+ FluidDomainSettings *mds = mmd->domain;
- if (fluidmd && fluidmd->fss) {
- FluidsimSettings *fss = fluidmd->fss;
ParticleSettings *part = psys->part;
ParticleData *pa = NULL;
- char filename[256];
- char debugStrBuffer[256];
- int curFrame = sim->scene->r.cfra - 1; // warning - sync with derived mesh fsmesh loading
- int p, j, totpart;
- int readMask, activeParts = 0, fileParts = 0;
- gzFile gzf;
-
- // XXX if (ob==G.obedit) // off...
- // return;
-
- // ok, start loading
- BLI_join_dirfile(
- filename, sizeof(filename), fss->surfdataPath, OB_FLUIDSIM_SURF_PARTICLES_FNAME);
- BLI_path_abs(filename, modifier_path_relbase_from_global(sim->ob));
-
- BLI_path_frame(filename, curFrame, 0); // fixed #frame-no
-
- gzf = BLI_gzopen(filename, "rb");
- if (!gzf) {
+ int p, totpart, tottypepart = 0;
+ int flagActivePart, activeParts = 0;
+ float posX, posY, posZ, velX, velY, velZ;
+ float resX, resY, resZ;
+ int upres = 1;
+ char debugStrBuffer[256];
+ float tmp[3] = {0}, tmp2[3] = {0};
+
+ /* Helper variables for scaling. */
+ float min[3], max[3], size[3], cell_size_scaled[3], max_size;
+
+ /* Sanity check: parts also enabled in fluid domain? */
+ if ((part->type == PART_FLUID_FLIP &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_FLIP) == 0) ||
+ (part->type == PART_FLUID_SPRAY &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) == 0) ||
+ (part->type == PART_FLUID_BUBBLE &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) == 0) ||
+ (part->type == PART_FLUID_FOAM &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) == 0) ||
+ (part->type == PART_FLUID_TRACER &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) == 0)) {
BLI_snprintf(debugStrBuffer,
sizeof(debugStrBuffer),
- "readFsPartData::error - Unable to open file for reading '%s'\n",
- filename);
- // XXX bad level call elbeemDebugOut(debugStrBuffer);
+ "particles_fluid_step::error - found particle system that is not enabled in "
+ "fluid domain\n");
+ return;
+ }
+
+ /* Count particle amount. tottypepart is only important for snd particles. */
+ if (part->type == PART_FLUID_FLIP) {
+ tottypepart = totpart = manta_liquid_get_num_flip_particles(mds->fluid);
+ }
+ if ((part->type == PART_FLUID_SPRAY) || (part->type == PART_FLUID_BUBBLE) ||
+ (part->type == PART_FLUID_FOAM) || (part->type == PART_FLUID_TRACER)) {
+ totpart = manta_liquid_get_num_snd_particles(mds->fluid);
+
+ /* tottypepart is the amount of particles of a snd particle type. */
+ for (p = 0; p < totpart; p++) {
+ flagActivePart = manta_liquid_get_snd_particle_flag_at(mds->fluid, p);
+ if ((part->type & PART_FLUID_SPRAY) && (flagActivePart & PARTICLE_TYPE_SPRAY)) {
+ tottypepart++;
+ }
+ if ((part->type & PART_FLUID_BUBBLE) && (flagActivePart & PARTICLE_TYPE_BUBBLE)) {
+ tottypepart++;
+ }
+ if ((part->type & PART_FLUID_FOAM) && (flagActivePart & PARTICLE_TYPE_FOAM)) {
+ tottypepart++;
+ }
+ if ((part->type & PART_FLUID_TRACER) && (flagActivePart & PARTICLE_TYPE_TRACER)) {
+ tottypepart++;
+ }
+ }
+ }
+ /* Sanity check: no particles present. */
+ if (!totpart || !tottypepart) {
return;
}
- gzread(gzf, &totpart, sizeof(totpart));
- totpart = (use_render_params) ? totpart : (part->disp * totpart) / 100;
+ /* How many particles to display? */
+ tottypepart = (use_render_params) ? tottypepart : (part->disp * tottypepart) / 100;
- part->totpart = totpart;
+ part->totpart = tottypepart;
part->sta = part->end = 1.0f;
part->lifetime = sim->scene->r.efra + 1;
- /* allocate particles */
+ /* Allocate particles. */
realloc_particles(sim, part->totpart);
- // set up reading mask
- readMask = fss->typeFlags;
+ /* Set some randomness when choosing which particles to display. */
+ sim->rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed);
+ double r, dispProb = (double)part->disp / 100.0;
- for (p = 0, pa = psys->particles; p < totpart; p++, pa++) {
- int ptype = 0;
+ /* Loop over *all* particles. Will break out of loop before tottypepart amount exceeded. */
+ for (p = 0, pa = psys->particles; p < totpart; p++) {
- gzread(gzf, &ptype, sizeof(ptype));
- if (ptype & readMask) {
- activeParts++;
+ /* Apply some randomness and determine which particles to skip. */
+ r = BLI_rng_get_double(sim->rng);
+ if (r > dispProb) {
+ continue;
+ }
- gzread(gzf, &(pa->size), sizeof(float));
+ /* flag, res, upres, pos, vel for FLIP and snd particles have different getters. */
+ if (part->type == PART_FLUID_FLIP) {
+ flagActivePart = manta_liquid_get_flip_particle_flag_at(mds->fluid, p);
- pa->size /= 10.0f;
+ resX = (float)manta_get_res_x(mds->fluid);
+ resY = (float)manta_get_res_y(mds->fluid);
+ resZ = (float)manta_get_res_z(mds->fluid);
- for (j = 0; j < 3; j++) {
- float wrf;
- gzread(gzf, &wrf, sizeof(wrf));
- pa->state.co[j] = wrf;
- // fprintf(stderr,"Rj%d ",j);
- }
- for (j = 0; j < 3; j++) {
- float wrf;
- gzread(gzf, &wrf, sizeof(wrf));
- pa->state.vel[j] = wrf;
+ upres = 1;
+
+ posX = manta_liquid_get_flip_particle_position_x_at(mds->fluid, p);
+ posY = manta_liquid_get_flip_particle_position_y_at(mds->fluid, p);
+ posZ = manta_liquid_get_flip_particle_position_z_at(mds->fluid, p);
+
+ velX = manta_liquid_get_flip_particle_velocity_x_at(mds->fluid, p);
+ velY = manta_liquid_get_flip_particle_velocity_y_at(mds->fluid, p);
+ velZ = manta_liquid_get_flip_particle_velocity_z_at(mds->fluid, p);
+ }
+ else if ((part->type == PART_FLUID_SPRAY) || (part->type == PART_FLUID_BUBBLE) ||
+ (part->type == PART_FLUID_FOAM) || (part->type == PART_FLUID_TRACER)) {
+ flagActivePart = manta_liquid_get_snd_particle_flag_at(mds->fluid, p);
+
+ resX = (float)manta_liquid_get_particle_res_x(mds->fluid);
+ resY = (float)manta_liquid_get_particle_res_y(mds->fluid);
+ resZ = (float)manta_liquid_get_particle_res_z(mds->fluid);
+
+ upres = manta_liquid_get_particle_upres(mds->fluid);
+
+ posX = manta_liquid_get_snd_particle_position_x_at(mds->fluid, p);
+ posY = manta_liquid_get_snd_particle_position_y_at(mds->fluid, p);
+ posZ = manta_liquid_get_snd_particle_position_z_at(mds->fluid, p);
+
+ velX = manta_liquid_get_snd_particle_velocity_x_at(mds->fluid, p);
+ velY = manta_liquid_get_snd_particle_velocity_y_at(mds->fluid, p);
+ velZ = manta_liquid_get_snd_particle_velocity_z_at(mds->fluid, p);
+ }
+ else {
+ BLI_snprintf(debugStrBuffer,
+ sizeof(debugStrBuffer),
+ "particles_fluid_step::error - unknown particle system type\n");
+ return;
+ }
+# if 0
+ /* Debugging: Print type of particle system and current particles. */
+ printf("system type is %d and particle type is %d\n", part->type, flagActivePart);
+# endif
+
+ /* Type of particle must match current particle system type
+ * (only important for snd particles). */
+ if ((flagActivePart & PARTICLE_TYPE_SPRAY) && (part->type & PART_FLUID_SPRAY) == 0) {
+ continue;
+ }
+ if ((flagActivePart & PARTICLE_TYPE_BUBBLE) && (part->type & PART_FLUID_BUBBLE) == 0) {
+ continue;
+ }
+ if ((flagActivePart & PARTICLE_TYPE_FOAM) && (part->type & PART_FLUID_FOAM) == 0) {
+ continue;
+ }
+ if ((flagActivePart & PARTICLE_TYPE_TRACER) && (part->type & PART_FLUID_TRACER) == 0) {
+ continue;
+ }
+# if 0
+ /* Debugging: Print type of particle system and current particles. */
+ printf("system type is %d and particle type is %d\n", part->type, flagActivePart);
+# endif
+ /* Particle system has allocated 'tottypepart' particles - so break early before exceeded.
+ */
+ if (activeParts >= tottypepart) {
+ break;
+ }
+
+ /* Only show active particles, i.e. filter out dead particles that just Mantaflow needs.
+ * Mantaflow convention: PARTICLE_TYPE_DELETE == inactive particle. */
+ if ((flagActivePart & PARTICLE_TYPE_DELETE) == 0) {
+ activeParts++;
+
+ /* Use particle system settings for particle size. */
+ pa->size = part->size;
+ if (part->randsize > 0.0f) {
+ pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
}
+ /* Get size (dimension) but considering scaling */
+ copy_v3_v3(cell_size_scaled, mds->cell_size);
+ mul_v3_v3(cell_size_scaled, ob->scale);
+ madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, cell_size_scaled, mds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(max, mds->p0, cell_size_scaled, mds->res_max);
+ sub_v3_v3v3(size, max, min);
+
+ /* Biggest dimension will be used for up-scaling. */
+ max_size = MAX3(size[0] / (float)upres, size[1] / (float)upres, size[2] / (float)upres);
+
+ /* Set particle position. */
+ float posParticle[3] = {posX, posY, posZ};
+ copy_v3_v3(pa->state.co, posParticle);
+
+ /* Normalize to unit cube around 0. */
+ float resDomain[3] = {resX, resY, resZ};
+ mul_v3_fl(resDomain, 0.5f);
+ sub_v3_v3(pa->state.co, resDomain);
+ mul_v3_fl(pa->state.co, mds->dx);
+
+ /* Match domain dimension / size. */
+ float scaleAbs[3] = {
+ 1. / fabsf(ob->scale[0]), 1. / fabsf(ob->scale[1]), 1. / fabsf(ob->scale[2])};
+ mul_v3_fl(scaleAbs, max_size);
+ mul_v3_v3(pa->state.co, scaleAbs);
+ ;
+
+ /* Match domain scale. */
+ mul_m4_v3(ob->obmat, pa->state.co);
+
+ /* Add origin offset to particle position. */
+ zero_v3(tmp);
+ zero_v3(tmp2);
+ sub_v3_v3v3(tmp2, mds->p1, mds->p0);
+ mul_v3_fl(tmp2, 0.5f);
+ add_v3_v3v3(tmp, tmp, mds->p1);
+ sub_v3_v3(tmp, tmp2);
+ mul_v3_v3(tmp, ob->scale);
+ add_v3_v3(pa->state.co, tmp);
+# if 0
+ /* Debugging: Print particle coordinates. */
+ printf("pa->state.co[0]: %f, pa->state.co[1]: %f, pa->state.co[2]: %f\n",
+ pa->state.co[0], pa->state.co[1], pa->state.co[2]);
+# endif
+ /* Set particle velocity. */
+ float velParticle[3] = {velX, velY, velZ};
+ copy_v3_v3(pa->state.vel, velParticle);
+ mul_v3_fl(pa->state.vel, mds->dx);
+# if 0
+ /* Debugging: Print particle velocity. */
+ printf("pa->state.vel[0]: %f, pa->state.vel[1]: %f, pa->state.vel[2]: %f\n",
+ pa->state.vel[0], pa->state.vel[1], pa->state.vel[2]);
+# endif
+ /* Set default angular velocity and particle rotation. */
zero_v3(pa->state.ave);
unit_qt(pa->state.rot);
@@ -4234,46 +4386,23 @@ static void particles_fluid_step(ParticleSimulationData *sim,
pa->dietime = sim->scene->r.efra + 1;
pa->lifetime = sim->scene->r.efra;
pa->alive = PARS_ALIVE;
-# if 0
- if (a < 25) {
- fprintf(stderr,
- "FSPARTICLE debug set %s, a%d = %f,%f,%f, life=%f\n",
- filename,
- a,
- pa->co[0],
- pa->co[1],
- pa->co[2],
- pa->lifetime);
- }
-# endif
- }
- else {
- // skip...
- for (j = 0; j < 2 * 3 + 1; j++) {
- float wrf;
- gzread(gzf, &wrf, sizeof(wrf));
- }
+
+ /* Increasing particle settings pointer only for active particles. */
+ pa++;
}
- fileParts++;
}
- gzclose(gzf);
+# if 0
+ /* Debugging: Print number of active particles. */
+ printf("active parts: %d\n", activeParts);
+# endif
+ totpart = psys->totpart = part->totpart = activeParts;
- totpart = psys->totpart = activeParts;
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d\n",
- psys->totpart,
- activeParts,
- fileParts,
- readMask);
- // bad level call
- // XXX elbeemDebugOut(debugStrBuffer);
+ BLI_rng_free(sim->rng);
+ sim->rng = NULL;
- } // fluid sim particles done
+ } /* Fluid sim particles done. */
}
-#else
- UNUSED_VARS(use_render_params);
-#endif // WITH_MOD_FLUID
+#endif /* WITH_FLUID */
}
static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNUSED(cfra))
@@ -4289,12 +4418,16 @@ static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNU
return totpart - oldtotpart;
}
-/* Calculates the next state for all particles of the system
- * In particles code most fra-ending are frames, time-ending are fra*timestep (seconds)
+/**
+ * Calculates the next state for all particles of the system.
+ * In particles code most 'cfra - ending' are frames,
+ * 'time - ending' are 'cfra * timestep' (seconds).
+ *
* 1. Emit particles
* 2. Check cache (if used) and return if frame is cached
* 3. Do dynamics
- * 4. Save to cache */
+ * 4. Save to cache
+ */
static void system_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
@@ -4654,128 +4787,125 @@ void particle_system_update(struct Depsgraph *depsgraph,
/* setup necessary physics type dependent additional data if it doesn't yet exist */
psys_prepare_physics(&sim);
- switch (part->type) {
- case PART_HAIR: {
- /* nothing to do so bail out early */
- if (psys->totpart == 0 && part->totpart == 0) {
- psys_free_path_cache(psys, NULL);
- free_hair(ob, psys, 0);
- psys->flag |= PSYS_HAIR_DONE;
+ if (part->type == PART_HAIR) {
+ /* nothing to do so bail out early */
+ if (psys->totpart == 0 && part->totpart == 0) {
+ psys_free_path_cache(psys, NULL);
+ free_hair(ob, psys, 0);
+ psys->flag |= PSYS_HAIR_DONE;
+ }
+ /* (re-)create hair */
+ else if (hair_needs_recalc(psys)) {
+ float hcfra = 0.0f;
+ int i, recalc = psys->recalc;
+
+ free_hair(ob, psys, 0);
+
+ if (psys_orig->edit && psys_orig->free_edit) {
+ psys_orig->free_edit(psys_orig->edit);
+ psys_orig->edit = NULL;
+ psys_orig->free_edit = NULL;
}
- /* (re-)create hair */
- else if (hair_needs_recalc(psys)) {
- float hcfra = 0.0f;
- int i, recalc = psys->recalc;
- free_hair(ob, psys, 0);
+ /* first step is negative so particles get killed and reset */
+ psys->cfra = 1.0f;
- if (psys_orig->edit && psys_orig->free_edit) {
- psys_orig->free_edit(psys_orig->edit);
- psys_orig->edit = NULL;
- psys_orig->free_edit = NULL;
- }
-
- /* first step is negative so particles get killed and reset */
- psys->cfra = 1.0f;
+ ParticleSettings *part_local = part;
+ if ((part->flag & PART_HAIR_REGROW) == 0) {
+ part_local = particle_settings_localize(part);
+ psys->part = part_local;
+ }
- ParticleSettings *part_local = part;
+ for (i = 0; i <= part->hair_step; i++) {
+ hcfra = 100.0f * (float)i / (float)psys->part->hair_step;
if ((part->flag & PART_HAIR_REGROW) == 0) {
- part_local = particle_settings_localize(part);
- psys->part = part_local;
+ BKE_animsys_evaluate_animdata(
+ scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false);
}
-
- for (i = 0; i <= part->hair_step; i++) {
- hcfra = 100.0f * (float)i / (float)psys->part->hair_step;
- if ((part->flag & PART_HAIR_REGROW) == 0) {
- BKE_animsys_evaluate_animdata(
- scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false);
- }
- system_step(&sim, hcfra, use_render_params);
- psys->cfra = hcfra;
- psys->recalc = 0;
- save_hair(&sim, hcfra);
- }
-
- if (part_local != part) {
- particle_settings_free_local(part_local);
- psys->part = part;
- }
-
- psys->flag |= PSYS_HAIR_DONE;
- psys->recalc = recalc;
- }
- else if (psys->flag & PSYS_EDITED) {
- psys->flag |= PSYS_HAIR_DONE;
+ system_step(&sim, hcfra, use_render_params);
+ psys->cfra = hcfra;
+ psys->recalc = 0;
+ save_hair(&sim, hcfra);
}
- if (psys->flag & PSYS_HAIR_DONE) {
- hair_step(&sim, cfra, use_render_params);
+ if (part_local != part) {
+ particle_settings_free_local(part_local);
+ psys->part = part;
}
- break;
+
+ psys->flag |= PSYS_HAIR_DONE;
+ psys->recalc = recalc;
}
- case PART_FLUID: {
- particles_fluid_step(&sim, (int)cfra, use_render_params);
- break;
+ else if (psys->flag & PSYS_EDITED) {
+ psys->flag |= PSYS_HAIR_DONE;
}
- default: {
- switch (part->phystype) {
- case PART_PHYS_NO:
- case PART_PHYS_KEYED: {
- PARTICLE_P;
- float disp = psys_get_current_display_percentage(psys, use_render_params);
- bool free_unexisting = false;
-
- /* Particles without dynamics haven't been reset yet because they don't use pointcache */
- if (psys->recalc & ID_RECALC_PSYS_RESET) {
- psys_reset(psys, PSYS_RESET_ALL);
- }
- if (emit_particles(&sim, NULL, cfra) || (psys->recalc & ID_RECALC_PSYS_RESET)) {
- free_keyed_keys(psys);
- distribute_particles(&sim, part->from);
- initialize_all_particles(&sim);
- free_unexisting = true;
+ if (psys->flag & PSYS_HAIR_DONE) {
+ hair_step(&sim, cfra, use_render_params);
+ }
+ }
+ else if ((part->type == PART_FLUID_FLIP) || (part->type == PART_FLUID_SPRAY) ||
+ (part->type == PART_FLUID_BUBBLE) || (part->type == PART_FLUID_FOAM) ||
+ (part->type == PART_FLUID_TRACER)) {
+ particles_fluid_step(&sim, (int)cfra, use_render_params);
+ }
+ else {
+ switch (part->phystype) {
+ case PART_PHYS_NO:
+ case PART_PHYS_KEYED: {
+ PARTICLE_P;
+ float disp = psys_get_current_display_percentage(psys, use_render_params);
+ bool free_unexisting = false;
+
+ /* Particles without dynamics haven't been reset yet because they don't use pointcache */
+ if (psys->recalc & ID_RECALC_PSYS_RESET) {
+ psys_reset(psys, PSYS_RESET_ALL);
+ }
- /* flag for possible explode modifiers after this system */
- sim.psmd->flag |= eParticleSystemFlag_Pars;
- }
+ if (emit_particles(&sim, NULL, cfra) || (psys->recalc & ID_RECALC_PSYS_RESET)) {
+ free_keyed_keys(psys);
+ distribute_particles(&sim, part->from);
+ initialize_all_particles(&sim);
+ free_unexisting = true;
- LOOP_EXISTING_PARTICLES
- {
- pa->size = part->size;
- if (part->randsize > 0.0f) {
- pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
- }
-
- reset_particle(&sim, pa, 0.0, cfra);
-
- if (psys_frand(psys, p) > disp) {
- pa->flag |= PARS_NO_DISP;
- }
- else {
- pa->flag &= ~PARS_NO_DISP;
- }
- }
+ /* flag for possible explode modifiers after this system */
+ sim.psmd->flag |= eParticleSystemFlag_Pars;
+ }
- /* free unexisting after resetting particles */
- if (free_unexisting) {
- free_unexisting_particles(&sim);
+ LOOP_EXISTING_PARTICLES
+ {
+ pa->size = part->size;
+ if (part->randsize > 0.0f) {
+ pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
}
- if (part->phystype == PART_PHYS_KEYED) {
- psys_count_keyed_targets(&sim);
- set_keyed_keys(&sim);
- psys_update_path_cache(&sim, (int)cfra, use_render_params);
+ reset_particle(&sim, pa, 0.0, cfra);
+
+ if (psys_frand(psys, p) > disp) {
+ pa->flag |= PARS_NO_DISP;
+ }
+ else {
+ pa->flag &= ~PARS_NO_DISP;
}
- break;
}
- default: {
- /* the main dynamic particle system step */
- system_step(&sim, cfra, use_render_params);
- break;
+
+ /* free unexisting after resetting particles */
+ if (free_unexisting) {
+ free_unexisting_particles(&sim);
}
+
+ if (part->phystype == PART_PHYS_KEYED) {
+ psys_count_keyed_targets(&sim);
+ set_keyed_keys(&sim);
+ psys_update_path_cache(&sim, (int)cfra, use_render_params);
+ }
+ break;
+ }
+ default: {
+ /* the main dynamic particle system step */
+ system_step(&sim, cfra, use_render_params);
+ break;
}
- break;
}
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 7ae5f91c615..5e1611cb3f9 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -40,7 +40,7 @@
#include "DNA_particle_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -64,7 +64,7 @@
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
-#include "BKE_smoke.h"
+#include "BKE_fluid.h"
#include "BKE_softbody.h"
#include "BIK_api.h"
@@ -591,11 +591,11 @@ static void ptcache_cloth_error(void *cloth_v, const char *message)
/* Smoke functions */
static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
+ FluidModifierData *mmd = (FluidModifierData *)smoke_v;
+ FluidDomainSettings *mds = mmd->domain;
- if (sds->fluid) {
- return sds->base_res[0] * sds->base_res[1] * sds->base_res[2];
+ if (mds->fluid) {
+ return mds->base_res[0] * mds->base_res[1] * mds->base_res[2];
}
else {
return 0;
@@ -604,28 +604,28 @@ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
static void ptcache_smoke_error(void *smoke_v, const char *message)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- modifier_setError(&smd->modifier, "%s", message);
+ FluidModifierData *mmd = (FluidModifierData *)smoke_v;
+ modifier_setError(&mmd->modifier, "%s", message);
}
# define SMOKE_CACHE_VERSION "1.04"
static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
+ FluidModifierData *mmd = (FluidModifierData *)smoke_v;
+ FluidDomainSettings *mds = mmd->domain;
int ret = 0;
- int fluid_fields = BKE_smoke_get_data_flags(sds);
+ int fluid_fields = BKE_fluid_get_data_flags(mds);
/* version header */
ptcache_file_write(pf, SMOKE_CACHE_VERSION, 4, sizeof(char));
ptcache_file_write(pf, &fluid_fields, 1, sizeof(int));
- ptcache_file_write(pf, &sds->active_fields, 1, sizeof(int));
- ptcache_file_write(pf, &sds->res, 3, sizeof(int));
- ptcache_file_write(pf, &sds->dx, 1, sizeof(float));
+ ptcache_file_write(pf, &mds->active_fields, 1, sizeof(int));
+ ptcache_file_write(pf, &mds->res, 3, sizeof(int));
+ ptcache_file_write(pf, &mds->dx, 1, sizeof(float));
- if (sds->fluid) {
- size_t res = sds->res[0] * sds->res[1] * sds->res[2];
+ if (mds->fluid) {
+ size_t res = mds->res[0] * mds->res[1] * mds->res[2];
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
unsigned int in_len = sizeof(float) * (unsigned int)res;
@@ -633,11 +633,11 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
"pointcache_lzo_buffer");
// int mode = res >= 1000000 ? 2 : 1;
int mode = 1; // light
- if (sds->cache_comp == SM_CACHE_HEAVY) {
+ if (mds->cache_comp == SM_CACHE_HEAVY) {
mode = 2; // heavy
}
- smoke_export(sds->fluid,
+ smoke_export(mds->fluid,
&dt,
&dx,
&dens,
@@ -652,20 +652,21 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
&r,
&g,
&b,
- &obstacles);
+ &obstacles,
+ NULL);
- ptcache_file_compressed_write(pf, (unsigned char *)sds->shadow, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)mds->shadow, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len, out, mode);
- if (fluid_fields & SM_ACTIVE_HEAT) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode);
}
- if (fluid_fields & SM_ACTIVE_FIRE) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)react, in_len, out, mode);
}
- if (fluid_fields & SM_ACTIVE_COLORS) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
ptcache_file_compressed_write(pf, (unsigned char *)r, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)g, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)b, in_len, out, mode);
@@ -676,52 +677,52 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
ptcache_file_compressed_write(pf, (unsigned char *)obstacles, (unsigned int)res, out, mode);
ptcache_file_write(pf, &dt, 1, sizeof(float));
ptcache_file_write(pf, &dx, 1, sizeof(float));
- ptcache_file_write(pf, &sds->p0, 3, sizeof(float));
- ptcache_file_write(pf, &sds->p1, 3, sizeof(float));
- ptcache_file_write(pf, &sds->dp0, 3, sizeof(float));
- ptcache_file_write(pf, &sds->shift, 3, sizeof(int));
- ptcache_file_write(pf, &sds->obj_shift_f, 3, sizeof(float));
- ptcache_file_write(pf, &sds->obmat, 16, sizeof(float));
- ptcache_file_write(pf, &sds->base_res, 3, sizeof(int));
- ptcache_file_write(pf, &sds->res_min, 3, sizeof(int));
- ptcache_file_write(pf, &sds->res_max, 3, sizeof(int));
- ptcache_file_write(pf, &sds->active_color, 3, sizeof(float));
+ ptcache_file_write(pf, &mds->p0, 3, sizeof(float));
+ ptcache_file_write(pf, &mds->p1, 3, sizeof(float));
+ ptcache_file_write(pf, &mds->dp0, 3, sizeof(float));
+ ptcache_file_write(pf, &mds->shift, 3, sizeof(int));
+ ptcache_file_write(pf, &mds->obj_shift_f, 3, sizeof(float));
+ ptcache_file_write(pf, &mds->obmat, 16, sizeof(float));
+ ptcache_file_write(pf, &mds->base_res, 3, sizeof(int));
+ ptcache_file_write(pf, &mds->res_min, 3, sizeof(int));
+ ptcache_file_write(pf, &mds->res_max, 3, sizeof(int));
+ ptcache_file_write(pf, &mds->active_color, 3, sizeof(float));
MEM_freeN(out);
ret = 1;
}
- if (sds->wt) {
+ if (mds->wt) {
int res_big_array[3];
int res_big;
- int res = sds->res[0] * sds->res[1] * sds->res[2];
+ int res = mds->res[0] * mds->res[1] * mds->res[2];
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
unsigned int in_len = sizeof(float) * (unsigned int)res;
unsigned int in_len_big;
unsigned char *out;
int mode;
- smoke_turbulence_get_res(sds->wt, res_big_array);
+ smoke_turbulence_get_res(mds->wt, res_big_array);
res_big = res_big_array[0] * res_big_array[1] * res_big_array[2];
// mode = res_big >= 1000000 ? 2 : 1;
mode = 1; // light
- if (sds->cache_high_comp == SM_CACHE_HEAVY) {
+ if (mds->cache_high_comp == SM_CACHE_HEAVY) {
mode = 2; // heavy
}
in_len_big = sizeof(float) * (unsigned int)res_big;
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+ smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len_big), "pointcache_lzo_buffer");
ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len_big, out, mode);
- if (fluid_fields & SM_ACTIVE_FIRE) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)react, in_len_big, out, mode);
}
- if (fluid_fields & SM_ACTIVE_COLORS) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
ptcache_file_compressed_write(pf, (unsigned char *)r, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)g, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)b, in_len_big, out, mode);
@@ -743,24 +744,24 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
/* read old smoke cache from 2.64 */
static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
+ FluidModifierData *mmd = (FluidModifierData *)smoke_v;
+ FluidDomainSettings *mds = mmd->domain;
- if (sds->fluid) {
- const size_t res = sds->res[0] * sds->res[1] * sds->res[2];
+ if (mds->fluid) {
+ const size_t res = mds->res[0] * mds->res[1] * mds->res[2];
const unsigned int out_len = (unsigned int)res * sizeof(float);
float dt, dx, *dens, *heat, *heatold, *vx, *vy, *vz;
unsigned char *obstacles;
float *tmp_array = MEM_callocN(out_len, "Smoke old cache tmp");
- int fluid_fields = BKE_smoke_get_data_flags(sds);
+ int fluid_fields = BKE_fluid_get_data_flags(mds);
/* Part part of the new cache header */
- sds->active_color[0] = 0.7f;
- sds->active_color[1] = 0.7f;
- sds->active_color[2] = 0.7f;
+ mds->active_color[0] = 0.7f;
+ mds->active_color[1] = 0.7f;
+ mds->active_color[2] = 0.7f;
- smoke_export(sds->fluid,
+ smoke_export(mds->fluid,
&dt,
&dx,
&dens,
@@ -775,13 +776,14 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
NULL,
NULL,
NULL,
- &obstacles);
+ &obstacles,
+ NULL);
- ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)mds->shadow, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)tmp_array, out_len);
- if (fluid_fields & SM_ACTIVE_HEAT) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
ptcache_file_compressed_read(pf, (unsigned char *)heat, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)heatold, out_len);
}
@@ -801,19 +803,19 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
MEM_freeN(tmp_array);
- if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
+ if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && mds->wt) {
int res_big, res_big_array[3];
float *tcu, *tcv, *tcw;
unsigned int out_len_big;
unsigned char *tmp_array_big;
- smoke_turbulence_get_res(sds->wt, res_big_array);
+ smoke_turbulence_get_res(mds->wt, res_big_array);
res_big = res_big_array[0] * res_big_array[1] * res_big_array[2];
out_len_big = sizeof(float) * (unsigned int)res_big;
tmp_array_big = MEM_callocN(out_len_big, "Smoke old cache tmp");
smoke_turbulence_export(
- sds->wt, &dens, NULL, NULL, NULL, NULL, NULL, NULL, &tcu, &tcv, &tcw);
+ mds->wt, &dens, NULL, NULL, NULL, NULL, NULL, NULL, &tcu, &tcv, &tcw);
ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char *)tmp_array_big, out_len_big);
@@ -831,12 +833,12 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
+ FluidModifierData *mmd = (FluidModifierData *)smoke_v;
+ FluidDomainSettings *mds = mmd->domain;
char version[4];
int ch_res[3];
float ch_dx;
- int fluid_fields = BKE_smoke_get_data_flags(sds);
+ int fluid_fields = BKE_fluid_get_data_flags(mds);
int cache_fields = 0;
int active_fields = 0;
int reallocate = 0;
@@ -856,8 +858,8 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
ptcache_file_read(pf, &ch_dx, 1, sizeof(float));
/* check if resolution has changed */
- if (sds->res[0] != ch_res[0] || sds->res[1] != ch_res[1] || sds->res[2] != ch_res[2]) {
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ if (mds->res[0] != ch_res[0] || mds->res[1] != ch_res[1] || mds->res[2] != ch_res[2]) {
+ if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
reallocate = 1;
}
else {
@@ -865,29 +867,26 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
}
}
/* check if active fields have changed */
- if (fluid_fields != cache_fields || active_fields != sds->active_fields) {
+ if (fluid_fields != cache_fields || active_fields != mds->active_fields) {
reallocate = 1;
}
/* reallocate fluid if needed*/
if (reallocate) {
- sds->active_fields = active_fields | cache_fields;
- BKE_smoke_reallocate_fluid(sds, ch_dx, ch_res, 1);
- sds->dx = ch_dx;
- copy_v3_v3_int(sds->res, ch_res);
- sds->total_cells = ch_res[0] * ch_res[1] * ch_res[2];
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, ch_dx, ch_res, 1);
- }
+ mds->active_fields = active_fields | cache_fields;
+ BKE_fluid_reallocate_fluid(mds, ch_res, 1);
+ mds->dx = ch_dx;
+ copy_v3_v3_int(mds->res, ch_res);
+ mds->total_cells = ch_res[0] * ch_res[1] * ch_res[2];
}
- if (sds->fluid) {
- size_t res = sds->res[0] * sds->res[1] * sds->res[2];
+ if (mds->fluid) {
+ size_t res = mds->res[0] * mds->res[1] * mds->res[2];
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
unsigned int out_len = (unsigned int)res * sizeof(float);
- smoke_export(sds->fluid,
+ smoke_export(mds->fluid,
&dt,
&dx,
&dens,
@@ -902,20 +901,21 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
&r,
&g,
&b,
- &obstacles);
+ &obstacles,
+ NULL);
- ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)mds->shadow, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len);
- if (cache_fields & SM_ACTIVE_HEAT) {
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
ptcache_file_compressed_read(pf, (unsigned char *)heat, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)heatold, out_len);
}
- if (cache_fields & SM_ACTIVE_FIRE) {
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
ptcache_file_compressed_read(pf, (unsigned char *)flame, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)fuel, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)react, out_len);
}
- if (cache_fields & SM_ACTIVE_COLORS) {
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
ptcache_file_compressed_read(pf, (unsigned char *)r, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)g, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)b, out_len);
@@ -926,38 +926,38 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
ptcache_file_compressed_read(pf, (unsigned char *)obstacles, (unsigned int)res);
ptcache_file_read(pf, &dt, 1, sizeof(float));
ptcache_file_read(pf, &dx, 1, sizeof(float));
- ptcache_file_read(pf, &sds->p0, 3, sizeof(float));
- ptcache_file_read(pf, &sds->p1, 3, sizeof(float));
- ptcache_file_read(pf, &sds->dp0, 3, sizeof(float));
- ptcache_file_read(pf, &sds->shift, 3, sizeof(int));
- ptcache_file_read(pf, &sds->obj_shift_f, 3, sizeof(float));
- ptcache_file_read(pf, &sds->obmat, 16, sizeof(float));
- ptcache_file_read(pf, &sds->base_res, 3, sizeof(int));
- ptcache_file_read(pf, &sds->res_min, 3, sizeof(int));
- ptcache_file_read(pf, &sds->res_max, 3, sizeof(int));
- ptcache_file_read(pf, &sds->active_color, 3, sizeof(float));
- }
-
- if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
- int res = sds->res[0] * sds->res[1] * sds->res[2];
+ ptcache_file_read(pf, &mds->p0, 3, sizeof(float));
+ ptcache_file_read(pf, &mds->p1, 3, sizeof(float));
+ ptcache_file_read(pf, &mds->dp0, 3, sizeof(float));
+ ptcache_file_read(pf, &mds->shift, 3, sizeof(int));
+ ptcache_file_read(pf, &mds->obj_shift_f, 3, sizeof(float));
+ ptcache_file_read(pf, &mds->obmat, 16, sizeof(float));
+ ptcache_file_read(pf, &mds->base_res, 3, sizeof(int));
+ ptcache_file_read(pf, &mds->res_min, 3, sizeof(int));
+ ptcache_file_read(pf, &mds->res_max, 3, sizeof(int));
+ ptcache_file_read(pf, &mds->active_color, 3, sizeof(float));
+ }
+
+ if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && mds->wt) {
+ int res = mds->res[0] * mds->res[1] * mds->res[2];
int res_big, res_big_array[3];
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
unsigned int out_len = sizeof(float) * (unsigned int)res;
unsigned int out_len_big;
- smoke_turbulence_get_res(sds->wt, res_big_array);
+ smoke_turbulence_get_res(mds->wt, res_big_array);
res_big = res_big_array[0] * res_big_array[1] * res_big_array[2];
out_len_big = sizeof(float) * (unsigned int)res_big;
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+ smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len_big);
- if (cache_fields & SM_ACTIVE_FIRE) {
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
ptcache_file_compressed_read(pf, (unsigned char *)flame, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char *)fuel, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char *)react, out_len_big);
}
- if (cache_fields & SM_ACTIVE_COLORS) {
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
ptcache_file_compressed_read(pf, (unsigned char *)r, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char *)g, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char *)b, out_len_big);
@@ -984,101 +984,101 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
* with `vs` = voxel size, and `px, py, pz`,
* the min position of the domain's bounding box.
*/
-static void compute_fluid_matrices(SmokeDomainSettings *sds)
+static void compute_fluid_matrices(FluidDomainSettings *mds)
{
float bbox_min[3];
- copy_v3_v3(bbox_min, sds->p0);
+ copy_v3_v3(bbox_min, mds->p0);
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- bbox_min[0] += (sds->cell_size[0] * (float)sds->res_min[0]);
- bbox_min[1] += (sds->cell_size[1] * (float)sds->res_min[1]);
- bbox_min[2] += (sds->cell_size[2] * (float)sds->res_min[2]);
- add_v3_v3(bbox_min, sds->obj_shift_f);
+ if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
+ bbox_min[0] += (mds->cell_size[0] * (float)mds->res_min[0]);
+ bbox_min[1] += (mds->cell_size[1] * (float)mds->res_min[1]);
+ bbox_min[2] += (mds->cell_size[2] * (float)mds->res_min[2]);
+ add_v3_v3(bbox_min, mds->obj_shift_f);
}
/* construct low res matrix */
- size_to_mat4(sds->fluidmat, sds->cell_size);
- copy_v3_v3(sds->fluidmat[3], bbox_min);
+ size_to_mat4(mds->fluidmat, mds->cell_size);
+ copy_v3_v3(mds->fluidmat[3], bbox_min);
/* The smoke simulator stores voxels cell-centered, whilst VDB is node
* centered, so we offset the matrix by half a voxel to compensate. */
- madd_v3_v3fl(sds->fluidmat[3], sds->cell_size, 0.5f);
+ madd_v3_v3fl(mds->fluidmat[3], mds->cell_size, 0.5f);
- mul_m4_m4m4(sds->fluidmat, sds->obmat, sds->fluidmat);
+ mul_m4_m4m4(mds->fluidmat, mds->obmat, mds->fluidmat);
- if (sds->wt) {
+ if (mds->wt) {
float voxel_size_high[3];
/* construct high res matrix */
- mul_v3_v3fl(voxel_size_high, sds->cell_size, 1.0f / (float)(sds->amplify + 1));
- size_to_mat4(sds->fluidmat_wt, voxel_size_high);
- copy_v3_v3(sds->fluidmat_wt[3], bbox_min);
+ mul_v3_v3fl(voxel_size_high, mds->cell_size, 1.0f / (float)(mds->amplify + 1));
+ size_to_mat4(mds->fluidmat_wt, voxel_size_high);
+ copy_v3_v3(mds->fluidmat_wt[3], bbox_min);
/* Same here, add half a voxel to adjust the position of the fluid. */
- madd_v3_v3fl(sds->fluidmat_wt[3], voxel_size_high, 0.5f);
+ madd_v3_v3fl(mds->fluidmat_wt[3], voxel_size_high, 0.5f);
- mul_m4_m4m4(sds->fluidmat_wt, sds->obmat, sds->fluidmat_wt);
+ mul_m4_m4m4(mds->fluidmat_wt, mds->obmat, mds->fluidmat_wt);
}
}
static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
-
- OpenVDBWriter_set_flags(writer, sds->openvdb_comp, (sds->data_depth == 16));
-
- OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", sds->active_fields);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", sds->res);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", sds->res_min);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", sds->res_max);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", sds->base_res);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", sds->p0);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", sds->p1);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", sds->dp0);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", sds->shift);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", sds->obj_shift_f);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", sds->active_color);
- OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", sds->obmat);
-
- int fluid_fields = BKE_smoke_get_data_flags(sds);
+ FluidModifierData *mmd = (FluidModifierData *)smoke_v;
+ FluidDomainSettings *mds = mmd->domain;
+
+ OpenVDBWriter_set_flags(writer, mds->openvdb_comp, (mds->data_depth == 16));
+
+ OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", mds->active_fields);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", mds->res);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", mds->res_min);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", mds->res_max);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", mds->base_res);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", mds->p0);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", mds->p1);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", mds->dp0);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", mds->shift);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", mds->obj_shift_f);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", mds->active_color);
+ OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", mds->obmat);
+
+ int fluid_fields = BKE_fluid_get_data_flags(mds);
struct OpenVDBFloatGrid *clip_grid = NULL;
- compute_fluid_matrices(sds);
+ compute_fluid_matrices(mds);
OpenVDBWriter_add_meta_int(writer, "blender/smoke/fluid_fields", fluid_fields);
- if (sds->wt) {
+ if (mds->wt) {
struct OpenVDBFloatGrid *wt_density_grid;
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+ smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
wt_density_grid = OpenVDB_export_grid_fl(
- writer, "density", dens, sds->res_wt, sds->fluidmat_wt, sds->clipping, NULL);
+ writer, "density", dens, mds->res_wt, mds->fluidmat_wt, mds->clipping, NULL);
clip_grid = wt_density_grid;
- if (fluid_fields & SM_ACTIVE_FIRE) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
OpenVDB_export_grid_fl(
- writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ writer, "flame", flame, mds->res_wt, mds->fluidmat_wt, mds->clipping, wt_density_grid);
OpenVDB_export_grid_fl(
- writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ writer, "fuel", fuel, mds->res_wt, mds->fluidmat_wt, mds->clipping, wt_density_grid);
OpenVDB_export_grid_fl(
- writer, "react", react, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ writer, "react", react, mds->res_wt, mds->fluidmat_wt, mds->clipping, wt_density_grid);
}
- if (fluid_fields & SM_ACTIVE_COLORS) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
OpenVDB_export_grid_vec(writer,
"color",
r,
g,
b,
- sds->res_wt,
- sds->fluidmat_wt,
+ mds->res_wt,
+ mds->fluidmat_wt,
VEC_INVARIANT,
true,
- sds->clipping,
+ mds->clipping,
wt_density_grid);
}
@@ -1087,20 +1087,20 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
tcu,
tcv,
tcw,
- sds->res,
- sds->fluidmat,
+ mds->res,
+ mds->fluidmat,
VEC_INVARIANT,
false,
- sds->clipping,
+ mds->clipping,
wt_density_grid);
}
- if (sds->fluid) {
+ if (mds->fluid) {
struct OpenVDBFloatGrid *density_grid;
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
- smoke_export(sds->fluid,
+ smoke_export(mds->fluid,
&dt,
&dx,
&dens,
@@ -1115,50 +1115,51 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
&r,
&g,
&b,
- &obstacles);
+ &obstacles,
+ NULL);
OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx);
OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt);
- const char *name = (!sds->wt) ? "density" : "density_low";
+ const char *name = (!mds->wt) ? "density" : "density_low";
density_grid = OpenVDB_export_grid_fl(
- writer, name, dens, sds->res, sds->fluidmat, sds->clipping, NULL);
- clip_grid = sds->wt ? clip_grid : density_grid;
+ writer, name, dens, mds->res, mds->fluidmat, mds->clipping, NULL);
+ clip_grid = mds->wt ? clip_grid : density_grid;
OpenVDB_export_grid_fl(
- writer, "shadow", sds->shadow, sds->res, sds->fluidmat, sds->clipping, NULL);
+ writer, "shadow", mds->shadow, mds->res, mds->fluidmat, mds->clipping, NULL);
- if (fluid_fields & SM_ACTIVE_HEAT) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
OpenVDB_export_grid_fl(
- writer, "heat", heat, sds->res, sds->fluidmat, sds->clipping, clip_grid);
+ writer, "heat", heat, mds->res, mds->fluidmat, mds->clipping, clip_grid);
OpenVDB_export_grid_fl(
- writer, "heat_old", heatold, sds->res, sds->fluidmat, sds->clipping, clip_grid);
+ writer, "heat_old", heatold, mds->res, mds->fluidmat, mds->clipping, clip_grid);
}
- if (fluid_fields & SM_ACTIVE_FIRE) {
- name = (!sds->wt) ? "flame" : "flame_low";
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ name = (!mds->wt) ? "flame" : "flame_low";
OpenVDB_export_grid_fl(
- writer, name, flame, sds->res, sds->fluidmat, sds->clipping, density_grid);
- name = (!sds->wt) ? "fuel" : "fuel_low";
+ writer, name, flame, mds->res, mds->fluidmat, mds->clipping, density_grid);
+ name = (!mds->wt) ? "fuel" : "fuel_low";
OpenVDB_export_grid_fl(
- writer, name, fuel, sds->res, sds->fluidmat, sds->clipping, density_grid);
- name = (!sds->wt) ? "react" : "react_low";
+ writer, name, fuel, mds->res, mds->fluidmat, mds->clipping, density_grid);
+ name = (!mds->wt) ? "react" : "react_low";
OpenVDB_export_grid_fl(
- writer, name, react, sds->res, sds->fluidmat, sds->clipping, density_grid);
+ writer, name, react, mds->res, mds->fluidmat, mds->clipping, density_grid);
}
- if (fluid_fields & SM_ACTIVE_COLORS) {
- name = (!sds->wt) ? "color" : "color_low";
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
+ name = (!mds->wt) ? "color" : "color_low";
OpenVDB_export_grid_vec(writer,
name,
r,
g,
b,
- sds->res,
- sds->fluidmat,
+ mds->res,
+ mds->fluidmat,
VEC_INVARIANT,
true,
- sds->clipping,
+ mds->clipping,
density_grid);
}
@@ -1167,14 +1168,14 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
vx,
vy,
vz,
- sds->res,
- sds->fluidmat,
+ mds->res,
+ mds->fluidmat,
VEC_CONTRAVARIANT_RELATIVE,
false,
- sds->clipping,
+ mds->clipping,
clip_grid);
OpenVDB_export_grid_ch(
- writer, "obstacles", obstacles, sds->res, sds->fluidmat, sds->clipping, NULL);
+ writer, "obstacles", obstacles, mds->res, mds->fluidmat, mds->clipping, NULL);
}
return 1;
@@ -1182,38 +1183,38 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+ FluidModifierData *mmd = (FluidModifierData *)smoke_v;
- if (!smd) {
+ if (!mmd) {
return 0;
}
- SmokeDomainSettings *sds = smd->domain;
+ FluidDomainSettings *mds = mmd->domain;
- int fluid_fields = BKE_smoke_get_data_flags(sds);
+ int fluid_fields = BKE_fluid_get_data_flags(mds);
int active_fields, cache_fields = 0;
int cache_res[3];
float cache_dx;
bool reallocate = false;
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", sds->res_min);
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", sds->res_max);
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", sds->base_res);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", sds->p0);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", sds->p1);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", sds->dp0);
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", sds->shift);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", sds->obj_shift_f);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", sds->active_color);
- OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", sds->obmat);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", mds->res_min);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", mds->res_max);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", mds->base_res);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", mds->p0);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", mds->p1);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", mds->dp0);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", mds->shift);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", mds->obj_shift_f);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", mds->active_color);
+ OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", mds->obmat);
OpenVDBReader_get_meta_int(reader, "blender/smoke/fluid_fields", &cache_fields);
OpenVDBReader_get_meta_int(reader, "blender/smoke/active_fields", &active_fields);
OpenVDBReader_get_meta_fl(reader, "blender/smoke/dx", &cache_dx);
OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/resolution", cache_res);
/* check if resolution has changed */
- if (sds->res[0] != cache_res[0] || sds->res[1] != cache_res[1] || sds->res[2] != cache_res[2]) {
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ if (mds->res[0] != cache_res[0] || mds->res[1] != cache_res[1] || mds->res[2] != cache_res[2]) {
+ if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
reallocate = true;
}
else {
@@ -1222,28 +1223,24 @@ static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_
}
/* check if active fields have changed */
- if ((fluid_fields != cache_fields) || (active_fields != sds->active_fields)) {
+ if ((fluid_fields != cache_fields) || (active_fields != mds->active_fields)) {
reallocate = true;
}
/* reallocate fluid if needed*/
if (reallocate) {
- sds->active_fields = active_fields | cache_fields;
- BKE_smoke_reallocate_fluid(sds, cache_dx, cache_res, 1);
- sds->dx = cache_dx;
- copy_v3_v3_int(sds->res, cache_res);
- sds->total_cells = cache_res[0] * cache_res[1] * cache_res[2];
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, cache_dx, cache_res, 1);
- }
+ mds->active_fields = active_fields | cache_fields;
+ BKE_fluid_reallocate_fluid(mds, cache_dx, cache_res, 1);
+ mds->dx = cache_dx;
+ copy_v3_v3_int(mds->res, cache_res);
+ mds->total_cells = cache_res[0] * cache_res[1] * cache_res[2];
}
- if (sds->fluid) {
+ if (mds->fluid) {
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
- smoke_export(sds->fluid,
+ smoke_export(mds->fluid,
&dt,
&dx,
&dens,
@@ -1258,56 +1255,57 @@ static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_
&r,
&g,
&b,
- &obstacles);
+ &obstacles,
+ NULL);
OpenVDBReader_get_meta_fl(reader, "blender/smoke/dt", &dt);
- OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res);
+ OpenVDB_import_grid_fl(reader, "shadow", &mds->shadow, mds->res);
- const char *name = (!sds->wt) ? "density" : "density_low";
- OpenVDB_import_grid_fl(reader, name, &dens, sds->res);
+ const char *name = (!mds->wt) ? "density" : "density_low";
+ OpenVDB_import_grid_fl(reader, name, &dens, mds->res);
- if (cache_fields & SM_ACTIVE_HEAT) {
- OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res);
- OpenVDB_import_grid_fl(reader, "heat_old", &heatold, sds->res);
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
+ OpenVDB_import_grid_fl(reader, "heat", &heat, mds->res);
+ OpenVDB_import_grid_fl(reader, "heat_old", &heatold, mds->res);
}
- if (cache_fields & SM_ACTIVE_FIRE) {
- name = (!sds->wt) ? "flame" : "flame_low";
- OpenVDB_import_grid_fl(reader, name, &flame, sds->res);
- name = (!sds->wt) ? "fuel" : "fuel_low";
- OpenVDB_import_grid_fl(reader, name, &fuel, sds->res);
- name = (!sds->wt) ? "react" : "react_low";
- OpenVDB_import_grid_fl(reader, name, &react, sds->res);
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ name = (!mds->wt) ? "flame" : "flame_low";
+ OpenVDB_import_grid_fl(reader, name, &flame, mds->res);
+ name = (!mds->wt) ? "fuel" : "fuel_low";
+ OpenVDB_import_grid_fl(reader, name, &fuel, mds->res);
+ name = (!mds->wt) ? "react" : "react_low";
+ OpenVDB_import_grid_fl(reader, name, &react, mds->res);
}
- if (cache_fields & SM_ACTIVE_COLORS) {
- name = (!sds->wt) ? "color" : "color_low";
- OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res);
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
+ name = (!mds->wt) ? "color" : "color_low";
+ OpenVDB_import_grid_vec(reader, name, &r, &g, &b, mds->res);
}
- OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, sds->res);
- OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, sds->res);
+ OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, mds->res);
+ OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, mds->res);
}
- if (sds->wt) {
+ if (mds->wt) {
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+ smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
- OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt);
+ OpenVDB_import_grid_fl(reader, "density", &dens, mds->res_wt);
- if (cache_fields & SM_ACTIVE_FIRE) {
- OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt);
- OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt);
- OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt);
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ OpenVDB_import_grid_fl(reader, "flame", &flame, mds->res_wt);
+ OpenVDB_import_grid_fl(reader, "fuel", &fuel, mds->res_wt);
+ OpenVDB_import_grid_fl(reader, "react", &react, mds->res_wt);
}
- if (cache_fields & SM_ACTIVE_COLORS) {
- OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt);
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
+ OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, mds->res_wt);
}
- OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, sds->res);
+ OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, mds->res);
}
OpenVDBReader_free(reader);
@@ -1698,21 +1696,21 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl
pid->max_step = 1;
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd)
+void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *mmd)
{
- SmokeDomainSettings *sds = smd->domain;
+ FluidDomainSettings *mds = mmd->domain;
memset(pid, 0, sizeof(PTCacheID));
pid->ob = ob;
- pid->calldata = smd;
+ pid->calldata = mmd;
pid->type = PTCACHE_TYPE_SMOKE_DOMAIN;
- pid->stack_index = sds->point_cache[0]->index;
+ pid->stack_index = mds->point_cache[0]->index;
- pid->cache = sds->point_cache[0];
- pid->cache_ptr = &(sds->point_cache[0]);
- pid->ptcaches = &(sds->ptcaches[0]);
+ pid->cache = mds->point_cache[0];
+ pid->cache_ptr = &(mds->point_cache[0]);
+ pid->ptcaches = &(mds->ptcaches[0]);
pid->totpoint = pid->totwrite = ptcache_smoke_totpoint;
pid->error = ptcache_smoke_error;
@@ -1737,16 +1735,16 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo
pid->data_types = 0;
pid->info_types = 0;
- if (sds->fluid) {
+ if (mds->fluid) {
pid->data_types |= (1 << BPHYS_DATA_SMOKE_LOW);
- }
- if (sds->wt) {
- pid->data_types |= (1 << BPHYS_DATA_SMOKE_HIGH);
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ pid->data_types |= (1 << BPHYS_DATA_SMOKE_HIGH);
+ }
}
pid->default_step = 1;
pid->max_step = 1;
- pid->file_type = smd->domain->cache_file_format;
+ pid->file_type = mmd->domain->cache_file_format;
}
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface)
@@ -1908,10 +1906,10 @@ static bool foreach_object_modifier_ptcache(Object *object,
return false;
}
}
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- BKE_ptcache_id_from_smoke(&pid, object, (SmokeModifierData *)md);
+ else if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN) {
+ BKE_ptcache_id_from_smoke(&pid, object, (FluidModifierData *)md);
if (!callback(&pid, callback_user_data)) {
return false;
}
@@ -3741,10 +3739,10 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData *)md);
reset |= BKE_ptcache_id_reset(scene, &pid, mode);
}
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- BKE_ptcache_id_from_smoke(&pid, ob, (SmokeModifierData *)md);
+ if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN) {
+ BKE_ptcache_id_from_smoke(&pid, ob, (FluidModifierData *)md);
reset |= BKE_ptcache_id_reset(scene, &pid, mode);
}
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 9dcebbba56e..e57a50a8a23 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -982,14 +982,16 @@ Object *BKE_scene_camera_switch_find(Scene *scene)
return NULL;
}
- TimeMarker *m;
- int cfra = scene->r.cfra;
+ const int cfra = ((scene->r.images == scene->r.framapto) ?
+ scene->r.cfra :
+ (int)(scene->r.cfra *
+ ((float)scene->r.framapto / (float)scene->r.images)));
int frame = -(MAXFRAME + 1);
int min_frame = MAXFRAME + 1;
Object *camera = NULL;
Object *first_camera = NULL;
- for (m = scene->markers.first; m; m = m->next) {
+ for (TimeMarker *m = scene->markers.first; m; m = m->next) {
if (m->camera && (m->camera->restrictflag & OB_RESTRICT_RENDER) == 0) {
if ((m->frame <= cfra) && (m->frame > frame)) {
camera = m->camera;
@@ -1284,6 +1286,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, const ViewLayer *view_
mesh,
(&(struct BMeshToMeshParams){
.calc_object_remap = true,
+ .update_shapekey_indices = true,
}));
DEG_id_tag_update(&mesh->id, 0);
}
@@ -1352,6 +1355,19 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
if (run_callbacks) {
BKE_callback_exec_id_depsgraph(
bmain, &scene->id, depsgraph, BKE_CB_EVT_DEPSGRAPH_UPDATE_POST);
+
+ /* It is possible that the custom callback modified scene and removed some IDs from the main
+ * database. In this case DEG_ids_clear_recalc() will crash because it iterates over all IDs
+ * which depsgraph was built for.
+ *
+ * The solution is to update relations prior to this call, avoiding access to freed IDs.
+ * Should be safe because relations update is supposed to preserve flags of all IDs which are
+ * still a part of the dependency graph. If an ID is kicked out of the dependency graph it
+ * should also be fine because when/if it's added to another dependency graph it will need to
+ * be tagged for an update anyway.
+ *
+ * If there are no relations changed by the callback this call will do nothing. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
}
/* Inform editors about possible changes. */
DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
@@ -1417,6 +1433,10 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
/* Notify editors and python about recalc. */
if (pass == 0) {
BKE_callback_exec_id_depsgraph(bmain, &scene->id, depsgraph, BKE_CB_EVT_FRAME_CHANGE_POST);
+
+ /* NOTE: Similar to this case in scene_graph_update_tagged(). Need to ensure that
+ * DEG_ids_clear_recalc() doesn't access freed memory of possibly removed ID. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
}
/* Inform editors about possible changes. */
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index b99d6e1684a..b05724ca6af 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -3558,7 +3558,6 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
IB_rect,
draw_flags,
scene->r.alphamode,
- U.ogl_multisamples,
viewname,
context->gpu_offscreen,
err_out);
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index c6cac2057d6..a2699e767e9 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -794,54 +794,59 @@ static bool target_project_tri_correct(void *UNUSED(userdata),
float x_next[3])
{
/* Insignificant correction threshold */
- const float epsilon = 1e-6f;
- const float dir_epsilon = 0.05f;
+ const float epsilon = 1e-5f;
+ /* Dot product threshold for checking if step is 'clearly' pointing outside. */
+ const float dir_epsilon = 0.5f;
bool fixed = false, locked = false;
- /* Weight 0 and 1 boundary check. */
- for (int i = 0; i < 2; i++) {
- if (step[i] > x[i]) {
- if (step[i] > dir_epsilon * fabsf(step[1 - i])) {
- /* Abort if the solution is clearly outside the domain. */
- if (x[i] < epsilon) {
- return false;
- }
+ /* The barycentric coordinate domain is a triangle bounded by
+ * the X and Y axes, plus the x+y=1 diagonal. First, clamp the
+ * movement against the diagonal. Note that step is subtracted. */
+ float sum = x[0] + x[1];
+ float sstep = -(step[0] + step[1]);
- /* Scale a significant step down to arrive at the boundary. */
- mul_v3_fl(step, x[i] / step[i]);
- fixed = true;
- }
- else {
- /* Reset precision errors to stay at the boundary. */
- step[i] = x[i];
- fixed = locked = true;
- }
- }
- }
+ if (sum + sstep > 1.0f) {
+ float ldist = 1.0f - sum;
- /* Weight 2 boundary check. */
- float sum = x[0] + x[1];
- float sstep = step[0] + step[1];
+ /* If already at the boundary, slide along it. */
+ if (ldist < epsilon * (float)M_SQRT2) {
+ float step_len = len_v2(step);
- if (sum - sstep > 1.0f) {
- if (sstep < -dir_epsilon * (fabsf(step[0]) + fabsf(step[1]))) {
/* Abort if the solution is clearly outside the domain. */
- if (sum > 1.0f - epsilon) {
+ if (step_len > epsilon && sstep > step_len * dir_epsilon * (float)M_SQRT2) {
return false;
}
+ /* Project the new position onto the diagonal. */
+ add_v2_fl(step, (sum + sstep - 1.0f) * 0.5f);
+ fixed = locked = true;
+ }
+ else {
/* Scale a significant step down to arrive at the boundary. */
- mul_v3_fl(step, (1.0f - sum) / -sstep);
+ mul_v3_fl(step, ldist / sstep);
fixed = true;
}
- else {
- /* Reset precision errors to stay at the boundary. */
- if (locked) {
- step[0] = step[1] = 0.0f;
+ }
+
+ /* Weight 0 and 1 boundary checks - along axis. */
+ for (int i = 0; i < 2; i++) {
+ if (step[i] > x[i]) {
+ /* If already at the boundary, slide along it. */
+ if (x[i] < epsilon) {
+ float step_len = len_v2(step);
+
+ /* Abort if the solution is clearly outside the domain. */
+ if (step_len > epsilon && (locked || step[i] > step_len * dir_epsilon)) {
+ return false;
+ }
+
+ /* Reset precision errors to stay at the boundary. */
+ step[i] = x[i];
+ fixed = true;
}
else {
- step[0] -= 0.5f * sstep;
- step[1] = -step[0];
+ /* Scale a significant step down to arrive at the boundary. */
+ mul_v3_fl(step, x[i] / step[i]);
fixed = true;
}
}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
deleted file mode 100644
index 4c3b7a619da..00000000000
--- a/source/blender/blenkernel/intern/smoke.c
+++ /dev/null
@@ -1,3654 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup bke
- */
-
-/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
-
-#include "MEM_guardedalloc.h"
-
-#include <float.h>
-#include <math.h>
-#include <stdio.h>
-#include <string.h> /* memset */
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_kdopbvh.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_customdata_types.h"
-#include "DNA_light_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_particle_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
-
-#include "BKE_appdir.h"
-#include "BKE_animsys.h"
-#include "BKE_armature.h"
-#include "BKE_bvhutils.h"
-#include "BKE_collision.h"
-#include "BKE_colortools.h"
-#include "BKE_constraint.h"
-#include "BKE_customdata.h"
-#include "BKE_deform.h"
-#include "BKE_effect.h"
-#include "BKE_library.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_pointcache.h"
-#include "BKE_scene.h"
-#include "BKE_smoke.h"
-#include "BKE_texture.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
-
-#include "RE_shader_ext.h"
-
-#include "GPU_glew.h"
-
-/* UNUSED so far, may be enabled later */
-/* #define USE_SMOKE_COLLISION_DM */
-
-//#define DEBUG_TIME
-
-#include "smoke_API.h"
-
-#ifdef DEBUG_TIME
-# include "PIL_time.h"
-#endif
-
-#ifdef WITH_SMOKE
-# include "BLI_task.h"
-# include "BLI_kdtree.h"
-# include "BLI_voxel.h"
-
-static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
-
-struct Mesh;
-struct Object;
-struct Scene;
-struct SmokeModifierData;
-
-// timestep default value for nice appearance 0.1f
-# define DT_DEFAULT 0.1f
-
-# define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
-# define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
-# define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
-
-#else /* WITH_SMOKE */
-
-/* Stubs to use when smoke is disabled */
-struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res),
- int UNUSED(amplify),
- int UNUSED(noisetype),
- const char *UNUSED(noisefile_path),
- int UNUSED(use_fire),
- int UNUSED(use_colors))
-{
- return NULL;
-}
-
-void smoke_free(struct FLUID_3D *UNUSED(fluid))
-{
-}
-float *smoke_get_density(struct FLUID_3D *UNUSED(fluid))
-{
- return NULL;
-}
-void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt))
-{
-}
-void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength))
-{
-}
-void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid),
- float *UNUSED(alpha),
- float *UNUSED(beta),
- float *UNUSED(dt_factor),
- float *UNUSED(vorticity),
- int *UNUSED(border_colli),
- float *UNUSED(burning_rate),
- float *UNUSED(flame_smoke),
- float *UNUSED(flame_smoke_color),
- float *UNUSED(flame_vorticity),
- float *UNUSED(flame_ignition_temp),
- float *UNUSED(flame_max_temp))
-{
-}
-struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd),
- Depsgraph *UNUSED(depsgraph),
- Scene *UNUSED(scene),
- Object *UNUSED(ob),
- Mesh *UNUSED(me))
-{
- return NULL;
-}
-float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob),
- float UNUSED(position[3]),
- float UNUSED(velocity[3]))
-{
- return 0.0f;
-}
-
-#endif /* WITH_SMOKE */
-
-#ifdef WITH_SMOKE
-
-void BKE_smoke_reallocate_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
-{
- int use_heat = (sds->active_fields & SM_ACTIVE_HEAT);
- int use_fire = (sds->active_fields & SM_ACTIVE_FIRE);
- int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
-
- if (free_old && sds->fluid) {
- smoke_free(sds->fluid);
- }
- if (!min_iii(res[0], res[1], res[2])) {
- sds->fluid = NULL;
- return;
- }
- sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors);
- smoke_initBlenderRNA(sds->fluid,
- &(sds->alpha),
- &(sds->beta),
- &(sds->time_scale),
- &(sds->vorticity),
- &(sds->border_collisions),
- &(sds->burning_rate),
- &(sds->flame_smoke),
- sds->flame_smoke_color,
- &(sds->flame_vorticity),
- &(sds->flame_ignition),
- &(sds->flame_max_temp));
-
- /* reallocate shadow buffer */
- if (sds->shadow) {
- MEM_freeN(sds->shadow);
- }
- sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow");
-}
-
-void BKE_smoke_reallocate_highres_fluid(SmokeDomainSettings *sds,
- float dx,
- int res[3],
- int free_old)
-{
- int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE));
- int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
-
- if (free_old && sds->wt) {
- smoke_turbulence_free(sds->wt);
- }
- if (!min_iii(res[0], res[1], res[2])) {
- sds->wt = NULL;
- return;
- }
-
- /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */
- BLI_thread_lock(LOCK_FFTW);
-
- sds->wt = smoke_turbulence_init(
- res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors);
-
- BLI_thread_unlock(LOCK_FFTW);
-
- sds->res_wt[0] = res[0] * (sds->amplify + 1);
- sds->res_wt[1] = res[1] * (sds->amplify + 1);
- sds->res_wt[2] = res[2] * (sds->amplify + 1);
- sds->dx_wt = dx / (sds->amplify + 1);
- smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength));
-}
-
-/* convert global position to domain cell space */
-static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3])
-{
- mul_m4_v3(sds->imat, pos);
- sub_v3_v3(pos, sds->p0);
- pos[0] *= 1.0f / sds->cell_size[0];
- pos[1] *= 1.0f / sds->cell_size[1];
- pos[2] *= 1.0f / sds->cell_size[2];
-}
-
-/* set domain transformations and base resolution from object mesh */
-static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds,
- Object *ob,
- Mesh *me,
- bool init_resolution)
-{
- size_t i;
- float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- float size[3];
- MVert *verts = me->mvert;
- float scale = 0.0;
- int res;
-
- res = sds->maxres;
-
- // get BB of domain
- for (i = 0; i < me->totvert; i++) {
- // min BB
- min[0] = MIN2(min[0], verts[i].co[0]);
- min[1] = MIN2(min[1], verts[i].co[1]);
- min[2] = MIN2(min[2], verts[i].co[2]);
-
- // max BB
- max[0] = MAX2(max[0], verts[i].co[0]);
- max[1] = MAX2(max[1], verts[i].co[1]);
- max[2] = MAX2(max[2], verts[i].co[2]);
- }
-
- /* set domain bounds */
- copy_v3_v3(sds->p0, min);
- copy_v3_v3(sds->p1, max);
- sds->dx = 1.0f / res;
-
- /* calculate domain dimensions */
- sub_v3_v3v3(size, max, min);
- if (init_resolution) {
- zero_v3_int(sds->base_res);
- copy_v3_v3(sds->cell_size, size);
- }
- /* apply object scale */
- for (i = 0; i < 3; i++) {
- size[i] = fabsf(size[i] * ob->scale[i]);
- }
- copy_v3_v3(sds->global_size, size);
- copy_v3_v3(sds->dp0, min);
-
- invert_m4_m4(sds->imat, ob->obmat);
-
- // prevent crash when initializing a plane as domain
- if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) ||
- (size[2] < FLT_EPSILON)) {
- return;
- }
-
- /* define grid resolutions from longest domain side */
- if (size[0] >= MAX2(size[1], size[2])) {
- scale = res / size[0];
- sds->scale = size[0] / fabsf(ob->scale[0]);
- sds->base_res[0] = res;
- sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
- sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
- }
- else if (size[1] >= MAX2(size[0], size[2])) {
- scale = res / size[1];
- sds->scale = size[1] / fabsf(ob->scale[1]);
- sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
- sds->base_res[1] = res;
- sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
- }
- else {
- scale = res / size[2];
- sds->scale = size[2] / fabsf(ob->scale[2]);
- sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
- sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
- sds->base_res[2] = res;
- }
-
- /* set cell size */
- sds->cell_size[0] /= (float)sds->base_res[0];
- sds->cell_size[1] /= (float)sds->base_res[1];
- sds->cell_size[2] /= (float)sds->base_res[2];
-}
-
-static int smokeModifier_init(SmokeModifierData *smd, Object *ob, int scene_framenr, Mesh *me)
-{
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) {
- SmokeDomainSettings *sds = smd->domain;
- int res[3];
- /* set domain dimensions from mesh */
- smoke_set_domain_from_mesh(sds, ob, me, true);
- /* reset domain values */
- zero_v3_int(sds->shift);
- zero_v3(sds->shift_f);
- add_v3_fl(sds->shift_f, 0.5f);
- zero_v3(sds->prev_loc);
- mul_m4_v3(ob->obmat, sds->prev_loc);
- copy_m4_m4(sds->obmat, ob->obmat);
-
- /* set resolutions */
- if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */
- }
- else {
- copy_v3_v3_int(res, sds->base_res);
- }
- copy_v3_v3_int(sds->res, res);
- sds->total_cells = sds->res[0] * sds->res[1] * sds->res[2];
- sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0;
- copy_v3_v3_int(sds->res_max, res);
-
- /* allocate fluid */
- BKE_smoke_reallocate_fluid(sds, sds->dx, sds->res, 0);
-
- smd->time = scene_framenr;
-
- /* allocate highres fluid */
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0);
- }
- /* allocate shadow buffer */
- if (!sds->shadow) {
- sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2],
- "SmokeDomainShadow");
- }
- return 1;
- }
- else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
- smd->time = scene_framenr;
-
- return 1;
- }
- else if ((smd->type & MOD_SMOKE_TYPE_COLL)) {
- if (!smd->coll) {
- smokeModifier_createType(smd);
- }
-
- smd->time = scene_framenr;
-
- return 1;
- }
-
- return 2;
-}
-
-#endif /* WITH_SMOKE */
-
-static void smokeModifier_freeDomain(SmokeModifierData *smd)
-{
- if (smd->domain) {
- if (smd->domain->shadow) {
- MEM_freeN(smd->domain->shadow);
- }
- smd->domain->shadow = NULL;
-
- if (smd->domain->fluid) {
- smoke_free(smd->domain->fluid);
- }
-
- if (smd->domain->fluid_mutex) {
- BLI_rw_mutex_free(smd->domain->fluid_mutex);
- }
-
- if (smd->domain->wt) {
- smoke_turbulence_free(smd->domain->wt);
- }
-
- if (smd->domain->effector_weights) {
- MEM_freeN(smd->domain->effector_weights);
- }
- smd->domain->effector_weights = NULL;
-
- if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) {
- BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
- smd->domain->point_cache[0] = NULL;
- }
-
- if (smd->domain->coba) {
- MEM_freeN(smd->domain->coba);
- }
-
- MEM_freeN(smd->domain);
- smd->domain = NULL;
- }
-}
-
-static void smokeModifier_freeFlow(SmokeModifierData *smd)
-{
- if (smd->flow) {
- if (smd->flow->mesh) {
- BKE_id_free(NULL, smd->flow->mesh);
- }
- if (smd->flow->verts_old) {
- MEM_freeN(smd->flow->verts_old);
- }
- MEM_freeN(smd->flow);
- smd->flow = NULL;
- }
-}
-
-static void smokeModifier_freeCollision(SmokeModifierData *smd)
-{
- if (smd->coll) {
- SmokeCollSettings *scs = smd->coll;
-
- if (scs->numverts) {
- if (scs->verts_old) {
- MEM_freeN(scs->verts_old);
- scs->verts_old = NULL;
- }
- }
-
- if (smd->coll->mesh) {
- BKE_id_free(NULL, smd->coll->mesh);
- }
- smd->coll->mesh = NULL;
-
- MEM_freeN(smd->coll);
- smd->coll = NULL;
- }
-}
-
-void smokeModifier_reset_turbulence(struct SmokeModifierData *smd)
-{
- if (smd && smd->domain && smd->domain->wt) {
- smoke_turbulence_free(smd->domain->wt);
- smd->domain->wt = NULL;
- }
-}
-
-static void smokeModifier_reset_ex(struct SmokeModifierData *smd, bool need_lock)
-{
- if (smd) {
- if (smd->domain) {
- if (smd->domain->shadow) {
- MEM_freeN(smd->domain->shadow);
- }
- smd->domain->shadow = NULL;
-
- if (smd->domain->fluid) {
- if (need_lock) {
- BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
- }
-
- smoke_free(smd->domain->fluid);
- smd->domain->fluid = NULL;
-
- if (need_lock) {
- BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
- }
- }
-
- smokeModifier_reset_turbulence(smd);
-
- smd->time = -1;
- smd->domain->total_cells = 0;
- smd->domain->active_fields = 0;
- }
- else if (smd->flow) {
- if (smd->flow->verts_old) {
- MEM_freeN(smd->flow->verts_old);
- }
- smd->flow->verts_old = NULL;
- smd->flow->numverts = 0;
- }
- else if (smd->coll) {
- SmokeCollSettings *scs = smd->coll;
-
- if (scs->numverts && scs->verts_old) {
- MEM_freeN(scs->verts_old);
- scs->verts_old = NULL;
- }
- }
- }
-}
-
-void smokeModifier_reset(struct SmokeModifierData *smd)
-{
- smokeModifier_reset_ex(smd, true);
-}
-
-void smokeModifier_free(SmokeModifierData *smd)
-{
- if (smd) {
- smokeModifier_freeDomain(smd);
- smokeModifier_freeFlow(smd);
- smokeModifier_freeCollision(smd);
- }
-}
-
-void smokeModifier_createType(struct SmokeModifierData *smd)
-{
- if (smd) {
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- if (smd->domain) {
- smokeModifier_freeDomain(smd);
- }
-
- smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
-
- smd->domain->smd = smd;
-
- smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0]));
- smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE;
- smd->domain->point_cache[0]->step = 1;
-
- /* Deprecated */
- smd->domain->point_cache[1] = NULL;
- BLI_listbase_clear(&smd->domain->ptcaches[1]);
- /* set some standard values */
- smd->domain->fluid = NULL;
- smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
- smd->domain->wt = NULL;
- smd->domain->eff_group = NULL;
- smd->domain->fluid_group = NULL;
- smd->domain->coll_group = NULL;
- smd->domain->maxres = 32;
- smd->domain->amplify = 1;
- smd->domain->alpha = -0.001;
- smd->domain->beta = 0.1;
- smd->domain->time_scale = 1.0;
- smd->domain->vorticity = 2.0;
- smd->domain->border_collisions = SM_BORDER_OPEN; // open domain
- smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG;
- smd->domain->highres_sampling = SM_HRES_FULLSAMPLE;
- smd->domain->strength = 2.0;
- smd->domain->noise = MOD_SMOKE_NOISEWAVE;
- smd->domain->diss_speed = 5;
- smd->domain->active_fields = 0;
-
- smd->domain->adapt_margin = 4;
- smd->domain->adapt_res = 0;
- smd->domain->adapt_threshold = 0.02f;
-
- smd->domain->burning_rate = 0.75f;
- smd->domain->flame_smoke = 1.0f;
- smd->domain->flame_vorticity = 0.5f;
- smd->domain->flame_ignition = 1.5f;
- smd->domain->flame_max_temp = 3.0f;
- /* color */
- smd->domain->flame_smoke_color[0] = 0.7f;
- smd->domain->flame_smoke_color[1] = 0.7f;
- smd->domain->flame_smoke_color[2] = 0.7f;
-
- smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOW_HIGHRES;
- smd->domain->effector_weights = BKE_effector_add_weights(NULL);
-
-#ifdef WITH_OPENVDB_BLOSC
- smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
-#else
- smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
-#endif
- smd->domain->data_depth = 0;
- smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE;
-
- smd->domain->display_thickness = 1.0f;
- smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED;
- smd->domain->axis_slice_method = AXIS_SLICE_FULL;
- smd->domain->slice_per_voxel = 5.0f;
- smd->domain->slice_depth = 0.5f;
- smd->domain->slice_axis = 0;
- smd->domain->vector_scale = 1.0f;
-
- smd->domain->coba = NULL;
- smd->domain->coba_field = FLUID_FIELD_DENSITY;
-
- smd->domain->clipping = 1e-3f;
- }
- else if (smd->type & MOD_SMOKE_TYPE_FLOW) {
- if (smd->flow) {
- smokeModifier_freeFlow(smd);
- }
-
- smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
-
- smd->flow->smd = smd;
-
- /* set some standard values */
- smd->flow->density = 1.0f;
- smd->flow->fuel_amount = 1.0f;
- smd->flow->temp = 1.0f;
- smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE | MOD_SMOKE_FLOW_USE_PART_SIZE;
- smd->flow->vel_multi = 1.0f;
- smd->flow->volume_density = 0.0f;
- smd->flow->surface_distance = 1.5f;
- smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH;
- smd->flow->texture_size = 1.0f;
- smd->flow->particle_size = 1.0f;
- smd->flow->subframes = 0;
-
- smd->flow->color[0] = 0.7f;
- smd->flow->color[1] = 0.7f;
- smd->flow->color[2] = 0.7f;
-
- smd->flow->mesh = NULL;
- smd->flow->psys = NULL;
- }
- else if (smd->type & MOD_SMOKE_TYPE_COLL) {
- if (smd->coll) {
- smokeModifier_freeCollision(smd);
- }
-
- smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
-
- smd->coll->smd = smd;
- smd->coll->verts_old = NULL;
- smd->coll->numverts = 0;
- smd->coll->type = 0; // static obstacle
- smd->coll->mesh = NULL;
- }
- }
-}
-
-void smokeModifier_copy(const struct SmokeModifierData *smd,
- struct SmokeModifierData *tsmd,
- const int flag)
-{
- tsmd->type = smd->type;
- tsmd->time = smd->time;
-
- smokeModifier_createType(tsmd);
-
- if (tsmd->domain) {
- SmokeDomainSettings *tsds = tsmd->domain;
- SmokeDomainSettings *sds = smd->domain;
-
- BKE_ptcache_free_list(&(tsds->ptcaches[0]));
-
- if (flag & LIB_ID_CREATE_NO_MAIN) {
- /* Share the cache with the original object's modifier. */
- tsmd->modifier.flag |= eModifierFlag_SharedCaches;
- tsds->point_cache[0] = sds->point_cache[0];
- tsds->ptcaches[0] = sds->ptcaches[0];
- }
- else {
- tsds->point_cache[0] = BKE_ptcache_copy_list(
- &(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag);
- }
-
- tsds->fluid_group = sds->fluid_group;
- tsds->coll_group = sds->coll_group;
-
- tsds->adapt_margin = sds->adapt_margin;
- tsds->adapt_res = sds->adapt_res;
- tsds->adapt_threshold = sds->adapt_threshold;
-
- tsds->alpha = sds->alpha;
- tsds->beta = sds->beta;
- tsds->amplify = sds->amplify;
- tsds->maxres = sds->maxres;
- tsds->flags = sds->flags;
- tsds->highres_sampling = sds->highres_sampling;
- tsds->viewsettings = sds->viewsettings;
- tsds->noise = sds->noise;
- tsds->diss_speed = sds->diss_speed;
- tsds->strength = sds->strength;
-
- tsds->border_collisions = sds->border_collisions;
- tsds->vorticity = sds->vorticity;
- tsds->time_scale = sds->time_scale;
-
- tsds->burning_rate = sds->burning_rate;
- tsds->flame_smoke = sds->flame_smoke;
- tsds->flame_vorticity = sds->flame_vorticity;
- tsds->flame_ignition = sds->flame_ignition;
- tsds->flame_max_temp = sds->flame_max_temp;
- copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color);
-
- MEM_freeN(tsds->effector_weights);
- tsds->effector_weights = MEM_dupallocN(sds->effector_weights);
- tsds->openvdb_comp = sds->openvdb_comp;
- tsds->data_depth = sds->data_depth;
- tsds->cache_file_format = sds->cache_file_format;
-
- tsds->display_thickness = sds->display_thickness;
- tsds->slice_method = sds->slice_method;
- tsds->axis_slice_method = sds->axis_slice_method;
- tsds->slice_per_voxel = sds->slice_per_voxel;
- tsds->slice_depth = sds->slice_depth;
- tsds->slice_axis = sds->slice_axis;
- tsds->interp_method = sds->interp_method;
- tsds->draw_velocity = sds->draw_velocity;
- tsds->vector_draw_type = sds->vector_draw_type;
- tsds->vector_scale = sds->vector_scale;
-
- tsds->use_coba = sds->use_coba;
- tsds->coba_field = sds->coba_field;
- if (sds->coba) {
- tsds->coba = MEM_dupallocN(sds->coba);
- }
-
- tsds->clipping = sds->clipping;
- }
- else if (tsmd->flow) {
- SmokeFlowSettings *tsfs = tsmd->flow;
- SmokeFlowSettings *sfs = smd->flow;
-
- tsfs->psys = sfs->psys;
- tsfs->noise_texture = sfs->noise_texture;
-
- tsfs->vel_multi = sfs->vel_multi;
- tsfs->vel_normal = sfs->vel_normal;
- tsfs->vel_random = sfs->vel_random;
-
- tsfs->density = sfs->density;
- copy_v3_v3(tsfs->color, sfs->color);
- tsfs->fuel_amount = sfs->fuel_amount;
- tsfs->temp = sfs->temp;
- tsfs->volume_density = sfs->volume_density;
- tsfs->surface_distance = sfs->surface_distance;
- tsfs->particle_size = sfs->particle_size;
- tsfs->subframes = sfs->subframes;
-
- tsfs->texture_size = sfs->texture_size;
- tsfs->texture_offset = sfs->texture_offset;
- BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name));
- tsfs->vgroup_density = sfs->vgroup_density;
-
- tsfs->type = sfs->type;
- tsfs->source = sfs->source;
- tsfs->texture_type = sfs->texture_type;
- tsfs->flags = sfs->flags;
- }
- else if (tsmd->coll) {
- /* leave it as initialized, collision settings is mostly caches */
- }
-}
-
-#ifdef WITH_SMOKE
-
-// forward declaration
-static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer);
-static float calc_voxel_transp(
- float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-
-static int get_light(ViewLayer *view_layer, float *light)
-{
- Base *base_tmp = NULL;
- int found_light = 0;
-
- // try to find a lamp, preferably local
- for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
- if (base_tmp->object->type == OB_LAMP) {
- Light *la = base_tmp->object->data;
-
- if (la->type == LA_LOCAL) {
- copy_v3_v3(light, base_tmp->object->obmat[3]);
- return 1;
- }
- else if (!found_light) {
- copy_v3_v3(light, base_tmp->object->obmat[3]);
- found_light = 1;
- }
- }
- }
-
- return found_light;
-}
-
-/**********************************************************
- * Obstacles
- **********************************************************/
-
-typedef struct ObstaclesFromDMData {
- SmokeDomainSettings *sds;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *looptri;
- BVHTreeFromMesh *tree;
- unsigned char *obstacle_map;
-
- bool has_velocity;
- float *vert_vel;
- float *velocityX, *velocityY, *velocityZ;
- int *num_obstacles;
-} ObstaclesFromDMData;
-
-static void obstacles_from_mesh_task_cb(void *__restrict userdata,
- const int z,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- ObstaclesFromDMData *data = userdata;
- SmokeDomainSettings *sds = data->sds;
-
- /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
- const float surface_distance = 0.867f;
-
- for (int x = sds->res_min[0]; x < sds->res_max[0]; x++) {
- for (int y = sds->res_min[1]; y < sds->res_max[1]; y++) {
- const int index = smoke_get_index(
- x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]);
-
- float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
- BVHTreeNearest nearest = {0};
- nearest.index = -1;
- nearest.dist_sq = surface_distance *
- surface_distance; /* find_nearest uses squared distance */
-
- /* find the nearest point on the mesh */
- if (BLI_bvhtree_find_nearest(
- data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) !=
- -1) {
- const MLoopTri *lt = &data->looptri[nearest.index];
- float weights[3];
- int v1, v2, v3;
-
- /* calculate barycentric weights for nearest point */
- v1 = data->mloop[lt->tri[0]].v;
- v2 = data->mloop[lt->tri[1]].v;
- v3 = data->mloop[lt->tri[2]].v;
- interp_weights_tri_v3(
- weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
-
- // DG TODO
- if (data->has_velocity) {
- /* apply object velocity */
- {
- float hit_vel[3];
- interp_v3_v3v3v3(hit_vel,
- &data->vert_vel[v1 * 3],
- &data->vert_vel[v2 * 3],
- &data->vert_vel[v3 * 3],
- weights);
- data->velocityX[index] += hit_vel[0];
- data->velocityY[index] += hit_vel[1];
- data->velocityZ[index] += hit_vel[2];
- }
- }
-
- /* tag obstacle cells */
- data->obstacle_map[index] = 1;
-
- if (data->has_velocity) {
- data->obstacle_map[index] |= 8;
- data->num_obstacles[index]++;
- }
- }
- }
- }
-}
-
-static void obstacles_from_mesh(Object *coll_ob,
- SmokeDomainSettings *sds,
- SmokeCollSettings *scs,
- unsigned char *obstacle_map,
- float *velocityX,
- float *velocityY,
- float *velocityZ,
- int *num_obstacles,
- float dt)
-{
- if (!scs->mesh) {
- return;
- }
- {
- Mesh *me = NULL;
- MVert *mvert = NULL;
- const MLoopTri *looptri;
- const MLoop *mloop;
- BVHTreeFromMesh treeData = {NULL};
- int numverts, i;
-
- float *vert_vel = NULL;
- bool has_velocity = false;
-
- me = BKE_mesh_copy_for_eval(scs->mesh, true);
- BKE_mesh_ensure_normals(me);
- mvert = me->mvert;
- mloop = me->mloop;
- looptri = BKE_mesh_runtime_looptri_ensure(me);
- numverts = me->totvert;
-
- // DG TODO
- // if (scs->type > SM_COLL_STATIC)
- // if line above is used, the code is in trouble if the object moves
- // but is declared as "does not move".
-
- {
- vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity");
-
- if (scs->numverts != numverts || !scs->verts_old) {
- if (scs->verts_old) {
- MEM_freeN(scs->verts_old);
- }
-
- scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old");
- scs->numverts = numverts;
- }
- else {
- has_velocity = true;
- }
- }
-
- /* Transform collider vertices to
- * domain grid space for fast lookups */
- for (i = 0; i < numverts; i++) {
- float n[3];
- float co[3];
-
- /* vert pos */
- mul_m4_v3(coll_ob->obmat, mvert[i].co);
- smoke_pos_to_cell(sds, mvert[i].co);
-
- /* vert normal */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(coll_ob->obmat, n);
- mul_mat3_m4_v3(sds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
-
- /* vert velocity */
- add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
- if (has_velocity) {
- sub_v3_v3v3(&vert_vel[i * 3], co, &scs->verts_old[i * 3]);
- mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
- }
- copy_v3_v3(&scs->verts_old[i * 3], co);
- }
-
- if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
- ObstaclesFromDMData data = {
- .sds = sds,
- .mvert = mvert,
- .mloop = mloop,
- .looptri = looptri,
- .tree = &treeData,
- .obstacle_map = obstacle_map,
- .has_velocity = has_velocity,
- .vert_vel = vert_vel,
- .velocityX = velocityX,
- .velocityY = velocityY,
- .velocityZ = velocityZ,
- .num_obstacles = num_obstacles,
- };
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(
- sds->res_min[2], sds->res_max[2], &data, obstacles_from_mesh_task_cb, &settings);
- }
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
- BKE_id_free(NULL, me);
-
- if (vert_vel) {
- MEM_freeN(vert_vel);
- }
- }
-}
-
-/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
-static void update_obstacles(Depsgraph *depsgraph,
- Object *ob,
- SmokeDomainSettings *sds,
- float dt,
- int UNUSED(substep),
- int UNUSED(totalsteps))
-{
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
-
- unsigned int collIndex;
- unsigned char *obstacles = smoke_get_obstacle(sds->fluid);
- float *velx = NULL;
- float *vely = NULL;
- float *velz = NULL;
- float *velxOrig = smoke_get_velocity_x(sds->fluid);
- float *velyOrig = smoke_get_velocity_y(sds->fluid);
- float *velzOrig = smoke_get_velocity_z(sds->fluid);
- float *density = smoke_get_density(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *flame = smoke_get_flame(sds->fluid);
- float *r = smoke_get_color_r(sds->fluid);
- float *g = smoke_get_color_g(sds->fluid);
- float *b = smoke_get_color_b(sds->fluid);
- unsigned int z;
-
- int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2],
- "smoke_num_obstacles");
-
- smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
-
- // TODO: delete old obstacle flags
- for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) {
- if (obstacles[z] & 8) // Do not delete static obstacles
- {
- obstacles[z] = 0;
- }
-
- velx[z] = 0;
- vely[z] = 0;
- velz[z] = 0;
- }
-
- collobjs = BKE_collision_objects_create(
- depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
-
- // update obstacle tags in cells
- for (collIndex = 0; collIndex < numcollobj; collIndex++) {
- Object *collob = collobjs[collIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
- eModifierType_Smoke);
-
- // DG TODO: check if modifier is active?
-
- if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
- SmokeCollSettings *scs = smd2->coll;
- obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
- }
- }
-
- BKE_collision_objects_free(collobjs);
-
- /* obstacle cells should not contain any velocity from the smoke simulation */
- for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) {
- if (obstacles[z]) {
- velxOrig[z] = 0;
- velyOrig[z] = 0;
- velzOrig[z] = 0;
- density[z] = 0;
- if (fuel) {
- fuel[z] = 0;
- flame[z] = 0;
- }
- if (r) {
- r[z] = 0;
- g[z] = 0;
- b[z] = 0;
- }
- }
- /* average velocities from multiple obstacles in one cell */
- if (num_obstacles[z]) {
- velx[z] /= num_obstacles[z];
- vely[z] /= num_obstacles[z];
- velz[z] /= num_obstacles[z];
- }
- }
-
- MEM_freeN(num_obstacles);
-}
-
-/**********************************************************
- * Flow emission code
- **********************************************************/
-
-typedef struct EmissionMap {
- float *influence;
- float *influence_high;
- float *velocity;
- int min[3], max[3], res[3];
- int hmin[3], hmax[3], hres[3];
- int total_cells, valid;
-} EmissionMap;
-
-static void em_boundInsert(EmissionMap *em, float point[3])
-{
- int i = 0;
- if (!em->valid) {
- for (; i < 3; i++) {
- em->min[i] = (int)floor(point[i]);
- em->max[i] = (int)ceil(point[i]);
- }
- em->valid = 1;
- }
- else {
- for (; i < 3; i++) {
- if (point[i] < em->min[i]) {
- em->min[i] = (int)floor(point[i]);
- }
- if (point[i] > em->max[i]) {
- em->max[i] = (int)ceil(point[i]);
- }
- }
- }
-}
-
-static void clampBoundsInDomain(SmokeDomainSettings *sds,
- int min[3],
- int max[3],
- float *min_vel,
- float *max_vel,
- int margin,
- float dt)
-{
- int i;
- for (i = 0; i < 3; i++) {
- int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0;
- /* add margin */
- min[i] -= margin;
- max[i] += margin;
-
- /* adapt to velocity */
- if (min_vel && min_vel[i] < 0.0f) {
- min[i] += (int)floor(min_vel[i] * dt);
- }
- if (max_vel && max_vel[i] > 0.0f) {
- max[i] += (int)ceil(max_vel[i] * dt);
- }
-
- /* clamp within domain max size */
- CLAMP(min[i], -adapt, sds->base_res[i] + adapt);
- CLAMP(max[i], -adapt, sds->base_res[i] + adapt);
- }
-}
-
-static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
-{
- int i, res[3];
-
- for (i = 0; i < 3; i++) {
- res[i] = em->max[i] - em->min[i];
- if (res[i] <= 0) {
- return;
- }
- }
- em->total_cells = res[0] * res[1] * res[2];
- copy_v3_v3_int(em->res, res);
-
- em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence");
- if (use_velocity) {
- em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity");
- }
-
- /* allocate high resolution map if required */
- if (hires_mul > 1) {
- int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul);
-
- for (i = 0; i < 3; i++) {
- em->hmin[i] = em->min[i] * hires_mul;
- em->hmax[i] = em->max[i] * hires_mul;
- em->hres[i] = em->res[i] * hires_mul;
- }
-
- em->influence_high = MEM_callocN(sizeof(float) * total_cells_high,
- "smoke_flow_influence_high");
- }
- em->valid = 1;
-}
-
-static void em_freeData(EmissionMap *em)
-{
- if (em->influence) {
- MEM_freeN(em->influence);
- }
- if (em->influence_high) {
- MEM_freeN(em->influence_high);
- }
- if (em->velocity) {
- MEM_freeN(em->velocity);
- }
-}
-
-static void em_combineMaps(
- EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
-{
- int i, x, y, z;
-
- /* copyfill input 1 struct and clear output for new allocation */
- EmissionMap em1;
- memcpy(&em1, output, sizeof(EmissionMap));
- memset(output, 0, sizeof(EmissionMap));
-
- for (i = 0; i < 3; i++) {
- if (em1.valid) {
- output->min[i] = MIN2(em1.min[i], em2->min[i]);
- output->max[i] = MAX2(em1.max[i], em2->max[i]);
- }
- else {
- output->min[i] = em2->min[i];
- output->max[i] = em2->max[i];
- }
- }
- /* allocate output map */
- em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
-
- /* base resolution inputs */
- for (x = output->min[0]; x < output->max[0]; x++) {
- for (y = output->min[1]; y < output->max[1]; y++) {
- for (z = output->min[2]; z < output->max[2]; z++) {
- int index_out = smoke_get_index(x - output->min[0],
- output->res[0],
- y - output->min[1],
- output->res[1],
- z - output->min[2]);
-
- /* initialize with first input if in range */
- if (x >= em1.min[0] && x < em1.max[0] && y >= em1.min[1] && y < em1.max[1] &&
- z >= em1.min[2] && z < em1.max[2]) {
- int index_in = smoke_get_index(
- x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]);
-
- /* values */
- output->influence[index_out] = em1.influence[index_in];
- if (output->velocity && em1.velocity) {
- copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]);
- }
- }
-
- /* apply second input if in range */
- if (x >= em2->min[0] && x < em2->max[0] && y >= em2->min[1] && y < em2->max[1] &&
- z >= em2->min[2] && z < em2->max[2]) {
- int index_in = smoke_get_index(
- x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]);
-
- /* values */
- if (additive) {
- output->influence[index_out] += em2->influence[index_in] * sample_size;
- }
- else {
- output->influence[index_out] = MAX2(em2->influence[index_in],
- output->influence[index_out]);
- }
- if (output->velocity && em2->velocity) {
- /* last sample replaces the velocity */
- output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3],
- em2->velocity[index_in * 3]);
- output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1],
- em2->velocity[index_in * 3 + 1]);
- output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2],
- em2->velocity[index_in * 3 + 2]);
- }
- }
- } // low res loop
- }
- }
-
- /* initialize high resolution input if available */
- if (output->influence_high) {
- for (x = output->hmin[0]; x < output->hmax[0]; x++) {
- for (y = output->hmin[1]; y < output->hmax[1]; y++) {
- for (z = output->hmin[2]; z < output->hmax[2]; z++) {
- int index_out = smoke_get_index(x - output->hmin[0],
- output->hres[0],
- y - output->hmin[1],
- output->hres[1],
- z - output->hmin[2]);
-
- /* initialize with first input if in range */
- if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] &&
- z >= em1.hmin[2] && z < em1.hmax[2]) {
- int index_in = smoke_get_index(
- x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]);
- /* values */
- output->influence_high[index_out] = em1.influence_high[index_in];
- }
-
- /* apply second input if in range */
- if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] &&
- z >= em2->hmin[2] && z < em2->hmax[2]) {
- int index_in = smoke_get_index(
- x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]);
-
- /* values */
- if (additive) {
- output->influence_high[index_out] += em2->influence_high[index_in] * sample_size;
- }
- else {
- output->influence_high[index_out] = MAX2(em2->influence_high[index_in],
- output->influence_high[index_out]);
- }
- }
- } // high res loop
- }
- }
- }
-
- /* free original data */
- em_freeData(&em1);
-}
-
-typedef struct EmitFromParticlesData {
- SmokeFlowSettings *sfs;
- KDTree_3d *tree;
- int hires_multiplier;
-
- EmissionMap *em;
- float *particle_vel;
- float hr;
-
- int *min, *max, *res;
-
- float solid;
- float smooth;
- float hr_smooth;
-} EmitFromParticlesData;
-
-static void emit_from_particles_task_cb(void *__restrict userdata,
- const int z,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- EmitFromParticlesData *data = userdata;
- SmokeFlowSettings *sfs = data->sfs;
- EmissionMap *em = data->em;
- const int hires_multiplier = data->hires_multiplier;
-
- for (int x = data->min[0]; x < data->max[0]; x++) {
- for (int y = data->min[1]; y < data->max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 ||
- !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- const int lx = x / hires_multiplier;
- const int ly = y / hires_multiplier;
- const int lz = z / hires_multiplier;
-
- const int index = smoke_get_index(
- lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- /* find particle distance from the kdtree */
- KDTreeNearest_3d nearest;
- const float range = data->solid + data->smooth;
- BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence[index] = (nearest.dist < data->solid) ?
- 1.0f :
- (1.0f - (nearest.dist - data->solid) / data->smooth);
- /* Uses particle velocity as initial velocity for smoke */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY &&
- (sfs->psys->part->phystype != PART_PHYS_NO)) {
- madd_v3_v3fl(
- &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], sfs->vel_multi);
- }
- }
- }
-
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- const float lx = ((float)x) * data->hr;
- const float ly = ((float)y) * data->hr;
- const float lz = ((float)z) * data->hr;
-
- const int index = smoke_get_index(
- x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
- const float ray_start[3] = {
- lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
-
- /* find particle distance from the kdtree */
- KDTreeNearest_3d nearest;
- const float range = data->solid + data->hr_smooth;
- BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence_high[index] = (nearest.dist < data->solid) ?
- 1.0f :
- (1.0f - (nearest.dist - data->solid) / data->smooth);
- }
- }
- }
- }
-}
-
-static void emit_from_particles(Object *flow_ob,
- SmokeDomainSettings *sds,
- SmokeFlowSettings *sfs,
- EmissionMap *em,
- Depsgraph *depsgraph,
- Scene *scene,
- float dt)
-{
- /* Is particle system selected. */
- if (sfs && sfs->psys && sfs->psys->part &&
- ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) {
- ParticleSimulationData sim;
- ParticleSystem *psys = sfs->psys;
- float *particle_pos;
- float *particle_vel;
- int totpart = psys->totpart, totchild;
- int p = 0;
- int valid_particles = 0;
- int bounds_margin = 1;
-
- /* radius based flow */
- const float solid = sfs->particle_size * 0.5f;
- const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
- int hires_multiplier = 1;
- KDTree_3d *tree = NULL;
-
- sim.depsgraph = depsgraph;
- sim.scene = scene;
- sim.ob = flow_ob;
- sim.psys = psys;
- sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
- /* prepare curvemapping tables */
- if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) {
- BKE_curvemapping_changed_all(psys->part->clumpcurve);
- }
- if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) {
- BKE_curvemapping_changed_all(psys->part->roughcurve);
- }
- if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) {
- BKE_curvemapping_changed_all(psys->part->twistcurve);
- }
-
- /* initialize particle cache */
- if (psys->part->type == PART_HAIR) {
- // TODO: PART_HAIR not supported whatsoever
- totchild = 0;
- }
- else {
- totchild = psys->totchild * psys->part->disp / 100;
- }
-
- particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
- particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
-
- /* setup particle radius emission if enabled */
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
-
- /* check need for high resolution map */
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- bounds_margin = (int)ceil(solid + smooth);
- }
-
- /* calculate local position for each particle */
- for (p = 0; p < totpart + totchild; p++) {
- ParticleKey state;
- float *pos;
- if (p < totpart) {
- if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
- continue;
- }
- }
- else {
- /* handle child particle */
- ChildParticle *cpa = &psys->child[p - totpart];
- if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
- continue;
- }
- }
-
- /* DEG_get_ctime(depsgraph) does not give subframe time */
- state.time = BKE_scene_frame_get(scene);
- if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
- continue;
- }
-
- /* location */
- pos = &particle_pos[valid_particles * 3];
- copy_v3_v3(pos, state.co);
- smoke_pos_to_cell(sds, pos);
-
- /* velocity */
- copy_v3_v3(&particle_vel[valid_particles * 3], state.vel);
- mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles * 3]);
-
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- BLI_kdtree_3d_insert(tree, valid_particles, pos);
- }
-
- /* calculate emission map bounds */
- em_boundInsert(em, pos);
- valid_particles++;
- }
-
- /* set emission map */
- clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt);
- em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
-
- if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
- for (p = 0; p < valid_particles; p++) {
- int cell[3];
- size_t i = 0;
- size_t index = 0;
- int badcell = 0;
-
- /* 1. get corresponding cell */
- cell[0] = floor(particle_pos[p * 3]) - em->min[0];
- cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1];
- cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2];
- /* check if cell is valid (in the domain boundary) */
- for (i = 0; i < 3; i++) {
- if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) {
- badcell = 1;
- break;
- }
- }
- if (badcell) {
- continue;
- }
- /* get cell index */
- index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]);
- /* Add influence to emission map */
- em->influence[index] = 1.0f;
- /* Uses particle velocity as initial velocity for smoke */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) {
- madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi);
- }
- } // particles loop
- }
- else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE
- int min[3], max[3], res[3];
- const float hr = 1.0f / ((float)hires_multiplier);
- /* slightly adjust high res antialias smoothness based on number of divisions
- * to allow smaller details but yet not differing too much from the low res size */
- const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f);
-
- /* setup loop bounds */
- for (int i = 0; i < 3; i++) {
- min[i] = em->min[i] * hires_multiplier;
- max[i] = em->max[i] * hires_multiplier;
- res[i] = em->res[i] * hires_multiplier;
- }
-
- BLI_kdtree_3d_balance(tree);
-
- EmitFromParticlesData data = {
- .sfs = sfs,
- .tree = tree,
- .hires_multiplier = hires_multiplier,
- .hr = hr,
- .em = em,
- .particle_vel = particle_vel,
- .min = min,
- .max = max,
- .res = res,
- .solid = solid,
- .smooth = smooth,
- .hr_smooth = hr_smooth,
- };
-
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings);
- }
-
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- BLI_kdtree_3d_free(tree);
- }
-
- /* free data */
- if (particle_pos) {
- MEM_freeN(particle_pos);
- }
- if (particle_vel) {
- MEM_freeN(particle_vel);
- }
- }
-}
-
-static void sample_mesh(SmokeFlowSettings *sfs,
- const MVert *mvert,
- const MLoop *mloop,
- const MLoopTri *mlooptri,
- const MLoopUV *mloopuv,
- float *influence_map,
- float *velocity_map,
- int index,
- const int base_res[3],
- float flow_center[3],
- BVHTreeFromMesh *treeData,
- const float ray_start[3],
- const float *vert_vel,
- bool has_velocity,
- int defgrp_index,
- MDeformVert *dvert,
- float x,
- float y,
- float z)
-{
- float ray_dir[3] = {1.0f, 0.0f, 0.0f};
- BVHTreeRayHit hit = {0};
- BVHTreeNearest nearest = {0};
-
- float volume_factor = 0.0f;
- float sample_str = 0.0f;
-
- hit.index = -1;
- hit.dist = 9999;
- nearest.index = -1;
- nearest.dist_sq = sfs->surface_distance *
- sfs->surface_distance; /* find_nearest uses squared distance */
-
- /* Check volume collision */
- if (sfs->volume_density) {
- if (BLI_bvhtree_ray_cast(treeData->tree,
- ray_start,
- ray_dir,
- 0.0f,
- &hit,
- treeData->raycast_callback,
- treeData) != -1) {
- float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
- /* If ray and hit face normal are facing same direction
- * hit point is inside a closed mesh. */
- if (dot >= 0) {
- /* Also cast a ray in opposite direction to make sure
- * point is at least surrounded by two faces */
- negate_v3(ray_dir);
- hit.index = -1;
- hit.dist = 9999;
-
- BLI_bvhtree_ray_cast(
- treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData);
- if (hit.index != -1) {
- volume_factor = sfs->volume_density;
- }
- }
- }
- }
-
- /* find the nearest point on the mesh */
- if (BLI_bvhtree_find_nearest(
- treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
- float weights[3];
- int v1, v2, v3, f_index = nearest.index;
- float n1[3], n2[3], n3[3], hit_normal[3];
-
- /* emit from surface based on distance */
- if (sfs->surface_distance) {
- sample_str = sqrtf(nearest.dist_sq) / sfs->surface_distance;
- CLAMP(sample_str, 0.0f, 1.0f);
- sample_str = pow(1.0f - sample_str, 0.5f);
- }
- else {
- sample_str = 0.0f;
- }
-
- /* calculate barycentric weights for nearest point */
- v1 = mloop[mlooptri[f_index].tri[0]].v;
- v2 = mloop[mlooptri[f_index].tri[1]].v;
- v3 = mloop[mlooptri[f_index].tri[2]].v;
- interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
-
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
- /* apply normal directional velocity */
- if (sfs->vel_normal) {
- /* interpolate vertex normal vectors to get nearest point normal */
- normal_short_to_float_v3(n1, mvert[v1].no);
- normal_short_to_float_v3(n2, mvert[v2].no);
- normal_short_to_float_v3(n3, mvert[v3].no);
- interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
- normalize_v3(hit_normal);
- /* apply normal directional and random velocity
- * - TODO: random disabled for now since it doesn't really work well
- * as pressure calc smoothens it out. */
- velocity_map[index * 3] += hit_normal[0] * sfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 1] += hit_normal[1] * sfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 2] += hit_normal[2] * sfs->vel_normal * 0.25f;
- /* TODO: for fire emitted from mesh surface we can use
- * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
- }
- /* apply object velocity */
- if (has_velocity && sfs->vel_multi) {
- float hit_vel[3];
- interp_v3_v3v3v3(
- hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
- velocity_map[index * 3] += hit_vel[0] * sfs->vel_multi;
- velocity_map[index * 3 + 1] += hit_vel[1] * sfs->vel_multi;
- velocity_map[index * 3 + 2] += hit_vel[2] * sfs->vel_multi;
- }
- }
-
- /* apply vertex group influence if used */
- if (defgrp_index != -1 && dvert) {
- float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
- defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
- defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
- sample_str *= weight_mask;
- }
-
- /* apply emission texture */
- if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) {
- float tex_co[3] = {0};
- TexResult texres;
-
- if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) {
- tex_co[0] = ((x - flow_center[0]) / base_res[0]) / sfs->texture_size;
- tex_co[1] = ((y - flow_center[1]) / base_res[1]) / sfs->texture_size;
- tex_co[2] = ((z - flow_center[2]) / base_res[2] - sfs->texture_offset) / sfs->texture_size;
- }
- else if (mloopuv) {
- const float *uv[3];
- uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
- uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
- uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
-
- interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
-
- /* map between -1.0f and 1.0f */
- tex_co[0] = tex_co[0] * 2.0f - 1.0f;
- tex_co[1] = tex_co[1] * 2.0f - 1.0f;
- tex_co[2] = sfs->texture_offset;
- }
- texres.nor = NULL;
- BKE_texture_get_value(NULL, sfs->noise_texture, tex_co, &texres, false);
- sample_str *= texres.tin;
- }
- }
-
- /* multiply initial velocity by emitter influence */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
- mul_v3_fl(&velocity_map[index * 3], sample_str);
- }
-
- /* apply final influence based on volume factor */
- influence_map[index] = MAX2(volume_factor, sample_str);
-}
-
-typedef struct EmitFromDMData {
- SmokeDomainSettings *sds;
- SmokeFlowSettings *sfs;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *mlooptri;
- const MLoopUV *mloopuv;
- MDeformVert *dvert;
- int defgrp_index;
-
- BVHTreeFromMesh *tree;
- int hires_multiplier;
- float hr;
-
- EmissionMap *em;
- bool has_velocity;
- float *vert_vel;
-
- float *flow_center;
- int *min, *max, *res;
-} EmitFromDMData;
-
-static void emit_from_mesh_task_cb(void *__restrict userdata,
- const int z,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- EmitFromDMData *data = userdata;
- EmissionMap *em = data->em;
- const int hires_multiplier = data->hires_multiplier;
-
- for (int x = data->min[0]; x < data->max[0]; x++) {
- for (int y = data->min[1]; y < data->max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 ||
- !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- const int lx = x / hires_multiplier;
- const int ly = y / hires_multiplier;
- const int lz = z / hires_multiplier;
-
- const int index = smoke_get_index(
- lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- sample_mesh(data->sfs,
- data->mvert,
- data->mloop,
- data->mlooptri,
- data->mloopuv,
- em->influence,
- em->velocity,
- index,
- data->sds->base_res,
- data->flow_center,
- data->tree,
- ray_start,
- data->vert_vel,
- data->has_velocity,
- data->defgrp_index,
- data->dvert,
- (float)lx,
- (float)ly,
- (float)lz);
- }
-
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- const float lx = ((float)x) * data->hr;
- const float ly = ((float)y) * data->hr;
- const float lz = ((float)z) * data->hr;
-
- const int index = smoke_get_index(
- x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
- const float ray_start[3] = {
- lx + 0.5f * data->hr,
- ly + 0.5f * data->hr,
- lz + 0.5f * data->hr,
- };
-
- sample_mesh(data->sfs,
- data->mvert,
- data->mloop,
- data->mlooptri,
- data->mloopuv,
- em->influence_high,
- NULL,
- index,
- data->sds->base_res,
- data->flow_center,
- data->tree,
- ray_start,
- data->vert_vel,
- data->has_velocity,
- data->defgrp_index,
- data->dvert,
- /* x,y,z needs to be always lowres */
- lx,
- ly,
- lz);
- }
- }
- }
-}
-
-static void emit_from_mesh(
- Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
-{
- if (sfs->mesh) {
- Mesh *me;
- int defgrp_index = sfs->vgroup_density - 1;
- MDeformVert *dvert = NULL;
- MVert *mvert = NULL;
- const MLoopTri *mlooptri = NULL;
- const MLoopUV *mloopuv = NULL;
- const MLoop *mloop = NULL;
- BVHTreeFromMesh treeData = {NULL};
- int numOfVerts, i;
- float flow_center[3] = {0};
-
- float *vert_vel = NULL;
- int has_velocity = 0;
- int min[3], max[3], res[3];
- int hires_multiplier = 1;
-
- /* copy mesh for thread safety because we modify it,
- * main issue is its VertArray being modified, then replaced and freed
- */
- me = BKE_mesh_copy_for_eval(sfs->mesh, true);
-
- /* Duplicate vertices to modify. */
- if (me->mvert) {
- me->mvert = MEM_dupallocN(me->mvert);
- CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
- }
-
- BKE_mesh_ensure_normals(me);
- mvert = me->mvert;
- numOfVerts = me->totvert;
- dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
- mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name);
- mloop = me->mloop;
- mlooptri = BKE_mesh_runtime_looptri_ensure(me);
-
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity");
-
- if (sfs->numverts != numOfVerts || !sfs->verts_old) {
- if (sfs->verts_old) {
- MEM_freeN(sfs->verts_old);
- }
- sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old");
- sfs->numverts = numOfVerts;
- }
- else {
- has_velocity = 1;
- }
- }
-
- /* Transform mesh vertices to
- * domain grid space for fast lookups */
- for (i = 0; i < numOfVerts; i++) {
- float n[3];
- /* vert pos */
- mul_m4_v3(flow_ob->obmat, mvert[i].co);
- smoke_pos_to_cell(sds, mvert[i].co);
- /* vert normal */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(flow_ob->obmat, n);
- mul_mat3_m4_v3(sds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
- /* vert velocity */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- float co[3];
- add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
- if (has_velocity) {
- sub_v3_v3v3(&vert_vel[i * 3], co, &sfs->verts_old[i * 3]);
- mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
- }
- copy_v3_v3(&sfs->verts_old[i * 3], co);
- }
-
- /* calculate emission map bounds */
- em_boundInsert(em, mvert[i].co);
- }
- mul_m4_v3(flow_ob->obmat, flow_center);
- smoke_pos_to_cell(sds, flow_center);
-
- /* check need for high resolution map */
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- /* set emission map */
- clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt);
- em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
-
- /* setup loop bounds */
- for (i = 0; i < 3; i++) {
- min[i] = em->min[i] * hires_multiplier;
- max[i] = em->max[i] * hires_multiplier;
- res[i] = em->res[i] * hires_multiplier;
- }
-
- if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
- const float hr = 1.0f / ((float)hires_multiplier);
-
- EmitFromDMData data = {
- .sds = sds,
- .sfs = sfs,
- .mvert = mvert,
- .mloop = mloop,
- .mlooptri = mlooptri,
- .mloopuv = mloopuv,
- .dvert = dvert,
- .defgrp_index = defgrp_index,
- .tree = &treeData,
- .hires_multiplier = hires_multiplier,
- .hr = hr,
- .em = em,
- .has_velocity = has_velocity,
- .vert_vel = vert_vel,
- .flow_center = flow_center,
- .min = min,
- .max = max,
- .res = res,
- };
-
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings);
- }
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
-
- if (vert_vel) {
- MEM_freeN(vert_vel);
- }
-
- if (me->mvert) {
- MEM_freeN(me->mvert);
- }
- BKE_id_free(NULL, me);
- }
-}
-
-/**********************************************************
- * Smoke step
- **********************************************************/
-
-static void adjustDomainResolution(SmokeDomainSettings *sds,
- int new_shift[3],
- EmissionMap *emaps,
- unsigned int numflowobj,
- float dt)
-{
- const int block_size = sds->amplify + 1;
- int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
- int total_cells = 1, res_changed = 0, shift_changed = 0;
- float min_vel[3], max_vel[3];
- int x, y, z;
- float *density = smoke_get_density(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *bigdensity = smoke_turbulence_get_density(sds->wt);
- float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
- float *vx = smoke_get_velocity_x(sds->fluid);
- float *vy = smoke_get_velocity_y(sds->fluid);
- float *vz = smoke_get_velocity_z(sds->fluid);
- int wt_res[3];
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- smoke_turbulence_get_res(sds->wt, wt_res);
- }
-
- INIT_MINMAX(min_vel, max_vel);
-
- /* Calculate bounds for current domain content */
- for (x = sds->res_min[0]; x < sds->res_max[0]; x++) {
- for (y = sds->res_min[1]; y < sds->res_max[1]; y++) {
- for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
- int xn = x - new_shift[0];
- int yn = y - new_shift[1];
- int zn = z - new_shift[2];
- int index;
- float max_den;
-
- /* skip if cell already belongs to new area */
- if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] &&
- zn <= max[2]) {
- continue;
- }
-
- index = smoke_get_index(x - sds->res_min[0],
- sds->res[0],
- y - sds->res_min[1],
- sds->res[1],
- z - sds->res_min[2]);
- max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
-
- /* check high resolution bounds if max density isnt already high enough */
- if (max_den < sds->adapt_threshold && sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- int i, j, k;
- /* high res grid index */
- int xx = (x - sds->res_min[0]) * block_size;
- int yy = (y - sds->res_min[1]) * block_size;
- int zz = (z - sds->res_min[2]) * block_size;
-
- for (i = 0; i < block_size; i++) {
- for (j = 0; j < block_size; j++) {
- for (k = 0; k < block_size; k++) {
- int big_index = smoke_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
- float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) :
- bigdensity[big_index];
- if (den > max_den) {
- max_den = den;
- }
- }
- }
- }
- }
-
- /* content bounds (use shifted coordinates) */
- if (max_den >= sds->adapt_threshold) {
- if (min[0] > xn) {
- min[0] = xn;
- }
- if (min[1] > yn) {
- min[1] = yn;
- }
- if (min[2] > zn) {
- min[2] = zn;
- }
- if (max[0] < xn) {
- max[0] = xn;
- }
- if (max[1] < yn) {
- max[1] = yn;
- }
- if (max[2] < zn) {
- max[2] = zn;
- }
- }
-
- /* velocity bounds */
- if (min_vel[0] > vx[index]) {
- min_vel[0] = vx[index];
- }
- if (min_vel[1] > vy[index]) {
- min_vel[1] = vy[index];
- }
- if (min_vel[2] > vz[index]) {
- min_vel[2] = vz[index];
- }
- if (max_vel[0] < vx[index]) {
- max_vel[0] = vx[index];
- }
- if (max_vel[1] < vy[index]) {
- max_vel[1] = vy[index];
- }
- if (max_vel[2] < vz[index]) {
- max_vel[2] = vz[index];
- }
- }
- }
- }
-
- /* also apply emission maps */
- for (int i = 0; i < numflowobj; i++) {
- EmissionMap *em = &emaps[i];
-
- for (x = em->min[0]; x < em->max[0]; x++) {
- for (y = em->min[1]; y < em->max[1]; y++) {
- for (z = em->min[2]; z < em->max[2]; z++) {
- int index = smoke_get_index(
- x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]);
- float max_den = em->influence[index];
-
- /* density bounds */
- if (max_den >= sds->adapt_threshold) {
- if (min[0] > x) {
- min[0] = x;
- }
- if (min[1] > y) {
- min[1] = y;
- }
- if (min[2] > z) {
- min[2] = z;
- }
- if (max[0] < x) {
- max[0] = x;
- }
- if (max[1] < y) {
- max[1] = y;
- }
- if (max[2] < z) {
- max[2] = z;
- }
- }
- }
- }
- }
- }
-
- /* calculate new bounds based on these values */
- mul_v3_fl(min_vel, 1.0f / sds->dx);
- mul_v3_fl(max_vel, 1.0f / sds->dx);
- clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin + 1, dt);
-
- for (int i = 0; i < 3; i++) {
- /* calculate new resolution */
- res[i] = max[i] - min[i];
- total_cells *= res[i];
-
- if (new_shift[i]) {
- shift_changed = 1;
- }
-
- /* if no content set minimum dimensions */
- if (res[i] <= 0) {
- int j;
- for (j = 0; j < 3; j++) {
- min[j] = 0;
- max[j] = 1;
- res[j] = 1;
- }
- res_changed = 1;
- total_cells = 1;
- break;
- }
- if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i]) {
- res_changed = 1;
- }
- }
-
- if (res_changed || shift_changed) {
- struct FLUID_3D *fluid_old = sds->fluid;
- struct WTURBULENCE *turb_old = sds->wt;
- /* allocate new fluid data */
- BKE_smoke_reallocate_fluid(sds, sds->dx, res, 0);
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, sds->dx, res, 0);
- }
-
- /* copy values from old fluid to new */
- if (sds->total_cells > 1 && total_cells > 1) {
- /* low res smoke */
- float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r,
- *o_g, *o_b;
- float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r,
- *n_g, *n_b;
- float dummy;
- unsigned char *dummy_p;
- /* high res smoke */
- int wt_res_old[3];
- float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw,
- *o_wt_r, *o_wt_g, *o_wt_b;
- float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw,
- *n_wt_r, *n_wt_g, *n_wt_b;
-
- smoke_export(fluid_old,
- &dummy,
- &dummy,
- &o_dens,
- &o_react,
- &o_flame,
- &o_fuel,
- &o_heat,
- &o_heatold,
- &o_vx,
- &o_vy,
- &o_vz,
- &o_r,
- &o_g,
- &o_b,
- &dummy_p);
- smoke_export(sds->fluid,
- &dummy,
- &dummy,
- &n_dens,
- &n_react,
- &n_flame,
- &n_fuel,
- &n_heat,
- &n_heatold,
- &n_vx,
- &n_vy,
- &n_vz,
- &n_r,
- &n_g,
- &n_b,
- &dummy_p);
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- smoke_turbulence_export(turb_old,
- &o_wt_dens,
- &o_wt_react,
- &o_wt_flame,
- &o_wt_fuel,
- &o_wt_r,
- &o_wt_g,
- &o_wt_b,
- &o_wt_tcu,
- &o_wt_tcv,
- &o_wt_tcw);
- smoke_turbulence_get_res(turb_old, wt_res_old);
- smoke_turbulence_export(sds->wt,
- &n_wt_dens,
- &n_wt_react,
- &n_wt_flame,
- &n_wt_fuel,
- &n_wt_r,
- &n_wt_g,
- &n_wt_b,
- &n_wt_tcu,
- &n_wt_tcv,
- &n_wt_tcw);
- }
-
- for (x = sds->res_min[0]; x < sds->res_max[0]; x++) {
- for (y = sds->res_min[1]; y < sds->res_max[1]; y++) {
- for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
- /* old grid index */
- int xo = x - sds->res_min[0];
- int yo = y - sds->res_min[1];
- int zo = z - sds->res_min[2];
- int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo);
- /* new grid index */
- int xn = x - min[0] - new_shift[0];
- int yn = y - min[1] - new_shift[1];
- int zn = z - min[2] - new_shift[2];
- int index_new = smoke_get_index(xn, res[0], yn, res[1], zn);
-
- /* skip if outside new domain */
- if (xn < 0 || xn >= res[0] || yn < 0 || yn >= res[1] || zn < 0 || zn >= res[2]) {
- continue;
- }
-
- /* copy data */
- n_dens[index_new] = o_dens[index_old];
- /* heat */
- if (n_heat && o_heat) {
- n_heat[index_new] = o_heat[index_old];
- n_heatold[index_new] = o_heatold[index_old];
- }
- /* fuel */
- if (n_fuel && o_fuel) {
- n_flame[index_new] = o_flame[index_old];
- n_fuel[index_new] = o_fuel[index_old];
- n_react[index_new] = o_react[index_old];
- }
- /* color */
- if (o_r && n_r) {
- n_r[index_new] = o_r[index_old];
- n_g[index_new] = o_g[index_old];
- n_b[index_new] = o_b[index_old];
- }
- n_vx[index_new] = o_vx[index_old];
- n_vy[index_new] = o_vy[index_old];
- n_vz[index_new] = o_vz[index_old];
-
- if (sds->flags & MOD_SMOKE_HIGHRES && turb_old) {
- int i, j, k;
- /* old grid index */
- int xx_o = xo * block_size;
- int yy_o = yo * block_size;
- int zz_o = zo * block_size;
- /* new grid index */
- int xx_n = xn * block_size;
- int yy_n = yn * block_size;
- int zz_n = zn * block_size;
-
- n_wt_tcu[index_new] = o_wt_tcu[index_old];
- n_wt_tcv[index_new] = o_wt_tcv[index_old];
- n_wt_tcw[index_new] = o_wt_tcw[index_old];
-
- for (i = 0; i < block_size; i++) {
- for (j = 0; j < block_size; j++) {
- for (k = 0; k < block_size; k++) {
- int big_index_old = smoke_get_index(
- xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
- int big_index_new = smoke_get_index(
- xx_n + i, sds->res_wt[0], yy_n + j, sds->res_wt[1], zz_n + k);
- /* copy data */
- n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
- if (n_wt_flame && o_wt_flame) {
- n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
- n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
- n_wt_react[big_index_new] = o_wt_react[big_index_old];
- }
- if (n_wt_r && o_wt_r) {
- n_wt_r[big_index_new] = o_wt_r[big_index_old];
- n_wt_g[big_index_new] = o_wt_g[big_index_old];
- n_wt_b[big_index_new] = o_wt_b[big_index_old];
- }
- }
- }
- }
- }
- }
- }
- }
- }
- smoke_free(fluid_old);
- if (turb_old) {
- smoke_turbulence_free(turb_old);
- }
-
- /* set new domain dimensions */
- copy_v3_v3_int(sds->res_min, min);
- copy_v3_v3_int(sds->res_max, max);
- copy_v3_v3_int(sds->res, res);
- sds->total_cells = total_cells;
- }
-}
-
-BLI_INLINE void apply_outflow_fields(int index,
- float *density,
- float *heat,
- float *fuel,
- float *react,
- float *color_r,
- float *color_g,
- float *color_b)
-{
- density[index] = 0.f;
- if (heat) {
- heat[index] = 0.f;
- }
- if (fuel) {
- fuel[index] = 0.f;
- react[index] = 0.f;
- }
- if (color_r) {
- color_r[index] = 0.f;
- color_g[index] = 0.f;
- color_b[index] = 0.f;
- }
-}
-
-BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs,
- float emission_value,
- int index,
- float *density,
- float *heat,
- float *fuel,
- float *react,
- float *color_r,
- float *color_g,
- float *color_b)
-{
- int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
- float dens_old = density[index];
- // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
- float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density;
- float fuel_flow = emission_value * sfs->fuel_amount;
- /* add heat */
- if (heat && emission_value > 0.0f) {
- heat[index] = ADD_IF_LOWER(heat[index], sfs->temp);
- }
- /* absolute */
- if (absolute_flow) {
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
- if (dens_flow > density[index]) {
- density[index] = dens_flow;
- }
- }
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) {
- if (fuel_flow > fuel[index]) {
- fuel[index] = fuel_flow;
- }
- }
- }
- /* additive */
- else {
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
- density[index] += dens_flow;
- CLAMP(density[index], 0.0f, 1.0f);
- }
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) {
- fuel[index] += fuel_flow;
- CLAMP(fuel[index], 0.0f, 10.0f);
- }
- }
-
- /* set color */
- if (color_r && dens_flow) {
- float total_dens = density[index] / (dens_old + dens_flow);
- color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens;
- color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens;
- color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens;
- }
-
- /* set fire reaction coordinate */
- if (fuel && fuel[index] > FLT_EPSILON) {
- /* instead of using 1.0 for all new fuel add slight falloff
- * to reduce flow blockiness */
- float value = 1.0f - pow2f(1.0f - emission_value);
-
- if (value > react[index]) {
- float f = fuel_flow / fuel[index];
- react[index] = value * f + (1.0f - f) * react[index];
- CLAMP(react[index], 0.0f, value);
- }
- }
-}
-
-static void update_flowsfluids(
- Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
-{
- Object **flowobjs = NULL;
- EmissionMap *emaps = NULL;
- unsigned int numflowobj = 0;
- unsigned int flowIndex;
- int new_shift[3] = {0};
- int active_fields = sds->active_fields;
-
- /* calculate domain shift for current frame if using adaptive domain */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- int total_shift[3];
- float frame_shift_f[3];
- float ob_loc[3] = {0};
-
- mul_m4_v3(ob->obmat, ob_loc);
-
- sub_v3_v3v3(frame_shift_f, ob_loc, sds->prev_loc);
- copy_v3_v3(sds->prev_loc, ob_loc);
- /* convert global space shift to local "cell" space */
- mul_mat3_m4_v3(sds->imat, frame_shift_f);
- frame_shift_f[0] = frame_shift_f[0] / sds->cell_size[0];
- frame_shift_f[1] = frame_shift_f[1] / sds->cell_size[1];
- frame_shift_f[2] = frame_shift_f[2] / sds->cell_size[2];
- /* add to total shift */
- add_v3_v3(sds->shift_f, frame_shift_f);
- /* convert to integer */
- total_shift[0] = (int)(floorf(sds->shift_f[0]));
- total_shift[1] = (int)(floorf(sds->shift_f[1]));
- total_shift[2] = (int)(floorf(sds->shift_f[2]));
- sub_v3_v3v3_int(new_shift, total_shift, sds->shift);
- copy_v3_v3_int(sds->shift, total_shift);
-
- /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */
- sds->p0[0] = sds->dp0[0] - sds->cell_size[0] * (sds->shift_f[0] - total_shift[0] - 0.5f);
- sds->p0[1] = sds->dp0[1] - sds->cell_size[1] * (sds->shift_f[1] - total_shift[1] - 0.5f);
- sds->p0[2] = sds->dp0[2] - sds->cell_size[2] * (sds->shift_f[2] - total_shift[2] - 0.5f);
- sds->p1[0] = sds->p0[0] + sds->cell_size[0] * sds->base_res[0];
- sds->p1[1] = sds->p0[1] + sds->cell_size[1] * sds->base_res[1];
- sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2];
- }
-
- flowobjs = BKE_collision_objects_create(
- depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
-
- /* init emission maps for each flow */
- emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps");
-
- /* Prepare flow emission maps */
- for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
- Object *collob = flowobjs[flowIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
- eModifierType_Smoke);
-
- // check for initialized smoke object
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
- // we got nice flow object
- SmokeFlowSettings *sfs = smd2->flow;
- int subframes = sfs->subframes;
- EmissionMap *em = &emaps[flowIndex];
-
- /* just sample flow directly to emission map if no subframes */
- if (!subframes) {
- if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
- emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt);
- }
- else {
- emit_from_mesh(collob, sds, sfs, em, dt);
- }
- }
- /* sample subframes */
- else {
- int scene_frame = (int)DEG_get_ctime(depsgraph);
- // float scene_subframe = scene->r.subframe; // UNUSED
- int subframe;
- for (subframe = 0; subframe <= subframes; subframe++) {
- EmissionMap em_temp = {NULL};
- float sample_size = 1.0f / (float)(subframes + 1);
- float prev_frame_pos = sample_size * (float)(subframe + 1);
- float sdt = dt * sample_size;
- int hires_multiplier = 1;
-
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- /* set scene frame to match previous frame + subframe
- * or use current frame for last sample */
- if (subframe < subframes) {
- scene->r.cfra = scene_frame - 1;
- scene->r.subframe = prev_frame_pos;
- }
- else {
- scene->r.cfra = scene_frame;
- scene->r.subframe = 0.0f;
- }
-
- /* update flow object frame */
- BLI_mutex_lock(&object_update_lock);
- BKE_object_modifier_update_subframe(
- depsgraph, scene, collob, true, 5, BKE_scene_frame_get(scene), eModifierType_Smoke);
- BLI_mutex_unlock(&object_update_lock);
-
- if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
- /* emit_from_particles() updates timestep internally */
- emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt);
- if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
- hires_multiplier = 1;
- }
- }
- else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
- /* apply flow */
- emit_from_mesh(collob, sds, sfs, &em_temp, sdt);
- }
-
- /* combine emission maps */
- em_combineMaps(em,
- &em_temp,
- hires_multiplier,
- !(sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE),
- sample_size);
- em_freeData(&em_temp);
- }
- }
-
- /* update required data fields */
- if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) {
- /* activate heat field if flow produces any heat */
- if (sfs->temp) {
- active_fields |= SM_ACTIVE_HEAT;
- }
- /* activate fuel field if flow adds any fuel */
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) {
- active_fields |= SM_ACTIVE_FIRE;
- }
- /* activate color field if flows add smoke with varying colors */
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) {
- if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
- copy_v3_v3(sds->active_color, sfs->color);
- active_fields |= SM_ACTIVE_COLOR_SET;
- }
- else if (!equals_v3v3(sds->active_color, sfs->color)) {
- copy_v3_v3(sds->active_color, sfs->color);
- active_fields |= SM_ACTIVE_COLORS;
- }
- }
- }
- }
- }
-
- /* monitor active fields based on domain settings */
- /* if domain has fire, activate new fields if required */
- if (active_fields & SM_ACTIVE_FIRE) {
- /* heat is always needed for fire */
- active_fields |= SM_ACTIVE_HEAT;
- /* also activate colors if domain smoke color differs from active color */
- if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
- copy_v3_v3(sds->active_color, sds->flame_smoke_color);
- active_fields |= SM_ACTIVE_COLOR_SET;
- }
- else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) {
- copy_v3_v3(sds->active_color, sds->flame_smoke_color);
- active_fields |= SM_ACTIVE_COLORS;
- }
- }
-
- /* Adjust domain size if needed */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt);
- }
-
- /* Initialize new data fields if any */
- if (active_fields & SM_ACTIVE_HEAT) {
- smoke_ensure_heat(sds->fluid);
- }
- if (active_fields & SM_ACTIVE_FIRE) {
- smoke_ensure_fire(sds->fluid, sds->wt);
- }
- if (active_fields & SM_ACTIVE_COLORS) {
- /* initialize all smoke with "active_color" */
- smoke_ensure_colors(
- sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]);
- }
- sds->active_fields = active_fields;
-
- /* Apply emission data */
- if (sds->fluid) {
- for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
- Object *collob = flowobjs[flowIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
- eModifierType_Smoke);
-
- // check for initialized smoke object
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
- // we got nice flow object
- SmokeFlowSettings *sfs = smd2->flow;
- EmissionMap *em = &emaps[flowIndex];
-
- float *density = smoke_get_density(sds->fluid);
- float *color_r = smoke_get_color_r(sds->fluid);
- float *color_g = smoke_get_color_g(sds->fluid);
- float *color_b = smoke_get_color_b(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *react = smoke_get_react(sds->fluid);
- float *bigdensity = smoke_turbulence_get_density(sds->wt);
- float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
- float *bigreact = smoke_turbulence_get_react(sds->wt);
- float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt);
- float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt);
- float *bigcolor_b = smoke_turbulence_get_color_b(sds->wt);
- float *heat = smoke_get_heat(sds->fluid);
- float *velocity_x = smoke_get_velocity_x(sds->fluid);
- float *velocity_y = smoke_get_velocity_y(sds->fluid);
- float *velocity_z = smoke_get_velocity_z(sds->fluid);
- // unsigned char *obstacle = smoke_get_obstacle(sds->fluid);
- // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
- int bigres[3];
- float *velocity_map = em->velocity;
- float *emission_map = em->influence;
- float *emission_map_high = em->influence_high;
-
- int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
- size_t e_index, d_index, index_big;
-
- // loop through every emission map cell
- for (gx = em->min[0]; gx < em->max[0]; gx++) {
- for (gy = em->min[1]; gy < em->max[1]; gy++) {
- for (gz = em->min[2]; gz < em->max[2]; gz++) {
- /* get emission map index */
- ex = gx - em->min[0];
- ey = gy - em->min[1];
- ez = gz - em->min[2];
- e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez);
-
- /* get domain index */
- dx = gx - sds->res_min[0];
- dy = gy - sds->res_min[1];
- dz = gz - sds->res_min[2];
- d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz);
- /* make sure emission cell is inside the new domain boundary */
- if (dx < 0 || dy < 0 || dz < 0 || dx >= sds->res[0] || dy >= sds->res[1] ||
- dz >= sds->res[2]) {
- continue;
- }
-
- if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
- apply_outflow_fields(
- d_index, density, heat, fuel, react, color_r, color_g, color_b);
- }
- else { // inflow
- apply_inflow_fields(sfs,
- emission_map[e_index],
- d_index,
- density,
- heat,
- fuel,
- react,
- color_r,
- color_g,
- color_b);
-
- /* initial velocity */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index],
- velocity_map[e_index * 3]);
- velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index],
- velocity_map[e_index * 3 + 1]);
- velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index],
- velocity_map[e_index * 3 + 2]);
- }
- }
-
- /* loop through high res blocks if high res enabled */
- if (bigdensity) {
- /* Neighbor cell emission densities
- * (for high resolution smoke smooth interpolation). */
- float c000, c001, c010, c011, c100, c101, c110, c111;
-
- smoke_turbulence_get_res(sds->wt, bigres);
- block_size = sds->amplify + 1; // high res block size
-
- c000 = (ex > 0 && ey > 0 && ez > 0) ?
- emission_map[smoke_get_index(
- ex - 1, em->res[0], ey - 1, em->res[1], ez - 1)] :
- 0;
- c001 =
- (ex > 0 && ey > 0) ?
- emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez)] :
- 0;
- c010 =
- (ex > 0 && ez > 0) ?
- emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1)] :
- 0;
- c011 = (ex > 0) ?
- emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez)] :
- 0;
-
- c100 =
- (ey > 0 && ez > 0) ?
- emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1)] :
- 0;
- c101 = (ey > 0) ?
- emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez)] :
- 0;
- c110 = (ez > 0) ?
- emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] :
- 0;
- c111 = emission_map[smoke_get_index(
- ex, em->res[0], ey, em->res[1], ez)]; // this cell
-
- for (ii = 0; ii < block_size; ii++) {
- for (jj = 0; jj < block_size; jj++) {
- for (kk = 0; kk < block_size; kk++) {
-
- float fx, fy, fz, interpolated_value;
- int shift_x = 0, shift_y = 0, shift_z = 0;
-
- /* Use full sample emission map if enabled and available */
- if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) {
- interpolated_value =
- emission_map_high[smoke_get_index(ex * block_size + ii,
- em->res[0] * block_size,
- ey * block_size + jj,
- em->res[1] * block_size,
- ez * block_size + kk)]; // this cell
- }
- else if (sds->highres_sampling == SM_HRES_NEAREST) {
- /* without interpolation use same low resolution
- * block value for all hi-res blocks */
- interpolated_value = c111;
- }
- /* Fall back to interpolated */
- else {
- /* get relative block position
- * for interpolation smoothing */
- fx = (float)ii / block_size + 0.5f / block_size;
- fy = (float)jj / block_size + 0.5f / block_size;
- fz = (float)kk / block_size + 0.5f / block_size;
-
- /* calculate trilinear interpolation */
- interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) +
- c100 * fx * (1 - fy) * (1 - fz) +
- c010 * (1 - fx) * fy * (1 - fz) +
- c001 * (1 - fx) * (1 - fy) * fz +
- c101 * fx * (1 - fy) * fz +
- c011 * (1 - fx) * fy * fz +
- c110 * fx * fy * (1 - fz) + c111 * fx * fy * fz;
-
- /* add some contrast / sharpness
- * depending on hi-res block size */
- interpolated_value = (interpolated_value - 0.4f) * (block_size / 2) + 0.4f;
- CLAMP(interpolated_value, 0.0f, 1.0f);
-
- /* shift smoke block index
- * (because pixel center is actually
- * in halfway of the low res block) */
- shift_x = (dx < 1) ? 0 : block_size / 2;
- shift_y = (dy < 1) ? 0 : block_size / 2;
- shift_z = (dz < 1) ? 0 : block_size / 2;
- }
-
- /* get shifted index for current high resolution block */
- index_big = smoke_get_index(block_size * dx + ii - shift_x,
- bigres[0],
- block_size * dy + jj - shift_y,
- bigres[1],
- block_size * dz + kk - shift_z);
-
- if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
- if (interpolated_value) {
- apply_outflow_fields(index_big,
- bigdensity,
- NULL,
- bigfuel,
- bigreact,
- bigcolor_r,
- bigcolor_g,
- bigcolor_b);
- }
- }
- else { // inflow
- apply_inflow_fields(sfs,
- interpolated_value,
- index_big,
- bigdensity,
- NULL,
- bigfuel,
- bigreact,
- bigcolor_r,
- bigcolor_g,
- bigcolor_b);
- }
- } // hires loop
- }
- }
- } // bigdensity
- } // low res loop
- }
- }
-
- // free emission maps
- em_freeData(em);
-
- } // end emission
- }
- }
-
- BKE_collision_objects_free(flowobjs);
- if (emaps) {
- MEM_freeN(emaps);
- }
-}
-
-typedef struct UpdateEffectorsData {
- Scene *scene;
- SmokeDomainSettings *sds;
- ListBase *effectors;
-
- float *density;
- float *fuel;
- float *force_x;
- float *force_y;
- float *force_z;
- float *velocity_x;
- float *velocity_y;
- float *velocity_z;
- unsigned char *obstacle;
-} UpdateEffectorsData;
-
-static void update_effectors_task_cb(void *__restrict userdata,
- const int x,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- UpdateEffectorsData *data = userdata;
- SmokeDomainSettings *sds = data->sds;
-
- for (int y = 0; y < sds->res[1]; y++) {
- for (int z = 0; z < sds->res[2]; z++) {
- EffectedPoint epoint;
- float mag;
- float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
- const unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
-
- if (((data->fuel ? MAX2(data->density[index], data->fuel[index]) : data->density[index]) <
- FLT_EPSILON) ||
- data->obstacle[index]) {
- continue;
- }
-
- vel[0] = data->velocity_x[index];
- vel[1] = data->velocity_y[index];
- vel[2] = data->velocity_z[index];
-
- /* convert vel to global space */
- mag = len_v3(vel);
- mul_mat3_m4_v3(sds->obmat, vel);
- normalize_v3(vel);
- mul_v3_fl(vel, mag);
-
- voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f);
- voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f);
- voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f);
- mul_m4_v3(sds->obmat, voxelCenter);
-
- pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
- BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
-
- /* convert retvel to local space */
- mag = len_v3(retvel);
- mul_mat3_m4_v3(sds->imat, retvel);
- normalize_v3(retvel);
- mul_v3_fl(retvel, mag);
-
- // TODO dg - do in force!
- data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
- data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
- data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
- }
- }
-}
-
-static void update_effectors(
- Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
-{
- ListBase *effectors;
- /* make sure smoke flow influence is 0.0f */
- sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
- effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights);
-
- if (effectors) {
- // precalculate wind forces
- UpdateEffectorsData data;
- data.scene = scene;
- data.sds = sds;
- data.effectors = effectors;
- data.density = smoke_get_density(sds->fluid);
- data.fuel = smoke_get_fuel(sds->fluid);
- data.force_x = smoke_get_force_x(sds->fluid);
- data.force_y = smoke_get_force_y(sds->fluid);
- data.force_z = smoke_get_force_z(sds->fluid);
- data.velocity_x = smoke_get_velocity_x(sds->fluid);
- data.velocity_y = smoke_get_velocity_y(sds->fluid);
- data.velocity_z = smoke_get_velocity_z(sds->fluid);
- data.obstacle = smoke_get_obstacle(sds->fluid);
-
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(0, sds->res[0], &data, update_effectors_task_cb, &settings);
- }
-
- BKE_effectors_free(effectors);
-}
-
-static void step(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- SmokeModifierData *smd,
- Mesh *domain_me,
- float fps)
-{
- SmokeDomainSettings *sds = smd->domain;
- /* stability values copied from wturbulence.cpp */
- const int maxSubSteps = 25;
- float maxVel;
- // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size)
-
- float dt;
- float maxVelMag = 0.0f;
- int totalSubsteps;
- int substep = 0;
- float dtSubdiv;
- float gravity[3] = {0.0f, 0.0f, -1.0f};
- float gravity_mag;
-
- /* update object state */
- invert_m4_m4(sds->imat, ob->obmat);
- copy_m4_m4(sds->obmat, ob->obmat);
- smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0);
-
- /* use global gravity if enabled */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- /* map default value to 1.0 */
- mul_v3_fl(gravity, 1.0f / 9.810f);
- }
- /* convert gravity to domain space */
- gravity_mag = len_v3(gravity);
- mul_mat3_m4_v3(sds->imat, gravity);
- normalize_v3(gravity);
- mul_v3_fl(gravity, gravity_mag);
-
- /* adapt timestep for different framerates, dt = 0.1 is at 25fps */
- dt = DT_DEFAULT * (25.0f / fps);
- // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel
- maxVel = (sds->dx * 5.0f);
-
- maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale;
- totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
- totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
- totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
-
- /* Disable substeps for now, since it results in numerical instability */
- totalSubsteps = 1.0f;
-
- dtSubdiv = (float)dt / (float)totalSubsteps;
-
- // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt);
-
- for (substep = 0; substep < totalSubsteps; substep++) {
- // calc animated obstacle velocities
- update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv);
- update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps);
-
- if (sds->total_cells > 1) {
- // DG TODO? problem --> uses forces instead of velocity,
- // need to check how they need to be changed with variable dt.
- update_effectors(depsgraph, scene, ob, sds, dtSubdiv);
- smoke_step(sds->fluid, gravity, dtSubdiv);
- }
- }
-}
-
-static Mesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
-{
- Mesh *result;
- MVert *mverts;
- MPoly *mpolys;
- MLoop *mloops;
- float min[3];
- float max[3];
- float *co;
- MPoly *mp;
- MLoop *ml;
-
- int num_verts = 8;
- int num_faces = 6;
- int i;
- float ob_loc[3] = {0};
- float ob_cache_loc[3] = {0};
-
- /* dont generate any mesh if there isnt any content */
- if (sds->total_cells <= 1) {
- num_verts = 0;
- num_faces = 0;
- }
-
- result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
- mverts = result->mvert;
- mpolys = result->mpoly;
- mloops = result->mloop;
-
- if (num_verts) {
- /* volume bounds */
- madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min);
- madd_v3fl_v3fl_v3fl_v3i(max, sds->p0, sds->cell_size, sds->res_max);
-
- /* set vertices */
- /* top slab */
- co = mverts[0].co;
- co[0] = min[0];
- co[1] = min[1];
- co[2] = max[2];
- co = mverts[1].co;
- co[0] = max[0];
- co[1] = min[1];
- co[2] = max[2];
- co = mverts[2].co;
- co[0] = max[0];
- co[1] = max[1];
- co[2] = max[2];
- co = mverts[3].co;
- co[0] = min[0];
- co[1] = max[1];
- co[2] = max[2];
- /* bottom slab */
- co = mverts[4].co;
- co[0] = min[0];
- co[1] = min[1];
- co[2] = min[2];
- co = mverts[5].co;
- co[0] = max[0];
- co[1] = min[1];
- co[2] = min[2];
- co = mverts[6].co;
- co[0] = max[0];
- co[1] = max[1];
- co[2] = min[2];
- co = mverts[7].co;
- co[0] = min[0];
- co[1] = max[1];
- co[2] = min[2];
-
- /* create faces */
- /* top */
- mp = &mpolys[0];
- ml = &mloops[0 * 4];
- mp->loopstart = 0 * 4;
- mp->totloop = 4;
- ml[0].v = 0;
- ml[1].v = 1;
- ml[2].v = 2;
- ml[3].v = 3;
- /* right */
- mp = &mpolys[1];
- ml = &mloops[1 * 4];
- mp->loopstart = 1 * 4;
- mp->totloop = 4;
- ml[0].v = 2;
- ml[1].v = 1;
- ml[2].v = 5;
- ml[3].v = 6;
- /* bottom */
- mp = &mpolys[2];
- ml = &mloops[2 * 4];
- mp->loopstart = 2 * 4;
- mp->totloop = 4;
- ml[0].v = 7;
- ml[1].v = 6;
- ml[2].v = 5;
- ml[3].v = 4;
- /* left */
- mp = &mpolys[3];
- ml = &mloops[3 * 4];
- mp->loopstart = 3 * 4;
- mp->totloop = 4;
- ml[0].v = 0;
- ml[1].v = 3;
- ml[2].v = 7;
- ml[3].v = 4;
- /* front */
- mp = &mpolys[4];
- ml = &mloops[4 * 4];
- mp->loopstart = 4 * 4;
- mp->totloop = 4;
- ml[0].v = 3;
- ml[1].v = 2;
- ml[2].v = 6;
- ml[3].v = 7;
- /* back */
- mp = &mpolys[5];
- ml = &mloops[5 * 4];
- mp->loopstart = 5 * 4;
- mp->totloop = 4;
- ml[0].v = 1;
- ml[1].v = 0;
- ml[2].v = 4;
- ml[3].v = 5;
-
- /* calculate required shift to match domain's global position
- * it was originally simulated at (if object moves without smoke step) */
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->obmat, ob_loc);
- mul_m4_v3(sds->obmat, ob_cache_loc);
- sub_v3_v3v3(sds->obj_shift_f, ob_cache_loc, ob_loc);
- /* convert shift to local space and apply to vertices */
- mul_mat3_m4_v3(ob->imat, sds->obj_shift_f);
- /* apply */
- for (i = 0; i < num_verts; i++) {
- add_v3_v3(mverts[i].co, sds->obj_shift_f);
- }
- }
-
- BKE_mesh_calc_edges(result, false, false);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
- return result;
-}
-
-static void smokeModifier_process(
- SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
-{
- const int scene_framenr = (int)DEG_get_ctime(depsgraph);
-
- if ((smd->type & MOD_SMOKE_TYPE_FLOW)) {
- if (scene_framenr >= smd->time) {
- smokeModifier_init(smd, ob, scene_framenr, me);
- }
-
- if (smd->flow->mesh) {
- BKE_id_free(NULL, smd->flow->mesh);
- }
- smd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
-
- if (scene_framenr > smd->time) {
- smd->time = scene_framenr;
- }
- else if (scene_framenr < smd->time) {
- smd->time = scene_framenr;
- smokeModifier_reset_ex(smd, false);
- }
- }
- else if (smd->type & MOD_SMOKE_TYPE_COLL) {
- if (scene_framenr >= smd->time) {
- smokeModifier_init(smd, ob, scene_framenr, me);
- }
-
- if (smd->coll) {
- if (smd->coll->mesh) {
- BKE_id_free(NULL, smd->coll->mesh);
- }
-
- smd->coll->mesh = BKE_mesh_copy_for_eval(me, false);
- }
-
- smd->time = scene_framenr;
- if (scene_framenr < smd->time) {
- smokeModifier_reset_ex(smd, false);
- }
- }
- else if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- SmokeDomainSettings *sds = smd->domain;
- PointCache *cache = NULL;
- PTCacheID pid;
- int startframe, endframe, framenr;
- float timescale;
-
- framenr = scene_framenr;
-
- cache = sds->point_cache[0];
- BKE_ptcache_id_from_smoke(&pid, ob, smd);
- BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
-
- if (!smd->domain->fluid || framenr == startframe) {
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- smokeModifier_reset_ex(smd, false);
- BKE_ptcache_validate(cache, framenr);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- }
-
- if (!smd->domain->fluid && (framenr != startframe) &&
- (smd->domain->flags & MOD_SMOKE_FILE_LOAD) == 0 && (cache->flag & PTCACHE_BAKED) == 0) {
- return;
- }
-
- smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD;
- CLAMP(framenr, startframe, endframe);
-
- /* If already viewing a pre/after frame, no need to reload */
- if ((smd->time == framenr) && (framenr != scene_framenr)) {
- return;
- }
-
- if (smokeModifier_init(smd, ob, scene_framenr, me) == 0) {
- printf("bad smokeModifier_init\n");
- return;
- }
-
- /* only calculate something when we advanced a single frame */
- /* don't simulate if viewing start frame, but scene frame is not real start frame */
- bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr);
-
- /* try to read from cache */
- if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) {
- BKE_ptcache_validate(cache, framenr);
- smd->time = framenr;
- return;
- }
-
- if (!can_simulate) {
- return;
- }
-
-# ifdef DEBUG_TIME
- double start = PIL_check_seconds_timer();
-# endif
-
- /* if on second frame, write cache for first frame */
- if ((int)smd->time == startframe &&
- (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
- BKE_ptcache_write(&pid, startframe);
- }
-
- // set new time
- smd->time = scene_framenr;
-
- /* do simulation */
-
- // simulate the actual smoke (c++ code in intern/smoke)
- // DG: interesting commenting this line + deactivating loading of noise files
- if (framenr != startframe) {
- if (sds->flags & MOD_SMOKE_DISSOLVE) {
- /* low res dissolve */
- smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
- /* high res dissolve */
- if (sds->wt) {
- smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
- }
- }
-
- step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base);
- }
-
- // create shadows before writing cache so they get stored
- smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph));
-
- if (sds->wt && sds->total_cells > 1) {
- smoke_turbulence_step(sds->wt, sds->fluid);
- }
-
- BKE_ptcache_validate(cache, framenr);
- if (framenr != startframe) {
- BKE_ptcache_write(&pid, framenr);
- }
-
-# ifdef DEBUG_TIME
- double end = PIL_check_seconds_timer();
- printf("Frame: %d, Time: %f\n\n", (int)smd->time, (float)(end - start));
-# endif
- }
-}
-
-struct Mesh *smokeModifier_do(
- SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
-{
- /* lock so preview render does not read smoke data while it gets modified */
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
- }
-
- smokeModifier_process(smd, depsgraph, scene, ob, me);
-
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
- }
-
- /* return generated geometry for adaptive domain */
- Mesh *result;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
- smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) {
- result = createDomainGeometry(smd->domain, ob);
- BKE_mesh_copy_settings(result, me);
- }
- else {
- result = BKE_mesh_copy_for_eval(me, false);
- }
-
- /* Smoke simulation needs a texture space relative to the adaptive domain bounds, not the
- * original mesh. So recompute it at this point in the modifier stack. See T58492. */
- BKE_mesh_texspace_calc(result);
-
- return result;
-}
-
-static float calc_voxel_transp(
- float *result, float *input, int res[3], int *pixel, float *tRay, float correct)
-{
- const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
-
- // T_ray *= T_vox
- *tRay *= expf(input[index] * correct);
-
- if (result[index] < 0.0f) {
- result[index] = *tRay;
- }
-
- return *tRay;
-}
-
-static void bresenham_linie_3D(int x1,
- int y1,
- int z1,
- int x2,
- int y2,
- int z2,
- float *tRay,
- bresenham_callback cb,
- float *result,
- float *input,
- int res[3],
- float correct)
-{
- int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
- int pixel[3];
-
- pixel[0] = x1;
- pixel[1] = y1;
- pixel[2] = z1;
-
- dx = x2 - x1;
- dy = y2 - y1;
- dz = z2 - z1;
-
- x_inc = (dx < 0) ? -1 : 1;
- l = abs(dx);
- y_inc = (dy < 0) ? -1 : 1;
- m = abs(dy);
- z_inc = (dz < 0) ? -1 : 1;
- n = abs(dz);
- dx2 = l << 1;
- dy2 = m << 1;
- dz2 = n << 1;
-
- if ((l >= m) && (l >= n)) {
- err_1 = dy2 - l;
- err_2 = dz2 - l;
- for (i = 0; i < l; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) {
- break;
- }
- if (err_1 > 0) {
- pixel[1] += y_inc;
- err_1 -= dx2;
- }
- if (err_2 > 0) {
- pixel[2] += z_inc;
- err_2 -= dx2;
- }
- err_1 += dy2;
- err_2 += dz2;
- pixel[0] += x_inc;
- }
- }
- else if ((m >= l) && (m >= n)) {
- err_1 = dx2 - m;
- err_2 = dz2 - m;
- for (i = 0; i < m; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) {
- break;
- }
- if (err_1 > 0) {
- pixel[0] += x_inc;
- err_1 -= dy2;
- }
- if (err_2 > 0) {
- pixel[2] += z_inc;
- err_2 -= dy2;
- }
- err_1 += dx2;
- err_2 += dz2;
- pixel[1] += y_inc;
- }
- }
- else {
- err_1 = dy2 - n;
- err_2 = dx2 - n;
- for (i = 0; i < n; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) {
- break;
- }
- if (err_1 > 0) {
- pixel[1] += y_inc;
- err_1 -= dz2;
- }
- if (err_2 > 0) {
- pixel[0] += x_inc;
- err_2 -= dz2;
- }
- err_1 += dy2;
- err_2 += dx2;
- pixel[2] += z_inc;
- }
- }
- cb(result, input, res, pixel, tRay, correct);
-}
-
-static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer)
-{
- float bv[6] = {0};
- float light[3];
- int a, z, slabsize = sds->res[0] * sds->res[1], size = sds->res[0] * sds->res[1] * sds->res[2];
- float *density = smoke_get_density(sds->fluid);
- float correct = -7.0f * sds->dx;
-
- if (!get_light(view_layer, light)) {
- return;
- }
-
- /* convert light pos to sim cell space */
- mul_m4_v3(sds->imat, light);
- light[0] = (light[0] - sds->p0[0]) / sds->cell_size[0] - 0.5f - (float)sds->res_min[0];
- light[1] = (light[1] - sds->p0[1]) / sds->cell_size[1] - 0.5f - (float)sds->res_min[1];
- light[2] = (light[2] - sds->p0[2]) / sds->cell_size[2] - 0.5f - (float)sds->res_min[2];
-
- for (a = 0; a < size; a++) {
- sds->shadow[a] = -1.0f;
- }
-
- /* calculate domain bounds in sim cell space */
- // 0,2,4 = 0.0f
- bv[1] = (float)sds->res[0]; // x
- bv[3] = (float)sds->res[1]; // y
- bv[5] = (float)sds->res[2]; // z
-
- for (z = 0; z < sds->res[2]; z++) {
- size_t index = z * slabsize;
- int x, y;
-
- for (y = 0; y < sds->res[1]; y++) {
- for (x = 0; x < sds->res[0]; x++, index++) {
- float voxelCenter[3];
- float pos[3];
- int cell[3];
- float tRay = 1.0;
-
- if (sds->shadow[index] >= 0.0f) {
- continue;
- }
- voxelCenter[0] = (float)x;
- voxelCenter[1] = (float)y;
- voxelCenter[2] = (float)z;
-
- // get starting cell (light pos)
- if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) {
- // we're outside -> use point on side of domain
- cell[0] = (int)floor(pos[0]);
- cell[1] = (int)floor(pos[1]);
- cell[2] = (int)floor(pos[2]);
- }
- else {
- // we're inside -> use light itself
- cell[0] = (int)floor(light[0]);
- cell[1] = (int)floor(light[1]);
- cell[2] = (int)floor(light[2]);
- }
- /* clamp within grid bounds */
- CLAMP(cell[0], 0, sds->res[0] - 1);
- CLAMP(cell[1], 0, sds->res[1] - 1);
- CLAMP(cell[2], 0, sds->res[2] - 1);
-
- bresenham_linie_3D(cell[0],
- cell[1],
- cell[2],
- x,
- y,
- z,
- &tRay,
- calc_voxel_transp,
- sds->shadow,
- density,
- sds->res,
- correct);
-
- // convention -> from a RGBA float array, use G value for tRay
- sds->shadow[index] = tRay;
- }
- }
- }
-}
-
-/* get smoke velocity and density at given coordinates
- * returns fluid density or -1.0f if outside domain. */
-float BKE_smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
-{
- SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke);
- zero_v3(velocity);
-
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && smd->domain->fluid) {
- SmokeDomainSettings *sds = smd->domain;
- float time_mult = 25.f * DT_DEFAULT;
- float vel_mag;
- float *velX = smoke_get_velocity_x(sds->fluid);
- float *velY = smoke_get_velocity_y(sds->fluid);
- float *velZ = smoke_get_velocity_z(sds->fluid);
- float density = 0.0f, fuel = 0.0f;
- float pos[3];
- copy_v3_v3(pos, position);
- smoke_pos_to_cell(sds, pos);
-
- /* check if point is outside domain max bounds */
- if (pos[0] < sds->res_min[0] || pos[1] < sds->res_min[1] || pos[2] < sds->res_min[2]) {
- return -1.0f;
- }
- if (pos[0] > sds->res_max[0] || pos[1] > sds->res_max[1] || pos[2] > sds->res_max[2]) {
- return -1.0f;
- }
-
- /* map pos between 0.0 - 1.0 */
- pos[0] = (pos[0] - sds->res_min[0]) / ((float)sds->res[0]);
- pos[1] = (pos[1] - sds->res_min[1]) / ((float)sds->res[1]);
- pos[2] = (pos[2] - sds->res_min[2]) / ((float)sds->res[2]);
-
- /* check if point is outside active area */
- if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) {
- return 0.0f;
- }
- if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) {
- return 0.0f;
- }
- }
-
- /* get interpolated velocity */
- velocity[0] = BLI_voxel_sample_trilinear(velX, sds->res, pos) * sds->global_size[0] *
- time_mult;
- velocity[1] = BLI_voxel_sample_trilinear(velY, sds->res, pos) * sds->global_size[1] *
- time_mult;
- velocity[2] = BLI_voxel_sample_trilinear(velZ, sds->res, pos) * sds->global_size[2] *
- time_mult;
-
- /* convert velocity direction to global space */
- vel_mag = len_v3(velocity);
- mul_mat3_m4_v3(sds->obmat, velocity);
- normalize_v3(velocity);
- mul_v3_fl(velocity, vel_mag);
-
- /* use max value of fuel or smoke density */
- density = BLI_voxel_sample_trilinear(smoke_get_density(sds->fluid), sds->res, pos);
- if (smoke_has_fuel(sds->fluid)) {
- fuel = BLI_voxel_sample_trilinear(smoke_get_fuel(sds->fluid), sds->res, pos);
- }
- return MAX2(density, fuel);
- }
- return -1.0f;
-}
-
-int BKE_smoke_get_data_flags(SmokeDomainSettings *sds)
-{
- int flags = 0;
-
- if (sds->fluid) {
- if (smoke_has_heat(sds->fluid)) {
- flags |= SM_ACTIVE_HEAT;
- }
- if (smoke_has_fuel(sds->fluid)) {
- flags |= SM_ACTIVE_FIRE;
- }
- if (smoke_has_colors(sds->fluid)) {
- flags |= SM_ACTIVE_COLORS;
- }
- }
-
- return flags;
-}
-
-#endif /* WITH_SMOKE */
-
-bool BKE_smoke_show_highres(Scene *scene, SmokeDomainSettings *sds)
-{
- if ((sds->viewsettings & MOD_SMOKE_VIEW_SHOW_HIGHRES) == 0) {
- return false;
- }
- if (scene->r.mode & R_SIMPLIFY) {
- return !scene->r.simplify_smoke_ignore_highres;
- }
- return true;
-}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 11d2314ace3..33a9875151a 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -2519,7 +2519,7 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags)
struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
- struct Scene *scene,
+ const struct Scene *scene,
float (*vertCos)[3],
SubsurfFlags flags)
{
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index f4e89160487..b1ae71c609f 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -558,7 +558,7 @@ void BKE_texture_pointdensity_init_data(PointDensity *pd)
pd->falloff_curve = BKE_curvemapping_add(1, 0, 0, 1, 1);
pd->falloff_curve->preset = CURVE_PRESET_LINE;
- pd->falloff_curve->cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
+ pd->falloff_curve->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
BKE_curvemap_reset(pd->falloff_curve->cm,
&pd->falloff_curve->clipr,
pd->falloff_curve->preset,
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index dd2b182474e..3e449fa6b25 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -26,6 +26,7 @@
#include "BLI_string_utils.h"
#include "BLI_listbase.h"
+#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -202,8 +203,10 @@ WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain)
}
void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *hook)
{
- /* workspaces should never be freed before wm (during which we call this function) */
- BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces));
+ /* workspaces should never be freed before wm (during which we call this function).
+ * However, when running in background mode, loading a blend file may allocate windows (that need
+ * to be freed) without creating workspaces. This happens in BlendfileLoadingBaseTest. */
+ BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces) || G.background);
/* Free relations for this hook */
for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
diff --git a/source/blender/blenlib/BLI_dial_2d.h b/source/blender/blenlib/BLI_dial_2d.h
index 460b75b3fb7..71b0683d149 100644
--- a/source/blender/blenlib/BLI_dial_2d.h
+++ b/source/blender/blenlib/BLI_dial_2d.h
@@ -40,7 +40,7 @@
*
* dial = BLI_dial_initialize(start_position, threshold);
*
- * angle = BLI_dial_angle(dial, curent_position);
+ * angle = BLI_dial_angle(dial, current_position);
*
* MEM_freeN(dial);
* \endcode
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index f2c0bf1e6f1..eb926c51ba9 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -406,6 +406,9 @@ GSet *BLI_gset_str_new(const char *info);
GSet *BLI_gset_pair_new_ex(const char *info, const unsigned int nentries_reserve)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GSet *BLI_gset_int_new_ex(const char *info,
+ const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GSet *BLI_gset_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/** \} */
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index b305e919e76..70fa633eeac 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -93,7 +93,6 @@ enum {
/* Use a priority queue to process nodes in the optimal order (for slow callbacks) */
BVH_OVERLAP_USE_THREADING = (1 << 0),
BVH_OVERLAP_RETURN_PAIRS = (1 << 1),
- BVH_OVERLAP_BREAK_ON_FIRST = (1 << 2),
};
enum {
/* Use a priority queue to process nodes in the optimal order (for slow callbacks) */
@@ -167,7 +166,8 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
/* optional callback to test the overlap before adding (must be thread-safe!) */
BVHTree_OverlapCallback callback,
void *userdata,
- int flag);
+ const uint max_interactions,
+ const int flag);
BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
const BVHTree *tree2,
unsigned int *r_overlap_tot,
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 2128b0a4711..2049f368578 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -92,6 +92,9 @@ float volume_tetrahedron_signed_v3(const float v1[3],
const float v3[3],
const float v4[3]);
+float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3]);
+float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3]);
+
bool is_edge_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
@@ -649,7 +652,7 @@ void orthographic_m4(float mat[4][4],
const float farClip);
void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y);
-void planes_from_projmat(float mat[4][4],
+void planes_from_projmat(const float mat[4][4],
float left[4],
float right[4],
float top[4],
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 814b13fa47f..ac0f5f44c74 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -205,6 +205,8 @@ void mul_transposed_m3_v3(const float M[3][3], float r[3]);
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]);
void mul_m3_v3_double(const float M[3][3], double r[3]);
+void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4]);
+
void mul_m3_fl(float R[3][3], float f);
void mul_m4_fl(float R[4][4], float f);
void mul_mat3_m4_fl(float R[4][4], float f);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 9fbd0227b7e..b39e979ec47 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -323,6 +323,8 @@ MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_
MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool equals_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool equals_v2v2_int(const int v1[2], const int v2[2]) ATTR_WARN_UNUSED_RESULT;
+
MINLINE bool compare_v2v2(const float a[2],
const float b[2],
const float limit) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 05c3d43a0de..24346454a3f 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -19,7 +19,6 @@
#include <string.h> /* for memset() */
-struct Link;
struct ListBase;
/** \file
diff --git a/source/blender/blenlib/intern/BLI_ghash_utils.c b/source/blender/blenlib/intern/BLI_ghash_utils.c
index 1c6484acbdf..63559da5bd7 100644
--- a/source/blender/blenlib/intern/BLI_ghash_utils.c
+++ b/source/blender/blenlib/intern/BLI_ghash_utils.c
@@ -278,4 +278,13 @@ GSet *BLI_gset_pair_new(const char *info)
return BLI_gset_pair_new_ex(info, 0);
}
+GSet *BLI_gset_int_new_ex(const char *info, const uint nentries_reserve)
+{
+ return BLI_gset_new_ex(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, info, nentries_reserve);
+}
+GSet *BLI_gset_int_new(const char *info)
+{
+ return BLI_gset_int_new_ex(info, 0);
+}
+
/** \} */
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index ae862c5ece5..252e7caa149 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -122,6 +122,7 @@ typedef struct BVHOverlapData_Shared {
typedef struct BVHOverlapData_Thread {
BVHOverlapData_Shared *shared;
struct BLI_Stack *overlap; /* store BVHTreeOverlap */
+ uint max_interactions;
/* use for callbacks */
int thread;
} BVHOverlapData_Thread;
@@ -1127,7 +1128,7 @@ static void tree_overlap_traverse(BVHOverlapData_Thread *data_thread,
}
}
else {
- for (j = 0; j < data->tree2->tree_type; j++) {
+ for (j = 0; j < data->tree1->tree_type; j++) {
if (node1->children[j]) {
tree_overlap_traverse(data_thread, node1->children[j], node2);
}
@@ -1174,7 +1175,7 @@ static void tree_overlap_traverse_cb(BVHOverlapData_Thread *data_thread,
}
}
else {
- for (j = 0; j < data->tree2->tree_type; j++) {
+ for (j = 0; j < data->tree1->tree_type; j++) {
if (node1->children[j]) {
tree_overlap_traverse_cb(data_thread, node1->children[j], node2);
}
@@ -1186,9 +1187,9 @@ static void tree_overlap_traverse_cb(BVHOverlapData_Thread *data_thread,
/**
* a version of #tree_overlap_traverse_cb that that break on first true return.
*/
-static bool tree_overlap_traverse_first_cb(BVHOverlapData_Thread *data_thread,
- const BVHNode *node1,
- const BVHNode *node2)
+static bool tree_overlap_traverse_num(BVHOverlapData_Thread *data_thread,
+ const BVHNode *node1,
+ const BVHNode *node2)
{
BVHOverlapData_Shared *data = data_thread->shared;
int j;
@@ -1213,20 +1214,23 @@ static bool tree_overlap_traverse_first_cb(BVHOverlapData_Thread *data_thread,
overlap->indexA = node1->index;
overlap->indexB = node2->index;
}
- return true;
+ return (--data_thread->max_interactions) == 0;
}
}
else {
for (j = 0; j < node2->totnode; j++) {
- if (tree_overlap_traverse_first_cb(data_thread, node1, node2->children[j])) {
+ if (tree_overlap_traverse_num(data_thread, node1, node2->children[j])) {
return true;
}
}
}
}
else {
+ const uint max_interactions = data_thread->max_interactions;
for (j = 0; j < node1->totnode; j++) {
- tree_overlap_traverse_first_cb(data_thread, node1->children[j], node2);
+ if (tree_overlap_traverse_num(data_thread, node1->children[j], node2)) {
+ data_thread->max_interactions = max_interactions;
+ }
}
}
}
@@ -1250,7 +1254,12 @@ static void bvhtree_overlap_task_cb(void *__restrict userdata,
BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j];
BVHOverlapData_Shared *data_shared = data->shared;
- if (data_shared->callback) {
+ if (data->max_interactions) {
+ tree_overlap_traverse_num(data,
+ data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
+ data_shared->tree2->nodes[data_shared->tree2->totleaf]);
+ }
+ else if (data_shared->callback) {
tree_overlap_traverse_cb(data,
data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
data_shared->tree2->nodes[data_shared->tree2->totleaf]);
@@ -1262,19 +1271,6 @@ static void bvhtree_overlap_task_cb(void *__restrict userdata,
}
}
-static void bvhtree_overlap_first_task_cb(void *__restrict userdata,
- const int j,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j];
- BVHOverlapData_Shared *data_shared = data->shared;
-
- tree_overlap_traverse_first_cb(
- data,
- data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
- data_shared->tree2->nodes[data_shared->tree2->totleaf]);
-}
-
BVHTreeOverlap *BLI_bvhtree_overlap_ex(
const BVHTree *tree1,
const BVHTree *tree2,
@@ -1282,16 +1278,18 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
/* optional callback to test the overlap before adding (must be thread-safe!) */
BVHTree_OverlapCallback callback,
void *userdata,
- int flag)
+ const uint max_interactions,
+ const int flag)
{
- bool use_threading = (flag & BVH_OVERLAP_USE_THREADING) != 0;
bool overlap_pairs = (flag & BVH_OVERLAP_RETURN_PAIRS) != 0;
- bool break_on_first = (flag & BVH_OVERLAP_BREAK_ON_FIRST) != 0;
+ bool use_threading = (flag & BVH_OVERLAP_USE_THREADING) != 0 &&
+ (tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
- /* `RETURN_PAIRS` was not implemented without `BREAK_ON_FIRST`. */
- BLI_assert(overlap_pairs || break_on_first);
+ /* `RETURN_PAIRS` was not implemented without `max_interations`. */
+ BLI_assert(overlap_pairs || max_interactions);
- const int thread_num = BLI_bvhtree_overlap_thread_num(tree1);
+ const int root_node_len = BLI_bvhtree_overlap_thread_num(tree1);
+ const int thread_num = use_threading ? root_node_len : 1;
int j;
size_t total = 0;
BVHTreeOverlap *overlap = NULL, *to = NULL;
@@ -1306,12 +1304,14 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
return NULL;
}
+ const BVHNode *root1 = tree1->nodes[tree1->totleaf];
+ const BVHNode *root2 = tree2->nodes[tree2->totleaf];
+
start_axis = min_axis(tree1->start_axis, tree2->start_axis);
stop_axis = min_axis(tree1->stop_axis, tree2->stop_axis);
/* fast check root nodes for collision before doing big splitting + traversal */
- if (!tree_overlap_test(
- tree1->nodes[tree1->totleaf], tree2->nodes[tree2->totleaf], start_axis, stop_axis)) {
+ if (!tree_overlap_test(root1, root2, start_axis, stop_axis)) {
return NULL;
}
@@ -1328,19 +1328,29 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
/* init BVHOverlapData_Thread */
data[j].shared = &data_shared;
data[j].overlap = overlap_pairs ? BLI_stack_new(sizeof(BVHTreeOverlap), __func__) : NULL;
+ data[j].max_interactions = max_interactions;
/* for callback */
data[j].thread = j;
}
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = use_threading && (tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
- BLI_task_parallel_range(0,
- thread_num,
- data,
- break_on_first ? bvhtree_overlap_first_task_cb : bvhtree_overlap_task_cb,
- &settings);
+ if (use_threading) {
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1;
+ BLI_task_parallel_range(0, root_node_len, data, bvhtree_overlap_task_cb, &settings);
+ }
+ else {
+ if (max_interactions) {
+ tree_overlap_traverse_num(data, root1, root2);
+ }
+ else if (callback) {
+ tree_overlap_traverse_cb(data, root1, root2);
+ }
+ else {
+ tree_overlap_traverse(data, root1, root2);
+ }
+ }
if (overlap_pairs) {
for (j = 0; j < thread_num; j++) {
@@ -1374,6 +1384,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
r_overlap_tot,
callback,
userdata,
+ 0,
BVH_OVERLAP_USE_THREADING | BVH_OVERLAP_RETURN_PAIRS);
}
diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c
index 27f7a2a4430..4faaf1605e0 100644
--- a/source/blender/blenlib/intern/delaunay_2d.c
+++ b/source/blender/blenlib/intern/delaunay_2d.c
@@ -53,6 +53,7 @@ typedef struct CDTVert {
SymEdge *symedge; /* Some edge attached to it. */
LinkNode *input_ids; /* List of corresponding vertex input ids. */
int index; /* Index into array that cdt keeps. */
+ int visit_index; /* Which visit epoch has this been seen. */
} CDTVert;
typedef struct CDTEdge {
@@ -110,7 +111,9 @@ static void dump_v(const CDTVert *v, const char *lab);
static void dump_se_cycle(const SymEdge *se, const char *lab, const int limit);
static void dump_id_list(const LinkNode *id_list, const char *lab);
static void dump_cdt(const CDT_state *cdt, const char *lab);
+static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const char *lab);
static void cdt_draw(CDT_state *cdt, const char *lab);
+static void write_cdt_input_to_file(const CDT_input *inp);
static void validate_face_centroid(SymEdge *se);
static void validate_cdt(CDT_state *cdt, bool check_all_tris);
#endif
@@ -151,14 +154,11 @@ static int CCW_test(const double a[2], const double b[2], const double c[2], con
return 0;
}
-/** return true if a -- b -- c are in that order, assuming they are on a straight line. */
-static bool in_line(const double a[2], const double b[2], const double c[2])
+/** return true if a -- b -- c are in that order, assuming they are on a straight line according to
+ * CCW_test. */
+static bool in_line(const double a[2], const double b[2], const double c[2], double eps)
{
- double dir_ab[2], dir_ac[2];
-
- sub_v2_v2v2_db(dir_ab, a, b);
- sub_v2_v2v2_db(dir_ac, a, c);
- return dot_v2v2_db(dir_ab, dir_ac) >= 0.0;
+ return fabs(len_v2v2_db(a, c) - (len_v2v2_db(a, b) + len_v2v2_db(b, c))) <= eps;
}
#ifndef NDEBUG
@@ -208,6 +208,7 @@ static CDTVert *add_cdtvert(CDT_state *cdt, double x, double y)
}
BLI_assert(cdt->vert_array_len < cdt->vert_array_len_alloc);
v->index = cdt->vert_array_len;
+ v->visit_index = 0;
cdt->vert_array[cdt->vert_array_len++] = v;
return v;
}
@@ -365,8 +366,8 @@ static CDTEdge *add_diagonal(CDT_state *cdt, SymEdge *s1, SymEdge *s2)
CDTFace *fold, *fnew;
SymEdge *sdiag, *sdiagsym;
SymEdge *s1prev, *s1prevsym, *s2prev, *s2prevsym, *se;
- BLI_assert(reachable(s1, s2, 20));
- BLI_assert(reachable(s2, s1, 20));
+ BLI_assert(reachable(s1, s2, 2000));
+ BLI_assert(reachable(s2, s1, 2000));
fold = s1->face;
fnew = add_cdtface(cdt);
s1prev = prev(s1);
@@ -385,7 +386,7 @@ static CDTEdge *add_diagonal(CDT_state *cdt, SymEdge *s1, SymEdge *s2)
s2->rot = sdiagsym;
sdiagsym->rot = s2prevsym;
#ifdef DEBUG_CDT
- BLI_assert(reachable(s2, sdiag, 20));
+ BLI_assert(reachable(s2, sdiag, 2000));
#endif
for (se = s2; se != sdiag; se = se->next) {
se->face = fnew;
@@ -1505,7 +1506,8 @@ static void add_edge_constraint(
SymEdge *se;
CDTEdge *edge;
int ccw1, ccw2, isect;
- int i, search_count;
+ int i, search_count, visit;
+ double curco[2];
double lambda;
const double epsilon = cdt->epsilon;
bool done, state_through_vert;
@@ -1553,7 +1555,7 @@ static void add_edge_constraint(
* in = a
* out = b
*
- * crossings[0] will have in = NULL, and crossings[last] will have out = NULL
+ * crossings[0] will have in = NULL, and crossings[last] will have out = NULL.
*/
if (r_edges) {
*r_edges = NULL;
@@ -1569,6 +1571,9 @@ static void add_edge_constraint(
dump_se(vse1, " se1");
dump_se(vse2, " se2");
}
+ if (dbg_level > 2) {
+ dump_cdt(cdt, "before insert_segment");
+ }
}
#endif
if (v1 == v2) {
@@ -1579,181 +1584,292 @@ static void add_edge_constraint(
#endif
return;
}
- state_through_vert = true;
+ /* Quick check for special case where segment is one of edges from v1. */
+ tstart = t = vse1;
done = false;
- t = vse1;
- search_count = 0;
- while (!done) {
- /* Invariant: crossings[0 .. BLI_array_len(crossings)] has crossing info for path up to
- * but not including the crossing of edge t, which will either be through a vert
- * (if state_through_vert is true) or through edge t not at either end.
- * In the latter case, t->face is the face that ray v1--v2 goes through after path-so-far.
- */
-#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(
- stderr, "top of insert_segment main loop, state_through_vert=%d\n", state_through_vert);
- dump_se_cycle(t, "current t ", 4);
- }
-#endif
- if (state_through_vert) {
- /* Invariant: ray v1--v2 contains t->vert. */
- cdata.in = (BLI_array_len(crossings) == 0) ? NULL : t;
- cdata.out = NULL; /* To be filled in if this isn't final. */
+ do {
+ if (t->next->vert == v2) {
+ cdata.in = NULL;
+ cdata.out = t->next;
cdata.lambda = 0.0;
cdata.vert = t->vert;
BLI_array_append(crossings, cdata);
- if (t->vert == v2) {
+ cdata.in = t->next->rot;
+ cdata.out = NULL;
+ cdata.lambda = 0.0;
+ cdata.vert = v2;
+ BLI_array_append(crossings, cdata);
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "found v2, so done\n");
- }
+ if (dbg_level > 1) {
+ fprintf(stderr, "special one segment case\n");
+ dump_se(t, " ");
+ }
#endif
- done = true;
+ done = true;
+ break;
+ }
+ t = t->rot;
+ } while (t != tstart);
+ if (!done) {
+ /* To prevent infinite loop in the face of epsilon tests that might lead us back to
+ * an already-visited (vertex, face) pair, use visit indices.
+ */
+ visit = ++cdt->visit_count;
+ state_through_vert = true;
+ done = false;
+ t = vse1;
+ search_count = 0;
+ while (!done) {
+ /* Invariant: crossings[0 .. BLI_array_len(crossings)] has crossing info for path up to
+ * but not including the crossing of edge t, which will either be through a vert
+ * (if state_through_vert is true) or through edge t not at either end.
+ * In the latter case, t->face is the face that ray v1--v2 goes through after path-so-far.
+ * Rather than continually looking for intersection of v1--v2, we keep track of
+ * last vertex or intersection point in curco,because that may be slightly off the ray
+ * v1--v2.
+ */
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr,
+ "top of insert_segment main loop, state_through_vert=%d\n",
+ state_through_vert);
+ dump_se_cycle(t, "current t ", 4);
}
- else {
- /* Do ccw scan of triangles around t->vert to find exit triangle for ray v1--v2. */
- tstart = t;
- tout = NULL;
- do {
- va = t->next->vert;
- vb = t->next->next->vert;
- ccw1 = CCW_test(t->vert->co, va->co, v2->co, epsilon);
- ccw2 = CCW_test(t->vert->co, vb->co, v2->co, epsilon);
+#endif
+ BLI_assert(t->vert->visit_index != visit || t->face->visit_index != visit);
+ t->vert->visit_index = visit;
+ t->face->visit_index = visit;
+ if (state_through_vert) {
+ /* Invariant: ray vcur--v2 contains t->vert. */
+ cdata.in = (BLI_array_len(crossings) == 0) ? NULL : t;
+ cdata.out = NULL; /* To be filled in if this isn't final. */
+ cdata.lambda = 0.0;
+ cdata.vert = t->vert;
+ BLI_array_append(crossings, cdata);
+ if (t->vert == v2) {
#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr, "non-final through vert case\n");
- dump_v(va, " va");
- dump_v(vb, " vb");
- fprintf(stderr, "ccw1=%d, ccw2=%d\n", ccw1, ccw2);
+ if (dbg_level > 0) {
+ fprintf(stderr, "found v2, so done\n");
}
#endif
- if (ccw1 == 0 && in_line(t->vert->co, va->co, v2->co)) {
+ done = true;
+ }
+ else {
+ /* Do ccw scan of triangles around t->vert to find exit triangle for ray vcur--v2. */
+ tstart = t;
+ tout = NULL;
+ do {
+ va = t->next->vert;
+ vb = t->next->next->vert;
+ ccw1 = CCW_test(t->vert->co, va->co, v2->co, epsilon);
+ ccw2 = CCW_test(t->vert->co, vb->co, v2->co, epsilon);
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "non-final through vert case\n");
+ dump_v(va, " va");
+ dump_v(vb, " vb");
+ fprintf(stderr, "ccw1=%d, ccw2=%d\n", ccw1, ccw2);
+ }
+#endif
+ if (ccw1 == 0 && in_line(t->vert->co, va->co, v2->co, epsilon) &&
+ va->visit_index != visit) {
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "ray goes through va\n");
+ if (dbg_level > 0) {
+ fprintf(stderr, "ray goes through va\n");
+ }
+#endif
+ state_through_vert = true;
+ tout = t;
+ t = t->next;
+ break;
}
+ else if (ccw2 == 0 && in_line(t->vert->co, vb->co, v2->co, epsilon) &&
+ vb->visit_index != visit) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "ray goes through vb\n");
+ }
#endif
- state_through_vert = true;
- tout = t;
- t = t->next;
- break;
- }
- else if (ccw2 == 0 && in_line(t->vert->co, vb->co, v2->co)) {
+ state_through_vert = true;
+ t = t->next->next;
+ tout = sym(t);
+ break;
+ }
+ else if (ccw1 > 0 && ccw2 < 0 &&
+ (t->next->vert->visit_index != visit ||
+ t->next->face->visit_index != visit)) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "segment intersects\n");
+ }
+#endif
+ state_through_vert = false;
+ tout = t;
+ t = t->next;
+ break;
+ }
+ t = t->rot;
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "ray goes through vb\n");
+ if (dbg_level > 1) {
+ dump_se_cycle(t, "next rot tri", 4);
}
#endif
- state_through_vert = true;
- t = t->next->next;
- tout = sym(t);
- break;
- }
- else if (ccw1 > 0 && ccw2 < 0) {
+ } while (t != tstart);
+ if (tout == NULL) {
+ /* With exact arithmetic this shouldn't happen, but maybe the epsilon tests made it so
+ * that we want to go back to a previous vertex.
+ * As desperation measure, pick unvisited vertex that is closest in line with
+ * destination.
+ */
#ifdef DEBUG_CDT
if (dbg_level > 0) {
- fprintf(stderr, "segment intersects\n");
+ fprintf(stderr, "add_edge_constraint desperation search\n");
}
#endif
- state_through_vert = false;
- tout = t;
- t = t->next;
- break;
- }
- t = t->rot;
+ SymEdge *bestt = NULL;
+ double dot, bestdot = -2.0;
+ double dir_tv_v2[2], dir_tvnext_v2[2];
+ sub_v2_v2v2_db(dir_tv_v2, v2->co, t->vert->co);
+ do {
+ if (t->next->vert->visit_index != visit) {
+ sub_v2_v2v2_db(dir_tvnext_v2, v2->co, t->next->vert->co);
+ dot = dot_v2v2_db(dir_tv_v2, dir_tvnext_v2);
+ if (dot > bestdot) {
+ bestdot = dot;
+ bestt = t->next;
+ }
+ }
+ t = t->rot;
+ } while (t != tstart);
+ if (bestt == NULL) {
+ /* No unvisited place to go! Give up on adding this edge constraint. */
+#ifdef DEBUG_CDT
+ fprintf(stderr, "could not add edge constraint\n");
+#endif
+ return;
+ }
+ else {
#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- dump_se_cycle(t, "next rot tri", 4);
- }
+ if (dbg_level > 0) {
+ fprintf(stderr, "add_edge_constraint desperation search chose to go through\n");
+ dump_v(bestt->vert, "desperation vert");
+ }
#endif
- } while (t != tstart);
- BLI_assert(tout != NULL); /* TODO: something sensible for "this can't happen" */
- crossings[BLI_array_len(crossings) - 1].out = tout;
- }
- }
- else { /* State is "through edge", not "through vert" */
- /* Invariant: ray v1--v2 intersects segment t->edge, not at either end.
- * and t->face is the face we have just passed through. */
- va = t->vert;
- vb = t->next->vert;
-#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr, "through edge case\n");
- dump_v(va, " va");
- dump_v(vb, " vb");
+ tout = bestt;
+ t = t->next;
+ }
+ }
+ crossings[BLI_array_len(crossings) - 1].out = tout;
+ }
}
-#endif
- isect = isect_seg_seg_v2_lambda_mu_db(va->co, vb->co, v1->co, v2->co, &lambda, NULL);
- /* TODO: something sensible for "this can't happen" */
- BLI_assert(isect == ISECT_LINE_LINE_CROSS);
- UNUSED_VARS_NDEBUG(isect);
+ else { /* State is "through edge", not "through vert" */
+ /* Invariant: ray v1--v2 intersects segment t->edge, not at either end.
+ * and t->face is the face we have just passed through.
+ * Whatever we make t next should not have both vert and face visited.
+ */
+ va = t->vert;
+ vb = t->next->vert;
+ /* Get curco; cdata should have data from last time through the loop still. */
+ if (cdata.lambda == 0.0) {
+ copy_v2_v2_db(curco, cdata.vert->co);
+ }
+ else {
+ interp_v2_v2v2_db(curco, cdata.in->vert->co, cdata.in->next->vert->co, lambda);
+ }
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "intersect point at %f along va--vb\n", lambda);
- if (dbg_level == 1) {
+ if (dbg_level > 1) {
+ fprintf(stderr, "through edge case, curco=(%f,%f)\n", F2(curco));
dump_v(va, " va");
dump_v(vb, " vb");
}
- }
#endif
- tout = sym(t)->next;
- cdata.in = t;
- cdata.out = tout;
- cdata.lambda = lambda;
- cdata.vert = NULL; /* To be filled in with edge split vertex later. */
- BLI_array_append(crossings, cdata);
+ isect = isect_seg_seg_v2_lambda_mu_db(va->co, vb->co, curco, v2->co, &lambda, NULL);
+ if (isect != ISECT_LINE_LINE_CROSS) {
+ /* Shouldn't happen. Just pick something. */
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- dump_se_cycle(tout, "next search tri", 4);
- }
+ if (dbg_level > 1) {
+ fprintf(stderr, "add_edge_constraint no intersect found, using lambda = 0.5\n");
+ }
#endif
- /* 'tout' is 'symedge' from 'vb' to third vertex, 'vc'. */
- BLI_assert(tout->vert == va);
- vc = tout->next->vert;
- ccw1 = CCW_test(v1->co, v2->co, vc->co, epsilon);
+ lambda = 0.5;
+ }
#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr, "now searching with third vertex ");
- dump_v(vc, "vc");
- fprintf(stderr, "ccw(v1, v2, vc) = %d\n", ccw1);
- }
+ if (dbg_level > 0) {
+ fprintf(stderr, "intersect point at %f along va--vb\n", lambda);
+ if (dbg_level == 1) {
+ dump_v(va, " va");
+ dump_v(vb, " vb");
+ }
+ }
#endif
- if (ccw1 == -1) {
- /* v1--v2 should intersect vb--vc. */
+ tout = sym(t)->next;
+ cdata.in = t;
+ cdata.out = tout;
+ cdata.lambda = lambda;
+ cdata.vert = NULL; /* To be filled in with edge split vertex later. */
+ BLI_array_append(crossings, cdata);
#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr, "v1--v2 intersects vb--vc\n");
+ if (dbg_level > 0) {
+ dump_se_cycle(tout, "next search tri", 4);
+ dump_se(tout, "tout");
}
#endif
- t = tout->next;
- state_through_vert = false;
- }
- else if (ccw1 == 1) {
- /* v1--v2 should intersect va--vc. */
+ /* 'tout' is 'symedge' from 'va' to third vertex, 'vc'. */
+ BLI_assert(tout->vert == va);
+ vc = tout->next->vert;
+ ccw1 = CCW_test(curco, v2->co, vc->co, epsilon);
#ifdef DEBUG_CDT
if (dbg_level > 1) {
- fprintf(stderr, "v1--v2 intersects va--vc\n");
+ fprintf(stderr, "now searching with third vertex ");
+ dump_v(vc, "vc");
+ fprintf(stderr, "ccw(vcur, v2, vc) = %d\n", ccw1);
}
#endif
- t = tout;
- state_through_vert = false;
- }
- else {
- /* ccw1 == 0. */
+ if (ccw1 == -1 && (vc->visit_index != visit || tout->next->face->visit_index != visit)) {
+ /* vcur--v2 should intersect vb--vc. */
#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr, "ccw==0 case, so going through or to vc\n");
+ if (dbg_level > 1) {
+ fprintf(stderr, "curco--v2 intersects vb--vc\n");
+ }
+#endif
+ t = tout->next;
+ state_through_vert = false;
}
+ else if (ccw1 == 1 && tout->face->visit_index != visit) {
+ /* vcur--v2 should intersect va--vc. */
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "curco--v2 intersects va--vc\n");
+ }
+#endif
+ t = tout;
+ state_through_vert = false;
+ }
+ else if (ccw1 == 0 && vc->visit_index != visit) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "ccw==0 case, so going through or to vc\n");
+ }
#endif
- t = tout->next;
- state_through_vert = true;
+ t = tout->next;
+ state_through_vert = true;
+ }
+ else {
+#ifdef DEBUG_CDT
+ fprintf(stderr, "add_edge_constraint desperation search 2\n");
+#endif
+ if (tout->face->visit_index != visit) {
+ /* Treat as if an intersection of va-vc. */
+ t = tout;
+ state_through_vert = false;
+ }
+ }
+ }
+ if (++search_count > 10000) {
+ fprintf(stderr, "infinite loop? bailing out\n");
+ BLI_assert(0); /* Catch these while developing. */
+ break;
}
- }
- if (++search_count > 10000) {
- fprintf(stderr, "infinite loop? bailing out\n");
- BLI_assert(0); /* Catch these while developing. */
- break;
}
}
#ifdef DEBUG_CDT
@@ -1968,7 +2084,7 @@ static void dissolve_symedge(CDT_state *cdt, SymEdge *se)
if (se->face->symedge == se) {
se->face->symedge = se->next;
}
- if (symse->face->symedge == se) {
+ if (symse->face->symedge == symse) {
symse->face->symedge = symse->next;
}
}
@@ -2380,7 +2496,13 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
CDTEdge *face_edge;
SymEdge *face_symedge;
#ifdef DEBUG_CDT
- int dbg_level = 1;
+ int dbg_level = 0;
+#endif
+
+#ifdef DEBUG_CDT
+ if (dbg_level == -1) {
+ write_cdt_input_to_file(input);
+ }
#endif
if ((nv > 0 && input->vert_coords == NULL) || (ne > 0 && input->edges == NULL) ||
@@ -2446,6 +2568,15 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
continue;
}
add_edge_constraint(cdt, verts[v1], verts[v2], i, NULL);
+#ifdef DEBUG_CDT
+ if (dbg_level > 3) {
+ char namebuf[60];
+ sprintf(namebuf, "after edge constraint %d = (%d,%d)\n", i, v1, v2);
+ cdt_draw(cdt, namebuf);
+ dump_cdt(cdt, namebuf);
+ validate_cdt(cdt, true);
+ }
+#endif
}
#ifdef DEBUG_CDT
if (dbg_level > 2) {
@@ -2579,20 +2710,37 @@ void BLI_delaunay_2d_cdt_free(CDT_result *result)
#ifdef DEBUG_CDT
-static void dump_se(const SymEdge *se, const char *lab)
+static const char *vertname(const CDTVert *v)
{
- if (se->next) {
- fprintf(
- stderr, "%s((%.3f,%.3f)->(%.3f,%.3f))\n", lab, F2(se->vert->co), F2(se->next->vert->co));
+ static char vertnamebuf[20];
+
+ if (v->index < 4) {
+ sprintf(vertnamebuf, "[%c]", "ABCD"[v->index]);
}
else {
- fprintf(stderr, "%s((%.3f,%.3f)->NULL)\n", lab, F2(se->vert->co));
+ sprintf(vertnamebuf, "[%d]", v->index - 4);
}
+ return vertnamebuf;
}
static void dump_v(const CDTVert *v, const char *lab)
{
- fprintf(stderr, "%s(%.3f,%.3f)\n", lab, F2(v->co));
+ fprintf(stderr, "%s%s(%.3f,%.3f)\n", lab, vertname(v), F2(v->co));
+}
+
+static void dump_se(const SymEdge *se, const char *lab)
+{
+ if (se->next) {
+ fprintf(stderr,
+ "%s%s((%.3f,%.3f)->(%.3f,%.3f))\n",
+ lab,
+ vertname(se->vert),
+ F2(se->vert->co),
+ F2(se->next->vert->co));
+ }
+ else {
+ fprintf(stderr, "%s%s((%.3f,%.3f)->NULL)\n", lab, vertname(se->vert), F2(se->vert->co));
+ }
}
static void dump_se_cycle(const SymEdge *se, const char *lab, const int limit)
@@ -2622,21 +2770,12 @@ static void dump_id_list(const LinkNode *id_list, const char *lab)
}
}
-static const char *vertname(CDTVert *v)
-{
- static char vertnamebuf[20];
-
- if (v->index < 4) {
- sprintf(vertnamebuf, "[%c]", "ABCD"[v->index]);
- }
- else {
- sprintf(vertnamebuf, "[%d]", v->index - 4);
- }
- return vertnamebuf;
-}
-
+/* If filter_fn != NULL, only dump vert v its edges when filter_fn(cdt, v, filter_data) is true. */
# define PL(p) (POINTER_AS_UINT(p) & 0xFFFF)
-static void dump_cdt(const CDT_state *cdt, const char *lab)
+static void dump_cdt_filtered(const CDT_state *cdt,
+ bool (*filter_fn)(const CDT_state *, int, void *),
+ void *filter_data,
+ const char *lab)
{
LinkNode *ln;
CDTVert *v, *vother;
@@ -2648,6 +2787,9 @@ static void dump_cdt(const CDT_state *cdt, const char *lab)
fprintf(stderr, "\nCDT %s\n", lab);
fprintf(stderr, "\nVERTS\n");
for (i = 0; i < cdt->vert_array_len; i++) {
+ if (filter_fn && !filter_fn(cdt, i, filter_data)) {
+ continue;
+ }
v = cdt->vert_array[i];
fprintf(stderr, "%s %x: (%f,%f) symedge=%x\n", vertname(v), PL(v), F2(v->co), PL(v->symedge));
dump_id_list(v->input_ids, " ");
@@ -2664,6 +2806,9 @@ static void dump_cdt(const CDT_state *cdt, const char *lab)
fprintf(stderr, "\n");
}
}
+ if (filter_fn) {
+ return;
+ }
fprintf(stderr, "\nEDGES\n");
for (ln = cdt->edges; ln; ln = ln->next) {
e = (CDTEdge *)ln->link;
@@ -2709,6 +2854,55 @@ static void dump_cdt(const CDT_state *cdt, const char *lab)
}
# undef PL
+static void dump_cdt(const CDT_state *cdt, const char *lab)
+{
+ dump_cdt_filtered(cdt, NULL, NULL, lab);
+}
+
+typedef struct ReachableFilterData {
+ int vstart_index;
+ int maxdist;
+} ReachableFilterData;
+
+/* Stupid algorithm will repeat itself. Don't use for large n. */
+static bool reachable_filter(const CDT_state *cdt, int v_index, void *filter_data)
+{
+ CDTVert *v;
+ SymEdge *se;
+ ReachableFilterData *rfd_in = (ReachableFilterData *)filter_data;
+ ReachableFilterData rfd_next;
+
+ if (v_index == rfd_in->vstart_index) {
+ return true;
+ }
+ if (rfd_in->maxdist <= 0 || v_index < 0 || v_index >= cdt->vert_array_len) {
+ return false;
+ }
+ else {
+ v = cdt->vert_array[v_index];
+ se = v->symedge;
+ if (se != NULL) {
+ rfd_next.vstart_index = rfd_in->vstart_index;
+ rfd_next.maxdist = rfd_in->maxdist - 1;
+ do {
+ if (reachable_filter(cdt, se->next->vert->index, &rfd_next)) {
+ return true;
+ }
+ se = se->rot;
+ } while (se != v->symedge);
+ }
+ }
+ return false;
+}
+
+static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const char *lab)
+{
+ ReachableFilterData rfd;
+ rfd.vstart_index = v;
+ rfd.maxdist = maxdist;
+ dump_cdt_filtered(cdt, reachable_filter, &rfd, lab);
+}
+
/**
* Make an html file with svg in it to display the argument cdt.
* Mouse-overs will reveal the coordinates of vertices and edges.
@@ -2716,8 +2910,12 @@ static void dump_cdt(const CDT_state *cdt, const char *lab)
* The first call creates DRAWFILE; subsequent calls append to it.
*/
# define DRAWFILE "/tmp/debug_draw.html"
-# define MAX_DRAW_WIDTH 1000
-# define MAX_DRAW_HEIGHT 700
+# define MAX_DRAW_WIDTH 2000
+# define MAX_DRAW_HEIGHT 1400
+# define THIN_LINE 1
+# define THICK_LINE 3
+# define VERT_RADIUS 3
+# define DRAW_VERT_LABELS 1
static void cdt_draw(CDT_state *cdt, const char *lab)
{
static bool append = false;
@@ -2727,9 +2925,7 @@ static void cdt_draw(CDT_state *cdt, const char *lab)
double maxx = cdt->maxx + draw_margin;
double miny = cdt->miny - draw_margin;
double maxy = cdt->maxy + draw_margin;
- double width = maxx - minx;
- double height = maxy - miny;
- double aspect = height / width;
+ double width, height, aspect;
int view_width, view_height;
double scale;
LinkNode *ln;
@@ -2737,6 +2933,10 @@ static void cdt_draw(CDT_state *cdt, const char *lab)
CDTEdge *e;
int i, strokew;
+ /* Note: to debug a small area: assign custom min's/max's here. */
+ width = maxx - minx;
+ height = maxy - miny;
+ aspect = height / width;
view_width = MAX_DRAW_WIDTH;
view_height = (int)(view_width * aspect);
if (view_height > MAX_DRAW_HEIGHT) {
@@ -2767,28 +2967,36 @@ static void cdt_draw(CDT_state *cdt, const char *lab)
}
u = e->symedges[0].vert;
v = e->symedges[1].vert;
- strokew = is_constrained_edge(e) ? 5 : 2;
+ strokew = is_constrained_edge(e) ? THICK_LINE : THIN_LINE;
fprintf(f,
"<line fill=\"none\" stroke=\"black\" stroke-width=\"%d\" "
- "x1=\"%.3f\" y1=\"%.3f\" x2=\"%.3f\" y2=\"%.3f\">\n",
+ "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\">\n",
strokew,
SX(u->co[0]),
SY(u->co[1]),
SX(v->co[0]),
SY(v->co[1]));
- fprintf(
- f, " <title>(%.3f,%.3f)(%.3f,%.3f)</title>\n", u->co[0], u->co[1], v->co[0], v->co[1]);
+ fprintf(f, " <title>%s", vertname(u));
+ fprintf(f, "%s</title>\n", vertname(v));
fprintf(f, "</line>\n");
}
i = cdt->output_prepared ? NUM_BOUND_VERTS : 0;
for (; i < cdt->vert_array_len; i++) {
v = cdt->vert_array[i];
fprintf(f,
- "<circle fill=\"black\" cx=\"%.3f\" cy=\"%.3f\" r=\"5\">\n",
+ "<circle fill=\"black\" cx=\"%f\" cy=\"%f\" r=\"%d\">\n",
SX(v->co[0]),
- SY(v->co[1]));
- fprintf(f, " <title>(%.3f,%.3f)</title>\n", v->co[0], v->co[1]);
+ SY(v->co[1]),
+ VERT_RADIUS);
+ fprintf(f, " <title>%s(%.3f,%.3f)</title>\n", vertname(v), v->co[0], v->co[1]);
fprintf(f, "</circle>\n");
+# if DRAW_VERT_LABELS
+ fprintf(f,
+ "<text x=\"%f\" y=\"%f\" font-size=\"small\">%s</text>\n",
+ SX(v->co[0]) + VERT_RADIUS,
+ SY(v->co[1]) - VERT_RADIUS,
+ vertname(v));
+# endif
}
fprintf(f, "</svg>\n</div>\n");
@@ -2798,6 +3006,28 @@ static void cdt_draw(CDT_state *cdt, const char *lab)
# undef SY
}
+# define CDTFILE "/tmp/cdtinput.txt"
+static void write_cdt_input_to_file(const CDT_input *inp)
+{
+ int i, j;
+ FILE *f = fopen(CDTFILE, "w");
+
+ fprintf(f, "%d %d %d\n", inp->verts_len, inp->edges_len, inp->faces_len);
+ for (i = 0; i < inp->verts_len; i++) {
+ fprintf(f, "%.17f %.17f\n", inp->vert_coords[i][0], inp->vert_coords[i][1]);
+ }
+ for (i = 0; i < inp->edges_len; i++) {
+ fprintf(f, "%d %d\n", inp->edges[i][0], inp->edges[i][1]);
+ }
+ for (i = 0; i < inp->faces_len; i++) {
+ for (j = 0; j < inp->faces_len_table[i]; j++) {
+ fprintf(f, "%d ", inp->faces[j + inp->faces_start_table[i]]);
+ }
+ fprintf(f, "\n");
+ }
+ fclose(f);
+}
+
# ifndef NDEBUG /* Only used in assert. */
/**
* Is a visible from b: i.e., ab crosses no edge of cdt?
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 4c86b9d3396..a1c88edca6f 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -58,6 +58,10 @@ MINLINE float pow4f(float x)
{
return pow2f(pow2f(x));
}
+MINLINE float pow5f(float x)
+{
+ return pow4f(x) * x;
+}
MINLINE float pow7f(float x)
{
return pow2f(pow3f(x)) * x;
@@ -359,6 +363,18 @@ MINLINE int mod_i(int i, int n)
return (i % n + n) % n;
}
+MINLINE float fractf(float a)
+{
+ return a - floorf(a);
+}
+
+/* Adapted from godotengine math_funcs.h. */
+MINLINE float wrapf(float value, float max, float min)
+{
+ float range = max - min;
+ return (range != 0.0f) ? value - (range * floorf((value - min) / range)) : min;
+}
+
MINLINE float min_ff(float a, float b)
{
return (a < b) ? a : b;
@@ -367,6 +383,17 @@ MINLINE float max_ff(float a, float b)
{
return (a > b) ? a : b;
}
+/* See: https://www.iquilezles.org/www/articles/smin/smin.htm. */
+MINLINE float smoothminf(float a, float b, float c)
+{
+ if (c != 0.0f) {
+ float h = max_ff(c - fabsf(a - b), 0.0f) / c;
+ return min_ff(a, b) - h * h * h * c * (1.0f / 6.0f);
+ }
+ else {
+ return min_ff(a, b);
+ }
+}
MINLINE double min_dd(double a, double b)
{
@@ -500,6 +527,19 @@ MINLINE float signf(float f)
return (f < 0.f) ? -1.f : 1.f;
}
+MINLINE float compatible_signf(float f)
+{
+ if (f > 0.0f) {
+ return 1.0f;
+ }
+ if (f < 0.0f) {
+ return -1.0f;
+ }
+ else {
+ return 0.0f;
+ }
+}
+
MINLINE int signum_i_ex(float a, float eps)
{
if (a > eps) {
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 24575e02328..449d0f6d07b 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -300,6 +300,25 @@ float volume_tetrahedron_signed_v3(const float v1[3],
return determinant_m3_array(m) / 6.0f;
}
+/**
+ * The volume from a triangle that is made into a tetrahedron.
+ * This uses a simplified formula where the tip of the tetrahedron is in the world origin.
+ * Using this method, the total volume of a closed triangle mesh can be calculated.
+ * Note that you need to divide the result by 6 to get the actual volume.
+ */
+float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3])
+{
+ float v_cross[3];
+ cross_v3_v3v3(v_cross, v1, v2);
+ float tetra_volume = dot_v3v3(v_cross, v3);
+ return tetra_volume;
+}
+
+float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3])
+{
+ return volume_tri_tetrahedron_signed_v3_6x(v1, v2, v3) / 6.0f;
+}
+
/********************************* Distance **********************************/
/* distance p to line v1-v2
@@ -4711,7 +4730,7 @@ void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x
*
* plane parameters can be NULL if you do not need them.
*/
-void planes_from_projmat(float mat[4][4],
+void planes_from_projmat(const float mat[4][4],
float left[4],
float right[4],
float top[4],
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 5118d8a698e..4d8a2f72eca 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -1235,6 +1235,27 @@ bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
#endif
}
+/**
+ * Combines transformations, handling scale separately in a manner equivalent
+ * to the Aligned Inherit Scale mode, in order to avoid creating shear.
+ * If A scale is uniform, the result is equivalent to ordinary multiplication.
+ */
+void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4])
+{
+ float loc_a[3], rot_a[3][3], size_a[3];
+ float loc_b[3], rot_b[3][3], size_b[3];
+ float loc_r[3], rot_r[3][3], size_r[3];
+
+ mat4_to_loc_rot_size(loc_a, rot_a, size_a, A);
+ mat4_to_loc_rot_size(loc_b, rot_b, size_b, B);
+
+ mul_v3_m4v3(loc_r, A, loc_b);
+ mul_m3_m3m3_uniq(rot_r, rot_a, rot_b);
+ mul_v3_v3v3(size_r, size_a, size_b);
+
+ loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
+}
+
/****************************** Linear Algebra *******************************/
void transpose_m3(float mat[3][3])
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index b4b53a1dd58..67bc5c2fa50 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -1220,6 +1220,11 @@ MINLINE bool equals_v4v4(const float v1[4], const float v2[4])
return ((v1[0] == v2[0]) && (v1[1] == v2[1]) && (v1[2] == v2[2]) && (v1[3] == v2[3]));
}
+MINLINE bool equals_v2v2_int(const int v1[2], const int v2[2])
+{
+ return ((v1[0] == v2[0]) && (v1[1] == v2[1]));
+}
+
MINLINE bool compare_v2v2(const float v1[2], const float v2[2], const float limit)
{
return (compare_ff(v1[0], v2[0], limit) && compare_ff(v1[1], v2[1], limit));
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index a81092be51b..20e34eee123 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -83,7 +83,7 @@
#include "DNA_sdna_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_speaker_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
@@ -113,6 +113,7 @@
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
+#include "BKE_fluid.h"
#include "BKE_global.h" // for G
#include "BKE_gpencil_modifier.h"
#include "BKE_idcode.h"
@@ -239,7 +240,7 @@
/* local prototypes */
static void read_libraries(FileData *basefd, ListBase *mainlist);
static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
-static void direct_link_modifiers(FileData *fd, ListBase *lb);
+static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob);
static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
@@ -1909,9 +1910,11 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
if (ima->cache) {
oldnewmap_insert(fd->imamap, ima->cache, ima->cache, 0);
}
- for (a = 0; a < TEXTARGET_COUNT; a++) {
- if (ima->gputexture[a]) {
- oldnewmap_insert(fd->imamap, ima->gputexture[a], ima->gputexture[a], 0);
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ for (a = 0; a < TEXTARGET_COUNT; a++) {
+ if (tile->gputexture[a] != NULL) {
+ oldnewmap_insert(fd->imamap, tile->gputexture[a], tile->gputexture[a], 0);
+ }
}
}
if (ima->rr) {
@@ -1955,8 +1958,10 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
if (ima->cache == NULL) {
ima->gpuflag = 0;
ima->gpuframenr = INT_MAX;
- for (i = 0; i < TEXTARGET_COUNT; i++) {
- ima->gputexture[i] = NULL;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ for (i = 0; i < TEXTARGET_COUNT; i++) {
+ tile->gputexture[i] = NULL;
+ }
}
ima->rr = NULL;
}
@@ -1964,8 +1969,10 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
slot->render = newimaadr(fd, slot->render);
}
- for (i = 0; i < TEXTARGET_COUNT; i++) {
- ima->gputexture[i] = newimaadr(fd, ima->gputexture[i]);
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ for (i = 0; i < TEXTARGET_COUNT; i++) {
+ tile->gputexture[i] = newimaadr(fd, tile->gputexture[i]);
+ }
}
ima->rr = newimaadr(fd, ima->rr);
}
@@ -4256,18 +4263,24 @@ static void direct_link_image(FileData *fd, Image *ima)
ima->cache = NULL;
}
+ link_list(fd, &ima->tiles);
+
/* if not restored, we keep the binded opengl index */
if (!ima->cache) {
ima->gpuflag = 0;
ima->gpuframenr = INT_MAX;
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- ima->gputexture[i] = NULL;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ tile->gputexture[i] = NULL;
+ }
}
ima->rr = NULL;
}
else {
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- ima->gputexture[i] = newimaadr(fd, ima->gputexture[i]);
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ tile->gputexture[i] = newimaadr(fd, tile->gputexture[i]);
+ }
}
ima->rr = newimaadr(fd, ima->rr);
}
@@ -4302,7 +4315,9 @@ static void direct_link_image(FileData *fd, Image *ima)
BLI_listbase_clear(&ima->anims);
ima->preview = direct_link_preview_image(fd, ima->preview);
ima->stereo3d_format = newdataadr(fd, ima->stereo3d_format);
- ima->ok = 1;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ tile->ok = 1;
+ }
}
/** \} */
@@ -4622,7 +4637,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
part->instance_object = newlibadr(fd, part->id.lib, part->instance_object);
part->instance_collection = newlibadr_us(fd, part->id.lib, part->instance_collection);
- part->eff_group = newlibadr(fd, part->id.lib, part->eff_group);
+ part->force_group = newlibadr(fd, part->id.lib, part->force_group);
part->bb_ob = newlibadr(fd, part->id.lib, part->bb_ob);
part->collision_group = newlibadr(fd, part->id.lib, part->collision_group);
@@ -4633,7 +4648,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group);
}
else {
- part->effector_weights = BKE_effector_add_weights(part->eff_group);
+ part->effector_weights = BKE_effector_add_weights(part->force_group);
}
if (part->instance_weights.first && part->instance_collection) {
@@ -4715,7 +4730,7 @@ static void direct_link_particlesettings(FileData *fd, ParticleSettings *part)
part->effector_weights = newdataadr(fd, part->effector_weights);
if (!part->effector_weights) {
- part->effector_weights = BKE_effector_add_weights(part->eff_group);
+ part->effector_weights = BKE_effector_add_weights(part->force_group);
}
link_list(fd, &part->instance_weights);
@@ -5358,12 +5373,12 @@ static void lib_link_object(FileData *fd, Main *main)
}
{
- SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob,
- eModifierType_Smoke);
+ FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob,
+ eModifierType_Fluid);
- if (smd && (smd->type == MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- /* Flag for refreshing the simulation after loading. */
- smd->domain->flags |= MOD_SMOKE_FILE_LOAD;
+ if (mmd && (mmd->type == MOD_FLUID_TYPE_DOMAIN) && mmd->domain) {
+ /* Flag for refreshing the simulation after loading */
+ mmd->domain->flags |= FLUID_DOMAIN_FILE_LOAD;
}
}
@@ -5471,7 +5486,121 @@ static void direct_link_pose(FileData *fd, bPose *pose)
}
}
-static void direct_link_modifiers(FileData *fd, ListBase *lb)
+/* TODO(sergey): Find a better place for this.
+ *
+ * Unfortunately, this can not be done as a regular do_versions() since the modifier type is
+ * set to NONE, so the do_versions code wouldn't know where the modifier came from.
+ *
+ * The best approach seems to have the functionality in versioning_280.c but still call the
+ * function from #direct_link_modifiers().
+ */
+
+/* Domain, inflow, ... */
+static void modifier_ensure_type(FluidModifierData *fluid_modifier_data, int type)
+{
+ fluid_modifier_data->type = type;
+ BKE_fluid_modifier_free(fluid_modifier_data);
+ BKE_fluid_modifier_create_type_data(fluid_modifier_data);
+}
+
+/**
+ * \note The old_modifier_data is NOT linked.
+ * This means that in order to access sub-data pointers #newdataadr is to be used.
+ */
+static ModifierData *modifier_replace_with_fluid(FileData *fd,
+ Object *object,
+ ListBase *modifiers,
+ ModifierData *old_modifier_data)
+{
+ ModifierData *new_modifier_data = modifier_new(eModifierType_Fluid);
+ FluidModifierData *fluid_modifier_data = (FluidModifierData *)new_modifier_data;
+
+ if (old_modifier_data->type == eModifierType_Fluidsim) {
+ FluidsimModifierData *old_fluidsim_modifier_data = (FluidsimModifierData *)old_modifier_data;
+ FluidsimSettings *old_fluidsim_settings = newdataadr(fd, old_fluidsim_modifier_data->fss);
+ switch (old_fluidsim_settings->type) {
+ case OB_FLUIDSIM_ENABLE:
+ modifier_ensure_type(fluid_modifier_data, 0);
+ break;
+ case OB_FLUIDSIM_DOMAIN:
+ modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_DOMAIN);
+ BKE_fluid_domain_type_set(object, fluid_modifier_data->domain, FLUID_DOMAIN_TYPE_LIQUID);
+ break;
+ case OB_FLUIDSIM_FLUID:
+ modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_FLOW);
+ BKE_fluid_flow_type_set(object, fluid_modifier_data->flow, FLUID_FLOW_TYPE_LIQUID);
+ /* No need to emit liquid far away from surface. */
+ fluid_modifier_data->flow->surface_distance = 0.0f;
+ break;
+ case OB_FLUIDSIM_OBSTACLE:
+ modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_EFFEC);
+ BKE_fluid_effector_type_set(
+ object, fluid_modifier_data->effector, FLUID_EFFECTOR_TYPE_COLLISION);
+ break;
+ case OB_FLUIDSIM_INFLOW:
+ modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_FLOW);
+ BKE_fluid_flow_type_set(object, fluid_modifier_data->flow, FLUID_FLOW_TYPE_LIQUID);
+ BKE_fluid_flow_behavior_set(object, fluid_modifier_data->flow, FLUID_FLOW_BEHAVIOR_INFLOW);
+ /* No need to emit liquid far away from surface. */
+ fluid_modifier_data->flow->surface_distance = 0.0f;
+ break;
+ case OB_FLUIDSIM_OUTFLOW:
+ modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_FLOW);
+ BKE_fluid_flow_type_set(object, fluid_modifier_data->flow, FLUID_FLOW_TYPE_LIQUID);
+ BKE_fluid_flow_behavior_set(
+ object, fluid_modifier_data->flow, FLUID_FLOW_BEHAVIOR_OUTFLOW);
+ break;
+ case OB_FLUIDSIM_PARTICLE:
+ /* "Particle" type objects not being used by Mantaflow fluid simulations.
+ * Skip this object, secondary particles can only be enabled through the domain object. */
+ break;
+ case OB_FLUIDSIM_CONTROL:
+ /* "Control" type objects not being used by Mantaflow fluid simulations.
+ * Use guiding type instead which is similar. */
+ modifier_ensure_type(fluid_modifier_data, MOD_FLUID_TYPE_EFFEC);
+ BKE_fluid_effector_type_set(
+ object, fluid_modifier_data->effector, FLUID_EFFECTOR_TYPE_GUIDE);
+ break;
+ }
+ }
+ else if (old_modifier_data->type == eModifierType_Smoke) {
+ SmokeModifierData *old_smoke_modifier_data = (SmokeModifierData *)old_modifier_data;
+ modifier_ensure_type(fluid_modifier_data, old_smoke_modifier_data->type);
+ if (fluid_modifier_data->type == MOD_FLUID_TYPE_DOMAIN) {
+ BKE_fluid_domain_type_set(object, fluid_modifier_data->domain, FLUID_DOMAIN_TYPE_GAS);
+ }
+ else if (fluid_modifier_data->type == MOD_FLUID_TYPE_FLOW) {
+ BKE_fluid_flow_type_set(object, fluid_modifier_data->flow, FLUID_FLOW_TYPE_SMOKE);
+ }
+ else if (fluid_modifier_data->type == MOD_FLUID_TYPE_EFFEC) {
+ BKE_fluid_effector_type_set(
+ object, fluid_modifier_data->effector, FLUID_EFFECTOR_TYPE_COLLISION);
+ }
+ }
+
+ /* Replace modifier data in the stack. */
+ new_modifier_data->next = old_modifier_data->next;
+ new_modifier_data->prev = old_modifier_data->prev;
+ if (new_modifier_data->prev != NULL) {
+ new_modifier_data->prev->next = new_modifier_data;
+ }
+ if (new_modifier_data->next != NULL) {
+ new_modifier_data->next->prev = new_modifier_data;
+ }
+ if (modifiers->first == old_modifier_data) {
+ modifiers->first = new_modifier_data;
+ }
+ if (modifiers->last == old_modifier_data) {
+ modifiers->last = new_modifier_data;
+ }
+
+ /* Free old modifier data. */
+ MEM_freeN(old_modifier_data);
+
+ return new_modifier_data;
+}
+
+static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob)
{
ModifierData *md;
@@ -5481,12 +5610,41 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
md->error = NULL;
md->runtime = NULL;
+ /* Modifier data has been allocated as a part of data migration process and
+ * no reading of nested fields from file is needed. */
+ bool is_allocated = false;
+
+ if (md->type == eModifierType_Fluidsim) {
+ blo_reportf_wrap(
+ fd->reports,
+ RPT_WARNING,
+ TIP_(
+ "Possible data loss when saving this file! %s modifier is deprecated (Object: %s)."),
+ md->name,
+ ob->id.name + 2);
+ md = modifier_replace_with_fluid(fd, ob, lb, md);
+ is_allocated = true;
+ }
+ else if (md->type == eModifierType_Smoke) {
+ blo_reportf_wrap(
+ fd->reports,
+ RPT_WARNING,
+ TIP_(
+ "Possible data loss when saving this file! %s modifier is deprecated (Object: %s)."),
+ md->name,
+ ob->id.name + 2);
+ md = modifier_replace_with_fluid(fd, ob, lb, md);
+ is_allocated = true;
+ }
/* if modifiers disappear, or for upward compatibility */
if (NULL == modifierType_getInfo(md->type)) {
md->type = eModifierType_None;
}
- if (md->type == eModifierType_Subsurf) {
+ if (is_allocated) {
+ /* All the fields has been properly allocated. */
+ }
+ else if (md->type == eModifierType_Subsurf) {
SubsurfModifierData *smd = (SubsurfModifierData *)md;
smd->emCache = smd->mCache = NULL;
@@ -5523,91 +5681,82 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
clmd->solver_result = NULL;
}
- else if (md->type == eModifierType_Fluidsim) {
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
+ else if (md->type == eModifierType_Fluid) {
- fluidmd->fss = newdataadr(fd, fluidmd->fss);
- if (fluidmd->fss) {
- fluidmd->fss->fmd = fluidmd;
- fluidmd->fss->meshVelocities = NULL;
- }
- }
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
-
- if (smd->type == MOD_SMOKE_TYPE_DOMAIN) {
- smd->flow = NULL;
- smd->coll = NULL;
- smd->domain = newdataadr(fd, smd->domain);
- smd->domain->smd = smd;
-
- smd->domain->fluid = NULL;
- smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
- smd->domain->wt = NULL;
- smd->domain->shadow = NULL;
- smd->domain->tex = NULL;
- smd->domain->tex_shadow = NULL;
- smd->domain->tex_flame = NULL;
- smd->domain->tex_flame_coba = NULL;
- smd->domain->tex_coba = NULL;
- smd->domain->tex_field = NULL;
- smd->domain->tex_velocity_x = NULL;
- smd->domain->tex_velocity_y = NULL;
- smd->domain->tex_velocity_z = NULL;
- smd->domain->tex_wt = NULL;
- smd->domain->coba = newdataadr(fd, smd->domain->coba);
-
- smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights);
- if (!smd->domain->effector_weights) {
- smd->domain->effector_weights = BKE_effector_add_weights(NULL);
+ FluidModifierData *mmd = (FluidModifierData *)md;
+
+ if (mmd->type == MOD_FLUID_TYPE_DOMAIN) {
+ mmd->flow = NULL;
+ mmd->effector = NULL;
+ mmd->domain = newdataadr(fd, mmd->domain);
+ mmd->domain->mmd = mmd;
+
+ mmd->domain->fluid = NULL;
+ mmd->domain->fluid_mutex = BLI_rw_mutex_alloc();
+ mmd->domain->tex = NULL;
+ mmd->domain->tex_shadow = NULL;
+ mmd->domain->tex_flame = NULL;
+ mmd->domain->tex_flame_coba = NULL;
+ mmd->domain->tex_coba = NULL;
+ mmd->domain->tex_field = NULL;
+ mmd->domain->tex_velocity_x = NULL;
+ mmd->domain->tex_velocity_y = NULL;
+ mmd->domain->tex_velocity_z = NULL;
+ mmd->domain->tex_wt = NULL;
+ mmd->domain->mesh_velocities = NULL;
+ mmd->domain->coba = newdataadr(fd, mmd->domain->coba);
+
+ mmd->domain->effector_weights = newdataadr(fd, mmd->domain->effector_weights);
+ if (!mmd->domain->effector_weights) {
+ mmd->domain->effector_weights = BKE_effector_add_weights(NULL);
}
direct_link_pointcache_list(
- fd, &(smd->domain->ptcaches[0]), &(smd->domain->point_cache[0]), 1);
+ fd, &(mmd->domain->ptcaches[0]), &(mmd->domain->point_cache[0]), 1);
- /* Smoke uses only one cache from now on, so store pointer convert */
- if (smd->domain->ptcaches[1].first || smd->domain->point_cache[1]) {
- if (smd->domain->point_cache[1]) {
- PointCache *cache = newdataadr(fd, smd->domain->point_cache[1]);
+ /* Manta sim uses only one cache from now on, so store pointer convert */
+ if (mmd->domain->ptcaches[1].first || mmd->domain->point_cache[1]) {
+ if (mmd->domain->point_cache[1]) {
+ PointCache *cache = newdataadr(fd, mmd->domain->point_cache[1]);
if (cache->flag & PTCACHE_FAKE_SMOKE) {
- /* Smoke was already saved in "new format" and this cache is a fake one. */
+ /* Manta-sim/smoke was already saved in "new format" and this cache is a fake one. */
}
else {
printf(
- "High resolution smoke cache not available due to pointcache update. Please "
+ "High resolution manta cache not available due to pointcache update. Please "
"reset the simulation.\n");
}
BKE_ptcache_free(cache);
}
- BLI_listbase_clear(&smd->domain->ptcaches[1]);
- smd->domain->point_cache[1] = NULL;
- }
- }
- else if (smd->type == MOD_SMOKE_TYPE_FLOW) {
- smd->domain = NULL;
- smd->coll = NULL;
- smd->flow = newdataadr(fd, smd->flow);
- smd->flow->smd = smd;
- smd->flow->mesh = NULL;
- smd->flow->verts_old = NULL;
- smd->flow->numverts = 0;
- smd->flow->psys = newdataadr(fd, smd->flow->psys);
- }
- else if (smd->type == MOD_SMOKE_TYPE_COLL) {
- smd->flow = NULL;
- smd->domain = NULL;
- smd->coll = newdataadr(fd, smd->coll);
- if (smd->coll) {
- smd->coll->smd = smd;
- smd->coll->verts_old = NULL;
- smd->coll->numverts = 0;
- smd->coll->mesh = NULL;
+ BLI_listbase_clear(&mmd->domain->ptcaches[1]);
+ mmd->domain->point_cache[1] = NULL;
+ }
+ }
+ else if (mmd->type == MOD_FLUID_TYPE_FLOW) {
+ mmd->domain = NULL;
+ mmd->effector = NULL;
+ mmd->flow = newdataadr(fd, mmd->flow);
+ mmd->flow->mmd = mmd;
+ mmd->flow->mesh = NULL;
+ mmd->flow->verts_old = NULL;
+ mmd->flow->numverts = 0;
+ mmd->flow->psys = newdataadr(fd, mmd->flow->psys);
+ }
+ else if (mmd->type == MOD_FLUID_TYPE_EFFEC) {
+ mmd->flow = NULL;
+ mmd->domain = NULL;
+ mmd->effector = newdataadr(fd, mmd->effector);
+ if (mmd->effector) {
+ mmd->effector->mmd = mmd;
+ mmd->effector->verts_old = NULL;
+ mmd->effector->numverts = 0;
+ mmd->effector->mesh = NULL;
}
else {
- smd->type = 0;
- smd->flow = NULL;
- smd->domain = NULL;
- smd->coll = NULL;
+ mmd->type = 0;
+ mmd->flow = NULL;
+ mmd->domain = NULL;
+ mmd->effector = NULL;
}
}
}
@@ -5930,7 +6079,7 @@ static void direct_link_object(FileData *fd, Object *ob)
ob->matbits = newdataadr(fd, ob->matbits);
/* do it here, below old data gets converted */
- direct_link_modifiers(fd, &ob->modifiers);
+ direct_link_modifiers(fd, &ob->modifiers, ob);
direct_link_gpencil_modifiers(fd, &ob->greasepencil_modifiers);
direct_link_shaderfxs(fd, &ob->shader_fx);
@@ -7376,10 +7525,7 @@ static void direct_link_area(FileData *fd, ScrArea *area)
}
else if (sl->spacetype == SPACE_TEXT) {
SpaceText *st = (SpaceText *)sl;
-
- st->drawcache = NULL;
- st->scroll_ofs_px[0] = 0;
- st->scroll_ofs_px[1] = 0;
+ memset(&st->runtime, 0, sizeof(st->runtime));
}
else if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
@@ -9045,7 +9191,7 @@ static ID *create_placeholder(Main *mainvar, const short idcode, const char *idn
ph_id->icon_id = 0;
BLI_addtail(lb, ph_id);
- id_sort_by_name(lb, ph_id);
+ id_sort_by_name(lb, ph_id, NULL);
return ph_id;
}
@@ -10373,7 +10519,7 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting
expand_doit(fd, mainvar, part->instance_object);
expand_doit(fd, mainvar, part->instance_collection);
- expand_doit(fd, mainvar, part->eff_group);
+ expand_doit(fd, mainvar, part->force_group);
expand_doit(fd, mainvar, part->bb_ob);
expand_doit(fd, mainvar, part->collision_group);
@@ -11446,7 +11592,7 @@ static ID *link_named_part(
if (id) {
/* sort by name in list */
ListBase *lb = which_libbase(mainl, idcode);
- id_sort_by_name(lb, id);
+ id_sort_by_name(lb, id, NULL);
}
}
else {
@@ -11503,7 +11649,7 @@ int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const unsigned int
if (id) {
/* sort by name in list */
ListBase *lb = which_libbase(mainl, GS(id->name));
- id_sort_by_name(lb, id);
+ id_sort_by_name(lb, id, NULL);
if (bhead->code == ID_OB) {
/* Instead of instancing Base's directly, postpone until after collections are loaded
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 3e7b1582603..a5ab0c0acb7 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -50,7 +50,7 @@
#include "DNA_screen_types.h"
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_world_types.h"
@@ -1789,19 +1789,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- smd->domain->vorticity = 2.0f;
- smd->domain->time_scale = 1.0f;
+ if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) {
+ mmd->domain->vorticity = 2.0f;
+ mmd->domain->time_scale = 1.0f;
- if (!(smd->domain->flags & (1 << 4))) {
+ if (!(mmd->domain->flags & (1 << 4))) {
continue;
}
/* delete old MOD_SMOKE_INITVELOCITY flag */
- smd->domain->flags &= ~(1 << 4);
+ mmd->domain->flags &= ~(1 << 4);
/* for now just add it to all flow objects in the scene */
{
@@ -1809,19 +1809,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
for (ob2 = bmain->objects.first; ob2; ob2 = ob2->id.next) {
ModifierData *md2;
for (md2 = ob2->modifiers.first; md2; md2 = md2->next) {
- if (md2->type == eModifierType_Smoke) {
- SmokeModifierData *smd2 = (SmokeModifierData *)md2;
+ if (md2->type == eModifierType_Fluid) {
+ FluidModifierData *mmd2 = (FluidModifierData *)md2;
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
- smd2->flow->flags |= MOD_SMOKE_FLOW_INITVELOCITY;
+ if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) {
+ mmd2->flow->flags |= FLUID_FLOW_INITVELOCITY;
}
}
}
}
}
}
- else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
- smd->flow->vel_multi = 1.0f;
+ else if ((mmd->type & MOD_FLUID_TYPE_FLOW) && mmd->flow) {
+ mmd->flow->vel_multi = 1.0f;
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 40219a36323..f23e4b5e2a4 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -39,7 +39,7 @@
#include "DNA_view3d_types.h"
#include "DNA_screen_types.h"
#include "DNA_sdna_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_space_types.h"
#include "DNA_world_types.h"
#include "DNA_light_types.h"
@@ -1292,12 +1292,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- int maxres = max_iii(smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]);
- smd->domain->scale = smd->domain->dx * maxres;
- smd->domain->dx = 1.0f / smd->domain->scale;
+ if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) {
+ int maxres = max_iii(mmd->domain->res[0], mmd->domain->res[1], mmd->domain->res[2]);
+ mmd->domain->scale = mmd->domain->dx * maxres;
+ mmd->domain->dx = 1.0f / mmd->domain->scale;
}
}
}
@@ -1610,31 +1610,31 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
+ if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) {
/* keep branch saves if possible */
- if (!smd->domain->flame_max_temp) {
- smd->domain->burning_rate = 0.75f;
- smd->domain->flame_smoke = 1.0f;
- smd->domain->flame_vorticity = 0.5f;
- smd->domain->flame_ignition = 1.25f;
- smd->domain->flame_max_temp = 1.75f;
- smd->domain->adapt_threshold = 0.02f;
- smd->domain->adapt_margin = 4;
- smd->domain->flame_smoke_color[0] = 0.7f;
- smd->domain->flame_smoke_color[1] = 0.7f;
- smd->domain->flame_smoke_color[2] = 0.7f;
+ if (!mmd->domain->flame_max_temp) {
+ mmd->domain->burning_rate = 0.75f;
+ mmd->domain->flame_smoke = 1.0f;
+ mmd->domain->flame_vorticity = 0.5f;
+ mmd->domain->flame_ignition = 1.25f;
+ mmd->domain->flame_max_temp = 1.75f;
+ mmd->domain->adapt_threshold = 0.02f;
+ mmd->domain->adapt_margin = 4;
+ mmd->domain->flame_smoke_color[0] = 0.7f;
+ mmd->domain->flame_smoke_color[1] = 0.7f;
+ mmd->domain->flame_smoke_color[2] = 0.7f;
}
}
- else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
- if (!smd->flow->texture_size) {
- smd->flow->fuel_amount = 1.0;
- smd->flow->surface_distance = 1.5;
- smd->flow->color[0] = 0.7f;
- smd->flow->color[1] = 0.7f;
- smd->flow->color[2] = 0.7f;
- smd->flow->texture_size = 1.0f;
+ else if ((mmd->type & MOD_FLUID_TYPE_FLOW) && mmd->flow) {
+ if (!mmd->flow->texture_size) {
+ mmd->flow->fuel_amount = 1.0;
+ mmd->flow->surface_distance = 1.5;
+ mmd->flow->color[0] = 0.7f;
+ mmd->flow->color[1] = 0.7f;
+ mmd->flow->color[2] = 0.7f;
+ mmd->flow->texture_size = 1.0f;
}
}
}
@@ -2140,14 +2140,14 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- if (smd->domain->flags & MOD_SMOKE_HIGH_SMOOTH) {
- smd->domain->highres_sampling = SM_HRES_LINEAR;
+ if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) {
+ if (mmd->domain->flags & FLUID_DOMAIN_USE_HIGH_SMOOTH) {
+ mmd->domain->highres_sampling = SM_HRES_LINEAR;
}
else {
- smd->domain->highres_sampling = SM_HRES_NEAREST;
+ mmd->domain->highres_sampling = SM_HRES_NEAREST;
}
}
}
@@ -2207,11 +2207,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
- if (!smd->flow->particle_size) {
- smd->flow->particle_size = 1.0f;
+ if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if ((mmd->type & MOD_FLUID_TYPE_FLOW) && mmd->flow) {
+ if (!mmd->flow->particle_size) {
+ mmd->flow->particle_size = 1.0f;
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index fb570b956b6..f421f31814c 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -46,7 +46,7 @@
#include "DNA_particle_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_view3d_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_light_types.h"
@@ -1549,18 +1549,18 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- if (!DNA_struct_elem_find(fd->filesdna, "SmokeModifierData", "float", "slice_per_voxel")) {
+ if (!DNA_struct_elem_find(fd->filesdna, "FluidModifierData", "float", "slice_per_voxel")) {
Object *ob;
ModifierData *md;
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->domain) {
- smd->domain->slice_per_voxel = 5.0f;
- smd->domain->slice_depth = 0.5f;
- smd->domain->display_thickness = 1.0f;
+ if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if (mmd->domain) {
+ mmd->domain->slice_per_voxel = 5.0f;
+ mmd->domain->slice_depth = 0.5f;
+ mmd->domain->display_thickness = 1.0f;
}
}
}
@@ -1719,16 +1719,16 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 279, 3)) {
- if (!DNA_struct_elem_find(fd->filesdna, "SmokeDomainSettings", "float", "clipping")) {
+ if (!DNA_struct_elem_find(fd->filesdna, "FluidDomainSettings", "float", "clipping")) {
Object *ob;
ModifierData *md;
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->domain) {
- smd->domain->clipping = 1e-3f;
+ if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if (mmd->domain) {
+ mmd->domain->clipping = 1e-3f;
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 49d3726a224..5e7a3a794b8 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -39,10 +39,14 @@
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curveprofile_types.h"
+#include "DNA_freestyle_types.h"
#include "DNA_gpu_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_light_types.h"
#include "DNA_layer_types.h"
#include "DNA_lightprobe_types.h"
+#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
@@ -52,12 +56,12 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "DNA_genfile.h"
-#include "DNA_gpencil_types.h"
#include "DNA_workspace_types.h"
#include "DNA_key_types.h"
#include "DNA_curve_types.h"
#include "DNA_armature_types.h"
#include "DNA_text_types.h"
+#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "BKE_animsys.h"
@@ -863,6 +867,232 @@ static void do_versions_local_collection_bits_set(LayerCollection *layer_collect
}
}
+static void do_version_curvemapping_flag_extend_extrapolate(CurveMapping *cumap)
+{
+#define CUMA_EXTEND_EXTRAPOLATE_OLD 1
+ for (int curve_map_index = 0; curve_map_index < 4; curve_map_index++) {
+ CurveMap *cuma = &cumap->cm[curve_map_index];
+ if (cuma->flag & CUMA_EXTEND_EXTRAPOLATE_OLD) {
+ cumap->flag |= CUMA_EXTEND_EXTRAPOLATE;
+ return;
+ }
+ }
+#undef CUMA_EXTEND_EXTRAPOLATE_OLD
+}
+
+/* Util version to walk over all CurveMappings in the given `bmain` */
+static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMapping *cumap))
+{
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ callback(&scene->r.mblur_shutter_curve);
+
+ if (scene->view_settings.curve_mapping) {
+ callback(scene->view_settings.curve_mapping);
+ }
+
+ if (scene->ed != NULL) {
+ LISTBASE_FOREACH (Sequence *, seq, &scene->ed->seqbase) {
+ LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) {
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+
+ if (smti) {
+ if (smd->type == seqModifierType_Curves) {
+ CurvesModifierData *cmd = (CurvesModifierData *)smd;
+ callback(&cmd->curve_mapping);
+ }
+ else if (smd->type == seqModifierType_HueCorrect) {
+ HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
+ callback(&hcmd->curve_mapping);
+ }
+ }
+ }
+ }
+ }
+
+ // toolsettings
+ ToolSettings *ts = scene->toolsettings;
+ if (ts->vpaint) {
+ callback(ts->vpaint->paint.cavity_curve);
+ }
+ if (ts->wpaint) {
+ callback(ts->wpaint->paint.cavity_curve);
+ }
+ if (ts->sculpt) {
+ callback(ts->sculpt->paint.cavity_curve);
+ }
+ if (ts->uvsculpt) {
+ callback(ts->uvsculpt->paint.cavity_curve);
+ }
+ if (ts->gp_paint) {
+ callback(ts->gp_paint->paint.cavity_curve);
+ }
+ if (ts->gp_interpolate.custom_ipo) {
+ callback(ts->gp_interpolate.custom_ipo);
+ }
+ if (ts->gp_sculpt.cur_falloff) {
+ callback(ts->gp_sculpt.cur_falloff);
+ }
+ if (ts->gp_sculpt.cur_primitive) {
+ callback(ts->gp_sculpt.cur_primitive);
+ }
+ callback(ts->imapaint.paint.cavity_curve);
+ }
+
+ FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
+ if (ELEM(node->type,
+ SH_NODE_CURVE_VEC,
+ SH_NODE_CURVE_RGB,
+ CMP_NODE_CURVE_VEC,
+ CMP_NODE_CURVE_RGB,
+ CMP_NODE_TIME,
+ CMP_NODE_HUECORRECT,
+ TEX_NODE_CURVE_RGB,
+ TEX_NODE_CURVE_TIME)) {
+ callback((CurveMapping *)node->storage);
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ LISTBASE_FOREACH (Light *, light, &bmain->lights) {
+ if (light->curfalloff) {
+ callback(light->curfalloff);
+ }
+ }
+
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->curve) {
+ callback(brush->curve);
+ }
+ if (brush->gpencil_settings) {
+ if (brush->gpencil_settings->curve_sensitivity) {
+ callback(brush->gpencil_settings->curve_sensitivity);
+ }
+ if (brush->gpencil_settings->curve_strength) {
+ callback(brush->gpencil_settings->curve_strength);
+ }
+ if (brush->gpencil_settings->curve_jitter) {
+ callback(brush->gpencil_settings->curve_jitter);
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (ParticleSettings *, part, &bmain->particles) {
+ if (part->clumpcurve) {
+ callback(part->clumpcurve);
+ }
+ if (part->roughcurve) {
+ callback(part->roughcurve);
+ }
+ if (part->twistcurve) {
+ callback(part->twistcurve);
+ }
+ }
+
+ /* Object */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ /* Object modifiers */
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData *)md;
+
+ if (hmd->curfalloff) {
+ callback(hmd->curfalloff);
+ }
+ }
+ else if (md->type == eModifierType_Warp) {
+ WarpModifierData *tmd = (WarpModifierData *)md;
+ if (tmd->curfalloff) {
+ callback(tmd->curfalloff);
+ }
+ }
+ else if (md->type == eModifierType_WeightVGEdit) {
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
+
+ if (wmd->cmap_curve) {
+ callback(wmd->cmap_curve);
+ }
+ }
+ }
+ /* Grease pencil modifiers */
+ LISTBASE_FOREACH (ModifierData *, md, &ob->greasepencil_modifiers) {
+ if (md->type == eGpencilModifierType_Thick) {
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+
+ if (gpmd->curve_thickness) {
+ callback(gpmd->curve_thickness);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Hook) {
+ HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
+
+ if (gpmd->curfalloff) {
+ callback(gpmd->curfalloff);
+ }
+ }
+ }
+ }
+
+ /* Free Style */
+ LISTBASE_FOREACH (struct FreestyleLineStyle *, linestyle, &bmain->linestyles) {
+ LISTBASE_FOREACH (LineStyleModifier *, m, &linestyle->thickness_modifiers) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ callback(((LineStyleAlphaModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ callback(((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ callback(((LineStyleAlphaModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ callback(((LineStyleAlphaModifier_Material *)m)->curve);
+ break;
+ case LS_MODIFIER_TANGENT:
+ callback(((LineStyleAlphaModifier_Tangent *)m)->curve);
+ break;
+ case LS_MODIFIER_NOISE:
+ callback(((LineStyleAlphaModifier_Noise *)m)->curve);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ callback(((LineStyleAlphaModifier_CreaseAngle *)m)->curve);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ callback(((LineStyleAlphaModifier_Curvature_3D *)m)->curve);
+ break;
+ }
+ }
+
+ LISTBASE_FOREACH (LineStyleModifier *, m, &linestyle->thickness_modifiers) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ callback(((LineStyleThicknessModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ callback(((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ callback(((LineStyleThicknessModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ callback(((LineStyleThicknessModifier_Material *)m)->curve);
+ break;
+ case LS_MODIFIER_TANGENT:
+ callback(((LineStyleThicknessModifier_Tangent *)m)->curve);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ callback(((LineStyleThicknessModifier_CreaseAngle *)m)->curve);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ callback(((LineStyleThicknessModifier_Curvature_3D *)m)->curve);
+ break;
+ }
+ }
+ }
+}
+
void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
{
bool use_collection_compat_28 = true;
@@ -912,11 +1142,10 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
}
}
- /* We need to assign lib pointer to generated hidden collections *after* all have been created,
- * otherwise we'll end up with several data-blocks sharing same name/library,
- * which is FORBIDDEN!
- * Note: we need this to be recursive,
- * since a child collection may be sorted before its parent in bmain. */
+ /* We need to assign lib pointer to generated hidden collections *after* all have been
+ * created, otherwise we'll end up with several data-blocks sharing same name/library,
+ * which is FORBIDDEN! Note: we need this to be recursive, since a child collection may be
+ * sorted before its parent in bmain. */
for (Collection *collection = bmain->collections.first; collection != NULL;
collection = collection->id.next) {
do_version_collection_propagate_lib_to_children(collection);
@@ -1220,7 +1449,8 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
}
if (!MAIN_VERSION_ATLEAST(bmain, 280, 38)) {
- /* Ensure we get valid rigidbody object/constraint data in relevant collections' objects. */
+ /* Ensure we get valid rigidbody object/constraint data in relevant collections' objects.
+ */
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -1433,7 +1663,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (error & NTREE_DOVERSION_NEED_OUTPUT) {
BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
printf(
- "You need to connect Principled and Eevee Specular shader nodes to new material output "
+ "You need to connect Principled and Eevee Specular shader nodes to new material "
+ "output "
"nodes.\n");
}
@@ -3165,19 +3396,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- if (!MAIN_VERSION_ATLEAST(bmain, 280, 45)) {
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_SEQ) {
- SpaceSeq *sseq = (SpaceSeq *)sl;
- sseq->flag |= SEQ_SHOW_MARKER_LINES;
- }
- }
- }
- }
- }
-
if (!MAIN_VERSION_ATLEAST(bmain, 280, 46)) {
/* Add wireframe color. */
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "wire_color_type")) {
@@ -3933,8 +4151,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- {
- /* Versioning code until next subversion bump goes here. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 282, 2)) {
+ do_version_curvemapping_walker(bmain, do_version_curvemapping_flag_extend_extrapolate);
+
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
sa->flag &= ~AREA_FLAG_UNUSED_6;
@@ -3974,12 +4193,139 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
/* Pose brush smooth iterations */
- if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "pose_smooth_itereations")) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "pose_smooth_iterations")) {
for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
br->pose_smooth_iterations = 4;
}
}
+ /* Cloth pressure */
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+
+ clmd->sim_parms->pressure_factor = 1;
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 282, 3)) {
+ /* Remove Unified pressure/size and pressure/alpha */
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ UnifiedPaintSettings *ups = &ts->unified_paint_settings;
+ ups->flag &= ~(UNIFIED_PAINT_FLAG_UNUSED_0 | UNIFIED_PAINT_FLAG_UNUSED_1);
+ }
+
+ /* Set the default render pass in the viewport to Combined. */
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "int", "render_pass")) {
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ scene->display.shading.render_pass = SCE_PASS_COMBINED;
+ }
+
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.render_pass = SCE_PASS_COMBINED;
+ }
+ }
+ }
+ }
+ }
+
+ /* Make markers region visible by default. */
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ switch (sl->spacetype) {
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ sseq->flag |= SEQ_SHOW_MARKERS;
+ break;
+ }
+ case SPACE_ACTION: {
+ SpaceAction *saction = (SpaceAction *)sl;
+ saction->flag |= SACTION_SHOW_MARKERS;
+ break;
+ }
+ case SPACE_GRAPH: {
+ SpaceGraph *sipo = (SpaceGraph *)sl;
+ sipo->flag |= SIPO_SHOW_MARKERS;
+ break;
+ }
+ case SPACE_NLA: {
+ SpaceNla *snla = (SpaceNla *)sl;
+ snla->flag |= SNLA_SHOW_MARKERS;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+
+ /* Cloth internal springs */
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+
+ clmd->sim_parms->internal_tension = 15.0f;
+ clmd->sim_parms->max_internal_tension = 15.0f;
+ clmd->sim_parms->internal_compression = 15.0f;
+ clmd->sim_parms->max_internal_compression = 15.0f;
+ clmd->sim_parms->internal_spring_max_diversion = M_PI / 4.0f;
+ }
+ }
+ }
+
+ /* Add primary tile to images. */
+ if (!DNA_struct_elem_find(fd->filesdna, "Image", "ListBase", "tiles")) {
+ for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
+ ImageTile *tile = MEM_callocN(sizeof(ImageTile), "Image Tile");
+ tile->ok = 1;
+ tile->tile_number = 1001;
+ BLI_addtail(&ima->tiles, tile);
+ }
+ }
+
+ /* UDIM Image Editor change. */
+ if (!DNA_struct_elem_find(fd->filesdna, "SpaceImage", "int", "tile_grid_shape[2]")) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+ sima->tile_grid_shape[0] = 1;
+ sima->tile_grid_shape[1] = 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* Brush cursor alpha */
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ br->add_col[3] = 0.9f;
+ br->sub_col[3] = 0.9f;
+ }
+
#ifdef WITH_OPENXR
if (!DNA_struct_find(fd->filesdna, "bXrSessionSettings")) {
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index 0fe7f97e4ee..466dd02b3b3 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -1205,6 +1205,51 @@ static void update_voronoi_node_square_distance(bNodeTree *ntree)
}
}
+/* Noise and Wave Texture nodes: Restore previous Distortion range.
+ * In 2.81 we used noise() for distortion, now we use snoise() which has twice the range.
+ * To fix this we halve distortion value, directly or by adding multiply node for used sockets.
+ */
+static void update_noise_and_wave_distortion(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_NOISE || node->type == SH_NODE_TEX_WAVE) {
+
+ bNodeSocket *sockDistortion = nodeFindSocket(node, SOCK_IN, "Distortion");
+ float *distortion = cycles_node_socket_float_value(sockDistortion);
+
+ if (socket_is_used(sockDistortion) && sockDistortion->link != NULL) {
+ bNode *distortionInputNode = sockDistortion->link->fromnode;
+ bNodeSocket *distortionInputSock = sockDistortion->link->fromsock;
+
+ bNode *mulNode = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ mulNode->custom1 = NODE_MATH_MULTIPLY;
+ mulNode->locx = node->locx;
+ mulNode->locy = node->locy - 240.0f;
+ mulNode->flag |= NODE_HIDDEN;
+ bNodeSocket *mulSockA = BLI_findlink(&mulNode->inputs, 0);
+ bNodeSocket *mulSockB = BLI_findlink(&mulNode->inputs, 1);
+ *cycles_node_socket_float_value(mulSockB) = 0.5f;
+ bNodeSocket *mulSockOut = nodeFindSocket(mulNode, SOCK_OUT, "Value");
+
+ nodeRemLink(ntree, sockDistortion->link);
+ nodeAddLink(ntree, distortionInputNode, distortionInputSock, mulNode, mulSockA);
+ nodeAddLink(ntree, mulNode, mulSockOut, node, sockDistortion);
+
+ need_update = true;
+ }
+ else if (*distortion != 0.0f) {
+ *distortion = *distortion * 0.5f;
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
{
/* Particle shape shared with Eevee. */
@@ -1435,4 +1480,13 @@ void do_versions_after_linking_cycles(Main *bmain)
}
FOREACH_NODETREE_END;
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 282, 4)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_noise_and_wave_distortion(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index f2d6db886d3..bc43d9605e2 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -150,10 +150,9 @@ static void blo_update_defaults_screen(bScreen *screen,
}
}
else if (sa->spacetype == SPACE_ACTION) {
- /* Show marker lines, hide channels and collapse summary in timelines. */
+ /* Show markers region, hide channels and collapse summary in timelines. */
SpaceAction *saction = sa->spacedata.first;
- saction->flag |= SACTION_SHOW_MARKER_LINES;
-
+ saction->flag |= SACTION_SHOW_MARKERS;
if (saction->mode == SACTCONT_TIMELINE) {
saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED;
@@ -166,11 +165,15 @@ static void blo_update_defaults_screen(bScreen *screen,
}
else if (sa->spacetype == SPACE_GRAPH) {
SpaceGraph *sipo = sa->spacedata.first;
- sipo->flag |= SIPO_MARKER_LINES;
+ sipo->flag |= SIPO_SHOW_MARKERS;
}
else if (sa->spacetype == SPACE_NLA) {
SpaceNla *snla = sa->spacedata.first;
- snla->flag |= SNLA_SHOW_MARKER_LINES;
+ snla->flag |= SNLA_SHOW_MARKERS;
+ }
+ else if (sa->spacetype == SPACE_SEQ) {
+ SpaceSeq *seq = sa->spacedata.first;
+ seq->flag |= SEQ_SHOW_MARKERS;
}
else if (sa->spacetype == SPACE_TEXT) {
/* Show syntax and line numbers in Script workspace text editor. */
@@ -215,6 +218,19 @@ static void blo_update_defaults_screen(bScreen *screen,
}
}
}
+
+ /* 2D animation template. */
+ if (app_template && STREQ(app_template, "2D_Animation")) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (sa->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = sa->spacedata.first;
+ /* Enable Sliders. */
+ saction->flag |= SACTION_SLIDERS;
+ }
+ }
+ }
+ }
}
void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_template)
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 5d46f0735eb..73cdd40c02c 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -2292,7 +2292,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
part->omat = paf->mat[0];
part->hair_step = paf->totkey;
- part->eff_group = paf->group;
+ part->force_group = paf->group;
/* old system didn't interpolate between keypoints at render time */
part->draw_step = part->ren_step = 0;
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index ad06d512266..b1f70848bdc 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -156,13 +156,25 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
copy_v4_v4_uchar(btheme->space_nla.nla_track, btheme->space_nla.header);
}
- /**
- * Include next version bump.
- */
- {
+ 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);
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - #BLO_version_defaults_userpref_blend in this file.
+ * - "versioning_{BLENDER_VERSION}.c"
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
}
#undef FROM_DEFAULT_V4_UCHAR
@@ -667,10 +679,7 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
userdef->file_space_data.filter_id = U_default.file_space_data.filter_id;
}
- /**
- * Include next version bump.
- */
- {
+ if (!USER_VERSION_ATLEAST(282, 4)) {
if (userdef->view_rotate_sensitivity_turntable == 0.0f) {
userdef->view_rotate_sensitivity_turntable = DEG2RADF(0.4f);
userdef->view_rotate_sensitivity_trackball = 1.0f;
@@ -678,7 +687,22 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
if (userdef->scrollback == 0) {
userdef->scrollback = U_default.scrollback;
}
- /* pass */
+
+ /* Enable Overlay Engine Smooth Wire by default */
+ userdef->gpu_flag |= USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE;
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - #do_versions_theme in this file.
+ * - "versioning_{BLENDER_VERSION}.c"
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
}
if (userdef->pixelsize == 0.0f) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index b3a16b1fb4d..30e7cf476fb 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -126,7 +126,7 @@
#include "DNA_scene_types.h"
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
@@ -1628,38 +1628,38 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
writestruct(wd, DATA, EffectorWeights, 1, clmd->sim_parms->effector_weights);
write_pointcaches(wd, &clmd->ptcaches);
}
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ else if (md->type == eModifierType_Fluid) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN) {
+ writestruct(wd, DATA, FluidDomainSettings, 1, mmd->domain);
- if (smd->domain) {
- write_pointcaches(wd, &(smd->domain->ptcaches[0]));
+ if (mmd->domain) {
+ write_pointcaches(wd, &(mmd->domain->ptcaches[0]));
/* create fake pointcache so that old blender versions can read it */
- smd->domain->point_cache[1] = BKE_ptcache_add(&smd->domain->ptcaches[1]);
- smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE;
- smd->domain->point_cache[1]->step = 1;
+ mmd->domain->point_cache[1] = BKE_ptcache_add(&mmd->domain->ptcaches[1]);
+ mmd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE;
+ mmd->domain->point_cache[1]->step = 1;
- write_pointcaches(wd, &(smd->domain->ptcaches[1]));
+ write_pointcaches(wd, &(mmd->domain->ptcaches[1]));
- if (smd->domain->coba) {
- writestruct(wd, DATA, ColorBand, 1, smd->domain->coba);
+ if (mmd->domain->coba) {
+ writestruct(wd, DATA, ColorBand, 1, mmd->domain->coba);
}
/* cleanup the fake pointcache */
- BKE_ptcache_free_list(&smd->domain->ptcaches[1]);
- smd->domain->point_cache[1] = NULL;
+ BKE_ptcache_free_list(&mmd->domain->ptcaches[1]);
+ mmd->domain->point_cache[1] = NULL;
- writestruct(wd, DATA, EffectorWeights, 1, smd->domain->effector_weights);
+ writestruct(wd, DATA, EffectorWeights, 1, mmd->domain->effector_weights);
}
}
- else if (smd->type & MOD_SMOKE_TYPE_FLOW) {
- writestruct(wd, DATA, SmokeFlowSettings, 1, smd->flow);
+ else if (mmd->type & MOD_FLUID_TYPE_FLOW) {
+ writestruct(wd, DATA, FluidFlowSettings, 1, mmd->flow);
}
- else if (smd->type & MOD_SMOKE_TYPE_COLL) {
- writestruct(wd, DATA, SmokeCollSettings, 1, smd->coll);
+ else if (mmd->type & MOD_FLUID_TYPE_EFFEC) {
+ writestruct(wd, DATA, FluidEffectorSettings, 1, mmd->effector);
}
}
else if (md->type == eModifierType_Fluidsim) {
@@ -2266,6 +2266,8 @@ static void write_image(WriteData *wd, Image *ima)
}
writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format);
+ writelist(wd, DATA, ImageTile, &ima->tiles);
+
ima->packedfile = NULL;
writelist(wd, DATA, RenderSlot, &ima->renderslots);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 9bab959f0a2..1ecbfccab74 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -91,7 +91,7 @@
#include "BKE_key.h"
#include "bmesh.h"
-#include "intern/bmesh_private.h" /* for element checking */
+#include "intern/bmesh_private.h" /* For element checking. */
void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
{
@@ -202,7 +202,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
if (!me || !me->totvert) {
- if (me && is_new) { /*no verts? still copy customdata layout*/
+ if (me && is_new) { /* No verts? still copy custom-data layout. */
CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_ASSIGN, 0);
CustomData_copy(&me->edata, &bm->edata, mask.emask, CD_ASSIGN, 0);
CustomData_copy(&me->ldata, &bm->ldata, mask.lmask, CD_ASSIGN, 0);
@@ -213,7 +213,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
}
- return; /* sanity check */
+ return; /* Sanity check. */
}
if (is_new) {
@@ -254,9 +254,8 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
if (tot_shape_keys) {
if (is_new) {
- /* check if we need to generate unique ids for the shapekeys.
- * this also exists in the file reading code, but is here for
- * a sanity check */
+ /* Check if we need to generate unique ids for the shape-keys.
+ * This also exists in the file reading code, but is here for a sanity check. */
if (!me->key->uidgen) {
fprintf(stderr,
"%s had to generate shape key uid's in a situation we shouldn't need to! "
@@ -310,10 +309,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
v = vtable[i] = BM_vert_create(bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD);
BM_elem_index_set(v, i); /* set_ok */
- /* transfer flag */
+ /* Transfer flag. */
v->head.hflag = BM_vert_flag_from_mflag(mvert->flag & ~SELECT);
- /* this is necessary for selection counts to work properly */
+ /* This is necessary for selection counts to work properly. */
if (mvert->flag & SELECT) {
BM_vert_select_set(bm, v, true);
}
@@ -327,12 +326,12 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f);
}
- /* set shape key original index */
+ /* Set shape key original index. */
if (cd_shape_keyindex_offset != -1) {
BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, i);
}
- /* set shapekey data */
+ /* Set shape-key data. */
if (tot_shape_keys) {
float(*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
for (int j = 0; j < tot_shape_keys; j++, co_dst++) {
@@ -341,7 +340,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
}
}
if (is_new) {
- bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */
+ bm->elem_index_dirty &= ~BM_VERT; /* Added in order, clear dirty flag. */
}
etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__);
@@ -352,10 +351,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
bm, vtable[medge->v1], vtable[medge->v2], NULL, BM_CREATE_SKIP_CD);
BM_elem_index_set(e, i); /* set_ok */
- /* transfer flags */
+ /* Transfer flags. */
e->head.hflag = BM_edge_flag_from_mflag(medge->flag & ~SELECT);
- /* this is necessary for selection counts to work properly */
+ /* This is necessary for selection counts to work properly. */
if (medge->flag & SELECT) {
BM_edge_select_set(bm, e, true);
}
@@ -371,10 +370,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
}
}
if (is_new) {
- bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */
+ bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */
}
- /* only needed for selection. */
+ /* Only needed for selection. */
if (me->mselect && me->totselect != 0) {
ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__);
}
@@ -400,13 +399,13 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
continue;
}
- /* don't use 'i' since we may have skipped the face */
+ /* Don't use 'i' since we may have skipped the face. */
BM_elem_index_set(f, bm->totface - 1); /* set_ok */
- /* transfer flag */
+ /* Transfer flag. */
f->head.hflag = BM_face_flag_from_mflag(mp->flag & ~ME_FACE_SEL);
- /* this is necessary for selection counts to work properly */
+ /* This is necessary for selection counts to work properly. */
if (mp->flag & ME_FACE_SEL) {
BM_face_select_set(bm, f, true);
}
@@ -419,7 +418,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
int j = mp->loopstart;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- /* don't use 'j' since we may have skipped some faces, hence some loops. */
+ /* Don't use 'j' since we may have skipped some faces, hence some loops. */
BM_elem_index_set(l_iter, totloops++); /* set_ok */
/* Save index of corresponding #MLoop. */
@@ -434,7 +433,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
}
}
if (is_new) {
- bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */
+ bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* Added in order, clear dirty flag. */
}
/* -------------------------------------------------------------------- */
@@ -489,7 +488,7 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
int i = 0;
BMIter iter;
- /* caller needs to ensure this */
+ /* Caller needs to ensure this. */
BLI_assert(ototvert > 0);
vertMap = MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap");
@@ -497,7 +496,7 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
if ((keyi != ORIGINDEX_NONE) && (keyi < ototvert) &&
- /* not fool-proof, but chances are if we have many verts with the same index,
+ /* Not fool-proof, but chances are if we have many verts with the same index,
* we will want to use the first one,
* since the second is more likely to be a duplicate. */
(vertMap[keyi] == NULL)) {
@@ -520,8 +519,9 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
}
/**
- * returns customdata shapekey index from a keyblock or -1
- * \note could split this out into a more generic function */
+ * Returns custom-data shapekey index from a keyblock or -1
+ * \note could split this out into a more generic function.
+ */
static int bm_to_mesh_shape_layer_index_from_kb(BMesh *bm, KeyBlock *currkey)
{
int i;
@@ -540,12 +540,12 @@ static int bm_to_mesh_shape_layer_index_from_kb(BMesh *bm, KeyBlock *currkey)
BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
{
- /* this is a cheap way to set the edge draw, its not precise and will
+ /* This is a cheap way to set the edge draw, its not precise and will
* pick the first 2 faces an edge uses.
* The dot comparison is a little arbitrary, but set so that a 5 subd
- * IcoSphere won't vanish but subd 6 will (as with pre-bmesh blender) */
+ * IcoSphere won't vanish but subd 6 will (as with pre-bmesh Blender). */
- if (/* (med->flag & ME_EDGEDRAW) && */ /* assume to be true */
+ if (/* (med->flag & ME_EDGEDRAW) && */ /* Assume to be true. */
(e->l && (e->l != e->l->radial_next)) &&
(dot_v3v3(e->l->f->no, e->l->radial_next->f->no) > 0.9995f)) {
med->flag &= ~ME_EDGEDRAW;
@@ -561,73 +561,49 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
*/
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
{
- MLoop *mloop;
- MPoly *mpoly;
- MVert *mvert, *oldverts;
- MEdge *med, *medge;
+ MEdge *med;
BMVert *v, *eve;
BMEdge *e;
BMFace *f;
BMIter iter;
- int i, j, ototvert;
+ int i, j;
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
- ototvert = me->totvert;
-
- /* new vertex block */
- if (bm->totvert == 0) {
- mvert = NULL;
- }
- else {
- mvert = MEM_callocN(bm->totvert * sizeof(MVert), "loadeditbMesh vert");
- }
-
- /* new edge block */
- if (bm->totedge == 0) {
- medge = NULL;
- }
- else {
- medge = MEM_callocN(bm->totedge * sizeof(MEdge), "loadeditbMesh edge");
- }
+ MVert *oldverts = NULL;
+ const int ototvert = me->totvert;
- /* new ngon face block */
- if (bm->totface == 0) {
- mpoly = NULL;
- }
- else {
- mpoly = MEM_callocN(bm->totface * sizeof(MPoly), "loadeditbMesh poly");
- }
+ if (me->key && (cd_shape_keyindex_offset != -1)) {
+ /* Keep the old verts in case we are working on* a key, which is done at the end. */
- /* new loop block */
- if (bm->totloop == 0) {
- mloop = NULL;
- }
- else {
- mloop = MEM_callocN(bm->totloop * sizeof(MLoop), "loadeditbMesh loop");
- }
-
- /* lets save the old verts just in case we are actually working on
- * a key ... we now do processing of the keys at the end */
+ /* Use the array in-place instead of duplicating the array. */
+#if 0
oldverts = MEM_dupallocN(me->mvert);
+#else
+ oldverts = me->mvert;
+ me->mvert = NULL;
+ CustomData_update_typemap(&me->vdata);
+ CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
+#endif
+ }
- /* free custom data */
+ /* Free custom data. */
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
CustomData_free(&me->ldata, me->totloop);
CustomData_free(&me->pdata, me->totpoly);
- /* add new custom data */
+ /* Add new custom data. */
me->totvert = bm->totvert;
me->totedge = bm->totedge;
me->totloop = bm->totloop;
me->totpoly = bm->totface;
- /* will be overwritten with a valid value if 'dotess' is set, otherwise we
- * end up with 'me->totface' and me->mface == NULL which can crash [#28625]
- */
+ /* Will be overwritten with a valid value if 'dotess' is set, otherwise we
+ * end up with 'me->totface' and me->mface == NULL which can crash T28625. */
me->totface = 0;
me->act_face = -1;
@@ -640,6 +616,11 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly);
}
+ MVert *mvert = bm->totvert ? MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") : NULL;
+ MEdge *medge = bm->totedge ? MEM_callocN(sizeof(MEdge) * bm->totedge, "bm_to_me.edge") : NULL;
+ MLoop *mloop = bm->totloop ? MEM_callocN(sizeof(MLoop) * bm->totloop, "bm_to_me.loop") : NULL;
+ MPoly *mpoly = bm->totface ? MEM_callocN(sizeof(MPoly) * bm->totface, "bm_to_me.poly") : NULL;
+
CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
@@ -647,7 +628,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
- /* this is called again, 'dotess' arg is used there */
+ /* This is called again, 'dotess' arg is used there. */
BKE_mesh_update_customdata_pointers(me, 0);
i = 0;
@@ -659,7 +640,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BM_elem_index_set(v, i); /* set_inline */
- /* copy over customdat */
+ /* Copy over custom-data. */
CustomData_from_bmesh_block(&bm->vdata, &me->vdata, v->head.data, i);
if (cd_vert_bweight_offset != -1) {
@@ -683,7 +664,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BM_elem_index_set(e, i); /* set_inline */
- /* copy over customdata */
+ /* Copy over custom-data. */
CustomData_from_bmesh_block(&bm->edata, &me->edata, e->head.data, i);
bmesh_quick_edgedraw_flag(med, e);
@@ -715,7 +696,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
mloop->e = BM_elem_index_get(l_iter->e);
mloop->v = BM_elem_index_get(l_iter->v);
- /* copy over customdata */
+ /* Copy over custom-data. */
CustomData_from_bmesh_block(&bm->ldata, &me->ldata, l_iter->head.data, j);
j++;
@@ -729,7 +710,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
me->act_face = i;
}
- /* copy over customdata */
+ /* Copy over custom-data. */
CustomData_from_bmesh_block(&bm->pdata, &me->pdata, f->head.data, i);
i++;
@@ -737,7 +718,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BM_CHECK_ELEMENT(f);
}
- /* patch hook indices and vertex parents */
+ /* Patch hook indices and vertex parents. */
if (params->calc_object_remap && (ototvert > 0)) {
BLI_assert(bmain != NULL);
Object *ob;
@@ -829,19 +810,16 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
- /* see comment below, this logic is in twice */
+ /* See comment below, this logic is in twice. */
if (me->key) {
- const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
-
KeyBlock *currkey;
KeyBlock *actkey = BLI_findlink(&me->key->block, bm->shapenr - 1);
float(*ofs)[3] = NULL;
- /* go through and find any shapekey customdata layers
- * that might not have corresponding KeyBlocks, and add them if
- * necessary */
+ /* Go through and find any shape-key custom-data layers
+ * that might not have corresponding KeyBlocks, and add them if necessary. */
j = 0;
for (i = 0; i < bm->vdata.totlayer; i++) {
if (bm->vdata.layers[i].type != CD_SHAPEKEY) {
@@ -862,30 +840,39 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
j++;
}
- /* editing the base key should update others */
- if ((me->key->type == KEY_RELATIVE) && /* only need offsets for relative shape keys */
- (actkey != NULL) && /* unlikely, but the active key may not be valid if the
- * bmesh and the mesh are out of sync */
- (oldverts != NULL)) /* not used here, but 'oldverts' is used later for applying 'ofs' */
- {
+ /* Editing the base key should update others. */
+ if (/* Only need offsets for relative shape keys. */
+ (me->key->type == KEY_RELATIVE) &&
+
+ /* Unlikely, but the active key may not be valid if the
+ * BMesh and the mesh are out of sync. */
+ (actkey != NULL) &&
+
+ /* Not used here, but 'oldverts' is used later for applying 'ofs'. */
+ (oldverts != NULL) &&
+
+ /* Needed for referencing oldverts. */
+ (cd_shape_keyindex_offset != -1)) {
+
const bool act_is_basis = BKE_keyblock_is_basis(me->key, bm->shapenr - 1);
- /* active key is a base */
- if (act_is_basis && (cd_shape_keyindex_offset != -1)) {
- float(*fp)[3] = actkey->data;
+ /* Active key is a base. */
+ if (act_is_basis) {
+ const float(*fp)[3] = actkey->data;
ofs = MEM_callocN(sizeof(float) * 3 * bm->totvert, "currkey->data");
mvert = me->mvert;
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
- if (keyi != ORIGINDEX_NONE) {
+ /* Could use 'eve->co' or 'mvert->co', they're the same at this point. */
+ if (keyi != ORIGINDEX_NONE && keyi < actkey->totelem) {
sub_v3_v3v3(ofs[i], mvert->co, fp[keyi]);
}
else {
- /* if there are new vertices in the mesh, we can't propagate the offset
+ /* If there are new vertices in the mesh, we can't propagate the offset
* because it will only work for the existing vertices and not the new
- * ones, creating a mess when doing e.g. subdivide + translate */
+ * ones, creating a mess when doing e.g. subdivide + translate. */
MEM_freeN(ofs);
ofs = NULL;
break;
@@ -901,7 +888,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
(bm->shapenr - 1 == currkey->relative));
int cd_shape_offset;
int keyi;
- float(*ofs_pt)[3] = ofs;
+ const float(*ofs_pt)[3] = ofs;
float *newkey, (*oldkey)[3], *fp;
j = bm_to_mesh_shape_layer_index_from_kb(bm, currkey);
@@ -916,11 +903,11 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
if (currkey == actkey) {
copy_v3_v3(fp, eve->co);
- if (actkey != me->key->refkey) { /* important see bug [#30771] */
+ if (actkey != me->key->refkey) { /* Important see bug T30771. */
if (cd_shape_keyindex_offset != -1) {
if (oldverts) {
keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
- if (keyi != ORIGINDEX_NONE && keyi < currkey->totelem) { /* valid old vertex */
+ if (keyi != ORIGINDEX_NONE && keyi < currkey->totelem) { /* Valid old vertex. */
copy_v3_v3(mvert->co, oldverts[keyi].co);
}
}
@@ -928,29 +915,29 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
else if (j != -1) {
- /* in most cases this runs */
+ /* In most cases this runs. */
copy_v3_v3(fp, BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset));
}
else if ((oldkey != NULL) && (cd_shape_keyindex_offset != -1) &&
((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) &&
(keyi < currkey->totelem)) {
- /* old method of reconstructing keys via vertice's original key indices,
- * currently used if the new method above fails (which is theoretically
- * possible in certain cases of undo) */
+ /* Old method of reconstructing keys via vertice's original key indices,
+ * currently used if the new method above fails
+ * (which is theoretically possible in certain cases of undo). */
copy_v3_v3(fp, oldkey[keyi]);
}
else {
- /* fail! fill in with dummy value */
+ /* Fail! fill in with dummy value. */
copy_v3_v3(fp, mvert->co);
}
- /* propagate edited basis offsets to other shapes */
+ /* Propagate edited basis offsets to other shapes. */
if (apply_offset) {
add_v3_v3(fp, *ofs_pt++);
- /* Apply back new coordinates of offsetted shapekeys into BMesh.
+ /* Apply back new coordinates of offsetted shape-keys into BMesh.
* Otherwise, in case we call again BM_mesh_bm_to_me on same BMesh,
* we'll apply diff from previous call to BM_mesh_bm_to_me,
- * to shapekey values from *original creation of the BMesh*. See T50524. */
+ * to shape-key values from *original creation of the BMesh*. See T50524. */
copy_v3_v3(BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp);
}
@@ -970,14 +957,25 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
+ /* Run this even when shape keys aren't used since it may be used for hooks or vertex parents. */
+ if (params->update_shapekey_indices) {
+ /* We have written a new shape key, if this mesh is _not_ going to be freed,
+ * update the shape key indices to match the newly updated. */
+ if (cd_shape_keyindex_offset != -1) {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ BM_ELEM_CD_SET_INT(eve, cd_shape_keyindex_offset, i);
+ }
+ }
+ }
+
if (oldverts != NULL) {
MEM_freeN(oldverts);
}
- /* topology could be changed, ensure mdisps are ok */
+ /* Topology could be changed, ensure mdisps are ok. */
multires_topology_changed(me);
- /* to be removed as soon as COW is enabled by default. */
+ /* To be removed as soon as COW is enabled by default.. */
BKE_mesh_runtime_clear_geometry(me);
}
@@ -1000,7 +998,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
*/
void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra)
{
- /* must be an empty mesh. */
+ /* Must be an empty mesh. */
BLI_assert(me->totvert == 0);
BLI_assert(cd_mask_extra == NULL || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0);
@@ -1019,8 +1017,8 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, bm->totloop);
CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, bm->totface);
- /* don't process shapekeys, we only feed them through the modifier stack as needed,
- * e.g. for applying modifiers or the like*/
+ /* Don't process shape-keys, we only feed them through the modifier stack as needed,
+ * e.g. for applying modifiers or the like. */
CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH;
if (cd_mask_extra != NULL) {
CustomData_MeshMasks_update(&mask, cd_mask_extra);
@@ -1050,7 +1048,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
me->runtime.deformed_only = true;
- /* don't add origindex layer if one already exists */
+ /* Don't add origindex layer if one already exists. */
add_orig = !CustomData_has_layer(&bm->pdata, CD_ORIGINDEX);
index = CustomData_get_layer(&me->vdata, CD_ORIGINDEX);
@@ -1089,8 +1087,8 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
med->flag = BM_edge_flag_to_mflag(eed);
- /* handle this differently to editmode switching,
- * only enable draw for single user edges rather then calculating angle */
+ /* Handle this differently to editmode switching,
+ * only enable draw for single user edges rather then calculating angle. */
if ((med->flag & ME_EDGEDRAW) == 0) {
if (eed->l && eed->l == eed->l->radial_next) {
med->flag |= ME_EDGEDRAW;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.h b/source/blender/bmesh/intern/bmesh_mesh_conv.h
index f0302764a5f..65d5c6d5494 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.h
@@ -48,6 +48,16 @@ void BM_mesh_bm_from_me(BMesh *bm, const struct Mesh *me, const struct BMeshFrom
struct BMeshToMeshParams {
/** Update object hook indices & vertex parents. */
uint calc_object_remap : 1;
+ /**
+ * This re-assigns shape-key indices. Only do if the BMesh will have continued use
+ * to update the mesh & shape key in the future.
+ * In the case the BMesh is freed immediately, this can be left false.
+ *
+ * This is needed when flushing changes from edit-mode into object mode,
+ * so a second flush or edit-mode exit doesn't run with indices
+ * that have become invalid from updating the shape-key, see T71865.
+ */
+ uint update_shapekey_indices : 1;
struct CustomData_MeshMasks cd_mask_extra;
};
void BM_mesh_bm_to_me(struct Main *bmain,
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
index ffdcf179491..6801501e95b 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.c
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -29,11 +29,17 @@
#include "BKE_bvhutils.h"
+#include "atomic_ops.h"
+
#include "bmesh.h"
#include "bmesh_intersect_edges.h" /* own include */
+//#define INTERSECT_EDGES_DEBUG
+
+#define KDOP_TREE_TYPE 4
#define KDOP_AXIS_LEN 14
+#define BLI_STACK_PAIR_LEN 2 * KDOP_TREE_TYPE
/* -------------------------------------------------------------------- */
/** \name Weld Linked Wire Edges into Linked Faces
@@ -239,21 +245,16 @@ struct EDBMSplitElem {
struct EDBMSplitData {
BMesh *bm;
- BLI_Stack *pair_stack;
- int cut_edges_a_len;
- int cut_edges_b_len;
+ BLI_Stack **pair_stack;
+ int cut_edges_len;
float dist_sq;
float dist_sq_sq;
};
/* Utils */
-static void bm_vert_pair_elem_setup_ex(BMVert *v,
- float edge_index,
- struct EDBMSplitElem *r_pair_elem)
+static void bm_vert_pair_elem_setup_ex(BMVert *v, struct EDBMSplitElem *r_pair_elem)
{
- BLI_assert(v->head.index == -1);
- v->head.index = edge_index;
r_pair_elem->vert = v;
}
@@ -265,30 +266,34 @@ static void bm_edge_pair_elem_setup(BMEdge *e,
r_pair_elem->edge = e;
r_pair_elem->lambda = lambda;
- e->head.index++;
- /* Obs: Check Multithread. */
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- (*r_data_cut_edges_len)++;
+ /* Even though we have multiple atomic operations, this is fine here, since
+ * there is no dependency on order.
+ * The `e->head.index` check + atomic increment will ever be true once, as
+ * expected. We don't care which instance of the code actually ends up
+ * incrementing `r_data_cut_edge_len`, so there is no race condition here. */
+ if (atomic_fetch_and_add_int32(&e->head.index, 1) == 0) {
+ atomic_fetch_and_add_int32(r_data_cut_edges_len, 1);
}
}
/* Util for Vert x Edge and Edge x Edge callbacks */
-static bool bm_vertxedge_isect_impl_ex(BMVert *v,
- BMEdge *e,
- int edge_index,
- const float co[3],
- const float dir[3],
- float lambda,
- float data_dist_sq,
- int *data_cut_edges_len,
- struct EDBMSplitElem r_pair[2])
+static bool bm_edgexvert_isect_impl(BMVert *v,
+ BMEdge *e,
+ const float co[3],
+ const float dir[3],
+ float lambda,
+ float data_dist_sq,
+ int *data_cut_edges_len,
+ struct EDBMSplitElem r_pair[2])
{
- BLI_assert(v->head.index == -1);
-
BMVert *e_v;
float dist_sq_vert_factor;
+ if (!IN_RANGE_INCL(lambda, 0.0f, 1.0f)) {
+ /* Vert x Vert is already handled elsewhere. */
+ return false;
+ }
+
if (lambda < 0.5f) {
e_v = e->v1;
dist_sq_vert_factor = lambda;
@@ -299,27 +304,19 @@ static bool bm_vertxedge_isect_impl_ex(BMVert *v,
}
if (v != e_v) {
- CLAMP(lambda, 0.0f, 1.0f);
+ float dist_sq_vert = SQUARE(dist_sq_vert_factor) * len_squared_v3(dir);
+ if (dist_sq_vert < data_dist_sq) {
+ /* Vert x Vert is already handled elsewhere. */
+ return false;
+ }
- float near[3];
- madd_v3_v3v3fl(near, co, dir, lambda);
+ float closest[3];
+ madd_v3_v3v3fl(closest, co, dir, lambda);
- float dist_sq = len_squared_v3v3(v->co, near);
+ float dist_sq = len_squared_v3v3(v->co, closest);
if (dist_sq < data_dist_sq) {
- float dist_sq_vert = SQUARE(dist_sq_vert_factor) * len_squared_v3(dir);
- if (dist_sq_vert < data_dist_sq) {
- if (e_v->head.index != -1) {
- /* Vertex already has an intersection. */
- return false;
- }
-
- bm_vert_pair_elem_setup_ex(e_v, -2, &r_pair[1]);
- }
- else {
- bm_edge_pair_elem_setup(e, lambda, data_cut_edges_len, &r_pair[1]);
- }
-
- bm_vert_pair_elem_setup_ex(v, edge_index, &r_pair[0]);
+ bm_edge_pair_elem_setup(e, lambda, data_cut_edges_len, &r_pair[0]);
+ bm_vert_pair_elem_setup_ex(v, &r_pair[1]);
return true;
}
}
@@ -329,86 +326,56 @@ static bool bm_vertxedge_isect_impl_ex(BMVert *v,
/* Vertex x Vertex Callback */
-static bool bm_vertxvert_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+static bool bm_vertxvert_isect_cb(void *userdata, int index_a, int index_b, int thread)
{
struct EDBMSplitData *data = userdata;
BMVert *v_a = BM_vert_at_index(data->bm, index_a);
BMVert *v_b = BM_vert_at_index(data->bm, index_b);
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
-
- BLI_assert(v_a->head.index == -1);
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack[thread]);
- /* Set index -2 for sure that it will not repeat keys in `targetmap`. */
- bm_vert_pair_elem_setup_ex(v_a, -2, &pair[0]);
- bm_vert_pair_elem_setup_ex(v_b, -1, &pair[1]);
+ bm_vert_pair_elem_setup_ex(v_a, &pair[0]);
+ bm_vert_pair_elem_setup_ex(v_b, &pair[1]);
return true;
}
+static bool bm_vertxvert_self_isect_cb(void *userdata, int index_a, int index_b, int thread)
+{
+ if (index_a < index_b) {
+ return bm_vertxvert_isect_cb(userdata, index_a, index_b, thread);
+ }
+ return false;
+}
+
/* Vertex x Edge and Edge x Vertex Callbacks */
-static int bm_vertxedge_isect_impl(BMesh *bm,
- int vert_index,
- int edge_index,
- float data_dist_sq,
- int *data_cut_edges_len,
- struct EDBMSplitElem r_pair[2])
+static bool bm_edgexvert_isect_cb(void *userdata, int index_a, int index_b, int thread)
{
- BMVert *v = BM_vert_at_index(bm, vert_index);
- BMEdge *e = BM_edge_at_index(bm, edge_index);
-
- if (v->head.index != -1) {
- /* Only one vertex per edge. */
- return false;
- }
+ struct EDBMSplitData *data = userdata;
+ BMEdge *e = BM_edge_at_index(data->bm, index_a);
+ BMVert *v = BM_vert_at_index(data->bm, index_b);
float co[3], dir[3], lambda;
copy_v3_v3(co, e->v1->co);
sub_v3_v3v3(dir, e->v2->co, co);
lambda = ray_point_factor_v3_ex(v->co, co, dir, 0.0f, -1.0f);
- return bm_vertxedge_isect_impl_ex(
- v, e, edge_index, co, dir, lambda, data_dist_sq, data_cut_edges_len, r_pair);
-}
-
-static bool bm_vertxedge_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
-{
- struct EDBMSplitData *data = userdata;
struct EDBMSplitElem pair_tmp[2];
- if (bm_vertxedge_isect_impl(
- data->bm, index_a, index_b, data->dist_sq, &data->cut_edges_b_len, pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ if (bm_edgexvert_isect_impl(
+ v, e, co, dir, lambda, data->dist_sq, &data->cut_edges_len, pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack[thread]);
pair[0] = pair_tmp[0];
pair[1] = pair_tmp[1];
-
- return true;
- }
-
- return false;
-}
-
-static bool bm_edgexvert_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
-{
- struct EDBMSplitData *data = userdata;
- struct EDBMSplitElem pair_tmp[2];
- if (bm_vertxedge_isect_impl(
- data->bm, index_b, index_a, data->dist_sq, &data->cut_edges_a_len, pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[1];
- pair[1] = pair_tmp[0];
-
- return true;
}
+ /* Always return false with edges. */
return false;
}
/* Edge x Edge Callbacks */
-static void bm_edgexedge_isect_impl(struct EDBMSplitData *data,
- int index_a,
- int index_b,
+static bool bm_edgexedge_isect_impl(struct EDBMSplitData *data,
BMEdge *e_a,
BMEdge *e_b,
const float co_a[3],
@@ -416,7 +383,8 @@ static void bm_edgexedge_isect_impl(struct EDBMSplitData *data,
const float co_b[3],
const float dir_b[3],
float lambda_a,
- float lambda_b)
+ float lambda_b,
+ struct EDBMSplitElem r_pair[2])
{
float dist_sq_va_factor, dist_sq_vb_factor;
BMVert *e_a_v, *e_b_v;
@@ -439,8 +407,18 @@ static void bm_edgexedge_isect_impl(struct EDBMSplitData *data,
}
if (e_a_v != e_b_v) {
- CLAMP(lambda_a, 0.0f, 1.0f);
- CLAMP(lambda_b, 0.0f, 1.0f);
+ if (!IN_RANGE_INCL(lambda_a, 0.0f, 1.0f) || !IN_RANGE_INCL(lambda_b, 0.0f, 1.0f)) {
+ /* Vert x Edge is already handled elsewhere. */
+ return false;
+ }
+
+ float dist_sq_va = SQUARE(dist_sq_va_factor) * len_squared_v3(dir_a);
+ float dist_sq_vb = SQUARE(dist_sq_vb_factor) * len_squared_v3(dir_b);
+
+ if (dist_sq_va < data->dist_sq || dist_sq_vb < data->dist_sq) {
+ /* Vert x Edge is already handled elsewhere. */
+ return false;
+ }
float near_a[3], near_b[3];
madd_v3_v3v3fl(near_a, co_a, dir_a, lambda_a);
@@ -448,49 +426,25 @@ static void bm_edgexedge_isect_impl(struct EDBMSplitData *data,
float dist_sq = len_squared_v3v3(near_a, near_b);
if (dist_sq < data->dist_sq) {
- struct EDBMSplitElem pair_tmp[2];
-
- float dist_sq_va = SQUARE(dist_sq_va_factor) * len_squared_v3(dir_a);
- float dist_sq_vb = SQUARE(dist_sq_vb_factor) * len_squared_v3(dir_b);
-
- if (dist_sq_va < data->dist_sq) {
- if (e_a_v->head.index != -1) {
- /* Only one vertex per edge. */
- return;
- }
- bm_vert_pair_elem_setup_ex(e_a_v, index_b, &pair_tmp[0]);
- }
-
- if (dist_sq_vb < data->dist_sq) {
- if (e_b_v->head.index != -1) {
- /* Only one vertex per edge. */
- return;
- }
- bm_vert_pair_elem_setup_ex(e_b_v, index_a, &pair_tmp[1]);
- }
- else {
- bm_edge_pair_elem_setup(e_b, lambda_b, &data->cut_edges_b_len, &pair_tmp[1]);
- }
-
- /* Don't setup edges before a return. */
- if (dist_sq_va >= data->dist_sq) {
- bm_edge_pair_elem_setup(e_a, lambda_a, &data->cut_edges_a_len, &pair_tmp[0]);
- }
-
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[0];
- pair[1] = pair_tmp[1];
+ bm_edge_pair_elem_setup(e_a, lambda_a, &data->cut_edges_len, &r_pair[0]);
+ bm_edge_pair_elem_setup(e_b, lambda_b, &data->cut_edges_len, &r_pair[1]);
+ return true;
}
}
+ return false;
}
-static bool bm_edgexedge_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+static bool bm_edgexedge_isect_cb(void *userdata, int index_a, int index_b, int thread)
{
- bool ret = false;
struct EDBMSplitData *data = userdata;
BMEdge *e_a = BM_edge_at_index(data->bm, index_a);
BMEdge *e_b = BM_edge_at_index(data->bm, index_b);
+ if (BM_edge_share_vert_check(e_a, e_b)) {
+ /* The other vertices may intersect but Vert x Edge is already handled elsewhere. */
+ return false;
+ }
+
float co_a[3], dir_a[3], co_b[3], dir_b[3];
copy_v3_v3(co_a, e_a->v1->co);
sub_v3_v3v3(dir_a, e_a->v2->co, co_a);
@@ -501,136 +455,56 @@ static bool bm_edgexedge_isect_cb(void *userdata, int index_a, int index_b, int
float lambda_a, lambda_b;
/* Using with dist^4 as `epsilon` is not the best solution, but it fits in most cases. */
if (isect_ray_ray_epsilon_v3(co_a, dir_a, co_b, dir_b, data->dist_sq_sq, &lambda_a, &lambda_b)) {
- if (ELEM(index_b, e_a->v1->head.index, e_a->v2->head.index) ||
- ELEM(index_a, e_b->v1->head.index, e_b->v2->head.index)) {
- return ret;
- }
-
- /* Edge x Edge returns always false. */
- bm_edgexedge_isect_impl(
- data, index_a, index_b, e_a, e_b, co_a, dir_a, co_b, dir_b, lambda_a, lambda_b);
- }
- else {
- /* Parallel */
struct EDBMSplitElem pair_tmp[2];
- float vec[3], len_sq_a, len_sq_b, lambda;
- sub_v3_v3v3(vec, co_b, co_a);
- len_sq_a = len_squared_v3(dir_a);
- len_sq_b = len_squared_v3(dir_b);
-
- if (!ELEM(e_b->v1, e_a->v1, e_a->v2) && e_b->v1->head.index == -1) {
- lambda = dot_v3v3(vec, dir_a) / len_sq_a;
- if (bm_vertxedge_isect_impl_ex(e_b->v1,
- e_a,
- index_a,
- co_a,
- dir_a,
- lambda,
- data->dist_sq,
- &data->cut_edges_a_len,
- pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[1];
- pair[1] = pair_tmp[0];
- ret |= true;
- }
- }
-
- if (!ELEM(e_a->v1, e_b->v1, e_b->v2) && e_a->v1->head.index == -1) {
- lambda = -dot_v3v3(vec, dir_b) / len_sq_b;
- if (bm_vertxedge_isect_impl_ex(e_a->v1,
- e_b,
- index_b,
- co_b,
- dir_b,
- lambda,
- data->dist_sq,
- &data->cut_edges_b_len,
- pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[0];
- pair[1] = pair_tmp[1];
- ret |= true;
- }
+ if (bm_edgexedge_isect_impl(
+ data, e_a, e_b, co_a, dir_a, co_b, dir_b, lambda_a, lambda_b, pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack[thread]);
+ pair[0] = pair_tmp[0];
+ pair[1] = pair_tmp[1];
}
+ }
- add_v3_v3(vec, dir_b);
- if (!ELEM(e_b->v2, e_a->v1, e_a->v2) && e_b->v2->head.index == -1) {
- lambda = dot_v3v3(vec, dir_a) / len_sq_a;
- if (bm_vertxedge_isect_impl_ex(e_b->v2,
- e_a,
- index_a,
- co_a,
- dir_a,
- lambda,
- data->dist_sq,
- &data->cut_edges_a_len,
- pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[1];
- pair[1] = pair_tmp[0];
- ret |= true;
- }
- }
+ /* Edge x Edge returns always false. */
+ return false;
+}
- sub_v3_v3(vec, dir_a);
- if (!ELEM(e_a->v2, e_b->v1, e_b->v2) && e_a->v2->head.index == -1) {
- lambda = 1.0f - dot_v3v3(vec, dir_b) / len_sq_b;
- if (bm_vertxedge_isect_impl_ex(e_a->v2,
- e_b,
- index_b,
- co_b,
- dir_b,
- lambda,
- data->dist_sq,
- &data->cut_edges_b_len,
- pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[0];
- pair[1] = pair_tmp[1];
- ret |= true;
- }
- }
+static bool bm_edgexedge_self_isect_cb(void *userdata, int index_a, int index_b, int thread)
+{
+ if (index_a < index_b) {
+ return bm_edgexedge_isect_cb(userdata, index_a, index_b, thread);
}
-
- return ret;
+ return false;
}
/* -------------------------------------------------------------------- */
/* BVHTree Overlap Function */
-static void bvhtree_overlap_thread_safe(const BVHTree *tree1,
- const BVHTree *tree2,
- BVHTree_OverlapCallback callback,
- void *userdata)
+static void bm_elemxelem_bvhtree_overlap(const BVHTree *tree1,
+ const BVHTree *tree2,
+ BVHTree_OverlapCallback callback,
+ struct EDBMSplitData *data,
+ BLI_Stack **pair_stack)
{
- BLI_bvhtree_overlap_ex(tree1, tree2, NULL, callback, userdata, BVH_OVERLAP_BREAK_ON_FIRST);
+ int parallel_tasks_num = BLI_bvhtree_overlap_thread_num(tree1);
+ for (int i = 0; i < parallel_tasks_num; i++) {
+ if (pair_stack[i] == NULL) {
+ pair_stack[i] = BLI_stack_new(sizeof(struct EDBMSplitElem[2]), __func__);
+ }
+ }
+ data->pair_stack = pair_stack;
+ BLI_bvhtree_overlap_ex(tree1, tree2, NULL, callback, data, 1, BVH_OVERLAP_USE_THREADING);
}
/* -------------------------------------------------------------------- */
/* Callbacks for `BLI_qsort_r` */
-static int sort_cmp_by_lambda_a_cb(const void *index1_v, const void *index2_v, void *keys_v)
+static int sort_cmp_by_lambda_cb(const void *index1_v, const void *index2_v, void *keys_v)
{
- const struct EDBMSplitElem(*pair_array)[2] = keys_v;
+ const struct EDBMSplitElem *pair_flat = keys_v;
const int index1 = *(int *)index1_v;
const int index2 = *(int *)index2_v;
- if (pair_array[index1][0].lambda > pair_array[index2][0].lambda) {
- return 1;
- }
- else {
- return -1;
- }
-}
-
-static int sort_cmp_by_lambda_b_cb(const void *index1_v, const void *index2_v, void *keys_v)
-{
- const struct EDBMSplitElem(*pair_array)[2] = keys_v;
- const int index1 = *(int *)index1_v;
- const int index2 = *(int *)index2_v;
-
- if (pair_array[index1][1].lambda > pair_array[index2][1].lambda) {
+ if (pair_flat[index1].lambda > pair_flat[index2].lambda) {
return 1;
}
else {
@@ -641,6 +515,8 @@ static int sort_cmp_by_lambda_b_cb(const void *index1_v, const void *index2_v, v
/* -------------------------------------------------------------------- */
/* Main API */
+#define INTERSECT_EDGES
+
bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap)
{
bool ok = false;
@@ -650,157 +526,227 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
BMEdge *e;
int i;
- BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE);
-
/* Store all intersections in this array. */
struct EDBMSplitElem(*pair_iter)[2], (*pair_array)[2] = NULL;
- BLI_Stack *pair_stack = BLI_stack_new(sizeof(*pair_array), __func__);
int pair_len = 0;
- float dist_sq = SQUARE(dist);
+ BLI_Stack *pair_stack[BLI_STACK_PAIR_LEN] = {NULL};
+ BLI_Stack **pair_stack_vertxvert = pair_stack;
+ BLI_Stack **pair_stack_edgexelem = &pair_stack[KDOP_TREE_TYPE];
+
+ const float dist_sq = SQUARE(dist);
+ const float dist_half = dist / 2;
+
struct EDBMSplitData data = {
.bm = bm,
.pair_stack = pair_stack,
- .cut_edges_a_len = 0,
- .cut_edges_b_len = 0,
+ .cut_edges_len = 0,
.dist_sq = dist_sq,
.dist_sq_sq = SQUARE(dist_sq),
};
+ BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE);
+
/* tag and count the verts to be tested. */
int verts_act_len = 0, verts_remain_len = 0;
- int loose_verts_act_len = 0, loose_verts_remain_len = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, hflag)) {
BM_elem_flag_enable(v, BM_ELEM_TAG);
v->head.index = -1;
verts_act_len++;
- if (!v->e) {
- loose_verts_act_len++;
- }
}
else {
BM_elem_flag_disable(v, BM_ELEM_TAG);
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
v->head.index = -1;
verts_remain_len++;
- if (!v->e) {
- loose_verts_remain_len++;
- }
}
}
}
bm->elem_index_dirty |= BM_VERT;
/* Start the creation of BVHTrees. */
- BVHTree *tree_loose_verts_act = NULL, *tree_loose_verts_remain = NULL;
- if (loose_verts_act_len) {
- tree_loose_verts_act = BLI_bvhtree_new(loose_verts_act_len, dist, 2, KDOP_AXIS_LEN);
+ BVHTree *tree_verts_act = NULL, *tree_verts_remain = NULL;
+ if (verts_act_len) {
+ tree_verts_act = BLI_bvhtree_new(verts_act_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
}
- if (loose_verts_remain_len) {
- tree_loose_verts_remain = BLI_bvhtree_new(loose_verts_remain_len, 0.0f, 2, KDOP_AXIS_LEN);
+ if (verts_remain_len) {
+ tree_verts_remain = BLI_bvhtree_new(
+ verts_remain_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
}
- if (tree_loose_verts_act || tree_loose_verts_remain) {
+ if (tree_verts_act || tree_verts_remain) {
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- if (tree_loose_verts_act && !v->e) {
- BLI_bvhtree_insert(tree_loose_verts_act, i, v->co, 1);
+ if (tree_verts_act) {
+ BLI_bvhtree_insert(tree_verts_act, i, v->co, 1);
}
}
- else if (tree_loose_verts_remain && !v->e && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- BLI_bvhtree_insert(tree_loose_verts_remain, i, v->co, 1);
+ else if (tree_verts_remain && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ BLI_bvhtree_insert(tree_verts_remain, i, v->co, 1);
}
}
- if (tree_loose_verts_act) {
- BLI_bvhtree_balance(tree_loose_verts_act);
+
+ if (tree_verts_act) {
+ BLI_bvhtree_balance(tree_verts_act);
+ /* First pair search. */
+ bm_elemxelem_bvhtree_overlap(
+ tree_verts_act, tree_verts_act, bm_vertxvert_self_isect_cb, &data, pair_stack_vertxvert);
}
- if (tree_loose_verts_remain) {
- BLI_bvhtree_balance(tree_loose_verts_remain);
+ if (tree_verts_remain) {
+ BLI_bvhtree_balance(tree_verts_remain);
}
- if (tree_loose_verts_act && tree_loose_verts_remain) {
- /* First pair search. */
- bvhtree_overlap_thread_safe(
- tree_loose_verts_act, tree_loose_verts_remain, bm_vertxvert_isect_cb, &data);
+ if (tree_verts_act && tree_verts_remain) {
+ bm_elemxelem_bvhtree_overlap(
+ tree_verts_remain, tree_verts_act, bm_vertxvert_isect_cb, &data, pair_stack_vertxvert);
}
}
+ for (i = KDOP_TREE_TYPE; i--;) {
+ if (pair_stack_vertxvert[i]) {
+ pair_len += BLI_stack_count(pair_stack_vertxvert[i]);
+ }
+ }
+
+#ifdef INTERSECT_EDGES
+ uint vertxvert_pair_len = pair_len;
+
+# define EDGE_ACT_TO_TEST 1
+# define EDGE_REMAIN_TO_TEST 2
/* Tag and count the edges. */
int edges_act_len = 0, edges_remain_len = 0;
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) ||
+ (len_squared_v3v3(e->v1->co, e->v2->co) < dist_sq)) {
+ /* Don't test hidden edges or smaller than the minimum distance.
+ * These have already been handled in the vertices overlap. */
+ BM_elem_index_set(e, 0);
+ continue;
+ }
+
if (BM_elem_flag_test(e->v1, BM_ELEM_TAG) || BM_elem_flag_test(e->v2, BM_ELEM_TAG)) {
- BM_elem_flag_enable(e, BM_ELEM_TAG);
+ BM_elem_index_set(e, EDGE_ACT_TO_TEST);
edges_act_len++;
}
else {
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- edges_remain_len++;
- }
+ BM_elem_index_set(e, EDGE_REMAIN_TO_TEST);
+ edges_remain_len++;
}
}
- if (edges_remain_len) {
- BVHTree *tree_edges_act = NULL, *tree_edges_remain = NULL;
- tree_edges_remain = BLI_bvhtree_new(edges_remain_len, 0.0f, 2, KDOP_AXIS_LEN);
- if (edges_act_len) {
- tree_edges_act = BLI_bvhtree_new(edges_act_len, dist, 2, KDOP_AXIS_LEN);
- }
+ BVHTree *tree_edges_act = NULL, *tree_edges_remain = NULL;
+ if (edges_act_len) {
+ tree_edges_act = BLI_bvhtree_new(edges_act_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
+ }
+
+ if (edges_remain_len && (tree_edges_act || tree_verts_act)) {
+ tree_edges_remain = BLI_bvhtree_new(
+ edges_remain_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
+ }
+ if (tree_edges_act || tree_edges_remain) {
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ int edge_test = BM_elem_index_get(e);
float co[2][3];
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- if (tree_edges_act) {
- e->head.index = 0;
- copy_v3_v3(co[0], e->v1->co);
- copy_v3_v3(co[1], e->v2->co);
- BLI_bvhtree_insert(tree_edges_act, i, co[0], 2);
- }
+ if (edge_test == EDGE_ACT_TO_TEST) {
+ BLI_assert(tree_edges_act);
+ e->head.index = 0;
+ copy_v3_v3(co[0], e->v1->co);
+ copy_v3_v3(co[1], e->v2->co);
+ BLI_bvhtree_insert(tree_edges_act, i, co[0], 2);
}
- else if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- /* Tag used in the overlap callbacks. */
- BM_elem_flag_enable(e, BM_ELEM_TAG);
+ else if (edge_test == EDGE_REMAIN_TO_TEST) {
+ BLI_assert(tree_edges_act);
e->head.index = 0;
copy_v3_v3(co[0], e->v1->co);
copy_v3_v3(co[1], e->v2->co);
BLI_bvhtree_insert(tree_edges_remain, i, co[0], 2);
}
+# ifdef INTERSECT_EDGES_DEBUG
+ else {
+ e->head.index = 0;
+ }
+# endif
+ /* Tag used when converting pairs to vert x vert. */
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
}
+# undef EDGE_ACT_TO_TEST
+# undef EDGE_REMAIN_TO_TEST
+
/* Use `e->head.index` to count intersections. */
bm->elem_index_dirty |= BM_EDGE;
- BLI_bvhtree_balance(tree_edges_remain);
if (tree_edges_act) {
BLI_bvhtree_balance(tree_edges_act);
}
+ if (tree_edges_remain) {
+ BLI_bvhtree_balance(tree_edges_remain);
+ }
+
+ int edgexedge_pair_len = 0;
if (tree_edges_act) {
/* Edge x Edge */
- bvhtree_overlap_thread_safe(tree_edges_act, tree_edges_remain, bm_edgexedge_isect_cb, &data);
+ bm_elemxelem_bvhtree_overlap(
+ tree_edges_act, tree_edges_act, bm_edgexedge_self_isect_cb, &data, pair_stack_edgexelem);
- if (tree_loose_verts_remain) {
- /* Edge x Vert */
- bvhtree_overlap_thread_safe(
- tree_edges_act, tree_loose_verts_remain, bm_edgexvert_isect_cb, &data);
+ if (tree_edges_remain) {
+ bm_elemxelem_bvhtree_overlap(
+ tree_edges_remain, tree_edges_act, bm_edgexedge_isect_cb, &data, pair_stack_edgexelem);
+ }
+
+ for (i = KDOP_TREE_TYPE; i--;) {
+ if (pair_stack_edgexelem[i]) {
+ edgexedge_pair_len += BLI_stack_count(pair_stack_edgexelem[i]);
+ }
+ }
+
+ if (tree_verts_act) {
+ /* Edge v Vert */
+ bm_elemxelem_bvhtree_overlap(
+ tree_edges_act, tree_verts_act, bm_edgexvert_isect_cb, &data, pair_stack_edgexelem);
+ }
+
+ if (tree_verts_remain) {
+ /* Edge v Vert */
+ bm_elemxelem_bvhtree_overlap(
+ tree_edges_act, tree_verts_remain, bm_edgexvert_isect_cb, &data, pair_stack_edgexelem);
}
BLI_bvhtree_free(tree_edges_act);
}
- if (tree_loose_verts_act) {
- /* Vert x Edge */
- bvhtree_overlap_thread_safe(
- tree_loose_verts_act, tree_edges_remain, bm_vertxedge_isect_cb, &data);
+ if (tree_verts_act && tree_edges_remain) {
+ /* Edge v Vert */
+ bm_elemxelem_bvhtree_overlap(
+ tree_edges_remain, tree_verts_act, bm_edgexvert_isect_cb, &data, pair_stack_edgexelem);
}
BLI_bvhtree_free(tree_edges_remain);
- pair_len = BLI_stack_count(pair_stack);
- if (pair_len) {
+ int edgexelem_pair_len = 0;
+ for (i = KDOP_TREE_TYPE; i--;) {
+ if (pair_stack_edgexelem[i]) {
+ edgexelem_pair_len += BLI_stack_count(pair_stack_edgexelem[i]);
+ }
+ }
+
+ pair_len += edgexelem_pair_len;
+ int edgexvert_pair_len = edgexelem_pair_len - edgexedge_pair_len;
+
+ if (edgexelem_pair_len) {
pair_array = MEM_mallocN(sizeof(*pair_array) * pair_len, __func__);
- BLI_stack_pop_n_reverse(pair_stack, pair_array, pair_len);
+
+ pair_iter = pair_array;
+ for (i = 0; i < BLI_STACK_PAIR_LEN; i++) {
+ if (pair_stack[i]) {
+ uint count = (uint)BLI_stack_count(pair_stack[i]);
+ BLI_stack_pop_n_reverse(pair_stack[i], pair_iter, count);
+ pair_iter += count;
+ }
+ }
/* Map intersections per edge. */
union {
@@ -811,82 +757,103 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
int as_int[0];
} * e_map_iter, *e_map;
- size_t e_map_size = (max_ii(data.cut_edges_a_len, data.cut_edges_b_len) * sizeof(*e_map)) +
- (pair_len * sizeof(*(e_map->cuts_index)));
+# ifdef INTERSECT_EDGES_DEBUG
+ int cut_edges_len = 0;
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (e->head.index != 0) {
+ cut_edges_len++;
+ }
+ }
+ BLI_assert(cut_edges_len == data.cut_edges_len);
+# endif
+
+ size_t e_map_size = (data.cut_edges_len * sizeof(*e_map)) +
+ (((size_t)2 * edgexedge_pair_len + edgexvert_pair_len) *
+ sizeof(*(e_map->cuts_index)));
e_map = MEM_mallocN(e_map_size, __func__);
+ int map_len = 0;
/* Convert every pair to Vert x Vert. */
- for (int pair = 0; pair < 2; pair++) {
- int map_len = 0;
- pair_iter = &pair_array[0];
- for (i = 0; i < pair_len; i++, pair_iter++) {
- if ((*pair_iter)[pair].elem->head.htype != BM_EDGE) {
- /* Take the opportunity to set all vert indices to -1 again. */
- (*pair_iter)[pair].elem->head.index = -1;
- continue;
- }
- e = (*pair_iter)[pair].edge;
- if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- int e_cuts_len = e->head.index;
-
- e_map_iter = (void *)&e_map->as_int[map_len];
- e_map_iter->cuts_len = e_cuts_len;
- e_map_iter->cuts_index[0] = i;
-
- /* Use `e->head.index` to indicate which slot to fill with the `cut` index. */
- e->head.index = map_len + 1;
- map_len += 1 + e_cuts_len;
- }
- else {
- e_map->as_int[++e->head.index] = i;
- }
+
+ /* The list of pairs starts with [vert x vert] followed by [edge x edge]
+ * and finally [edge x vert].
+ * Ignore the [vert x vert] pairs */
+ struct EDBMSplitElem *pair_flat, *pair_flat_iter;
+ pair_flat = (struct EDBMSplitElem *)&pair_array[vertxvert_pair_len];
+ pair_flat_iter = &pair_flat[0];
+ uint pair_flat_len = 2 * edgexelem_pair_len;
+ for (i = 0; i < pair_flat_len; i++, pair_flat_iter++) {
+ if (pair_flat_iter->elem->head.htype != BM_EDGE) {
+ continue;
}
- /* Split Edges A to set all Vert x Edge. */
- for (i = 0; i < map_len;
- e_map_iter = (void *)&e_map->as_int[i], i += 1 + e_map_iter->cuts_len) {
-
- /* sort by lambda. */
- BLI_qsort_r(e_map_iter->cuts_index,
- e_map_iter->cuts_len,
- sizeof(*(e_map->cuts_index)),
- pair == 0 ? sort_cmp_by_lambda_a_cb : sort_cmp_by_lambda_b_cb,
- pair_array);
-
- float lambda, lambda_prev = 0.0f;
- for (int j = 0; j < e_map_iter->cuts_len; j++) {
- struct EDBMSplitElem *pair_elem = &pair_array[e_map_iter->cuts_index[j]][pair];
- lambda = (pair_elem->lambda - lambda_prev) / (1.0f - lambda_prev);
- lambda_prev = pair_elem->lambda;
- e = pair_elem->edge;
-
- BMVert *v_new = BM_edge_split(bm, e, e->v1, NULL, lambda);
- v_new->head.index = -1;
- pair_elem->vert = v_new;
- }
+ e = pair_flat_iter->edge;
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ int e_cuts_len = e->head.index;
+
+ e_map_iter = (void *)&e_map->as_int[map_len];
+ e_map_iter->cuts_len = e_cuts_len;
+ e_map_iter->cuts_index[0] = i;
+
+ /* Use `e->head.index` to indicate which slot to fill with the `cut` index. */
+ e->head.index = map_len + 1;
+ map_len += 1 + e_cuts_len;
+ }
+ else {
+ e_map->as_int[++e->head.index] = i;
+ }
+ }
+
+ /* Split Edges A to set all Vert x Edge. */
+ for (i = 0; i < map_len;
+ e_map_iter = (void *)&e_map->as_int[i], i += 1 + e_map_iter->cuts_len) {
+
+ /* sort by lambda. */
+ BLI_qsort_r(e_map_iter->cuts_index,
+ e_map_iter->cuts_len,
+ sizeof(*(e_map->cuts_index)),
+ sort_cmp_by_lambda_cb,
+ pair_flat);
+
+ float lambda, lambda_prev = 0.0f;
+ for (int j = 0; j < e_map_iter->cuts_len; j++) {
+ uint index = e_map_iter->cuts_index[j];
+
+ struct EDBMSplitElem *pair_elem = &pair_flat[index];
+ lambda = (pair_elem->lambda - lambda_prev) / (1.0f - lambda_prev);
+ lambda_prev = pair_elem->lambda;
+ e = pair_elem->edge;
+
+ BMVert *v_new = BM_edge_split(bm, e, e->v1, NULL, lambda);
+ v_new->head.index = -1;
+ pair_elem->vert = v_new;
}
}
MEM_freeN(e_map);
}
}
+#endif
- BLI_bvhtree_free(tree_loose_verts_act);
- BLI_bvhtree_free(tree_loose_verts_remain);
+ BLI_bvhtree_free(tree_verts_act);
+ BLI_bvhtree_free(tree_verts_remain);
if (r_targetmap) {
- if (pair_array == NULL) {
- pair_len = BLI_stack_count(pair_stack);
- if (pair_len) {
- pair_array = MEM_mallocN(sizeof(*pair_array) * pair_len, __func__);
- BLI_stack_pop_n_reverse(pair_stack, pair_array, pair_len);
+ if (pair_len && pair_array == NULL) {
+ pair_array = MEM_mallocN(sizeof(*pair_array) * pair_len, __func__);
+ pair_iter = pair_array;
+ for (i = 0; i < BLI_STACK_PAIR_LEN; i++) {
+ if (pair_stack[i]) {
+ uint count = (uint)BLI_stack_count(pair_stack[i]);
+ BLI_stack_pop_n_reverse(pair_stack[i], pair_iter, count);
+ pair_iter += count;
+ }
}
}
if (pair_array) {
- /* Organize the vertices in the order they will be merged. */
pair_iter = &pair_array[0];
for (i = 0; i < pair_len; i++, pair_iter++) {
BLI_assert((*pair_iter)[0].elem->head.htype == BM_VERT);
@@ -900,7 +867,11 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
}
}
- BLI_stack_free(pair_stack);
+ for (i = BLI_STACK_PAIR_LEN; i--;) {
+ if (pair_stack[i]) {
+ BLI_stack_free(pair_stack[i]);
+ }
+ }
if (pair_array) {
MEM_freeN(pair_array);
}
diff --git a/source/blender/collada/AnimationClipExporter.h b/source/blender/collada/AnimationClipExporter.h
index ead894dc941..25c69fe6b93 100644
--- a/source/blender/collada/AnimationClipExporter.h
+++ b/source/blender/collada/AnimationClipExporter.h
@@ -14,6 +14,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#ifndef __ANIMATIONCLIPEXPORTER_H__
+#define __ANIMATIONCLIPEXPORTER_H__
+
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
@@ -44,3 +47,5 @@ class AnimationClipExporter : COLLADASW::LibraryAnimationClips {
void exportAnimationClips(Scene *sce);
};
+
+#endif /* __ANIMATIONCLIPEXPORTER_H__ */
diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h
index 2be2dadeeeb..64751ec5327 100644
--- a/source/blender/collada/AnimationExporter.h
+++ b/source/blender/collada/AnimationExporter.h
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BC_ANIMATION_EXPORTER_H__
-#define __BC_ANIMATION_EXPORTER_H__
+#ifndef __ANIMATIONEXPORTER_H__
+#define __ANIMATIONEXPORTER_H__
#include <stdlib.h>
#include <stdio.h>
@@ -263,4 +263,4 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
#endif
};
-#endif
+#endif /* __ANIMATIONEXPORTER_H__ */
diff --git a/source/blender/collada/BCAnimationCurve.h b/source/blender/collada/BCAnimationCurve.h
index 33533258dc2..4651290ea0f 100644
--- a/source/blender/collada/BCAnimationCurve.h
+++ b/source/blender/collada/BCAnimationCurve.h
@@ -17,8 +17,8 @@
* All rights reserved.
*/
-#ifndef __BC_ANIMATION_CURVE_H__
-#define __BC_ANIMATION_CURVE_H__
+#ifndef __BCANIMATIONCURVE_H__
+#define __BCANIMATIONCURVE_H__
#include "collada_utils.h"
#include "BCSampleData.h"
@@ -148,4 +148,4 @@ class BCAnimationCurve {
typedef std::map<BCCurveKey, BCAnimationCurve *> BCAnimationCurveMap;
-#endif
+#endif /* __BCANIMATIONCURVE_H__ */
diff --git a/source/blender/collada/BCAnimationSampler.h b/source/blender/collada/BCAnimationSampler.h
index e8d2ab56ae7..0f192a7a68b 100644
--- a/source/blender/collada/BCAnimationSampler.h
+++ b/source/blender/collada/BCAnimationSampler.h
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BC_ANIMATION_CURVE_CONTAINER_H__
-#define __BC_ANIMATION_CURVE_CONTAINER_H__
+#ifndef __BCANIMATIONSAMPLER_H__
+#define __BCANIMATIONSAMPLER_H__
#include "BCAnimationCurve.h"
#include "BCSampleData.h"
@@ -191,4 +191,4 @@ class BCAnimationSampler {
std::set<Object *> &animated_objects);
};
-#endif
+#endif /* __BCANIMATIONSAMPLER_H__ */
diff --git a/source/blender/collada/BCMath.h b/source/blender/collada/BCMath.h
index bb62f6c179a..9ecea85b08c 100644
--- a/source/blender/collada/BCMath.h
+++ b/source/blender/collada/BCMath.h
@@ -18,8 +18,8 @@
* \ingroup collada
*/
-#ifndef __BCMATRIX_H__
-#define __BCMATRIX_H__
+#ifndef __BCMATH_H__
+#define __BCMATH_H__
#include "BlenderTypes.h"
@@ -107,4 +107,4 @@ class BCMatrix {
static void transpose(Matrix &matrix);
};
-#endif
+#endif /* __BCMATH_H__ */
diff --git a/source/blender/collada/BCSampleData.h b/source/blender/collada/BCSampleData.h
index c4e840ac3b3..07ecb544c71 100644
--- a/source/blender/collada/BCSampleData.h
+++ b/source/blender/collada/BCSampleData.h
@@ -17,8 +17,8 @@
* All rights reserved.
*/
-#ifndef __BC_SAMPLE_H__
-#define __BC_SAMPLE_H__
+#ifndef __BCSAMPLEDATA_H__
+#define __BCSAMPLEDATA_H__
#include <string>
#include <map>
@@ -63,4 +63,4 @@ typedef std::map<Object *, BCSample *> BCSampleMap;
typedef std::map<int, const BCSample *> BCFrameSampleMap;
typedef std::map<int, const BCMatrix *> BCMatrixSampleMap;
-#endif
+#endif /* __BCSAMPLEDATA_H__ */
diff --git a/source/blender/collada/ErrorHandler.h b/source/blender/collada/ErrorHandler.h
index 5851e5da67b..f040855244d 100644
--- a/source/blender/collada/ErrorHandler.h
+++ b/source/blender/collada/ErrorHandler.h
@@ -18,6 +18,9 @@
* \ingroup collada
*/
+#ifndef __ERRORHANDLER_H__
+#define __ERRORHANDLER_H__
+
#include <string>
#include <map>
#include <vector>
@@ -50,3 +53,5 @@ class ErrorHandler : public COLLADASaxFWL::IErrorHandler {
/** Hold error status. */
bool mError;
};
+
+#endif /* __ERRORHANDLER_H__ */
diff --git a/source/blender/collada/ExtraHandler.h b/source/blender/collada/ExtraHandler.h
index b695f5221f6..021eb8e9663 100644
--- a/source/blender/collada/ExtraHandler.h
+++ b/source/blender/collada/ExtraHandler.h
@@ -18,6 +18,9 @@
* \ingroup collada
*/
+#ifndef __EXTRAHANDLER_H__
+#define __EXTRAHANDLER_H__
+
#include <string>
#include <map>
#include <vector>
@@ -76,3 +79,5 @@ class ExtraHandler : public COLLADASaxFWL::IExtraDataCallbackHandler {
ExtraTags *currentExtraTags;
std::string currentElement;
};
+
+#endif /* __EXTRAHANDLER_H__ */
diff --git a/source/blender/collada/ExtraTags.h b/source/blender/collada/ExtraTags.h
index 2d827159af8..9191182c757 100644
--- a/source/blender/collada/ExtraTags.h
+++ b/source/blender/collada/ExtraTags.h
@@ -18,6 +18,9 @@
* \ingroup collada
*/
+#ifndef __EXTRATAGS_H__
+#define __EXTRATAGS_H__
+
#include <string>
#include <map>
#include <vector>
@@ -70,3 +73,5 @@ class ExtraTags {
/** Get text data for tag as a string. */
std::string asString(std::string tag, bool *ok);
};
+
+#endif /* __EXTRATAGS_H__ */
diff --git a/source/blender/collada/Materials.h b/source/blender/collada/Materials.h
index 8f3c3dbcd93..0a4f2ee61a5 100644
--- a/source/blender/collada/Materials.h
+++ b/source/blender/collada/Materials.h
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __MATERIAL_H__
-#define __MATERIAL_H__
+#ifndef __MATERIALS_H__
+#define __MATERIALS_H__
#include <map>
#include <string>
@@ -73,4 +73,4 @@ class MaterialNode {
COLLADAFW::FloatOrParam &val);
};
-#endif
+#endif /* __MATERIALS_H__ */
diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cpp b/source/blender/compositor/nodes/COM_DenoiseNode.cpp
index 7de120d1204..a18fc82908a 100644
--- a/source/blender/compositor/nodes/COM_DenoiseNode.cpp
+++ b/source/blender/compositor/nodes/COM_DenoiseNode.cpp
@@ -1,6 +1,4 @@
/*
- * Copyright 2019, Blender Foundation.
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -15,10 +13,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor:
- * Stefan Werner
+ * Copyright 2019, Blender Foundation.
*/
-
#include "COM_DenoiseNode.h"
#include "DNA_node_types.h"
#include "COM_SetValueOperation.h"
diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.h b/source/blender/compositor/nodes/COM_DenoiseNode.h
index 0924da8931c..6cbe598f7d2 100644
--- a/source/blender/compositor/nodes/COM_DenoiseNode.h
+++ b/source/blender/compositor/nodes/COM_DenoiseNode.h
@@ -1,6 +1,4 @@
/*
- * Copyright 2019, Blender Foundation.
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -15,8 +13,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor:
- * Stefan Werner
+ * Copyright 2019, Blender Foundation.
*/
#ifndef __COM_DENOISENODE_H__
diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cpp
index d13b34bb6b5..5497d4a4755 100644
--- a/source/blender/compositor/nodes/COM_MathNode.cpp
+++ b/source/blender/compositor/nodes/COM_MathNode.cpp
@@ -56,6 +56,15 @@ void MathNode::convertToOperations(NodeConverter &converter,
case NODE_MATH_ARCTANGENT:
operation = new MathArcTangentOperation();
break;
+ case NODE_MATH_SINH:
+ operation = new MathHyperbolicSineOperation();
+ break;
+ case NODE_MATH_COSH:
+ operation = new MathHyperbolicCosineOperation();
+ break;
+ case NODE_MATH_TANH:
+ operation = new MathHyperbolicTangentOperation();
+ break;
case NODE_MATH_POWER:
operation = new MathPowerOperation();
break;
@@ -83,6 +92,12 @@ void MathNode::convertToOperations(NodeConverter &converter,
case NODE_MATH_ABSOLUTE:
operation = new MathAbsoluteOperation();
break;
+ case NODE_MATH_RADIANS:
+ operation = new MathRadiansOperation();
+ break;
+ case NODE_MATH_DEGREES:
+ operation = new MathDegreesOperation();
+ break;
case NODE_MATH_ARCTAN2:
operation = new MathArcTan2Operation();
break;
@@ -98,6 +113,39 @@ void MathNode::convertToOperations(NodeConverter &converter,
case NODE_MATH_SQRT:
operation = new MathSqrtOperation();
break;
+ case NODE_MATH_INV_SQRT:
+ operation = new MathInverseSqrtOperation();
+ break;
+ case NODE_MATH_SIGN:
+ operation = new MathSignOperation();
+ break;
+ case NODE_MATH_EXPONENT:
+ operation = new MathExponentOperation();
+ break;
+ case NODE_MATH_TRUNC:
+ operation = new MathTruncOperation();
+ break;
+ case NODE_MATH_SNAP:
+ operation = new MathSnapOperation();
+ break;
+ case NODE_MATH_WRAP:
+ operation = new MathWrapOperation();
+ break;
+ case NODE_MATH_PINGPONG:
+ operation = new MathPingpongOperation();
+ break;
+ case NODE_MATH_COMPARE:
+ operation = new MathCompareOperation();
+ break;
+ case NODE_MATH_MULTIPLY_ADD:
+ operation = new MathMultiplyAddOperation();
+ break;
+ case NODE_MATH_SMOOTH_MIN:
+ operation = new MathSmoothMinOperation();
+ break;
+ case NODE_MATH_SMOOTH_MAX:
+ operation = new MathSmoothMaxOperation();
+ break;
}
if (operation) {
@@ -107,6 +155,7 @@ void MathNode::convertToOperations(NodeConverter &converter,
converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
+ converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
}
}
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cpp b/source/blender/compositor/operations/COM_DenoiseOperation.cpp
index 8235c296c5a..d9a59002caf 100644
--- a/source/blender/compositor/operations/COM_DenoiseOperation.cpp
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.cpp
@@ -1,6 +1,4 @@
/*
- * Copyright 2019, Blender Foundation.
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -15,8 +13,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor:
- * Stefan Werner
+ * Copyright 2019, Blender Foundation.
*/
#include "COM_DenoiseOperation.h"
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.h b/source/blender/compositor/operations/COM_DenoiseOperation.h
index fc06bb81a97..6a53eead65c 100644
--- a/source/blender/compositor/operations/COM_DenoiseOperation.h
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.h
@@ -1,6 +1,4 @@
/*
- * Copyright 2019, Blender Foundation.
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -15,8 +13,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor:
- * Stefan Werner
+ * Copyright 2019, Blender Foundation.
*/
#ifndef __COM_DENOISEOPERATION_H__
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp
index 15dbd4e2ac9..524812ac992 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.cpp
@@ -25,9 +25,11 @@ MathBaseOperation::MathBaseOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_VALUE);
this->addInputSocket(COM_DT_VALUE);
+ this->addInputSocket(COM_DT_VALUE);
this->addOutputSocket(COM_DT_VALUE);
this->m_inputValue1Operation = NULL;
this->m_inputValue2Operation = NULL;
+ this->m_inputValue3Operation = NULL;
this->m_useClamp = false;
}
@@ -35,12 +37,14 @@ void MathBaseOperation::initExecution()
{
this->m_inputValue1Operation = this->getInputSocketReader(0);
this->m_inputValue2Operation = this->getInputSocketReader(1);
+ this->m_inputValue3Operation = this->getInputSocketReader(2);
}
void MathBaseOperation::deinitExecution()
{
this->m_inputValue1Operation = NULL;
this->m_inputValue2Operation = NULL;
+ this->m_inputValue3Operation = NULL;
}
void MathBaseOperation::determineResolution(unsigned int resolution[2],
@@ -182,6 +186,54 @@ void MathTangentOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MathHyperbolicSineOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+ float inputValue2[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+
+ output[0] = sinh(inputValue1[0]);
+
+ clampIfNeeded(output);
+}
+
+void MathHyperbolicCosineOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+ float inputValue2[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+
+ output[0] = cosh(inputValue1[0]);
+
+ clampIfNeeded(output);
+}
+
+void MathHyperbolicTangentOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+ float inputValue2[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+
+ output[0] = tanh(inputValue1[0]);
+
+ clampIfNeeded(output);
+}
+
void MathArcSineOperation::executePixelSampled(float output[4],
float x,
float y,
@@ -404,6 +456,34 @@ void MathAbsoluteOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+void MathRadiansOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+
+ output[0] = DEG2RADF(inputValue1[0]);
+
+ clampIfNeeded(output);
+}
+
+void MathDegreesOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+
+ output[0] = RAD2DEGF(inputValue1[0]);
+
+ clampIfNeeded(output);
+}
+
void MathArcTan2Operation::executePixelSampled(float output[4],
float x,
float y,
@@ -480,3 +560,194 @@ void MathSqrtOperation::executePixelSampled(float output[4],
clampIfNeeded(output);
}
+
+void MathInverseSqrtOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+
+ if (inputValue1[0] > 0) {
+ output[0] = 1.0f / sqrt(inputValue1[0]);
+ }
+ else {
+ output[0] = 0.0f;
+ }
+
+ clampIfNeeded(output);
+}
+
+void MathSignOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+
+ output[0] = compatible_signf(inputValue1[0]);
+
+ clampIfNeeded(output);
+}
+
+void MathExponentOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+
+ output[0] = expf(inputValue1[0]);
+
+ clampIfNeeded(output);
+}
+
+void MathTruncOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+
+ output[0] = (inputValue1[0] >= 0.0f) ? floor(inputValue1[0]) : ceil(inputValue1[0]);
+
+ clampIfNeeded(output);
+}
+
+void MathSnapOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+ float inputValue2[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+
+ if (inputValue1[0] == 0 || inputValue2[0] == 0) { /* We don't want to divide by zero. */
+ output[0] = 0.0f;
+ }
+ else {
+ output[0] = floorf(inputValue1[0] / inputValue2[0]) * inputValue2[0];
+ }
+
+ clampIfNeeded(output);
+}
+
+void MathWrapOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+ float inputValue2[4];
+ float inputValue3[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler);
+
+ output[0] = wrapf(inputValue1[0], inputValue2[0], inputValue3[0]);
+
+ clampIfNeeded(output);
+}
+
+void MathPingpongOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+ float inputValue2[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+
+ output[0] = fabsf(fractf((inputValue1[0] - inputValue2[0]) / (inputValue2[0] * 2.0f)) *
+ inputValue2[0] * 2.0f -
+ inputValue2[0]);
+
+ clampIfNeeded(output);
+}
+
+void MathCompareOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+ float inputValue2[4];
+ float inputValue3[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler);
+
+ output[0] = (fabsf(inputValue1[0] - inputValue2[0]) <= MAX2(inputValue3[0], 1e-5f)) ? 1.0f :
+ 0.0f;
+
+ clampIfNeeded(output);
+}
+
+void MathMultiplyAddOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+ float inputValue2[4];
+ float inputValue3[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler);
+
+ output[0] = inputValue1[0] * inputValue2[0] + inputValue3[0];
+
+ clampIfNeeded(output);
+}
+
+void MathSmoothMinOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+ float inputValue2[4];
+ float inputValue3[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler);
+
+ output[0] = smoothminf(inputValue1[0], inputValue2[0], inputValue3[0]);
+
+ clampIfNeeded(output);
+}
+
+void MathSmoothMaxOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float inputValue1[4];
+ float inputValue2[4];
+ float inputValue3[4];
+
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler);
+
+ output[0] = -smoothminf(-inputValue1[0], -inputValue2[0], inputValue3[0]);
+
+ clampIfNeeded(output);
+}
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h
index 7c11ea8f45b..199b59d8649 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.h
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.h
@@ -31,6 +31,7 @@ class MathBaseOperation : public NodeOperation {
*/
SocketReader *m_inputValue1Operation;
SocketReader *m_inputValue2Operation;
+ SocketReader *m_inputValue3Operation;
bool m_useClamp;
@@ -119,6 +120,28 @@ class MathTangentOperation : public MathBaseOperation {
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
+class MathHyperbolicSineOperation : public MathBaseOperation {
+ public:
+ MathHyperbolicSineOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+class MathHyperbolicCosineOperation : public MathBaseOperation {
+ public:
+ MathHyperbolicCosineOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+class MathHyperbolicTangentOperation : public MathBaseOperation {
+ public:
+ MathHyperbolicTangentOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
class MathArcSineOperation : public MathBaseOperation {
public:
MathArcSineOperation() : MathBaseOperation()
@@ -206,6 +229,22 @@ class MathAbsoluteOperation : public MathBaseOperation {
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
+class MathRadiansOperation : public MathBaseOperation {
+ public:
+ MathRadiansOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathDegreesOperation : public MathBaseOperation {
+ public:
+ MathDegreesOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
class MathArcTan2Operation : public MathBaseOperation {
public:
MathArcTan2Operation() : MathBaseOperation()
@@ -246,4 +285,91 @@ class MathSqrtOperation : public MathBaseOperation {
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
+class MathInverseSqrtOperation : public MathBaseOperation {
+ public:
+ MathInverseSqrtOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathSignOperation : public MathBaseOperation {
+ public:
+ MathSignOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathExponentOperation : public MathBaseOperation {
+ public:
+ MathExponentOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathTruncOperation : public MathBaseOperation {
+ public:
+ MathTruncOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathSnapOperation : public MathBaseOperation {
+ public:
+ MathSnapOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathWrapOperation : public MathBaseOperation {
+ public:
+ MathWrapOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathPingpongOperation : public MathBaseOperation {
+ public:
+ MathPingpongOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathCompareOperation : public MathBaseOperation {
+ public:
+ MathCompareOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathMultiplyAddOperation : public MathBaseOperation {
+ public:
+ MathMultiplyAddOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathSmoothMinOperation : public MathBaseOperation {
+ public:
+ MathSmoothMinOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
+class MathSmoothMaxOperation : public MathBaseOperation {
+ public:
+ MathSmoothMaxOperation() : MathBaseOperation()
+ {
+ }
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
#endif
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cpp
index 3f7619523e3..b6caf52a9f7 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cpp
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cpp
@@ -153,7 +153,8 @@ void ViewerOperation::initImage()
if (ibuf->x > 0 && ibuf->y > 0) {
imb_addrectfloatImBuf(ibuf);
}
- ima->ok = IMA_OK_LOADED;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ tile->ok = IMA_OK_LOADED;
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
}
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 21ab148496c..4abeec19645 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -58,6 +58,15 @@ set(SRC
intern/eval/deg_eval.cc
intern/eval/deg_eval_copy_on_write.cc
intern/eval/deg_eval_flush.cc
+ intern/eval/deg_eval_runtime_backup.cc
+ intern/eval/deg_eval_runtime_backup_modifier.cc
+ intern/eval/deg_eval_runtime_backup_movieclip.cc
+ intern/eval/deg_eval_runtime_backup_object.cc
+ intern/eval/deg_eval_runtime_backup_pose.cc
+ intern/eval/deg_eval_runtime_backup_scene.cc
+ intern/eval/deg_eval_runtime_backup_sequence.cc
+ intern/eval/deg_eval_runtime_backup_sequencer.cc
+ intern/eval/deg_eval_runtime_backup_sound.cc
intern/eval/deg_eval_stats.cc
intern/node/deg_node.cc
intern/node/deg_node_component.cc
@@ -98,6 +107,15 @@ set(SRC
intern/eval/deg_eval.h
intern/eval/deg_eval_copy_on_write.h
intern/eval/deg_eval_flush.h
+ intern/eval/deg_eval_runtime_backup.h
+ intern/eval/deg_eval_runtime_backup_modifier.h
+ intern/eval/deg_eval_runtime_backup_movieclip.h
+ intern/eval/deg_eval_runtime_backup_object.h
+ intern/eval/deg_eval_runtime_backup_pose.h
+ intern/eval/deg_eval_runtime_backup_scene.h
+ intern/eval/deg_eval_runtime_backup_sequence.h
+ intern/eval/deg_eval_runtime_backup_sequencer.h
+ intern/eval/deg_eval_runtime_backup_sound.h
intern/eval/deg_eval_stats.h
intern/node/deg_node.h
intern/node/deg_node_component.h
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index fb456611b15..c8ddffa57c7 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -26,6 +26,8 @@
#ifndef __DEG_DEPSGRAPH_QUERY_H__
#define __DEG_DEPSGRAPH_QUERY_H__
+#include "BLI_iterator.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 4ca7240abd1..fb7104e7556 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -55,6 +55,12 @@ extern "C" {
namespace DEG {
+bool deg_check_id_in_depsgraph(const Depsgraph *graph, ID *id_orig)
+{
+ IDNode *id_node = graph->find_id_node(id_orig);
+ return id_node != NULL;
+}
+
bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base)
{
Object *object_orig = base->base_orig->object;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index 97e12e9ceb2..2db861b6fca 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -24,6 +24,7 @@
#pragma once
struct Base;
+struct ID;
struct Main;
struct Object;
struct bPoseChannel;
@@ -53,6 +54,7 @@ class DepsgraphBuilder {
DepsgraphBuilderCache *cache_;
};
+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);
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index f67ab381c79..0acf777e2f0 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -345,7 +345,7 @@ class DepsgraphFromIDsFilter {
DepsgraphFromIDsFilter(ID **ids, const int num_ids)
{
for (int i = 0; i < num_ids; ++i) {
- ids_.insert(ids[0]);
+ ids_.insert(ids[i]);
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc
index 3f81e49b170..f47081cd54e 100644
--- a/source/blender/depsgraph/intern/depsgraph_physics.cc
+++ b/source/blender/depsgraph/intern/depsgraph_physics.cc
@@ -54,7 +54,7 @@ static ePhysicsRelationType modifier_to_relation_type(unsigned int modifier_type
switch (modifier_type) {
case eModifierType_Collision:
return DEG_PHYSICS_COLLISION;
- case eModifierType_Smoke:
+ case eModifierType_Fluid:
return DEG_PHYSICS_SMOKE_COLLISION;
case eModifierType_DynamicPaint:
return DEG_PHYSICS_DYNAMIC_BRUSH;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 8a33453b923..afb73a84afe 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -21,7 +21,7 @@
* \ingroup depsgraph
*/
-/* Enable special; trickery to treat nested owned IDs (such as nodetree of
+/* Enable special trickery to treat nested owned IDs (such as nodetree of
* material) to be handled in same way as "real" data-blocks, even tho some
* internal BKE routines doesn't treat them like that.
*
@@ -95,6 +95,7 @@ extern "C" {
#include "intern/depsgraph.h"
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_nodes.h"
+#include "intern/eval/deg_eval_runtime_backup.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_id.h"
@@ -758,17 +759,17 @@ void update_animation_data_after_copy(const ID *id_orig, ID *id_cow)
/* Some builders (like motion path one) will ignore proxies from being built. This code makes it so
* proxy and proxy_group pointers never point to an original objects, preventing evaluation code
* from assign evaluated pointer to an original proxy->proxy_from. */
-void update_proxy_pointers_after_copy(const Depsgraph * /*depsgraph*/,
- const Object * /*object_orig*/,
+void update_proxy_pointers_after_copy(const Depsgraph *depsgraph,
+ const Object *object_orig,
Object *object_cow)
{
if (object_cow->proxy != NULL) {
- if ((object_cow->proxy->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
+ if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy->id)) {
object_cow->proxy = NULL;
}
}
if (object_cow->proxy_group != NULL) {
- if ((object_cow->proxy_group->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
+ if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy_group->id)) {
object_cow->proxy_group = NULL;
}
}
@@ -945,545 +946,6 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
return deg_expand_copy_on_write_datablock(depsgraph, id_node, node_builder, create_placeholders);
}
-namespace {
-
-/* Backup of sequencer strips runtime data. */
-
-/* Backup of a single strip. */
-class SequenceBackup {
- public:
- SequenceBackup()
- {
- reset();
- }
-
- inline void reset()
- {
- scene_sound = NULL;
- }
-
- void init_from_sequence(Sequence *sequence)
- {
- scene_sound = sequence->scene_sound;
-
- sequence->scene_sound = NULL;
- }
-
- void restore_to_sequence(Sequence *sequence)
- {
- sequence->scene_sound = scene_sound;
- reset();
- }
-
- inline bool isEmpty() const
- {
- return (scene_sound == NULL);
- }
-
- void *scene_sound;
-};
-
-class SequencerBackup {
- public:
- SequencerBackup();
-
- void init_from_scene(Scene *scene);
- void restore_to_scene(Scene *scene);
-
- typedef map<Sequence *, SequenceBackup> SequencesBackupMap;
- SequencesBackupMap sequences_backup;
-};
-
-SequencerBackup::SequencerBackup()
-{
-}
-
-void SequencerBackup::init_from_scene(Scene *scene)
-{
- Sequence *sequence;
- SEQ_BEGIN (scene->ed, sequence) {
- SequenceBackup sequence_backup;
- sequence_backup.init_from_sequence(sequence);
- if (!sequence_backup.isEmpty()) {
- sequences_backup.insert(make_pair(sequence->orig_sequence, sequence_backup));
- }
- }
- SEQ_END;
-}
-
-void SequencerBackup::restore_to_scene(Scene *scene)
-{
- Sequence *sequence;
- SEQ_BEGIN (scene->ed, sequence) {
- SequencesBackupMap::iterator it = sequences_backup.find(sequence->orig_sequence);
- if (it == sequences_backup.end()) {
- continue;
- }
- SequenceBackup &sequence_backup = it->second;
- sequence_backup.restore_to_sequence(sequence);
- }
- SEQ_END;
- /* Cleanup audio while the scene is still known. */
- for (SequencesBackupMap::value_type &it : sequences_backup) {
- SequenceBackup &sequence_backup = it.second;
- if (sequence_backup.scene_sound != NULL) {
- BKE_sound_remove_scene_sound(scene, sequence_backup.scene_sound);
- }
- }
-}
-
-/* Backup of scene runtime data. */
-
-class SceneBackup {
- public:
- SceneBackup();
-
- void reset();
-
- void init_from_scene(Scene *scene);
- void restore_to_scene(Scene *scene);
-
- /* Sound/audio related pointers of the scene itself.
- *
- * NOTE: Scene can not disappear after relations update, because otherwise the entire dependency
- * graph will be gone. This means we don't need to compare original scene pointer, or worry about
- * freeing those if they cant' be restored: we just copy them over to a new scene. */
- void *sound_scene;
- void *playback_handle;
- void *sound_scrub_handle;
- void *speaker_handles;
- float rigidbody_last_time;
-
- SequencerBackup sequencer_backup;
-};
-
-SceneBackup::SceneBackup()
-{
- reset();
-}
-
-void SceneBackup::reset()
-{
- sound_scene = NULL;
- playback_handle = NULL;
- sound_scrub_handle = NULL;
- speaker_handles = NULL;
- rigidbody_last_time = -1;
-}
-
-void SceneBackup::init_from_scene(Scene *scene)
-{
- sound_scene = scene->sound_scene;
- playback_handle = scene->playback_handle;
- sound_scrub_handle = scene->sound_scrub_handle;
- speaker_handles = scene->speaker_handles;
-
- if (scene->rigidbody_world != NULL) {
- rigidbody_last_time = scene->rigidbody_world->ltime;
- }
-
- /* Clear pointers stored in the scene, so they are not freed when copied-on-written datablock
- * is freed for re-allocation. */
- scene->sound_scene = NULL;
- scene->playback_handle = NULL;
- scene->sound_scrub_handle = NULL;
- scene->speaker_handles = NULL;
-
- sequencer_backup.init_from_scene(scene);
-}
-
-void SceneBackup::restore_to_scene(Scene *scene)
-{
- scene->sound_scene = sound_scene;
- scene->playback_handle = playback_handle;
- scene->sound_scrub_handle = sound_scrub_handle;
- scene->speaker_handles = speaker_handles;
-
- if (scene->rigidbody_world != NULL) {
- scene->rigidbody_world->ltime = rigidbody_last_time;
- }
-
- sequencer_backup.restore_to_scene(scene);
-
- reset();
-}
-
-/* Backup of sound datablocks runtime data. */
-
-class SoundBackup {
- public:
- SoundBackup();
-
- void reset();
-
- void init_from_sound(bSound *sound);
- void restore_to_sound(bSound *sound);
-
- void *cache;
- void *waveform;
- void *playback_handle;
-};
-
-SoundBackup::SoundBackup()
-{
- reset();
-}
-
-void SoundBackup::reset()
-{
- cache = NULL;
- waveform = NULL;
- playback_handle = NULL;
-}
-
-void SoundBackup::init_from_sound(bSound *sound)
-{
- cache = sound->cache;
- waveform = sound->waveform;
- playback_handle = sound->playback_handle;
-
- sound->cache = NULL;
- sound->waveform = NULL;
- sound->playback_handle = NULL;
-}
-
-void SoundBackup::restore_to_sound(bSound *sound)
-{
- sound->cache = cache;
- sound->waveform = waveform;
- sound->playback_handle = playback_handle;
-
- reset();
-}
-
-/* Identifier used to match modifiers to backup/restore their runtime data.
- * Identification is happening using original modifier data pointer and the
- * modifier type.
- * It is not enough to only pointer, since it's possible to have a situation
- * when modifier is removed and a new one added, and due to memory allocation
- * policy they might have same pointer.
- * By adding type into matching we are at least ensuring that modifier will not
- * try to interpret runtime data created by another modifier type. */
-class ModifierDataBackupID {
- public:
- ModifierDataBackupID() : ModifierDataBackupID(NULL, eModifierType_None)
- {
- }
-
- ModifierDataBackupID(ModifierData *modifier_data, ModifierType type)
- : modifier_data(modifier_data), type(type)
- {
- }
-
- bool operator<(const ModifierDataBackupID &other) const
- {
- if (modifier_data < other.modifier_data) {
- return true;
- }
- if (modifier_data == other.modifier_data) {
- return static_cast<int>(type) < static_cast<int>(other.type);
- }
- return false;
- }
-
- ModifierData *modifier_data;
- ModifierType type;
-};
-
-/* Storage for backed up runtime modifier data. */
-typedef map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup;
-
-/* Storage for backed up pose channel runtime data. */
-typedef map<bPoseChannel *, bPoseChannel_Runtime> PoseChannelRuntimeDataBackup;
-
-class ObjectRuntimeBackup {
- public:
- ObjectRuntimeBackup() : base_flag(0), base_local_view_bits(0)
- {
- /* TODO(sergey): Use something like BKE_object_runtime_reset(). */
- memset(&runtime, 0, sizeof(runtime));
- }
-
- /* Make a backup of object's evaluation runtime data, additionally
- * make object to be safe for free without invalidating backed up
- * pointers. */
- void init_from_object(Object *object);
- void backup_modifier_runtime_data(Object *object);
- void backup_pose_channel_runtime_data(Object *object);
-
- /* Restore all fields to the given object. */
- void restore_to_object(Object *object);
- /* NOTE: Will free all runtime data which has not been restored. */
- void restore_modifier_runtime_data(Object *object);
- void restore_pose_channel_runtime_data(Object *object);
-
- Object_Runtime runtime;
- short base_flag;
- unsigned short base_local_view_bits;
- ModifierRuntimeDataBackup modifier_runtime_data;
- PoseChannelRuntimeDataBackup pose_channel_runtime_data;
-};
-
-void ObjectRuntimeBackup::init_from_object(Object *object)
-{
- /* Store evaluated mesh and curve_cache, and make sure we don't free it. */
- Mesh *mesh_eval = object->runtime.mesh_eval;
- runtime = object->runtime;
- BKE_object_runtime_reset(object);
- /* Keep bbox (for now at least). */
- object->runtime.bb = runtime.bb;
- /* Object update will override actual object->data to an evaluated version.
- * Need to make sure we don't have data set to evaluated one before free
- * anything. */
- if (mesh_eval != NULL && object->data == mesh_eval) {
- object->data = runtime.mesh_orig;
- }
- /* Make a backup of base flags. */
- base_flag = object->base_flag;
- base_local_view_bits = object->base_local_view_bits;
- /* Backup tuntime data of all modifiers. */
- backup_modifier_runtime_data(object);
- /* Backup runtime data of all pose channels. */
- backup_pose_channel_runtime_data(object);
-}
-
-inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier_data)
-{
- return ModifierDataBackupID(modifier_data->orig_modifier_data,
- static_cast<ModifierType>(modifier_data->type));
-}
-
-void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object)
-{
- LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
- if (modifier_data->runtime == NULL) {
- continue;
- }
- BLI_assert(modifier_data->orig_modifier_data != NULL);
- ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data);
- modifier_runtime_data.insert(make_pair(modifier_data_id, modifier_data->runtime));
- modifier_data->runtime = NULL;
- }
-}
-
-void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object)
-{
- if (object->pose != NULL) {
- LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- /* This is NULL in Edit mode. */
- if (pchan->orig_pchan != NULL) {
- pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime;
- BKE_pose_channel_runtime_reset(&pchan->runtime);
- }
- }
- }
-}
-
-void ObjectRuntimeBackup::restore_to_object(Object *object)
-{
- Mesh *mesh_orig = object->runtime.mesh_orig;
- BoundBox *bb = object->runtime.bb;
- object->runtime = runtime;
- object->runtime.mesh_orig = mesh_orig;
- object->runtime.bb = bb;
- if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) {
- if (object->id.recalc & ID_RECALC_GEOMETRY) {
- /* If geometry is tagged for update it means, that part of
- * evaluated mesh are not valid anymore. In this case we can not
- * have any "persistent" pointers to point to an invalid data.
- *
- * We restore object's data datablock to an original copy of
- * that datablock. */
- object->data = mesh_orig;
-
- /* After that, immediately free the invalidated caches. */
- BKE_object_free_derived_caches(object);
- }
- else {
- Mesh *mesh_eval = object->runtime.mesh_eval;
- /* Do same thing as object update: override actual object data
- * pointer with evaluated datablock. */
- object->data = mesh_eval;
- /* Evaluated mesh simply copied edit_mesh pointer from
- * original mesh during update, need to make sure no dead
- * pointers are left behind. */
- mesh_eval->edit_mesh = mesh_orig->edit_mesh;
- }
- }
- object->base_flag = base_flag;
- object->base_local_view_bits = base_local_view_bits;
- /* Restore modifier's runtime data.
- * NOTE: Data of unused modifiers will be freed there. */
- restore_modifier_runtime_data(object);
- restore_pose_channel_runtime_data(object);
-}
-
-void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object)
-{
- LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
- BLI_assert(modifier_data->orig_modifier_data != NULL);
- ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data);
- ModifierRuntimeDataBackup::iterator runtime_data_iterator = modifier_runtime_data.find(
- modifier_data_id);
- if (runtime_data_iterator != modifier_runtime_data.end()) {
- modifier_data->runtime = runtime_data_iterator->second;
- runtime_data_iterator->second = NULL;
- }
- }
- for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) {
- const ModifierDataBackupID modifier_data_id = value.first;
- void *runtime = value.second;
- if (value.second == NULL) {
- continue;
- }
- const ModifierTypeInfo *modifier_type_info = modifierType_getInfo(modifier_data_id.type);
- BLI_assert(modifier_type_info != NULL);
- modifier_type_info->freeRuntimeData(runtime);
- }
-}
-
-void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object)
-{
- if (object->pose != NULL) {
- LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- /* This is NULL in Edit mode. */
- if (pchan->orig_pchan != NULL) {
- PoseChannelRuntimeDataBackup::iterator runtime_data_iterator =
- pose_channel_runtime_data.find(pchan->orig_pchan);
- if (runtime_data_iterator != pose_channel_runtime_data.end()) {
- pchan->runtime = runtime_data_iterator->second;
- pose_channel_runtime_data.erase(runtime_data_iterator);
- }
- }
- }
- }
- for (PoseChannelRuntimeDataBackup::value_type &value : pose_channel_runtime_data) {
- BKE_pose_channel_runtime_free(&value.second);
- }
-}
-
-/* Backup of movie clip runtime data. */
-
-class MovieClipBackup {
- public:
- MovieClipBackup();
-
- void reset();
-
- void init_from_movieclip(MovieClip *movieclip);
- void restore_to_movieclip(MovieClip *movieclip);
-
- struct anim *anim;
- struct MovieClipCache *cache;
-};
-
-MovieClipBackup::MovieClipBackup()
-{
- reset();
-}
-
-void MovieClipBackup::reset()
-{
- anim = NULL;
- cache = NULL;
-}
-
-void MovieClipBackup::init_from_movieclip(MovieClip *movieclip)
-{
- anim = movieclip->anim;
- cache = movieclip->cache;
- /* Clear pointers stored in the movie clip, so they are not freed when copied-on-written
- * datablock is freed for re-allocation. */
- movieclip->anim = NULL;
- movieclip->cache = NULL;
-}
-
-void MovieClipBackup::restore_to_movieclip(MovieClip *movieclip)
-{
- movieclip->anim = anim;
- movieclip->cache = cache;
-
- reset();
-}
-
-class RuntimeBackup {
- public:
- RuntimeBackup() : drawdata_ptr(NULL)
- {
- drawdata_backup.first = drawdata_backup.last = NULL;
- }
-
- /* NOTE: Will reset all runbtime fields which has been backed up to NULL. */
- void init_from_id(ID *id);
-
- /* Restore fields to the given ID. */
- void restore_to_id(ID *id);
-
- SceneBackup scene_backup;
- SoundBackup sound_backup;
- ObjectRuntimeBackup object_backup;
- DrawDataList drawdata_backup;
- DrawDataList *drawdata_ptr;
- MovieClipBackup movieclip_backup;
-};
-
-void RuntimeBackup::init_from_id(ID *id)
-{
- if (!check_datablock_expanded(id)) {
- return;
- }
- const ID_Type id_type = GS(id->name);
- switch (id_type) {
- case ID_OB:
- object_backup.init_from_object(reinterpret_cast<Object *>(id));
- break;
- case ID_SCE:
- scene_backup.init_from_scene(reinterpret_cast<Scene *>(id));
- break;
- case ID_SO:
- sound_backup.init_from_sound(reinterpret_cast<bSound *>(id));
- break;
- case ID_MC:
- movieclip_backup.init_from_movieclip(reinterpret_cast<MovieClip *>(id));
- break;
- default:
- break;
- }
- /* Note that we never free GPU draw data from here since that's not
- * safe for threading and draw data is likely to be re-used. */
- drawdata_ptr = DRW_drawdatalist_from_id(id);
- if (drawdata_ptr != NULL) {
- drawdata_backup = *drawdata_ptr;
- drawdata_ptr->first = drawdata_ptr->last = NULL;
- }
-}
-
-void RuntimeBackup::restore_to_id(ID *id)
-{
- const ID_Type id_type = GS(id->name);
- switch (id_type) {
- case ID_OB:
- object_backup.restore_to_object(reinterpret_cast<Object *>(id));
- break;
- case ID_SCE:
- scene_backup.restore_to_scene(reinterpret_cast<Scene *>(id));
- break;
- case ID_SO:
- sound_backup.restore_to_sound(reinterpret_cast<bSound *>(id));
- break;
- case ID_MC:
- movieclip_backup.restore_to_movieclip(reinterpret_cast<MovieClip *>(id));
- break;
- default:
- break;
- }
- if (drawdata_ptr != NULL) {
- *drawdata_ptr = drawdata_backup;
- }
-}
-
-} // namespace
-
ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode *id_node)
{
const ID *id_orig = id_node->id_orig;
@@ -1492,7 +954,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode
if (!deg_copy_on_write_is_needed(id_orig)) {
return id_cow;
}
- RuntimeBackup backup;
+ RuntimeBackup backup(depsgraph);
backup.init_from_id(id_cow);
deg_free_copy_on_write_datablock(id_cow);
deg_expand_copy_on_write_datablock(depsgraph, id_node);
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
new file mode 100644
index 00000000000..88390ab412f
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
@@ -0,0 +1,101 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup.h"
+
+#include "intern/eval/deg_eval_copy_on_write.h"
+
+#include "BLI_utildefines.h"
+
+#include "DRW_engine.h"
+
+namespace DEG {
+
+RuntimeBackup::RuntimeBackup(const Depsgraph *depsgraph)
+ : scene_backup(depsgraph),
+ sound_backup(depsgraph),
+ object_backup(depsgraph),
+ drawdata_ptr(NULL),
+ movieclip_backup(depsgraph)
+{
+ drawdata_backup.first = drawdata_backup.last = NULL;
+}
+
+void RuntimeBackup::init_from_id(ID *id)
+{
+ if (!deg_copy_on_write_is_expanded(id)) {
+ return;
+ }
+
+ const ID_Type id_type = GS(id->name);
+ switch (id_type) {
+ case ID_OB:
+ object_backup.init_from_object(reinterpret_cast<Object *>(id));
+ break;
+ case ID_SCE:
+ scene_backup.init_from_scene(reinterpret_cast<Scene *>(id));
+ break;
+ case ID_SO:
+ sound_backup.init_from_sound(reinterpret_cast<bSound *>(id));
+ break;
+ case ID_MC:
+ movieclip_backup.init_from_movieclip(reinterpret_cast<MovieClip *>(id));
+ break;
+ default:
+ break;
+ }
+
+ /* Note that we never free GPU draw data from here since that's not
+ * safe for threading and draw data is likely to be re-used. */
+ drawdata_ptr = DRW_drawdatalist_from_id(id);
+ if (drawdata_ptr != NULL) {
+ drawdata_backup = *drawdata_ptr;
+ drawdata_ptr->first = drawdata_ptr->last = NULL;
+ }
+}
+
+void RuntimeBackup::restore_to_id(ID *id)
+{
+ const ID_Type id_type = GS(id->name);
+ switch (id_type) {
+ case ID_OB:
+ object_backup.restore_to_object(reinterpret_cast<Object *>(id));
+ break;
+ case ID_SCE:
+ scene_backup.restore_to_scene(reinterpret_cast<Scene *>(id));
+ break;
+ case ID_SO:
+ sound_backup.restore_to_sound(reinterpret_cast<bSound *>(id));
+ break;
+ case ID_MC:
+ movieclip_backup.restore_to_movieclip(reinterpret_cast<MovieClip *>(id));
+ break;
+ default:
+ break;
+ }
+ if (drawdata_ptr != NULL) {
+ *drawdata_ptr = drawdata_backup;
+ }
+}
+
+} // namespace 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
new file mode 100644
index 00000000000..31ae3164e37
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "DNA_ID.h"
+
+#include "intern/eval/deg_eval_runtime_backup_movieclip.h"
+#include "intern/eval/deg_eval_runtime_backup_object.h"
+#include "intern/eval/deg_eval_runtime_backup_scene.h"
+#include "intern/eval/deg_eval_runtime_backup_sound.h"
+
+namespace DEG {
+
+struct Depsgraph;
+
+class RuntimeBackup {
+ public:
+ explicit RuntimeBackup(const Depsgraph *depsgraph);
+
+ /* NOTE: Will reset all runtime fields which has been backed up to NULL. */
+ void init_from_id(ID *id);
+
+ /* Restore fields to the given ID. */
+ void restore_to_id(ID *id);
+
+ SceneBackup scene_backup;
+ SoundBackup sound_backup;
+ ObjectRuntimeBackup object_backup;
+ DrawDataList drawdata_backup;
+ DrawDataList *drawdata_ptr;
+ MovieClipBackup movieclip_backup;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc
new file mode 100644
index 00000000000..c5744533083
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc
@@ -0,0 +1,49 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_modifier.h"
+
+namespace DEG {
+
+ModifierDataBackupID::ModifierDataBackupID(const Depsgraph * /*depsgraph*/)
+ : ModifierDataBackupID(NULL, eModifierType_None)
+{
+}
+
+ModifierDataBackupID::ModifierDataBackupID(ModifierData *modifier_data, ModifierType type)
+ : modifier_data(modifier_data), type(type)
+{
+}
+
+bool ModifierDataBackupID::operator<(const ModifierDataBackupID &other) const
+{
+ if (modifier_data < other.modifier_data) {
+ return true;
+ }
+ if (modifier_data == other.modifier_data) {
+ return static_cast<int>(type) < static_cast<int>(other.type);
+ }
+ return false;
+}
+
+} // namespace 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
new file mode 100644
index 00000000000..4b3d46126f3
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "BKE_modifier.h"
+
+#include "intern/depsgraph_type.h"
+
+struct ModifierData;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Identifier used to match modifiers to backup/restore their runtime data.
+ * Identification is happening using original modifier data pointer and the
+ * modifier type.
+ * It is not enough to only pointer, since it's possible to have a situation
+ * when modifier is removed and a new one added, and due to memory allocation
+ * policy they might have same pointer.
+ * By adding type into matching we are at least ensuring that modifier will not
+ * try to interpret runtime data created by another modifier type. */
+class ModifierDataBackupID {
+ public:
+ ModifierDataBackupID(const Depsgraph *depsgraph);
+ ModifierDataBackupID(ModifierData *modifier_data, ModifierType type);
+
+ bool operator<(const ModifierDataBackupID &other) const;
+
+ ModifierData *modifier_data;
+ ModifierType type;
+};
+
+/* Storage for backed up runtime modifier data. */
+typedef map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup;
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc
new file mode 100644
index 00000000000..54838475bbf
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc
@@ -0,0 +1,61 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_movieclip.h"
+
+#include "DNA_movieclip_types.h"
+
+#include "BLI_utildefines.h"
+
+namespace DEG {
+
+MovieClipBackup::MovieClipBackup(const Depsgraph * /*depsgraph*/)
+{
+ reset();
+}
+
+void MovieClipBackup::reset()
+{
+ anim = NULL;
+ cache = NULL;
+}
+
+void MovieClipBackup::init_from_movieclip(MovieClip *movieclip)
+{
+ anim = movieclip->anim;
+ cache = movieclip->cache;
+ /* Clear pointers stored in the movie clip, so they are not freed when copied-on-written
+ * datablock is freed for re-allocation. */
+ movieclip->anim = NULL;
+ movieclip->cache = NULL;
+}
+
+void MovieClipBackup::restore_to_movieclip(MovieClip *movieclip)
+{
+ movieclip->anim = anim;
+ movieclip->cache = cache;
+
+ reset();
+}
+
+} // namespace DEG
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h
index da70568353e..427e9c7b483 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h
@@ -13,27 +13,36 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) Blender Foundation
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
* All rights reserved.
*/
/** \file
- * \ingroup modifiers
+ * \ingroup depsgraph
*/
-#ifndef __MOD_FLUIDSIM_UTIL_H__
-#define __MOD_FLUIDSIM_UTIL_H__
+#pragma once
-struct FluidsimModifierData;
-struct Mesh;
-struct ModifierEvalContext;
+struct MovieClip;
+struct MovieClipCache;
+struct anim;
-/* new fluid-modifier interface */
-void fluidsim_init(struct FluidsimModifierData *fluidmd);
-void fluidsim_free(struct FluidsimModifierData *fluidmd);
+namespace DEG {
-struct Mesh *fluidsimModifier_do(struct FluidsimModifierData *fluidmd,
- const struct ModifierEvalContext *ctx,
- struct Mesh *me);
+struct Depsgraph;
-#endif
+/* Backup of movie clip runtime data. */
+class MovieClipBackup {
+ public:
+ MovieClipBackup(const Depsgraph *depsgraph);
+
+ void reset();
+
+ void init_from_movieclip(MovieClip *movieclip);
+ void restore_to_movieclip(MovieClip *movieclip);
+
+ struct anim *anim;
+ struct MovieClipCache *cache;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc
new file mode 100644
index 00000000000..a6a042f3e7b
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc
@@ -0,0 +1,182 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_object.h"
+
+#include <cstring>
+
+#include "DNA_mesh_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_action.h"
+#include "BKE_object.h"
+
+namespace DEG {
+
+ObjectRuntimeBackup::ObjectRuntimeBackup(const Depsgraph * /*depsgraph*/)
+ : base_flag(0), base_local_view_bits(0)
+{
+ /* TODO(sergey): Use something like BKE_object_runtime_reset(). */
+ memset(&runtime, 0, sizeof(runtime));
+}
+
+void ObjectRuntimeBackup::init_from_object(Object *object)
+{
+ /* Store evaluated mesh and curve_cache, and make sure we don't free it. */
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ runtime = object->runtime;
+ BKE_object_runtime_reset(object);
+ /* Keep bbox (for now at least). */
+ object->runtime.bb = runtime.bb;
+ /* Object update will override actual object->data to an evaluated version.
+ * Need to make sure we don't have data set to evaluated one before free
+ * anything. */
+ if (mesh_eval != NULL && object->data == mesh_eval) {
+ object->data = runtime.mesh_orig;
+ }
+ /* Make a backup of base flags. */
+ base_flag = object->base_flag;
+ base_local_view_bits = object->base_local_view_bits;
+ /* Backup tuntime data of all modifiers. */
+ backup_modifier_runtime_data(object);
+ /* Backup runtime data of all pose channels. */
+ backup_pose_channel_runtime_data(object);
+}
+
+inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier_data)
+{
+ return ModifierDataBackupID(modifier_data->orig_modifier_data,
+ static_cast<ModifierType>(modifier_data->type));
+}
+
+void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object)
+{
+ LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
+ if (modifier_data->runtime == NULL) {
+ continue;
+ }
+ BLI_assert(modifier_data->orig_modifier_data != NULL);
+ ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data);
+ modifier_runtime_data.insert(make_pair(modifier_data_id, modifier_data->runtime));
+ modifier_data->runtime = NULL;
+ }
+}
+
+void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object)
+{
+ if (object->pose != NULL) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ /* This is NULL in Edit mode. */
+ if (pchan->orig_pchan != NULL) {
+ pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime;
+ BKE_pose_channel_runtime_reset(&pchan->runtime);
+ }
+ }
+ }
+}
+
+void ObjectRuntimeBackup::restore_to_object(Object *object)
+{
+ Mesh *mesh_orig = object->runtime.mesh_orig;
+ BoundBox *bb = object->runtime.bb;
+ object->runtime = runtime;
+ object->runtime.mesh_orig = mesh_orig;
+ object->runtime.bb = bb;
+ if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) {
+ if (object->id.recalc & ID_RECALC_GEOMETRY) {
+ /* If geometry is tagged for update it means, that part of
+ * evaluated mesh are not valid anymore. In this case we can not
+ * have any "persistent" pointers to point to an invalid data.
+ *
+ * We restore object's data datablock to an original copy of
+ * that datablock. */
+ object->data = mesh_orig;
+
+ /* After that, immediately free the invalidated caches. */
+ BKE_object_free_derived_caches(object);
+ }
+ else {
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ /* Do same thing as object update: override actual object data
+ * pointer with evaluated datablock. */
+ object->data = mesh_eval;
+ /* Evaluated mesh simply copied edit_mesh pointer from
+ * original mesh during update, need to make sure no dead
+ * pointers are left behind. */
+ mesh_eval->edit_mesh = mesh_orig->edit_mesh;
+ }
+ }
+ object->base_flag = base_flag;
+ object->base_local_view_bits = base_local_view_bits;
+ /* Restore modifier's runtime data.
+ * NOTE: Data of unused modifiers will be freed there. */
+ restore_modifier_runtime_data(object);
+ restore_pose_channel_runtime_data(object);
+}
+
+void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object)
+{
+ LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
+ BLI_assert(modifier_data->orig_modifier_data != NULL);
+ ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data);
+ ModifierRuntimeDataBackup::iterator runtime_data_iterator = modifier_runtime_data.find(
+ modifier_data_id);
+ if (runtime_data_iterator != modifier_runtime_data.end()) {
+ modifier_data->runtime = runtime_data_iterator->second;
+ runtime_data_iterator->second = NULL;
+ }
+ }
+ for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) {
+ const ModifierDataBackupID modifier_data_id = value.first;
+ void *runtime = value.second;
+ if (value.second == NULL) {
+ continue;
+ }
+ const ModifierTypeInfo *modifier_type_info = modifierType_getInfo(modifier_data_id.type);
+ BLI_assert(modifier_type_info != NULL);
+ modifier_type_info->freeRuntimeData(runtime);
+ }
+}
+
+void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object)
+{
+ if (object->pose != NULL) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ /* This is NULL in Edit mode. */
+ if (pchan->orig_pchan != NULL) {
+ PoseChannelRuntimeDataBackup::iterator runtime_data_iterator =
+ pose_channel_runtime_data.find(pchan->orig_pchan);
+ if (runtime_data_iterator != pose_channel_runtime_data.end()) {
+ pchan->runtime = runtime_data_iterator->second;
+ pose_channel_runtime_data.erase(runtime_data_iterator);
+ }
+ }
+ }
+ }
+ for (PoseChannelRuntimeDataBackup::value_type &value : pose_channel_runtime_data) {
+ BKE_pose_channel_runtime_free(&value.second);
+ }
+}
+
+} // namespace 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
new file mode 100644
index 00000000000..e5c3d6a967a
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h
@@ -0,0 +1,59 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "DNA_object_types.h"
+
+#include "intern/eval/deg_eval_runtime_backup_modifier.h"
+#include "intern/eval/deg_eval_runtime_backup_pose.h"
+
+struct Object;
+
+namespace DEG {
+
+class ObjectRuntimeBackup {
+ public:
+ ObjectRuntimeBackup(const Depsgraph *depsgraph);
+
+ /* Make a backup of object's evaluation runtime data, additionally
+ * make object to be safe for free without invalidating backed up
+ * pointers. */
+ void init_from_object(Object *object);
+ void backup_modifier_runtime_data(Object *object);
+ void backup_pose_channel_runtime_data(Object *object);
+
+ /* Restore all fields to the given object. */
+ void restore_to_object(Object *object);
+ /* NOTE: Will free all runtime data which has not been restored. */
+ void restore_modifier_runtime_data(Object *object);
+ void restore_pose_channel_runtime_data(Object *object);
+
+ Object_Runtime runtime;
+ short base_flag;
+ unsigned short base_local_view_bits;
+ ModifierRuntimeDataBackup modifier_runtime_data;
+ PoseChannelRuntimeDataBackup pose_channel_runtime_data;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc
new file mode 100644
index 00000000000..821cc21f359
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_pose.h"
+
+namespace DEG {
+
+} // namespace DEG
diff --git a/source/blender/draw/modes/edit_mesh_mode_intern.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h
index 706c7b7bd88..53a2c4c0784 100644
--- a/source/blender/draw/modes/edit_mesh_mode_intern.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h
@@ -12,24 +12,26 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
*/
/** \file
- * \ingroup draw
+ * \ingroup depsgraph
*/
-#ifndef __EDIT_MESH_MODE_INTERN_H__
-#define __EDIT_MESH_MODE_INTERN_H__
+#pragma once
+
+#include "intern/depsgraph_type.h"
+
+#include "DNA_action_types.h"
+
+struct bPoseChannel;
-struct ARegion;
-struct Object;
-struct UnitSettings;
-struct View3D;
+namespace DEG {
-/* edit_mesh_mode_text.c */
-void DRW_edit_mesh_mode_text_measure_stats(struct ARegion *ar,
- struct View3D *v3d,
- struct Object *ob,
- const UnitSettings *unit);
+/* Storage for backed up pose channel runtime data. */
+typedef map<bPoseChannel *, bPoseChannel_Runtime> PoseChannelRuntimeDataBackup;
-#endif /* __EDIT_MESH_MODE_INTERN_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc
new file mode 100644
index 00000000000..a288fb6ab92
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc
@@ -0,0 +1,82 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_scene.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_rigidbody_types.h"
+
+namespace DEG {
+
+SceneBackup::SceneBackup(const Depsgraph *depsgraph) : sequencer_backup(depsgraph)
+{
+ reset();
+}
+
+void SceneBackup::reset()
+{
+ sound_scene = NULL;
+ playback_handle = NULL;
+ sound_scrub_handle = NULL;
+ speaker_handles = NULL;
+ rigidbody_last_time = -1;
+}
+
+void SceneBackup::init_from_scene(Scene *scene)
+{
+ sound_scene = scene->sound_scene;
+ playback_handle = scene->playback_handle;
+ sound_scrub_handle = scene->sound_scrub_handle;
+ speaker_handles = scene->speaker_handles;
+
+ if (scene->rigidbody_world != NULL) {
+ rigidbody_last_time = scene->rigidbody_world->ltime;
+ }
+
+ /* Clear pointers stored in the scene, so they are not freed when copied-on-written datablock
+ * is freed for re-allocation. */
+ scene->sound_scene = NULL;
+ scene->playback_handle = NULL;
+ scene->sound_scrub_handle = NULL;
+ scene->speaker_handles = NULL;
+
+ sequencer_backup.init_from_scene(scene);
+}
+
+void SceneBackup::restore_to_scene(Scene *scene)
+{
+ scene->sound_scene = sound_scene;
+ scene->playback_handle = playback_handle;
+ scene->sound_scrub_handle = sound_scrub_handle;
+ scene->speaker_handles = speaker_handles;
+
+ if (scene->rigidbody_world != NULL) {
+ scene->rigidbody_world->ltime = rigidbody_last_time;
+ }
+
+ sequencer_backup.restore_to_scene(scene);
+
+ reset();
+}
+
+} // namespace 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
new file mode 100644
index 00000000000..751bc4208d2
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/eval/deg_eval_runtime_backup_sequencer.h"
+
+struct Scene;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Backup of scene runtime data. */
+class SceneBackup {
+ public:
+ SceneBackup(const Depsgraph *depsgraph);
+
+ void reset();
+
+ void init_from_scene(Scene *scene);
+ void restore_to_scene(Scene *scene);
+
+ /* Sound/audio related pointers of the scene itself.
+ *
+ * NOTE: Scene can not disappear after relations update, because otherwise the entire dependency
+ * graph will be gone. This means we don't need to compare original scene pointer, or worry about
+ * freeing those if they cant' be restored: we just copy them over to a new scene. */
+ void *sound_scene;
+ void *playback_handle;
+ void *sound_scrub_handle;
+ void *speaker_handles;
+ float rigidbody_last_time;
+
+ SequencerBackup sequencer_backup;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc
new file mode 100644
index 00000000000..0150281a4ef
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_sequence.h"
+
+#include "DNA_sequence_types.h"
+
+namespace DEG {
+
+SequenceBackup::SequenceBackup(const Depsgraph * /*depsgraph*/)
+{
+ reset();
+}
+
+void SequenceBackup::reset()
+{
+ scene_sound = NULL;
+}
+
+void SequenceBackup::init_from_sequence(Sequence *sequence)
+{
+ scene_sound = sequence->scene_sound;
+
+ sequence->scene_sound = NULL;
+}
+
+void SequenceBackup::restore_to_sequence(Sequence *sequence)
+{
+ sequence->scene_sound = scene_sound;
+ reset();
+}
+
+bool SequenceBackup::isEmpty() const
+{
+ return (scene_sound == NULL);
+}
+
+} // namespace 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
new file mode 100644
index 00000000000..8a762a2785e
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h
@@ -0,0 +1,47 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+struct Sequence;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Backup of a single strip. */
+class SequenceBackup {
+ public:
+ SequenceBackup(const Depsgraph *depsgraph);
+
+ void reset();
+
+ void init_from_sequence(Sequence *sequence);
+ void restore_to_sequence(Sequence *sequence);
+
+ bool isEmpty() const;
+
+ void *scene_sound;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc
new file mode 100644
index 00000000000..08c2697aab3
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc
@@ -0,0 +1,72 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_sequencer.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BKE_sequencer.h"
+#include "BKE_sound.h"
+
+namespace DEG {
+
+SequencerBackup::SequencerBackup(const Depsgraph *depsgraph) : depsgraph(depsgraph)
+{
+}
+
+void SequencerBackup::init_from_scene(Scene *scene)
+{
+ Sequence *sequence;
+ SEQ_BEGIN (scene->ed, sequence) {
+ SequenceBackup sequence_backup(depsgraph);
+ sequence_backup.init_from_sequence(sequence);
+ if (!sequence_backup.isEmpty()) {
+ sequences_backup.insert(make_pair(sequence->orig_sequence, sequence_backup));
+ }
+ }
+ SEQ_END;
+}
+
+void SequencerBackup::restore_to_scene(Scene *scene)
+{
+ Sequence *sequence;
+ SEQ_BEGIN (scene->ed, sequence) {
+ SequencesBackupMap::iterator it = sequences_backup.find(sequence->orig_sequence);
+ if (it == sequences_backup.end()) {
+ continue;
+ }
+ SequenceBackup &sequence_backup = it->second;
+ sequence_backup.restore_to_sequence(sequence);
+ }
+ SEQ_END;
+ /* Cleanup audio while the scene is still known. */
+ for (SequencesBackupMap::value_type &it : sequences_backup) {
+ SequenceBackup &sequence_backup = it.second;
+ if (sequence_backup.scene_sound != NULL) {
+ BKE_sound_remove_scene_sound(scene, sequence_backup.scene_sound);
+ }
+ }
+}
+
+} // namespace 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
new file mode 100644
index 00000000000..57b533a1b84
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h
@@ -0,0 +1,49 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/eval/deg_eval_runtime_backup_sequence.h"
+#include "intern/depsgraph_type.h"
+
+struct Scene;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Backup of sequencer strips runtime data. */
+class SequencerBackup {
+ public:
+ SequencerBackup(const Depsgraph *depsgraph);
+
+ void init_from_scene(Scene *scene);
+ void restore_to_scene(Scene *scene);
+
+ const Depsgraph *depsgraph;
+
+ typedef map<Sequence *, SequenceBackup> SequencesBackupMap;
+ SequencesBackupMap sequences_backup;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc
new file mode 100644
index 00000000000..0c54032e32c
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_sound.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_sound_types.h"
+
+namespace DEG {
+
+SoundBackup::SoundBackup(const Depsgraph * /*depsgraph*/)
+{
+ reset();
+}
+
+void SoundBackup::reset()
+{
+ cache = NULL;
+ waveform = NULL;
+ playback_handle = NULL;
+}
+
+void SoundBackup::init_from_sound(bSound *sound)
+{
+ cache = sound->cache;
+ waveform = sound->waveform;
+ playback_handle = sound->playback_handle;
+
+ sound->cache = NULL;
+ sound->waveform = NULL;
+ sound->playback_handle = NULL;
+}
+
+void SoundBackup::restore_to_sound(bSound *sound)
+{
+ sound->cache = cache;
+ sound->waveform = waveform;
+ sound->playback_handle = playback_handle;
+
+ reset();
+}
+
+} // namespace 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
new file mode 100644
index 00000000000..87783146701
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h
@@ -0,0 +1,47 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+struct bSound;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Backup of sound datablocks runtime data. */
+class SoundBackup {
+ public:
+ SoundBackup(const Depsgraph *depsgraph);
+
+ void reset();
+
+ void init_from_sound(bSound *sound);
+ void restore_to_sound(bSound *sound);
+
+ void *cache;
+ void *waveform;
+ void *playback_handle;
+};
+
+} // namespace DEG
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 950adf3ddc5..6c55fa7ce30 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -21,7 +21,6 @@
set(INC
.
intern
- modes
../blenfont
../blenkernel
@@ -49,8 +48,6 @@ set(INC_SYS
)
set(SRC
- intern/draw_anim_viz.c
- intern/draw_armature.c
intern/draw_cache.c
intern/draw_cache_extract_mesh.c
intern/draw_cache_impl_curve.c
@@ -72,20 +69,6 @@ set(SRC
intern/draw_manager_texture.c
intern/draw_select_buffer.c
intern/draw_view.c
- modes/edit_armature_mode.c
- modes/edit_curve_mode.c
- modes/edit_lattice_mode.c
- modes/edit_mesh_mode.c
- modes/edit_mesh_mode_text.c
- modes/edit_metaball_mode.c
- modes/edit_text_mode.c
- modes/object_mode.c
- modes/overlay_mode.c
- modes/paint_texture_mode.c
- modes/paint_vertex_mode.c
- modes/particle_mode.c
- modes/pose_mode.c
- modes/sculpt_mode.c
engines/basic/basic_engine.c
engines/eevee/eevee_bloom.c
engines/eevee/eevee_data.c
@@ -102,6 +85,7 @@ set(SRC
engines/eevee/eevee_motion_blur.c
engines/eevee/eevee_occlusion.c
engines/eevee/eevee_render.c
+ engines/eevee/eevee_renderpasses.c
engines/eevee/eevee_sampling.c
engines/eevee/eevee_screen_raytrace.c
engines/eevee/eevee_shaders.c
@@ -135,6 +119,25 @@ set(SRC
engines/gpencil/gpencil_shader_fx.c
engines/select/select_draw_utils.c
engines/select/select_engine.c
+ engines/overlay/overlay_antialiasing.c
+ engines/overlay/overlay_armature.c
+ engines/overlay/overlay_edit_curve.c
+ engines/overlay/overlay_edit_mesh.c
+ engines/overlay/overlay_edit_text.c
+ engines/overlay/overlay_engine.c
+ engines/overlay/overlay_extra.c
+ engines/overlay/overlay_facing.c
+ engines/overlay/overlay_grid.c
+ engines/overlay/overlay_image.c
+ engines/overlay/overlay_lattice.c
+ engines/overlay/overlay_metaball.c
+ engines/overlay/overlay_motion_path.c
+ engines/overlay/overlay_outline.c
+ engines/overlay/overlay_paint.c
+ engines/overlay/overlay_particle.c
+ engines/overlay/overlay_sculpt.c
+ engines/overlay/overlay_shader.c
+ engines/overlay/overlay_wireframe.c
DRW_engine.h
DRW_select_buffer.h
@@ -151,8 +154,7 @@ set(SRC
intern/draw_manager_profiling.h
intern/draw_manager_text.h
intern/draw_view.h
- modes/draw_mode_engines.h
- modes/edit_mesh_mode_intern.h
+ intern/smaa_textures.h
engines/basic/basic_engine.h
engines/eevee/eevee_engine.h
engines/eevee/eevee_lightcache.h
@@ -163,6 +165,8 @@ set(SRC
engines/workbench/workbench_private.h
engines/select/select_engine.h
engines/select/select_private.h
+ engines/overlay/overlay_engine.h
+ engines/overlay/overlay_private.h
)
set(LIB
@@ -221,6 +225,7 @@ data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/update_noise_frag.glsl SRC)
@@ -259,90 +264,14 @@ data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_colormanagement_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_globals_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_hair_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_hair_refine_vert.glsl SRC)
-data_to_c_simple(modes/shaders/common_view_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_fxaa_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_fullscreen_vert.glsl SRC)
-data_to_c_simple(modes/shaders/animviz_mpath_lines_vert.glsl SRC)
-data_to_c_simple(modes/shaders/animviz_mpath_lines_geom.glsl SRC)
-data_to_c_simple(modes/shaders/animviz_mpath_points_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_axes_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_sphere_solid_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_sphere_solid_frag.glsl SRC)
-data_to_c_simple(modes/shaders/armature_sphere_outline_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_envelope_solid_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_envelope_solid_frag.glsl SRC)
-data_to_c_simple(modes/shaders/armature_envelope_outline_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_envelope_distance_frag.glsl SRC)
-data_to_c_simple(modes/shaders/armature_shape_solid_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_shape_solid_frag.glsl SRC)
-data_to_c_simple(modes/shaders/armature_shape_outline_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_shape_outline_geom.glsl SRC)
-data_to_c_simple(modes/shaders/armature_stick_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_stick_frag.glsl SRC)
-data_to_c_simple(modes/shaders/armature_dof_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_common_lib.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_frag.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_geom.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_mix_frag.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_frag.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_skin_root_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_curve_overlay_handle_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_curve_overlay_handle_geom.glsl SRC)
-data_to_c_simple(modes/shaders/edit_curve_overlay_loosevert_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_curve_overlay_normals_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_lattice_overlay_frag.glsl SRC)
-data_to_c_simple(modes/shaders/edit_lattice_overlay_loosevert_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_normals_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_normals_geom.glsl SRC)
-data_to_c_simple(modes/shaders/overlay_face_orientation_frag.glsl SRC)
-data_to_c_simple(modes/shaders/overlay_face_orientation_vert.glsl SRC)
-data_to_c_simple(modes/shaders/overlay_face_wireframe_vert.glsl SRC)
-data_to_c_simple(modes/shaders/overlay_face_wireframe_geom.glsl SRC)
-data_to_c_simple(modes/shaders/overlay_face_wireframe_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_camera_image_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_camera_image_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_color_axes_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_empty_axes_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_empty_image_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_empty_image_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_resolve_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_expand_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_detect_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_prepass_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_prepass_geom.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_prepass_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_grid_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_grid_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_lightprobe_grid_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_mball_handles_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_particle_prim_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_particle_dot_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_particle_dot_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_loose_points_frag.glsl SRC)
-data_to_c_simple(modes/shaders/paint_texture_frag.glsl SRC)
-data_to_c_simple(modes/shaders/paint_texture_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_vertex_frag.glsl SRC)
-data_to_c_simple(modes/shaders/paint_vertex_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_weight_frag.glsl SRC)
-data_to_c_simple(modes/shaders/paint_weight_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_face_selection_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_face_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_wire_frag.glsl SRC)
-data_to_c_simple(modes/shaders/paint_wire_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_vert_frag.glsl SRC)
-data_to_c_simple(modes/shaders/particle_strand_frag.glsl SRC)
-data_to_c_simple(modes/shaders/particle_strand_vert.glsl SRC)
-data_to_c_simple(modes/shaders/pose_selection_vert.glsl SRC)
-data_to_c_simple(modes/shaders/sculpt_mask_vert.glsl SRC)
-data_to_c_simple(modes/shaders/volume_velocity_vert.glsl SRC)
+data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_globals_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_hair_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_hair_refine_vert.glsl SRC)
+data_to_c_simple(intern/shaders/common_view_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_fxaa_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_smaa_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_fullscreen_vert.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_fill_vert.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_fill_frag.glsl SRC)
@@ -378,6 +307,80 @@ data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl SRC)
data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC)
data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/antialiasing_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/antialiasing_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_dof_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_envelope_outline_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_shape_outline_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_shape_outline_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_shape_solid_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_shape_solid_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_shape_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_sphere_outline_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_stick_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_stick_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_wire_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/depth_only_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_curve_handle_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_curve_handle_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_curve_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_curve_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_lattice_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_lattice_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_common_lib.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_facefill_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_facefill_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_normal_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_analysis_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_analysis_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_skin_root_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_particle_strand_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_particle_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_groundline_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_lightprobe_grid_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_loose_point_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_loose_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_wire_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/facing_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/facing_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/grid_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/grid_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/image_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/image_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/motion_path_line_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/motion_path_line_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/motion_path_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_detect_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_prepass_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_prepass_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_prepass_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_face_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_texture_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_texture_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_vertcol_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_vertcol_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_weight_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_weight_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/particle_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/particle_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/sculpt_mask_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/volume_velocity_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/wireframe_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/wireframe_frag.glsl SRC)
list(APPEND INC
)
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 24f92d57b48..f36494daed0 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -23,6 +23,10 @@
#ifndef __DRW_ENGINE_H__
#define __DRW_ENGINE_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "BLI_sys_types.h" /* for bool */
struct ARegion;
@@ -48,6 +52,7 @@ struct rcti;
/* Buffer and textures used by the viewport by default */
typedef struct DefaultFramebufferList {
struct GPUFrameBuffer *default_fb;
+ struct GPUFrameBuffer *in_front_fb;
struct GPUFrameBuffer *color_only_fb;
struct GPUFrameBuffer *depth_only_fb;
struct GPUFrameBuffer *multisample_fb;
@@ -56,6 +61,7 @@ typedef struct DefaultFramebufferList {
typedef struct DefaultTextureList {
struct GPUTexture *color;
struct GPUTexture *depth;
+ struct GPUTexture *depth_in_front;
struct GPUTexture *multisample_color;
struct GPUTexture *multisample_depth;
} DefaultTextureList;
@@ -128,6 +134,7 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
struct View3D *v3d,
struct GPUViewport *viewport);
void DRW_draw_depth_object(struct ARegion *ar,
+ struct View3D *v3d,
struct GPUViewport *viewport,
struct Object *object);
void DRW_draw_select_id(struct Depsgraph *depsgraph,
@@ -171,4 +178,8 @@ void DRW_deferred_shader_remove(struct GPUMaterial *mat);
struct DrawDataList *DRW_drawdatalist_from_id(struct ID *id);
void DRW_drawdata_free(struct ID *id);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __DRW_ENGINE_H__ */
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index 0dd1a4fd686..fcbe227ca1b 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -46,8 +46,8 @@ typedef struct BASIC_StorageList {
} BASIC_StorageList;
typedef struct BASIC_PassList {
- struct DRWPass *depth_pass;
- struct DRWPass *depth_pass_cull;
+ struct DRWPass *depth_pass[2];
+ struct DRWPass *depth_pass_cull[2];
} BASIC_PassList;
typedef struct BASIC_Data {
@@ -70,8 +70,8 @@ static struct {
} e_data = {{{NULL}}}; /* Engine data */
typedef struct BASIC_PrivateData {
- DRWShadingGroup *depth_shgrp;
- DRWShadingGroup *depth_shgrp_cull;
+ DRWShadingGroup *depth_shgrp[2];
+ DRWShadingGroup *depth_shgrp_cull[2];
} BASIC_PrivateData; /* Transient data */
/* Functions */
@@ -97,24 +97,21 @@ static void basic_cache_init(void *vedata)
if (!stl->g_data) {
/* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
}
- {
- psl->depth_pass = DRW_pass_create("Depth Pass",
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
- stl->g_data->depth_shgrp = DRW_shgroup_create(sh_data->depth, psl->depth_pass);
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(stl->g_data->depth_shgrp, DRW_STATE_CLIP_PLANES);
- }
+ /* Twice for normal and infront objects. */
+ for (int i = 0; i < 2; i++) {
+ DRWState clip_state = (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? DRW_STATE_CLIP_PLANES : 0;
+ DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull",
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_CULL_BACK);
- stl->g_data->depth_shgrp_cull = DRW_shgroup_create(sh_data->depth, psl->depth_pass_cull);
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(stl->g_data->depth_shgrp_cull, DRW_STATE_CLIP_PLANES);
- }
+ DRW_PASS_CREATE(psl->depth_pass[i], state | clip_state | infront_state);
+ stl->g_data->depth_shgrp[i] = DRW_shgroup_create(sh_data->depth, psl->depth_pass[i]);
+
+ state |= DRW_STATE_CULL_BACK;
+ DRW_PASS_CREATE(psl->depth_pass_cull[i], state | clip_state | infront_state);
+ stl->g_data->depth_shgrp_cull[i] = DRW_shgroup_create(sh_data->depth, psl->depth_pass_cull[i]);
}
}
@@ -128,6 +125,8 @@ static void basic_cache_populate(void *vedata, Object *ob)
return;
}
+ bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+
const DRWContextState *draw_ctx = DRW_context_state_get();
if (ob != draw_ctx->object_edit) {
for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) {
@@ -138,7 +137,7 @@ static void basic_cache_populate(void *vedata, Object *ob)
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
if (draw_as == PART_DRAW_PATH) {
struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
- DRW_shgroup_call(stl->g_data->depth_shgrp, hairs, NULL);
+ DRW_shgroup_call(stl->g_data->depth_shgrp[do_in_front], hairs, NULL);
}
}
}
@@ -155,7 +154,7 @@ static void basic_cache_populate(void *vedata, Object *ob)
/* Avoid losing flat objects when in ortho views (see T56549) */
struct GPUBatch *geom = DRW_cache_object_all_edges_get(ob);
if (geom) {
- DRW_shgroup_call(stl->g_data->depth_shgrp, geom, ob);
+ DRW_shgroup_call(stl->g_data->depth_shgrp[do_in_front], geom, ob);
}
return;
}
@@ -165,7 +164,8 @@ static void basic_cache_populate(void *vedata, Object *ob)
!DRW_state_is_image_render();
const bool do_cull = (draw_ctx->v3d &&
(draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING));
- DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
+ DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull[do_in_front] :
+ stl->g_data->depth_shgrp[do_in_front];
if (use_sculpt_pbvh) {
DRW_shgroup_call_sculpt(shgrp, ob, false, false, false);
@@ -189,8 +189,10 @@ static void basic_draw_scene(void *vedata)
{
BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
- DRW_draw_pass(psl->depth_pass);
- DRW_draw_pass(psl->depth_pass_cull);
+ DRW_draw_pass(psl->depth_pass[0]);
+ DRW_draw_pass(psl->depth_pass_cull[0]);
+ DRW_draw_pass(psl->depth_pass[1]);
+ DRW_draw_pass(psl->depth_pass_cull[1]);
}
static void basic_engine_free(void)
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index d59d1f56e92..824ea69ea73 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -136,8 +136,6 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
EEVEE_TextureList *txl = vedata->txl;
EEVEE_EffectsInfo *effects;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
const float *viewport_size = DRW_viewport_size_get();
int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]};
@@ -172,7 +170,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
EEVEE_subsurface_init(sldata, vedata);
/* Force normal buffer creation. */
- if (DRW_state_is_image_render() && !minimal && (view_layer->passflag & SCE_PASS_NORMAL) != 0) {
+ if (!minimal && (stl->g_data->render_passes & SCE_PASS_NORMAL) != 0) {
effects->enabled_effects |= EFFECT_NORMAL_BUFFER;
}
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index a1096390bce..a6ad7d97922 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -27,6 +27,8 @@
#include "BKE_object.h"
#include "BKE_global.h" /* for G.debug_value */
+#include "DEG_depsgraph_query.h"
+
#include "DNA_world_types.h"
#include "eevee_private.h"
@@ -81,7 +83,9 @@ static void eevee_engine_init(void *ved)
&sldata->common_data);
}
- /* EEVEE_effects_init needs to go first for TAA */
+ /* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`.
+ * `EEVEE_effects_init` needs to go second for TAA. */
+ EEVEE_renderpasses_init(vedata);
EEVEE_effects_init(sldata, vedata, camera, false);
EEVEE_materials_init(sldata, stl, fbl);
EEVEE_shadows_init(sldata);
@@ -147,6 +151,8 @@ static void eevee_cache_finish(void *vedata)
{
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
EEVEE_PrivateData *g_data = ((EEVEE_Data *)vedata)->stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
EEVEE_volumes_cache_finish(sldata, vedata);
EEVEE_materials_cache_finish(sldata, vedata);
@@ -156,6 +162,14 @@ static void eevee_cache_finish(void *vedata)
EEVEE_effects_draw_init(sldata, vedata);
EEVEE_volumes_draw_init(sldata, vedata);
+ uint tot_samples = scene_eval->eevee.taa_render_samples;
+ if (tot_samples == 0) {
+ /* Use a high number of samples so the outputs accumulation buffers
+ * will have the highest possible precision. */
+ tot_samples = 1024;
+ }
+ EEVEE_renderpasses_output_init(sldata, vedata, tot_samples);
+
/* Restart taa if a shader has finish compiling. */
/* HACK We should use notification of some sort from the compilation job instead. */
if (g_data->queued_shaders_count != g_data->queued_shaders_count_prev) {
@@ -306,6 +320,8 @@ static void eevee_draw_background(void *vedata)
EEVEE_draw_effects(sldata, vedata);
DRW_stats_group_end();
+ EEVEE_renderpasses_output_accumulate(sldata, vedata);
+
DRW_view_set_active(NULL);
if (DRW_state_is_image_render() && (stl->effects->enabled_effects & EFFECT_SSR) &&
@@ -319,14 +335,19 @@ static void eevee_draw_background(void *vedata)
}
}
- /* Tonemapping and transfer result to default framebuffer. */
- bool use_render_settings = stl->g_data->use_color_render_settings;
+ if ((stl->g_data->render_passes & SCE_PASS_COMBINED) > 0) {
+ /* Tonemapping and transfer result to default framebuffer. */
+ bool use_render_settings = stl->g_data->use_color_render_settings;
- GPU_framebuffer_bind(dfbl->default_fb);
- DRW_transform_to_display(stl->effects->final_tx, true, use_render_settings);
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_transform_to_display(stl->effects->final_tx, true, use_render_settings);
- /* Draw checkerboard with alpha under. */
- EEVEE_draw_alpha_checker(vedata);
+ /* Draw checkerboard with alpha under. */
+ EEVEE_draw_alpha_checker(vedata);
+ }
+ else {
+ EEVEE_renderpasses_draw(sldata, vedata);
+ }
/* Debug : Output buffer to view. */
switch (G.debug_value) {
@@ -483,6 +504,7 @@ static void eevee_engine_free(void)
EEVEE_screen_raytrace_free();
EEVEE_subsurface_free();
EEVEE_volumes_free();
+ EEVEE_renderpasses_free();
}
static const DrawEngineDataSize eevee_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data);
diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c
index 7209651a1d4..c9b56a6d551 100644
--- a/source/blender/draw/engines/eevee/eevee_mist.c
+++ b/source/blender/draw/engines/eevee/eevee_mist.c
@@ -49,6 +49,7 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_TextureList *txl = vedata->txl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_PassList *psl = vedata->psl;
+ EEVEE_EffectsInfo *effects = stl->effects;
EEVEE_PrivateData *g_data = stl->g_data;
Scene *scene = draw_ctx->scene;
@@ -74,8 +75,10 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->mist_accum)});
/* Clear texture. */
- GPU_framebuffer_bind(fbl->mist_accum_fb);
- GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear);
+ if (DRW_state_is_image_render() || effects->taa_current_sample == 1) {
+ GPU_framebuffer_bind(fbl->mist_accum_fb);
+ GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear);
+ }
/* Mist settings. */
if (scene && scene->world) {
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
index 48e9b5bcc13..6ba518b3a28 100644
--- a/source/blender/draw/engines/eevee/eevee_occlusion.c
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -131,7 +131,7 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
return 0;
}
-void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples)
{
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
@@ -143,18 +143,22 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) {
+ const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_R32F : GPU_R16F;
+
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
/* Should be enough precision for many samples. */
- DRW_texture_ensure_fullscreen_2d(&txl->ao_accum, GPU_R32F, 0);
+ DRW_texture_ensure_fullscreen_2d(&txl->ao_accum, texture_format, 0);
GPU_framebuffer_ensure_config(&fbl->ao_accum_fb,
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ao_accum)});
/* Clear texture. */
- GPU_framebuffer_bind(fbl->ao_accum_fb);
- GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear);
+ if (DRW_state_is_image_render() || effects->taa_current_sample == 1) {
+ GPU_framebuffer_bind(fbl->ao_accum_fb);
+ GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear);
+ }
/* Accumulation pass */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD;
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 7d02aacfac7..97bde2e5f2e 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -271,6 +271,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *update_noise_pass;
struct DRWPass *lookdev_glossy_pass;
struct DRWPass *lookdev_diffuse_pass;
+ struct DRWPass *renderpass_pass;
} EEVEE_PassList;
typedef struct EEVEE_FramebufferList {
@@ -295,6 +296,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *screen_tracing_fb;
struct GPUFrameBuffer *refract_fb;
struct GPUFrameBuffer *mist_accum_fb;
+ struct GPUFrameBuffer *renderpass_fb;
struct GPUFrameBuffer *ao_accum_fb;
struct GPUFrameBuffer *velocity_resolve_fb;
@@ -341,6 +343,8 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *maxzbuffer;
+ struct GPUTexture *renderpass;
+
struct GPUTexture *color; /* R16_G16_B16 */
struct GPUTexture *color_double_buffer;
struct GPUTexture *depth_double_buffer;
@@ -799,6 +803,10 @@ typedef struct EEVEE_PrivateData {
float studiolight_glossy_clamp;
float studiolight_filter_quality;
+ /* Renderpasses */
+ /* Bitmask containing the active render_passes */
+ eScenePassType render_passes;
+
/** For rendering shadows. */
struct DRWView *cube_views[6];
/** For rendering probes. */
@@ -988,7 +996,9 @@ void EEVEE_bloom_free(void);
/* eevee_occlusion.c */
int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ uint tot_samples);
void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_occlusion_compute(EEVEE_ViewLayerData *sldata,
@@ -1009,7 +1019,9 @@ void EEVEE_screen_raytrace_free(void);
void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ uint tot_samples);
void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
uint sss_id,
@@ -1035,6 +1047,19 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_mist_free(void);
+/* eevee_renderpasses.c */
+void EEVEE_renderpasses_init(EEVEE_Data *vedata);
+void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ uint tot_samples);
+void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ eScenePassType renderpass_type);
+void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_renderpasses_free(void);
+bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata);
+
/* eevee_temporal_sampling.c */
void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata);
int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index 75e837f140b..ba5704f14e5 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -130,7 +130,9 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
DRW_view_default_set(view);
DRW_view_set_active(view);
- /* EEVEE_effects_init needs to go first for TAA */
+ /* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`.
+ * `EEVEE_effects_init` needs to go second for TAA. */
+ EEVEE_renderpasses_init(vedata);
EEVEE_effects_init(sldata, vedata, ob_camera_eval, false);
EEVEE_materials_init(sldata, stl, fbl);
EEVEE_shadows_init(sldata);
@@ -202,79 +204,60 @@ void EEVEE_render_cache(void *vedata,
}
}
-static void eevee_render_result_combined(RenderLayer *rl,
- const char *viewname,
- const rcti *rect,
- EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata))
+static void eevee_render_color_result(RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect,
+ const char *render_pass_name,
+ int num_channels,
+ GPUFrameBuffer *framebuffer,
+ EEVEE_Data *vedata)
{
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
-
- GPU_framebuffer_bind(vedata->stl->effects->final_fb);
- GPU_framebuffer_read_color(vedata->stl->effects->final_fb,
+ RenderPass *rp = RE_pass_find_by_name(rl, render_pass_name, viewname);
+ GPU_framebuffer_bind(framebuffer);
+ GPU_framebuffer_read_color(framebuffer,
vedata->stl->g_data->overscan_pixels + rect->xmin,
vedata->stl->g_data->overscan_pixels + rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
- 4,
+ num_channels,
0,
rp->rect);
}
+static void eevee_render_result_combined(RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect,
+ EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *UNUSED(sldata))
+{
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_COMBINED, 4, vedata->stl->effects->final_fb, vedata);
+}
+
static void eevee_render_result_subsurface(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata),
- int render_samples)
+ EEVEE_ViewLayerData *sldata)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
-
if (vedata->fbl->sss_accum_fb == NULL) {
/* SSS is not enabled. */
return;
}
- if ((view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_COLOR, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->sss_accum_fb);
- GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb,
- vedata->stl->g_data->overscan_pixels + rect->xmin,
- vedata->stl->g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- 3,
- 1,
- rp->rect);
-
- /* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rp->rectx * rp->recty * 3; i++) {
- rp->rect[i] /= (float)render_samples;
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_COLOR) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_SUBSURFACE_COLOR);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_SUBSURFACE_COLOR, 3, vedata->fbl->renderpass_fb, vedata);
}
- if ((view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_DIRECT, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->sss_accum_fb);
- GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb,
- vedata->stl->g_data->overscan_pixels + rect->xmin,
- vedata->stl->g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- 3,
- 0,
- rp->rect);
-
- /* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rp->rectx * rp->recty * 3; i++) {
- rp->rect[i] /= (float)render_samples;
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_DIRECT) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_SUBSURFACE_DIRECT);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_SUBSURFACE_DIRECT, 3, vedata->fbl->renderpass_fb, vedata);
}
- if ((view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT) != 0) {
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_INDIRECT) != 0) {
/* Do nothing as all the lighting is in the direct pass.
* TODO : Separate Direct from indirect lighting. */
}
@@ -284,54 +267,19 @@ static void eevee_render_result_normal(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata))
+ EEVEE_ViewLayerData *sldata)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_PrivateData *g_data = stl->g_data;
+ const int current_sample = vedata->stl->effects->taa_current_sample;
/* Only read the center texel. */
- if (stl->effects->taa_current_sample > 1) {
+ if (current_sample > 1) {
return;
}
- if ((view_layer->passflag & SCE_PASS_NORMAL) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_NORMAL, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->main_fb);
- GPU_framebuffer_read_color(vedata->fbl->main_fb,
- g_data->overscan_pixels + rect->xmin,
- g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- 3,
- 1,
- rp->rect);
-
- float viewinv[4][4];
- DRW_view_viewmat_get(NULL, viewinv, true);
-
- /* Convert Eevee encoded normals to Blender normals. */
- for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) {
- if (rp->rect[i] == 0.0f && rp->rect[i + 1] == 0.0f) {
- /* If normal is not correct then do not produce NANs. */
- continue;
- }
-
- float fenc[2];
- fenc[0] = rp->rect[i + 0] * 4.0f - 2.0f;
- fenc[1] = rp->rect[i + 1] * 4.0f - 2.0f;
-
- float f = dot_v2v2(fenc, fenc);
- float g = sqrtf(1.0f - f / 4.0f);
-
- rp->rect[i + 0] = fenc[0] * g;
- rp->rect[i + 1] = fenc[1] * g;
- rp->rect[i + 2] = 1.0f - f / 2.0f;
-
- mul_mat3_m4_v3(viewinv, &rp->rect[i]);
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_NORMAL) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_NORMAL);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_NORMAL, 3, vedata->fbl->renderpass_fb, vedata);
}
}
@@ -341,49 +289,17 @@ static void eevee_render_result_z(RenderLayer *rl,
EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
- EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_PrivateData *g_data = stl->g_data;
+ const int current_sample = vedata->stl->effects->taa_current_sample;
/* Only read the center texel. */
- if (stl->effects->taa_current_sample > 1) {
+ if (current_sample > 1) {
return;
}
- if ((view_layer->passflag & SCE_PASS_Z) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->main_fb);
- GPU_framebuffer_read_depth(vedata->fbl->main_fb,
- g_data->overscan_pixels + rect->xmin,
- g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- rp->rect);
-
- bool is_persp = DRW_view_is_persp_get(NULL);
-
- float winmat[4][4];
- DRW_view_winmat_get(NULL, winmat, false);
-
- /* Convert ogl depth [0..1] to view Z [near..far] */
- for (int i = 0; i < rp->rectx * rp->recty; i++) {
- if (rp->rect[i] == 1.0f) {
- rp->rect[i] = 1e10f; /* Background */
- }
- else {
- if (is_persp) {
- rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
- rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
- }
- else {
- rp->rect[i] = -common_data->view_vecs[0][2] +
- rp->rect[i] * -common_data->view_vecs[1][2];
- }
- }
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_Z) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_Z);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_Z, 1, vedata->fbl->renderpass_fb, vedata);
}
}
@@ -391,29 +307,12 @@ static void eevee_render_result_mist(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata),
- int render_samples)
+ EEVEE_ViewLayerData *sldata)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
-
- if ((view_layer->passflag & SCE_PASS_MIST) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_MIST, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->mist_accum_fb);
- GPU_framebuffer_read_color(vedata->fbl->mist_accum_fb,
- vedata->stl->g_data->overscan_pixels + rect->xmin,
- vedata->stl->g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- 1,
- 0,
- rp->rect);
-
- /* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rp->rectx * rp->recty; i++) {
- rp->rect[i] /= (float)render_samples;
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_MIST) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_MIST);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_MIST, 1, vedata->fbl->renderpass_fb, vedata);
}
}
@@ -421,35 +320,17 @@ static void eevee_render_result_occlusion(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata),
- int render_samples)
+ EEVEE_ViewLayerData *sldata)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
-
if (vedata->fbl->ao_accum_fb == NULL) {
/* AO is not enabled. */
return;
}
- if ((view_layer->passflag & SCE_PASS_AO) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_AO, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->ao_accum_fb);
- GPU_framebuffer_read_color(vedata->fbl->ao_accum_fb,
- vedata->stl->g_data->overscan_pixels + rect->xmin,
- vedata->stl->g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- 3,
- 0,
- rp->rect);
-
- /* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) {
- rp->rect[i] = rp->rect[i + 1] = rp->rect[i + 2] = min_ff(
- 1.0f, rp->rect[i] / (float)render_samples);
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_AO) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_AO);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_AO, 3, vedata->fbl->renderpass_fb, vedata);
}
}
@@ -488,7 +369,6 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
- ViewLayer *view_layer = draw_ctx->view_layer;
const char *viewname = RE_GetActiveRenderView(engine->re);
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
@@ -517,31 +397,20 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
GPU_framebuffer_bind(fbl->main_fb);
DRW_hair_update();
- if ((view_layer->passflag & (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT |
- SCE_PASS_SUBSURFACE_INDIRECT)) != 0) {
- EEVEE_subsurface_output_init(sldata, vedata);
- }
-
- if ((view_layer->passflag & SCE_PASS_MIST) != 0) {
- EEVEE_mist_output_init(sldata, vedata);
- }
-
- if ((view_layer->passflag & SCE_PASS_AO) != 0) {
- EEVEE_occlusion_output_init(sldata, vedata);
- }
-
uint tot_sample = scene_eval->eevee.taa_render_samples;
uint render_samples = 0;
- if (RE_engine_test_break(engine)) {
- return;
- }
-
/* SSR needs one iteration to start properly. */
if (stl->effects->enabled_effects & EFFECT_SSR) {
tot_sample += 1;
}
+ EEVEE_renderpasses_output_init(sldata, vedata, tot_sample);
+
+ if (RE_engine_test_break(engine)) {
+ return;
+ }
+
while (render_samples < tot_sample && !RE_engine_test_break(engine)) {
float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float clear_depth = 1.0f;
@@ -616,16 +485,12 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
DRW_draw_pass(psl->refract_depth_pass);
DRW_draw_pass(psl->refract_depth_pass_cull);
DRW_draw_pass(psl->refract_pass);
- /* Subsurface output */
- EEVEE_subsurface_output_accumulate(sldata, vedata);
- /* Occlusion output */
- EEVEE_occlusion_output_accumulate(sldata, vedata);
/* Result NORMAL */
eevee_render_result_normal(rl, viewname, rect, vedata, sldata);
/* Volumetrics Resolve Opaque */
EEVEE_volumes_resolve(sldata, vedata);
- /* Mist output */
- EEVEE_mist_output_accumulate(sldata, vedata);
+ /* Subsurface output, Occlusion output, Mist output */
+ EEVEE_renderpasses_output_accumulate(sldata, vedata);
/* Transparent */
GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0);
GPU_framebuffer_bind(fbl->main_color_fb);
@@ -644,9 +509,9 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
}
eevee_render_result_combined(rl, viewname, rect, vedata, sldata);
- eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata, render_samples);
- eevee_render_result_mist(rl, viewname, rect, vedata, sldata, render_samples);
- eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata, render_samples);
+ eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata);
+ eevee_render_result_mist(rl, viewname, rect, vedata, sldata);
+ eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata);
/* Restore original viewport size. */
DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]});
diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c
new file mode 100644
index 00000000000..927ff70a52b
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c
@@ -0,0 +1,278 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BLI_string_utils.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_renderpass_postprocess_frag_glsl[];
+
+static struct {
+ struct GPUShader *postprocess_sh;
+} e_data = {NULL}; /* Engine data */
+
+/* bitmask containing all renderpasses that need post-processing */
+#define EEVEE_RENDERPASSES_WITH_POST_PROCESSING \
+ (SCE_PASS_Z | SCE_PASS_MIST | SCE_PASS_NORMAL | SCE_PASS_AO | SCE_PASS_SUBSURFACE_COLOR | \
+ SCE_PASS_SUBSURFACE_DIRECT)
+
+#define EEVEE_RENDERPASSES_SUBSURFACE \
+ (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT | SCE_PASS_SUBSURFACE_INDIRECT)
+
+#define EEVEE_RENDERPASSES_ALL (EEVEE_RENDERPASSES_WITH_POST_PROCESSING | SCE_PASS_COMBINED)
+
+#define EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE (SCE_PASS_Z | SCE_PASS_NORMAL)
+
+#define EEVEE_RENDERPASSES_COLOR_PASS (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT)
+
+bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ return (g_data->render_passes & ~EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) == 0;
+}
+
+void EEVEE_renderpasses_init(EEVEE_Data *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ View3D *v3d = draw_ctx->v3d;
+
+ if (v3d) {
+ g_data->render_passes = v3d->shading.render_pass;
+ }
+ else {
+ g_data->render_passes = (view_layer->passflag & EEVEE_RENDERPASSES_ALL) | SCE_PASS_COMBINED;
+ }
+}
+
+void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ uint tot_samples)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+
+ const bool needs_post_processing = (g_data->render_passes &
+ EEVEE_RENDERPASSES_WITH_POST_PROCESSING) > 0;
+ if (needs_post_processing) {
+ if (e_data.postprocess_sh == NULL) {
+ char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_renderpass_postprocess_frag_glsl);
+ e_data.postprocess_sh = DRW_shader_create_fullscreen(frag_str, NULL);
+ MEM_freeN(frag_str);
+ }
+
+ /* Create FrameBuffer. */
+
+ /* Should be enough to store the data needs for a single pass.
+ * Some passes will use less, but it is only relevant for final renderings and
+ * when renderpasses other than `SCE_PASS_COMBINED` are requested */
+ DRW_texture_ensure_fullscreen_2d(&txl->renderpass, GPU_RGBA16F, 0);
+ GPU_framebuffer_ensure_config(&fbl->renderpass_fb,
+ {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->renderpass)});
+
+ if ((g_data->render_passes & EEVEE_RENDERPASSES_SUBSURFACE) != 0) {
+ EEVEE_subsurface_output_init(sldata, vedata, tot_samples);
+ }
+
+ if ((g_data->render_passes & SCE_PASS_MIST) != 0) {
+ EEVEE_mist_output_init(sldata, vedata);
+ }
+
+ if ((g_data->render_passes & SCE_PASS_AO) != 0) {
+ EEVEE_occlusion_output_init(sldata, vedata, tot_samples);
+ }
+
+ /* Create Pass. */
+ DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR);
+ }
+ else {
+ /* Free unneeded memory */
+ DRW_TEXTURE_FREE_SAFE(txl->renderpass);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb);
+ psl->renderpass_pass = NULL;
+ }
+}
+
+/* Postprocess data to construct a specific renderpass
+ *
+ * This method will create a shading group to perform the post-processing for the given
+ * `renderpass_type`. The post-processing will be done and the result will be stored in the
+ * `vedata->txl->renderpass` texture.
+ *
+ * Only invoke this function for passes that need post-processing.
+ *
+ * After invoking this function the active framebuffer is set to `vedata->fbl->renderpass_fb`. */
+void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ eScenePassType renderpass_type)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ const int current_sample = effects->taa_current_sample;
+
+ DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.postprocess_sh, psl->renderpass_pass);
+ DRW_shgroup_uniform_int_copy(shgrp, "renderpassType", renderpass_type);
+
+ switch (renderpass_type) {
+ case SCE_PASS_Z: {
+ DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_texture_ref(shgrp, "depthBuffer", &dtxl->depth);
+ break;
+ }
+
+ case SCE_PASS_AO: {
+ DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->ao_accum);
+ DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
+ break;
+ }
+
+ case SCE_PASS_NORMAL: {
+ DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &effects->ssr_normal_input);
+ DRW_shgroup_uniform_texture_ref(shgrp, "depthBuffer", &dtxl->depth);
+ break;
+ }
+
+ case SCE_PASS_MIST: {
+ DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->mist_accum);
+ DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
+ break;
+ }
+
+ case SCE_PASS_SUBSURFACE_DIRECT: {
+ DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->sss_dir_accum);
+ DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
+ break;
+ }
+
+ case SCE_PASS_SUBSURFACE_COLOR: {
+ DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->sss_col_accum);
+ DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
+ break;
+ }
+
+ default: {
+ break;
+ }
+ }
+
+ DRW_shgroup_call(shgrp, DRW_cache_fullscreen_quad_get(), NULL);
+
+ /* only draw the shading group that has been added. This function can be called multiple times
+ * and the pass still hold the previous shading groups.*/
+ GPU_framebuffer_bind(fbl->renderpass_fb);
+ DRW_draw_pass_subset(psl->renderpass_pass, shgrp, shgrp);
+}
+
+void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ eScenePassType render_pass = stl->g_data->render_passes;
+
+ if ((render_pass & SCE_PASS_MIST) != 0) {
+ EEVEE_mist_output_accumulate(sldata, vedata);
+ }
+ if ((effects->enabled_effects & EFFECT_SSS) &&
+ (render_pass & EEVEE_RENDERPASSES_SUBSURFACE) != 0) {
+ EEVEE_subsurface_output_accumulate(sldata, vedata);
+ }
+ if ((render_pass & SCE_PASS_AO) != 0) {
+ EEVEE_occlusion_output_accumulate(sldata, vedata);
+ }
+}
+
+void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ eScenePassType render_pass = stl->g_data->render_passes;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ bool is_valid = (render_pass & EEVEE_RENDERPASSES_ALL) > 0;
+ bool needs_color_transfer = (render_pass & EEVEE_RENDERPASSES_COLOR_PASS) > 0 &&
+ DRW_state_is_opengl_render();
+
+ /* When SSS isn't available, but the pass is requested, we mark it as invalid */
+ if ((render_pass & EEVEE_RENDERPASSES_SUBSURFACE) != 0 &&
+ (effects->enabled_effects & EFFECT_SSS) == 0) {
+ is_valid = false;
+ }
+
+ /* When SSS isn't available, but the pass is requested, we mark it as invalid */
+ if ((render_pass & SCE_PASS_AO) != 0 && (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) == 0) {
+ is_valid = false;
+ }
+
+ const int current_sample = stl->effects->taa_current_sample;
+ const int total_samples = stl->effects->taa_total_sample;
+ if ((render_pass & EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) &&
+ (current_sample > 1 && total_samples != 1)) {
+ return;
+ }
+
+ if (is_valid) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, render_pass);
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_transform_to_display(txl->renderpass, needs_color_transfer, false);
+ }
+ else {
+ /* Draw state is not valid for this pass, clear the buffer */
+ static float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_clear_color(dfbl->default_fb, clear_color);
+ }
+ GPU_framebuffer_bind(fbl->main_fb);
+}
+
+void EEVEE_renderpasses_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.postprocess_sh);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index 8376b8c67b8..e94fc903694 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -156,7 +156,9 @@ static void set_shgrp_stencil(void *UNUSED(userData), DRWShadingGroup *shgrp)
DRW_shgroup_stencil_mask(shgrp, 255);
}
-void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata),
+ EEVEE_Data *vedata,
+ uint tot_samples)
{
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
@@ -164,8 +166,10 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
EEVEE_EffectsInfo *effects = stl->effects;
if (effects->enabled_effects & EFFECT_SSS) {
- DRW_texture_ensure_fullscreen_2d(&txl->sss_dir_accum, GPU_RGBA16F, 0);
- DRW_texture_ensure_fullscreen_2d(&txl->sss_col_accum, GPU_RGBA16F, 0);
+ const eGPUTextureFormat texture_format_light = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F;
+ const eGPUTextureFormat texture_format_color = (tot_samples > 512) ? GPU_RGBA32F : GPU_RGBA16F;
+ DRW_texture_ensure_fullscreen_2d(&txl->sss_dir_accum, texture_format_light, 0);
+ DRW_texture_ensure_fullscreen_2d(&txl->sss_col_accum, texture_format_color, 0);
GPUTexture *stencil_tex = effects->sss_stencil;
@@ -183,9 +187,11 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
GPU_ATTACHMENT_TEXTURE(txl->sss_col_accum)});
/* Clear texture. */
- float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- GPU_framebuffer_bind(fbl->sss_accum_fb);
- GPU_framebuffer_clear_color(fbl->sss_accum_fb, clear);
+ if (DRW_state_is_image_render() || effects->taa_current_sample == 1) {
+ float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPU_framebuffer_bind(fbl->sss_accum_fb);
+ GPU_framebuffer_clear_color(fbl->sss_accum_fb, clear);
+ }
/* Make the opaque refraction pass mask the sss. */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES |
@@ -253,7 +259,8 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
- if (DRW_state_is_image_render()) {
+ if ((stl->g_data->render_passes & (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT)) !=
+ 0) {
grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_accum_ps);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
index e5f89aab4d1..0f0b4a3e0a9 100644
--- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -234,7 +234,9 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
view_is_valid = view_is_valid && (ED_screen_animation_no_scrub(wm) == NULL);
}
- effects->taa_total_sample = scene_eval->eevee.taa_samples;
+ effects->taa_total_sample = EEVEE_renderpasses_only_first_sample_pass_active(vedata) ?
+ 1 :
+ scene_eval->eevee.taa_samples;
MAX2(effects->taa_total_sample, 0);
DRW_view_persmat_get(NULL, persmat, false);
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 67fd441a0b1..d32f93432b8 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -28,12 +28,12 @@
#include "BLI_string_utils.h"
#include "DNA_object_force_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_world_types.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
-#include "BKE_smoke.h"
+#include "BKE_fluid.h"
#include "ED_screen.h"
@@ -63,7 +63,7 @@ static struct {
GPUTexture *dummy_scatter;
GPUTexture *dummy_transmit;
- /* List of all smoke domains rendered within this frame. */
+ /* List of all fluid simulation / smoke domains rendered within this frame. */
ListBase smoke_domains;
} e_data = {NULL}; /* Engine data */
@@ -390,8 +390,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
Scene *scene,
Object *ob)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- static float white[3] = {1.0f, 1.0f, 1.0f};
+ static const float white[3] = {1.0f, 1.0f, 1.0f};
float *texcoloc = NULL;
float *texcosize = NULL;
@@ -430,41 +429,49 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
/* Smoke Simulation */
if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (md = modifiers_findByType(ob, eModifierType_Fluid)) &&
(modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- ((SmokeModifierData *)md)->domain != NULL) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- SmokeDomainSettings *sds = smd->domain;
+ ((FluidModifierData *)md)->domain != NULL) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ FluidDomainSettings *mds = mmd->domain;
+
+ /* Don't try to show liquid domains here. */
+ if (!mds->fluid || !(mds->type == FLUID_DOMAIN_TYPE_GAS)) {
+ return;
+ }
/* Don't show smoke before simulation starts, this could be made an option in the future. */
+ /* (sebbas): Always show smoke for manta */
+#if 0
+ const DRWContextState *draw_ctx = DRW_context_state_get();
const bool show_smoke = ((int)DEG_get_ctime(draw_ctx->depsgraph) >=
- sds->point_cache[0]->startframe);
+ *mds->point_cache[0]->startframe);
+#endif
- if (sds->fluid && show_smoke) {
- const bool show_highres = BKE_smoke_show_highres(scene, sds);
- if (!sds->wt || !show_highres) {
- GPU_create_smoke(smd, 0);
+ if (mds->fluid && (mds->type == FLUID_DOMAIN_TYPE_GAS) /* && show_smoke */) {
+ if (!(mds->flags & FLUID_DOMAIN_USE_NOISE)) {
+ GPU_create_smoke(mmd, 0);
}
- else if (sds->wt && show_highres) {
- GPU_create_smoke(smd, 1);
+ else if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ GPU_create_smoke(mmd, 1);
}
- BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd));
+ BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(mmd));
}
DRW_shgroup_uniform_texture_ref(
- grp, "sampdensity", sds->tex ? &sds->tex : &e_data.dummy_density);
+ grp, "sampdensity", mds->tex ? &mds->tex : &e_data.dummy_density);
DRW_shgroup_uniform_texture_ref(
- grp, "sampflame", sds->tex_flame ? &sds->tex_flame : &e_data.dummy_flame);
+ grp, "sampflame", mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame);
/* Constant Volume color. */
- bool use_constant_color = ((sds->active_fields & SM_ACTIVE_COLORS) == 0 &&
- (sds->active_fields & SM_ACTIVE_COLOR_SET) != 0);
+ bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
+ (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
DRW_shgroup_uniform_vec3(
- grp, "volumeColor", (use_constant_color) ? sds->active_color : white, 1);
+ grp, "volumeColor", (use_constant_color) ? mds->active_color : white, 1);
/* Output is such that 0..1 maps to 0..1000K */
- DRW_shgroup_uniform_vec2(grp, "unftemperature", &sds->flame_ignition, 1);
+ DRW_shgroup_uniform_vec2(grp, "unftemperature", &mds->flame_ignition, 1);
}
else {
DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density);
@@ -692,8 +699,8 @@ void EEVEE_volumes_free_smoke_textures(void)
{
/* Free Smoke Textures after rendering */
for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) {
- SmokeModifierData *smd = (SmokeModifierData *)link->data;
- GPU_free_smoke(smd);
+ FluidModifierData *mmd = (FluidModifierData *)link->data;
+ GPU_free_smoke(mmd);
}
BLI_freelistN(&e_data.smoke_domains);
}
diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
new file mode 100644
index 00000000000..35bfb411cb9
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
@@ -0,0 +1,64 @@
+#define SCE_PASS_Z (1 << 1)
+#define SCE_PASS_AO (1 << 6)
+#define SCE_PASS_NORMAL (1 << 8)
+#define SCE_PASS_MIST (1 << 14)
+#define SCE_PASS_SUBSURFACE_DIRECT (1 << 28)
+#define SCE_PASS_SUBSURFACE_COLOR (1 << 30)
+
+#define ACCUMULATED_COLOR_PASSES (SCE_PASS_SUBSURFACE_DIRECT | SCE_PASS_SUBSURFACE_COLOR)
+#define ACCUMULATED_VALUE_PASSES (SCE_PASS_MIST)
+uniform int renderpassType;
+uniform int currentSample;
+uniform sampler2D inputBuffer;
+
+out vec4 fragColor;
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+
+ if (renderpassType == SCE_PASS_Z) {
+ float depth = texelFetch(depthBuffer, texel, 0).r;
+ if (depth == 1.0f) {
+ depth = 1e10;
+ }
+ else {
+ depth = -get_view_z_from_depth(depth);
+ }
+ fragColor.r = depth;
+ }
+
+ else if (renderpassType == SCE_PASS_AO) {
+ float ao_accum = texelFetch(inputBuffer, texel, 0).r;
+ fragColor = vec4(vec3(min(1.0, ao_accum / currentSample)), 1.0);
+ }
+
+ else if (renderpassType == SCE_PASS_NORMAL) {
+ float depth = texelFetch(depthBuffer, texel, 0).r;
+ vec2 encoded_normal = texelFetch(inputBuffer, texel, 0).rg;
+ /* decode the normals only when they are valid. otherwise the result buffer will be filled with
+ * NaN's */
+ if (depth != 1.0 && any(notEqual(encoded_normal, vec2(0.0)))) {
+ vec3 decoded_normal = normal_decode(texelFetch(inputBuffer, texel, 0).rg, vec3(0.0));
+ vec3 world_normal = mat3(ViewMatrixInverse) * decoded_normal;
+ fragColor = vec4(world_normal, 1.0);
+ }
+ else {
+ fragColor = vec4(0.0, 0.0, 0.0, 1.0);
+ }
+ }
+
+ else if ((renderpassType & ACCUMULATED_VALUE_PASSES) != 0) {
+ float accumulated_value = texelFetch(inputBuffer, texel, 0).r;
+ fragColor = vec4(vec3(accumulated_value / currentSample), 1.0);
+ }
+
+ else if ((renderpassType & ACCUMULATED_COLOR_PASSES) != 0) {
+ vec3 accumulated_color = texelFetch(inputBuffer, texel, 0).rgb;
+ fragColor = vec4(accumulated_color / currentSample, 1.0);
+ }
+
+ else {
+ fragColor = vec4(1.0, 0.0, 1.0, 1.0);
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
index 8006c784190..cfd99b0bdfc 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
@@ -338,7 +338,7 @@ void gpencil_get_fill_geom(struct GpencilBatchCacheElem *be,
/* Calculate triangles cache for filling area (must be done only after changes) */
if ((gps->flag & GP_STROKE_RECALC_GEOMETRY) || (gps->tot_triangles == 0) ||
(gps->triangles == NULL)) {
- gpencil_triangulate_stroke_fill(ob, gps);
+ BKE_gpencil_triangulate_stroke_fill((bGPdata *)ob->data, gps);
}
BLI_assert(gps->tot_triangles >= 1);
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index 48912a914dc..4c6ce896ebc 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -20,8 +20,6 @@
* \ingroup draw
*/
-#include "BLI_polyfill_2d.h"
-
#include "DRW_render.h"
#include "BKE_gpencil.h"
@@ -284,58 +282,6 @@ static bool gpencil_can_draw_stroke(struct MaterialGPencilStyle *gp_style,
return true;
}
-/* calc bounding box in 2d using flat projection data */
-static void gpencil_calc_2d_bounding_box(const float (*points2d)[2],
- int totpoints,
- float minv[2],
- float maxv[2])
-{
- minv[0] = points2d[0][0];
- minv[1] = points2d[0][1];
- maxv[0] = points2d[0][0];
- maxv[1] = points2d[0][1];
-
- for (int i = 1; i < totpoints; i++) {
- /* min */
- if (points2d[i][0] < minv[0]) {
- minv[0] = points2d[i][0];
- }
- if (points2d[i][1] < minv[1]) {
- minv[1] = points2d[i][1];
- }
- /* max */
- if (points2d[i][0] > maxv[0]) {
- maxv[0] = points2d[i][0];
- }
- if (points2d[i][1] > maxv[1]) {
- maxv[1] = points2d[i][1];
- }
- }
- /* use a perfect square */
- if (maxv[0] > maxv[1]) {
- maxv[1] = maxv[0];
- }
- else {
- maxv[0] = maxv[1];
- }
-}
-
-/* calc texture coordinates using flat projected points */
-static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2],
- int totpoints,
- const float minv[2],
- float maxv[2],
- float (*r_uv)[2])
-{
- float d[2];
- d[0] = maxv[0] - minv[0];
- d[1] = maxv[1] - minv[1];
- for (int i = 0; i < totpoints; i++) {
- r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0];
- r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1];
- }
-}
-
/* recalc the internal geometry caches for fill and uvs */
static void gpencil_recalc_geometry_caches(Object *ob,
bGPDlayer *gpl,
@@ -348,7 +294,7 @@ static void gpencil_recalc_geometry_caches(Object *ob,
if ((gps->totpoints > 2) && (gp_style->flag & GP_STYLE_FILL_SHOW) &&
((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0) ||
(gpl->blend_mode != eGplBlendMode_Regular))) {
- gpencil_triangulate_stroke_fill(ob, gps);
+ BKE_gpencil_triangulate_stroke_fill((bGPdata *)ob->data, gps);
}
}
@@ -1509,84 +1455,6 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
}
}
-/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was
- * modified) */
-void gpencil_triangulate_stroke_fill(Object *ob, bGPDstroke *gps)
-{
- BLI_assert(gps->totpoints >= 3);
-
- bGPdata *gpd = (bGPdata *)ob->data;
-
- /* allocate memory for temporary areas */
- gps->tot_triangles = gps->totpoints - 2;
- uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles,
- "GP Stroke temp triangulation");
- float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints,
- "GP Stroke temp 2d points");
- float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
-
- int direction = 0;
-
- /* convert to 2d and triangulate */
- BKE_gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
- BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
-
- /* calc texture coordinates automatically */
- float minv[2];
- float maxv[2];
- /* first needs bounding box data */
- if (gpd->flag & GP_DATA_UV_ADAPTIVE) {
- gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv);
- }
- else {
- ARRAY_SET_ITEMS(minv, -1.0f, -1.0f);
- ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f);
- }
-
- /* calc uv data */
- gpencil_calc_stroke_fill_uv(points2d, gps->totpoints, minv, maxv, uv);
-
- /* Number of triangles */
- gps->tot_triangles = gps->totpoints - 2;
- /* save triangulation data in stroke cache */
- if (gps->tot_triangles > 0) {
- if (gps->triangles == NULL) {
- gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles,
- "GP Stroke triangulation");
- }
- else {
- gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
- }
-
- for (int i = 0; i < gps->tot_triangles; i++) {
- bGPDtriangle *stroke_triangle = &gps->triangles[i];
- memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3]));
- /* copy texture coordinates */
- copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]);
- copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]);
- copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]);
- }
- }
- else {
- /* No triangles needed - Free anything allocated previously */
- if (gps->triangles) {
- MEM_freeN(gps->triangles);
- }
-
- gps->triangles = NULL;
- }
-
- /* disable recalculation flag */
- if (gps->flag & GP_STROKE_RECALC_GEOMETRY) {
- gps->flag &= ~GP_STROKE_RECALC_GEOMETRY;
- }
-
- /* clear memory */
- MEM_SAFE_FREE(tmp_triangles);
- MEM_SAFE_FREE(points2d);
- MEM_SAFE_FREE(uv);
-}
-
/* Check if stencil is required */
static bool gpencil_is_stencil_required(MaterialGPencilStyle *gp_style)
{
@@ -1816,7 +1684,6 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
for (int i = 0; i < cache->grp_used; i++) {
elm = &cache->grp_cache[i];
array_elm = &cache_ob->shgrp_array[idx];
- const float scale = cache_ob->scale;
/* Limit stencil id */
if (stencil_id > 255) {
@@ -1858,6 +1725,8 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
break;
}
+ const float scale = (!cache_ob->is_dup_ob) ? mat4_to_scale(gpf->runtime.parent_obmat) :
+ cache_ob->scale;
float(*obmat)[4] = (!cache_ob->is_dup_ob) ? gpf->runtime.parent_obmat : cache_ob->obmat;
switch (elm->type) {
case eGpencilBatchGroupType_Stroke: {
@@ -2079,9 +1948,12 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
bGPdata *gpd = (bGPdata *)ob->data;
- const bool main_onion = stl->storage->is_main_onion;
+ /* If render mode, instead to use view switches, test if the datablock has
+ * the onion activated for render. */
+ const bool render_onion = (gpd && gpd->onion_flag & GP_ONION_GHOST_ALWAYS);
+ const bool main_onion = (stl->storage->is_render) ? render_onion : stl->storage->is_main_onion;
+ const bool overlay = (stl->storage->is_render) ? render_onion : stl->storage->is_main_overlay;
const bool playing = stl->storage->is_playing;
- const bool overlay = stl->storage->is_main_overlay;
const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
main_onion && !playing && gpencil_onion_active(gpd);
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 9554e9c0275..a1a1f7cc389 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -33,8 +33,6 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
-#include "draw_mode_engines.h"
-
#include "GPU_texture.h"
#include "gpencil_engine.h"
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 36bc205f41a..b5e7349fb88 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -25,6 +25,8 @@
#include "GPU_batch.h"
+extern DrawEngineType draw_engine_gpencil_type;
+
struct GPENCIL_Data;
struct GPENCIL_StorageList;
struct MaterialGPencilStyle;
@@ -415,7 +417,6 @@ void gpencil_populate_multiedit(struct GPENCIL_e_data *e_data,
void *vedata,
struct Object *ob,
struct tGPencilObjectCache *cache_ob);
-void gpencil_triangulate_stroke_fill(struct Object *ob, struct bGPDstroke *gps);
void gpencil_populate_particles(struct GPENCIL_e_data *e_data,
struct GHash *gh_objects,
void *vedata);
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 81e48eb05f2..8c126310ea2 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -29,8 +29,6 @@
#include "DEG_depsgraph_query.h"
-#include "draw_mode_engines.h"
-
#include "RE_pipeline.h"
#include "gpencil_engine.h"
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
index 0c290260b20..8285541e0b4 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
@@ -51,6 +51,7 @@ uniform float fade_ob_factor;
#define V3D_SHADING_MATERIAL_COLOR 0
#define V3D_SHADING_TEXTURE_COLOR 3
+#define V3D_SHADING_VERTEX_COLOR 5
in vec4 finalColor;
in vec2 texCoord_interp;
@@ -210,7 +211,8 @@ void main()
/* for solid override color */
if (shading_type[0] == OB_SOLID) {
if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) &&
- (shading_type[1] != V3D_SHADING_TEXTURE_COLOR)) {
+ (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) &&
+ (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) {
fragColor = wire_color;
}
if (viewport_xray == 1) {
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
index 87963c66858..33d7d714231 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
@@ -26,6 +26,7 @@ out vec4 finalprev_pos;
#define V3D_SHADING_MATERIAL_COLOR 0
#define V3D_SHADING_TEXTURE_COLOR 3
+#define V3D_SHADING_VERTEX_COLOR 5
float defaultpixsize = pixsize * (1000.0 / pixfactor);
@@ -52,7 +53,8 @@ void main()
/* for solid override color */
if (shading_type[0] == OB_SOLID) {
if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) &&
- (shading_type[1] != V3D_SHADING_TEXTURE_COLOR)) {
+ (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) &&
+ (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) {
finalColor = wire_color;
}
if (viewport_xray == 1) {
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
index 582b9a7f249..8df08f0bf68 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
@@ -24,6 +24,7 @@ out vec2 finaluvdata;
#define V3D_SHADING_MATERIAL_COLOR 0
#define V3D_SHADING_TEXTURE_COLOR 3
+#define V3D_SHADING_VERTEX_COLOR 5
float defaultpixsize = pixsize * (1000.0 / pixfactor);
@@ -49,7 +50,8 @@ void main(void)
/* for solid override color */
if (shading_type[0] == OB_SOLID) {
if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) &&
- (shading_type[1] != V3D_SHADING_TEXTURE_COLOR)) {
+ (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) &&
+ (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) {
finalColor = wire_color;
}
if (viewport_xray == 1) {
diff --git a/source/blender/draw/engines/overlay/overlay_antialiasing.c b/source/blender/draw/engines/overlay/overlay_antialiasing.c
new file mode 100644
index 00000000000..751c6dc7016
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_antialiasing.c
@@ -0,0 +1,202 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Overlay antialiasing:
+ *
+ * Most of the overlays are wires which causes a lot of flickering in motions
+ * due to aliasing problems.
+ *
+ * Our goal is to have a technique that works with single sample per pixel
+ * to avoid extra cost of managing MSAA or additional texture buffers and jitters.
+ *
+ * To solve this we use a simple and effective post-process AA. The technique
+ * goes like this:
+ *
+ * - During wireframe rendering, we output the line color, the line direction
+ * and the distance from the line for the pixel center.
+ *
+ * - Then, in a post process pass, for each pixels we gather all lines in a search area
+ * that could cover (even partially) the center pixel.
+ * We compute the coverage of each line and do a sorted alpha compositing of them.
+ *
+ * This technique has one major shortcoming compared to MSAA:
+ * - It handles (initial) partial visibility poorly (because of single sample). This makes
+ * overlapping / crossing wires a bit too thin at their intersection.
+ * Wireframe meshes overlaid over solid meshes can have half of the edge missing due to
+ * z-fighting (this has workaround).
+ * Another manifestation of this, is flickering of really dense wireframe if using small
+ * line thickness (also has workaround).
+ *
+ * The pros of this approach are many:
+ * - Works without geometry shader.
+ * - Can inflate line thickness.
+ * - Coverage is very close to perfect and can even be filtered (Blackman-Harris, gaussian).
+ * - Wires can "bleed" / overlap non-line objects since the filter is in screenspace.
+ * - Only uses one additional lightweight fullscreen buffer (compared to MSAA/SMAA).
+ * - No convergence time (compared to TAA).
+ */
+
+#include "DRW_render.h"
+
+#include "ED_screen.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_antialiasing_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ /* Small texture which will have very small impact on rendertime. */
+ DRW_texture_ensure_2d(&txl->dummy_depth_tx, 1, 1, GPU_DEPTH_COMPONENT24, 0);
+
+ if (!DRW_state_is_fbo()) {
+ pd->antialiasing.enabled = false;
+ return;
+ }
+
+ bool need_wire_expansion = (G_draw.block.sizePixel > 1.0f);
+ pd->antialiasing.enabled = need_wire_expansion ||
+ ((U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) > 0);
+
+ GPUTexture *color_tex = NULL;
+ GPUTexture *line_tex = NULL;
+
+ if (pd->antialiasing.enabled) {
+ DRW_texture_ensure_fullscreen_2d(&txl->overlay_color_tx, GPU_RGBA8, DRW_TEX_FILTER);
+ DRW_texture_ensure_fullscreen_2d(&txl->overlay_line_tx, GPU_RGBA8, 0);
+
+ color_tex = txl->overlay_color_tx;
+ line_tex = txl->overlay_line_tx;
+ }
+ else {
+ /* Just a copy of the defaults framebuffers. */
+ color_tex = dtxl->color;
+ }
+
+ GPU_framebuffer_ensure_config(&fbl->overlay_color_only_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(color_tex),
+ });
+ GPU_framebuffer_ensure_config(&fbl->overlay_default_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(color_tex),
+ });
+ GPU_framebuffer_ensure_config(&fbl->overlay_line_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(color_tex),
+ GPU_ATTACHMENT_TEXTURE(line_tex),
+ });
+}
+
+void OVERLAY_antialiasing_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_PassList *psl = vedata->psl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ if (pd->antialiasing.enabled) {
+ /* `antialiasing.enabled` is also enabled for wire expansion. Check here if
+ * anti aliasing is needed. */
+ const bool do_smooth_lines = (U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) > 0;
+
+ DRW_PASS_CREATE(psl->antialiasing_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL);
+
+ sh = OVERLAY_shader_antialiasing();
+ grp = DRW_shgroup_create(sh, psl->antialiasing_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "doSmoothLines", do_smooth_lines);
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", &dtxl->depth);
+ DRW_shgroup_uniform_texture_ref(grp, "colorTex", &txl->overlay_color_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "lineTex", &txl->overlay_line_tx);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+void OVERLAY_antialiasing_cache_finish(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ if (pd->antialiasing.enabled) {
+ GPU_framebuffer_ensure_config(&fbl->overlay_in_front_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx)});
+
+ GPU_framebuffer_ensure_config(&fbl->overlay_line_in_front_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)});
+ }
+ else {
+ GPU_framebuffer_ensure_config(
+ &fbl->overlay_in_front_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+
+ GPU_framebuffer_ensure_config(&fbl->overlay_line_in_front_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(dtxl->color),
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)});
+ }
+}
+
+void OVERLAY_antialiasing_start(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ if (pd->antialiasing.enabled) {
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPU_framebuffer_bind(fbl->overlay_line_fb);
+ GPU_framebuffer_clear_color(fbl->overlay_line_fb, clear_col);
+ }
+
+ /* If we are not in solid shading mode, we clear the depth. */
+ if (DRW_state_is_fbo() && pd->clear_in_front) {
+ /* TODO(fclem) This clear should be done in a global place. */
+ GPU_framebuffer_bind(fbl->overlay_in_front_fb);
+ GPU_framebuffer_clear_depth(fbl->overlay_in_front_fb, 1.0f);
+ }
+}
+
+void OVERLAY_antialiasing_end(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (pd->antialiasing.enabled) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->antialiasing_ps);
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
new file mode 100644
index 00000000000..0b77fcad265
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -0,0 +1,2357 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_object_types.h"
+
+#include "DRW_render.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_armature.h"
+#include "BKE_modifier.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_armature.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+
+#include "draw_common.h"
+#include "draw_manager_text.h"
+
+#include "overlay_private.h"
+
+#define BONE_VAR(eBone, pchan, var) ((eBone) ? (eBone->var) : (pchan->var))
+#define BONE_FLAG(eBone, pchan) ((eBone) ? (eBone->flag) : (pchan->bone->flag))
+
+#define PT_DEFAULT_RAD 0.05f /* radius of the point batch. */
+
+typedef struct ArmatureDrawContext {
+ /* Current armature object */
+ Object *ob;
+ /* bArmature *arm; */ /* TODO */
+
+ union {
+ struct {
+ DRWCallBuffer *outline;
+ DRWCallBuffer *solid;
+ DRWCallBuffer *wire;
+ };
+ struct {
+ DRWCallBuffer *envelope_outline;
+ DRWCallBuffer *envelope_solid;
+ DRWCallBuffer *envelope_distance;
+ };
+ struct {
+ DRWCallBuffer *stick;
+ };
+ };
+
+ DRWCallBuffer *dof_lines;
+ DRWCallBuffer *dof_sphere;
+ DRWCallBuffer *point_solid;
+ DRWCallBuffer *point_outline;
+ DRWShadingGroup *custom_solid;
+ DRWShadingGroup *custom_outline;
+ DRWShadingGroup *custom_wire;
+ GHash *custom_shapes_ghash;
+
+ OVERLAY_ExtraCallBuffers *extras;
+
+ /**
+ * Follow `TH_*` naming except for mixed colors.
+ */
+ struct {
+ float select[4];
+ float edge_select[4];
+ float bone_select[4]; /* tint */
+ float wire[4];
+ float wire_edit[4];
+ float bone_solid[4];
+ float bone_active_unselect[4]; /* mix */
+ float bone_pose[4];
+ float bone_pose_active[4];
+ float bone_pose_active_unselect[4]; /* mix */
+ float text_hi[4];
+ float text[4];
+ float vertex_select[4];
+ float vertex[4];
+ } color;
+
+ /* not a theme, this is an override */
+ const float *const_color;
+ float const_wire;
+
+ bool do_relations;
+ bool transparent;
+ bool show_relations;
+
+ const ThemeWireColor *bcolor; /* pchan color */
+} ArmatureDrawContext;
+
+/**
+ * Return true if armature should be handled by the pose mode engine.
+ */
+bool OVERLAY_armature_is_pose_mode(Object *ob, const DRWContextState *draw_ctx)
+{
+ Object *active_ob = draw_ctx->obact;
+
+ /* Pose armature is handled by pose mode engine. */
+ if (((ob == active_ob) || (ob->mode & OB_MODE_POSE)) &&
+ ((draw_ctx->object_mode & OB_MODE_POSE) != 0)) {
+ return true;
+ }
+
+ /* Armature parent is also handled by pose mode engine. */
+ if ((active_ob != NULL) && ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) != 0)) {
+ if (ob == draw_ctx->object_pose) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool is_select_mode = DRW_state_is_select();
+ pd->armature.transparent = (draw_ctx->v3d->shading.type == OB_WIRE) ||
+ XRAY_FLAG_ENABLED(draw_ctx->v3d);
+ pd->armature.show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0) &&
+ !is_select_mode;
+ pd->armature.do_pose_fade_geom = (pd->overlay.flag & V3D_OVERLAY_BONE_SELECT) &&
+ ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) &&
+ draw_ctx->object_pose != NULL;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD;
+ DRW_PASS_CREATE(psl->armature_transp_ps, state | pd->clipping_state);
+
+ if (pd->armature.do_pose_fade_geom) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->armature_bone_select_ps, state | pd->clipping_state);
+
+ float alpha = pd->overlay.xray_alpha_bone;
+ struct GPUShader *sh = OVERLAY_shader_uniform_color();
+ DRWShadingGroup *grp;
+
+ pd->armature_bone_select_act_grp = grp = DRW_shgroup_create(sh, psl->armature_bone_select_ps);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){0.0f, 0.0f, 0.0f, alpha});
+
+ pd->armature_bone_select_grp = grp = DRW_shgroup_create(sh, psl->armature_bone_select_ps);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){0.0f, 0.0f, 0.0f, pow(alpha, 4)});
+ }
+
+ for (int i = 0; i < 2; i++) {
+ struct GPUShader *sh;
+ struct GPUVertFormat *format;
+ DRWShadingGroup *grp = NULL;
+
+ OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+ OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[i];
+ DRWPass **p_armature_ps = &psl->armature_ps[i];
+
+ cb->custom_shapes_ghash = BLI_ghash_ptr_new(__func__);
+
+ DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK |
+ (pd->armature.transparent ? DRW_STATE_BLEND_ALPHA : DRW_STATE_WRITE_DEPTH);
+ DRW_PASS_CREATE(*p_armature_ps, state | pd->clipping_state | infront_state);
+
+ DRWPass *armature_ps = *p_armature_ps;
+
+#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
+#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES)
+
+ {
+ format = formats->instance_bone;
+
+ sh = OVERLAY_shader_armature_sphere(false);
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", pd->armature.transparent ? 0.4f : 1.0f);
+ cb->point_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
+
+ sh = OVERLAY_shader_armature_shape(false);
+ cb->custom_solid = grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", pd->armature.transparent ? 0.6f : 1.0f);
+ cb->box_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
+ cb->octa_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
+
+ sh = OVERLAY_shader_armature_sphere(true);
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
+
+ sh = OVERLAY_shader_armature_shape(true);
+ cb->custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
+ cb->octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
+
+ sh = OVERLAY_shader_armature_shape_wire();
+ cb->custom_wire = grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ }
+ {
+ format = formats->instance_extra;
+
+ sh = OVERLAY_shader_armature_degrees_of_freedom();
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
+ cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
+
+ grp = DRW_shgroup_create(sh, psl->armature_transp_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get());
+ }
+ {
+ format = formats->instance_bone_stick;
+
+ sh = OVERLAY_shader_armature_stick();
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get());
+ }
+ {
+ format = formats->instance_bone_envelope;
+
+ sh = OVERLAY_shader_armature_envelope(false);
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "isDistance", false);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", pd->armature.transparent ? 0.6f : 1.0f);
+ cb->envelope_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+
+ format = formats->instance_bone_envelope_outline;
+
+ sh = OVERLAY_shader_armature_envelope(true);
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->envelope_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_outline_get());
+
+ format = formats->instance_bone_envelope_distance;
+
+ sh = OVERLAY_shader_armature_envelope(false);
+ grp = DRW_shgroup_create(sh, psl->armature_transp_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "isDistance", true);
+ DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
+ cb->envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+ }
+ {
+ format = formats->pos_color;
+
+ sh = OVERLAY_shader_armature_wire();
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->wire = BUF_LINE(grp, format);
+ }
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Shader Groups (DRW_shgroup)
+ * \{ */
+
+static void bone_instance_data_set_angle_minmax(BoneInstanceData *data,
+ const float aminx,
+ const float aminz,
+ const float amaxx,
+ const float amaxz)
+{
+ data->amin_a = aminx;
+ data->amin_b = aminz;
+ data->amax_a = amaxx;
+ data->amax_b = amaxz;
+}
+
+/* Encode 2 units float with byte precision into a float. */
+static float encode_2f_to_float(float a, float b)
+{
+ CLAMP(a, 0.0f, 1.0f);
+ CLAMP(b, 0.0f, 2.0f); /* Can go up to 2. Needed for wire size. */
+ return (float)((int)(a * 255) | ((int)(b * 255) << 8));
+}
+
+void OVERLAY_bone_instance_data_set_color_hint(BoneInstanceData *data, const float hint_color[4])
+{
+ /* Encoded color into 2 floats to be able to use the obmat to color the custom bones. */
+ data->color_hint_a = encode_2f_to_float(hint_color[0], hint_color[1]);
+ data->color_hint_b = encode_2f_to_float(hint_color[2], hint_color[3]);
+}
+
+void OVERLAY_bone_instance_data_set_color(BoneInstanceData *data, const float bone_color[4])
+{
+ /* Encoded color into 2 floats to be able to use the obmat to color the custom bones. */
+ data->color_a = encode_2f_to_float(bone_color[0], bone_color[1]);
+ data->color_b = encode_2f_to_float(bone_color[2], bone_color[3]);
+}
+
+/* Octahedral */
+static void drw_shgroup_bone_octahedral(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float bone_color[4],
+ const float hint_color[4],
+ const float outline_color[4])
+{
+ BoneInstanceData inst_data;
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+ if (ctx->solid) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+ DRW_buffer_add_entry_struct(ctx->solid, &inst_data);
+ }
+ if (outline_color[3] > 0.0f) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+ DRW_buffer_add_entry_struct(ctx->outline, &inst_data);
+ }
+}
+
+/* Box / B-Bone */
+static void drw_shgroup_bone_box(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float bone_color[4],
+ const float hint_color[4],
+ const float outline_color[4])
+{
+ BoneInstanceData inst_data;
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+ if (ctx->solid) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+ DRW_buffer_add_entry_struct(ctx->solid, &inst_data);
+ }
+ if (outline_color[3] > 0.0f) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+ DRW_buffer_add_entry_struct(ctx->outline, &inst_data);
+ }
+}
+
+/* Wire */
+static void drw_shgroup_bone_wire(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float color[4])
+{
+ float head[3], tail[3];
+ mul_v3_m4v3(head, ctx->ob->obmat, bone_mat[3]);
+ add_v3_v3v3(tail, bone_mat[3], bone_mat[1]);
+ mul_m4_v3(ctx->ob->obmat, tail);
+
+ DRW_buffer_add_entry(ctx->wire, head, color);
+ DRW_buffer_add_entry(ctx->wire, tail, color);
+}
+
+/* Stick */
+static void drw_shgroup_bone_stick(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float col_wire[4],
+ const float col_bone[4],
+ const float col_head[4],
+ const float col_tail[4])
+{
+ float head[3], tail[3];
+ mul_v3_m4v3(head, ctx->ob->obmat, bone_mat[3]);
+ add_v3_v3v3(tail, bone_mat[3], bone_mat[1]);
+ mul_m4_v3(ctx->ob->obmat, tail);
+
+ DRW_buffer_add_entry(ctx->stick, head, tail, col_wire, col_bone, col_head, col_tail);
+}
+
+/* Envelope */
+static void drw_shgroup_bone_envelope_distance(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float *radius_head,
+ const float *radius_tail,
+ const float *distance)
+{
+ if (ctx->envelope_distance) {
+ float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ /* Still less operation than m4 multiplication. */
+ mul_m4_v4(bone_mat, head_sph);
+ mul_m4_v4(bone_mat, tail_sph);
+ mul_m4_v4(bone_mat, xaxis);
+ mul_m4_v4(ctx->ob->obmat, head_sph);
+ mul_m4_v4(ctx->ob->obmat, tail_sph);
+ mul_m4_v4(ctx->ob->obmat, xaxis);
+ sub_v3_v3(xaxis, head_sph);
+ head_sph[3] = *radius_head;
+ head_sph[3] += *distance;
+ tail_sph[3] = *radius_tail;
+ tail_sph[3] += *distance;
+ DRW_buffer_add_entry(ctx->envelope_distance, head_sph, tail_sph, xaxis);
+ }
+}
+
+static void drw_shgroup_bone_envelope(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float bone_col[4],
+ const float hint_col[4],
+ const float outline_col[4],
+ const float *radius_head,
+ const float *radius_tail)
+{
+ float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ /* Still less operation than m4 multiplication. */
+ mul_m4_v4(bone_mat, head_sph);
+ mul_m4_v4(bone_mat, tail_sph);
+ mul_m4_v4(bone_mat, xaxis);
+ mul_m4_v4(ctx->ob->obmat, head_sph);
+ mul_m4_v4(ctx->ob->obmat, tail_sph);
+ mul_m4_v4(ctx->ob->obmat, xaxis);
+ head_sph[3] = *radius_head;
+ tail_sph[3] = *radius_tail;
+
+ if (head_sph[3] < 0.0f || tail_sph[3] < 0.0f) {
+ BoneInstanceData inst_data;
+ if (head_sph[3] < 0.0f) {
+ /* Draw Tail only */
+ scale_m4_fl(inst_data.mat, tail_sph[3] / PT_DEFAULT_RAD);
+ copy_v3_v3(inst_data.mat[3], tail_sph);
+ }
+ else {
+ /* Draw Head only */
+ scale_m4_fl(inst_data.mat, head_sph[3] / PT_DEFAULT_RAD);
+ copy_v3_v3(inst_data.mat[3], head_sph);
+ }
+
+ if (ctx->point_solid) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_col);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_col);
+ DRW_buffer_add_entry_struct(ctx->point_solid, &inst_data);
+ }
+ if (outline_col[3] > 0.0f) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_col);
+ DRW_buffer_add_entry_struct(ctx->point_outline, &inst_data);
+ }
+ }
+ else {
+ /* Draw Body */
+ float tmp_sph[4];
+ float len = len_v3v3(tail_sph, head_sph);
+ float fac_head = (len - head_sph[3]) / len;
+ float fac_tail = (len - tail_sph[3]) / len;
+ /* Small epsilon to avoid problem with float precision in shader. */
+ if (len > (tail_sph[3] + head_sph[3]) + 1e-8f) {
+ copy_v4_v4(tmp_sph, head_sph);
+ interp_v4_v4v4(head_sph, tail_sph, head_sph, fac_head);
+ interp_v4_v4v4(tail_sph, tmp_sph, tail_sph, fac_tail);
+ if (ctx->envelope_solid) {
+ DRW_buffer_add_entry(ctx->envelope_solid, head_sph, tail_sph, bone_col, hint_col, xaxis);
+ }
+ if (outline_col[3] > 0.0f) {
+ DRW_buffer_add_entry(ctx->envelope_outline, head_sph, tail_sph, outline_col, xaxis);
+ }
+ }
+ else {
+ /* Distance between endpoints is too small for a capsule. Draw a Sphere instead. */
+ float fac = max_ff(fac_head, 1.0f - fac_tail);
+ interp_v4_v4v4(tmp_sph, tail_sph, head_sph, clamp_f(fac, 0.0f, 1.0f));
+
+ BoneInstanceData inst_data;
+ scale_m4_fl(inst_data.mat, tmp_sph[3] / PT_DEFAULT_RAD);
+ copy_v3_v3(inst_data.mat[3], tmp_sph);
+ if (ctx->point_solid) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_col);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_col);
+ DRW_buffer_add_entry_struct(ctx->point_solid, &inst_data);
+ }
+ if (outline_col[3] > 0.0f) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_col);
+ DRW_buffer_add_entry_struct(ctx->point_outline, &inst_data);
+ }
+ }
+ }
+}
+
+/* Custom (geometry) */
+
+extern void drw_batch_cache_validate(Object *custom);
+extern void drw_batch_cache_generate_requested(Object *custom);
+
+BLI_INLINE DRWCallBuffer *custom_bone_instance_shgroup(ArmatureDrawContext *ctx,
+ DRWShadingGroup *grp,
+ struct GPUBatch *custom_geom)
+{
+ DRWCallBuffer *buf = BLI_ghash_lookup(ctx->custom_shapes_ghash, custom_geom);
+ if (buf == NULL) {
+ OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+ buf = DRW_shgroup_call_buffer_instance(grp, formats->instance_bone, custom_geom);
+ BLI_ghash_insert(ctx->custom_shapes_ghash, custom_geom, buf);
+ }
+ return buf;
+}
+
+static void drw_shgroup_bone_custom_solid(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float bone_color[4],
+ const float hint_color[4],
+ const float outline_color[4],
+ Object *custom)
+{
+ /* TODO(fclem) arg... less than ideal but we never iter on this object
+ * to assure batch cache is valid. */
+ drw_batch_cache_validate(custom);
+
+ struct GPUBatch *surf = DRW_cache_object_surface_get(custom);
+ struct GPUBatch *edges = DRW_cache_object_edge_detection_get(custom, NULL);
+ struct GPUBatch *ledges = DRW_cache_object_loose_edges_get(custom);
+ BoneInstanceData inst_data;
+ DRWCallBuffer *buf;
+
+ if (surf || edges || ledges) {
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+ }
+
+ if (surf && ctx->custom_solid) {
+ buf = custom_bone_instance_shgroup(ctx, ctx->custom_solid, surf);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+ DRW_buffer_add_entry_struct(buf, inst_data.mat);
+ }
+
+ if (edges && ctx->custom_outline) {
+ buf = custom_bone_instance_shgroup(ctx, ctx->custom_outline, edges);
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+ DRW_buffer_add_entry_struct(buf, inst_data.mat);
+ }
+
+ if (ledges) {
+ buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, ledges);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, outline_color);
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+ DRW_buffer_add_entry_struct(buf, inst_data.mat);
+ }
+
+ /* TODO(fclem) needs to be moved elsewhere. */
+ drw_batch_cache_generate_requested(custom);
+}
+
+static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float color[4],
+ Object *custom)
+{
+ /* TODO(fclem) arg... less than ideal but we never iter on this object
+ * to assure batch cache is valid. */
+ drw_batch_cache_validate(custom);
+
+ struct GPUBatch *geom = DRW_cache_object_all_edges_get(custom);
+
+ if (geom) {
+ DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, geom);
+ BoneInstanceData inst_data;
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, color);
+ OVERLAY_bone_instance_data_set_color(&inst_data, color);
+ DRW_buffer_add_entry_struct(buf, inst_data.mat);
+ }
+
+ /* TODO(fclem) needs to be moved elsewhere. */
+ drw_batch_cache_generate_requested(custom);
+}
+
+static void drw_shgroup_bone_custom_empty(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float color[4],
+ Object *custom)
+{
+ float final_color[4] = {color[0], color[1], color[2], 1.0f};
+ float mat[4][4];
+ mul_m4_m4m4(mat, ctx->ob->obmat, bone_mat);
+
+ switch (custom->empty_drawtype) {
+ case OB_PLAINAXES:
+ case OB_SINGLE_ARROW:
+ case OB_CUBE:
+ case OB_CIRCLE:
+ case OB_EMPTY_SPHERE:
+ case OB_EMPTY_CONE:
+ case OB_ARROWS:
+ OVERLAY_empty_shape(
+ ctx->extras, mat, custom->empty_drawsize, custom->empty_drawtype, final_color);
+ break;
+ case OB_EMPTY_IMAGE:
+ break;
+ }
+}
+
+/* Head and tail sphere */
+static void drw_shgroup_bone_point(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float bone_color[4],
+ const float hint_color[4],
+ const float outline_color[4])
+{
+ BoneInstanceData inst_data;
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+ if (ctx->point_solid) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+ DRW_buffer_add_entry_struct(ctx->point_solid, &inst_data);
+ }
+ if (outline_color[3] > 0.0f) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+ DRW_buffer_add_entry_struct(ctx->point_outline, &inst_data);
+ }
+}
+
+/* Axes */
+static void drw_shgroup_bone_axes(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float color[4])
+{
+ float mat[4][4];
+ mul_m4_m4m4(mat, ctx->ob->obmat, bone_mat);
+ /* Move to bone tail. */
+ add_v3_v3(mat[3], mat[1]);
+ OVERLAY_empty_shape(ctx->extras, mat, 0.25f, OB_ARROWS, color);
+}
+
+/* Relationship lines */
+static void drw_shgroup_bone_relationship_lines_ex(ArmatureDrawContext *ctx,
+ const float start[3],
+ const float end[3],
+ const float color[4])
+{
+ float s[3], e[3];
+ mul_v3_m4v3(s, ctx->ob->obmat, start);
+ mul_v3_m4v3(e, ctx->ob->obmat, end);
+ /* reverse order to have less stipple overlap */
+ OVERLAY_extra_line_dashed(ctx->extras, s, e, color);
+}
+
+static void drw_shgroup_bone_relationship_lines(ArmatureDrawContext *ctx,
+ const float start[3],
+ const float end[3])
+{
+ drw_shgroup_bone_relationship_lines_ex(ctx, start, end, ctx->color.wire);
+}
+
+static void drw_shgroup_bone_ik_lines(ArmatureDrawContext *ctx,
+ const float start[3],
+ const float end[3])
+{
+ float fcolor[4] = {0.8f, 0.5f, 0.0f, 1.0f}; /* add theme! */
+ drw_shgroup_bone_relationship_lines_ex(ctx, start, end, fcolor);
+}
+
+static void drw_shgroup_bone_ik_no_target_lines(ArmatureDrawContext *ctx,
+ const float start[3],
+ const float end[3])
+{
+ float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */
+ drw_shgroup_bone_relationship_lines_ex(ctx, start, end, fcolor);
+}
+
+static void drw_shgroup_bone_ik_spline_lines(ArmatureDrawContext *ctx,
+ const float start[3],
+ const float end[3])
+{
+ float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */
+ drw_shgroup_bone_relationship_lines_ex(ctx, start, end, fcolor);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing Theme Helpers
+ *
+ * Note, this section is duplicate of code in 'drawarmature.c'.
+ *
+ * \{ */
+
+/* values of colCode for set_pchan_color */
+enum {
+ PCHAN_COLOR_NORMAL = 0, /* normal drawing */
+ PCHAN_COLOR_SOLID, /* specific case where "solid" color is needed */
+ PCHAN_COLOR_CONSTS, /* "constraint" colors (which may/may-not be suppressed) */
+
+ PCHAN_COLOR_SPHEREBONE_BASE, /* for the 'stick' of sphere (envelope) bones */
+ PCHAN_COLOR_SPHEREBONE_END, /* for the ends of sphere (envelope) bones */
+ PCHAN_COLOR_LINEBONE, /* for the middle of line-bones */
+};
+
+/* This function sets the color-set for coloring a certain bone */
+static void set_pchan_colorset(ArmatureDrawContext *ctx, Object *ob, bPoseChannel *pchan)
+{
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bActionGroup *grp = NULL;
+ short color_index = 0;
+
+ /* sanity check */
+ if (ELEM(NULL, ob, arm, pose, pchan)) {
+ ctx->bcolor = NULL;
+ return;
+ }
+
+ /* only try to set custom color if enabled for armature */
+ if (arm->flag & ARM_COL_CUSTOM) {
+ /* currently, a bone can only use a custom color set if it's group (if it has one),
+ * has been set to use one
+ */
+ if (pchan->agrp_index) {
+ grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1));
+ if (grp) {
+ color_index = grp->customCol;
+ }
+ }
+ }
+
+ /* bcolor is a pointer to the color set to use. If NULL, then the default
+ * color set (based on the theme colors for 3d-view) is used.
+ */
+ if (color_index > 0) {
+ bTheme *btheme = UI_GetTheme();
+ ctx->bcolor = &btheme->tarm[(color_index - 1)];
+ }
+ else if (color_index == -1) {
+ /* use the group's own custom color set (grp is always != NULL here) */
+ ctx->bcolor = &grp->cs;
+ }
+ else {
+ ctx->bcolor = NULL;
+ }
+}
+
+/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */
+static void cp_shade_color3ub(uchar cp[3], const int offset)
+{
+ int r, g, b;
+
+ r = offset + (int)cp[0];
+ CLAMP(r, 0, 255);
+ g = offset + (int)cp[1];
+ CLAMP(g, 0, 255);
+ b = offset + (int)cp[2];
+ CLAMP(b, 0, 255);
+
+ cp[0] = r;
+ cp[1] = g;
+ cp[2] = b;
+}
+
+static void cp_shade_color3f(float cp[3], const float offset)
+{
+ add_v3_fl(cp, offset);
+ CLAMP(cp[0], 0, 255);
+ CLAMP(cp[1], 0, 255);
+ CLAMP(cp[2], 0, 255);
+}
+
+/* This function sets the gl-color for coloring a certain bone (based on bcolor) */
+static bool set_pchan_color(const ArmatureDrawContext *ctx,
+ short colCode,
+ const int boneflag,
+ const short constflag,
+ float r_color[4])
+{
+ float *fcolor = r_color;
+ const ThemeWireColor *bcolor = ctx->bcolor;
+
+ switch (colCode) {
+ case PCHAN_COLOR_NORMAL: {
+ if (bcolor) {
+ uchar cp[4] = {255};
+
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3_uchar(cp, bcolor->active);
+ if (!(boneflag & BONE_SELECTED)) {
+ cp_shade_color3ub(cp, -80);
+ }
+ }
+ else if (boneflag & BONE_SELECTED) {
+ copy_v3_v3_uchar(cp, bcolor->select);
+ }
+ else {
+ /* a bit darker than solid */
+ copy_v3_v3_uchar(cp, bcolor->solid);
+ cp_shade_color3ub(cp, -50);
+ }
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) {
+ UI_GetThemeColor4fv(TH_BONE_POSE_ACTIVE, fcolor);
+ }
+ else if (boneflag & BONE_DRAW_ACTIVE) {
+ UI_GetThemeColorBlendShade4fv(TH_WIRE, TH_BONE_POSE, 0.15f, 0, fcolor);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_WIRE, fcolor);
+ }
+ }
+
+ return true;
+ }
+ case PCHAN_COLOR_SOLID: {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+
+ if (bcolor) {
+ float solid_bcolor[3];
+ rgb_uchar_to_float(solid_bcolor, (uchar *)bcolor->solid);
+ interp_v3_v3v3(fcolor, fcolor, solid_bcolor, 1.0f);
+ }
+
+ return true;
+ }
+ case PCHAN_COLOR_CONSTS: {
+ if ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) {
+ uchar cp[4];
+ if (constflag & PCHAN_HAS_TARGET) {
+ rgba_uchar_args_set(cp, 255, 150, 0, 80);
+ }
+ else if (constflag & PCHAN_HAS_IK) {
+ rgba_uchar_args_set(cp, 255, 255, 0, 80);
+ }
+ else if (constflag & PCHAN_HAS_SPLINEIK) {
+ rgba_uchar_args_set(cp, 200, 255, 0, 80);
+ }
+ else if (constflag & PCHAN_HAS_CONST) {
+ rgba_uchar_args_set(cp, 0, 255, 120, 80);
+ }
+ else {
+ return false;
+ }
+
+ rgba_uchar_to_float(fcolor, cp);
+
+ return true;
+ }
+ return false;
+ }
+ case PCHAN_COLOR_SPHEREBONE_BASE: {
+ if (bcolor) {
+ uchar cp[4] = {255};
+
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3_uchar(cp, bcolor->active);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ copy_v3_v3_uchar(cp, bcolor->select);
+ }
+ else {
+ copy_v3_v3_uchar(cp, bcolor->solid);
+ }
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ UI_GetThemeColorShade4fv(TH_BONE_POSE, 40, fcolor);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+ }
+ }
+
+ return true;
+ }
+ case PCHAN_COLOR_SPHEREBONE_END: {
+ if (bcolor) {
+ uchar cp[4] = {255};
+
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3_uchar(cp, bcolor->active);
+ cp_shade_color3ub(cp, 10);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ copy_v3_v3_uchar(cp, bcolor->select);
+ cp_shade_color3ub(cp, -30);
+ }
+ else {
+ copy_v3_v3_uchar(cp, bcolor->solid);
+ cp_shade_color3ub(cp, -30);
+ }
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ UI_GetThemeColorShade4fv(TH_BONE_POSE, 10, fcolor);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ UI_GetThemeColorShade4fv(TH_BONE_POSE, -30, fcolor);
+ }
+ else {
+ UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor);
+ }
+ }
+ break;
+ }
+ case PCHAN_COLOR_LINEBONE: {
+ /* inner part in background color or constraint */
+ if ((constflag) && ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS))) {
+ uchar cp[4];
+ if (constflag & PCHAN_HAS_TARGET) {
+ rgba_uchar_args_set(cp, 255, 150, 0, 255);
+ }
+ else if (constflag & PCHAN_HAS_IK) {
+ rgba_uchar_args_set(cp, 255, 255, 0, 255);
+ }
+ else if (constflag & PCHAN_HAS_SPLINEIK) {
+ rgba_uchar_args_set(cp, 200, 255, 0, 255);
+ }
+ else if (constflag & PCHAN_HAS_CONST) {
+ rgba_uchar_args_set(cp, 0, 255, 120, 255);
+ }
+ else if (constflag) {
+ UI_GetThemeColor4ubv(TH_BONE_POSE, cp);
+ } /* PCHAN_HAS_ACTION */
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if (bcolor) {
+ const uchar *cp = bcolor->solid;
+ rgb_uchar_to_float(fcolor, (uchar *)cp);
+ fcolor[3] = 204.f / 255.f;
+ }
+ else {
+ UI_GetThemeColorShade4fv(TH_BACK, -30, fcolor);
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing Color Helpers
+ * \{ */
+
+static const float *get_bone_solid_color(const ArmatureDrawContext *ctx,
+ const EditBone *UNUSED(eBone),
+ const bPoseChannel *pchan,
+ const bArmature *arm,
+ const int boneflag,
+ const short constflag)
+{
+ if (ctx->const_color) {
+ return ctx->color.bone_solid;
+ }
+
+ if (arm->flag & ARM_POSEMODE) {
+ static float disp_color[4];
+ copy_v4_v4(disp_color, pchan->draw_data->solid_color);
+ set_pchan_color(ctx, PCHAN_COLOR_SOLID, boneflag, constflag, disp_color);
+ return disp_color;
+ }
+
+ return ctx->color.bone_solid;
+}
+
+static const float *get_bone_solid_with_consts_color(const ArmatureDrawContext *ctx,
+ const EditBone *eBone,
+ const bPoseChannel *pchan,
+ const bArmature *arm,
+ const int boneflag,
+ const short constflag)
+{
+ if (ctx->const_color) {
+ return ctx->color.bone_solid;
+ }
+
+ const float *col = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+ static float consts_color[4];
+ if ((arm->flag & ARM_POSEMODE) &&
+ set_pchan_color(ctx, PCHAN_COLOR_CONSTS, boneflag, constflag, consts_color)) {
+ interp_v3_v3v3(consts_color, col, consts_color, 0.5f);
+ }
+ else {
+ copy_v4_v4(consts_color, col);
+ }
+ return consts_color;
+}
+
+static float get_bone_wire_thickness(const ArmatureDrawContext *ctx, int boneflag)
+{
+ if (ctx->const_color) {
+ return ctx->const_wire;
+ }
+ else if (boneflag & (BONE_DRAW_ACTIVE | BONE_SELECTED)) {
+ return 2.0f;
+ }
+ else {
+ return 1.0f;
+ }
+}
+
+static const float *get_bone_wire_color(const ArmatureDrawContext *ctx,
+ const EditBone *eBone,
+ const bPoseChannel *pchan,
+ const bArmature *arm,
+ const int boneflag,
+ const short constflag)
+{
+ static float disp_color[4];
+
+ if (ctx->const_color) {
+ copy_v3_v3(disp_color, ctx->const_color);
+ }
+ else if (eBone) {
+ if (boneflag & BONE_SELECTED) {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3(disp_color, ctx->color.edge_select);
+ }
+ else {
+ copy_v3_v3(disp_color, ctx->color.bone_select);
+ }
+ }
+ else {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3(disp_color, ctx->color.bone_active_unselect);
+ }
+ else {
+ copy_v3_v3(disp_color, ctx->color.wire_edit);
+ }
+ }
+ }
+ else if (arm->flag & ARM_POSEMODE) {
+ copy_v4_v4(disp_color, pchan->draw_data->wire_color);
+ set_pchan_color(ctx, PCHAN_COLOR_NORMAL, boneflag, constflag, disp_color);
+ }
+ else {
+ copy_v3_v3(disp_color, ctx->color.vertex);
+ }
+
+ disp_color[3] = get_bone_wire_thickness(ctx, boneflag);
+
+ return disp_color;
+}
+
+#define HINT_MUL 0.5f
+#define HINT_SHADE 0.2f
+
+static void bone_hint_color_shade(float hint_color[4], const float color[4])
+{
+ mul_v3_v3fl(hint_color, color, HINT_MUL);
+ cp_shade_color3f(hint_color, -HINT_SHADE);
+ hint_color[3] = 1.0f;
+}
+
+static const float *get_bone_hint_color(const ArmatureDrawContext *ctx,
+ const EditBone *eBone,
+ const bPoseChannel *pchan,
+ const bArmature *arm,
+ const int boneflag,
+ const short constflag)
+{
+ static float hint_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ if (ctx->const_color) {
+ bone_hint_color_shade(hint_color, ctx->color.bone_solid);
+ }
+ else {
+ const float *wire_color = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ bone_hint_color_shade(hint_color, wire_color);
+ }
+
+ return hint_color;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Helper Utils
+ * \{ */
+
+static void pchan_draw_data_init(bPoseChannel *pchan)
+{
+ if (pchan->draw_data != NULL) {
+ if (pchan->draw_data->bbone_matrix_len != pchan->bone->segments) {
+ MEM_SAFE_FREE(pchan->draw_data);
+ }
+ }
+
+ if (pchan->draw_data == NULL) {
+ pchan->draw_data = MEM_mallocN(
+ sizeof(*pchan->draw_data) + sizeof(Mat4) * pchan->bone->segments, __func__);
+ pchan->draw_data->bbone_matrix_len = pchan->bone->segments;
+ }
+}
+
+static void draw_bone_update_disp_matrix_default(EditBone *eBone, bPoseChannel *pchan)
+{
+ float s[4][4], ebmat[4][4];
+ float length;
+ float(*bone_mat)[4];
+ float(*disp_mat)[4];
+ float(*disp_tail_mat)[4];
+
+ /* TODO : This should be moved to depsgraph or armature refresh
+ * and not be tight to the draw pass creation.
+ * This would refresh armature without invalidating the draw cache */
+ if (pchan) {
+ length = pchan->bone->length;
+ bone_mat = pchan->pose_mat;
+ disp_mat = pchan->disp_mat;
+ disp_tail_mat = pchan->disp_tail_mat;
+ }
+ else {
+ eBone->length = len_v3v3(eBone->tail, eBone->head);
+ ED_armature_ebone_to_mat4(eBone, ebmat);
+
+ length = eBone->length;
+ bone_mat = ebmat;
+ disp_mat = eBone->disp_mat;
+ disp_tail_mat = eBone->disp_tail_mat;
+ }
+
+ scale_m4_fl(s, length);
+ mul_m4_m4m4(disp_mat, bone_mat, s);
+ copy_m4_m4(disp_tail_mat, disp_mat);
+ translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
+}
+
+/* compute connected child pointer for B-Bone drawing */
+static void edbo_compute_bbone_child(bArmature *arm)
+{
+ EditBone *eBone;
+
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ eBone->bbone_child = NULL;
+ }
+
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+ eBone->parent->bbone_child = eBone;
+ }
+ }
+}
+
+/* A version of BKE_pchan_bbone_spline_setup() for previewing editmode curve settings. */
+static void ebone_spline_preview(EditBone *ebone, float result_array[MAX_BBONE_SUBDIV][4][4])
+{
+ BBoneSplineParameters param;
+ EditBone *prev, *next;
+ float imat[4][4], bonemat[4][4];
+ float tmp[3];
+
+ memset(&param, 0, sizeof(param));
+
+ param.segments = ebone->segments;
+ param.length = ebone->length;
+
+ /* Get "next" and "prev" bones - these are used for handle calculations. */
+ if (ebone->bbone_prev_type == BBONE_HANDLE_AUTO) {
+ /* Use connected parent. */
+ if (ebone->flag & BONE_CONNECTED) {
+ prev = ebone->parent;
+ }
+ else {
+ prev = NULL;
+ }
+ }
+ else {
+ prev = ebone->bbone_prev;
+ }
+
+ if (ebone->bbone_next_type == BBONE_HANDLE_AUTO) {
+ /* Use connected child. */
+ next = ebone->bbone_child;
+ }
+ else {
+ next = ebone->bbone_next;
+ }
+
+ /* compute handles from connected bones */
+ if (prev || next) {
+ ED_armature_ebone_to_mat4(ebone, imat);
+ invert_m4(imat);
+
+ if (prev) {
+ param.use_prev = true;
+
+ if (ebone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
+ zero_v3(param.prev_h);
+ }
+ else if (ebone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
+ sub_v3_v3v3(tmp, prev->tail, prev->head);
+ sub_v3_v3v3(tmp, ebone->head, tmp);
+ mul_v3_m4v3(param.prev_h, imat, tmp);
+ }
+ else {
+ param.prev_bbone = (prev->segments > 1);
+
+ mul_v3_m4v3(param.prev_h, imat, prev->head);
+ }
+
+ if (!param.prev_bbone) {
+ ED_armature_ebone_to_mat4(prev, bonemat);
+ mul_m4_m4m4(param.prev_mat, imat, bonemat);
+ }
+ }
+
+ if (next) {
+ param.use_next = true;
+
+ if (ebone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
+ copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
+ }
+ else if (ebone->bbone_next_type == BBONE_HANDLE_TANGENT) {
+ sub_v3_v3v3(tmp, next->tail, next->head);
+ add_v3_v3v3(tmp, ebone->tail, tmp);
+ mul_v3_m4v3(param.next_h, imat, tmp);
+ }
+ else {
+ param.next_bbone = (next->segments > 1);
+
+ mul_v3_m4v3(param.next_h, imat, next->tail);
+ }
+
+ ED_armature_ebone_to_mat4(next, bonemat);
+ mul_m4_m4m4(param.next_mat, imat, bonemat);
+ }
+ }
+
+ param.ease1 = ebone->ease1;
+ param.ease2 = ebone->ease2;
+ param.roll1 = ebone->roll1;
+ param.roll2 = ebone->roll2;
+
+ if (prev && (ebone->flag & BONE_ADD_PARENT_END_ROLL)) {
+ param.roll1 += prev->roll2;
+ }
+
+ param.scale_in_x = ebone->scale_in_x;
+ param.scale_in_y = ebone->scale_in_y;
+
+ param.scale_out_x = ebone->scale_out_x;
+ param.scale_out_y = ebone->scale_out_y;
+
+ param.curve_in_x = ebone->curve_in_x;
+ param.curve_in_y = ebone->curve_in_y;
+
+ param.curve_out_x = ebone->curve_out_x;
+ param.curve_out_y = ebone->curve_out_y;
+
+ ebone->segments = BKE_pchan_bbone_spline_compute(&param, false, (Mat4 *)result_array);
+}
+
+static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pchan)
+{
+ float s[4][4], ebmat[4][4];
+ float length, xwidth, zwidth;
+ float(*bone_mat)[4];
+ short bbone_segments;
+
+ /* TODO : This should be moved to depsgraph or armature refresh
+ * and not be tight to the draw pass creation.
+ * This would refresh armature without invalidating the draw cache */
+ if (pchan) {
+ length = pchan->bone->length;
+ xwidth = pchan->bone->xwidth;
+ zwidth = pchan->bone->zwidth;
+ bone_mat = pchan->pose_mat;
+ bbone_segments = pchan->bone->segments;
+ }
+ else {
+ eBone->length = len_v3v3(eBone->tail, eBone->head);
+ ED_armature_ebone_to_mat4(eBone, ebmat);
+
+ length = eBone->length;
+ xwidth = eBone->xwidth;
+ zwidth = eBone->zwidth;
+ bone_mat = ebmat;
+ bbone_segments = eBone->segments;
+ }
+
+ size_to_mat4(s, (const float[3]){xwidth, length / bbone_segments, zwidth});
+
+ /* Compute BBones segment matrices... */
+ /* Note that we need this even for one-segment bones, because box drawing need specific weirdo
+ * matrix for the box, that we cannot use to draw end points & co. */
+ if (pchan) {
+ Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+ if (bbone_segments > 1) {
+ BKE_pchan_bbone_spline_setup(pchan, false, false, bbones_mat);
+
+ for (int i = bbone_segments; i--; bbones_mat++) {
+ mul_m4_m4m4(bbones_mat->mat, bbones_mat->mat, s);
+ mul_m4_m4m4(bbones_mat->mat, bone_mat, bbones_mat->mat);
+ }
+ }
+ else {
+ mul_m4_m4m4(bbones_mat->mat, bone_mat, s);
+ }
+ }
+ else {
+ float(*bbones_mat)[4][4] = eBone->disp_bbone_mat;
+
+ if (bbone_segments > 1) {
+ ebone_spline_preview(eBone, bbones_mat);
+
+ for (int i = bbone_segments; i--; bbones_mat++) {
+ mul_m4_m4m4(*bbones_mat, *bbones_mat, s);
+ mul_m4_m4m4(*bbones_mat, bone_mat, *bbones_mat);
+ }
+ }
+ else {
+ mul_m4_m4m4(*bbones_mat, bone_mat, s);
+ }
+ }
+
+ /* Grrr... We need default display matrix to draw end points, axes, etc. :( */
+ draw_bone_update_disp_matrix_default(eBone, pchan);
+}
+
+static void draw_bone_update_disp_matrix_custom(bPoseChannel *pchan)
+{
+ float s[4][4];
+ float length;
+ float(*bone_mat)[4];
+ float(*disp_mat)[4];
+ float(*disp_tail_mat)[4];
+
+ /* See TODO above */
+ length = PCHAN_CUSTOM_DRAW_SIZE(pchan);
+ bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
+ disp_mat = pchan->disp_mat;
+ disp_tail_mat = pchan->disp_tail_mat;
+
+ scale_m4_fl(s, length);
+ mul_m4_m4m4(disp_mat, bone_mat, s);
+ copy_m4_m4(disp_tail_mat, disp_mat);
+ translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
+}
+
+static void draw_axes(ArmatureDrawContext *ctx, EditBone *eBone, bPoseChannel *pchan)
+{
+ float final_col[4];
+ const float *col = (ctx->const_color) ?
+ ctx->const_color :
+ (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? ctx->color.text_hi :
+ ctx->color.text;
+ copy_v4_v4(final_col, col);
+ /* Mix with axes color. */
+ final_col[3] = (ctx->const_color) ? 1.0 : (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? 0.3 : 0.8;
+ drw_shgroup_bone_axes(ctx, BONE_VAR(eBone, pchan, disp_mat), final_col);
+}
+
+static void draw_points(ArmatureDrawContext *ctx,
+ const EditBone *eBone,
+ const bPoseChannel *pchan,
+ const bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ float col_solid_root[4], col_solid_tail[4], col_wire_root[4], col_wire_tail[4];
+ float col_hint_root[4], col_hint_tail[4];
+
+ copy_v4_v4(col_solid_root, ctx->color.bone_solid);
+ copy_v4_v4(col_solid_tail, ctx->color.bone_solid);
+ copy_v4_v4(col_wire_root, (ctx->const_color) ? ctx->const_color : ctx->color.vertex);
+ copy_v4_v4(col_wire_tail, (ctx->const_color) ? ctx->const_color : ctx->color.vertex);
+
+ const bool is_envelope_draw = (arm->drawtype == ARM_ENVELOPE);
+ const float envelope_ignore = -1.0f;
+
+ col_wire_tail[3] = col_wire_root[3] = get_bone_wire_thickness(ctx, boneflag);
+
+ /* Edit bone points can be selected */
+ if (eBone) {
+ if (eBone->flag & BONE_ROOTSEL) {
+ copy_v3_v3(col_wire_root, ctx->color.vertex_select);
+ }
+ if (eBone->flag & BONE_TIPSEL) {
+ copy_v3_v3(col_wire_tail, ctx->color.vertex_select);
+ }
+ }
+ else if (arm->flag & ARM_POSEMODE) {
+ const float *solid_color = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *wire_color = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ copy_v4_v4(col_wire_tail, wire_color);
+ copy_v4_v4(col_wire_root, wire_color);
+ copy_v4_v4(col_solid_tail, solid_color);
+ copy_v4_v4(col_solid_root, solid_color);
+ }
+
+ bone_hint_color_shade(col_hint_root, (ctx->const_color) ? col_solid_root : col_wire_root);
+ bone_hint_color_shade(col_hint_tail, (ctx->const_color) ? col_solid_tail : col_wire_tail);
+
+ /* Draw root point if we are not connected to our parent */
+ if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
+ (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_ROOT);
+ }
+
+ if (eBone) {
+ if (is_envelope_draw) {
+ drw_shgroup_bone_envelope(ctx,
+ eBone->disp_mat,
+ col_solid_root,
+ col_hint_root,
+ col_wire_root,
+ &eBone->rad_head,
+ &envelope_ignore);
+ }
+ else {
+ drw_shgroup_bone_point(ctx, eBone->disp_mat, col_solid_root, col_hint_root, col_wire_root);
+ }
+ }
+ else {
+ Bone *bone = pchan->bone;
+ if (is_envelope_draw) {
+ drw_shgroup_bone_envelope(ctx,
+ pchan->disp_mat,
+ col_solid_root,
+ col_hint_root,
+ col_wire_root,
+ &bone->rad_head,
+ &envelope_ignore);
+ }
+ else {
+ drw_shgroup_bone_point(ctx, pchan->disp_mat, col_solid_root, col_hint_root, col_wire_root);
+ }
+ }
+ }
+
+ /* Draw tip point */
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_TIP);
+ }
+
+ if (is_envelope_draw) {
+ const float *rad_tail = eBone ? &eBone->rad_tail : &pchan->bone->rad_tail;
+ drw_shgroup_bone_envelope(ctx,
+ BONE_VAR(eBone, pchan, disp_mat),
+ col_solid_tail,
+ col_hint_tail,
+ col_wire_tail,
+ &envelope_ignore,
+ rad_tail);
+ }
+ else {
+ drw_shgroup_bone_point(
+ ctx, BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail, col_hint_tail, col_wire_tail);
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Bones
+ * \{ */
+
+static void draw_bone_custom_shape(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float(*disp_mat)[4] = pchan->disp_mat;
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ if (pchan->custom->type == OB_EMPTY) {
+ Object *ob = pchan->custom;
+ if (ob->empty_drawtype != OB_EMPTY_IMAGE) {
+ drw_shgroup_bone_custom_empty(ctx, disp_mat, col_wire, pchan->custom);
+ }
+ }
+ if ((boneflag & BONE_DRAWWIRE) == 0) {
+ drw_shgroup_bone_custom_solid(ctx, disp_mat, col_solid, col_hint, col_wire, pchan->custom);
+ }
+ else {
+ drw_shgroup_bone_custom_wire(ctx, disp_mat, col_wire, pchan->custom);
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+}
+
+static void draw_bone_envelope(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_with_consts_color(
+ ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+ float *rad_head, *rad_tail, *distance;
+ if (eBone) {
+ rad_tail = &eBone->rad_tail;
+ distance = &eBone->dist;
+ rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail :
+ &eBone->rad_head;
+ }
+ else {
+ rad_tail = &pchan->bone->rad_tail;
+ distance = &pchan->bone->dist;
+ rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail :
+ &pchan->bone->rad_head;
+ }
+
+ if ((select_id == -1) && (boneflag & BONE_NO_DEFORM) == 0 &&
+ ((boneflag & BONE_SELECTED) || (eBone && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL))))) {
+ drw_shgroup_bone_envelope_distance(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), rad_head, rad_tail, distance);
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ drw_shgroup_bone_envelope(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_solid, col_hint, col_wire, rad_head, rad_tail);
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+}
+
+static void draw_bone_line(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_bone = get_bone_solid_with_consts_color(
+ ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float no_display[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float *col_head = no_display;
+ const float *col_tail = col_bone;
+
+ if (ctx->const_color != NULL) {
+ col_wire = no_display; /* actually shrink the display. */
+ col_bone = col_head = col_tail = ctx->const_color;
+ }
+ else {
+ if (eBone) {
+ if (eBone->flag & BONE_TIPSEL) {
+ col_tail = ctx->color.vertex_select;
+ }
+ if (boneflag & BONE_SELECTED) {
+ col_bone = ctx->color.edge_select;
+ }
+ col_wire = ctx->color.wire;
+ }
+
+ /* Draw root point if we are not connected to our parent. */
+ if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
+ (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
+
+ if (eBone) {
+ col_head = (eBone->flag & BONE_ROOTSEL) ? ctx->color.vertex_select : col_bone;
+ }
+ else {
+ col_head = col_bone;
+ }
+ }
+ }
+
+ if (select_id == -1) {
+ /* Not in selection mode, draw everything at once. */
+ drw_shgroup_bone_stick(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, col_bone, col_head, col_tail);
+ }
+ else {
+ /* In selection mode, draw bone, root and tip separately. */
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ drw_shgroup_bone_stick(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, col_bone, no_display, no_display);
+
+ if (col_head[3] > 0.0f) {
+ DRW_select_load_id(select_id | BONESEL_ROOT);
+ drw_shgroup_bone_stick(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, no_display, col_head, no_display);
+ }
+
+ DRW_select_load_id(select_id | BONESEL_TIP);
+ drw_shgroup_bone_stick(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, no_display, no_display, col_tail);
+
+ DRW_select_load_id(-1);
+ }
+}
+
+static void draw_bone_wire(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ if (pchan) {
+ Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+ BLI_assert(bbones_mat != NULL);
+
+ for (int i = pchan->bone->segments; i--; bbones_mat++) {
+ drw_shgroup_bone_wire(ctx, bbones_mat->mat, col_wire);
+ }
+ }
+ else if (eBone) {
+ for (int i = 0; i < eBone->segments; i++) {
+ drw_shgroup_bone_wire(ctx, eBone->disp_bbone_mat[i], col_wire);
+ }
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ if (eBone) {
+ draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+ }
+}
+
+static void draw_bone_box(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_with_consts_color(
+ ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ if (pchan) {
+ Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+ BLI_assert(bbones_mat != NULL);
+
+ for (int i = pchan->bone->segments; i--; bbones_mat++) {
+ drw_shgroup_bone_box(ctx, bbones_mat->mat, col_solid, col_hint, col_wire);
+ }
+ }
+ else if (eBone) {
+ for (int i = 0; i < eBone->segments; i++) {
+ drw_shgroup_bone_box(ctx, eBone->disp_bbone_mat[i], col_solid, col_hint, col_wire);
+ }
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ if (eBone) {
+ draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+ }
+}
+
+static void draw_bone_octahedral(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_with_consts_color(
+ ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ drw_shgroup_bone_octahedral(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_solid, col_hint, col_wire);
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Degrees of Freedom
+ * \{ */
+
+static void draw_bone_degrees_of_freedom(ArmatureDrawContext *ctx, bPoseChannel *pchan)
+{
+ BoneInstanceData inst_data;
+ float tmp[4][4], posetrans[4][4];
+ float xminmax[2], zminmax[2];
+ float color[4];
+
+ if (ctx->dof_sphere == NULL) {
+ return;
+ }
+
+ /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
+ xminmax[0] = sinf(pchan->limitmin[0] * 0.5f);
+ xminmax[1] = sinf(pchan->limitmax[0] * 0.5f);
+ zminmax[0] = sinf(pchan->limitmin[2] * 0.5f);
+ zminmax[1] = sinf(pchan->limitmax[2] * 0.5f);
+
+ unit_m4(posetrans);
+ translate_m4(posetrans, pchan->pose_mat[3][0], pchan->pose_mat[3][1], pchan->pose_mat[3][2]);
+ /* in parent-bone pose space... */
+ if (pchan->parent) {
+ copy_m4_m4(tmp, pchan->parent->pose_mat);
+ zero_v3(tmp[3]);
+ mul_m4_m4m4(posetrans, posetrans, tmp);
+ }
+ /* ... but own restspace */
+ mul_m4_m4m3(posetrans, posetrans, pchan->bone->bone_mat);
+
+ float scale = pchan->bone->length * pchan->size[1];
+ scale_m4_fl(tmp, scale);
+ tmp[1][1] = -tmp[1][1];
+ mul_m4_m4m4(posetrans, posetrans, tmp);
+
+ /* into world space. */
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, posetrans);
+
+ if ((pchan->ikflag & BONE_IK_XLIMIT) && (pchan->ikflag & BONE_IK_ZLIMIT)) {
+ bone_instance_data_set_angle_minmax(
+ &inst_data, xminmax[0], zminmax[0], xminmax[1], zminmax[1]);
+
+ copy_v4_fl4(color, 0.25f, 0.25f, 0.25f, 0.25f);
+ DRW_buffer_add_entry(ctx->dof_sphere, color, &inst_data);
+
+ copy_v4_fl4(color, 0.0f, 0.0f, 0.0f, 1.0f);
+ DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
+ }
+ if (pchan->ikflag & BONE_IK_XLIMIT) {
+ bone_instance_data_set_angle_minmax(&inst_data, xminmax[0], 0.0f, xminmax[1], 0.0f);
+ copy_v4_fl4(color, 1.0f, 0.0f, 0.0f, 1.0f);
+ DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
+ }
+ if (pchan->ikflag & BONE_IK_ZLIMIT) {
+ bone_instance_data_set_angle_minmax(&inst_data, 0.0f, zminmax[0], 0.0f, zminmax[1]);
+ copy_v4_fl4(color, 0.0f, 0.0f, 1.0f, 1.0f);
+ DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Relationships
+ * \{ */
+
+static void pchan_draw_ik_lines(ArmatureDrawContext *ctx,
+ bPoseChannel *pchan,
+ const bool only_temp,
+ const int constflag)
+{
+ bConstraint *con;
+ bPoseChannel *parchan;
+ float *line_start = NULL, *line_end = NULL;
+
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->enforce == 0.0f) {
+ continue;
+ }
+
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC: {
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+ int segcount = 0;
+
+ /* if only_temp, only draw if it is a temporary ik-chain */
+ if (only_temp && !(data->flag & CONSTRAINT_IK_TEMP)) {
+ continue;
+ }
+
+ /* exclude tip from chain? */
+ parchan = ((data->flag & CONSTRAINT_IK_TIP) == 0) ? pchan->parent : pchan;
+ line_start = parchan->pose_tail;
+
+ /* Find the chain's root */
+ while (parchan->parent) {
+ segcount++;
+ if (segcount == data->rootbone || segcount > 255) {
+ break; /* 255 is weak */
+ }
+ parchan = parchan->parent;
+ }
+
+ if (parchan) {
+ line_end = parchan->pose_head;
+
+ if (constflag & PCHAN_HAS_TARGET) {
+ drw_shgroup_bone_ik_lines(ctx, line_start, line_end);
+ }
+ else {
+ drw_shgroup_bone_ik_no_target_lines(ctx, line_start, line_end);
+ }
+ }
+ break;
+ }
+ case CONSTRAINT_TYPE_SPLINEIK: {
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+ int segcount = 0;
+
+ /* don't draw if only_temp, as Spline IK chains cannot be temporary */
+ if (only_temp) {
+ continue;
+ }
+
+ parchan = pchan;
+ line_start = parchan->pose_tail;
+
+ /* Find the chain's root */
+ while (parchan->parent) {
+ segcount++;
+ /* FIXME: revise the breaking conditions */
+ if (segcount == data->chainlen || segcount > 255) {
+ break; /* 255 is weak */
+ }
+ parchan = parchan->parent;
+ }
+ /* Only draw line in case our chain is more than one bone long! */
+ if (parchan != pchan) { /* XXX revise the breaking conditions to only stop at the tail? */
+ line_end = parchan->pose_head;
+ drw_shgroup_bone_ik_spline_lines(ctx, line_start, line_end);
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void draw_bone_relations(ArmatureDrawContext *ctx,
+ EditBone *ebone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag)
+{
+ if (ebone && ebone->parent) {
+ if (ctx->do_relations) {
+ /* Always draw for unconnected bones, regardless of selection,
+ * since riggers will want to know about the links between bones
+ */
+ if ((boneflag & BONE_CONNECTED) == 0) {
+ drw_shgroup_bone_relationship_lines(ctx, ebone->head, ebone->parent->tail);
+ }
+ }
+ }
+ else if (pchan && pchan->parent) {
+ if (ctx->do_relations) {
+ /* Only draw if bone or its parent is selected - reduces viewport complexity with complex
+ * rigs */
+ if ((boneflag & BONE_SELECTED) ||
+ (pchan->parent->bone && (pchan->parent->bone->flag & BONE_SELECTED))) {
+ if ((boneflag & BONE_CONNECTED) == 0) {
+ drw_shgroup_bone_relationship_lines(ctx, pchan->pose_head, pchan->parent->pose_tail);
+ }
+ }
+ }
+
+ /* Draw a line to IK root bone if bone is selected. */
+ if (arm->flag & ARM_POSEMODE) {
+ if (constflag & (PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK)) {
+ if (boneflag & BONE_SELECTED) {
+ pchan_draw_ik_lines(ctx, pchan, !ctx->do_relations, constflag);
+ }
+ }
+ }
+ }
+}
+
+static void draw_bone_name(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag)
+{
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ uchar color[4];
+ float vec[3];
+
+ bool highlight = (pchan && (arm->flag & ARM_POSEMODE) && (boneflag & BONE_SELECTED)) ||
+ (eBone && (eBone->flag & BONE_SELECTED));
+
+ UI_GetThemeColor4ubv(highlight ? TH_TEXT_HI : TH_TEXT, color);
+
+ float *head = pchan ? pchan->pose_head : eBone->head;
+ float *tail = pchan ? pchan->pose_tail : eBone->tail;
+ mid_v3_v3v3(vec, head, tail);
+ mul_m4_v3(ctx->ob->obmat, vec);
+
+ DRW_text_cache_add(dt,
+ vec,
+ (pchan) ? pchan->name : eBone->name,
+ (pchan) ? strlen(pchan->name) : strlen(eBone->name),
+ 10,
+ 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ color);
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Draw Loops
+ * \{ */
+
+static void draw_armature_edit(ArmatureDrawContext *ctx)
+{
+ Object *ob = ctx->ob;
+ EditBone *eBone;
+ int index;
+ const bool is_select = DRW_state_is_select();
+ const bool show_text = DRW_state_show_text();
+
+ const Object *ob_orig = DEG_get_original_object(ob);
+ /* FIXME(campbell): We should be able to use the CoW object,
+ * however the active bone isn't updated. Long term solution is an 'EditArmature' struct.
+ * for now we can draw from the original armature. See: T66773. */
+ // bArmature *arm = ob->data;
+ bArmature *arm = ob_orig->data;
+
+ edbo_compute_bbone_child(arm);
+
+ for (eBone = arm->edbo->first, index = ob_orig->runtime.select_id; eBone;
+ eBone = eBone->next, index += 0x10000) {
+ if (eBone->layer & arm->layer) {
+ if ((eBone->flag & BONE_HIDDEN_A) == 0) {
+ const int select_id = is_select ? index : (uint)-1;
+ const short constflag = 0;
+
+ /* catch exception for bone with hidden parent */
+ int boneflag = eBone->flag;
+ if ((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent)) {
+ boneflag &= ~BONE_CONNECTED;
+ }
+
+ /* set temporary flag for drawing bone as active, but only if selected */
+ if (eBone == arm->act_edbone) {
+ boneflag |= BONE_DRAW_ACTIVE;
+ }
+
+ draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag);
+
+ if (arm->drawtype == ARM_ENVELOPE) {
+ draw_bone_update_disp_matrix_default(eBone, NULL);
+ draw_bone_envelope(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_LINE) {
+ draw_bone_update_disp_matrix_default(eBone, NULL);
+ draw_bone_line(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_WIRE) {
+ draw_bone_update_disp_matrix_bbone(eBone, NULL);
+ draw_bone_wire(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_B_BONE) {
+ draw_bone_update_disp_matrix_bbone(eBone, NULL);
+ draw_bone_box(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else {
+ draw_bone_update_disp_matrix_default(eBone, NULL);
+ draw_bone_octahedral(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+
+ if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+ draw_bone_name(ctx, eBone, NULL, arm, boneflag);
+ }
+
+ if (arm->flag & ARM_DRAWAXES) {
+ draw_axes(ctx, eBone, NULL);
+ }
+ }
+ }
+ }
+}
+
+static void draw_armature_pose(ArmatureDrawContext *ctx)
+{
+ Object *ob = ctx->ob;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+ int index = -1;
+ const bool show_text = DRW_state_show_text();
+
+ /* We can't safely draw non-updated pose, might contain NULL bone pointers... */
+ if (ob->pose->flag & POSE_RECALC) {
+ return;
+ }
+
+ bool is_pose_select = false;
+ /* Object can be edited in the scene. */
+ if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
+ if ((draw_ctx->object_mode & OB_MODE_POSE) || (ob == draw_ctx->object_pose)) {
+ arm->flag |= ARM_POSEMODE;
+ }
+ is_pose_select =
+ /* If we're in pose-mode or object-mode with the ability to enter pose mode. */
+ (
+ /* Draw as if in pose mode (when selection is possible). */
+ (arm->flag & ARM_POSEMODE) ||
+ /* When we're in object mode, which may select bones. */
+ ((ob->mode & OB_MODE_POSE) &&
+ (
+ /* Switch from object mode when object lock is disabled. */
+ ((draw_ctx->object_mode == OB_MODE_OBJECT) &&
+ (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) ||
+ /* Allow selection when in weight-paint mode
+ * (selection code ensures this wont become active). */
+ ((draw_ctx->object_mode == OB_MODE_WEIGHT_PAINT) &&
+ (draw_ctx->object_pose != NULL))))) &&
+ DRW_state_is_select();
+
+ if (is_pose_select) {
+ const Object *ob_orig = DEG_get_original_object(ob);
+ index = ob_orig->runtime.select_id;
+ }
+ }
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, index += 0x10000) {
+ Bone *bone = pchan->bone;
+ const bool bone_visible = (bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0;
+
+ if (bone_visible) {
+ if (bone->layer & arm->layer) {
+ const bool draw_dofs = !is_pose_select && ctx->show_relations &&
+ (arm->flag & ARM_POSEMODE) && (bone->flag & BONE_SELECTED) &&
+ ((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
+ (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT));
+ const int select_id = is_pose_select ? index : (uint)-1;
+ const short constflag = pchan->constflag;
+
+ pchan_draw_data_init(pchan);
+
+ if (!ctx->const_color) {
+ set_pchan_colorset(ctx, ob, pchan);
+ }
+
+ int boneflag = bone->flag;
+ /* catch exception for bone with hidden parent */
+ boneflag = bone->flag;
+ if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
+ boneflag &= ~BONE_CONNECTED;
+ }
+
+ /* set temporary flag for drawing bone as active, but only if selected */
+ if (bone == arm->act_bone) {
+ boneflag |= BONE_DRAW_ACTIVE;
+ }
+
+ draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag);
+
+ if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) {
+ draw_bone_update_disp_matrix_custom(pchan);
+ draw_bone_custom_shape(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_ENVELOPE) {
+ draw_bone_update_disp_matrix_default(NULL, pchan);
+ draw_bone_envelope(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_LINE) {
+ draw_bone_update_disp_matrix_default(NULL, pchan);
+ draw_bone_line(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_WIRE) {
+ draw_bone_update_disp_matrix_bbone(NULL, pchan);
+ draw_bone_wire(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_B_BONE) {
+ draw_bone_update_disp_matrix_bbone(NULL, pchan);
+ draw_bone_box(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else {
+ draw_bone_update_disp_matrix_default(NULL, pchan);
+ draw_bone_octahedral(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+
+ if (draw_dofs) {
+ draw_bone_degrees_of_freedom(ctx, pchan);
+ }
+
+ if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+ draw_bone_name(ctx, NULL, pchan, arm, boneflag);
+ }
+
+ if (arm->flag & ARM_DRAWAXES) {
+ draw_axes(ctx, NULL, pchan);
+ }
+ }
+ }
+ }
+
+ arm->flag &= ~ARM_POSEMODE;
+}
+
+static void armature_context_setup(ArmatureDrawContext *ctx,
+ OVERLAY_PrivateData *pd,
+ Object *ob,
+ const bool do_envelope_dist,
+ const bool is_edit_mode,
+ const bool is_pose_mode,
+ float *const_color)
+{
+ const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0 ||
+ (pd->armature.do_pose_fade_geom && is_pose_mode);
+ const bool is_filled = !pd->armature.transparent || do_envelope_dist;
+ bArmature *arm = ob->data;
+ OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[is_xray];
+
+ static const float select_const_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ switch (arm->drawtype) {
+ case ARM_ENVELOPE:
+ ctx->envelope_outline = cb->envelope_outline;
+ ctx->envelope_solid = (is_filled) ? cb->envelope_solid : NULL;
+ ctx->envelope_distance = (do_envelope_dist) ? cb->envelope_distance : NULL;
+ break;
+ case ARM_LINE:
+ ctx->stick = cb->stick;
+ break;
+ case ARM_WIRE:
+ ctx->wire = cb->wire;
+ break;
+ case ARM_B_BONE:
+ ctx->outline = cb->box_outline;
+ ctx->solid = (is_filled) ? cb->box_solid : NULL;
+ break;
+ case ARM_OCTA:
+ ctx->outline = cb->octa_outline;
+ ctx->solid = (is_filled) ? cb->octa_solid : NULL;
+ break;
+ }
+ ctx->ob = ob;
+ ctx->extras = &pd->extra_call_buffers[is_xray];
+ ctx->dof_lines = cb->dof_lines;
+ ctx->dof_sphere = cb->dof_sphere;
+ ctx->point_solid = (is_filled) ? cb->point_solid : NULL;
+ ctx->point_outline = cb->point_outline;
+ ctx->custom_solid = (is_filled) ? cb->custom_solid : NULL;
+ ctx->custom_outline = cb->custom_outline;
+ ctx->custom_wire = cb->custom_wire;
+ ctx->custom_shapes_ghash = cb->custom_shapes_ghash;
+ ctx->transparent = pd->armature.transparent;
+ ctx->show_relations = pd->armature.show_relations;
+ ctx->do_relations = !DRW_state_is_select() && pd->armature.show_relations &&
+ (is_edit_mode | is_pose_mode);
+ ctx->const_color = DRW_state_is_select() ? select_const_color : const_color;
+ ctx->const_wire = (((ob->base_flag & BASE_SELECTED) || (arm->drawtype == ARM_WIRE)) ?
+ 1.5f :
+ ((ctx->transparent) ? 1.0f : 0.0f));
+
+ /** See: 'set_pchan_color'*/
+#define NO_ALPHA(c) (((c)[3] = 1.0f), (c))
+
+ UI_GetThemeColor3fv(TH_SELECT, NO_ALPHA(ctx->color.select));
+ UI_GetThemeColorShade3fv(TH_EDGE_SELECT, 60, NO_ALPHA(ctx->color.edge_select));
+ UI_GetThemeColorShade3fv(TH_EDGE_SELECT, -20, NO_ALPHA(ctx->color.bone_select));
+ UI_GetThemeColor3fv(TH_WIRE, NO_ALPHA(ctx->color.wire));
+ UI_GetThemeColor3fv(TH_WIRE_EDIT, NO_ALPHA(ctx->color.wire_edit));
+ UI_GetThemeColor3fv(TH_BONE_SOLID, NO_ALPHA(ctx->color.bone_solid));
+ UI_GetThemeColorBlendShade3fv(
+ TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f, 0, NO_ALPHA(ctx->color.bone_active_unselect));
+ UI_GetThemeColor3fv(TH_BONE_POSE, NO_ALPHA(ctx->color.bone_pose));
+ UI_GetThemeColor3fv(TH_BONE_POSE_ACTIVE, NO_ALPHA(ctx->color.bone_pose_active));
+ UI_GetThemeColorBlendShade3fv(
+ TH_WIRE, TH_BONE_POSE, 0.15f, 0, NO_ALPHA(ctx->color.bone_pose_active_unselect));
+ UI_GetThemeColor3fv(TH_TEXT_HI, NO_ALPHA(ctx->color.text_hi));
+ UI_GetThemeColor3fv(TH_TEXT, NO_ALPHA(ctx->color.text));
+ UI_GetThemeColor3fv(TH_VERTEX_SELECT, NO_ALPHA(ctx->color.vertex_select));
+ UI_GetThemeColor3fv(TH_VERTEX, NO_ALPHA(ctx->color.vertex));
+
+#undef NO_ALPHA
+}
+
+void OVERLAY_edit_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ ArmatureDrawContext arm_ctx;
+ armature_context_setup(&arm_ctx, pd, ob, true, true, false, NULL);
+ draw_armature_edit(&arm_ctx);
+}
+
+void OVERLAY_pose_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ ArmatureDrawContext arm_ctx;
+ armature_context_setup(&arm_ctx, pd, ob, true, false, true, NULL);
+ draw_armature_pose(&arm_ctx);
+}
+
+void OVERLAY_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ ArmatureDrawContext arm_ctx;
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+ armature_context_setup(&arm_ctx, pd, ob, false, false, false, color);
+ draw_armature_pose(&arm_ctx);
+}
+
+static bool POSE_is_driven_by_active_armature(Object *ob)
+{
+ Object *ob_arm = modifiers_isDeformedByArmature(ob);
+ if (ob_arm) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ bool is_active = OVERLAY_armature_is_pose_mode(ob_arm, draw_ctx);
+ if (!is_active && ob_arm->proxy_from) {
+ is_active = OVERLAY_armature_is_pose_mode(ob_arm->proxy_from, draw_ctx);
+ }
+ return is_active;
+ }
+ else {
+ Object *ob_mesh_deform = modifiers_isDeformedByMeshDeform(ob);
+ if (ob_mesh_deform) {
+ /* Recursive. */
+ return POSE_is_driven_by_active_armature(ob_mesh_deform);
+ }
+ }
+ return false;
+}
+
+void OVERLAY_pose_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ if (POSE_is_driven_by_active_armature(ob)) {
+ DRW_shgroup_call(pd->armature_bone_select_act_grp, geom, ob);
+ }
+ else {
+ DRW_shgroup_call(pd->armature_bone_select_grp, geom, ob);
+ }
+ }
+}
+
+void OVERLAY_armature_cache_finish(OVERLAY_Data *vedata)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ for (int i = 0; i < 2; i++) {
+ if (pd->armature_call_buffers[i].custom_shapes_ghash) {
+ /* TODO(fclem): Do not free it for each frame but reuse it. Avoiding alloc cost. */
+ BLI_ghash_free(pd->armature_call_buffers[i].custom_shapes_ghash, NULL, NULL);
+ }
+ }
+}
+
+void OVERLAY_armature_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->armature_transp_ps);
+ DRW_draw_pass(psl->armature_ps[0]);
+}
+
+void OVERLAY_armature_in_front_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ if (psl->armature_bone_select_ps == NULL) {
+ DRW_draw_pass(psl->armature_ps[1]);
+ }
+}
+
+void OVERLAY_pose_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+ if (psl->armature_bone_select_ps != NULL) {
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+
+ DRW_draw_pass(psl->armature_bone_select_ps);
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_line_fb);
+ }
+
+ DRW_draw_pass(psl->armature_ps[1]);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_curve.c b/source/blender/draw/engines/overlay/overlay_edit_curve.c
new file mode 100644
index 00000000000..d9b9fac6b4b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_edit_curve.c
@@ -0,0 +1,132 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_curve_types.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ DRWShadingGroup *grp;
+ GPUShader *sh;
+ DRWState state;
+
+ pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+ pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length;
+
+ /* Run Twice for in-front passes. */
+ for (int i = 0; i < 2; i++) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH;
+ state |= ((i == 0) ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_ALWAYS);
+ DRW_PASS_CREATE(psl->edit_curve_wire_ps[i], state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_curve_wire();
+ pd->edit_curve_normal_grp[i] = grp = DRW_shgroup_create(sh, psl->edit_curve_wire_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "normalSize", pd->shdata.edit_curve_normal_length);
+
+ pd->edit_curve_wire_grp[i] = grp = DRW_shgroup_create(sh, psl->edit_curve_wire_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "normalSize", 0.0f);
+ }
+ {
+ state = DRW_STATE_WRITE_COLOR;
+ DRW_PASS_CREATE(psl->edit_curve_handle_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_curve_handle();
+ pd->edit_curve_handle_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+ sh = OVERLAY_shader_edit_curve_point();
+ pd->edit_curve_points_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+}
+
+void OVERLAY_edit_curve_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ bool draw_normals = (pd->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0;
+ bool do_xray = (ob->dtx & OB_DRAWXRAY) != 0;
+
+ Curve *cu = ob->data;
+ struct GPUBatch *geom;
+
+ geom = DRW_cache_curve_edge_wire_get(ob);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_curve_wire_grp[do_xray], geom, ob);
+ }
+
+ if ((cu->flag & CU_3D) && draw_normals) {
+ geom = DRW_cache_curve_edge_normal_get(ob);
+ DRW_shgroup_call_instances(pd->edit_curve_normal_grp[do_xray], ob, geom, 3);
+ }
+
+ geom = DRW_cache_curve_edge_overlay_get(ob);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_curve_handle_grp, geom, ob);
+ }
+
+ geom = DRW_cache_curve_vert_overlay_get(ob, pd->edit_curve.show_handles);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_curve_points_grp, geom, ob);
+ }
+}
+
+void OVERLAY_edit_surf_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUBatch *geom;
+
+ geom = DRW_cache_curve_edge_overlay_get(ob);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_curve_handle_grp, geom, ob);
+ }
+
+ geom = DRW_cache_curve_vert_overlay_get(ob, false);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_curve_points_grp, geom, ob);
+ }
+}
+
+void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+
+ DRW_draw_pass(psl->edit_curve_wire_ps[0]);
+ DRW_draw_pass(psl->edit_curve_wire_ps[1]);
+
+ DRW_draw_pass(psl->edit_curve_handle_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
new file mode 100644
index 00000000000..56fbc3cca01
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
@@ -0,0 +1,412 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "ED_view3d.h"
+
+#include "DNA_mesh_types.h"
+
+#include "BKE_editmesh.h"
+
+#include "draw_cache_impl.h"
+#include "draw_manager_text.h"
+
+#include "overlay_private.h"
+
+#define OVERLAY_EDIT_TEXT \
+ (V3D_OVERLAY_EDIT_EDGE_LEN | V3D_OVERLAY_EDIT_FACE_AREA | V3D_OVERLAY_EDIT_FACE_ANG | \
+ V3D_OVERLAY_EDIT_EDGE_ANG | V3D_OVERLAY_EDIT_INDICES)
+
+void OVERLAY_edit_mesh_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ pd->edit_mesh.do_zbufclip = XRAY_FLAG_ENABLED(draw_ctx->v3d);
+
+ /* Create view with depth offset */
+ DRWView *default_view = (DRWView *)DRW_view_default_get();
+ pd->view_edit_faces = default_view;
+ pd->view_edit_faces_cage = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 0.5f);
+ pd->view_edit_edges = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 1.0f);
+ pd->view_edit_verts = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 1.5f);
+}
+
+void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_ShadingData *shdata = &pd->shdata;
+ DRWShadingGroup *grp = NULL;
+ GPUShader *sh = NULL;
+ DRWState state = 0;
+
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ToolSettings *tsettings = draw_ctx->scene->toolsettings;
+ View3D *v3d = draw_ctx->v3d;
+ bool select_vert = pd->edit_mesh.select_vert = (tsettings->selectmode & SCE_SELECT_VERTEX) != 0;
+ bool select_face = pd->edit_mesh.select_face = (tsettings->selectmode & SCE_SELECT_FACE) != 0;
+ bool select_edge = pd->edit_mesh.select_edge = (tsettings->selectmode & SCE_SELECT_EDGE) != 0;
+
+ bool do_occlude_wire = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
+ bool show_face_dots = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) != 0 ||
+ pd->edit_mesh.do_zbufclip;
+
+ pd->edit_mesh.ghost_ob = 0;
+ pd->edit_mesh.edit_ob = 0;
+ pd->edit_mesh.do_faces = true;
+ pd->edit_mesh.do_edges = true;
+
+ int *mask = shdata->data_mask;
+ mask[0] = 0xFF; /* Face Flag */
+ mask[1] = 0xFF; /* Edge Flag */
+
+ const int flag = pd->edit_mesh.flag = v3d->overlay.edit_flag;
+
+ SET_FLAG_FROM_TEST(mask[0], flag & V3D_OVERLAY_EDIT_FACES, VFLAG_FACE_SELECTED);
+ SET_FLAG_FROM_TEST(mask[0], flag & V3D_OVERLAY_EDIT_FREESTYLE_FACE, VFLAG_FACE_FREESTYLE);
+ SET_FLAG_FROM_TEST(mask[1], flag & V3D_OVERLAY_EDIT_FREESTYLE_EDGE, VFLAG_EDGE_FREESTYLE);
+ SET_FLAG_FROM_TEST(mask[1], flag & V3D_OVERLAY_EDIT_SEAMS, VFLAG_EDGE_SEAM);
+ SET_FLAG_FROM_TEST(mask[1], flag & V3D_OVERLAY_EDIT_SHARP, VFLAG_EDGE_SHARP);
+ SET_FLAG_FROM_TEST(mask[2], flag & V3D_OVERLAY_EDIT_CREASES, 0xFF);
+ SET_FLAG_FROM_TEST(mask[3], flag & V3D_OVERLAY_EDIT_BWEIGHTS, 0xFF);
+
+ if ((flag & V3D_OVERLAY_EDIT_FACES) == 0) {
+ pd->edit_mesh.do_faces = false;
+ pd->edit_mesh.do_zbufclip = false;
+ }
+ if ((flag & V3D_OVERLAY_EDIT_EDGES) == 0) {
+ if ((tsettings->selectmode & SCE_SELECT_EDGE) == 0) {
+ if ((v3d->shading.type < OB_SOLID) || (v3d->shading.flag & V3D_SHADING_XRAY)) {
+ /* Special case, when drawing wire, draw edges, see: T67637. */
+ }
+ else {
+ pd->edit_mesh.do_edges = false;
+ }
+ }
+ }
+
+ float backwire_opacity = (pd->edit_mesh.do_zbufclip) ? v3d->overlay.backwire_opacity : 1.0f;
+ float face_alpha = (do_occlude_wire || !pd->edit_mesh.do_faces) ? 0.0f : 1.0f;
+ GPUTexture **depth_tex = (pd->edit_mesh.do_zbufclip) ? &dtxl->depth : &txl->dummy_depth_tx;
+
+ if (select_face && !pd->edit_mesh.do_faces && pd->edit_mesh.do_edges) {
+ /* Force display of face centers in this case because that's
+ * the only way to see if a face is selected. */
+ show_face_dots = true;
+ }
+
+ {
+ /* TODO(fclem) Shouldn't this be going into the paint overlay? */
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->edit_mesh_weight_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_paint_weight();
+ pd->edit_mesh_weight_grp = grp = DRW_shgroup_create(sh, psl->edit_mesh_weight_ps);
+ DRW_shgroup_uniform_float_copy(grp, "opacity", 1.0);
+ DRW_shgroup_uniform_bool_copy(grp, "drawContours", false);
+ DRW_shgroup_uniform_texture(grp, "colorramp", G_draw.weight_ramp);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+ /* Run Twice for in-front passes. */
+ for (int i = 0; i < 2; i++) {
+ /* Complementary Depth Pass */
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
+ DRW_PASS_CREATE(psl->edit_mesh_depth_ps[i], state | pd->clipping_state);
+
+ sh = OVERLAY_shader_depth_only();
+ pd->edit_mesh_depth_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_depth_ps[i]);
+ }
+ {
+ /* Normals */
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
+ (pd->edit_mesh.do_zbufclip ? DRW_STATE_BLEND_ALPHA : 0);
+ DRW_PASS_CREATE(psl->edit_mesh_normals_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_mesh_normal();
+ pd->edit_mesh_normals_grp = grp = DRW_shgroup_create(sh, psl->edit_mesh_normals_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "normalSize", v3d->overlay.normals_length);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+ }
+ {
+ /* Mesh Analysis Pass */
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->edit_mesh_analysis_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_mesh_analysis();
+ pd->edit_mesh_analysis_grp = grp = DRW_shgroup_create(sh, psl->edit_mesh_analysis_ps);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+ }
+ /* Run Twice for in-front passes. */
+ for (int i = 0; i < 2; i++) {
+ GPUShader *edge_sh = OVERLAY_shader_edit_mesh_edge(!select_vert);
+ GPUShader *face_sh = OVERLAY_shader_edit_mesh_face();
+ const bool do_zbufclip = (i == 0 && pd->edit_mesh.do_zbufclip);
+ DRWState state_common = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND_ALPHA;
+ /* Faces */
+ /* Cage geom needs to be offsetted to avoid Z-fighting. */
+ for (int j = 0; j < 2; j++) {
+ DRWPass **edit_face_ps = (j == 0) ? &psl->edit_mesh_faces_ps[i] :
+ &psl->edit_mesh_faces_cage_ps[i];
+ DRWShadingGroup **shgrp = (j == 0) ? &pd->edit_mesh_faces_grp[i] :
+ &pd->edit_mesh_faces_cage_grp[i];
+ state = state_common;
+ DRW_PASS_CREATE(*edit_face_ps, state | pd->clipping_state);
+
+ grp = *shgrp = DRW_shgroup_create(face_sh, *edit_face_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_ivec4(grp, "dataMask", mask, 1);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", face_alpha);
+ DRW_shgroup_uniform_bool_copy(grp, "selectFaces", select_face);
+ }
+
+ if (do_zbufclip) {
+ state_common |= DRW_STATE_WRITE_DEPTH;
+ // state_common &= ~DRW_STATE_BLEND_ALPHA;
+ }
+
+ /* Edges */
+ /* Change first vertex convention to match blender loop structure. */
+ state = state_common | DRW_STATE_FIRST_VERTEX_CONVENTION;
+ DRW_PASS_CREATE(psl->edit_mesh_edges_ps[i], state | pd->clipping_state);
+
+ grp = pd->edit_mesh_edges_grp[i] = DRW_shgroup_create(edge_sh, psl->edit_mesh_edges_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_ivec4(grp, "dataMask", mask, 1);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+ DRW_shgroup_uniform_bool_copy(grp, "selectEdges", pd->edit_mesh.do_edges || select_edge);
+
+ /* Verts */
+ DRW_PASS_CREATE(psl->edit_mesh_verts_ps[i], state | pd->clipping_state);
+
+ if (select_vert) {
+ sh = OVERLAY_shader_edit_mesh_vert();
+ grp = pd->edit_mesh_verts_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+
+ sh = OVERLAY_shader_edit_mesh_skin_root();
+ grp = pd->edit_mesh_skin_roots_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+ /* Facedots */
+ if (select_face && show_face_dots) {
+ sh = OVERLAY_shader_edit_mesh_facedot();
+ grp = pd->edit_mesh_facedots_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+ DRW_shgroup_state_enable(grp, DRW_STATE_WRITE_DEPTH);
+ }
+ else {
+ pd->edit_mesh_facedots_grp[i] = NULL;
+ }
+ }
+}
+
+static void overlay_edit_mesh_add_ob_to_pass(OVERLAY_PrivateData *pd, Object *ob, bool in_front)
+{
+ struct GPUBatch *geom_tris, *geom_verts, *geom_edges, *geom_fcenter, *skin_roots, *circle;
+ DRWShadingGroup *vert_shgrp, *edge_shgrp, *fdot_shgrp, *face_shgrp, *skin_roots_shgrp;
+
+ bool has_edit_mesh_cage = false;
+ bool has_skin_roots = false;
+ /* TODO: Should be its own function. */
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *embm = me->edit_mesh;
+ if (embm) {
+ has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
+ has_skin_roots = CustomData_get_offset(&embm->bm->vdata, CD_MVERT_SKIN) != -1;
+ }
+
+ vert_shgrp = pd->edit_mesh_verts_grp[in_front];
+ edge_shgrp = pd->edit_mesh_edges_grp[in_front];
+ fdot_shgrp = pd->edit_mesh_facedots_grp[in_front];
+ face_shgrp = (has_edit_mesh_cage) ? pd->edit_mesh_faces_cage_grp[in_front] :
+ pd->edit_mesh_faces_grp[in_front];
+ skin_roots_shgrp = pd->edit_mesh_skin_roots_grp[in_front];
+
+ geom_edges = DRW_mesh_batch_cache_get_edit_edges(ob->data);
+ geom_tris = DRW_mesh_batch_cache_get_edit_triangles(ob->data);
+ DRW_shgroup_call_no_cull(edge_shgrp, geom_edges, ob);
+ DRW_shgroup_call_no_cull(face_shgrp, geom_tris, ob);
+
+ if (pd->edit_mesh.select_vert) {
+ geom_verts = DRW_mesh_batch_cache_get_edit_vertices(ob->data);
+ DRW_shgroup_call_no_cull(vert_shgrp, geom_verts, ob);
+
+ if (has_skin_roots) {
+ circle = DRW_cache_circle_get();
+ skin_roots = DRW_mesh_batch_cache_get_edit_skin_roots(ob->data);
+ DRW_shgroup_call_instances_with_attribs(skin_roots_shgrp, ob, circle, skin_roots);
+ }
+ }
+
+ if (fdot_shgrp) {
+ geom_fcenter = DRW_mesh_batch_cache_get_edit_facedots(ob->data);
+ DRW_shgroup_call_no_cull(fdot_shgrp, geom_fcenter, ob);
+ }
+}
+
+void OVERLAY_edit_mesh_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUBatch *geom = NULL;
+
+ bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+ bool do_occlude_wire = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
+ bool do_show_weight = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_WEIGHT) != 0;
+ bool do_show_mesh_analysis = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_STATVIS) != 0;
+ bool fnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_FACE_NORMALS) != 0;
+ bool vnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_VERT_NORMALS) != 0;
+ bool lnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_LOOP_NORMALS) != 0;
+
+ if (do_show_weight) {
+ geom = DRW_cache_mesh_surface_weights_get(ob);
+ DRW_shgroup_call_no_cull(pd->edit_mesh_weight_grp, geom, ob);
+ }
+ else if (do_show_mesh_analysis && !pd->xray_enabled) {
+ geom = DRW_cache_mesh_surface_mesh_analysis_get(ob);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_mesh_analysis_grp, geom, ob);
+ }
+ }
+
+ if (do_occlude_wire || do_in_front) {
+ geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call_no_cull(pd->edit_mesh_depth_grp[do_in_front], geom, ob);
+ }
+
+ if (vnormals_do || lnormals_do || fnormals_do) {
+ struct GPUBatch *normal_geom = DRW_cache_normal_arrow_get();
+ if (vnormals_do) {
+ geom = DRW_mesh_batch_cache_get_edit_vnors(ob->data);
+ DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+ }
+ if (lnormals_do) {
+ geom = DRW_mesh_batch_cache_get_edit_lnors(ob->data);
+ DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+ }
+ if (fnormals_do) {
+ geom = DRW_mesh_batch_cache_get_edit_facedots(ob->data);
+ DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+ }
+ }
+
+ if (pd->edit_mesh.do_zbufclip) {
+ overlay_edit_mesh_add_ob_to_pass(pd, ob, false);
+ }
+ else {
+ overlay_edit_mesh_add_ob_to_pass(pd, ob, do_in_front);
+ }
+
+ pd->edit_mesh.ghost_ob += (ob->dtx & OB_DRAWXRAY) ? 1 : 0;
+ pd->edit_mesh.edit_ob += 1;
+
+ if (DRW_state_show_text() && (pd->edit_mesh.flag & OVERLAY_EDIT_TEXT)) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ DRW_text_edit_mesh_measure_stats(draw_ctx->ar, draw_ctx->v3d, ob, &draw_ctx->scene->unit);
+ }
+}
+
+static void overlay_edit_mesh_draw_components(OVERLAY_PassList *psl,
+ OVERLAY_PrivateData *pd,
+ bool in_front)
+{
+ DRW_view_set_active(pd->view_edit_faces);
+ DRW_draw_pass(psl->edit_mesh_faces_ps[in_front]);
+
+ DRW_view_set_active(pd->view_edit_faces_cage);
+ DRW_draw_pass(psl->edit_mesh_faces_cage_ps[in_front]);
+
+ DRW_view_set_active(pd->view_edit_edges);
+ DRW_draw_pass(psl->edit_mesh_edges_ps[in_front]);
+
+ DRW_view_set_active(pd->view_edit_verts);
+ DRW_draw_pass(psl->edit_mesh_verts_ps[in_front]);
+}
+
+void OVERLAY_edit_mesh_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(fbl->overlay_default_fb);
+ }
+
+ DRW_draw_pass(psl->edit_mesh_weight_ps);
+ DRW_draw_pass(psl->edit_mesh_analysis_ps);
+
+ DRW_draw_pass(psl->edit_mesh_depth_ps[NOT_IN_FRONT]);
+
+ if (pd->edit_mesh.do_zbufclip) {
+ DRW_draw_pass(psl->edit_mesh_depth_ps[IN_FRONT]);
+
+ /* render facefill */
+ DRW_view_set_active(pd->view_edit_faces);
+ DRW_draw_pass(psl->edit_mesh_faces_ps[NOT_IN_FRONT]);
+
+ DRW_view_set_active(pd->view_edit_faces_cage);
+ DRW_draw_pass(psl->edit_mesh_faces_cage_ps[NOT_IN_FRONT]);
+
+ DRW_view_set_active(NULL);
+
+ GPU_framebuffer_bind(fbl->overlay_in_front_fb);
+ GPU_framebuffer_clear_depth(fbl->overlay_in_front_fb, 1.0f);
+ DRW_draw_pass(psl->edit_mesh_normals_ps);
+
+ DRW_view_set_active(pd->view_edit_edges);
+ DRW_draw_pass(psl->edit_mesh_edges_ps[NOT_IN_FRONT]);
+
+ DRW_view_set_active(pd->view_edit_verts);
+ DRW_draw_pass(psl->edit_mesh_verts_ps[NOT_IN_FRONT]);
+ }
+ else {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ DRW_draw_pass(psl->edit_mesh_normals_ps);
+ overlay_edit_mesh_draw_components(psl, pd, false);
+
+ if (v3d->shading.type == OB_SOLID && pd->edit_mesh.ghost_ob == 1 &&
+ pd->edit_mesh.edit_ob == 1) {
+ /* In the case of single ghost object edit (common case for retopology):
+ * we clear the depth buffer so that only the depth of the retopo mesh
+ * is occluding the edit cage. */
+ GPU_framebuffer_clear_depth(fbl->overlay_default_fb, 1.0f);
+ }
+
+ DRW_draw_pass(psl->edit_mesh_depth_ps[IN_FRONT]);
+ overlay_edit_mesh_draw_components(psl, pd, true);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.c b/source/blender/draw/engines/overlay/overlay_edit_text.c
new file mode 100644
index 00000000000..72b5ae74255
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_edit_text.c
@@ -0,0 +1,205 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_font.h"
+
+#include "DNA_curve_types.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ DRWShadingGroup *grp;
+ GPUShader *sh;
+ DRWState state;
+
+ pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+ pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length;
+
+ /* Run Twice for in-front passes. */
+ for (int i = 0; i < 2; i++) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH;
+ state |= ((i == 0) ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_ALWAYS);
+ DRW_PASS_CREATE(psl->edit_text_wire_ps[i], state | pd->clipping_state);
+
+ sh = OVERLAY_shader_uniform_color();
+ pd->edit_text_wire_grp[i] = grp = DRW_shgroup_create(sh, psl->edit_text_wire_ps[i]);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", G_draw.block.colorWire);
+ }
+ {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_LOGIC_INVERT;
+ DRW_PASS_CREATE(psl->edit_text_overlay_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_uniform_color();
+ pd->edit_text_overlay_grp = DRW_shgroup_create(sh, psl->edit_text_overlay_ps);
+ }
+}
+
+/* Use 2D quad corners to create a matrix that set
+ * a [-1..1] quad at the right position. */
+static void v2_quad_corners_to_mat4(float corners[4][2], float r_mat[4][4])
+{
+ unit_m4(r_mat);
+ sub_v2_v2v2(r_mat[0], corners[1], corners[0]);
+ sub_v2_v2v2(r_mat[1], corners[3], corners[0]);
+ mul_v2_fl(r_mat[0], 0.5f);
+ mul_v2_fl(r_mat[1], 0.5f);
+ copy_v2_v2(r_mat[3], corners[0]);
+ add_v2_v2(r_mat[3], r_mat[0]);
+ add_v2_v2(r_mat[3], r_mat[1]);
+}
+
+static void edit_text_cache_populate_select(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const Curve *cu = ob->data;
+ EditFont *ef = cu->editfont;
+ float final_mat[4][4], box[4][2];
+ struct GPUBatch *geom = DRW_cache_quad_get();
+
+ for (int i = 0; i < ef->selboxes_len; i++) {
+ EditFontSelBox *sb = &ef->selboxes[i];
+
+ float selboxw;
+ if (i + 1 != ef->selboxes_len) {
+ if (ef->selboxes[i + 1].y == sb->y) {
+ selboxw = ef->selboxes[i + 1].x - sb->x;
+ }
+ else {
+ selboxw = sb->w;
+ }
+ }
+ else {
+ selboxw = sb->w;
+ }
+ /* NOTE: v2_quad_corners_to_mat4 don't need the 3rd corner. */
+ if (sb->rot == 0.0f) {
+ copy_v2_fl2(box[0], sb->x, sb->y);
+ copy_v2_fl2(box[1], sb->x + selboxw, sb->y);
+ copy_v2_fl2(box[3], sb->x, sb->y + sb->h);
+ }
+ else {
+ float mat[2][2];
+ angle_to_mat2(mat, sb->rot);
+ copy_v2_fl2(box[0], sb->x, sb->y);
+ mul_v2_v2fl(box[1], mat[0], selboxw);
+ add_v2_v2(box[1], &sb->x);
+ mul_v2_v2fl(box[3], mat[1], sb->h);
+ add_v2_v2(box[3], &sb->x);
+ }
+ v2_quad_corners_to_mat4(box, final_mat);
+ mul_m4_m4m4(final_mat, ob->obmat, final_mat);
+
+ DRW_shgroup_call_obmat(pd->edit_text_overlay_grp, geom, final_mat);
+ }
+}
+
+static void edit_text_cache_populate_cursor(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const Curve *cu = ob->data;
+ EditFont *edit_font = cu->editfont;
+ float(*cursor)[2] = edit_font->textcurs;
+ float mat[4][4];
+
+ v2_quad_corners_to_mat4(cursor, mat);
+ mul_m4_m4m4(mat, ob->obmat, mat);
+
+ struct GPUBatch *geom = DRW_cache_quad_get();
+ DRW_shgroup_call_obmat(pd->edit_text_overlay_grp, geom, mat);
+}
+
+static void edit_text_cache_populate_boxes(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const Curve *cu = ob->data;
+
+ for (int i = 0; i < cu->totbox; i++) {
+ TextBox *tb = &cu->tb[i];
+ const bool is_active = (i == (cu->actbox - 1));
+ float *color = is_active ? G_draw.block.colorActive : G_draw.block.colorWire;
+
+ if ((tb->w != 0.0f) || (tb->h != 0.0f)) {
+ float vecs[4][3];
+ vecs[0][0] = vecs[1][0] = vecs[2][0] = vecs[3][0] = cu->xof + tb->x;
+ vecs[0][1] = vecs[1][1] = vecs[2][1] = vecs[3][1] = cu->yof + tb->y + cu->fsize_realtime;
+ vecs[0][2] = vecs[1][2] = vecs[2][2] = vecs[3][2] = 0.001;
+
+ vecs[1][0] += tb->w;
+ vecs[2][0] += tb->w;
+ vecs[2][1] -= tb->h;
+ vecs[3][1] -= tb->h;
+
+ for (int j = 0; j < 4; j++) {
+ mul_v3_m4v3(vecs[j], ob->obmat, vecs[j]);
+ }
+ for (int j = 0; j < 4; j++) {
+ OVERLAY_extra_line_dashed(cb, vecs[j], vecs[(j + 1) % 4], color);
+ }
+ }
+ }
+}
+
+void OVERLAY_edit_text_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ Curve *cu = ob->data;
+ struct GPUBatch *geom;
+ bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+
+ bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f || cu->ext2 != 0.0f;
+ if ((cu->flag & CU_FAST) || !has_surface) {
+ geom = DRW_cache_text_edge_wire_get(ob);
+ if (geom) {
+ DRW_shgroup_call(pd->edit_text_wire_grp[do_in_front], geom, ob);
+ }
+ }
+ else {
+ /* object mode draws */
+ }
+
+ edit_text_cache_populate_select(vedata, ob);
+ edit_text_cache_populate_cursor(vedata, ob);
+ edit_text_cache_populate_boxes(vedata, ob);
+}
+
+void OVERLAY_edit_text_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (DRW_state_is_fbo()) {
+ /* Text overlay need final color for color inversion. */
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+
+ DRW_draw_pass(psl->edit_text_wire_ps[0]);
+ DRW_draw_pass(psl->edit_text_wire_ps[1]);
+
+ DRW_draw_pass(psl->edit_text_overlay_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
new file mode 100644
index 00000000000..fe39b8580e3
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -0,0 +1,485 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Engine for drawing a selection map where the pixels indicate the selection indices.
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "ED_view3d.h"
+
+#include "BKE_object.h"
+
+#include "overlay_engine.h"
+#include "overlay_private.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Engine Callbacks
+ * \{ */
+
+static void OVERLAY_engine_init(void *vedata)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_StorageList *stl = data->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const RegionView3D *rv3d = draw_ctx->rv3d;
+ const View3D *v3d = draw_ctx->v3d;
+
+ if (!stl->pd) {
+ /* Alloc transient pointers */
+ stl->pd = MEM_callocN(sizeof(*stl->pd), __func__);
+ }
+
+ OVERLAY_PrivateData *pd = stl->pd;
+
+ pd->hide_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) != 0;
+ pd->ctx_mode = CTX_data_mode_enum_ex(
+ draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
+
+ if (!pd->hide_overlays) {
+ pd->overlay = v3d->overlay;
+ pd->v3d_flag = v3d->flag;
+ pd->v3d_gridflag = v3d->gridflag;
+ }
+ else {
+ memset(&pd->overlay, 0, sizeof(pd->overlay));
+ pd->v3d_flag = 0;
+ pd->v3d_gridflag = 0;
+ pd->overlay.flag = V3D_OVERLAY_HIDE_TEXT | V3D_OVERLAY_HIDE_MOTION_PATHS |
+ V3D_OVERLAY_HIDE_BONES | V3D_OVERLAY_HIDE_OBJECT_XTRAS |
+ V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
+ }
+
+ if (v3d->shading.type == OB_WIRE) {
+ pd->overlay.flag |= V3D_OVERLAY_WIREFRAMES;
+ }
+
+ pd->wireframe_mode = (v3d->shading.type == OB_WIRE);
+ pd->clipping_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0;
+ pd->xray_enabled = XRAY_ACTIVE(v3d);
+ pd->xray_enabled_and_not_wire = pd->xray_enabled && v3d->shading.type > OB_WIRE;
+ pd->clear_in_front = (v3d->shading.type != OB_SOLID);
+
+ OVERLAY_antialiasing_init(vedata);
+
+ switch (stl->pd->ctx_mode) {
+ case CTX_MODE_EDIT_MESH:
+ OVERLAY_edit_mesh_init(vedata);
+ break;
+ default:
+ /* Nothing to do. */
+ break;
+ }
+ OVERLAY_facing_init(vedata);
+ OVERLAY_grid_init(vedata);
+ OVERLAY_image_init(vedata);
+ OVERLAY_outline_init(vedata);
+ OVERLAY_wireframe_init(vedata);
+}
+
+static void OVERLAY_cache_init(void *vedata)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_StorageList *stl = data->stl;
+ OVERLAY_PrivateData *pd = stl->pd;
+
+ switch (pd->ctx_mode) {
+ case CTX_MODE_EDIT_MESH:
+ OVERLAY_edit_mesh_cache_init(vedata);
+ break;
+ case CTX_MODE_EDIT_SURFACE:
+ case CTX_MODE_EDIT_CURVE:
+ OVERLAY_edit_curve_cache_init(vedata);
+ break;
+ case CTX_MODE_EDIT_TEXT:
+ OVERLAY_edit_text_cache_init(vedata);
+ break;
+ case CTX_MODE_EDIT_ARMATURE:
+ break;
+ case CTX_MODE_EDIT_METABALL:
+ break;
+ case CTX_MODE_EDIT_LATTICE:
+ OVERLAY_edit_lattice_cache_init(vedata);
+ break;
+ case CTX_MODE_PARTICLE:
+ OVERLAY_edit_particle_cache_init(vedata);
+ break;
+ case CTX_MODE_POSE:
+ case CTX_MODE_PAINT_WEIGHT:
+ case CTX_MODE_PAINT_VERTEX:
+ case CTX_MODE_PAINT_TEXTURE:
+ OVERLAY_paint_cache_init(vedata);
+ break;
+ case CTX_MODE_SCULPT:
+ OVERLAY_sculpt_cache_init(vedata);
+ break;
+ case CTX_MODE_OBJECT:
+ case CTX_MODE_PAINT_GPENCIL:
+ case CTX_MODE_EDIT_GPENCIL:
+ case CTX_MODE_SCULPT_GPENCIL:
+ case CTX_MODE_WEIGHT_GPENCIL:
+ break;
+ default:
+ BLI_assert(!"Draw mode invalid");
+ break;
+ }
+ OVERLAY_antialiasing_cache_init(vedata);
+ OVERLAY_armature_cache_init(vedata);
+ OVERLAY_extra_cache_init(vedata);
+ OVERLAY_facing_cache_init(vedata);
+ OVERLAY_grid_cache_init(vedata);
+ OVERLAY_image_cache_init(vedata);
+ OVERLAY_metaball_cache_init(vedata);
+ OVERLAY_motion_path_cache_init(vedata);
+ OVERLAY_outline_cache_init(vedata);
+ OVERLAY_particle_cache_init(vedata);
+ OVERLAY_wireframe_cache_init(vedata);
+}
+
+BLI_INLINE OVERLAY_DupliData *OVERLAY_duplidata_get(Object *ob, void *vedata, bool *do_init)
+{
+ OVERLAY_DupliData **dupli_data = (OVERLAY_DupliData **)DRW_duplidata_get(vedata);
+ *do_init = false;
+ if (!ELEM(ob->type, OB_MESH, OB_SURF, OB_LATTICE, OB_CURVE, OB_FONT)) {
+ return NULL;
+ }
+
+ if (dupli_data) {
+ if (*dupli_data == NULL) {
+ *dupli_data = MEM_callocN(sizeof(OVERLAY_DupliData), __func__);
+ *do_init = true;
+ }
+ else if ((*dupli_data)->base_flag != ob->base_flag) {
+ /* Select state might have change, reinit. */
+ *do_init = true;
+ }
+ return *dupli_data;
+ }
+ return NULL;
+}
+
+static void OVERLAY_cache_populate(void *vedata, Object *ob)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_PrivateData *pd = data->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool is_select = DRW_state_is_select();
+ const bool renderable = DRW_object_is_renderable(ob);
+ const bool in_pose_mode = ob->type == OB_ARMATURE && OVERLAY_armature_is_pose_mode(ob, draw_ctx);
+ const bool in_edit_mode = BKE_object_is_in_editmode(ob);
+ const bool in_particle_edit_mode = ob->mode == OB_MODE_PARTICLE_EDIT;
+ const bool in_paint_mode = (ob == draw_ctx->obact) &&
+ (draw_ctx->object_mode & OB_MODE_ALL_PAINT);
+ const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL);
+ const bool has_surface = ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT);
+ const bool draw_surface = !((ob->dt < OB_WIRE) || (!renderable && (ob->dt != OB_WIRE)));
+ const bool draw_facing = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION);
+ 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 &&
+ (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 &&
+ !is_select;
+ const bool draw_extras =
+ (!pd->hide_overlays) &&
+ (((pd->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_XTRAS) == 0) ||
+ /* Show if this is the camera we're looking through since it's useful for selecting. */
+ ((draw_ctx->rv3d->persp == RV3D_CAMOB) && ((ID *)draw_ctx->v3d->camera == ob->id.orig_id)));
+
+ const bool draw_motion_paths = (pd->overlay.flag & V3D_OVERLAY_HIDE_MOTION_PATHS) == 0;
+
+ bool do_init;
+ OVERLAY_DupliData *dupli = OVERLAY_duplidata_get(ob, vedata, &do_init);
+
+ if (draw_facing) {
+ OVERLAY_facing_cache_populate(vedata, ob);
+ }
+ if (draw_wires) {
+ OVERLAY_wireframe_cache_populate(vedata, ob, dupli, do_init);
+ }
+ if (draw_outlines) {
+ OVERLAY_outline_cache_populate(vedata, ob, dupli, do_init);
+ }
+ if (draw_bone_selection) {
+ OVERLAY_pose_cache_populate(vedata, ob);
+ }
+
+ if (in_edit_mode && !pd->hide_overlays) {
+ switch (ob->type) {
+ case OB_MESH:
+ OVERLAY_edit_mesh_cache_populate(vedata, ob);
+ break;
+ case OB_ARMATURE:
+ if (draw_bones) {
+ OVERLAY_edit_armature_cache_populate(vedata, ob);
+ }
+ break;
+ case OB_CURVE:
+ OVERLAY_edit_curve_cache_populate(vedata, ob);
+ break;
+ case OB_SURF:
+ OVERLAY_edit_surf_cache_populate(vedata, ob);
+ break;
+ case OB_LATTICE:
+ OVERLAY_edit_lattice_cache_populate(vedata, ob);
+ break;
+ case OB_MBALL:
+ OVERLAY_edit_metaball_cache_populate(vedata, ob);
+ break;
+ case OB_FONT:
+ OVERLAY_edit_text_cache_populate(vedata, ob);
+ break;
+ }
+ }
+ else if (in_pose_mode && draw_bones) {
+ OVERLAY_pose_armature_cache_populate(vedata, ob);
+ }
+ else if (in_paint_mode) {
+ switch (draw_ctx->object_mode) {
+ case OB_MODE_VERTEX_PAINT:
+ OVERLAY_paint_vertex_cache_populate(vedata, ob);
+ break;
+ case OB_MODE_WEIGHT_PAINT:
+ OVERLAY_paint_weight_cache_populate(vedata, ob);
+ break;
+ case OB_MODE_TEXTURE_PAINT:
+ OVERLAY_paint_texture_cache_populate(vedata, ob);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (in_particle_edit_mode) {
+ OVERLAY_edit_particle_cache_populate(vedata, ob);
+ }
+
+ if (in_sculpt_mode) {
+ OVERLAY_sculpt_cache_populate(vedata, ob);
+ }
+
+ if (draw_motion_paths) {
+ OVERLAY_motion_path_cache_populate(vedata, ob);
+ }
+
+ if (!pd->hide_overlays) {
+ switch (ob->type) {
+ case OB_ARMATURE:
+ if (draw_bones && (is_select || (!in_edit_mode && !in_pose_mode))) {
+ OVERLAY_armature_cache_populate(vedata, ob);
+ }
+ break;
+ case OB_MBALL:
+ if (!in_edit_mode) {
+ OVERLAY_metaball_cache_populate(vedata, ob);
+ }
+ break;
+ case OB_GPENCIL:
+ OVERLAY_gpencil_cache_populate(vedata, ob);
+ break;
+ }
+ }
+ /* Non-Meshes */
+ if (draw_extras) {
+ switch (ob->type) {
+ case OB_EMPTY:
+ OVERLAY_empty_cache_populate(vedata, ob);
+ break;
+ case OB_LAMP:
+ OVERLAY_light_cache_populate(vedata, ob);
+ break;
+ case OB_CAMERA:
+ OVERLAY_camera_cache_populate(vedata, ob);
+ break;
+ case OB_SPEAKER:
+ OVERLAY_speaker_cache_populate(vedata, ob);
+ break;
+ case OB_LIGHTPROBE:
+ OVERLAY_lightprobe_cache_populate(vedata, ob);
+ break;
+ case OB_LATTICE:
+ OVERLAY_lattice_cache_populate(vedata, ob);
+ break;
+ }
+ }
+
+ if (!BLI_listbase_is_empty(&ob->particlesystem)) {
+ OVERLAY_particle_cache_populate(vedata, ob);
+ }
+
+ /* Relationship, object center, bounbox ... */
+ if (!pd->hide_overlays) {
+ OVERLAY_extra_cache_populate(vedata, ob);
+ }
+
+ if (dupli) {
+ dupli->base_flag = ob->base_flag;
+ }
+}
+
+static void OVERLAY_cache_finish(void *vedata)
+{
+ /* TODO(fclem) Only do this when really needed. */
+ {
+ /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
+
+ GPU_framebuffer_ensure_config(
+ &dfbl->default_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ GPU_framebuffer_ensure_config(
+ &dfbl->in_front_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ }
+
+ OVERLAY_antialiasing_cache_finish(vedata);
+ OVERLAY_armature_cache_finish(vedata);
+ OVERLAY_image_cache_finish(vedata);
+}
+
+static void OVERLAY_draw_scene(void *vedata)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_PrivateData *pd = data->stl->pd;
+ OVERLAY_FramebufferList *fbl = data->fbl;
+
+ OVERLAY_antialiasing_start(vedata);
+
+ DRW_view_set_active(NULL);
+
+ OVERLAY_outline_draw(vedata);
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+
+ OVERLAY_image_draw(vedata);
+ OVERLAY_facing_draw(vedata);
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_line_fb);
+ }
+
+ OVERLAY_wireframe_draw(vedata);
+ OVERLAY_armature_draw(vedata);
+ OVERLAY_particle_draw(vedata);
+ OVERLAY_metaball_draw(vedata);
+ OVERLAY_extra_draw(vedata);
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_color_only_fb);
+ }
+
+ OVERLAY_grid_draw(vedata);
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_line_in_front_fb);
+ }
+
+ OVERLAY_wireframe_in_front_draw(vedata);
+ OVERLAY_armature_in_front_draw(vedata);
+ OVERLAY_extra_in_front_draw(vedata);
+ OVERLAY_metaball_in_front_draw(vedata);
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_color_only_fb);
+ }
+
+ OVERLAY_image_in_front_draw(vedata);
+ OVERLAY_motion_path_draw(vedata);
+ OVERLAY_extra_centers_draw(vedata);
+
+ /* Functions after this point can change FBO freely. */
+
+ switch (pd->ctx_mode) {
+ case CTX_MODE_EDIT_MESH:
+ OVERLAY_edit_mesh_draw(vedata);
+ break;
+ case CTX_MODE_EDIT_SURFACE:
+ case CTX_MODE_EDIT_CURVE:
+ OVERLAY_edit_curve_draw(vedata);
+ break;
+ case CTX_MODE_EDIT_TEXT:
+ OVERLAY_edit_text_draw(vedata);
+ break;
+ case CTX_MODE_EDIT_LATTICE:
+ OVERLAY_edit_lattice_draw(vedata);
+ break;
+ case CTX_MODE_POSE:
+ OVERLAY_paint_draw(vedata);
+ OVERLAY_pose_draw(vedata);
+ break;
+ case CTX_MODE_PAINT_WEIGHT:
+ case CTX_MODE_PAINT_VERTEX:
+ case CTX_MODE_PAINT_TEXTURE:
+ OVERLAY_paint_draw(vedata);
+ break;
+ case CTX_MODE_PARTICLE:
+ OVERLAY_edit_particle_draw(vedata);
+ break;
+ case CTX_MODE_SCULPT:
+ OVERLAY_sculpt_draw(vedata);
+ break;
+ default:
+ break;
+ }
+
+ OVERLAY_antialiasing_end(vedata);
+}
+
+static void OVERLAY_engine_free(void)
+{
+ OVERLAY_shader_free();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Engine Type
+ * \{ */
+
+static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data);
+
+DrawEngineType draw_engine_overlay_type = {
+ NULL,
+ NULL,
+ N_("Overlay"),
+ &overlay_data_size,
+ &OVERLAY_engine_init,
+ &OVERLAY_engine_free,
+ &OVERLAY_cache_init,
+ &OVERLAY_cache_populate,
+ &OVERLAY_cache_finish,
+ NULL,
+ &OVERLAY_draw_scene,
+ NULL,
+ NULL,
+ NULL,
+};
+
+/** \} */
+
+#undef SELECT_ENGINE
diff --git a/source/blender/draw/engines/overlay/overlay_engine.h b/source/blender/draw/engines/overlay/overlay_engine.h
new file mode 100644
index 00000000000..795e3805037
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_engine.h
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#ifndef __OVERLAY_ENGINE_H__
+#define __OVERLAY_ENGINE_H__
+
+extern DrawEngineType draw_engine_overlay_type;
+
+#endif /* __OVERLAY_ENGINE_H__ */
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
new file mode 100644
index 00000000000..90ddb9f7476
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -0,0 +1,1626 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "UI_resources.h"
+
+#include "BKE_anim.h"
+#include "BKE_camera.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_movieclip.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_tracking.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_lightprobe_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_fluid_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "GPU_draw.h"
+
+#include "overlay_private.h"
+
+#include "draw_common.h"
+#include "draw_manager_text.h"
+
+void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ DRWState state_blend = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->extra_blend_ps, state_blend | pd->clipping_state);
+ DRW_PASS_CREATE(psl->extra_centers_ps, state_blend | pd->clipping_state);
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR;
+
+ DRW_PASS_CREATE(psl->extra_grid_ps, state | pd->clipping_state);
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DRWShadingGroup *grp;
+ struct GPUShader *sh = OVERLAY_shader_extra_grid();
+ struct GPUTexture *tex = DRW_state_is_fbo() ? dtxl->depth : txl->dummy_depth_tx;
+
+ pd->extra_grid_grp = grp = DRW_shgroup_create(sh, psl->extra_grid_ps);
+ DRW_shgroup_uniform_texture_persistent(grp, "depthBuffer", tex);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
+ }
+
+ for (int i = 0; i < 2; i++) {
+ /* Non Meshes Pass (Camera, empties, lights ...) */
+ struct GPUShader *sh;
+ struct GPUVertFormat *format;
+ DRWShadingGroup *grp, *grp_sub;
+
+ OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+ OVERLAY_ExtraCallBuffers *cb = &pd->extra_call_buffers[i];
+ DRWPass **p_extra_ps = &psl->extra_ps[i];
+
+ DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(*p_extra_ps, state | pd->clipping_state | infront_state);
+
+ DRWPass *extra_ps = *p_extra_ps;
+
+#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
+#define BUF_POINT(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_POINTS)
+#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES)
+
+ /* Sorted by shader to avoid state changes during render. */
+ {
+ format = formats->instance_extra;
+ sh = OVERLAY_shader_extra();
+
+ grp = DRW_shgroup_create(sh, extra_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ cb->camera_distances = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_distances_get());
+ cb->camera_frame = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_frame_get());
+ cb->camera_tria[0] = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_tria_wire_get());
+ cb->camera_tria[1] = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_tria_get());
+ cb->empty_axes = BUF_INSTANCE(grp_sub, format, DRW_cache_bone_arrows_get());
+ cb->empty_capsule_body = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_capsule_body_get());
+ cb->empty_capsule_cap = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_capsule_cap_get());
+ cb->empty_circle = BUF_INSTANCE(grp_sub, format, DRW_cache_circle_get());
+ cb->empty_cone = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_cone_get());
+ cb->empty_cube = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_cube_get());
+ cb->empty_cylinder = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_cylinder_get());
+ cb->empty_image_frame = BUF_INSTANCE(grp_sub, format, DRW_cache_quad_wires_get());
+ cb->empty_plain_axes = BUF_INSTANCE(grp_sub, format, DRW_cache_plain_axes_get());
+ cb->empty_single_arrow = BUF_INSTANCE(grp_sub, format, DRW_cache_single_arrow_get());
+ cb->empty_sphere = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_sphere_get());
+ cb->empty_sphere_solid = BUF_INSTANCE(grp_sub, format, DRW_cache_sphere_get());
+ cb->field_cone_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_cone_limit_get());
+ cb->field_curve = BUF_INSTANCE(grp_sub, format, DRW_cache_field_curve_get());
+ cb->field_force = BUF_INSTANCE(grp_sub, format, DRW_cache_field_force_get());
+ cb->field_sphere_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_sphere_limit_get());
+ cb->field_tube_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_tube_limit_get());
+ cb->field_vortex = BUF_INSTANCE(grp_sub, format, DRW_cache_field_vortex_get());
+ cb->field_wind = BUF_INSTANCE(grp_sub, format, DRW_cache_field_wind_get());
+ cb->light_area[0] = BUF_INSTANCE(grp_sub, format, DRW_cache_light_area_disk_lines_get());
+ cb->light_area[1] = BUF_INSTANCE(grp_sub, format, DRW_cache_light_area_square_lines_get());
+ cb->light_point = BUF_INSTANCE(grp_sub, format, DRW_cache_light_point_lines_get());
+ cb->light_spot = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_lines_get());
+ cb->light_sun = BUF_INSTANCE(grp_sub, format, DRW_cache_light_sun_lines_get());
+ cb->probe_cube = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_planar_get());
+ cb->probe_grid = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_grid_get());
+ cb->probe_planar = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_planar_get());
+ cb->solid_quad = BUF_INSTANCE(grp_sub, format, DRW_cache_quad_get());
+ cb->speaker = BUF_INSTANCE(grp_sub, format, DRW_cache_speaker_get());
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_enable(grp_sub, DRW_STATE_DEPTH_ALWAYS);
+ DRW_shgroup_state_disable(grp_sub, DRW_STATE_DEPTH_LESS_EQUAL);
+ cb->origin_xform = BUF_INSTANCE(grp_sub, format, DRW_cache_bone_arrows_get());
+ }
+ {
+ format = formats->instance_extra;
+ grp = DRW_shgroup_create(sh, psl->extra_blend_ps); /* NOTE: not the same pass! */
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_enable(grp_sub, DRW_STATE_CULL_BACK);
+ cb->camera_volume = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_volume_get());
+ cb->camera_volume_frame = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_volume_wire_get());
+ cb->light_spot_cone_back = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_volume_get());
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_enable(grp_sub, DRW_STATE_CULL_FRONT);
+ cb->light_spot_cone_front = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_volume_get());
+ }
+ {
+ format = formats->instance_pos;
+ sh = OVERLAY_shader_extra_groundline();
+
+ grp = DRW_shgroup_create(sh, extra_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+ cb->groundline = BUF_INSTANCE(grp, format, DRW_cache_groundline_get());
+ }
+ {
+ sh = OVERLAY_shader_extra_wire(false);
+
+ grp = DRW_shgroup_create(sh, extra_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+ cb->extra_dashed_lines = BUF_LINE(grp, formats->pos_color);
+ cb->extra_lines = BUF_LINE(grp, formats->wire_extra);
+ }
+ {
+ sh = OVERLAY_shader_extra_wire(true);
+
+ cb->extra_wire = grp = DRW_shgroup_create(sh, extra_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ }
+ {
+ sh = OVERLAY_shader_extra_loose_point();
+
+ cb->extra_loose_points = grp = DRW_shgroup_create(sh, extra_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ }
+ {
+ format = formats->pos;
+ sh = OVERLAY_shader_extra_point();
+
+ grp = DRW_shgroup_create(sh, psl->extra_centers_ps); /* NOTE: not the same pass! */
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorActive);
+ cb->center_active = BUF_POINT(grp_sub, format);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorSelect);
+ cb->center_selected = BUF_POINT(grp_sub, format);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorDeselect);
+ cb->center_deselected = BUF_POINT(grp_sub, format);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorLibrarySelect);
+ cb->center_selected_lib = BUF_POINT(grp_sub, format);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorLibrary);
+ cb->center_deselected_lib = BUF_POINT(grp_sub, format);
+ }
+ }
+}
+
+void OVERLAY_extra_line_dashed(OVERLAY_ExtraCallBuffers *cb,
+ const float start[3],
+ const float end[3],
+ const float color[4])
+{
+ DRW_buffer_add_entry(cb->extra_dashed_lines, end, color);
+ DRW_buffer_add_entry(cb->extra_dashed_lines, start, color);
+}
+
+void OVERLAY_extra_line(OVERLAY_ExtraCallBuffers *cb,
+ const float start[3],
+ const float end[3],
+ const int color_id)
+{
+ DRW_buffer_add_entry(cb->extra_lines, start, &color_id);
+ DRW_buffer_add_entry(cb->extra_lines, end, &color_id);
+}
+
+OVERLAY_ExtraCallBuffers *OVERLAY_extra_call_buffer_get(OVERLAY_Data *vedata, Object *ob)
+{
+ bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ return &pd->extra_call_buffers[do_in_front];
+}
+
+void OVERLAY_extra_loose_points(OVERLAY_ExtraCallBuffers *cb,
+ struct GPUBatch *geom,
+ const float mat[4][4],
+ const float color[4])
+{
+ float draw_mat[4][4];
+ pack_v4_in_mat4(draw_mat, mat, color);
+ DRW_shgroup_call_obmat(cb->extra_loose_points, geom, draw_mat);
+}
+
+void OVERLAY_extra_wire(OVERLAY_ExtraCallBuffers *cb,
+ struct GPUBatch *geom,
+ const float mat[4][4],
+ const float color[4])
+{
+ float draw_mat[4][4];
+ float col[4] = {UNPACK3(color), 0.0f /* No stipples. */};
+ pack_v4_in_mat4(draw_mat, mat, col);
+ DRW_shgroup_call_obmat(cb->extra_wire, geom, draw_mat);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Empties
+ * \{ */
+
+void OVERLAY_empty_shape(OVERLAY_ExtraCallBuffers *cb,
+ const float mat[4][4],
+ const float draw_size,
+ const char draw_type,
+ const float color[4])
+{
+ float instdata[4][4];
+ pack_fl_in_mat4(instdata, mat, draw_size);
+
+ switch (draw_type) {
+ case OB_PLAINAXES:
+ DRW_buffer_add_entry(cb->empty_plain_axes, color, instdata);
+ break;
+ case OB_SINGLE_ARROW:
+ DRW_buffer_add_entry(cb->empty_single_arrow, color, instdata);
+ break;
+ case OB_CUBE:
+ DRW_buffer_add_entry(cb->empty_cube, color, instdata);
+ break;
+ case OB_CIRCLE:
+ DRW_buffer_add_entry(cb->empty_circle, color, instdata);
+ break;
+ case OB_EMPTY_SPHERE:
+ DRW_buffer_add_entry(cb->empty_sphere, color, instdata);
+ break;
+ case OB_EMPTY_CONE:
+ DRW_buffer_add_entry(cb->empty_cone, color, instdata);
+ break;
+ case OB_ARROWS:
+ DRW_buffer_add_entry(cb->empty_axes, color, instdata);
+ break;
+ case OB_EMPTY_IMAGE:
+ /* This only show the frame. See OVERLAY_image_empty_cache_populate() for the image. */
+ DRW_buffer_add_entry(cb->empty_image_frame, color, instdata);
+ break;
+ }
+}
+
+void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ if (((ob->base_flag & BASE_FROM_DUPLI) != 0) && ((ob->transflag & OB_DUPLICOLLECTION) != 0) &&
+ ob->instance_collection) {
+ return;
+ }
+
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ float *color;
+
+ switch (ob->empty_drawtype) {
+ case OB_PLAINAXES:
+ case OB_SINGLE_ARROW:
+ case OB_CUBE:
+ case OB_CIRCLE:
+ case OB_EMPTY_SPHERE:
+ case OB_EMPTY_CONE:
+ case OB_ARROWS:
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+ OVERLAY_empty_shape(cb, ob->obmat, ob->empty_drawsize, ob->empty_drawtype, color);
+ break;
+ case OB_EMPTY_IMAGE:
+ OVERLAY_image_empty_cache_populate(vedata, ob);
+ break;
+ }
+}
+
+static void OVERLAY_bounds(
+ OVERLAY_ExtraCallBuffers *cb, Object *ob, int theme_id, char boundtype, bool around_origin)
+{
+ float color[4], center[3], size[3], tmp[4][4], final_mat[4][4];
+ BoundBox bb_local;
+
+ if (ob->type == OB_MBALL && !BKE_mball_is_basis(ob)) {
+ return;
+ }
+
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+
+ if (bb == NULL) {
+ const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
+ bb = &bb_local;
+ BKE_boundbox_init_from_minmax(bb, min, max);
+ }
+
+ UI_GetThemeColor4fv(theme_id, color);
+ BKE_boundbox_calc_size_aabb(bb, size);
+
+ if (around_origin) {
+ zero_v3(center);
+ }
+ else {
+ BKE_boundbox_calc_center_aabb(bb, center);
+ }
+
+ switch (boundtype) {
+ case OB_BOUND_BOX:
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_cube, color, tmp);
+ break;
+ case OB_BOUND_SPHERE:
+ size[0] = max_fff(size[0], size[1], size[2]);
+ size[1] = size[2] = size[0];
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_sphere, color, tmp);
+ break;
+ case OB_BOUND_CYLINDER:
+ size[0] = max_ff(size[0], size[1]);
+ size[1] = size[0];
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_cylinder, color, tmp);
+ break;
+ case OB_BOUND_CONE:
+ size[0] = max_ff(size[0], size[1]);
+ size[1] = size[0];
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ /* Cone batch has base at 0 and is pointing towards +Y. */
+ swap_v3_v3(tmp[1], tmp[2]);
+ tmp[3][2] -= size[2];
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_cone, color, tmp);
+ break;
+ case OB_BOUND_CAPSULE:
+ size[0] = max_ff(size[0], size[1]);
+ size[1] = size[0];
+ scale_m4_fl(tmp, size[0]);
+ copy_v2_v2(tmp[3], center);
+ tmp[3][2] = center[2] + max_ff(0.0f, size[2] - size[0]);
+ mul_m4_m4m4(final_mat, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_capsule_cap, color, final_mat);
+ negate_v3(tmp[2]);
+ tmp[3][2] = center[2] - max_ff(0.0f, size[2] - size[0]);
+ mul_m4_m4m4(final_mat, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_capsule_cap, color, final_mat);
+ tmp[2][2] = max_ff(0.0f, size[2] * 2.0f - size[0] * 2.0f);
+ mul_m4_m4m4(final_mat, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_capsule_body, color, final_mat);
+ break;
+ }
+}
+
+static void OVERLAY_collision(OVERLAY_ExtraCallBuffers *cb, Object *ob, int theme_id)
+{
+ switch (ob->rigidbody_object->shape) {
+ case RB_SHAPE_BOX:
+ OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_BOX, true);
+ break;
+ case RB_SHAPE_SPHERE:
+ OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_SPHERE, true);
+ break;
+ case RB_SHAPE_CONE:
+ OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_CONE, true);
+ break;
+ case RB_SHAPE_CYLINDER:
+ OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_CYLINDER, true);
+ break;
+ case RB_SHAPE_CAPSULE:
+ OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_CAPSULE, true);
+ break;
+ }
+}
+
+static void OVERLAY_texture_space(OVERLAY_ExtraCallBuffers *cb, Object *ob, int theme_id)
+{
+ if (ob->data == NULL) {
+ return;
+ }
+
+ ID *ob_data = ob->data;
+ float *texcoloc = NULL;
+ float *texcosize = NULL;
+
+ switch (GS(ob_data->name)) {
+ case ID_ME:
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
+ break;
+ case ID_CU: {
+ Curve *cu = (Curve *)ob_data;
+ BKE_curve_texspace_ensure(cu);
+ texcoloc = cu->loc;
+ texcosize = cu->size;
+ break;
+ }
+ case ID_MB: {
+ MetaBall *mb = (MetaBall *)ob_data;
+ texcoloc = mb->loc;
+ texcosize = mb->size;
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+
+ float mat[4][4], color[4];
+ size_to_mat4(mat, texcosize);
+ copy_v3_v3(mat[3], texcoloc);
+
+ mul_m4_m4m4(mat, ob->obmat, mat);
+
+ UI_GetThemeColor4fv(theme_id, color);
+
+ DRW_buffer_add_entry(cb->empty_cube, color, mat);
+}
+
+static void OVERLAY_forcefield(OVERLAY_ExtraCallBuffers *cb, Object *ob, ViewLayer *view_layer)
+{
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ float *color = DRW_color_background_blend_get(theme_id);
+ PartDeflect *pd = ob->pd;
+ Curve *cu = (ob->type == OB_CURVE) ? ob->data : NULL;
+
+ union {
+ float mat[4][4];
+ struct {
+ float _pad00[3], size_x;
+ float _pad01[3], size_y;
+ float _pad02[3], size_z;
+ float pos[3], _pad03[1];
+ };
+ } instdata;
+
+ copy_m4_m4(instdata.mat, ob->obmat);
+ instdata.size_x = instdata.size_y = instdata.size_z = ob->empty_drawsize;
+
+ switch (pd->forcefield) {
+ case PFIELD_FORCE:
+ DRW_buffer_add_entry(cb->field_force, color, &instdata);
+ break;
+ case PFIELD_WIND:
+ instdata.size_z = pd->f_strength;
+ DRW_buffer_add_entry(cb->field_wind, color, &instdata);
+ break;
+ case PFIELD_VORTEX:
+ instdata.size_y = (pd->f_strength < 0.0f) ? -instdata.size_y : instdata.size_y;
+ DRW_buffer_add_entry(cb->field_vortex, color, &instdata);
+ break;
+ case PFIELD_GUIDE:
+ if (cu && (cu->flag & CU_PATH) && ob->runtime.curve_cache->path &&
+ ob->runtime.curve_cache->path->data) {
+ instdata.size_x = instdata.size_y = instdata.size_z = pd->f_strength;
+ float pos[3], tmp[3];
+ where_on_path(ob, 0.0f, pos, tmp, NULL, NULL, NULL);
+ copy_v3_v3(instdata.pos, ob->obmat[3]);
+ translate_m4(instdata.mat, pos[0], pos[1], pos[2]);
+ DRW_buffer_add_entry(cb->field_curve, color, &instdata);
+
+ where_on_path(ob, 1.0f, pos, tmp, NULL, NULL, NULL);
+ copy_v3_v3(instdata.pos, ob->obmat[3]);
+ translate_m4(instdata.mat, pos[0], pos[1], pos[2]);
+ DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata);
+ /* Restore */
+ copy_v3_v3(instdata.pos, ob->obmat[3]);
+ }
+ break;
+ }
+
+ if (pd->falloff == PFIELD_FALL_TUBE) {
+ if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+ instdata.size_z = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
+ instdata.size_x = (pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f;
+ instdata.size_y = instdata.size_x;
+ DRW_buffer_add_entry(cb->field_tube_limit, color, &instdata);
+ }
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ instdata.size_z = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
+ instdata.size_x = (pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f;
+ instdata.size_y = instdata.size_x;
+ DRW_buffer_add_entry(cb->field_tube_limit, color, &instdata);
+ }
+ }
+ else if (pd->falloff == PFIELD_FALL_CONE) {
+ if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+ float radius = DEG2RADF((pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f);
+ float distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
+ instdata.size_x = distance * sinf(radius);
+ instdata.size_z = distance * cosf(radius);
+ instdata.size_y = instdata.size_x;
+ DRW_buffer_add_entry(cb->field_cone_limit, color, &instdata);
+ }
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ float radius = DEG2RADF((pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f);
+ float distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
+ instdata.size_x = distance * sinf(radius);
+ instdata.size_z = distance * cosf(radius);
+ instdata.size_y = instdata.size_x;
+ DRW_buffer_add_entry(cb->field_cone_limit, color, &instdata);
+ }
+ }
+ else if (pd->falloff == PFIELD_FALL_SPHERE) {
+ if (pd->flag & PFIELD_USEMAX) {
+ instdata.size_x = instdata.size_y = instdata.size_z = pd->maxdist;
+ DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata);
+ }
+ if (pd->flag & PFIELD_USEMIN) {
+ instdata.size_x = instdata.size_y = instdata.size_z = pd->mindist;
+ DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lights
+ * \{ */
+
+void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ Light *la = ob->data;
+ float *color_p;
+ DRW_object_wire_theme_get(ob, view_layer, &color_p);
+ /* Remove the alpha. */
+ float color[4] = {color_p[0], color_p[1], color_p[2], 1.0f};
+ /* Pack render data into object matrix. */
+ union {
+ float mat[4][4];
+ struct {
+ float _pad00[3];
+ union {
+ float area_size_x;
+ float spot_cosine;
+ };
+ float _pad01[3];
+ union {
+ float area_size_y;
+ float spot_blend;
+ };
+ float _pad02[3], clip_sta;
+ float pos[3], clip_end;
+ };
+ } instdata;
+
+ copy_m4_m4(instdata.mat, ob->obmat);
+ /* FIXME / TODO: clipend has no meaning nowadays.
+ * In EEVEE, Only clipsta is used shadowmaping.
+ * Clip end is computed automatically based on light power. */
+ instdata.clip_end = la->clipend;
+ instdata.clip_sta = la->clipsta;
+
+ DRW_buffer_add_entry(cb->groundline, instdata.pos);
+
+ if (la->type == LA_LOCAL) {
+ instdata.area_size_x = instdata.area_size_y = la->area_size;
+ DRW_buffer_add_entry(cb->light_point, color, &instdata);
+ }
+ else if (la->type == LA_SUN) {
+ DRW_buffer_add_entry(cb->light_sun, color, &instdata);
+ }
+ else if (la->type == LA_SPOT) {
+ /* For cycles and eevee the spot attenuation is
+ * y = (1/(1 + x^2) - a)/((1 - a) b)
+ * We solve the case where spot attenuation y = 1 and y = 0
+ * root for y = 1 is (-1 - c) / c
+ * root for y = 0 is (1 - a) / a
+ * and use that to position the blend circle. */
+ float a = cosf(la->spotsize * 0.5f);
+ float b = la->spotblend;
+ float c = a * b - a - b;
+ /* Optimized version or root1 / root0 */
+ instdata.spot_blend = sqrtf((-a - c * a) / (c - c * a));
+ instdata.spot_cosine = a;
+ /* HACK: We pack the area size in alpha color. This is decoded by the shader. */
+ color[3] = -max_ff(la->area_size, FLT_MIN);
+ DRW_buffer_add_entry(cb->light_spot, color, &instdata);
+
+ if ((la->mode & LA_SHOW_CONE) && !DRW_state_is_select()) {
+ float color_inside[4] = {0.0f, 0.0f, 0.0f, 0.5f};
+ float color_outside[4] = {1.0f, 1.0f, 1.0f, 0.3f};
+ DRW_buffer_add_entry(cb->light_spot_cone_front, color_inside, &instdata);
+ DRW_buffer_add_entry(cb->light_spot_cone_back, color_outside, &instdata);
+ }
+ }
+ else if (la->type == LA_AREA) {
+ bool uniform_scale = !ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE);
+ int sqr = ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_RECT);
+ instdata.area_size_x = la->area_size;
+ instdata.area_size_y = uniform_scale ? la->area_size : la->area_sizey;
+ DRW_buffer_add_entry(cb->light_area[sqr], color, &instdata);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lightprobe
+ * \{ */
+
+void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ float *color_p;
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color_p);
+ const LightProbe *prb = (LightProbe *)ob->data;
+ const bool show_clipping = (prb->flag & LIGHTPROBE_FLAG_SHOW_CLIP_DIST) != 0;
+ const bool show_parallax = (prb->flag & LIGHTPROBE_FLAG_SHOW_PARALLAX) != 0;
+ const bool show_influence = (prb->flag & LIGHTPROBE_FLAG_SHOW_INFLUENCE) != 0;
+ const bool show_data = (ob->base_flag & BASE_SELECTED) || DRW_state_is_select();
+
+ union {
+ float mat[4][4];
+ struct {
+ float _pad00[4];
+ float _pad01[4];
+ float _pad02[3], clip_sta;
+ float pos[3], clip_end;
+ };
+ } instdata;
+
+ copy_m4_m4(instdata.mat, ob->obmat);
+
+ switch (prb->type) {
+ case LIGHTPROBE_TYPE_CUBE:
+ instdata.clip_sta = show_clipping ? prb->clipsta : -1.0;
+ instdata.clip_end = show_clipping ? prb->clipend : -1.0;
+ DRW_buffer_add_entry(cb->probe_grid, color_p, &instdata);
+ DRW_buffer_add_entry(cb->groundline, instdata.pos);
+
+ if (show_influence) {
+ char shape = (prb->attenuation_type == LIGHTPROBE_SHAPE_BOX) ? OB_CUBE : OB_EMPTY_SPHERE;
+ float f = 1.0f - prb->falloff;
+ OVERLAY_empty_shape(cb, ob->obmat, prb->distinf, shape, color_p);
+ OVERLAY_empty_shape(cb, ob->obmat, prb->distinf * f, shape, color_p);
+ }
+
+ if (show_parallax) {
+ char shape = (prb->parallax_type == LIGHTPROBE_SHAPE_BOX) ? OB_CUBE : OB_EMPTY_SPHERE;
+ float dist = ((prb->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) ? prb->distpar :
+ prb->distinf;
+ OVERLAY_empty_shape(cb, ob->obmat, dist, shape, color_p);
+ }
+ break;
+ case LIGHTPROBE_TYPE_GRID:
+ instdata.clip_sta = show_clipping ? prb->clipsta : -1.0;
+ instdata.clip_end = show_clipping ? prb->clipend : -1.0;
+ DRW_buffer_add_entry(cb->probe_grid, color_p, &instdata);
+
+ if (show_influence) {
+ float f = 1.0f - prb->falloff;
+ OVERLAY_empty_shape(cb, ob->obmat, 1.0 + prb->distinf, OB_CUBE, color_p);
+ OVERLAY_empty_shape(cb, ob->obmat, 1.0 + prb->distinf * f, OB_CUBE, color_p);
+ }
+
+ /* Data dots */
+ if (show_data) {
+ instdata.mat[0][3] = prb->grid_resolution_x;
+ instdata.mat[1][3] = prb->grid_resolution_y;
+ instdata.mat[2][3] = prb->grid_resolution_z;
+ /* Put theme id in matrix. */
+ if (UNLIKELY(ob->base_flag & BASE_FROM_DUPLI)) {
+ instdata.mat[3][3] = 0.0;
+ }
+ else if (theme_id == TH_ACTIVE) {
+ instdata.mat[3][3] = 1.0;
+ }
+ else /* TH_SELECT */ {
+ instdata.mat[3][3] = 2.0;
+ }
+
+ uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
+ DRWShadingGroup *grp = DRW_shgroup_create_sub(vedata->stl->pd->extra_grid_grp);
+ DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[0]", instdata.mat[0]);
+ DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[1]", instdata.mat[1]);
+ DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[2]", instdata.mat[2]);
+ DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[3]", instdata.mat[3]);
+ DRW_shgroup_call_procedural_points(grp, NULL, cell_count);
+ }
+ break;
+ case LIGHTPROBE_TYPE_PLANAR:
+ DRW_buffer_add_entry(cb->probe_planar, color_p, &instdata);
+
+ if (DRW_state_is_select() && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ DRW_buffer_add_entry(cb->solid_quad, color_p, &instdata);
+ }
+
+ if (show_influence) {
+ normalize_v3_length(instdata.mat[2], prb->distinf);
+ DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata);
+ mul_v3_fl(instdata.mat[2], 1.0f - prb->falloff);
+ DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata);
+ }
+ zero_v3(instdata.mat[2]);
+ DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata);
+
+ normalize_m4_m4(instdata.mat, ob->obmat);
+ OVERLAY_empty_shape(cb, instdata.mat, ob->empty_drawsize, OB_SINGLE_ARROW, color_p);
+ break;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Speaker
+ * \{ */
+
+void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ float *color_p;
+ DRW_object_wire_theme_get(ob, view_layer, &color_p);
+
+ DRW_buffer_add_entry(cb->speaker, color_p, ob->obmat);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera
+ * \{ */
+
+typedef union OVERLAY_CameraInstanceData {
+ /* Pack render data into object matrix and object color. */
+ struct {
+ float color[4];
+ float mat[4][4];
+ };
+ struct {
+ float _pad0[2];
+ float volume_sta;
+ union {
+ float depth;
+ float focus;
+ float volume_end;
+ };
+ float _pad00[3];
+ union {
+ float corner_x;
+ float dist_color_id;
+ };
+ float _pad01[3];
+ union {
+ float corner_y;
+ };
+ float _pad02[3];
+ union {
+ float center_x;
+ float clip_sta;
+ float mist_sta;
+ };
+ float pos[3];
+ union {
+ float center_y;
+ float clip_end;
+ float mist_end;
+ };
+ };
+} OVERLAY_CameraInstanceData;
+
+static void camera_view3d_reconstruction(OVERLAY_ExtraCallBuffers *cb,
+ Scene *scene,
+ View3D *v3d,
+ Object *camera_object,
+ Object *ob,
+ const float color[4])
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool is_select = DRW_state_is_select();
+ const Object *orig_camera_object = DEG_get_original_object(camera_object);
+
+ MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
+ if (clip == NULL) {
+ return;
+ }
+
+ const bool is_solid_bundle = (v3d->bundle_drawtype == OB_EMPTY_SPHERE) &&
+ ((v3d->shading.type != OB_SOLID) || !XRAY_FLAG_ENABLED(v3d));
+
+ MovieTracking *tracking = &clip->tracking;
+ /* Index must start in 1, to mimic BKE_tracking_track_get_indexed. */
+ int track_index = 1;
+
+ uchar text_color_selected[4], text_color_unselected[4];
+ float bundle_color_unselected[4], bundle_color_solid[4];
+
+ UI_GetThemeColor4ubv(TH_SELECT, text_color_selected);
+ UI_GetThemeColor4ubv(TH_TEXT, text_color_unselected);
+ UI_GetThemeColor4fv(TH_WIRE, bundle_color_unselected);
+ UI_GetThemeColor4fv(TH_BUNDLE_SOLID, bundle_color_solid);
+
+ float camera_mat[4][4], normal_mat[4][4];
+ BKE_tracking_get_camera_object_matrix(scene, ob, camera_mat);
+
+ normalize_m4_m4(normal_mat, ob->obmat);
+
+ LISTBASE_FOREACH (MovieTrackingObject *, tracking_object, &tracking->objects) {
+ float tracking_object_mat[4][4];
+
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ copy_m4_m4(tracking_object_mat, camera_mat);
+ }
+ else {
+ const int framenr = BKE_movieclip_remap_scene_to_clip_frame(
+ clip, DEG_get_ctime(draw_ctx->depsgraph));
+ float object_mat[4][4];
+ BKE_tracking_camera_get_reconstructed_interpolate(
+ tracking, tracking_object, framenr, object_mat);
+
+ invert_m4(object_mat);
+ mul_m4_m4m4(tracking_object_mat, normal_mat, object_mat);
+ }
+
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ for (MovieTrackingTrack *track = tracksbase->first; track; track = track->next) {
+ if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
+ continue;
+ }
+ bool is_selected = TRACK_SELECTED(track);
+
+ float bundle_mat[4][4];
+ copy_m4_m4(bundle_mat, tracking_object_mat);
+ translate_m4(bundle_mat, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+
+ const float *bundle_color;
+ if (track->flag & TRACK_CUSTOMCOLOR) {
+ bundle_color = track->color;
+ }
+ else if (is_solid_bundle) {
+ bundle_color = bundle_color_solid;
+ }
+ else if (is_selected) {
+ bundle_color = color;
+ }
+ else {
+ bundle_color = bundle_color_unselected;
+ }
+
+ if (is_select) {
+ DRW_select_load_id(orig_camera_object->runtime.select_id | (track_index << 16));
+ track_index++;
+ }
+
+ if (is_solid_bundle) {
+ if (is_selected) {
+ OVERLAY_empty_shape(cb, bundle_mat, v3d->bundle_size, v3d->bundle_drawtype, color);
+ }
+
+ const float bundle_color_v4[4] = {
+ bundle_color[0],
+ bundle_color[1],
+ bundle_color[2],
+ 1.0f,
+ };
+
+ bundle_mat[3][3] = v3d->bundle_size; /* See shader. */
+ DRW_buffer_add_entry(cb->empty_sphere_solid, bundle_color_v4, bundle_mat);
+ }
+ else {
+ OVERLAY_empty_shape(cb, bundle_mat, v3d->bundle_size, v3d->bundle_drawtype, bundle_color);
+ }
+
+ if ((v3d->flag2 & V3D_SHOW_BUNDLENAME) && !is_select) {
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+
+ DRW_text_cache_add(dt,
+ bundle_mat[3],
+ track->name,
+ strlen(track->name),
+ 10,
+ 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ is_selected ? text_color_selected : text_color_unselected);
+ }
+ }
+
+ if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA) &&
+ !is_select) {
+ MovieTrackingReconstruction *reconstruction;
+ reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
+
+ if (reconstruction->camnr) {
+ MovieReconstructedCamera *camera = reconstruction->cameras;
+ float v0[3], v1[3];
+ for (int a = 0; a < reconstruction->camnr; a++, camera++) {
+ copy_v3_v3(v0, v1);
+ copy_v3_v3(v1, camera->mat[3]);
+ mul_m4_v3(camera_mat, v1);
+ if (a > 0) {
+ /* This one is suboptimal (gl_lines instead of gl_line_strip)
+ * but we keep this for simplicity */
+ OVERLAY_extra_line(cb, v0, v1, TH_CAMERA_PATH);
+ }
+ }
+ }
+ }
+ }
+}
+
+static float camera_offaxis_shiftx_get(Scene *scene,
+ Object *ob,
+ const OVERLAY_CameraInstanceData *instdata,
+ bool right_eye)
+{
+ Camera *cam = ob->data;
+ if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
+ const char *viewnames[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ const float shiftx = BKE_camera_multiview_shift_x(&scene->r, ob, viewnames[right_eye]);
+ const float delta_shiftx = shiftx - cam->shiftx;
+ const float width = instdata->corner_x * 2.0f;
+ return delta_shiftx * width;
+ }
+ else {
+ return 0.0;
+ }
+}
+/**
+ * Draw the stereo 3d support elements (cameras, plane, volume).
+ * They are only visible when not looking through the camera:
+ */
+static void camera_stereoscopy_extra(OVERLAY_ExtraCallBuffers *cb,
+ Scene *scene,
+ View3D *v3d,
+ Object *ob,
+ const OVERLAY_CameraInstanceData *instdata)
+{
+ OVERLAY_CameraInstanceData stereodata = *instdata;
+ Camera *cam = ob->data;
+ const bool is_select = DRW_state_is_select();
+ const char *viewnames[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) != 0;
+ const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) != 0;
+ const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME) != 0;
+
+ for (int eye = 0; eye < 2; eye++) {
+ ob = BKE_camera_multiview_render(scene, ob, viewnames[eye]);
+ BKE_camera_multiview_model_matrix(&scene->r, ob, viewnames[eye], stereodata.mat);
+
+ stereodata.corner_x = instdata->corner_x;
+ stereodata.corner_y = instdata->corner_y;
+ stereodata.center_x = instdata->center_x + camera_offaxis_shiftx_get(scene, ob, instdata, eye);
+ stereodata.center_y = instdata->center_y;
+ stereodata.depth = instdata->depth;
+
+ if (is_stereo3d_cameras) {
+ DRW_buffer_add_entry_struct(cb->camera_frame, &stereodata);
+
+ /* Connecting line between cameras. */
+ OVERLAY_extra_line_dashed(cb, stereodata.pos, instdata->pos, G_draw.block.colorWire);
+ }
+
+ if (is_stereo3d_volume && !is_select) {
+ float r = (eye == 1) ? 2.0f : 1.0f;
+
+ stereodata.volume_sta = -cam->clip_start;
+ stereodata.volume_end = -cam->clip_end;
+ /* Encode eye + intensity and alpha (see shader) */
+ copy_v2_fl2(stereodata.color, r + 0.15f, 1.0f);
+ DRW_buffer_add_entry_struct(cb->camera_volume_frame, &stereodata);
+
+ if (v3d->stereo3d_volume_alpha > 0.0f) {
+ /* Encode eye + intensity and alpha (see shader) */
+ copy_v2_fl2(stereodata.color, r + 0.999f, v3d->stereo3d_volume_alpha);
+ DRW_buffer_add_entry_struct(cb->camera_volume, &stereodata);
+ }
+ /* restore */
+ copy_v3_v3(stereodata.color, instdata->color);
+ }
+ }
+
+ if (is_stereo3d_plane && !is_select) {
+ if (cam->stereo.convergence_mode == CAM_S3D_TOE) {
+ /* There is no real convergence plane but we highlight the center
+ * point where the views are pointing at. */
+ // zero_v3(stereodata.mat[0]); /* We reconstruct from Z and Y */
+ // zero_v3(stereodata.mat[1]); /* Y doesn't change */
+ zero_v3(stereodata.mat[2]);
+ zero_v3(stereodata.mat[3]);
+ for (int i = 0; i < 2; i++) {
+ float mat[4][4];
+ /* Need normalized version here. */
+ BKE_camera_multiview_model_matrix(&scene->r, ob, viewnames[i], mat);
+ add_v3_v3(stereodata.mat[2], mat[2]);
+ madd_v3_v3fl(stereodata.mat[3], mat[3], 0.5f);
+ }
+ normalize_v3(stereodata.mat[2]);
+ cross_v3_v3v3(stereodata.mat[0], stereodata.mat[1], stereodata.mat[2]);
+ }
+ else if (cam->stereo.convergence_mode == CAM_S3D_PARALLEL) {
+ /* Show plane at the given distance between the views even if it makes no sense. */
+ zero_v3(stereodata.pos);
+ for (int i = 0; i < 2; i++) {
+ float mat[4][4];
+ BKE_camera_multiview_model_matrix_scaled(&scene->r, ob, viewnames[i], mat);
+ madd_v3_v3fl(stereodata.pos, mat[3], 0.5f);
+ }
+ }
+ else if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
+ /* Nothing to do. Everything is already setup. */
+ }
+ stereodata.volume_sta = -cam->stereo.convergence_distance;
+ stereodata.volume_end = -cam->stereo.convergence_distance;
+ /* Encode eye + intensity and alpha (see shader) */
+ copy_v2_fl2(stereodata.color, 0.1f, 1.0f);
+ DRW_buffer_add_entry_struct(cb->camera_volume_frame, &stereodata);
+
+ if (v3d->stereo3d_convergence_alpha > 0.0f) {
+ /* Encode eye + intensity and alpha (see shader) */
+ copy_v2_fl2(stereodata.color, 0.0f, v3d->stereo3d_convergence_alpha);
+ DRW_buffer_add_entry_struct(cb->camera_volume, &stereodata);
+ }
+ }
+}
+
+void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ OVERLAY_CameraInstanceData instdata;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
+ Camera *cam = ob->data;
+ Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+ const bool is_select = DRW_state_is_select();
+ const bool is_active = (ob == camera_object);
+ const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB));
+
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+ const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+ const bool is_stereo3d_display_extra = is_active && is_multiview && (!look_through) &&
+ ((v3d->stereo3d_flag) != 0);
+ const bool is_selection_camera_stereo = is_select && look_through && is_multiview &&
+ is_stereo3d_view;
+
+ float vec[4][3], asp[2], shift[2], scale[3], drawsize, center[2], corner[2];
+
+ float *color_p;
+ DRW_object_wire_theme_get(ob, view_layer, &color_p);
+ copy_v4_v4(instdata.color, color_p);
+
+ normalize_m4_m4(instdata.mat, ob->obmat);
+
+ /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here. */
+ if (is_selection_camera_stereo) {
+ copy_v3_fl(scale, 1.0f);
+ }
+ else {
+ copy_v3_fl3(scale, len_v3(ob->obmat[0]), len_v3(ob->obmat[1]), len_v3(ob->obmat[2]));
+ invert_v3(scale);
+ }
+
+ BKE_camera_view_frame_ex(
+ scene, cam, cam->drawsize, look_through, scale, asp, shift, &drawsize, vec);
+
+ /* Apply scale to simplify the rest of the drawing. */
+ invert_v3(scale);
+ for (int i = 0; i < 4; i++) {
+ mul_v3_v3(vec[i], scale);
+ /* Project to z=-1 plane. Makes positionning / scaling easier. (see shader) */
+ mul_v2_fl(vec[i], 1.0f / fabsf(vec[i][2]));
+ }
+
+ /* Frame coords */
+ mid_v2_v2v2(center, vec[0], vec[2]);
+ sub_v2_v2v2(corner, vec[0], center);
+ instdata.corner_x = corner[0];
+ instdata.corner_y = corner[1];
+ instdata.center_x = center[0];
+ instdata.center_y = center[1];
+ instdata.depth = vec[0][2];
+
+ if (look_through) {
+ if (!DRW_state_is_image_render()) {
+ /* Only draw the frame. */
+ if (is_multiview) {
+ float mat[4][4];
+ const bool is_right = v3d->multiview_eye == STEREO_RIGHT_ID;
+ const char *view_name = is_right ? STEREO_RIGHT_NAME : STEREO_LEFT_NAME;
+ BKE_camera_multiview_model_matrix(&scene->r, ob, view_name, mat);
+ instdata.center_x += camera_offaxis_shiftx_get(scene, ob, &instdata, is_right);
+ for (int i = 0; i < 4; i++) {
+ /* Partial copy to avoid overriding packed data. */
+ copy_v3_v3(instdata.mat[i], mat[i]);
+ }
+ }
+ instdata.depth = -instdata.depth; /* Hides the back of the camera wires (see shader). */
+ DRW_buffer_add_entry_struct(cb->camera_frame, &instdata);
+ }
+ }
+ else {
+ /* Stereo cameras, volumes, plane drawing. */
+ if (is_stereo3d_display_extra) {
+ camera_stereoscopy_extra(cb, scene, v3d, ob, &instdata);
+ }
+ else {
+ DRW_buffer_add_entry_struct(cb->camera_frame, &instdata);
+ }
+ }
+
+ if (!look_through) {
+ /* Triangle. */
+ float tria_size = 0.7f * drawsize / fabsf(instdata.depth);
+ float tria_margin = 0.1f * drawsize / fabsf(instdata.depth);
+ instdata.center_x = center[0];
+ instdata.center_y = center[1] + instdata.corner_y + tria_margin + tria_size;
+ instdata.corner_x = instdata.corner_y = -tria_size;
+ DRW_buffer_add_entry_struct(cb->camera_tria[is_active], &instdata);
+ }
+
+ if (cam->flag & CAM_SHOWLIMITS) {
+ /* Scale focus point. */
+ mul_v3_fl(instdata.mat[0], cam->drawsize);
+ mul_v3_fl(instdata.mat[1], cam->drawsize);
+
+ instdata.dist_color_id = (is_active) ? 3 : 2;
+ instdata.focus = -BKE_camera_object_dof_distance(ob);
+ instdata.clip_sta = cam->clip_start;
+ instdata.clip_end = cam->clip_end;
+ DRW_buffer_add_entry_struct(cb->camera_distances, &instdata);
+ }
+
+ if (cam->flag & CAM_SHOWMIST) {
+ World *world = scene->world;
+ if (world) {
+ instdata.dist_color_id = (is_active) ? 1 : 0;
+ instdata.focus = 1.0f; /* Disable */
+ instdata.mist_sta = world->miststa;
+ instdata.mist_end = world->miststa + world->mistdist;
+ DRW_buffer_add_entry_struct(cb->camera_distances, &instdata);
+ }
+ }
+
+ /* Motion Tracking. */
+ if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) != 0) {
+ camera_view3d_reconstruction(cb, scene, v3d, camera_object, ob, color_p);
+ }
+
+ /* Background images. */
+ if (look_through && (cam->flag & CAM_SHOW_BG_IMAGE) && !BLI_listbase_is_empty(&cam->bg_images)) {
+ OVERLAY_image_camera_cache_populate(vedata, ob);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Relationships & constraints
+ * \{ */
+
+static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
+{
+ float *relation_color = G_draw.block.colorWire;
+ float *constraint_color = G_draw.block.colorGridAxisZ; /* ? */
+
+ if (ob->parent && (DRW_object_visibility_in_active_context(ob->parent) & OB_VISIBLE_SELF)) {
+ float *parent_pos = ob->runtime.parent_display_origin;
+ OVERLAY_extra_line_dashed(cb, parent_pos, ob->obmat[3], relation_color);
+ }
+
+ if (ob->rigidbody_constraint) {
+ Object *rbc_ob1 = ob->rigidbody_constraint->ob1;
+ Object *rbc_ob2 = ob->rigidbody_constraint->ob2;
+ if (rbc_ob1 && (DRW_object_visibility_in_active_context(rbc_ob1) & OB_VISIBLE_SELF)) {
+ OVERLAY_extra_line_dashed(cb, rbc_ob1->obmat[3], ob->obmat[3], relation_color);
+ }
+ if (rbc_ob2 && (DRW_object_visibility_in_active_context(rbc_ob2) & OB_VISIBLE_SELF)) {
+ OVERLAY_extra_line_dashed(cb, rbc_ob2->obmat[3], ob->obmat[3], relation_color);
+ }
+ }
+
+ /* Drawing the constraint lines */
+ if (!BLI_listbase_is_empty(&ob->constraints)) {
+ bConstraint *curcon;
+ bConstraintOb *cob;
+ ListBase *list = &ob->constraints;
+
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+
+ for (curcon = list->first; curcon; curcon = curcon->next) {
+ if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+ /* special case for object solver and follow track constraints because they don't fill
+ * constraint targets properly (design limitation -- scene is needed for their target
+ * but it can't be accessed from get_targets callback) */
+ Object *camob = NULL;
+
+ if (curcon->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
+ bFollowTrackConstraint *data = (bFollowTrackConstraint *)curcon->data;
+ camob = data->camera ? data->camera : scene->camera;
+ }
+ else if (curcon->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ bObjectSolverConstraint *data = (bObjectSolverConstraint *)curcon->data;
+ camob = data->camera ? data->camera : scene->camera;
+ }
+
+ if (camob) {
+ OVERLAY_extra_line_dashed(cb, camob->obmat[3], ob->obmat[3], constraint_color);
+ }
+ }
+ else {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+
+ if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) {
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* calculate target's matrix */
+ if (cti->get_target_matrix) {
+ cti->get_target_matrix(depsgraph, curcon, cob, ct, DEG_get_ctime(depsgraph));
+ }
+ else {
+ unit_m4(ct->matrix);
+ }
+ 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_constraints_clear_evalob(cob);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GPencil.
+ * \{ */
+
+static void OVERLAY_gpencil_color_names(Object *ob)
+{
+ if (ob->mode != OB_MODE_EDIT_GPENCIL) {
+ return;
+ }
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (gpd == NULL) {
+ return;
+ }
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ uchar color[4];
+ UI_GetThemeColor4ubv(theme_id, color);
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_HIDE) {
+ continue;
+ }
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL) {
+ continue;
+ }
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ Material *ma = give_current_material(ob, gps->mat_nr + 1);
+ if (ma == NULL) {
+ continue;
+ }
+
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* skip stroke if it doesn't have any valid data */
+ if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
+ continue;
+ }
+ /* check if the color is visible */
+ if (gp_style->flag & GP_STYLE_COLOR_HIDE) {
+ continue;
+ }
+
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ float fpt[3];
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if (pt->flag & GP_SPOINT_SELECT) {
+ mul_v3_m4v3(fpt, ob->obmat, &pt->x);
+ DRW_text_cache_add(dt,
+ fpt,
+ ma->id.name + 2,
+ strlen(ma->id.name + 2),
+ 10,
+ 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ color);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void OVERLAY_gpencil_cache_populate(OVERLAY_Data *UNUSED(vedata), Object *ob)
+{
+ /* don't show object extras in set's */
+ if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
+ if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) {
+ OVERLAY_gpencil_color_names(ob);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Volumetric / Smoke sim
+ * \{ */
+
+static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb,
+ OVERLAY_Data *data,
+ Object *ob,
+ ModifierData *md,
+ Scene *scene,
+ float *color)
+{
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ FluidDomainSettings *mds = mmd->domain;
+
+ /* Don't show smoke before simulation starts, this could be made an option in the future. */
+ const bool draw_velocity = (mds->draw_velocity && mds->fluid &&
+ CFRA >= mds->point_cache[0]->startframe);
+
+ /* Small cube showing voxel size. */
+ {
+ float min[3];
+ madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, mds->cell_size, mds->res_min);
+ float voxel_cubemat[4][4] = {{0.0f}};
+ /* scale small cube to voxel size */
+ voxel_cubemat[0][0] = 1.0f / (float)mds->base_res[0];
+ voxel_cubemat[1][1] = 1.0f / (float)mds->base_res[1];
+ voxel_cubemat[2][2] = 1.0f / (float)mds->base_res[2];
+ voxel_cubemat[3][3] = 1.0f;
+ /* translate small cube to corner */
+ copy_v3_v3(voxel_cubemat[3], min);
+ /* move small cube into the domain (otherwise its centered on vertex of domain object) */
+ translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f);
+ mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat);
+
+ DRW_buffer_add_entry(cb->empty_cube, color, voxel_cubemat);
+ }
+
+ if (draw_velocity) {
+ const bool use_needle = (mds->vector_draw_type == VECTOR_DRAW_NEEDLE);
+ int line_count = (use_needle) ? 6 : 1;
+ int slice_axis = -1;
+ line_count *= mds->res[0] * mds->res[1] * mds->res[2];
+
+ if (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED &&
+ mds->axis_slice_method == AXIS_SLICE_SINGLE) {
+ float viewinv[4][4];
+ DRW_view_viewmat_get(NULL, viewinv, true);
+
+ const int axis = (mds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) :
+ mds->slice_axis - 1;
+ slice_axis = axis;
+ line_count /= mds->res[axis];
+ }
+
+ GPU_create_smoke_velocity(mmd);
+
+ GPUShader *sh = OVERLAY_shader_volume_velocity(use_needle);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, data->psl->extra_ps[0]);
+ DRW_shgroup_uniform_texture(grp, "velocityX", mds->tex_velocity_x);
+ DRW_shgroup_uniform_texture(grp, "velocityY", mds->tex_velocity_y);
+ DRW_shgroup_uniform_texture(grp, "velocityZ", mds->tex_velocity_z);
+ DRW_shgroup_uniform_float_copy(grp, "displaySize", mds->vector_scale);
+ DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth);
+ DRW_shgroup_uniform_vec3_copy(grp, "cellSize", mds->cell_size);
+ DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", mds->p0);
+ DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", mds->res_min);
+ DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis);
+ DRW_shgroup_call_procedural_lines(grp, ob, line_count);
+
+ BLI_addtail(&data->stl->pd->smoke_domains, BLI_genericNodeN(mmd));
+ }
+}
+
+static void OVERLAY_volume_free_smoke_textures(OVERLAY_Data *data)
+{
+ /* Free Smoke Textures after rendering */
+ /* XXX This is a waste of processing and GPU bandwidth if nothing
+ * is updated. But the problem is since Textures are stored in the
+ * modifier we don't want them to take precious VRAM if the
+ * modifier is not used for display. We should share them for
+ * all viewport in a redraw at least. */
+ LinkData *link;
+ while ((link = BLI_pophead(&data->stl->pd->smoke_domains))) {
+ FluidModifierData *mmd = (FluidModifierData *)link->data;
+ GPU_free_smoke_velocity(mmd);
+ MEM_freeN(link);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+static void OVERLAY_object_center(OVERLAY_ExtraCallBuffers *cb,
+ Object *ob,
+ OVERLAY_PrivateData *pd,
+ ViewLayer *view_layer)
+{
+ const bool is_library = ob->id.us > 1 || ID_IS_LINKED(ob);
+
+ if (ob == OBACT(view_layer)) {
+ DRW_buffer_add_entry(cb->center_active, ob->obmat[3]);
+ }
+ else if (ob->base_flag & BASE_SELECTED) {
+ DRWCallBuffer *cbuf = (is_library) ? cb->center_selected_lib : cb->center_selected;
+ DRW_buffer_add_entry(cbuf, ob->obmat[3]);
+ }
+ else if (pd->v3d_flag & V3D_DRAW_CENTERS) {
+ DRWCallBuffer *cbuf = (is_library) ? cb->center_deselected_lib : cb->center_deselected;
+ DRW_buffer_add_entry(cbuf, ob->obmat[3]);
+ }
+}
+
+static void OVERLAY_object_name(Object *ob, int theme_id)
+{
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ uchar color[4];
+ UI_GetThemeColor4ubv(theme_id, color);
+
+ DRW_text_cache_add(dt,
+ ob->obmat[3],
+ ob->id.name + 2,
+ strlen(ob->id.name + 2),
+ 10,
+ 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ color);
+}
+
+void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ Scene *scene = draw_ctx->scene;
+ ModifierData *md = NULL;
+
+ const bool is_select_mode = DRW_state_is_select();
+ const bool is_paint_mode = (draw_ctx->object_mode &
+ (OB_MODE_ALL_PAINT | OB_MODE_ALL_PAINT_GPENCIL)) != 0;
+ const bool from_dupli = (ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) != 0;
+ const bool has_bounds = !ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_EMPTY, OB_SPEAKER, OB_LIGHTPROBE);
+ const bool has_texspace = has_bounds &&
+ !ELEM(ob->type, OB_EMPTY, OB_LATTICE, OB_ARMATURE, OB_GPENCIL);
+
+ const bool draw_relations = ((pd->v3d_flag & V3D_HIDE_HELPLINES) == 0) && !is_select_mode;
+ const bool draw_obcenters = !is_paint_mode &&
+ (pd->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_ORIGINS) == 0;
+ const bool draw_texspace = (ob->dtx & OB_TEXSPACE) && has_texspace;
+ const bool draw_obname = (ob->dtx & OB_DRAWNAME) && DRW_state_show_text();
+ const bool draw_bounds = has_bounds && ((ob->dt == OB_BOUNDBOX) ||
+ ((ob->dtx & OB_DRAWBOUNDOX) && !from_dupli));
+ const bool draw_xform = draw_ctx->object_mode == OB_MODE_OBJECT &&
+ (scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) &&
+ (ob->base_flag & BASE_SELECTED) && !is_select_mode;
+ const bool draw_volume = !from_dupli && (md = modifiers_findByType(ob, eModifierType_Fluid)) &&
+ (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
+ (((FluidModifierData *)md)->domain != NULL);
+
+ float *color;
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ if (ob->pd && ob->pd->forcefield) {
+ OVERLAY_forcefield(cb, ob, view_layer);
+ }
+
+ if (draw_bounds) {
+ OVERLAY_bounds(cb, ob, theme_id, ob->boundtype, false);
+ }
+ /* Helpers for when we're transforming origins. */
+ if (draw_xform) {
+ float color_xform[4] = {0.75f, 0.75f, 0.75f, 0.5f};
+ DRW_buffer_add_entry(cb->origin_xform, color_xform, ob->obmat);
+ }
+ /* don't show object extras in set's */
+ if (!from_dupli) {
+ if (draw_obcenters) {
+ OVERLAY_object_center(cb, ob, pd, view_layer);
+ }
+ if (draw_relations) {
+ OVERLAY_relationship_lines(cb, draw_ctx->depsgraph, draw_ctx->scene, ob);
+ }
+ if (draw_obname) {
+ OVERLAY_object_name(ob, theme_id);
+ }
+ if (draw_texspace) {
+ OVERLAY_texture_space(cb, ob, theme_id);
+ }
+ if (ob->rigidbody_object != NULL) {
+ OVERLAY_collision(cb, ob, theme_id);
+ }
+ if (ob->dtx & OB_AXIS) {
+ DRW_buffer_add_entry(cb->empty_axes, color, ob->obmat);
+ }
+ if (draw_volume) {
+ OVERLAY_volume_extra(cb, vedata, ob, md, scene, color);
+ }
+ }
+}
+
+void OVERLAY_extra_blend_draw(OVERLAY_Data *vedata)
+{
+ DRW_draw_pass(vedata->psl->extra_blend_ps);
+}
+
+void OVERLAY_extra_draw(OVERLAY_Data *vedata)
+{
+ DRW_draw_pass(vedata->psl->extra_ps[0]);
+}
+
+void OVERLAY_extra_in_front_draw(OVERLAY_Data *vedata)
+{
+ DRW_draw_pass(vedata->psl->extra_ps[1]);
+
+ OVERLAY_volume_free_smoke_textures(vedata);
+}
+
+void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->extra_grid_ps);
+ DRW_draw_pass(psl->extra_centers_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_facing.c b/source/blender/draw/engines/overlay/overlay_facing.c
new file mode 100644
index 00000000000..fd974e9b8b8
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_facing.c
@@ -0,0 +1,59 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_facing_init(OVERLAY_Data *UNUSED(vedata))
+{
+}
+
+void OVERLAY_facing_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->facing_ps, state | pd->clipping_state);
+
+ GPUShader *sh = OVERLAY_shader_facing();
+ pd->facing_grp = DRW_shgroup_create(sh, psl->facing_ps);
+ DRW_shgroup_uniform_block_persistent(pd->facing_grp, "globalsBlock", G_draw.block_ubo);
+}
+
+void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ DRW_shgroup_call(pd->facing_grp, geom, ob);
+ }
+}
+
+void OVERLAY_facing_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->facing_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c
new file mode 100644
index 00000000000..6f6ad36b4f8
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_grid.c
@@ -0,0 +1,216 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_camera_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "overlay_private.h"
+
+enum {
+ SHOW_AXIS_X = (1 << 0),
+ SHOW_AXIS_Y = (1 << 1),
+ SHOW_AXIS_Z = (1 << 2),
+ SHOW_GRID = (1 << 3),
+ PLANE_XY = (1 << 4),
+ PLANE_XZ = (1 << 5),
+ PLANE_YZ = (1 << 6),
+ CLIP_ZPOS = (1 << 7),
+ CLIP_ZNEG = (1 << 8),
+ GRID_BACK = (1 << 9),
+};
+
+void OVERLAY_grid_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_ShadingData *shd = &pd->shdata;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
+ const bool show_axis_x = (pd->v3d_gridflag & V3D_SHOW_X) != 0;
+ const bool show_axis_y = (pd->v3d_gridflag & V3D_SHOW_Y) != 0;
+ const bool show_axis_z = (pd->v3d_gridflag & V3D_SHOW_Z) != 0;
+ const bool show_floor = (pd->v3d_gridflag & V3D_SHOW_FLOOR) != 0;
+ const bool show_ortho_grid = (pd->v3d_gridflag & V3D_SHOW_ORTHO_GRID) != 0;
+
+ shd->grid_flag = 0;
+
+ if (pd->hide_overlays || !(show_axis_y || show_axis_z || show_floor || show_ortho_grid)) {
+ return;
+ }
+
+ float viewinv[4][4], wininv[4][4];
+ float viewmat[4][4], winmat[4][4];
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_winmat_get(NULL, wininv, true);
+ DRW_view_viewmat_get(NULL, viewmat, false);
+ DRW_view_viewmat_get(NULL, viewinv, true);
+
+ /* if perps */
+ if (winmat[3][3] == 0.0f || rv3d->view == RV3D_VIEW_USER) {
+ if (show_axis_x) {
+ shd->grid_flag |= PLANE_XY | SHOW_AXIS_X;
+ }
+ if (show_axis_y) {
+ shd->grid_flag |= PLANE_XY | SHOW_AXIS_Y;
+ }
+ if (show_floor) {
+ shd->grid_flag |= PLANE_XY | SHOW_GRID;
+ }
+ }
+ else {
+ if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) {
+ shd->grid_flag = PLANE_YZ | SHOW_AXIS_Y | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK;
+ }
+ else if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
+ shd->grid_flag = PLANE_XY | SHOW_AXIS_X | SHOW_AXIS_Y | SHOW_GRID | GRID_BACK;
+ }
+ else if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
+ shd->grid_flag = PLANE_XZ | SHOW_AXIS_X | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK;
+ }
+ }
+
+ shd->grid_axes[0] = (float)((shd->grid_flag & (PLANE_XZ | PLANE_XY)) != 0);
+ shd->grid_axes[1] = (float)((shd->grid_flag & (PLANE_YZ | PLANE_XY)) != 0);
+ shd->grid_axes[2] = (float)((shd->grid_flag & (PLANE_YZ | PLANE_XZ)) != 0);
+
+ /* Z axis if needed */
+ if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) {
+ shd->zpos_flag = SHOW_AXIS_Z;
+
+ float zvec[3], campos[3];
+ negate_v3_v3(zvec, viewinv[2]);
+ copy_v3_v3(campos, viewinv[3]);
+
+ /* z axis : chose the most facing plane */
+ if (fabsf(zvec[0]) < fabsf(zvec[1])) {
+ shd->zpos_flag |= PLANE_XZ;
+ }
+ else {
+ shd->zpos_flag |= PLANE_YZ;
+ }
+
+ shd->zneg_flag = shd->zpos_flag;
+
+ /* Persp : If camera is below floor plane, we switch clipping
+ * Ortho : If eye vector is looking up, we switch clipping */
+ if (((winmat[3][3] == 0.0f) && (campos[2] > 0.0f)) ||
+ ((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f))) {
+ shd->zpos_flag |= CLIP_ZPOS;
+ shd->zneg_flag |= CLIP_ZNEG;
+ }
+ else {
+ shd->zpos_flag |= CLIP_ZNEG;
+ shd->zneg_flag |= CLIP_ZPOS;
+ }
+
+ shd->zplane_axes[0] = (float)((shd->zpos_flag & (PLANE_XZ | PLANE_XY)) != 0);
+ shd->zplane_axes[1] = (float)((shd->zpos_flag & (PLANE_YZ | PLANE_XY)) != 0);
+ shd->zplane_axes[2] = (float)((shd->zpos_flag & (PLANE_YZ | PLANE_XZ)) != 0);
+ }
+ else {
+ shd->zneg_flag = shd->zpos_flag = CLIP_ZNEG | CLIP_ZPOS;
+ }
+
+ float dist;
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) {
+ Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+ dist = ((Camera *)(camera_object->data))->clip_end;
+ }
+ else {
+ dist = v3d->clip_end;
+ }
+
+ if (winmat[3][3] == 0.0f) {
+ shd->grid_mesh_size = dist;
+ }
+ else {
+ float viewdist = 1.0f / min_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1]));
+ shd->grid_mesh_size = viewdist * dist;
+ }
+
+ shd->grid_distance = dist / 2.0f;
+ shd->grid_line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f;
+
+ ED_view3d_grid_steps(scene, v3d, rv3d, shd->grid_steps);
+}
+
+void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_ShadingData *shd = &vedata->stl->pd->shdata;
+ OVERLAY_PassList *psl = vedata->psl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ psl->grid_ps = NULL;
+
+ if (shd->grid_flag == 0 || !DRW_state_is_fbo()) {
+ return;
+ }
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->grid_ps, state);
+
+ GPUShader *sh = OVERLAY_shader_grid();
+ struct GPUBatch *geom = DRW_cache_grid_get();
+
+ /* Create 3 quads to render ordered transparency Z axis */
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->grid_ps);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &shd->zneg_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->zplane_axes, 1);
+ DRW_shgroup_uniform_float(grp, "gridDistance", &shd->grid_distance, 1);
+ DRW_shgroup_uniform_float_copy(grp, "lineKernel", shd->grid_line_size);
+ DRW_shgroup_uniform_float_copy(grp, "meshSize", shd->grid_mesh_size);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call(grp, geom, NULL);
+
+ grp = DRW_shgroup_create(sh, psl->grid_ps);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &shd->grid_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->grid_axes, 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_uniform_float(grp, "gridSteps", shd->grid_steps, ARRAY_SIZE(shd->grid_steps));
+ DRW_shgroup_call(grp, geom, NULL);
+
+ grp = DRW_shgroup_create(sh, psl->grid_ps);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &shd->zpos_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->zplane_axes, 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call(grp, geom, NULL);
+}
+
+void OVERLAY_grid_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ if (psl->grid_ps) {
+ DRW_draw_pass(psl->grid_ps);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c
new file mode 100644
index 00000000000..cda55fcfb5e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_image.c
@@ -0,0 +1,481 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_camera.h"
+#include "BKE_image.h"
+#include "BKE_movieclip.h"
+#include "BKE_object.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_screen_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_image_init(OVERLAY_Data *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ DRWView *default_view = (DRWView *)DRW_view_default_get();
+ pd->view_reference_images = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, -1.0f);
+}
+
+void OVERLAY_image_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DRWState state;
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL;
+ DRW_PASS_CREATE(psl->image_background_under_ps, state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->image_background_over_ps, state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ DRW_PASS_CREATE(psl->image_empties_ps, state | pd->clipping_state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->image_empties_back_ps, state | pd->clipping_state);
+ DRW_PASS_CREATE(psl->image_empties_blend_ps, state | pd->clipping_state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->image_empties_front_ps, state);
+ DRW_PASS_CREATE(psl->image_foreground_ps, state);
+}
+
+static void overlay_image_calc_aspect(Image *ima, const int size[2], float r_image_aspect[2])
+{
+ float ima_x, ima_y;
+ if (ima) {
+ ima_x = size[0];
+ ima_y = size[1];
+ }
+ else {
+ /* if no image, make it a 1x1 empty square, honor scale & offset */
+ ima_x = ima_y = 1.0f;
+ }
+ /* Get the image aspect even if the buffer is invalid */
+ float sca_x = 1.0f, sca_y = 1.0f;
+ if (ima) {
+ if (ima->aspx > ima->aspy) {
+ sca_y = ima->aspy / ima->aspx;
+ }
+ else if (ima->aspx < ima->aspy) {
+ sca_x = ima->aspx / ima->aspy;
+ }
+ }
+
+ const float scale_x_inv = ima_x * sca_x;
+ const float scale_y_inv = ima_y * sca_y;
+ if (scale_x_inv > scale_y_inv) {
+ r_image_aspect[0] = 1.0f;
+ r_image_aspect[1] = scale_y_inv / scale_x_inv;
+ }
+ else {
+ r_image_aspect[0] = scale_x_inv / scale_y_inv;
+ r_image_aspect[1] = 1.0f;
+ }
+}
+
+static void camera_background_images_stereo_setup(Scene *scene,
+ View3D *v3d,
+ Image *ima,
+ ImageUser *iuser)
+{
+ if (BKE_image_is_stereo(ima)) {
+ iuser->flag |= IMA_SHOW_STEREO;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+ iuser->multiview_eye = STEREO_LEFT_ID;
+ }
+ else if (v3d->stereo3d_camera != STEREO_3D_ID) {
+ /* show only left or right camera */
+ iuser->multiview_eye = v3d->stereo3d_camera;
+ }
+
+ BKE_image_multiview_index(ima, iuser);
+ }
+ else {
+ iuser->flag &= ~IMA_SHOW_STEREO;
+ }
+}
+
+static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgpic,
+ const DRWContextState *draw_ctx,
+ OVERLAY_PrivateData *pd,
+ float *r_aspect,
+ bool *r_use_alpha_premult)
+{
+ Image *image = bgpic->ima;
+ ImageUser *iuser = &bgpic->iuser;
+ MovieClip *clip = NULL;
+ GPUTexture *tex = NULL;
+ Scene *scene = draw_ctx->scene;
+ float aspect_x, aspect_y;
+ int width, height;
+ int ctime = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ *r_use_alpha_premult = false;
+
+ switch (bgpic->source) {
+ case CAM_BGIMG_SOURCE_IMAGE:
+ if (image == NULL) {
+ return NULL;
+ }
+ *r_use_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL);
+
+ BKE_image_user_frame_calc(image, iuser, ctime);
+ if (image->source == IMA_SRC_SEQUENCE && !(iuser->flag & IMA_USER_FRAME_IN_RANGE)) {
+ /* Frame is out of range, dont show. */
+ return NULL;
+ }
+ else {
+ camera_background_images_stereo_setup(scene, draw_ctx->v3d, image, iuser);
+ }
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
+ if (ibuf == NULL) {
+ return NULL;
+ }
+
+ tex = GPU_texture_from_blender(image, iuser, GL_TEXTURE_2D);
+ if (tex == NULL) {
+ return NULL;
+ }
+
+ aspect_x = bgpic->ima->aspx;
+ aspect_y = bgpic->ima->aspy;
+
+ width = ibuf->x;
+ height = ibuf->y;
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ break;
+
+ case CAM_BGIMG_SOURCE_MOVIE:
+ if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
+ if (scene->camera) {
+ clip = BKE_object_movieclip_get(scene, scene->camera, true);
+ }
+ }
+ else {
+ clip = bgpic->clip;
+ }
+
+ if (clip == NULL) {
+ return NULL;
+ }
+
+ BKE_movieclip_user_set_frame(&bgpic->cuser, ctime);
+ tex = GPU_texture_from_movieclip(clip, &bgpic->cuser, GL_TEXTURE_2D);
+ if (tex == NULL) {
+ return NULL;
+ }
+
+ aspect_x = clip->aspx;
+ aspect_y = clip->aspy;
+
+ BKE_movieclip_get_size(clip, &bgpic->cuser, &width, &height);
+
+ /* Save for freeing. */
+ BLI_addtail(&pd->bg_movie_clips, BLI_genericNodeN(clip));
+ break;
+
+ default:
+ /* Unsupported type. */
+ return NULL;
+ }
+
+ *r_aspect = (width * aspect_x) / (height * aspect_y);
+ return tex;
+}
+
+static void OVERLAY_image_free_movieclips_textures(OVERLAY_Data *data)
+{
+ /* Free Movie clip textures after rendering */
+ LinkData *link;
+ while ((link = BLI_pophead(&data->stl->pd->bg_movie_clips))) {
+ MovieClip *clip = (MovieClip *)link->data;
+ GPU_free_texture_movieclip(clip);
+ MEM_freeN(link);
+ }
+}
+
+static void image_camera_background_matrix_get(const Camera *cam,
+ const CameraBGImage *bgpic,
+ const DRWContextState *draw_ctx,
+ const float image_aspect,
+ float rmat[4][4])
+{
+ float rotate[4][4], scale[4][4], translate[4][4];
+
+ axis_angle_to_mat4_single(rotate, 'Z', -bgpic->rotation);
+ unit_m4(scale);
+ unit_m4(translate);
+
+ /* Normalized Object space camera frame corners. */
+ float cam_corners[4][3];
+ BKE_camera_view_frame(draw_ctx->scene, cam, cam_corners);
+ float cam_width = fabsf(cam_corners[0][0] - cam_corners[3][0]);
+ float cam_height = fabsf(cam_corners[0][1] - cam_corners[1][1]);
+ float cam_aspect = cam_width / cam_height;
+
+ if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) {
+ /* Crop. */
+ if (image_aspect > cam_aspect) {
+ scale[0][0] *= cam_height * image_aspect;
+ scale[1][1] *= cam_height;
+ }
+ else {
+ scale[0][0] *= cam_width;
+ scale[1][1] *= cam_width / image_aspect;
+ }
+ }
+ else if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
+ /* Fit. */
+ if (image_aspect > cam_aspect) {
+ scale[0][0] *= cam_width;
+ scale[1][1] *= cam_width / image_aspect;
+ }
+ else {
+ scale[0][0] *= cam_height * image_aspect;
+ scale[1][1] *= cam_height;
+ }
+ }
+ else {
+ /* Stretch. */
+ scale[0][0] *= cam_width;
+ scale[1][1] *= cam_height;
+ }
+
+ translate[3][0] = bgpic->offset[0];
+ translate[3][1] = bgpic->offset[1];
+ translate[3][2] = cam_corners[0][2];
+ /* These lines are for keeping 2.80 behavior and could be removed to keep 2.79 behavior. */
+ translate[3][0] *= min_ff(1.0f, cam_aspect);
+ translate[3][1] /= max_ff(1.0f, cam_aspect) * (image_aspect / cam_aspect);
+ /* quad is -1..1 so divide by 2. */
+ scale[0][0] *= 0.5f * bgpic->scale * ((bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0);
+ scale[1][1] *= 0.5f * bgpic->scale * ((bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0);
+ /* Camera shift. (middle of cam_corners) */
+ translate[3][0] += (cam_corners[0][0] + cam_corners[2][0]) * 0.5f;
+ translate[3][1] += (cam_corners[0][1] + cam_corners[2][1]) * 0.5f;
+
+ mul_m4_series(rmat, translate, rotate, scale);
+}
+
+void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_PassList *psl = vedata->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Camera *cam = ob->data;
+
+ const bool show_frame = BKE_object_empty_image_frame_is_visible_in_view3d(ob, draw_ctx->rv3d);
+
+ if (!show_frame || DRW_state_is_select()) {
+ return;
+ }
+
+ float norm_obmat[4][4];
+ normalize_m4_m4(norm_obmat, ob->obmat);
+
+ for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->flag & CAM_BGIMG_FLAG_DISABLED) {
+ continue;
+ }
+
+ float aspect = 1.0;
+ bool use_alpha_premult;
+ float mat[4][4];
+
+ /* retrieve the image we want to show, continue to next when no image could be found */
+ GPUTexture *tex = image_camera_background_texture_get(
+ bgpic, draw_ctx, pd, &aspect, &use_alpha_premult);
+
+ if (tex) {
+ image_camera_background_matrix_get(cam, bgpic, draw_ctx, aspect, mat);
+
+ mul_m4_m4m4(mat, norm_obmat, mat);
+ const bool is_foreground = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != 0;
+
+ float color_alpha[4] = {1.0f, 1.0f, 1.0f, bgpic->alpha};
+ float color_premult_alpha[4] = {bgpic->alpha, bgpic->alpha, bgpic->alpha, bgpic->alpha};
+
+ /* When drawing background we do 2 passes.
+ * - One alpha over, which works where background is visible.
+ * - One alpha under, works under partially visible objects. (only in cycles)
+ * This approach is not ideal and should be revisited.
+ **/
+ for (int i = 0; i < (is_foreground ? 1 : 2); i++) {
+ DRWPass *pass = is_foreground ? psl->image_foreground_ps :
+ ((i == 0) ? psl->image_background_under_ps :
+ psl->image_background_over_ps);
+ GPUShader *sh = OVERLAY_shader_image();
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ float *color = (is_foreground || i == 1) ? color_alpha : color_premult_alpha;
+ DRW_shgroup_uniform_texture(grp, "imgTexture", tex);
+ DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", use_alpha_premult);
+ DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", true);
+ DRW_shgroup_uniform_bool_copy(grp, "imgLinear", !DRW_state_do_color_management());
+ DRW_shgroup_uniform_bool_copy(grp, "depthSet", true);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+ DRW_shgroup_call_obmat(grp, DRW_cache_quad_get(), mat);
+ }
+ }
+ }
+}
+
+void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const RegionView3D *rv3d = draw_ctx->rv3d;
+ GPUTexture *tex = NULL;
+ Image *ima = ob->data;
+ float mat[4][4];
+
+ const bool show_frame = BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d);
+ const bool show_image = show_frame && BKE_object_empty_image_data_is_visible_in_view3d(ob, rv3d);
+ const bool use_alpha_blend = (ob->empty_image_flag & OB_EMPTY_IMAGE_USE_ALPHA_BLEND) != 0;
+ const bool use_alpha_premult = ima && (ima->alpha_mode == IMA_ALPHA_PREMUL);
+
+ if (!show_frame) {
+ return;
+ }
+
+ {
+ /* Calling 'BKE_image_get_size' may free the texture. Get the size from 'tex' instead,
+ * see: T59347 */
+ int size[2] = {0};
+ if (ima != NULL) {
+ tex = GPU_texture_from_blender(ima, ob->iuser, GL_TEXTURE_2D);
+ if (tex) {
+ size[0] = GPU_texture_orig_width(tex);
+ size[1] = GPU_texture_orig_height(tex);
+ }
+ }
+ CLAMP_MIN(size[0], 1);
+ CLAMP_MIN(size[1], 1);
+
+ float image_aspect[2];
+ overlay_image_calc_aspect(ob->data, size, image_aspect);
+
+ copy_m4_m4(mat, ob->obmat);
+ mul_v3_fl(mat[0], image_aspect[0] * 0.5f * ob->empty_drawsize);
+ mul_v3_fl(mat[1], image_aspect[1] * 0.5f * ob->empty_drawsize);
+ madd_v3_v3fl(mat[3], mat[0], ob->ima_ofs[0] * 2.0f + 1.0f);
+ madd_v3_v3fl(mat[3], mat[1], ob->ima_ofs[1] * 2.0f + 1.0f);
+ }
+
+ /* Use the actual depth if we are doing depth tests to determine the distance to the object */
+ char depth_mode = DRW_state_is_depth() ? OB_EMPTY_IMAGE_DEPTH_DEFAULT : ob->empty_image_depth;
+ DRWPass *pass = NULL;
+ switch (depth_mode) {
+ case OB_EMPTY_IMAGE_DEPTH_DEFAULT:
+ pass = (use_alpha_blend) ? psl->image_empties_blend_ps : psl->image_empties_ps;
+ break;
+ case OB_EMPTY_IMAGE_DEPTH_BACK:
+ pass = psl->image_empties_back_ps;
+ break;
+ case OB_EMPTY_IMAGE_DEPTH_FRONT:
+ pass = psl->image_empties_front_ps;
+ break;
+ }
+
+ if (show_frame) {
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+ OVERLAY_empty_shape(cb, mat, 1.0f, OB_EMPTY_IMAGE, color);
+ }
+
+ if (show_image && tex && ((ob->color[3] > 0.0f) || !use_alpha_blend)) {
+ GPUShader *sh = OVERLAY_shader_image();
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_texture(grp, "imgTexture", tex);
+ DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", use_alpha_premult);
+ DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", use_alpha_blend);
+ DRW_shgroup_uniform_bool_copy(grp, "imgLinear", false);
+ DRW_shgroup_uniform_bool_copy(grp, "depthSet", depth_mode != OB_EMPTY_IMAGE_DEPTH_DEFAULT);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", ob->color);
+ DRW_shgroup_call_obmat(grp, DRW_cache_quad_get(), mat);
+ }
+}
+
+void OVERLAY_image_cache_finish(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_pass_sort_shgroup_reverse(psl->image_background_under_ps);
+ DRW_pass_sort_shgroup_z(psl->image_empties_blend_ps);
+ DRW_pass_sort_shgroup_z(psl->image_empties_front_ps);
+ DRW_pass_sort_shgroup_z(psl->image_empties_back_ps);
+}
+
+void OVERLAY_image_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+ const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ DRW_view_set_active(pd->view_reference_images);
+ DRW_draw_pass(psl->image_background_over_ps);
+
+ if (DRW_state_is_fbo() && !DRW_pass_is_empty(psl->image_background_under_ps)) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_draw_pass(psl->image_background_under_ps);
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+
+ DRW_draw_pass(psl->image_empties_back_ps);
+
+ DRW_draw_pass(psl->image_empties_ps);
+ DRW_draw_pass(psl->image_empties_blend_ps);
+
+ DRW_view_set_active(NULL);
+}
+
+void OVERLAY_image_in_front_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ DRW_view_set_active(pd->view_reference_images);
+
+ DRW_draw_pass(psl->image_empties_front_ps);
+ DRW_draw_pass(psl->image_foreground_ps);
+
+ DRW_view_set_active(NULL);
+
+ OVERLAY_image_free_movieclips_textures(vedata);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_lattice.c b/source/blender/draw/engines/overlay/overlay_lattice.c
new file mode 100644
index 00000000000..84d9dcc3e94
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_lattice.c
@@ -0,0 +1,83 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->edit_lattice_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_lattice_wire();
+ pd->edit_lattice_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_lattice_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+
+ sh = OVERLAY_shader_edit_lattice_point();
+ pd->edit_lattice_points_grp = grp = DRW_shgroup_create(sh, psl->edit_lattice_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+}
+
+void OVERLAY_edit_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUBatch *geom;
+
+ geom = DRW_cache_lattice_wire_get(ob, true);
+ DRW_shgroup_call(pd->edit_lattice_wires_grp, geom, ob);
+
+ geom = DRW_cache_lattice_vert_overlay_get(ob);
+ DRW_shgroup_call(pd->edit_lattice_points_grp, geom, ob);
+}
+
+void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+
+ struct GPUBatch *geom = DRW_cache_lattice_wire_get(ob, false);
+ OVERLAY_extra_wire(cb, geom, ob->obmat, color);
+}
+
+void OVERLAY_edit_lattice_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+
+ DRW_draw_pass(psl->edit_lattice_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_metaball.c b/source/blender/draw/engines/overlay/overlay_metaball.c
new file mode 100644
index 00000000000..a634aed812c
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_metaball.c
@@ -0,0 +1,143 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_meta_types.h"
+
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_mball.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_metaball_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+
+#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
+
+ for (int i = 0; i < 2; i++) {
+ DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->metaball_ps[i], state | pd->clipping_state | infront_state);
+
+ /* Reuse armature shader as it's perfect to outline ellipsoids. */
+ struct GPUVertFormat *format = formats->instance_bone;
+ struct GPUShader *sh = OVERLAY_shader_armature_sphere(true);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->metaball_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ pd->mball.handle[i] = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
+ }
+}
+
+static void metaball_instance_data_set(
+ BoneInstanceData *data, Object *ob, const float *pos, const float radius, const float color[4])
+{
+ /* Bone point radius is 0.05. Compensate for that. */
+ mul_v3_v3fl(data->mat[0], ob->obmat[0], radius / 0.05f);
+ mul_v3_v3fl(data->mat[1], ob->obmat[1], radius / 0.05f);
+ mul_v3_v3fl(data->mat[2], ob->obmat[2], radius / 0.05f);
+ mul_v3_m4v3(data->mat[3], ob->obmat, pos);
+ /* WATCH: Reminder, alpha is wiresize. */
+ OVERLAY_bone_instance_data_set_color(data, color);
+}
+
+void OVERLAY_edit_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ const bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+ const bool is_select = DRW_state_is_select();
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ MetaBall *mb = ob->data;
+
+ const float *color;
+ const float col_radius[4] = {0.63f, 0.19f, 0.19f, 1.0f}; /* 0x3030A0 */
+ const float col_radius_select[4] = {0.94f, 0.63f, 0.63f, 1.0f}; /* 0xA0A0F0 */
+ const float col_stiffness[4] = {0.19f, 0.63f, 0.19f, 1.0f}; /* 0x30A030 */
+ const float col_stiffness_select[4] = {0.63f, 0.94f, 0.63f, 1.0f}; /* 0xA0F0A0 */
+
+ int select_id = 0;
+ if (is_select) {
+ const Object *orig_object = DEG_get_original_object(ob);
+ select_id = orig_object->runtime.select_id;
+ }
+
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
+ const bool is_selected = (ml->flag & SELECT) != 0;
+ const bool is_scale_radius = (ml->flag & MB_SCALE_RAD) != 0;
+ float stiffness_radius = ml->rad * atanf(ml->s) / (float)M_PI_2;
+ BoneInstanceData instdata;
+
+ if (is_select) {
+ DRW_select_load_id(select_id | MBALLSEL_RADIUS);
+ }
+ color = (is_selected && is_scale_radius) ? col_radius_select : col_radius;
+ metaball_instance_data_set(&instdata, ob, &ml->x, ml->rad, color);
+ DRW_buffer_add_entry_struct(pd->mball.handle[do_in_front], &instdata);
+
+ if (is_select) {
+ DRW_select_load_id(select_id | MBALLSEL_STIFF);
+ }
+ color = (is_selected && !is_scale_radius) ? col_stiffness_select : col_stiffness;
+ metaball_instance_data_set(&instdata, ob, &ml->x, stiffness_radius, color);
+ DRW_buffer_add_entry_struct(pd->mball.handle[do_in_front], &instdata);
+
+ select_id += 0x10000;
+ }
+}
+
+void OVERLAY_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ const bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ MetaBall *mb = ob->data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+
+ LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
+ /* Draw radius only. */
+ BoneInstanceData instdata;
+ metaball_instance_data_set(&instdata, ob, &ml->x, ml->rad, color);
+ DRW_buffer_add_entry_struct(pd->mball.handle[do_in_front], &instdata);
+ }
+}
+
+void OVERLAY_metaball_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->metaball_ps[0]);
+}
+
+void OVERLAY_metaball_in_front_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->metaball_ps[1]);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c
new file mode 100644
index 00000000000..a532618d472
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_motion_path.c
@@ -0,0 +1,231 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_string.h"
+
+#include "DNA_armature_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "GPU_batch.h"
+
+#include "UI_resources.h"
+
+#include "draw_manager_text.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DRWShadingGroup *grp;
+ GPUShader *sh;
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ DRW_PASS_CREATE(psl->motion_paths_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_motion_path_line();
+ pd->motion_path_lines_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+ sh = OVERLAY_shader_motion_path_vert();
+ pd->motion_path_points_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+}
+
+/* Just convert the CPU cache to GPU cache. */
+/* T0D0(fclem) This should go into a draw_cache_impl_motionpath. */
+static GPUVertBuf *mpath_vbo_get(bMotionPath *mpath)
+{
+ if (!mpath->points_vbo) {
+ GPUVertFormat format = {0};
+ /* Match structure of bMotionPathVert. */
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "flag", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ mpath->points_vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(mpath->points_vbo, mpath->length);
+ /* meh... a useless memcpy. */
+ memcpy(mpath->points_vbo->data, mpath->points, sizeof(bMotionPathVert) * mpath->length);
+ }
+ return mpath->points_vbo;
+}
+
+static GPUBatch *mpath_batch_line_get(bMotionPath *mpath)
+{
+ if (!mpath->batch_line) {
+ mpath->batch_line = GPU_batch_create(GPU_PRIM_LINE_STRIP, mpath_vbo_get(mpath), NULL);
+ }
+ return mpath->batch_line;
+}
+
+static GPUBatch *mpath_batch_points_get(bMotionPath *mpath)
+{
+ if (!mpath->batch_points) {
+ mpath->batch_points = GPU_batch_create(GPU_PRIM_POINTS, mpath_vbo_get(mpath), NULL);
+ }
+ return mpath->batch_points;
+}
+
+static void motion_path_get_frame_range_to_draw(bAnimVizSettings *avs,
+ bMotionPath *mpath,
+ int current_frame,
+ int *r_start,
+ int *r_end,
+ int *r_step)
+{
+ int start, end;
+
+ if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
+ start = current_frame - avs->path_bc;
+ end = current_frame + avs->path_ac + 1;
+ }
+ else {
+ start = avs->path_sf;
+ end = avs->path_ef;
+ }
+
+ if (start > end) {
+ SWAP(int, start, end);
+ }
+
+ CLAMP(start, mpath->start_frame, mpath->end_frame);
+ CLAMP(end, mpath->start_frame, mpath->end_frame);
+
+ *r_start = start;
+ *r_end = end;
+ *r_step = max_ii(avs->path_step, 1);
+}
+
+static void motion_path_cache(OVERLAY_Data *vedata,
+ Object *ob,
+ bPoseChannel *pchan,
+ bAnimVizSettings *avs,
+ bMotionPath *mpath)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ int txt_flag = DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_ASCII;
+ int cfra = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ bool selected = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->base_flag & BASE_SELECTED);
+ bool show_keyframes = (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) != 0;
+ bool show_keyframes_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
+ bool show_frame_no = (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) != 0;
+ bool show_lines = (mpath->flag & MOTIONPATH_FLAG_LINES) != 0;
+ float no_custom_col[3] = {-1.0f, -1.0f, -1.0f};
+ float *color = (mpath->flag & MOTIONPATH_FLAG_CUSTOM) ? mpath->color : no_custom_col;
+
+ int sfra, efra, stepsize;
+ motion_path_get_frame_range_to_draw(avs, mpath, cfra, &sfra, &efra, &stepsize);
+
+ int len = efra - sfra;
+ if (len == 0) {
+ return;
+ }
+ int start_index = sfra - mpath->start_frame;
+
+ /* Draw curve-line of path. */
+ if (show_lines) {
+ int motion_path_settings[4] = {cfra, sfra, efra, mpath->start_frame};
+ DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->motion_path_lines_grp);
+ DRW_shgroup_uniform_ivec4_copy(grp, "mpathLineSettings", motion_path_settings);
+ DRW_shgroup_uniform_int_copy(grp, "lineThickness", mpath->line_thickness);
+ DRW_shgroup_uniform_bool_copy(grp, "selected", selected);
+ DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
+ /* Only draw the required range. */
+ DRW_shgroup_call_range(grp, mpath_batch_line_get(mpath), start_index, len);
+ }
+
+ /* Draw points. */
+ {
+ int pt_size = max_ii(mpath->line_thickness - 1, 1);
+ int motion_path_settings[4] = {pt_size, cfra, mpath->start_frame, stepsize};
+ DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->motion_path_points_grp);
+ DRW_shgroup_uniform_ivec4_copy(grp, "mpathPointSettings", motion_path_settings);
+ DRW_shgroup_uniform_bool_copy(grp, "showKeyFrames", show_keyframes);
+ DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
+ /* Only draw the required range. */
+ DRW_shgroup_call_range(grp, mpath_batch_points_get(mpath), start_index, len);
+ }
+
+ /* Draw frame numbers at each frame-step value. */
+ if (show_frame_no || (show_keyframes_no && show_keyframes)) {
+ int i;
+ uchar col[4], col_kf[4];
+ UI_GetThemeColor3ubv(TH_TEXT_HI, col);
+ UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col_kf);
+ col[3] = col_kf[3] = 255;
+
+ bMotionPathVert *mpv = mpath->points + start_index;
+ for (i = 0; i < len; i += stepsize, mpv += stepsize) {
+ int frame = sfra + i;
+ char numstr[32];
+ size_t numstr_len;
+ bool is_keyframe = (mpv->flag & MOTIONPATH_VERT_KEY) != 0;
+
+ if ((show_keyframes && show_keyframes_no && is_keyframe) || (show_frame_no && (i == 0))) {
+ numstr_len = BLI_snprintf(numstr, sizeof(numstr), " %d", frame);
+ DRW_text_cache_add(
+ dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, (is_keyframe) ? col_kf : col);
+ }
+ else if (show_frame_no) {
+ bMotionPathVert *mpvP = (mpv - stepsize);
+ bMotionPathVert *mpvN = (mpv + stepsize);
+ /* Only draw frame number if several consecutive highlighted points
+ * don't occur on same point. */
+ if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) {
+ numstr_len = BLI_snprintf(numstr, sizeof(numstr), " %d", frame);
+ DRW_text_cache_add(dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+}
+
+void OVERLAY_motion_path_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (ob->type == OB_ARMATURE) {
+ if (OVERLAY_armature_is_pose_mode(ob, draw_ctx)) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->mpath) {
+ motion_path_cache(vedata, ob, pchan, &ob->pose->avs, pchan->mpath);
+ }
+ }
+ }
+ }
+
+ if (ob->mpath) {
+ motion_path_cache(vedata, ob, NULL, &ob->avs, ob->mpath);
+ }
+}
+
+void OVERLAY_motion_path_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->motion_paths_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
new file mode 100644
index 00000000000..63738b3c214
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -0,0 +1,182 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_global.h"
+
+#include "DNA_lightprobe_types.h"
+
+#include "UI_resources.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_outline_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ if (DRW_state_is_fbo()) {
+ /* TODO only alloc if needed. */
+ DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0);
+ DRW_texture_ensure_fullscreen_2d(&txl->outlines_id_tx, GPU_R16UI, 0);
+
+ GPU_framebuffer_ensure_config(
+ &fbl->outlines_prepass_fb,
+ {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->outlines_id_tx)});
+
+ if (pd->antialiasing.enabled) {
+ GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb,
+ {GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)});
+ }
+ else {
+ GPU_framebuffer_ensure_config(
+ &fbl->outlines_resolve_fb,
+ {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ }
+ }
+}
+
+void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DRWShadingGroup *grp = NULL;
+
+ const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
+ const bool do_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->outlines_prepass_ps, state | pd->clipping_state);
+
+ GPUShader *sh_geom = OVERLAY_shader_outline_prepass(pd->xray_enabled_and_not_wire);
+
+ pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, 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. */
+ if (!(pd->v3d_flag & V3D_SELECT_OUTLINE)) {
+ return;
+ }
+
+ {
+ /* We can only do alpha blending with lineOutput just after clearing the buffer. */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
+ DRW_PASS_CREATE(psl->outlines_detect_ps, state);
+
+ GPUShader *sh = OVERLAY_shader_outline_detect();
+
+ grp = DRW_shgroup_create(sh, psl->outlines_detect_ps);
+ /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
+ DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.35f);
+ DRW_shgroup_uniform_bool_copy(grp, "doThickOutlines", do_expand);
+ DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", pd->antialiasing.enabled);
+ DRW_shgroup_uniform_bool_copy(grp, "isXrayWires", pd->xray_enabled_and_not_wire);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
+ Object *ob,
+ OVERLAY_DupliData *dupli,
+ bool init_dupli)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ struct GPUBatch *geom;
+ DRWShadingGroup *shgroup = NULL;
+ const bool draw_outline = ob->dt > OB_BOUNDBOX;
+
+ /* Early exit: outlines of bounding boxes are not drawn. */
+ if (!draw_outline) {
+ return;
+ }
+
+ if (dupli && !init_dupli) {
+ geom = dupli->outline_geom;
+ shgroup = dupli->outline_shgrp;
+ }
+ else {
+ /* This fixes only the biggest case which is a plane in ortho view. */
+ int flat_axis = 0;
+ bool is_flat_object_viewed_from_side = ((draw_ctx->rv3d->persp == RV3D_ORTHO) &&
+ DRW_object_is_flat(ob, &flat_axis) &&
+ DRW_object_axis_orthogonal_to_view(ob, flat_axis));
+
+ if (pd->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) {
+ geom = DRW_cache_object_edge_detection_get(ob, NULL);
+ }
+ else {
+ geom = DRW_cache_object_surface_get(ob);
+ }
+
+ if (geom) {
+ shgroup = pd->outlines_grp;
+ }
+ }
+
+ if (shgroup && geom) {
+ DRW_shgroup_call(shgroup, geom, ob);
+ }
+
+ if (init_dupli) {
+ dupli->outline_shgrp = shgroup;
+ dupli->outline_geom = geom;
+ }
+}
+
+void OVERLAY_outline_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_PassList *psl = vedata->psl;
+ float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ bool do_outlines = psl->outlines_prepass_ps != NULL &&
+ !DRW_pass_is_empty(psl->outlines_prepass_ps);
+
+ if (DRW_state_is_fbo() && do_outlines) {
+ DRW_stats_group_start("Outlines");
+
+ /* Render filled polygon on a separate framebuffer */
+ GPU_framebuffer_bind(fbl->outlines_prepass_fb);
+ GPU_framebuffer_clear_color_depth_stencil(fbl->outlines_prepass_fb, clearcol, 1.0f, 0x00);
+ DRW_draw_pass(psl->outlines_prepass_ps);
+
+ /* Search outline pixels */
+ GPU_framebuffer_bind(fbl->outlines_resolve_fb);
+ DRW_draw_pass(psl->outlines_detect_ps);
+
+ DRW_stats_group_end();
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_paint.c b/source/blender/draw/engines/overlay/overlay_paint.c
new file mode 100644
index 00000000000..047659fbeee
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_paint.c
@@ -0,0 +1,209 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_mesh_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_paint_cache_init(OVERLAY_Data *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+ DRWState state;
+
+ const bool use_alpha_blending = (draw_ctx->v3d->shading.type == OB_WIRE);
+ const bool draw_contours = (pd->overlay.wpaint_flag & V3D_OVERLAY_WPAINT_CONTOURS) != 0;
+ float opacity = 0.0f;
+
+ switch (pd->ctx_mode) {
+ case CTX_MODE_POSE:
+ case CTX_MODE_PAINT_WEIGHT: {
+ opacity = pd->overlay.weight_paint_mode_opacity;
+ if (opacity > 0.0f) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
+ state |= use_alpha_blending ? DRW_STATE_BLEND_ALPHA : DRW_STATE_BLEND_MUL;
+ DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_paint_weight();
+ pd->paint_surf_grp = grp = DRW_shgroup_create(sh, psl->paint_color_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "drawContours", draw_contours);
+ DRW_shgroup_uniform_bool_copy(grp, "useAlphaBlend", use_alpha_blending);
+ DRW_shgroup_uniform_float_copy(grp, "opacity", opacity);
+ DRW_shgroup_uniform_texture(grp, "colorramp", G_draw.weight_ramp);
+ }
+ break;
+ }
+ case CTX_MODE_PAINT_VERTEX: {
+ opacity = pd->overlay.vertex_paint_mode_opacity;
+ if (opacity > 0.0f) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
+ state |= use_alpha_blending ? DRW_STATE_BLEND_ALPHA : DRW_STATE_BLEND_MUL;
+ DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_paint_vertcol();
+ pd->paint_surf_grp = grp = DRW_shgroup_create(sh, psl->paint_color_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "useAlphaBlend", use_alpha_blending);
+ DRW_shgroup_uniform_float_copy(grp, "opacity", opacity);
+ }
+ break;
+ }
+ case CTX_MODE_PAINT_TEXTURE: {
+ const ImagePaintSettings *imapaint = &draw_ctx->scene->toolsettings->imapaint;
+ const bool mask_enabled = imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL &&
+ imapaint->stencil != NULL;
+
+ opacity = mask_enabled ? pd->overlay.texture_paint_mode_opacity : 0.0f;
+ if (opacity > 0.0f) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
+
+ GPUTexture *tex = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D);
+
+ const bool mask_premult = (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL);
+ const bool mask_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0;
+ sh = OVERLAY_shader_paint_texture();
+ pd->paint_surf_grp = grp = DRW_shgroup_create(sh, psl->paint_color_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "opacity", opacity);
+ DRW_shgroup_uniform_bool_copy(grp, "maskPremult", mask_premult);
+ DRW_shgroup_uniform_vec3_copy(grp, "maskColor", imapaint->stencil_col);
+ DRW_shgroup_uniform_bool_copy(grp, "maskInvertStencil", mask_inverted);
+ DRW_shgroup_uniform_texture(grp, "maskImage", tex);
+ }
+ break;
+ }
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ if (opacity <= 0.0f) {
+ psl->paint_color_ps = NULL;
+ pd->paint_surf_grp = NULL;
+ }
+
+ {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->paint_overlay_ps, state | pd->clipping_state);
+ sh = OVERLAY_shader_paint_face();
+ pd->paint_face_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){1.0f, 1.0f, 1.0f, 0.2f});
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+ sh = OVERLAY_shader_paint_wire();
+ pd->paint_wire_selected_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "useSelect", true);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+ pd->paint_wire_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "useSelect", false);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+ sh = OVERLAY_shader_paint_point();
+ pd->paint_point_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+}
+
+void OVERLAY_paint_texture_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUBatch *geom = NULL;
+
+ const Mesh *me_orig = DEG_get_original_object(ob)->data;
+ const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ if (pd->paint_surf_grp) {
+ geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
+ DRW_shgroup_call(pd->paint_surf_grp, geom, ob);
+ }
+
+ if (use_face_sel) {
+ geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call(pd->paint_face_grp, geom, ob);
+ }
+}
+
+void OVERLAY_paint_vertex_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUBatch *geom = NULL;
+
+ const Mesh *me_orig = DEG_get_original_object(ob)->data;
+ const bool use_wire = (pd->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0;
+ const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+
+ if (pd->paint_surf_grp) {
+ if (ob->mode == OB_MODE_WEIGHT_PAINT) {
+ geom = DRW_cache_mesh_surface_weights_get(ob);
+ DRW_shgroup_call(pd->paint_surf_grp, geom, ob);
+ }
+ }
+
+ if (use_face_sel || use_wire) {
+ geom = DRW_cache_mesh_surface_edges_get(ob);
+ DRW_shgroup_call(use_face_sel ? pd->paint_wire_selected_grp : pd->paint_wire_grp, geom, ob);
+ }
+
+ if (use_face_sel) {
+ geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call(pd->paint_face_grp, geom, ob);
+ }
+
+ if (use_vert_sel) {
+ geom = DRW_cache_mesh_all_verts_get(ob);
+ DRW_shgroup_call(pd->paint_point_grp, geom, ob);
+ }
+}
+
+void OVERLAY_paint_weight_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_paint_vertex_cache_populate(vedata, ob);
+}
+
+void OVERLAY_paint_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (DRW_state_is_fbo()) {
+ /* Pain overlay needs final color because of multiply blend mode. */
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+
+ if (psl->paint_color_ps) {
+ DRW_draw_pass(psl->paint_color_ps);
+ }
+ DRW_draw_pass(psl->paint_overlay_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_particle.c b/source/blender/draw/engines/overlay/overlay_particle.c
new file mode 100644
index 00000000000..3540de35e46
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_particle.c
@@ -0,0 +1,222 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_particle_types.h"
+
+#include "BKE_pointcache.h"
+
+#include "ED_particle.h"
+
+#include "overlay_private.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Particles
+ * \{ */
+
+void OVERLAY_edit_particle_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
+ GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ pd->edit_particle.use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
+ pd->edit_particle.select_mode = pset->selectmode;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->edit_particle_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_particle_strand();
+ pd->edit_particle_strand_grp = grp = DRW_shgroup_create(sh, psl->edit_particle_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "useWeight", pd->edit_particle.use_weight);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+
+ sh = OVERLAY_shader_edit_particle_point();
+ pd->edit_particle_point_grp = grp = DRW_shgroup_create(sh, psl->edit_particle_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+}
+
+void OVERLAY_edit_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
+
+ /* Usually the edit structure is created by Particle Edit Mode Toggle
+ * operator, but sometimes it's invoked after tagging hair as outdated
+ * (for example, when toggling edit mode). That makes it impossible to
+ * create edit structure for until after next dependency graph evaluation.
+ *
+ * Ideally, the edit structure will be created here already via some
+ * dependency graph callback or so, but currently trying to make it nicer
+ * only causes bad level calls and breaks design from the past.
+ */
+ Object *ob_orig = DEG_get_original_object(ob);
+ PTCacheEdit *edit = PE_create_current(draw_ctx->depsgraph, scene_orig, ob_orig);
+ if (edit == NULL) {
+ /* Happens when trying to edit particles in EMITTER mode without
+ * having them cached.
+ */
+ return;
+ }
+ /* NOTE: We need to pass evaluated particle system, which we need
+ * to find first.
+ */
+ ParticleSystem *psys = ob->particlesystem.first;
+ LISTBASE_FOREACH (ParticleSystem *, psys_orig, &ob_orig->particlesystem) {
+ if (PE_get_current_from_psys(psys_orig) == edit) {
+ break;
+ }
+ psys = psys->next;
+ }
+ if (psys == NULL) {
+ printf("Error getting evaluated particle system for edit.\n");
+ return;
+ }
+
+ struct GPUBatch *geom;
+ {
+ geom = DRW_cache_particles_get_edit_strands(ob, psys, edit, pd->edit_particle.use_weight);
+ DRW_shgroup_call(pd->edit_particle_strand_grp, geom, NULL);
+ }
+
+ if (pd->edit_particle.select_mode == SCE_SELECT_POINT) {
+ geom = DRW_cache_particles_get_edit_inner_points(ob, psys, edit);
+ DRW_shgroup_call(pd->edit_particle_point_grp, geom, NULL);
+ }
+
+ if (ELEM(pd->edit_particle.select_mode, SCE_SELECT_POINT, SCE_SELECT_END)) {
+ geom = DRW_cache_particles_get_edit_tip_points(ob, psys, edit);
+ DRW_shgroup_call(pd->edit_particle_point_grp, geom, NULL);
+ }
+}
+
+void OVERLAY_edit_particle_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+
+ DRW_draw_pass(psl->edit_particle_ps);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Particles
+ * \{ */
+
+void OVERLAY_particle_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
+ GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ pd->edit_particle.use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
+ pd->edit_particle.select_mode = pset->selectmode;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->particle_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_particle_dot();
+ pd->particle_dots_grp = grp = DRW_shgroup_create(sh, psl->particle_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp);
+
+ sh = OVERLAY_shader_particle_shape();
+ pd->particle_shapes_grp = grp = DRW_shgroup_create(sh, psl->particle_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp);
+}
+
+void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+
+ ParticleSettings *part = psys->part;
+ int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (part->type == PART_HAIR) {
+ /* Hairs should have been rendered by the render engine.*/
+ continue;
+ }
+
+ if (!ELEM(draw_as, PART_DRAW_NOT, PART_DRAW_OB, PART_DRAW_GR)) {
+ struct GPUBatch *geom = DRW_cache_particles_get_dots(ob, psys);
+ struct GPUBatch *shape = NULL;
+ DRWShadingGroup *grp;
+
+ /* TODO(fclem) Here would be a good place for preemptive culling. */
+
+ /* fclem: Is color even usefull in our modern context? */
+ Material *ma = give_current_material(ob, part->omat);
+ float color[4] = {0.6f, 0.6f, 0.6f, part->draw_size};
+ if (ma != NULL) {
+ copy_v3_v3(color, &ma->r);
+ }
+
+ switch (draw_as) {
+ default:
+ case PART_DRAW_DOT:
+ grp = DRW_shgroup_create_sub(pd->particle_dots_grp);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+ DRW_shgroup_call(grp, geom, NULL);
+ break;
+ case PART_DRAW_AXIS:
+ case PART_DRAW_CIRC:
+ case PART_DRAW_CROSS:
+ grp = DRW_shgroup_create_sub(pd->particle_shapes_grp);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+ shape = DRW_cache_particles_get_prim(draw_as);
+ DRW_shgroup_call_instances_with_attribs(grp, NULL, shape, geom);
+ break;
+ }
+ }
+ }
+}
+
+void OVERLAY_particle_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->particle_ps);
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
new file mode 100644
index 00000000000..996ee845799
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -0,0 +1,574 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __OVERLAY_PRIVATE_H__
+#define __OVERLAY_PRIVATE_H__
+
+#ifdef __APPLE__
+# define USE_GEOM_SHADER_WORKAROUND 1
+#else
+# define USE_GEOM_SHADER_WORKAROUND 0
+#endif
+
+typedef struct OVERLAY_FramebufferList {
+ struct GPUFrameBuffer *overlay_default_fb;
+ struct GPUFrameBuffer *overlay_line_fb;
+ struct GPUFrameBuffer *overlay_color_only_fb;
+ struct GPUFrameBuffer *overlay_in_front_fb;
+ struct GPUFrameBuffer *overlay_line_in_front_fb;
+ struct GPUFrameBuffer *outlines_prepass_fb;
+ struct GPUFrameBuffer *outlines_resolve_fb;
+} OVERLAY_FramebufferList;
+
+typedef struct OVERLAY_TextureList {
+ struct GPUTexture *temp_depth_tx;
+ struct GPUTexture *dummy_depth_tx;
+ struct GPUTexture *outlines_id_tx;
+ struct GPUTexture *overlay_color_tx;
+ struct GPUTexture *overlay_line_tx;
+} OVERLAY_TextureList;
+
+#define NOT_IN_FRONT 0
+#define IN_FRONT 1
+
+typedef struct OVERLAY_PassList {
+ DRWPass *antialiasing_ps;
+ DRWPass *armature_ps[2];
+ DRWPass *armature_bone_select_ps;
+ DRWPass *armature_transp_ps;
+ DRWPass *edit_curve_wire_ps[2];
+ DRWPass *edit_curve_handle_ps;
+ DRWPass *edit_lattice_ps;
+ DRWPass *edit_mesh_depth_ps[2];
+ DRWPass *edit_mesh_verts_ps[2];
+ DRWPass *edit_mesh_edges_ps[2];
+ DRWPass *edit_mesh_faces_ps[2];
+ DRWPass *edit_mesh_faces_cage_ps[2];
+ DRWPass *edit_mesh_analysis_ps;
+ DRWPass *edit_mesh_normals_ps;
+ DRWPass *edit_mesh_weight_ps;
+ DRWPass *edit_particle_ps;
+ DRWPass *edit_text_overlay_ps;
+ DRWPass *edit_text_wire_ps[2];
+ DRWPass *extra_ps[2];
+ DRWPass *extra_blend_ps;
+ DRWPass *extra_centers_ps;
+ DRWPass *extra_grid_ps;
+ DRWPass *facing_ps;
+ DRWPass *grid_ps;
+ DRWPass *image_background_under_ps;
+ DRWPass *image_background_over_ps;
+ DRWPass *image_empties_ps;
+ DRWPass *image_empties_back_ps;
+ DRWPass *image_empties_blend_ps;
+ DRWPass *image_empties_front_ps;
+ DRWPass *image_foreground_ps;
+ DRWPass *metaball_ps[2];
+ DRWPass *motion_paths_ps;
+ DRWPass *outlines_prepass_ps;
+ DRWPass *outlines_detect_ps;
+ DRWPass *outlines_resolve_ps;
+ DRWPass *paint_color_ps;
+ DRWPass *paint_overlay_ps;
+ DRWPass *particle_ps;
+ DRWPass *sculpt_mask_ps;
+ DRWPass *wireframe_ps;
+ DRWPass *wireframe_xray_ps;
+} OVERLAY_PassList;
+
+/* Data used by GLSL shader. To be used as UBO. */
+typedef struct OVERLAY_ShadingData {
+ /** Grid */
+ float grid_axes[3], grid_distance;
+ float zplane_axes[3], grid_mesh_size;
+ float grid_steps[8];
+ float inv_viewport_size[2];
+ float grid_line_size;
+ int grid_flag;
+ int zpos_flag;
+ int zneg_flag;
+ /** Wireframe */
+ float wire_step_param;
+ /** Edit Curve */
+ float edit_curve_normal_length;
+ /** Edit Mesh */
+ int data_mask[4];
+} OVERLAY_ShadingData;
+
+typedef struct OVERLAY_ExtraCallBuffers {
+ DRWCallBuffer *camera_frame;
+ DRWCallBuffer *camera_tria[2];
+ DRWCallBuffer *camera_distances;
+ DRWCallBuffer *camera_volume;
+ DRWCallBuffer *camera_volume_frame;
+
+ DRWCallBuffer *center_active;
+ DRWCallBuffer *center_selected;
+ DRWCallBuffer *center_deselected;
+ DRWCallBuffer *center_selected_lib;
+ DRWCallBuffer *center_deselected_lib;
+
+ DRWCallBuffer *empty_axes;
+ DRWCallBuffer *empty_capsule_body;
+ DRWCallBuffer *empty_capsule_cap;
+ DRWCallBuffer *empty_circle;
+ DRWCallBuffer *empty_cone;
+ DRWCallBuffer *empty_cube;
+ DRWCallBuffer *empty_cylinder;
+ DRWCallBuffer *empty_image_frame;
+ DRWCallBuffer *empty_plain_axes;
+ DRWCallBuffer *empty_single_arrow;
+ DRWCallBuffer *empty_sphere;
+ DRWCallBuffer *empty_sphere_solid;
+
+ DRWCallBuffer *extra_dashed_lines;
+ DRWCallBuffer *extra_lines;
+
+ DRWCallBuffer *field_curve;
+ DRWCallBuffer *field_force;
+ DRWCallBuffer *field_vortex;
+ DRWCallBuffer *field_wind;
+ DRWCallBuffer *field_cone_limit;
+ DRWCallBuffer *field_sphere_limit;
+ DRWCallBuffer *field_tube_limit;
+
+ DRWCallBuffer *groundline;
+
+ DRWCallBuffer *light_point;
+ DRWCallBuffer *light_sun;
+ DRWCallBuffer *light_spot;
+ DRWCallBuffer *light_spot_cone_back;
+ DRWCallBuffer *light_spot_cone_front;
+ DRWCallBuffer *light_area[2];
+
+ DRWCallBuffer *origin_xform;
+
+ DRWCallBuffer *probe_planar;
+ DRWCallBuffer *probe_cube;
+ DRWCallBuffer *probe_grid;
+
+ DRWCallBuffer *solid_quad;
+
+ DRWCallBuffer *speaker;
+
+ DRWShadingGroup *extra_wire;
+ DRWShadingGroup *extra_loose_points;
+} OVERLAY_ExtraCallBuffers;
+
+typedef struct OVERLAY_ArmatureCallBuffers {
+ DRWCallBuffer *box_outline;
+ DRWCallBuffer *box_solid;
+
+ DRWCallBuffer *dof_lines;
+ DRWCallBuffer *dof_sphere;
+
+ DRWCallBuffer *envelope_distance;
+ DRWCallBuffer *envelope_outline;
+ DRWCallBuffer *envelope_solid;
+
+ DRWCallBuffer *octa_outline;
+ DRWCallBuffer *octa_solid;
+
+ DRWCallBuffer *point_outline;
+ DRWCallBuffer *point_solid;
+
+ DRWCallBuffer *stick;
+
+ DRWCallBuffer *wire;
+
+ DRWShadingGroup *custom_solid;
+ DRWShadingGroup *custom_outline;
+ DRWShadingGroup *custom_wire;
+ GHash *custom_shapes_ghash;
+} OVERLAY_ArmatureCallBuffers;
+
+typedef struct OVERLAY_PrivateData {
+ DRWShadingGroup *armature_bone_select_act_grp;
+ DRWShadingGroup *armature_bone_select_grp;
+ DRWShadingGroup *edit_curve_normal_grp[2];
+ DRWShadingGroup *edit_curve_wire_grp[2];
+ DRWShadingGroup *edit_curve_handle_grp;
+ DRWShadingGroup *edit_curve_points_grp;
+ DRWShadingGroup *edit_lattice_points_grp;
+ DRWShadingGroup *edit_lattice_wires_grp;
+ DRWShadingGroup *edit_mesh_depth_grp[2];
+ DRWShadingGroup *edit_mesh_faces_grp[2];
+ DRWShadingGroup *edit_mesh_faces_cage_grp[2];
+ DRWShadingGroup *edit_mesh_verts_grp[2];
+ DRWShadingGroup *edit_mesh_edges_grp[2];
+ DRWShadingGroup *edit_mesh_facedots_grp[2];
+ DRWShadingGroup *edit_mesh_skin_roots_grp[2];
+ DRWShadingGroup *edit_mesh_normals_grp;
+ DRWShadingGroup *edit_mesh_analysis_grp;
+ DRWShadingGroup *edit_mesh_weight_grp;
+ DRWShadingGroup *edit_particle_strand_grp;
+ DRWShadingGroup *edit_particle_point_grp;
+ DRWShadingGroup *edit_text_overlay_grp;
+ DRWShadingGroup *edit_text_wire_grp[2];
+ DRWShadingGroup *extra_grid_grp;
+ DRWShadingGroup *facing_grp;
+ DRWShadingGroup *motion_path_lines_grp;
+ DRWShadingGroup *motion_path_points_grp;
+ DRWShadingGroup *outlines_grp;
+ DRWShadingGroup *paint_surf_grp;
+ DRWShadingGroup *paint_wire_grp;
+ DRWShadingGroup *paint_wire_selected_grp;
+ DRWShadingGroup *paint_point_grp;
+ DRWShadingGroup *paint_face_grp;
+ DRWShadingGroup *particle_dots_grp;
+ DRWShadingGroup *particle_shapes_grp;
+ DRWShadingGroup *sculpt_mask_grp;
+ DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */
+ DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */
+ DRWShadingGroup *wires_sculpt_grp[2];
+
+ DRWView *view_default;
+ DRWView *view_wires;
+ DRWView *view_edit_faces;
+ DRWView *view_edit_faces_cage;
+ DRWView *view_edit_edges;
+ DRWView *view_edit_verts;
+ DRWView *view_reference_images;
+
+ /** TODO get rid of this. */
+ ListBase smoke_domains;
+ ListBase bg_movie_clips;
+
+ /** Two instances for in_front option and without. */
+ OVERLAY_ExtraCallBuffers extra_call_buffers[2];
+
+ OVERLAY_ArmatureCallBuffers armature_call_buffers[2];
+
+ View3DOverlay overlay;
+ enum eContextObjectMode ctx_mode;
+ bool clear_in_front;
+ bool wireframe_mode;
+ bool hide_overlays;
+ bool xray_enabled;
+ bool xray_enabled_and_not_wire;
+ short v3d_flag; /* TODO move to View3DOverlay */
+ short v3d_gridflag; /* TODO move to View3DOverlay */
+ DRWState clipping_state;
+ OVERLAY_ShadingData shdata;
+
+ struct {
+ bool enabled;
+ } antialiasing;
+ struct {
+ bool show_handles;
+ } edit_curve;
+ struct {
+ int ghost_ob;
+ int edit_ob;
+ bool do_zbufclip;
+ bool do_faces;
+ bool do_edges;
+ bool select_vert;
+ bool select_face;
+ bool select_edge;
+ int flag; /** Copy of v3d->overlay.edit_flag. */
+ } edit_mesh;
+ struct {
+ bool use_weight;
+ int select_mode;
+ } edit_particle;
+ struct {
+ bool transparent;
+ bool show_relations;
+ bool do_pose_fade_geom;
+ } armature;
+ struct {
+ DRWCallBuffer *handle[2];
+ } mball;
+} OVERLAY_PrivateData; /* Transient data */
+
+typedef struct OVERLAY_StorageList {
+ struct OVERLAY_PrivateData *pd;
+} OVERLAY_StorageList;
+
+typedef struct OVERLAY_Data {
+ void *engine_type;
+ OVERLAY_FramebufferList *fbl;
+ OVERLAY_TextureList *txl;
+ OVERLAY_PassList *psl;
+ OVERLAY_StorageList *stl;
+} OVERLAY_Data;
+
+typedef struct OVERLAY_DupliData {
+ DRWShadingGroup *wire_shgrp;
+ DRWShadingGroup *outline_shgrp;
+ DRWShadingGroup *extra_shgrp;
+ struct GPUBatch *wire_geom;
+ struct GPUBatch *outline_geom;
+ struct GPUBatch *extra_geom;
+ short base_flag;
+} OVERLAY_DupliData;
+
+typedef struct BoneInstanceData {
+ /* Keep sync with bone instance vertex format (OVERLAY_InstanceFormats) */
+ union {
+ float mat[4][4];
+ struct {
+ float _pad0[3], color_hint_a;
+ float _pad1[3], color_hint_b;
+ float _pad2[3], color_a;
+ float _pad3[3], color_b;
+ };
+ struct {
+ float _pad00[3], amin_a;
+ float _pad01[3], amin_b;
+ float _pad02[3], amax_a;
+ float _pad03[3], amax_b;
+ };
+ };
+} BoneInstanceData;
+
+typedef struct OVERLAY_InstanceFormats {
+ struct GPUVertFormat *instance_pos;
+ struct GPUVertFormat *instance_extra;
+ struct GPUVertFormat *instance_bone;
+ struct GPUVertFormat *instance_bone_outline;
+ struct GPUVertFormat *instance_bone_envelope;
+ struct GPUVertFormat *instance_bone_envelope_distance;
+ struct GPUVertFormat *instance_bone_envelope_outline;
+ struct GPUVertFormat *instance_bone_stick;
+ struct GPUVertFormat *pos;
+ struct GPUVertFormat *pos_color;
+ struct GPUVertFormat *wire_extra;
+} OVERLAY_InstanceFormats;
+
+/* Pack data into the last row of the 4x4 matrix. It will be decoded by the vertex shader. */
+BLI_INLINE void pack_data_in_mat4(
+ float rmat[4][4], const float mat[4][4], float a, float b, float c, float d)
+{
+ copy_m4_m4(rmat, mat);
+ rmat[0][3] = a;
+ rmat[1][3] = b;
+ rmat[2][3] = c;
+ rmat[3][3] = d;
+}
+
+BLI_INLINE void pack_v4_in_mat4(float rmat[4][4], const float mat[4][4], const float v[4])
+{
+ pack_data_in_mat4(rmat, mat, v[0], v[1], v[2], v[3]);
+}
+
+BLI_INLINE void pack_fl_in_mat4(float rmat[4][4], const float mat[4][4], float a)
+{
+ copy_m4_m4(rmat, mat);
+ rmat[3][3] = a;
+}
+
+void OVERLAY_antialiasing_init(OVERLAY_Data *vedata);
+void OVERLAY_antialiasing_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_antialiasing_cache_finish(OVERLAY_Data *vedata);
+void OVERLAY_antialiasing_start(OVERLAY_Data *vedata);
+void OVERLAY_antialiasing_end(OVERLAY_Data *vedata);
+
+bool OVERLAY_armature_is_pose_mode(Object *ob, const struct DRWContextState *draw_ctx);
+void OVERLAY_armature_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_armature_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_armature_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_pose_armature_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_armature_cache_finish(OVERLAY_Data *vedata);
+void OVERLAY_armature_draw(OVERLAY_Data *vedata);
+void OVERLAY_armature_in_front_draw(OVERLAY_Data *vedata);
+void OVERLAY_pose_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_pose_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_bone_instance_data_set_color_hint(BoneInstanceData *data, const float hint_color[4]);
+void OVERLAY_bone_instance_data_set_color(BoneInstanceData *data, const float bone_color[4]);
+
+void OVERLAY_edit_curve_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_curve_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_surf_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_lattice_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_text_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_text_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_edit_mesh_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_mesh_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_mesh_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_edit_particle_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_particle_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_particle_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_extra_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_extra_blend_draw(OVERLAY_Data *vedata);
+void OVERLAY_extra_draw(OVERLAY_Data *vedata);
+void OVERLAY_extra_in_front_draw(OVERLAY_Data *vedata);
+void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob);
+
+OVERLAY_ExtraCallBuffers *OVERLAY_extra_call_buffer_get(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_extra_line_dashed(OVERLAY_ExtraCallBuffers *cb,
+ const float start[3],
+ const float end[3],
+ const float color[4]);
+void OVERLAY_extra_line(OVERLAY_ExtraCallBuffers *cb,
+ const float start[3],
+ const float end[3],
+ const int color_id);
+void OVERLAY_empty_shape(OVERLAY_ExtraCallBuffers *cb,
+ const float mat[4][4],
+ const float draw_size,
+ const char draw_type,
+ const float color[4]);
+void OVERLAY_extra_loose_points(OVERLAY_ExtraCallBuffers *cb,
+ struct GPUBatch *geom,
+ const float mat[4][4],
+ const float color[4]);
+void OVERLAY_extra_wire(OVERLAY_ExtraCallBuffers *cb,
+ struct GPUBatch *geom,
+ const float mat[4][4],
+ const float color[4]);
+
+void OVERLAY_facing_init(OVERLAY_Data *vedata);
+void OVERLAY_facing_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_facing_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_grid_init(OVERLAY_Data *vedata);
+void OVERLAY_grid_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_grid_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_image_init(OVERLAY_Data *vedata);
+void OVERLAY_image_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_image_cache_finish(OVERLAY_Data *vedata);
+void OVERLAY_image_draw(OVERLAY_Data *vedata);
+void OVERLAY_image_in_front_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_metaball_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_metaball_draw(OVERLAY_Data *vedata);
+void OVERLAY_metaball_in_front_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_motion_path_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_motion_path_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_outline_init(OVERLAY_Data *vedata);
+void OVERLAY_outline_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
+ Object *ob,
+ OVERLAY_DupliData *dupli,
+ bool init_dupli);
+void OVERLAY_outline_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_paint_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_paint_texture_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_paint_vertex_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_paint_weight_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_paint_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_particle_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_particle_draw(OVERLAY_Data *vedata);
+
+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_wireframe_init(OVERLAY_Data *vedata);
+void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
+ Object *ob,
+ OVERLAY_DupliData *dupli,
+ bool init_dupli);
+void OVERLAY_wireframe_draw(OVERLAY_Data *vedata);
+void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *vedata);
+
+GPUShader *OVERLAY_shader_antialiasing(void);
+GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void);
+GPUShader *OVERLAY_shader_armature_envelope(bool use_outline);
+GPUShader *OVERLAY_shader_armature_shape(bool use_outline);
+GPUShader *OVERLAY_shader_armature_shape_wire(void);
+GPUShader *OVERLAY_shader_armature_sphere(bool use_outline);
+GPUShader *OVERLAY_shader_armature_stick(void);
+GPUShader *OVERLAY_shader_armature_wire(void);
+GPUShader *OVERLAY_shader_depth_only(void);
+GPUShader *OVERLAY_shader_edit_curve_handle(void);
+GPUShader *OVERLAY_shader_edit_curve_point(void);
+GPUShader *OVERLAY_shader_edit_curve_wire(void);
+GPUShader *OVERLAY_shader_edit_lattice_point(void);
+GPUShader *OVERLAY_shader_edit_lattice_wire(void);
+GPUShader *OVERLAY_shader_edit_mesh_analysis(void);
+GPUShader *OVERLAY_shader_edit_mesh_edge(bool use_flat_interp);
+GPUShader *OVERLAY_shader_edit_mesh_face(void);
+GPUShader *OVERLAY_shader_edit_mesh_facedot(void);
+GPUShader *OVERLAY_shader_edit_mesh_normal(void);
+GPUShader *OVERLAY_shader_edit_mesh_skin_root(void);
+GPUShader *OVERLAY_shader_edit_mesh_vert(void);
+GPUShader *OVERLAY_shader_edit_particle_strand(void);
+GPUShader *OVERLAY_shader_edit_particle_point(void);
+GPUShader *OVERLAY_shader_extra(void);
+GPUShader *OVERLAY_shader_extra_groundline(void);
+GPUShader *OVERLAY_shader_extra_wire(bool use_object);
+GPUShader *OVERLAY_shader_extra_loose_point(void);
+GPUShader *OVERLAY_shader_extra_point(void);
+GPUShader *OVERLAY_shader_facing(void);
+GPUShader *OVERLAY_shader_grid(void);
+GPUShader *OVERLAY_shader_image(void);
+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_extra_grid(void);
+GPUShader *OVERLAY_shader_outline_detect(void);
+GPUShader *OVERLAY_shader_paint_face(void);
+GPUShader *OVERLAY_shader_paint_point(void);
+GPUShader *OVERLAY_shader_paint_texture(void);
+GPUShader *OVERLAY_shader_paint_vertcol(void);
+GPUShader *OVERLAY_shader_paint_weight(void);
+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_volume_velocity(bool use_needle);
+GPUShader *OVERLAY_shader_wireframe(void);
+GPUShader *OVERLAY_shader_wireframe_select(void);
+
+OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void);
+
+void OVERLAY_shader_free(void);
+
+#endif /* __OVERLAY_PRIVATE_H__ */
diff --git a/source/blender/draw/engines/overlay/overlay_sculpt.c b/source/blender/draw/engines/overlay/overlay_sculpt.c
new file mode 100644
index 00000000000..dc286d36e9e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_sculpt.c
@@ -0,0 +1,70 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "overlay_private.h"
+
+#include "BKE_pbvh.h"
+#include "BKE_paint.h"
+#include "BKE_subdiv_ccg.h"
+
+void OVERLAY_sculpt_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DRWShadingGroup *grp;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->sculpt_mask_ps, state | pd->clipping_state);
+
+ GPUShader *sh = OVERLAY_shader_sculpt_mask();
+ pd->sculpt_mask_grp = grp = DRW_shgroup_create(sh, psl->sculpt_mask_ps);
+ DRW_shgroup_uniform_float_copy(grp, "maskOpacity", pd->overlay.sculpt_mode_mask_opacity);
+}
+
+void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+
+ if (use_pbvh || !ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active) {
+ if (!use_pbvh || pbvh_has_mask(pbvh)) {
+ DRW_shgroup_call_sculpt(pd->sculpt_mask_grp, ob, false, true, false);
+ }
+ }
+}
+
+void OVERLAY_sculpt_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+
+ DRW_draw_pass(psl->sculpt_mask_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
new file mode 100644
index 00000000000..7bd3cf4a067
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -0,0 +1,1317 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "GPU_shader.h"
+
+#include "UI_resources.h"
+
+#include "overlay_private.h"
+
+extern char datatoc_antialiasing_frag_glsl[];
+extern char datatoc_antialiasing_vert_glsl[];
+extern char datatoc_armature_dof_vert_glsl[];
+extern char datatoc_armature_envelope_distance_frag_glsl[];
+extern char datatoc_armature_envelope_outline_vert_glsl[];
+extern char datatoc_armature_envelope_solid_frag_glsl[];
+extern char datatoc_armature_envelope_solid_vert_glsl[];
+extern char datatoc_armature_shape_outline_geom_glsl[];
+extern char datatoc_armature_shape_outline_vert_glsl[];
+extern char datatoc_armature_shape_solid_frag_glsl[];
+extern char datatoc_armature_shape_solid_vert_glsl[];
+extern char datatoc_armature_shape_wire_vert_glsl[];
+extern char datatoc_armature_sphere_outline_vert_glsl[];
+extern char datatoc_armature_sphere_solid_frag_glsl[];
+extern char datatoc_armature_sphere_solid_vert_glsl[];
+extern char datatoc_armature_stick_frag_glsl[];
+extern char datatoc_armature_stick_vert_glsl[];
+extern char datatoc_armature_wire_frag_glsl[];
+extern char datatoc_armature_wire_vert_glsl[];
+extern char datatoc_depth_only_vert_glsl[];
+extern char datatoc_edit_curve_handle_geom_glsl[];
+extern char datatoc_edit_curve_handle_vert_glsl[];
+extern char datatoc_edit_curve_point_vert_glsl[];
+extern char datatoc_edit_curve_wire_vert_glsl[];
+extern char datatoc_edit_lattice_point_vert_glsl[];
+extern char datatoc_edit_lattice_wire_vert_glsl[];
+extern char datatoc_edit_mesh_common_lib_glsl[];
+extern char datatoc_edit_mesh_frag_glsl[];
+extern char datatoc_edit_mesh_geom_glsl[];
+extern char datatoc_edit_mesh_vert_glsl[];
+extern char datatoc_edit_mesh_normal_vert_glsl[];
+extern char datatoc_edit_mesh_skin_root_vert_glsl[];
+extern char datatoc_edit_mesh_analysis_vert_glsl[];
+extern char datatoc_edit_mesh_analysis_frag_glsl[];
+extern char datatoc_edit_particle_strand_vert_glsl[];
+extern char datatoc_edit_particle_point_vert_glsl[];
+extern char datatoc_extra_frag_glsl[];
+extern char datatoc_extra_vert_glsl[];
+extern char datatoc_extra_groundline_vert_glsl[];
+extern char datatoc_extra_lightprobe_grid_vert_glsl[];
+extern char datatoc_extra_loose_point_vert_glsl[];
+extern char datatoc_extra_loose_point_frag_glsl[];
+extern char datatoc_extra_point_vert_glsl[];
+extern char datatoc_extra_wire_frag_glsl[];
+extern char datatoc_extra_wire_vert_glsl[];
+extern char datatoc_facing_frag_glsl[];
+extern char datatoc_facing_vert_glsl[];
+extern char datatoc_grid_frag_glsl[];
+extern char datatoc_grid_vert_glsl[];
+extern char datatoc_image_frag_glsl[];
+extern char datatoc_image_vert_glsl[];
+extern char datatoc_motion_path_line_vert_glsl[];
+extern char datatoc_motion_path_line_geom_glsl[];
+extern char datatoc_motion_path_point_vert_glsl[];
+extern char datatoc_outline_detect_frag_glsl[];
+extern char datatoc_outline_prepass_frag_glsl[];
+extern char datatoc_outline_prepass_geom_glsl[];
+extern char datatoc_outline_prepass_vert_glsl[];
+extern char datatoc_paint_face_vert_glsl[];
+extern char datatoc_paint_point_vert_glsl[];
+extern char datatoc_paint_texture_frag_glsl[];
+extern char datatoc_paint_texture_vert_glsl[];
+extern char datatoc_paint_vertcol_frag_glsl[];
+extern char datatoc_paint_vertcol_vert_glsl[];
+extern char datatoc_paint_weight_frag_glsl[];
+extern char datatoc_paint_weight_vert_glsl[];
+extern char datatoc_paint_wire_vert_glsl[];
+extern char datatoc_particle_vert_glsl[];
+extern char datatoc_particle_frag_glsl[];
+extern char datatoc_sculpt_mask_vert_glsl[];
+extern char datatoc_volume_velocity_vert_glsl[];
+extern char datatoc_wireframe_vert_glsl[];
+extern char datatoc_wireframe_frag_glsl[];
+
+extern char datatoc_gpu_shader_depth_only_frag_glsl[];
+extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
+extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[];
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+
+extern char datatoc_common_colormanagement_lib_glsl[];
+extern char datatoc_common_fullscreen_vert_glsl[];
+extern char datatoc_common_fxaa_lib_glsl[];
+extern char datatoc_common_smaa_lib_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
+typedef struct OVERLAY_Shaders {
+ GPUShader *antialiasing;
+ GPUShader *armature_dof;
+ GPUShader *armature_envelope_outline;
+ GPUShader *armature_envelope_solid;
+ GPUShader *armature_shape_outline;
+ GPUShader *armature_shape_solid;
+ GPUShader *armature_shape_wire;
+ GPUShader *armature_sphere_outline;
+ GPUShader *armature_sphere_solid;
+ GPUShader *armature_stick;
+ GPUShader *armature_wire;
+ GPUShader *depth_only;
+ GPUShader *edit_curve_handle;
+ GPUShader *edit_curve_point;
+ GPUShader *edit_curve_wire;
+ GPUShader *edit_lattice_point;
+ GPUShader *edit_lattice_wire;
+ GPUShader *edit_mesh_vert;
+ GPUShader *edit_mesh_edge;
+ GPUShader *edit_mesh_edge_flat;
+ GPUShader *edit_mesh_face;
+ GPUShader *edit_mesh_facedot;
+ GPUShader *edit_mesh_skin_root;
+ GPUShader *edit_mesh_vnormals;
+ GPUShader *edit_mesh_normals;
+ GPUShader *edit_mesh_fnormals;
+ GPUShader *edit_mesh_analysis;
+ GPUShader *edit_particle_strand;
+ GPUShader *edit_particle_point;
+ GPUShader *extra;
+ GPUShader *extra_groundline;
+ GPUShader *extra_wire[2];
+ GPUShader *extra_point;
+ GPUShader *extra_lightprobe_grid;
+ GPUShader *extra_loose_point;
+ GPUShader *facing;
+ GPUShader *grid;
+ GPUShader *image;
+ GPUShader *motion_path_line;
+ GPUShader *motion_path_vert;
+ GPUShader *outline_prepass;
+ GPUShader *outline_prepass_wire;
+ GPUShader *outline_detect;
+ GPUShader *paint_face;
+ GPUShader *paint_point;
+ GPUShader *paint_texture;
+ GPUShader *paint_vertcol;
+ GPUShader *paint_weight;
+ GPUShader *paint_wire;
+ GPUShader *particle_dot;
+ GPUShader *particle_shape;
+ GPUShader *sculpt_mask;
+ GPUShader *uniform_color;
+ GPUShader *volume_velocity_needle_sh;
+ GPUShader *volume_velocity_sh;
+ GPUShader *wireframe_select;
+ GPUShader *wireframe;
+} OVERLAY_Shaders;
+
+static struct {
+ OVERLAY_Shaders sh_data[GPU_SHADER_CFG_LEN];
+} e_data = {{{NULL}}};
+
+GPUShader *OVERLAY_shader_antialiasing(void)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (!sh_data->antialiasing) {
+ sh_data->antialiasing = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_antialiasing_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_antialiasing_frag_glsl,
+ NULL},
+ .defs = (const char *[]){NULL},
+ });
+ }
+ return sh_data->antialiasing;
+}
+
+GPUShader *OVERLAY_shader_depth_only(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->depth_only) {
+ sh_data->depth_only = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_depth_only_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_depth_only_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->depth_only;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_vert(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_vert) {
+ sh_data->edit_mesh_vert = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_common_lib_glsl,
+ datatoc_edit_mesh_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define VERT\n", NULL},
+ });
+ }
+ return sh_data->edit_mesh_vert;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_edge(bool use_flat_interp)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ GPUShader **sh = use_flat_interp ? &sh_data->edit_mesh_edge_flat : &sh_data->edit_mesh_edge;
+ if (*sh == NULL) {
+ /* Use geometry shader to draw edge wire-frame. This ensure us
+ * the same result across platforms and more flexibility.
+ * But we pay the cost of running a geometry shader.
+ * In the future we might consider using only the vertex shader
+ * and loading data manually with buffer textures. */
+ const bool use_geom_shader = true;
+ const bool use_smooth_wires = (U.gpu_flag & USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE) == 0;
+ const char *geom_sh_code[] = {use_geom_shader ? sh_cfg->lib : NULL,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_geom_glsl,
+ NULL};
+ const char *vert_sh_code[] = {sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_common_lib_glsl,
+ datatoc_edit_mesh_vert_glsl,
+ NULL};
+ const char *frag_sh_code[] = {sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_common_lib_glsl,
+ datatoc_edit_mesh_frag_glsl,
+ NULL};
+ const char *defs[] = {sh_cfg->def,
+ use_geom_shader ? "#define USE_GEOM_SHADER\n" : "",
+ use_smooth_wires ? "#define USE_SMOOTH_WIRE\n" : "",
+ use_flat_interp ? "#define FLAT\n" : "",
+ "#define EDGE\n",
+ NULL};
+
+ *sh = GPU_shader_create_from_arrays({
+ .vert = vert_sh_code,
+ .frag = frag_sh_code,
+ .geom = geom_sh_code,
+ .defs = defs,
+ });
+ }
+ return *sh;
+}
+
+GPUShader *OVERLAY_shader_armature_sphere(bool use_outline)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ const char extensions[] = "#extension GL_ARB_conservative_depth : enable\n";
+ if (use_outline && !sh_data->armature_sphere_outline) {
+ sh_data->armature_sphere_outline = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_sphere_outline_vert_glsl,
+ NULL},
+ .frag = (const char *[]){extensions,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_wire_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ else if (!sh_data->armature_sphere_solid) {
+ sh_data->armature_sphere_solid = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_sphere_solid_vert_glsl,
+ NULL},
+ .frag = (const char *[]){extensions,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_sphere_solid_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return use_outline ? sh_data->armature_sphere_outline : sh_data->armature_sphere_solid;
+}
+
+GPUShader *OVERLAY_shader_armature_shape(bool use_outline)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (use_outline && !sh_data->armature_shape_outline) {
+ sh_data->armature_shape_outline = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_shape_outline_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_shape_outline_geom_glsl,
+ NULL},
+ .frag =
+ (const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ else if (!sh_data->armature_shape_solid) {
+ sh_data->armature_shape_solid = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_shape_solid_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_armature_shape_solid_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return use_outline ? sh_data->armature_shape_outline : sh_data->armature_shape_solid;
+}
+
+GPUShader *OVERLAY_shader_armature_shape_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->armature_shape_wire) {
+ sh_data->armature_shape_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_shape_wire_vert_glsl,
+ NULL},
+ .frag =
+ (const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->armature_shape_wire;
+}
+
+GPUShader *OVERLAY_shader_armature_envelope(bool use_outline)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (use_outline && !sh_data->armature_envelope_outline) {
+ sh_data->armature_envelope_outline = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_envelope_outline_vert_glsl,
+ NULL},
+ .frag =
+ (const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ else if (!sh_data->armature_envelope_solid) {
+ sh_data->armature_envelope_solid = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_envelope_solid_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_armature_envelope_solid_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return use_outline ? sh_data->armature_envelope_outline : sh_data->armature_envelope_solid;
+}
+
+GPUShader *OVERLAY_shader_armature_stick(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->armature_stick) {
+ sh_data->armature_stick = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_stick_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_armature_stick_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->armature_stick;
+}
+
+GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->armature_dof) {
+ sh_data->armature_dof = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_dof_vert_glsl,
+ NULL},
+ .frag =
+ (const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->armature_dof;
+}
+
+GPUShader *OVERLAY_shader_armature_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->armature_wire) {
+ sh_data->armature_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_wire_vert_glsl,
+ NULL},
+ .frag =
+ (const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->armature_wire;
+}
+
+GPUShader *OVERLAY_shader_edit_curve_handle(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_curve_handle) {
+ sh_data->edit_curve_handle = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_curve_handle_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_curve_handle_geom_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_curve_handle;
+}
+
+GPUShader *OVERLAY_shader_edit_curve_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_curve_point) {
+ sh_data->edit_curve_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_curve_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_curve_point;
+}
+
+GPUShader *OVERLAY_shader_edit_curve_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_curve_wire) {
+ sh_data->edit_curve_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_curve_wire_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define IN_PLACE_INSTANCES\n", NULL},
+ });
+ }
+ return sh_data->edit_curve_wire;
+}
+
+GPUShader *OVERLAY_shader_edit_lattice_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_lattice_point) {
+ sh_data->edit_lattice_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_lattice_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_lattice_point;
+}
+
+GPUShader *OVERLAY_shader_edit_lattice_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_lattice_wire) {
+ sh_data->edit_lattice_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_lattice_wire_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_lattice_wire;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_face(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_face) {
+ sh_data->edit_mesh_face = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_common_lib_glsl,
+ datatoc_edit_mesh_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define FACE\n", NULL},
+ });
+ }
+ return sh_data->edit_mesh_face;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_facedot(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_facedot) {
+ sh_data->edit_mesh_facedot = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_common_lib_glsl,
+ datatoc_edit_mesh_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define FACEDOT\n", NULL},
+ });
+ }
+ return sh_data->edit_mesh_facedot;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_normal(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_normals) {
+ sh_data->edit_mesh_normals = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_normal_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTRIB\n", NULL},
+ });
+ }
+ return sh_data->edit_mesh_normals;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_analysis(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_analysis) {
+ sh_data->edit_mesh_analysis = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_analysis_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_edit_mesh_analysis_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_mesh_analysis;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_skin_root(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_skin_root) {
+ sh_data->edit_mesh_skin_root = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_skin_root_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTRIB\n", NULL},
+ });
+ }
+ return sh_data->edit_mesh_skin_root;
+}
+
+GPUShader *OVERLAY_shader_edit_particle_strand(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_particle_strand) {
+ sh_data->edit_particle_strand = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_particle_strand_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_particle_strand;
+}
+
+GPUShader *OVERLAY_shader_edit_particle_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_particle_point) {
+ sh_data->edit_particle_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_particle_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_particle_point;
+}
+
+GPUShader *OVERLAY_shader_extra(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra) {
+ sh_data->extra = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_extra_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->extra;
+}
+
+GPUShader *OVERLAY_shader_extra_grid(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra_lightprobe_grid) {
+ sh_data->extra_lightprobe_grid = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_common_globals_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl,
+ datatoc_extra_lightprobe_grid_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->extra_lightprobe_grid;
+}
+
+GPUShader *OVERLAY_shader_extra_groundline(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra_groundline) {
+ sh_data->extra_groundline = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_extra_groundline_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->extra_groundline;
+}
+
+GPUShader *OVERLAY_shader_extra_wire(bool use_object)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra_wire[use_object]) {
+ char colorids[1024];
+ /* NOTE: define all ids we need here. */
+ BLI_snprintf(colorids,
+ sizeof(colorids),
+ "#define TH_ACTIVE %d\n"
+ "#define TH_SELECT %d\n"
+ "#define TH_TRANSFORM %d\n"
+ "#define TH_WIRE %d\n"
+ "#define TH_CAMERA_PATH %d\n",
+ TH_ACTIVE,
+ TH_SELECT,
+ TH_TRANSFORM,
+ TH_WIRE,
+ TH_CAMERA_PATH);
+ sh_data->extra_wire[use_object] = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_extra_wire_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_wire_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def,
+ colorids,
+ (use_object) ? "#define OBJECT_WIRE \n" : NULL,
+ NULL},
+ });
+ }
+ return sh_data->extra_wire[use_object];
+}
+
+GPUShader *OVERLAY_shader_extra_loose_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra_loose_point) {
+ sh_data->extra_loose_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_extra_loose_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_extra_loose_point_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->extra_loose_point;
+}
+
+GPUShader *OVERLAY_shader_extra_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra_point) {
+ sh_data->extra_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_extra_point_vert_glsl,
+ NULL},
+ .frag =
+ (const char *[]){datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->extra_point;
+}
+
+GPUShader *OVERLAY_shader_facing(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->facing) {
+ sh_data->facing = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_facing_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl, datatoc_facing_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->facing;
+}
+
+GPUShader *OVERLAY_shader_grid(void)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (!sh_data->grid) {
+ sh_data->grid = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_grid_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_grid_frag_glsl,
+ NULL},
+ });
+ }
+ return sh_data->grid;
+}
+
+GPUShader *OVERLAY_shader_image(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->image) {
+ sh_data->image = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_image_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+ datatoc_image_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->image;
+}
+
+GPUShader *OVERLAY_shader_motion_path_line(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->motion_path_line) {
+ sh_data->motion_path_line = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_motion_path_line_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_motion_path_line_geom_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->motion_path_line;
+}
+
+GPUShader *OVERLAY_shader_motion_path_vert(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->motion_path_vert) {
+ sh_data->motion_path_vert = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_motion_path_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->motion_path_vert;
+}
+
+GPUShader *OVERLAY_shader_outline_prepass(bool use_wire)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (use_wire && !sh_data->outline_prepass_wire) {
+ sh_data->outline_prepass_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl,
+ datatoc_outline_prepass_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_outline_prepass_geom_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_outline_prepass_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define USE_GEOM\n", NULL},
+ });
+ }
+ else if (!sh_data->outline_prepass) {
+ sh_data->outline_prepass = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl,
+ datatoc_outline_prepass_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_outline_prepass_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return use_wire ? sh_data->outline_prepass_wire : sh_data->outline_prepass;
+}
+
+GPUShader *OVERLAY_shader_outline_detect(void)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (!sh_data->outline_detect) {
+ sh_data->outline_detect = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){datatoc_common_fullscreen_vert_glsl, NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl,
+ datatoc_common_globals_lib_glsl,
+ datatoc_outline_detect_frag_glsl,
+ NULL},
+ });
+ }
+ return sh_data->outline_detect;
+}
+
+GPUShader *OVERLAY_shader_paint_face(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_face) {
+ sh_data->paint_face = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_face_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_face;
+}
+
+GPUShader *OVERLAY_shader_paint_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_point) {
+ sh_data->paint_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_point;
+}
+
+GPUShader *OVERLAY_shader_paint_texture(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_texture) {
+ sh_data->paint_texture = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_texture_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+ datatoc_paint_texture_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_texture;
+}
+
+GPUShader *OVERLAY_shader_paint_vertcol(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_vertcol) {
+ sh_data->paint_vertcol = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_vertcol_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_paint_vertcol_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_vertcol;
+}
+
+GPUShader *OVERLAY_shader_paint_weight(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_weight) {
+ sh_data->paint_weight = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_weight_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_paint_weight_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_weight;
+}
+
+GPUShader *OVERLAY_shader_paint_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_wire) {
+ sh_data->paint_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_wire_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_wire;
+}
+
+GPUShader *OVERLAY_shader_particle_dot(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->particle_dot) {
+ sh_data->particle_dot = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_particle_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_particle_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define USE_DOTS\n", NULL},
+ });
+ }
+ return sh_data->particle_dot;
+}
+
+GPUShader *OVERLAY_shader_particle_shape(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->particle_shape) {
+ sh_data->particle_shape = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_particle_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTRIB\n", NULL},
+ });
+ }
+ return sh_data->particle_shape;
+}
+
+GPUShader *OVERLAY_shader_sculpt_mask(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->sculpt_mask) {
+ sh_data->sculpt_mask = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_sculpt_mask_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->sculpt_mask;
+}
+
+struct GPUShader *OVERLAY_shader_uniform_color(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->uniform_color) {
+ sh_data->uniform_color = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_depth_only_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->uniform_color;
+}
+
+struct GPUShader *OVERLAY_shader_volume_velocity(bool use_needle)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (use_needle && !sh_data->volume_velocity_needle_sh) {
+ sh_data->volume_velocity_needle_sh = DRW_shader_create_with_lib(
+ datatoc_volume_velocity_vert_glsl,
+ NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ "#define USE_NEEDLE\n");
+ }
+ else if (!sh_data->volume_velocity_sh) {
+ sh_data->volume_velocity_sh = DRW_shader_create_with_lib(
+ datatoc_volume_velocity_vert_glsl,
+ NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ NULL);
+ }
+ return (use_needle) ? sh_data->volume_velocity_needle_sh : sh_data->volume_velocity_sh;
+}
+
+GPUShader *OVERLAY_shader_wireframe_select(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->wireframe_select) {
+ sh_data->wireframe_select = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_common_globals_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl,
+ datatoc_wireframe_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_wireframe_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define SELECT_EDGES\n", NULL},
+ });
+ }
+ return sh_data->wireframe_select;
+}
+
+GPUShader *OVERLAY_shader_wireframe(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->wireframe) {
+ sh_data->wireframe = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_common_globals_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl,
+ datatoc_wireframe_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_wireframe_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->wireframe;
+}
+
+static OVERLAY_InstanceFormats g_formats = {NULL};
+
+OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void)
+{
+ DRW_shgroup_instance_format(g_formats.pos,
+ {
+ {"pos", DRW_ATTR_FLOAT, 3},
+ });
+ DRW_shgroup_instance_format(g_formats.pos_color,
+ {
+ {"pos", DRW_ATTR_FLOAT, 3},
+ {"color", DRW_ATTR_FLOAT, 4},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_pos,
+ {
+ {"inst_pos", DRW_ATTR_FLOAT, 3},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_extra,
+ {
+ {"color", DRW_ATTR_FLOAT, 4},
+ {"inst_obmat", DRW_ATTR_FLOAT, 16},
+ });
+ DRW_shgroup_instance_format(g_formats.wire_extra,
+ {
+ {"pos", DRW_ATTR_FLOAT, 3},
+ {"colorid", DRW_ATTR_INT, 1},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_bone,
+ {
+ {"inst_obmat", DRW_ATTR_FLOAT, 16},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_bone_stick,
+ {
+ {"boneStart", DRW_ATTR_FLOAT, 3},
+ {"boneEnd", DRW_ATTR_FLOAT, 3},
+ {"wireColor", DRW_ATTR_FLOAT, 4}, /* TODO uchar color */
+ {"boneColor", DRW_ATTR_FLOAT, 4},
+ {"headColor", DRW_ATTR_FLOAT, 4},
+ {"tailColor", DRW_ATTR_FLOAT, 4},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_bone_envelope_outline,
+ {
+ {"headSphere", DRW_ATTR_FLOAT, 4},
+ {"tailSphere", DRW_ATTR_FLOAT, 4},
+ {"outlineColorSize", DRW_ATTR_FLOAT, 4},
+ {"xAxis", DRW_ATTR_FLOAT, 3},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_bone_envelope_distance,
+ {
+ {"headSphere", DRW_ATTR_FLOAT, 4},
+ {"tailSphere", DRW_ATTR_FLOAT, 4},
+ {"xAxis", DRW_ATTR_FLOAT, 3},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_bone_envelope,
+ {
+ {"headSphere", DRW_ATTR_FLOAT, 4},
+ {"tailSphere", DRW_ATTR_FLOAT, 4},
+ {"boneColor", DRW_ATTR_FLOAT, 3},
+ {"stateColor", DRW_ATTR_FLOAT, 3},
+ {"xAxis", DRW_ATTR_FLOAT, 3},
+ });
+
+ return &g_formats;
+}
+
+void OVERLAY_shader_free(void)
+{
+ for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_data_index];
+ GPUShader **sh_data_as_array = (GPUShader **)sh_data;
+ for (int i = 0; i < (sizeof(OVERLAY_Shaders) / sizeof(GPUShader *)); i++) {
+ DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
+ }
+ }
+ struct GPUVertFormat **format = (struct GPUVertFormat **)&g_formats;
+ for (int i = 0; i < sizeof(g_formats) / sizeof(void *); i++, format++) {
+ MEM_SAFE_FREE(*format);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
new file mode 100644
index 00000000000..b52434fa6c6
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -0,0 +1,243 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+
+#include "BLI_hash.h"
+
+#include "GPU_shader.h"
+#include "DRW_render.h"
+
+#include "ED_view3d.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_wireframe_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ DRWView *default_view = (DRWView *)DRW_view_default_get();
+ pd->view_wires = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 0.5f);
+}
+
+void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ DRWShadingGroup *grp = NULL;
+
+ View3DShading *shading = &draw_ctx->v3d->shading;
+
+ pd->shdata.wire_step_param = pd->overlay.wireframe_threshold - 254.0f / 255.0f;
+
+ bool is_wire_shmode = (shading->type == OB_WIRE);
+ bool is_material_shmode = (shading->type > OB_SOLID);
+ bool is_object_color = is_wire_shmode && (shading->wire_color_type == V3D_SHADING_OBJECT_COLOR);
+ bool is_random_color = is_wire_shmode && (shading->wire_color_type == V3D_SHADING_RANDOM_COLOR);
+
+ const bool use_select = (DRW_state_is_select() || DRW_state_is_depth());
+ GPUShader *wires_sh = use_select ? OVERLAY_shader_wireframe_select() :
+ OVERLAY_shader_wireframe();
+
+ for (int xray = 0; xray < 2; xray++) {
+ /* Only do stencil test if stencil buffer is written by the render engine. */
+ DRWState stencil_state = is_material_shmode ? 0 : DRW_STATE_STENCIL_EQUAL;
+ DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR |
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRWPass *pass;
+ uint stencil_mask;
+
+ if (xray == 0) {
+ DRW_PASS_CREATE(psl->wireframe_ps, state | stencil_state | pd->clipping_state);
+ pass = psl->wireframe_ps;
+ stencil_mask = 0xFF;
+ }
+ else {
+ DRW_PASS_CREATE(psl->wireframe_xray_ps, state | pd->clipping_state);
+ pass = psl->wireframe_xray_ps;
+ stencil_mask = 0x00;
+ }
+
+ for (int use_coloring = 0; use_coloring < 2; use_coloring++) {
+ pd->wires_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "wireStepParam", pd->shdata.wire_step_param);
+ DRW_shgroup_uniform_bool_copy(grp, "useColoring", use_coloring);
+ DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
+ DRW_shgroup_uniform_bool_copy(grp, "isObjectColor", is_object_color);
+ DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color);
+ DRW_shgroup_stencil_mask(grp, stencil_mask);
+
+ pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
+ DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f);
+ DRW_shgroup_stencil_mask(grp, stencil_mask);
+ }
+
+ pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass);
+ DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f);
+ DRW_shgroup_uniform_bool_copy(grp, "useColoring", false);
+ DRW_shgroup_stencil_mask(grp, stencil_mask);
+ }
+}
+
+void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
+ Object *ob,
+ OVERLAY_DupliData *dupli,
+ bool init_dupli)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_PrivateData *pd = data->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES) != 0;
+ const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0;
+ const bool is_mesh = ob->type == OB_MESH;
+ const bool use_wire = (pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) || (ob->dtx & OB_DRAWWIRE) ||
+ (ob->dt == OB_WIRE);
+
+ if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+
+ struct GPUBatch *geom = NULL;
+ switch (ob->type) {
+ case OB_CURVE:
+ geom = DRW_cache_curve_edge_wire_get(ob);
+ break;
+ case OB_SURF:
+ geom = DRW_cache_surf_edge_wire_get(ob);
+ break;
+ }
+
+ if (geom) {
+ OVERLAY_extra_wire(cb, geom, ob->obmat, color);
+ }
+ }
+
+ /* Fast path for duplis. */
+ if (dupli && !init_dupli) {
+ if (dupli->wire_shgrp && dupli->wire_geom) {
+ if (dupli->base_flag == ob->base_flag) {
+ DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob);
+ return;
+ }
+ }
+ else {
+ /* Nothing to draw for this dupli. */
+ return;
+ }
+ }
+
+ const bool is_edit_mode = BKE_object_is_in_editmode(ob);
+ bool has_edit_mesh_cage = false;
+ if (is_mesh && is_edit_mode) {
+ /* TODO: Should be its own function. */
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *embm = me->edit_mesh;
+ if (embm) {
+ has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
+ }
+ }
+
+ /* Don't do that in edit Mesh mode, unless there is a modifier preview. */
+ if (use_wire && (!is_mesh || (!is_edit_mode || has_edit_mesh_cage))) {
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
+ const bool use_coloring = (use_wire && !is_edit_mode && !use_sculpt_pbvh &&
+ !has_edit_mesh_cage);
+ DRWShadingGroup *shgrp = NULL;
+ struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob);
+
+ if (geom || use_sculpt_pbvh) {
+ if (use_sculpt_pbvh) {
+ shgrp = pd->wires_sculpt_grp[is_xray];
+ }
+ else if (all_wires) {
+ shgrp = pd->wires_all_grp[is_xray][use_coloring];
+ }
+ else {
+ shgrp = pd->wires_grp[is_xray][use_coloring];
+ }
+
+ if (use_sculpt_pbvh) {
+ DRW_shgroup_call_sculpt(shgrp, ob, true, false, false);
+ }
+ else {
+ DRW_shgroup_call(shgrp, geom, ob);
+ }
+ }
+
+ if (dupli) {
+ dupli->wire_shgrp = shgrp;
+ dupli->wire_geom = geom;
+ }
+ }
+ else if (is_mesh && (!is_edit_mode || has_edit_mesh_cage)) {
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ Mesh *me = ob->data;
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+
+ /* Draw loose geometry. */
+ if (me->totedge == 0 && me->totvert > 0) {
+ struct GPUBatch *geom = DRW_cache_mesh_all_verts_get(ob);
+ if (geom) {
+ OVERLAY_extra_loose_points(cb, geom, ob->obmat, color);
+ }
+ }
+ else {
+ struct GPUBatch *geom = DRW_cache_mesh_loose_edges_get(ob);
+ if (geom) {
+ OVERLAY_extra_wire(cb, geom, ob->obmat, color);
+ }
+ }
+ }
+}
+
+void OVERLAY_wireframe_draw(OVERLAY_Data *data)
+{
+ OVERLAY_PassList *psl = data->psl;
+ OVERLAY_PrivateData *pd = data->stl->pd;
+
+ DRW_view_set_active(pd->view_wires);
+ DRW_draw_pass(psl->wireframe_ps);
+
+ DRW_view_set_active(NULL);
+}
+
+void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *data)
+{
+ OVERLAY_PassList *psl = data->psl;
+ OVERLAY_PrivateData *pd = data->stl->pd;
+
+ DRW_view_set_active(pd->view_wires);
+ DRW_draw_pass(psl->wireframe_xray_ps);
+
+ DRW_view_set_active(NULL);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
new file mode 100644
index 00000000000..4784d420e1d
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
@@ -0,0 +1,150 @@
+
+uniform sampler2D colorTex;
+uniform sampler2D depthTex;
+uniform sampler2D lineTex;
+uniform bool doSmoothLines;
+
+in vec2 uvs;
+
+out vec4 fragColor;
+
+#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */
+
+/**
+ * We want to know how much a pixel is covered by a line.
+ * We replace the square pixel with acircle of the same area and try to find the intersection area.
+ * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment
+ * The formula for the area uses inverse trig function and is quite complexe. Instead,
+ * we approximate it by using the smoothstep function and a 1.05 factor to the disc radius.
+ */
+#define DISC_RADIUS (M_1_SQRTPI * 1.05)
+#define LINE_SMOOTH_START (0.5 - DISC_RADIUS)
+#define LINE_SMOOTH_END (0.5 + DISC_RADIUS)
+
+/**
+ * Returns coverage of a line onto a sample that is distance_to_line (in pixels) far from the line.
+ * line_kernel_size is the inner size of the line with 100% coverage.
+ */
+float line_coverage(float distance_to_line, float line_kernel_size)
+{
+ if (doSmoothLines) {
+ return smoothstep(
+ LINE_SMOOTH_END, LINE_SMOOTH_START, abs(distance_to_line) - line_kernel_size);
+ }
+ else {
+ return step(-0.5, line_kernel_size - abs(distance_to_line));
+ }
+}
+vec4 line_coverage(vec4 distance_to_line, float line_kernel_size)
+{
+ if (doSmoothLines) {
+ return smoothstep(
+ LINE_SMOOTH_END, LINE_SMOOTH_START, abs(distance_to_line) - line_kernel_size);
+ }
+ else {
+ return step(-0.5, line_kernel_size - abs(distance_to_line));
+ }
+}
+
+vec2 decode_line_dir(vec2 dir)
+{
+ return dir * 2.0 - 1.0;
+}
+
+float decode_line_dist(float dist)
+{
+ return (dist - 0.1) * 4.0 - 2.0;
+}
+
+float neighbor_dist(vec3 line_dir_and_dist, vec2 ofs)
+{
+ float dist = decode_line_dist(line_dir_and_dist.z);
+ vec2 dir = decode_line_dir(line_dir_and_dist.xy);
+
+ bool is_line = line_dir_and_dist.z != 0.0;
+ bool dir_horiz = abs(dir.x) > abs(dir.y);
+ bool ofs_horiz = (ofs.x != 0);
+
+ if (!is_line || (ofs_horiz != dir_horiz)) {
+ dist += 1e10; /* No line. */
+ }
+ else {
+ dist += dot(ofs, -dir);
+ }
+ return dist;
+}
+
+void neighbor_blend(
+ float line_coverage, float line_depth, vec4 line_color, inout float frag_depth, inout vec4 col)
+{
+ line_color *= line_coverage;
+ if (line_coverage > 0.0 && line_depth < frag_depth) {
+ /* Alpha over. */
+ col = col * (1.0 - line_color.a) + line_color;
+ frag_depth = line_depth;
+ }
+ else {
+ /* Alpha under. */
+ col = col + line_color * (1.0 - col.a);
+ }
+}
+
+void main()
+{
+ ivec2 center_texel = ivec2(gl_FragCoord.xy);
+ float line_kernel = sizePixel * 0.5 - 0.5;
+
+ fragColor = texelFetch(colorTex, center_texel, 0);
+
+ bool original_col_has_alpha = fragColor.a < 1.0;
+
+ float depth = texelFetch(depthTex, center_texel, 0).r;
+
+ float dist_raw = texelFetch(lineTex, center_texel, 0).b;
+ float dist = decode_line_dist(dist_raw);
+
+ /* TODO Opti: use textureGather */
+ vec4 neightbor_col0 = texelFetchOffset(colorTex, center_texel, 0, ivec2(1, 0));
+ vec4 neightbor_col1 = texelFetchOffset(colorTex, center_texel, 0, ivec2(-1, 0));
+ vec4 neightbor_col2 = texelFetchOffset(colorTex, center_texel, 0, ivec2(0, 1));
+ vec4 neightbor_col3 = texelFetchOffset(colorTex, center_texel, 0, ivec2(0, -1));
+
+ vec3 neightbor_line0 = texelFetchOffset(lineTex, center_texel, 0, ivec2(1, 0)).rgb;
+ vec3 neightbor_line1 = texelFetchOffset(lineTex, center_texel, 0, ivec2(-1, 0)).rgb;
+ vec3 neightbor_line2 = texelFetchOffset(lineTex, center_texel, 0, ivec2(0, 1)).rgb;
+ vec3 neightbor_line3 = texelFetchOffset(lineTex, center_texel, 0, ivec2(0, -1)).rgb;
+
+ vec4 depths;
+ depths.x = texelFetchOffset(depthTex, center_texel, 0, ivec2(1, 0)).r;
+ depths.y = texelFetchOffset(depthTex, center_texel, 0, ivec2(-1, 0)).r;
+ depths.z = texelFetchOffset(depthTex, center_texel, 0, ivec2(0, 1)).r;
+ depths.w = texelFetchOffset(depthTex, center_texel, 0, ivec2(0, -1)).r;
+
+ vec4 line_dists;
+ line_dists.x = neighbor_dist(neightbor_line0, vec2(1, 0));
+ line_dists.y = neighbor_dist(neightbor_line1, vec2(-1, 0));
+ line_dists.z = neighbor_dist(neightbor_line2, vec2(0, 1));
+ line_dists.w = neighbor_dist(neightbor_line3, vec2(0, -1));
+
+ vec4 coverage = line_coverage(line_dists, line_kernel);
+
+ if (dist_raw > 0.0) {
+ fragColor *= line_coverage(dist, line_kernel);
+ }
+
+ /* We dont order fragments but use alpha over/alpha under based on current minimum frag depth. */
+ neighbor_blend(coverage.x, depths.x, neightbor_col0, depth, fragColor);
+ neighbor_blend(coverage.y, depths.y, neightbor_col1, depth, fragColor);
+ neighbor_blend(coverage.z, depths.z, neightbor_col2, depth, fragColor);
+ neighbor_blend(coverage.w, depths.w, neightbor_col3, depth, fragColor);
+
+#if 1
+ /* Fix aliasing issue with really dense meshes and 1 pixel sized lines. */
+ if (!original_col_has_alpha && dist_raw > 0.0 && line_kernel < 0.45) {
+ vec4 lines = vec4(neightbor_line0.z, neightbor_line1.z, neightbor_line2.z, neightbor_line3.z);
+ /* Count number of line neighbors. */
+ float blend = dot(vec4(0.25), step(0.001, lines));
+ fragColor = mix(fragColor, fragColor / fragColor.a, blend);
+ }
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl
new file mode 100644
index 00000000000..8cf8ba121ed
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl
@@ -0,0 +1,11 @@
+
+out vec2 uvs;
+
+void main()
+{
+ int v = gl_VertexID % 3;
+ float x = float((v & 1) << 2);
+ float y = float((v & 2) << 1);
+ gl_Position = vec4(x - 1.0, y - 1.0, 1.0, 1.0);
+ uvs = vec2(x, y) * 0.5;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl
new file mode 100644
index 00000000000..b15554bbb6a
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl
@@ -0,0 +1,43 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec2 pos;
+
+/* ---- Per instance Attrs ---- */
+/* Assumed to be in world coordinate already. */
+in vec4 color;
+in mat4 inst_obmat;
+
+flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+
+vec3 sphere_project(float ax, float az)
+{
+ float sine = 1.0 - ax * ax - az * az;
+ float q3 = sqrt(max(0.0, sine));
+
+ return vec3(-az * q3, 0.5 - sine, ax * q3) * 2.0;
+}
+
+void main()
+{
+ mat4 model_mat = inst_obmat;
+ model_mat[0][3] = model_mat[1][3] = model_mat[2][3] = 0.0;
+ model_mat[3][3] = 1.0;
+
+ vec2 amin = vec2(inst_obmat[0][3], inst_obmat[1][3]);
+ vec2 amax = vec2(inst_obmat[2][3], inst_obmat[3][3]);
+
+ vec3 final_pos = sphere_project(pos.x * abs((pos.x > 0.0) ? amax.x : amin.x),
+ pos.y * abs((pos.y > 0.0) ? amax.y : amin.y));
+
+ vec3 world_pos = (model_mat * vec4(final_pos, 1.0)).xyz;
+ gl_Position = point_world_to_ndc(world_pos);
+ finalColor = color;
+
+ edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl
index c0bde90bf28..2260b2d3fa6 100644
--- a/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl
@@ -1,12 +1,4 @@
-uniform mat4 ViewMatrix;
-uniform mat4 ViewMatrixInverse;
-uniform mat4 ViewProjectionMatrix;
-uniform mat4 ProjectionMatrix;
-
-uniform vec2 viewportSize;
-uniform float lineThickness = 2.0;
-
/* ---- Instantiated Attrs ---- */
in vec2 pos0;
in vec2 pos1;
@@ -20,11 +12,13 @@ in vec4 outlineColorSize;
in vec3 xAxis;
flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
/* project to screen space */
vec2 proj(vec4 pos)
{
- return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+ return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
}
vec2 compute_dir(vec2 v0, vec2 v1, vec2 v2)
@@ -140,32 +134,27 @@ void main()
vec3 wpos2 = get_outline_point(
pos2, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
- vec4 pos_4d = vec4(wpos1, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(pos_4d.xyz);
+ world_clip_planes_calc_clip_distance(wpos1);
#endif
- vec4 V = ViewMatrix * pos_4d;
- float pres_fac = (ProjectionMatrix[3][3] == 0.0) ? abs(V.z) : 1.0;
+ vec4 p0 = point_world_to_ndc(wpos0);
+ vec4 p1 = point_world_to_ndc(wpos1);
+ vec4 p2 = point_world_to_ndc(wpos2);
- vec4 p0 = ViewProjectionMatrix * vec4(wpos0, 1.0);
- vec4 p1 = ProjectionMatrix * V;
- vec4 p2 = ViewProjectionMatrix * vec4(wpos2, 1.0);
+ gl_Position = p1;
/* compute position from 3 vertex because the change in direction
* can happen very quicky and lead to very thin edges. */
vec2 ss0 = proj(p0);
vec2 ss1 = proj(p1);
vec2 ss2 = proj(p2);
- vec2 edge_dir = compute_dir(ss0, ss1, ss2);
+ vec2 ofs_dir = compute_dir(ss0, ss1, ss2);
- bool outer = ((gl_VertexID & 1) == 1);
- vec2 t = outlineColorSize.w * (lineThickness / viewportSize);
- t *= pres_fac;
- t = (outer) ? t : vec2(0.0);
+ /* Offset away from the center to avoid overlap with solid shape. */
+ gl_Position.xy += ofs_dir * sizeViewportInv.xy * gl_Position.w;
- gl_Position = p1;
- gl_Position.xy += t * edge_dir;
+ edgeStart = edgePos = proj(gl_Position);
finalColor = vec4(outlineColorSize.rgb, 1.0);
}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
new file mode 100644
index 00000000000..1be9a46e8c7
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
@@ -0,0 +1,27 @@
+
+uniform float alpha = 0.6;
+uniform bool isDistance;
+
+flat in vec3 finalStateColor;
+flat in vec3 finalBoneColor;
+in vec3 normalView;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
+
+void main()
+{
+ float n = normalize(normalView).z;
+ if (isDistance) {
+ n = 1.0 - clamp(-n, 0.0, 1.0);
+ fragColor = vec4(1.0, 1.0, 1.0, 0.2) * n;
+ }
+ else {
+ /* Smooth lighting factor. */
+ const float s = 0.2; /* [0.0-0.5] range */
+ float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0);
+ fragColor.rgb = mix(finalStateColor, finalBoneColor, fac);
+ fragColor.a = alpha;
+ }
+ lineOutput = vec4(0.0);
+}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl
index d9567bb84f4..620b3f2527c 100644
--- a/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl
@@ -1,8 +1,4 @@
-uniform mat4 ViewMatrix;
-uniform mat4 ViewMatrixInverse;
-uniform mat4 ViewProjectionMatrix;
-
/* ---- Instantiated Attrs ---- */
in vec3 pos;
diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl
index dc84b8924d1..ffc941149c7 100644
--- a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl
@@ -1,6 +1,6 @@
layout(lines_adjacency) in;
-layout(triangle_strip, max_vertices = 6) out;
+layout(line_strip, max_vertices = 2) out;
in vec4 pPos[];
in vec3 vPos[];
@@ -9,57 +9,8 @@ in vec2 ssNor[];
in vec4 vColSize[];
flat out vec4 finalColor;
-uniform vec2 viewportSize;
-uniform float lineThickness = 2.0;
-
-vec2 compute_dir(vec2 v0, vec2 v1)
-{
- vec2 dir = normalize(v1 - v0);
- dir = vec2(-dir.y, dir.x);
- return dir;
-}
-
-void emit_edge(vec2 edge_dir, vec2 hidden_dir, vec2 thick, bool is_persp)
-{
- float fac = dot(-hidden_dir, edge_dir);
- edge_dir *= (fac < 0.0) ? -1.0 : 1.0;
-
- vec2 t = thick * (is_persp ? abs(vPos[1].z) : 1.0);
- gl_Position = pPos[1];
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
-#endif
- EmitVertex();
- gl_Position.xy += t * edge_dir;
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
-#endif
- EmitVertex();
-
- t = thick * (is_persp ? abs(vPos[2].z) : 1.0);
- gl_Position = pPos[2];
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[2].gl_ClipDistance);
-#endif
- EmitVertex();
- gl_Position.xy += t * edge_dir;
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[2].gl_ClipDistance);
-#endif
- EmitVertex();
-}
-
-void emit_corner(const int e, vec2 thick, bool is_persp)
-{
- vec2 corner_dir = ssNor[e];
- vec2 t = thick * (is_persp ? abs(vPos[e].z) : 1.0);
-
- gl_Position = pPos[e] + vec4(t * corner_dir, 0.0, 0.0);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[e].gl_ClipDistance);
-#endif
- EmitVertex();
-}
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
void main(void)
{
@@ -93,8 +44,8 @@ void main(void)
return;
}
- vec2 thick = vColSize[0].w * (lineThickness / viewportSize);
- vec2 edge_dir = compute_dir(ssPos[1], ssPos[2]);
+ vec2 perp = normalize(ssPos[2] - ssPos[1]);
+ vec2 edge_dir = vec2(-perp.y, perp.x);
vec2 hidden_point;
/* Take the farthest point to compute edge direction
@@ -110,8 +61,30 @@ void main(void)
}
vec2 hidden_dir = normalize(hidden_point - ssPos[1]);
- emit_corner(1, thick, is_persp);
- emit_edge(edge_dir, hidden_dir, thick, is_persp);
- emit_corner(2, thick, is_persp);
+ float fac = dot(-hidden_dir, edge_dir);
+ edge_dir *= (fac < 0.0) ? -1.0 : 1.0;
+
+ gl_Position = pPos[1];
+ /* Offset away from the center to avoid overlap with solid shape. */
+ gl_Position.xy += (edge_dir - perp) * sizeViewportInv.xy * gl_Position.w;
+ /* Improve AA bleeding inside bone silhouette. */
+ gl_Position.z -= 1e-4;
+ edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
+#endif
+ EmitVertex();
+
+ gl_Position = pPos[2];
+ /* Offset away from the center to avoid overlap with solid shape. */
+ gl_Position.xy += (edge_dir + perp) * sizeViewportInv.xy * gl_Position.w;
+ /* Improve AA bleeding inside bone silhouette. */
+ gl_Position.z -= 1e-4;
+ edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[2].gl_ClipDistance);
+#endif
+ EmitVertex();
+
EndPrimitive();
}
diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl
index fb2735c196c..cd9368a997a 100644
--- a/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl
@@ -1,13 +1,11 @@
-uniform vec2 viewportSize;
-
/* ---- Instantiated Attrs ---- */
in vec3 pos;
in vec3 snor;
/* ---- Per instance Attrs ---- */
-in mat4 InstanceModelMatrix;
-in vec4 outlineColorSize;
+in vec4 color;
+in mat4 inst_obmat;
out vec4 pPos;
out vec3 vPos;
@@ -18,12 +16,15 @@ out vec4 vColSize;
/* project to screen space */
vec2 proj(vec4 pos)
{
- return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+ return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
}
void main()
{
- vec4 worldPosition = InstanceModelMatrix * vec4(pos, 1.0);
+ vec4 bone_color, state_color;
+ mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
+
+ vec4 worldPosition = model_mat * vec4(pos, 1.0);
vec4 viewpos = ViewMatrix * worldPosition;
vPos = viewpos.xyz;
@@ -31,7 +32,7 @@ void main()
/* This is slow and run per vertex, but it's still faster than
* doing it per instance on CPU and sending it on via instance attribute. */
- mat3 normal_mat = transpose(inverse(mat3(InstanceModelMatrix)));
+ mat3 normal_mat = transpose(inverse(mat3(model_mat)));
/* TODO FIX: there is still a problem with this vector
* when the bone is scaled or in persp mode. But it's
* barelly visible at the outline corners. */
@@ -39,7 +40,7 @@ void main()
ssPos = proj(pPos);
- vColSize = outlineColorSize;
+ vColSize = bone_color;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(worldPosition.xyz);
diff --git a/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl
index 39963344dd8..54cd807edaa 100644
--- a/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl
@@ -3,9 +3,11 @@ uniform float alpha = 0.6;
in vec4 finalColor;
-out vec4 fragColor;
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
void main()
{
fragColor = vec4(finalColor.rgb, alpha);
+ lineOutput = vec4(0.0);
}
diff --git a/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl
index df6a9ce2d76..8284bd43adc 100644
--- a/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl
@@ -4,17 +4,18 @@ in vec3 pos;
in vec3 nor;
/* ---- Per instance Attrs ---- */
-in mat4 InstanceModelMatrix;
-in vec3 boneColor;
-in vec3 stateColor;
+in mat4 inst_obmat;
out vec4 finalColor;
void main()
{
+ vec4 bone_color, state_color;
+ mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
+
/* This is slow and run per vertex, but it's still faster than
* doing it per instance on CPU and sending it on via instance attribute. */
- mat3 normal_mat = transpose(inverse(mat3(InstanceModelMatrix)));
+ mat3 normal_mat = transpose(inverse(mat3(model_mat)));
vec3 normal = normalize(normal_world_to_view(normal_mat * nor));
/* Do lighting at an angle to avoid flat shading on front facing bone. */
@@ -24,10 +25,10 @@ void main()
/* Smooth lighting factor. */
const float s = 0.2; /* [0.0-0.5] range */
float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0);
- finalColor.rgb = mix(stateColor, boneColor, fac);
+ finalColor.rgb = mix(state_color.rgb, bone_color.rgb, fac);
finalColor.a = 1.0;
- vec4 worldPosition = InstanceModelMatrix * vec4(pos, 1.0);
+ vec4 worldPosition = model_mat * vec4(pos, 1.0);
gl_Position = ViewProjectionMatrix * worldPosition;
#ifdef USE_WORLD_CLIP_PLANES
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl
new file mode 100644
index 00000000000..0bf21cbaaac
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl
@@ -0,0 +1,29 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec3 pos;
+in vec3 nor;
+
+/* ---- Per instance Attrs ---- */
+in mat4 inst_obmat;
+
+flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+
+void main()
+{
+ vec4 bone_color, state_color;
+ mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
+
+ vec3 world_pos = (model_mat * vec4(pos, 1.0)).xyz;
+ gl_Position = point_world_to_ndc(world_pos);
+
+ finalColor.rgb = mix(state_color.rgb, bone_color.rgb, 0.5);
+ finalColor.a = 1.0;
+
+ edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl
index 70a7f495af9..934485359b3 100644
--- a/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl
@@ -1,40 +1,26 @@
-uniform mat4 ViewMatrix;
-uniform mat4 ProjectionMatrix;
-uniform vec2 viewportSize;
-uniform float lineThickness = 2.0;
-
/* ---- Instantiated Attrs ---- */
-in vec2 pos0;
-in vec2 pos1;
+in vec2 pos;
/* ---- Per instance Attrs ---- */
-in mat4 InstanceModelMatrix;
-in vec4 outlineColorSize;
+in mat4 inst_obmat;
flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
/* project to screen space */
vec2 proj(vec4 pos)
{
- return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
-}
-
-vec2 compute_dir(vec2 v0, vec2 v1, vec2 c)
-{
- vec2 dir = normalize(v1 - v0);
- dir = vec2(dir.y, -dir.x);
- /* The model matrix can be scaled negativly.
- * Use projected sphere center to determine
- * the outline direction. */
- vec2 cv = c - v0;
- dir = (dot(dir, cv) > 0.0) ? -dir : dir;
- return dir;
+ return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
}
void main()
{
- mat4 model_view_matrix = ViewMatrix * InstanceModelMatrix;
+ 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 sphereMatrix = inverse(model_view_matrix);
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
@@ -76,32 +62,22 @@ void main()
}
/* Camera oriented position (but still in local space) */
- vec3 cam_pos0 = x_axis * pos0.x + y_axis * pos0.y + z_axis * z_ofs;
- vec3 cam_pos1 = x_axis * pos1.x + y_axis * pos1.y + z_axis * z_ofs;
+ 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);
- vec4 p0 = ProjectionMatrix * V;
- vec4 p1 = ProjectionMatrix * (model_view_matrix * vec4(cam_pos1, 1.0));
- vec4 c = ProjectionMatrix * vec4(model_view_matrix[3].xyz, 1.0);
-
- vec2 ssc = proj(c);
- vec2 ss0 = proj(p0);
- vec2 ss1 = proj(p1);
- vec2 edge_dir = compute_dir(ss0, ss1, ssc);
-
- bool outer = ((gl_VertexID & 1) == 1);
+ gl_Position = ProjectionMatrix * V;
+ vec4 center = ProjectionMatrix * vec4(model_view_matrix[3].xyz, 1.0);
- vec2 t = outlineColorSize.w * (lineThickness / viewportSize);
- t *= (is_persp) ? abs(V.z) : 1.0;
- t = (outer) ? t : vec2(0.0);
+ /* Offset away from the center to avoid overlap with solid shape. */
+ vec2 ofs_dir = normalize(proj(gl_Position) - proj(center));
+ gl_Position.xy += ofs_dir * sizeViewportInv.xy * gl_Position.w;
- gl_Position = p0;
- gl_Position.xy += t * edge_dir;
+ edgeStart = edgePos = proj(gl_Position);
- finalColor = vec4(outlineColorSize.rgb, 1.0);
+ finalColor = vec4(bone_color.rgb, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- vec4 worldPosition = InstanceModelMatrix * vec4(cam_pos0, 1.0);
+ vec4 worldPosition = model_mat * vec4(cam_pos0, 1.0);
world_clip_planes_calc_clip_distance(worldPosition.xyz);
#endif
}
diff --git a/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl
index 93edbe940fd..0ff0fdf0870 100644
--- a/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl
@@ -1,8 +1,4 @@
-#extension GL_ARB_conservative_depth : enable
-
-uniform mat4 ViewMatrixInverse;
-uniform mat4 ProjectionMatrix;
uniform float alpha = 0.4;
flat in vec3 finalStateColor;
@@ -15,7 +11,8 @@ in vec3 viewPosition;
layout(depth_greater) out float gl_FragDepth;
#endif
-out vec4 fragColor;
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
#define cameraPos ViewMatrixInverse[3].xyz
@@ -74,6 +71,7 @@ void main()
dither *= (1.0 / 255.0); /* Assume 8bit per color buffer. */
fragColor = vec4(fragColor.rgb + dither, alpha);
+ lineOutput = vec4(0.0);
t /= ray_len;
gl_FragDepth = get_depth_from_view_z(ray_dir_view.z * t + ray_ori_view.z);
diff --git a/source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl
index 38a721616a0..e6fa29ce851 100644
--- a/source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl
@@ -1,14 +1,10 @@
-uniform mat4 ViewMatrix;
-uniform mat4 ProjectionMatrix;
-
/* ---- Instantiated Attrs ---- */
in vec2 pos;
/* ---- Per instance Attrs ---- */
-in mat4 InstanceModelMatrix;
-in vec3 stateColor;
-in vec3 boneColor;
+in vec4 color;
+in mat4 inst_obmat;
flat out vec3 finalStateColor;
flat out vec3 finalBoneColor;
@@ -20,7 +16,10 @@ const float rad = 0.05;
void main()
{
- mat4 model_view_matrix = ViewMatrix * InstanceModelMatrix;
+ 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;
sphereMatrix = inverse(model_view_matrix);
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
@@ -78,11 +77,11 @@ void main()
gl_Position = ProjectionMatrix * V;
viewPosition = V.xyz;
- finalStateColor = stateColor;
- finalBoneColor = boneColor;
+ finalStateColor = state_color.xyz;
+ finalBoneColor = bone_color.xyz;
#ifdef USE_WORLD_CLIP_PLANES
- vec4 worldPosition = InstanceModelMatrix * pos_4d;
+ vec4 worldPosition = model_mat * pos_4d;
world_clip_planes_calc_clip_distance(worldPosition.xyz);
#endif
}
diff --git a/source/blender/draw/modes/shaders/armature_stick_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
index ba89619e051..e7696c1ea7d 100644
--- a/source/blender/draw/modes/shaders/armature_stick_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
@@ -3,11 +3,13 @@ noperspective in float colorFac;
flat in vec4 finalWireColor;
flat in vec4 finalInnerColor;
-out vec4 fragColor;
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
void main()
{
float fac = smoothstep(1.0, 0.2, colorFac);
fragColor.rgb = mix(finalInnerColor.rgb, finalWireColor.rgb, fac);
fragColor.a = 1.0;
+ lineOutput = vec4(0.0);
}
diff --git a/source/blender/draw/modes/shaders/armature_stick_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl
index fd8a12fcd2c..99bdbfea2be 100644
--- a/source/blender/draw/modes/shaders/armature_stick_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl
@@ -1,10 +1,4 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewProjectionMatrix;
-
-uniform mat4 ViewMatrix;
-uniform vec2 viewportSize;
-
/* ---- Instantiated Attrs ---- */
in vec2 pos; /* bone aligned screen space */
in uint flag;
@@ -34,12 +28,10 @@ noperspective out float colorFac;
flat out vec4 finalWireColor;
flat out vec4 finalInnerColor;
-uniform float stickSize = 5.0; /* might be dependent on DPI setting in the future. */
-
/* project to screen space */
vec2 proj(vec4 pos)
{
- return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+ return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
}
void main()
@@ -83,8 +75,9 @@ void main()
vpos *= (do_wire) ? 1.0 : 0.5;
if (finalInnerColor.a > 0.0) {
+ float stick_size = sizePixel * 5.0;
gl_Position = (is_head) ? p0 : p1;
- gl_Position.xy += stickSize * (vpos / viewportSize);
+ gl_Position.xy += stick_size * (vpos * sizeViewportInv.xy);
gl_Position.z += (is_bone) ? 0.0 : 1e-6; /* Avoid Z fighting of head/tails. */
#ifdef USE_WORLD_CLIP_PLANES
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
new file mode 100644
index 00000000000..9413ac0f365
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
@@ -0,0 +1,13 @@
+
+flat in vec4 finalColor;
+flat in vec2 edgeStart;
+noperspective in vec2 edgePos;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
+
+void main()
+{
+ lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
+ fragColor = finalColor;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl
new file mode 100644
index 00000000000..d6d6cb6e024
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl
@@ -0,0 +1,22 @@
+
+in vec3 color;
+in vec3 pos;
+
+flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+
+void main()
+{
+ finalColor.rgb = color;
+ finalColor.a = 1.0;
+
+ vec3 worldPosition = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(worldPosition);
+
+ edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(worldPosition);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/pose_selection_vert.glsl b/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl
index 2dd84c0a060..7a3af0f3b61 100644
--- a/source/blender/draw/modes/shaders/pose_selection_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl
@@ -3,6 +3,8 @@ in vec3 pos;
void main()
{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl
index d5674e8f570..b6576ba7a21 100644
--- a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl
@@ -6,7 +6,6 @@
layout(lines) in;
layout(triangle_strip, max_vertices = 10) out;
-uniform vec2 viewportSize;
uniform bool showCurveHandles;
flat in int vertFlag[];
@@ -82,9 +81,9 @@ void main()
vec4(inner_color.rgb, 0.0);
vec2 v1_2 = (v2.xy / v2.w - v1.xy / v1.w);
- vec2 offset = sizeEdge * 4.0 / viewportSize; /* 4.0 is eyeballed */
+ vec2 offset = sizeEdge * 4.0 * sizeViewportInv.xy; /* 4.0 is eyeballed */
- if (abs(v1_2.x * viewportSize.x) < abs(v1_2.y * viewportSize.y)) {
+ if (abs(v1_2.x * sizeViewport.x) < abs(v1_2.y * sizeViewport.y)) {
offset.y = 0.0;
}
else {
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl
index 590c2905be6..a2b0d072719 100644
--- a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl
@@ -1,4 +1,3 @@
-/* Draw Curve Handles */
in vec3 pos;
in int data;
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl
index 6eec43d99be..aca40bba171 100644
--- a/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl
@@ -1,6 +1,3 @@
-/* Draw Curve Vertices */
-
-uniform vec2 viewportSize;
in vec3 pos;
in int data;
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl
index e1d5319ffb9..5dd8e579db3 100644
--- a/source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl
@@ -1,4 +1,3 @@
-/* Draw Curve Normals */
uniform float normalSize;
@@ -7,6 +6,8 @@ in vec3 nor;
in vec3 tan;
in float rad;
+flat out vec4 finalColor;
+
void main()
{
GPU_INTEL_VERTEX_SHADER_WORKAROUND
@@ -22,6 +23,8 @@ void main()
vec3 world_pos = point_object_to_world(final_pos);
gl_Position = point_world_to_ndc(world_pos);
+ finalColor = colorWireEdit;
+
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl
new file mode 100644
index 00000000000..06d34c22ba1
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl
@@ -0,0 +1,32 @@
+
+in vec3 pos;
+in int data;
+
+out vec4 finalColor;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ if ((data & VERT_SELECTED) != 0) {
+ finalColor = colorVertexSelect;
+ }
+ else if ((data & VERT_ACTIVE) != 0) {
+ finalColor = colorEditMeshActive;
+ }
+ else {
+ finalColor = colorVertex;
+ }
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ /* Small offset in Z */
+ gl_Position.z -= 3e-4;
+
+ gl_PointSize = sizeVertex * 2.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl
new file mode 100644
index 00000000000..efa6ca72feb
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl
@@ -0,0 +1,38 @@
+
+uniform sampler1D weightTex;
+
+in vec3 pos;
+in float weight;
+
+out vec4 finalColor;
+
+#define no_active_weight 666.0
+
+vec3 weight_to_rgb(float t)
+{
+ if (t == no_active_weight) {
+ /* No weight. */
+ return colorWire.rgb;
+ }
+ if (t > 1.0 || t < 0.0) {
+ /* Error color */
+ return vec3(1.0, 0.0, 1.0);
+ }
+ else {
+ return texture(weightTex, t).rgb;
+ }
+}
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ finalColor = vec4(weight_to_rgb(weight), 1.0);
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl
index 8d96c0e418f..8d96c0e418f 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl
index b89a3f407f9..b89a3f407f9 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
index b79bae45f23..b79bae45f23 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl
index a8371958ec2..a8371958ec2 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl
index df37c6fb0bc..df37c6fb0bc 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl
index 7fe3cea8a42..1fe20d1cb1f 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl
@@ -12,12 +12,20 @@
#define GRID_LINE_SMOOTH_START (0.5 - DISC_RADIUS)
#define GRID_LINE_SMOOTH_END (0.5 + DISC_RADIUS)
+uniform sampler2D depthTex;
+uniform float alpha = 1.0;
+
flat in vec4 finalColorOuter_f;
in vec4 finalColor_f;
noperspective in float edgeCoord_f;
out vec4 FragColor;
+bool test_occlusion()
+{
+ return gl_FragCoord.z > texelFetch(depthTex, ivec2(gl_FragCoord.xy), 0).r;
+}
+
void main()
{
float dist = abs(edgeCoord_f) - max(sizeEdge - 0.5, 0.0);
@@ -33,4 +41,6 @@ void main()
FragColor = mix(finalColorOuter_f, finalColor_f, 1.0 - mix_w * finalColorOuter_f.a);
/* Line edges shape. */
FragColor.a *= 1.0 - (finalColorOuter_f.a > 0.0 ? mix_w_outer : mix_w);
+
+ FragColor.a *= test_occlusion() ? alpha : 1.0;
}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl
index 047bd1dccc6..92252bbd223 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl
@@ -2,9 +2,6 @@
layout(lines) in;
layout(triangle_strip, max_vertices = 4) out;
-uniform vec2 viewportSize;
-uniform vec2 viewportSizeInv;
-
in vec4 finalColor[2];
in vec4 finalColorOuter[2];
in int selectOveride[2];
@@ -55,7 +52,7 @@ void main()
ss_pos[1] = pos1.xy / pos1.w;
vec2 line = ss_pos[0] - ss_pos[1];
- line = abs(line) * viewportSize;
+ line = abs(line) * sizeViewport.xy;
finalColorOuter_f = finalColorOuter[0];
float half_size = sizeEdge;
@@ -67,7 +64,7 @@ void main()
half_size += 0.5;
#endif
- vec3 edge_ofs = half_size * viewportSizeInv.xyy * vec3(1.0, 1.0, 0.0);
+ vec3 edge_ofs = vec3(half_size * sizeViewportInv.xy, 0.0);
bool horizontal = line.x > line.y;
edge_ofs = (horizontal) ? edge_ofs.zyz : edge_ofs.xzz;
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl
new file mode 100644
index 00000000000..2a00160836b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl
@@ -0,0 +1,53 @@
+
+uniform float normalSize;
+uniform sampler2D depthTex;
+uniform float alpha = 1.0;
+
+in vec3 pos;
+in vec3 lnor;
+in vec3 vnor;
+in vec4 norAndFlag;
+
+flat out vec4 finalColor;
+
+bool test_occlusion()
+{
+ vec3 ndc = (gl_Position.xyz / gl_Position.w) * 0.5 + 0.5;
+ return (ndc.z - 0.00035) > texture(depthTex, ndc.xy).r;
+}
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 nor;
+ /* Select the right normal by cheking if the generic attrib is used. */
+ if (!all(equal(lnor, vec3(0)))) {
+ nor = lnor;
+ finalColor = colorLNormal;
+ }
+ else if (!all(equal(vnor, vec3(0)))) {
+ nor = vnor;
+ finalColor = colorVNormal;
+ }
+ else {
+ nor = norAndFlag.xyz;
+ finalColor = colorNormal;
+ }
+
+ vec3 n = normalize(normal_object_to_world(nor));
+
+ vec3 world_pos = point_object_to_world(pos);
+
+ if (gl_VertexID == 0) {
+ world_pos += n * normalSize;
+ }
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ finalColor.a *= (test_occlusion()) ? alpha : 1.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl
new file mode 100644
index 00000000000..944eb41058e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl
@@ -0,0 +1,25 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec3 pos;
+
+/* ---- Per instance Attrs ---- */
+in float size;
+in vec3 local_pos;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ mat3 imat = mat3(ModelMatrixInverse);
+ vec3 right = normalize(imat * screenVecs[0].xyz);
+ 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;
+ /* Manual stipple: one segment out of 2 is transparent. */
+ finalColor = ((gl_VertexID & 1) == 0) ? colorSkinRoot : vec4(0.0);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos_4d.xyz);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
index af0a47f1858..8759ef80888 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
@@ -1,5 +1,6 @@
-uniform float faceAlphaMod;
+uniform sampler2D depthTex;
+uniform float alpha = 1.0;
uniform ivec4 dataMask = ivec4(0xFF);
in ivec4 data;
@@ -12,11 +13,19 @@ in vec4 norAndFlag;
#endif
out vec4 finalColor;
+#ifdef EDGE
out vec4 finalColorOuter;
+#endif
#ifdef USE_GEOM_SHADER
out int selectOveride;
#endif
+bool test_occlusion()
+{
+ vec3 ndc = (gl_Position.xyz / gl_Position.w) * 0.5 + 0.5;
+ return ndc.z > texture(depthTex, ndc.xy).r;
+}
+
void main()
{
GPU_INTEL_VERTEX_SHADER_WORKAROUND
@@ -37,6 +46,8 @@ void main()
gl_Position.z -= 1e-7;
}
+ bool occluded = test_occlusion();
+
#elif defined(EDGE)
# ifdef FLAT
finalColor = EDIT_MESH_edge_color_inner(m_data.y);
@@ -50,18 +61,25 @@ void main()
float bweight = float(m_data.w) / 255.0;
finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, crease, bweight);
+ bool occluded = false; /* Done in fragment shader */
+
#elif defined(FACE)
finalColor = EDIT_MESH_face_color(m_data.x);
- finalColor.a *= faceAlphaMod;
+ bool occluded = true;
#elif defined(FACEDOT)
finalColor = EDIT_MESH_facedot_color(norAndFlag.w);
+
/* Bias Facedot Z position in clipspace. */
gl_Position.z -= 0.00035;
gl_PointSize = sizeFaceDot;
+ bool occluded = test_occlusion();
+
#endif
+ finalColor.a *= (occluded) ? alpha : 1.0;
+
#if !defined(FACE)
/* Facing based color blend */
vec3 vpos = point_world_to_view(world_pos);
diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl
new file mode 100644
index 00000000000..86d5547225c
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl
@@ -0,0 +1,19 @@
+
+in vec3 pos;
+in float color;
+
+out vec4 finalColor;
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ finalColor = mix(colorWire, colorEdgeSelect, color);
+
+ gl_PointSize = sizeVertex * 2.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl
new file mode 100644
index 00000000000..1dde94f751c
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl
@@ -0,0 +1,42 @@
+
+uniform sampler1D weightTex;
+uniform bool useWeight;
+
+in vec3 pos;
+in float color;
+
+out vec4 finalColor;
+
+#define no_active_weight 666.0
+
+vec3 weight_to_rgb(float t)
+{
+ if (t == no_active_weight) {
+ /* No weight. */
+ return colorWire.rgb;
+ }
+ if (t > 1.0 || t < 0.0) {
+ /* Error color */
+ return vec3(1.0, 0.0, 1.0);
+ }
+ else {
+ return texture(weightTex, t).rgb;
+ }
+}
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ if (useWeight) {
+ finalColor = vec4(weight_to_rgb(color), 1.0);
+ }
+ else {
+ finalColor = mix(colorWire, colorEdgeSelect, color);
+ }
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_frag.glsl
new file mode 100644
index 00000000000..a2572f44e70
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_frag.glsl
@@ -0,0 +1,13 @@
+
+noperspective in vec2 edgePos;
+flat in vec2 edgeStart;
+flat in vec4 finalColor;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
+
+void main()
+{
+ fragColor = finalColor;
+ lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl
new file mode 100644
index 00000000000..738f0025f07
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl
@@ -0,0 +1,30 @@
+
+in vec3 pos;
+
+/* Instance */
+in vec3 inst_pos;
+
+flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+
+void main()
+{
+ finalColor = colorLight;
+
+ /* Relative to DPI scalling. Have constant screen size. */
+ vec3 screen_pos = screenVecs[0].xyz * pos.x + screenVecs[1].xyz * pos.y;
+ vec3 p = inst_pos;
+ p.z *= (pos.z == 0.0) ? 0.0 : 1.0;
+ float screen_size = mul_project_m4_v3_zfac(p) * sizePixel;
+ vec3 world_pos = p + screen_pos * screen_size;
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ /* Convert to screen position [0..sizeVp]. */
+ edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
new file mode 100644
index 00000000000..3746cbcf90b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
@@ -0,0 +1,70 @@
+
+uniform sampler2D depthBuffer;
+uniform vec4 gridModelMatrix[4];
+uniform bool isTransform;
+
+out vec4 finalColor;
+
+vec4 color_from_id(float color_id)
+{
+ if (isTransform) {
+ return colorTransform;
+ }
+ else if (color_id == 0.0) {
+ return colorDupliSelect;
+ }
+ else if (color_id == 1.0) {
+ return colorActive;
+ }
+ else /* 2.0 */ {
+ return colorSelect;
+ }
+
+ return colorTransform;
+}
+
+/* Replace top 2 bits (of the 16bit output) by outlineId.
+ * This leaves 16K different IDs to create outlines between objects.
+ * SHIFT = (32 - (16 - 2)) */
+#define SHIFT 18u
+
+void main()
+{
+ mat4 model_mat = mat4(
+ gridModelMatrix[0], gridModelMatrix[1], gridModelMatrix[2], gridModelMatrix[3]);
+ model_mat[0][3] = model_mat[1][3] = model_mat[2][3] = 0.0;
+ model_mat[3][3] = 1.0;
+ float color_id = gridModelMatrix[3].w;
+
+ ivec3 grid_resolution = ivec3(gridModelMatrix[0].w, gridModelMatrix[1].w, gridModelMatrix[2].w);
+
+ vec3 ls_cell_location;
+ /* Keep in sync with update_irradiance_probe */
+ ls_cell_location.z = float(gl_VertexID % grid_resolution.z);
+ ls_cell_location.y = float((gl_VertexID / grid_resolution.z) % grid_resolution.y);
+ ls_cell_location.x = float(gl_VertexID / (grid_resolution.z * grid_resolution.y));
+
+ ls_cell_location += 0.5;
+ ls_cell_location /= vec3(grid_resolution);
+ ls_cell_location = ls_cell_location * 2.0 - 1.0;
+
+ vec3 ws_cell_location = (model_mat * vec4(ls_cell_location, 1.0)).xyz;
+ gl_Position = point_world_to_ndc(ws_cell_location);
+ gl_PointSize = sizeVertex * 2.0;
+
+ finalColor = color_from_id(color_id);
+
+ /* Shade occluded points differently. */
+ vec4 p = gl_Position / gl_Position.w;
+ float z_depth = texture(depthBuffer, p.xy * 0.5 + 0.5).r * 2.0 - 1.0;
+ float z_delta = p.z - z_depth;
+ if (z_delta > 0.0) {
+ float fac = 1.0 - z_delta * 10000.0;
+ /* Smooth blend to avoid flickering. */
+ finalColor = mix(colorBackground, finalColor, clamp(fac, 0.5, 1.0));
+ }
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(ws_cell_location);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/object_loose_points_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl
index 5730cb2d96e..c27061f8f97 100644
--- a/source/blender/draw/modes/shaders/object_loose_points_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl
@@ -1,6 +1,5 @@
-uniform vec4 color;
-uniform vec4 innerColor;
+in vec4 finalColor;
out vec4 fragColor;
@@ -10,7 +9,7 @@ void main()
float dist = max(centered.x, centered.y);
float fac = dist * dist * 4.0;
- fragColor = mix(innerColor, color, 0.45 + fac * 0.65);
+ fragColor = mix(colorEditMeshMiddle, finalColor, 0.45 + fac * 0.65);
/* Make the effect more like a fresnel by offsetting
* the depth and creating mini-spheres.
diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl
new file mode 100644
index 00000000000..7e31bf966bc
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl
@@ -0,0 +1,20 @@
+
+in vec3 pos;
+
+out vec4 finalColor;
+
+void main()
+{
+ /* Extract data packed inside the unused mat4 members. */
+ mat4 obmat = ModelMatrix;
+ finalColor = vec4(obmat[0][3], obmat[1][3], obmat[2][3], obmat[3][3]);
+
+ vec3 world_pos = (ModelMatrix * vec4(pos, 1.0)).xyz;
+ gl_Position = point_world_to_ndc(world_pos);
+
+ gl_PointSize = sizeVertex * 2.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl
new file mode 100644
index 00000000000..537c55cf3f5
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl
@@ -0,0 +1,30 @@
+
+uniform vec4 color;
+
+in vec3 pos;
+
+out vec4 radii;
+out vec4 fillColor;
+out vec4 outlineColor;
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ gl_PointSize = sizeObjectCenter;
+ float radius = 0.5 * sizeObjectCenter;
+ float outline_width = sizePixel;
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+ radii[2] = radius - outline_width;
+ radii[3] = radius - outline_width - 1.0;
+ radii /= sizeObjectCenter;
+
+ fillColor = color;
+ outlineColor = colorOutline;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl
new file mode 100644
index 00000000000..92db27ea6dd
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl
@@ -0,0 +1,227 @@
+
+in vec3 pos;
+in int vclass;
+
+/* Instance */
+in mat4 inst_obmat;
+in vec4 color;
+
+#define lamp_area_size inst_data.xy
+#define lamp_clip_sta inst_data.z
+#define lamp_clip_end inst_data.w
+
+#define lamp_spot_cosine inst_data.x
+#define lamp_spot_blend inst_data.y
+
+#define camera_corner inst_data.xy
+#define camera_center inst_data.zw
+#define camera_dist inst_color_data
+#define camera_dist_sta inst_data.z
+#define camera_dist_end inst_data.w
+#define camera_distance_color inst_data.x
+
+#define empty_size inst_data.xyz
+#define empty_scale inst_data.w
+
+#define VCLASS_LIGHT_AREA_SHAPE (1 << 0)
+#define VCLASS_LIGHT_SPOT_SHAPE (1 << 1)
+#define VCLASS_LIGHT_SPOT_BLEND (1 << 2)
+#define VCLASS_LIGHT_SPOT_CONE (1 << 3)
+#define VCLASS_LIGHT_DIST (1 << 4)
+
+#define VCLASS_CAMERA_FRAME (1 << 5)
+#define VCLASS_CAMERA_DIST (1 << 6)
+#define VCLASS_CAMERA_VOLUME (1 << 7)
+
+#define VCLASS_SCREENSPACE (1 << 8)
+#define VCLASS_SCREENALIGNED (1 << 9)
+
+#define VCLASS_EMPTY_SCALED (1 << 10)
+#define VCLASS_EMPTY_AXES (1 << 11)
+#define VCLASS_EMPTY_AXES_NAME (1 << 12)
+#define VCLASS_EMPTY_AXES_SHADOW (1 << 13)
+#define VCLASS_EMPTY_SIZE (1 << 14)
+
+flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+
+void main()
+{
+ /* Extract data packed inside the unused mat4 members. */
+ vec4 inst_data = vec4(inst_obmat[0][3], inst_obmat[1][3], inst_obmat[2][3], inst_obmat[3][3]);
+ float inst_color_data = color.a;
+ mat4 obmat = inst_obmat;
+ obmat[0][3] = obmat[1][3] = obmat[2][3] = 0.0;
+ obmat[3][3] = 1.0;
+
+ finalColor = color;
+ if (color.a < 0.0) {
+ finalColor.a = 1.0;
+ }
+
+ float lamp_spot_sine;
+ vec3 vpos = pos;
+ vec3 vofs = vec3(0.0);
+ /* Lights */
+ if ((vclass & VCLASS_LIGHT_AREA_SHAPE) != 0) {
+ /* HACK: use alpha color for spots to pass the area_size. */
+ if (inst_color_data < 0.0) {
+ lamp_area_size.xy = vec2(-inst_color_data);
+ }
+ vpos.xy *= lamp_area_size.xy;
+ }
+ else if ((vclass & VCLASS_LIGHT_SPOT_SHAPE) != 0) {
+ lamp_spot_sine = sqrt(1.0 - lamp_spot_cosine * lamp_spot_cosine);
+ lamp_spot_sine *= ((vclass & VCLASS_LIGHT_SPOT_BLEND) != 0) ? lamp_spot_blend : 1.0;
+ vpos = vec3(pos.xy * lamp_spot_sine, -lamp_spot_cosine);
+ }
+ else if ((vclass & VCLASS_LIGHT_DIST) != 0) {
+ /* Meh nasty mess. Select one of the 6 axes to display on. (see light_distance_z_get()) */
+ int dist_axis = int(pos.z);
+ float dist = pos.z - floor(pos.z) - 0.5;
+ float inv = sign(dist);
+ dist = (abs(dist) > 0.15) ? lamp_clip_end : lamp_clip_sta;
+ vofs[dist_axis] = inv * dist / length(obmat[dist_axis].xyz);
+ vpos.z = 0.0;
+ if (lamp_clip_end < 0.0) {
+ vpos = vofs = vec3(0.0);
+ }
+ }
+ /* Camera */
+ else if ((vclass & VCLASS_CAMERA_FRAME) != 0) {
+ if ((vclass & VCLASS_CAMERA_VOLUME) != 0) {
+ vpos.z = mix(color.b, color.a, pos.z);
+ }
+ else if (camera_dist > 0.0) {
+ vpos.z = -abs(camera_dist);
+ }
+ else {
+ vpos.z *= -abs(camera_dist);
+ }
+ vpos.xy = (camera_center + camera_corner * vpos.xy) * abs(vpos.z);
+ }
+ else if ((vclass & VCLASS_CAMERA_DIST) != 0) {
+ vofs.xy = vec2(0.0);
+ vofs.z = -mix(camera_dist_sta, camera_dist_end, pos.z);
+ vpos.z = 0.0;
+ /* Distance line endpoints color */
+ if (any(notEqual(pos.xy, vec2(0.0)))) {
+ /* Override color. */
+ switch (int(camera_distance_color)) {
+ case 0: /* Mist */
+ finalColor = vec4(0.5, 0.5, 0.5, 1.0);
+ break;
+ case 1: /* Mist Active */
+ finalColor = vec4(1.0, 1.0, 1.0, 1.0);
+ break;
+ case 2: /* Clip */
+ finalColor = vec4(0.5, 0.5, 0.25, 1.0);
+ break;
+ case 3: /* Clip Active */
+ finalColor = vec4(1.0, 1.0, 0.5, 1.0);
+ break;
+ }
+ }
+ /* Focus cross */
+ if (pos.z == 2.0) {
+ vofs.z = 0.0;
+ if (camera_dist < 0.0) {
+ vpos.z = -abs(camera_dist);
+ }
+ else {
+ /* Disabled */
+ vpos = vec3(0.0);
+ }
+ }
+ }
+ /* Empties */
+ else if ((vclass & VCLASS_EMPTY_SCALED) != 0) {
+ /* This is a bit silly but we avoid scalling the object matrix on CPU (saving a mat4 mul) */
+ vpos *= empty_scale;
+ }
+ else if ((vclass & VCLASS_EMPTY_SIZE) != 0) {
+ /* This is a bit silly but we avoid scalling the object matrix on CPU (saving a mat4 mul) */
+ vpos *= empty_size;
+ }
+ else if ((vclass & VCLASS_EMPTY_AXES) != 0) {
+ float axis = vpos.z;
+ vofs[int(axis)] = (1.0 + fract(axis)) * empty_scale;
+ /* Scale uniformly by axis length */
+ vpos *= length(obmat[int(axis)].xyz) * empty_scale;
+
+ vec3 axis_color = vec3(0.0);
+ axis_color[int(axis)] = 1.0;
+ finalColor.rgb = mix(axis_color + fract(axis), color.rgb, color.a);
+ finalColor.a = 1.0;
+ }
+
+ /* Not exclusive with previous flags. */
+ if ((vclass & VCLASS_CAMERA_VOLUME) != 0) {
+ /* Unpack final color. */
+ int color_class = int(floor(color.r));
+ float color_intensity = fract(color.r);
+ switch (color_class) {
+ case 0: /* No eye (convergence plane) */
+ finalColor = vec4(1.0, 1.0, 1.0, 1.0);
+ break;
+ case 1: /* Left eye */
+ finalColor = vec4(0.0, 1.0, 1.0, 1.0);
+ break;
+ case 2: /* Right eye */
+ finalColor = vec4(1.0, 0.0, 0.0, 1.0);
+ break;
+ }
+ finalColor *= vec4(vec3(color_intensity), color.g);
+ }
+
+ vec3 world_pos;
+ if ((vclass & VCLASS_SCREENSPACE) != 0) {
+ /* Relative to DPI scalling. Have constant screen size. */
+ vec3 screen_pos = screenVecs[0].xyz * vpos.x + screenVecs[1].xyz * vpos.y;
+ vec3 p = (obmat * vec4(vofs, 1.0)).xyz;
+ float screen_size = mul_project_m4_v3_zfac(p) * sizePixel;
+ world_pos = p + screen_pos * screen_size;
+ }
+ else if ((vclass & VCLASS_SCREENALIGNED) != 0) {
+ /* World sized, camera facing geometry. */
+ vec3 screen_pos = screenVecs[0].xyz * vpos.x + screenVecs[1].xyz * vpos.y;
+ world_pos = (obmat * vec4(vofs, 1.0)).xyz + screen_pos;
+ }
+ else {
+ world_pos = (obmat * vec4(vofs + vpos, 1.0)).xyz;
+ }
+
+ if ((vclass & VCLASS_LIGHT_SPOT_CONE) != 0) {
+ /* Compute point on the cone before and after this one. */
+ vec2 perp = vec2(pos.y, -pos.x);
+ const float incr_angle = 2.0 * 3.1415 / 32.0;
+ const vec2 slope = vec2(cos(incr_angle), sin(incr_angle));
+ vec3 p0 = vec3((pos.xy * slope.x + perp * slope.y) * lamp_spot_sine, -lamp_spot_cosine);
+ vec3 p1 = vec3((pos.xy * slope.x - perp * slope.y) * lamp_spot_sine, -lamp_spot_cosine);
+ p0 = (obmat * vec4(p0, 1.0)).xyz;
+ p1 = (obmat * vec4(p1, 1.0)).xyz;
+ /* Compute normals of each side. */
+ 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;
+ /* Discard non-silhouete edges. */
+ bool facing0 = dot(n0, V) > 0.0;
+ bool facing1 = dot(n1, V) > 0.0;
+ if (facing0 == facing1) {
+ /* Hide line by making it cover 0 pixels. */
+ world_pos = obmat[3].xyz;
+ }
+ }
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ /* Convert to screen position [0..sizeVp]. */
+ edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl
new file mode 100644
index 00000000000..a2bc13ba443
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl
@@ -0,0 +1,31 @@
+
+noperspective in vec2 stipple_coord;
+flat in vec2 stipple_start;
+flat in vec4 finalColor;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
+
+void main()
+{
+ fragColor = finalColor;
+
+ /* Stipple */
+ const float dash_width = 6.0;
+ const float dash_factor = 0.5;
+
+ lineOutput = pack_line_data(gl_FragCoord.xy, stipple_start, stipple_coord);
+
+ float dist = distance(stipple_start, stipple_coord);
+
+ if (fragColor.a == 0.0) {
+ /* Disable stippling. */
+ dist = 0.0;
+ }
+
+ fragColor.a = 1.0;
+
+ if (fract(dist / dash_width) > dash_factor) {
+ discard;
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl
new file mode 100644
index 00000000000..97183638a71
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl
@@ -0,0 +1,40 @@
+
+in vec3 pos;
+in vec4 color;
+in int colorid; /* if equal 0 (i.e: Not specified) use color attrib and stippling. */
+
+noperspective out vec2 stipple_coord;
+flat out vec2 stipple_start;
+flat out vec4 finalColor;
+
+vec2 screen_position(vec4 p)
+{
+ return ((p.xy / p.w) * 0.5 + 0.5) * sizeViewport.xy;
+}
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ stipple_coord = stipple_start = screen_position(gl_Position);
+
+#ifdef OBJECT_WIRE
+ /* Extract data packed inside the unused mat4 members. */
+ finalColor = vec4(ModelMatrix[0][3], ModelMatrix[1][3], ModelMatrix[2][3], ModelMatrix[3][3]);
+#else
+
+ if (colorid == TH_CAMERA_PATH) {
+ finalColor = colorCameraPath;
+ finalColor.a = 0.0; /* No Stipple */
+ }
+ else {
+ finalColor = color;
+ finalColor.a = 1.0; /* Stipple */
+ }
+#endif
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl b/source/blender/draw/engines/overlay/shaders/facing_frag.glsl
new file mode 100644
index 00000000000..ca7b4eeaf47
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/facing_frag.glsl
@@ -0,0 +1,6 @@
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = gl_FrontFacing ? colorFaceFront : colorFaceBack;
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl b/source/blender/draw/engines/overlay/shaders/facing_vert.glsl
index 2dd84c0a060..2dd84c0a060 100644
--- a/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/facing_vert.glsl
diff --git a/source/blender/draw/modes/shaders/object_grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
index 751d839eb79..db845c7f1dd 100644
--- a/source/blender/draw/modes/shaders/object_grid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
@@ -9,7 +9,6 @@ in vec3 local_pos;
out vec4 FragColor;
uniform vec3 planeAxes;
-uniform vec3 screenVecs[2];
uniform float gridDistance;
uniform float meshSize;
uniform float lineKernel = 0.0;
@@ -120,7 +119,7 @@ void main()
if ((gridFlag & GRID) != 0) {
/* Using `max(dot(dFdxPos, screenVecs[0]), dot(dFdyPos, screenVecs[1]))`
* would be more accurate, but not really necessary. */
- float grid_res = dot(dFdxPos, screenVecs[0]);
+ float grid_res = dot(dFdxPos, screenVecs[0].xyz);
/* The gride begins to appear when it comprises 4 pixels */
grid_res *= 4;
diff --git a/source/blender/draw/modes/shaders/object_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/grid_vert.glsl
index 496bb011c74..496bb011c74 100644
--- a/source/blender/draw/modes/shaders/object_grid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/grid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/image_frag.glsl b/source/blender/draw/engines/overlay/shaders/image_frag.glsl
new file mode 100644
index 00000000000..0da7067851d
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/image_frag.glsl
@@ -0,0 +1,34 @@
+
+uniform sampler2D imgTexture;
+uniform bool imgPremultiplied;
+uniform bool imgAlphaBlend;
+uniform bool imgLinear;
+uniform vec4 color;
+
+in vec2 uvs;
+
+out vec4 fragColor;
+
+void main()
+{
+ vec2 uvs_clamped = clamp(uvs, 0.0, 1.0);
+ vec4 tex_color;
+ if (imgLinear) {
+ tex_color = texture_read_as_linearrgb(imgTexture, imgPremultiplied, uvs_clamped);
+ }
+ else {
+ tex_color = texture_read_as_srgb(imgTexture, imgPremultiplied, uvs_clamped);
+ }
+ fragColor = tex_color * color;
+
+ if (!imgAlphaBlend) {
+ /* Arbitrary discard anything below 5% opacity.
+ * Note that this could be exposed to the User. */
+ if (tex_color.a < 0.05) {
+ discard;
+ }
+ else {
+ fragColor.a = 1.0;
+ }
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/image_vert.glsl b/source/blender/draw/engines/overlay/shaders/image_vert.glsl
new file mode 100644
index 00000000000..621e1d8068b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/image_vert.glsl
@@ -0,0 +1,21 @@
+
+uniform bool depthSet;
+
+in vec3 pos;
+
+out vec2 uvs;
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ if (depthSet) {
+ /* Result in a position at 1.0 (far plane). Small epsilon to avoid precision issue.
+ * This mimics the effect of infinite projection matrix
+ * (see http://www.terathon.com/gdc07_lengyel.pdf). */
+ gl_Position.z = gl_Position.w - 2.4e-7;
+ }
+
+ uvs = pos.xy * 0.5 + 0.5;
+}
diff --git a/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl
index b81f9f639ca..95e5b08049e 100644
--- a/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl
@@ -2,8 +2,6 @@
layout(lines) in;
layout(triangle_strip, max_vertices = 4) out;
-uniform mat4 ProjectionMatrix;
-uniform vec2 viewportSize;
uniform int lineThickness = 2;
in vec4 finalColor_geom[];
@@ -21,19 +19,26 @@ vec2 compute_dir(vec2 v0, vec2 v1)
void main(void)
{
vec2 t;
- vec2 edge_dir = compute_dir(ssPos[0], ssPos[1]) / viewportSize;
+ vec2 edge_dir = compute_dir(ssPos[0], ssPos[1]) * sizeViewportInv.xy;
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ float line_size = float(lineThickness) * sizePixel;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance);
+#endif
finalColor = finalColor_geom[0];
- t = edge_dir * (float(lineThickness) * (is_persp ? gl_in[0].gl_Position.w : 1.0));
+ t = edge_dir * (line_size * (is_persp ? gl_in[0].gl_Position.w : 1.0));
gl_Position = gl_in[0].gl_Position + vec4(t, 0.0, 0.0);
EmitVertex();
gl_Position = gl_in[0].gl_Position - vec4(t, 0.0, 0.0);
EmitVertex();
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
+#endif
finalColor = finalColor_geom[1];
- t = edge_dir * (float(lineThickness) * (is_persp ? gl_in[1].gl_Position.w : 1.0));
+ t = edge_dir * (line_size * (is_persp ? gl_in[1].gl_Position.w : 1.0));
gl_Position = gl_in[1].gl_Position + vec4(t, 0.0, 0.0);
EmitVertex();
gl_Position = gl_in[1].gl_Position - vec4(t, 0.0, 0.0);
diff --git a/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl
index b4d8abfe180..6d7f673731e 100644
--- a/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl
@@ -1,16 +1,13 @@
-uniform mat4 ViewMatrix;
-uniform mat4 ViewProjectionMatrix;
-uniform vec2 viewportSize;
-
-uniform int frameCurrent;
-uniform int frameStart;
-uniform int frameEnd;
-uniform int cacheStart;
+uniform ivec4 mpathLineSettings;
uniform bool selected;
-uniform bool useCustomColor;
uniform vec3 customColor;
+#define frameCurrent mpathLineSettings.x
+#define frameStart mpathLineSettings.y
+#define frameEnd mpathLineSettings.z
+#define cacheStart mpathLineSettings.w
+
in vec3 pos;
out vec2 ssPos;
@@ -19,7 +16,7 @@ out vec4 finalColor_geom;
/* project to screen space */
vec2 proj(vec4 pos)
{
- return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+ return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
}
#define SET_INTENSITY(A, B, C, min, max) \
@@ -38,10 +35,10 @@ void main()
vec3 blend_base = (abs(frame - frameCurrent) == 1) ?
colorCurrentFrame.rgb :
colorBackground.rgb; /* "bleed" cframe color to ease color blending */
-
+ bool use_custom_color = customColor.x >= 0.0;
/* TODO: We might want something more consistent with custom color and standard colors. */
if (frame < frameCurrent) {
- if (useCustomColor) {
+ if (use_custom_color) {
/* Custom color: previous frames color is darker than current frame */
finalColor_geom.rgb = customColor * 0.25;
}
@@ -57,7 +54,7 @@ void main()
}
}
else if (frame > frameCurrent) {
- if (useCustomColor) {
+ if (use_custom_color) {
/* Custom color: next frames color is equal to user selected color */
finalColor_geom.rgb = customColor;
}
@@ -74,7 +71,7 @@ void main()
}
}
else {
- if (useCustomColor) {
+ if (use_custom_color) {
/* Custom color: current frame color is slightly darker than user selected color */
finalColor_geom.rgb = customColor * 0.5;
}
@@ -92,4 +89,8 @@ void main()
}
finalColor_geom.a = 1.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos);
+#endif
}
diff --git a/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl
index 70267e78d9e..14335eb1b99 100644
--- a/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl
@@ -1,13 +1,12 @@
-uniform mat4 ViewProjectionMatrix;
-
-uniform int pointSize = 2;
-uniform int frameCurrent;
-uniform int cacheStart;
+uniform ivec4 mpathPointSettings;
uniform bool showKeyFrames = true;
-uniform bool useCustomColor;
uniform vec3 customColor;
-uniform int stepSize;
+
+#define pointSize mpathPointSettings.x
+#define frameCurrent mpathPointSettings.y
+#define cacheStart mpathPointSettings.z
+#define stepSize mpathPointSettings.w
in vec3 pos;
in int flag;
@@ -23,7 +22,8 @@ void main()
gl_PointSize = float(pointSize + 2);
int frame = gl_VertexID + cacheStart;
- finalColor = (useCustomColor) ? vec4(customColor, 1.0) : vec4(1.0);
+ bool use_custom_color = customColor.x >= 0.0;
+ finalColor = (use_custom_color) ? vec4(customColor, 1.0) : vec4(1.0);
/* Bias to reduce z fighting with the path */
gl_Position.z -= 1e-4;
@@ -49,4 +49,10 @@ void main()
gl_Position.z -= 1e-4;
}
}
+
+ gl_PointSize *= sizePixel;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos);
+#endif
}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
new file mode 100644
index 00000000000..f5a3aa2c332
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
@@ -0,0 +1,335 @@
+
+uniform float alphaOcclu;
+uniform bool isXrayWires;
+uniform bool doAntiAliasing;
+uniform bool doThickOutlines;
+uniform usampler2D outlineId;
+uniform sampler2D outlineDepth;
+uniform sampler2D sceneDepth;
+
+in vec4 uvcoordsvar;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
+
+#define XPOS (1 << 0)
+#define XNEG (1 << 1)
+#define YPOS (1 << 2)
+#define YNEG (1 << 3)
+
+#define ALL (XPOS | XNEG | YPOS | YNEG)
+#define NONE 0
+
+#define DIAG_XNEG_YPOS (XNEG | YPOS)
+#define DIAG_XPOS_YPOS (XPOS | YPOS)
+#define DIAG_XPOS_YNEG (XPOS | YNEG)
+#define DIAG_XNEG_YNEG (XNEG | YNEG)
+
+#define APEX_XPOS (ALL & (~XPOS))
+#define APEX_XNEG (ALL & (~XNEG))
+#define APEX_YPOS (ALL & (~YPOS))
+#define APEX_YNEG (ALL & (~YNEG))
+
+bool has_edge(uint id, vec2 uv, uint ref, inout uint ref_col, inout vec2 depth_uv)
+{
+ if (ref_col == 0u) {
+ /* Make outline bleed on the background. */
+ ref_col = id;
+ depth_uv = uv;
+ }
+ return (id != ref);
+}
+
+/* A gather4 + check against ref. */
+bvec4 gather_edges(vec2 uv, uint ref)
+{
+ uvec4 ids;
+#ifdef GPU_ARB_texture_gather
+ ids = textureGather(outlineId, uv);
+#else
+ vec3 ofs = vec3(0.5, 0.5, -0.5) * sizeViewportInv.xyy;
+ ids.x = textureLod(outlineId, uv - ofs.xz, 0.0).r;
+ ids.y = textureLod(outlineId, uv + ofs.xy, 0.0).r;
+ ids.z = textureLod(outlineId, uv + ofs.xz, 0.0).r;
+ ids.w = textureLod(outlineId, uv - ofs.xy, 0.0).r;
+#endif
+
+ return notEqual(ids, uvec4(ref));
+}
+
+/* Apply offset to line endpoint based on surrounding edges infos. */
+bool line_offset(bvec2 edges, vec2 ofs, inout vec2 line_point)
+{
+ if (all(edges.xy)) {
+ line_point.y -= ofs.y;
+ }
+ else if (!edges.x) {
+ line_point.y += ofs.y;
+ }
+ else /* !edges.y */ {
+ line_point.x += ofs.x;
+ return true;
+ }
+ return false;
+}
+
+/* Changes Antialiasing pattern and makes line thicker. 0.0 is thin. */
+#define PROXIMITY_OFS -0.35
+
+/* Use surrounding edges to approximate the outline direction to create smooth lines. */
+void straight_line_dir(bvec4 edges1, bvec4 edges2, out vec2 line_start, out vec2 line_end)
+{
+ line_end = vec2(1.5, 0.5 + PROXIMITY_OFS);
+ line_start = vec2(-line_end.x, line_end.y);
+
+ vec2 line_ofs = vec2(1.0, 0.5);
+ if (line_offset(edges1.xw, line_ofs, line_end)) {
+ line_offset(edges1.yz, line_ofs, line_end);
+ }
+ line_ofs = vec2(-line_ofs.x, line_ofs.y);
+ if (line_offset(edges2.yz, line_ofs, line_start)) {
+ line_offset(edges2.xw, line_ofs, line_start);
+ }
+}
+
+/* Compute line direction vector from the bottom left corner. */
+void diag_dir(bvec4 edges, out vec2 line_start, out vec2 line_end)
+{
+ /* TODO Improve diagonal antialiasing. */
+ if (all(edges.wz)) {
+ line_start = vec2(-3.0, -0.5 + PROXIMITY_OFS);
+ line_end = vec2(3.0, 0.5 + PROXIMITY_OFS);
+ }
+ else if (all(not(edges.xw))) {
+ line_start = vec2(-0.5 - PROXIMITY_OFS, -3.0);
+ line_end = vec2(0.5 - PROXIMITY_OFS, 3.0);
+ }
+ else if (edges.w) {
+ line_start = vec2(-1.0, -0.5 - PROXIMITY_OFS);
+ line_end = vec2(2.0, 0.5 - PROXIMITY_OFS);
+ }
+ else {
+ line_start = vec2(-0.6, -0.5 + PROXIMITY_OFS);
+ line_end = vec2(0.6 - PROXIMITY_OFS, 0.5);
+ }
+}
+/* Clockwise */
+vec2 rotate_90(vec2 v)
+{
+ return vec2(v.y, -v.x);
+}
+vec2 rotate_180(vec2 v)
+{
+ return vec2(-v.x, -v.y);
+}
+vec2 rotate_270(vec2 v)
+{
+ return vec2(-v.y, v.x);
+}
+
+/* Counter-Clockwise */
+bvec4 rotate_90(bvec4 v)
+{
+ return v.yzwx;
+}
+bvec4 rotate_180(bvec4 v)
+{
+ return v.zwxy;
+}
+bvec4 rotate_270(bvec4 v)
+{
+ return v.wxyz;
+}
+
+void main()
+{
+ uint ref = textureLod(outlineId, uvcoordsvar.st, 0.0).r;
+ uint ref_col = ref;
+
+ vec2 uvs = gl_FragCoord.xy * sizeViewportInv.xy;
+ vec3 ofs = vec3(1.0, 1.0, 0.0) * sizeViewportInv.xyy;
+
+ vec2 depth_uv = uvs;
+
+ uvec4 ids;
+#ifdef GPU_ARB_texture_gather
+ /* Reminder: Samples order is CW starting from top left. */
+ uvec2 tmp1, tmp2, tmp3, tmp4;
+ if (doThickOutlines) {
+ tmp1 = textureGather(outlineId, uvs + ofs.xy * vec2(1.5, -0.5)).xy;
+ tmp2 = textureGather(outlineId, uvs + ofs.xy * vec2(-1.5, -0.5)).yx;
+ tmp3 = textureGather(outlineId, uvs + ofs.xy * vec2(0.5, 1.5)).wx;
+ tmp4 = textureGather(outlineId, uvs + ofs.xy * vec2(0.5, -1.5)).xw;
+ ids.x = tmp1.x;
+ ids.y = tmp2.x;
+ ids.z = tmp3.x;
+ ids.w = tmp4.x;
+ }
+ else {
+ ids.xz = textureGather(outlineId, uvs + ofs.xy * 0.5).zx;
+ ids.yw = textureGather(outlineId, uvs - ofs.xy * 0.5).xz;
+ }
+#else
+ ids.x = textureLod(outlineId, uvs + ofs.xz, 0.0).r;
+ ids.y = textureLod(outlineId, uvs - ofs.xz, 0.0).r;
+ ids.z = textureLod(outlineId, uvs + ofs.zy, 0.0).r;
+ ids.w = textureLod(outlineId, uvs - ofs.zy, 0.0).r;
+#endif
+
+ bool has_edge_pos_x = has_edge(ids.x, uvs + ofs.xz, ref, ref_col, depth_uv);
+ bool has_edge_neg_x = has_edge(ids.y, uvs - ofs.xz, ref, ref_col, depth_uv);
+ bool has_edge_pos_y = has_edge(ids.z, uvs + ofs.zy, ref, ref_col, depth_uv);
+ bool has_edge_neg_y = has_edge(ids.w, uvs - ofs.zy, ref, ref_col, depth_uv);
+
+ if (doThickOutlines) {
+ if (!any(bvec4(has_edge_pos_x, has_edge_neg_x, has_edge_pos_y, has_edge_neg_y))) {
+#ifdef GPU_ARB_texture_gather
+ ids.x = tmp1.y;
+ ids.y = tmp2.y;
+ ids.z = tmp3.y;
+ ids.w = tmp4.y;
+#else
+ ids.x = textureLod(outlineId, uvs + 2.0 * ofs.xz, 0.0).r;
+ ids.y = textureLod(outlineId, uvs - 2.0 * ofs.xz, 0.0).r;
+ ids.z = textureLod(outlineId, uvs + 2.0 * ofs.zy, 0.0).r;
+ ids.w = textureLod(outlineId, uvs - 2.0 * ofs.zy, 0.0).r;
+#endif
+
+ has_edge_pos_x = has_edge(ids.x, uvs + 2.0 * ofs.xz, ref, ref_col, depth_uv);
+ has_edge_neg_x = has_edge(ids.y, uvs - 2.0 * ofs.xz, ref, ref_col, depth_uv);
+ has_edge_pos_y = has_edge(ids.z, uvs + 2.0 * ofs.zy, ref, ref_col, depth_uv);
+ has_edge_neg_y = has_edge(ids.w, uvs - 2.0 * ofs.zy, ref, ref_col, depth_uv);
+ }
+ }
+
+ if (isXrayWires) {
+ /* Don't inflate the wire outlines too much. */
+ has_edge_neg_x = has_edge_neg_y = false;
+ }
+
+ /* WATCH: Keep in sync with outlineId of the prepass. */
+ uint color_id = ref_col >> 14u;
+ if (ref_col == 0u) {
+ fragColor = vec4(0.0);
+ }
+ else if (color_id == 1u) {
+ fragColor = colorSelect;
+ }
+ else if (color_id == 2u) {
+ fragColor = colorDupliSelect;
+ }
+ else if (color_id == 3u) {
+ fragColor = colorActive;
+ }
+ else {
+ fragColor = colorTransform;
+ }
+
+ float ref_depth = textureLod(outlineDepth, depth_uv, 0.0).r;
+ float scene_depth = textureLod(sceneDepth, depth_uv, 0.0).r;
+
+ /* Avoid bad cases of zfighting for occlusion only. */
+ const float epsilon = 3.0 / 8388608.0;
+ bool occluded = (ref_depth > scene_depth + epsilon);
+
+ /* NOTE: We never set alpha to 1.0 to avoid Antialiasing destroying the line. */
+ fragColor *= (occluded ? alphaOcclu : 1.0) * (254.0 / 255.0);
+
+ int edge_case = 0;
+ edge_case += int(has_edge_pos_x) * XPOS;
+ edge_case += int(has_edge_neg_x) * XNEG;
+ edge_case += int(has_edge_pos_y) * YPOS;
+ edge_case += int(has_edge_neg_y) * YNEG;
+
+ if (edge_case == ALL || edge_case == NONE) {
+ discard;
+ }
+
+ if (!doAntiAliasing) {
+ lineOutput = vec4(0.0);
+ return;
+ }
+
+ vec2 line_start, line_end;
+ vec2 line_ofs;
+ bvec4 extra_edges, extra_edges2;
+ /* TODO simplify this branching hell. */
+ switch (edge_case) {
+ /* Straight lines. */
+ case YPOS:
+ extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(2.5, 0.5), ref);
+ extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(-2.5, 0.5), ref);
+ straight_line_dir(extra_edges, extra_edges2, line_start, line_end);
+ break;
+ case YNEG:
+ extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(-2.5, -0.5), ref);
+ extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(2.5, -0.5), ref);
+ extra_edges = rotate_180(extra_edges);
+ extra_edges2 = rotate_180(extra_edges2);
+ straight_line_dir(extra_edges, extra_edges2, line_start, line_end);
+ line_start = rotate_180(line_start);
+ line_end = rotate_180(line_end);
+ break;
+ case XPOS:
+ extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(0.5, 2.5), ref);
+ extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(0.5, -2.5), ref);
+ extra_edges = rotate_90(extra_edges);
+ extra_edges2 = rotate_90(extra_edges2);
+ straight_line_dir(extra_edges, extra_edges2, line_start, line_end);
+ line_start = rotate_90(line_start);
+ line_end = rotate_90(line_end);
+ break;
+ case XNEG:
+ extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(-0.5, 2.5), ref);
+ extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(-0.5, -2.5), ref);
+ extra_edges = rotate_270(extra_edges);
+ extra_edges2 = rotate_270(extra_edges2);
+ straight_line_dir(extra_edges, extra_edges2, line_start, line_end);
+ line_start = rotate_270(line_start);
+ line_end = rotate_270(line_end);
+ break;
+
+ /* Diagonal */
+ case DIAG_XNEG_YPOS:
+ extra_edges = gather_edges(uvs + ofs.xy * vec2(1.5), ref);
+ diag_dir(extra_edges, line_start, line_end);
+ break;
+ case DIAG_XPOS_YNEG:
+ extra_edges = gather_edges(uvs - ofs.xy * vec2(1.5), ref);
+ extra_edges = rotate_180(extra_edges);
+ diag_dir(extra_edges, line_start, line_end);
+ line_start = rotate_180(line_start);
+ line_end = rotate_180(line_end);
+ break;
+ case DIAG_XPOS_YPOS:
+ extra_edges = gather_edges(uvs + ofs.xy * vec2(1.5, -1.5), ref);
+ extra_edges = rotate_90(extra_edges);
+ diag_dir(extra_edges, line_start, line_end);
+ line_start = rotate_90(line_start);
+ line_end = rotate_90(line_end);
+ break;
+ case DIAG_XNEG_YNEG:
+ extra_edges = gather_edges(uvs - ofs.xy * vec2(1.5, -1.5), ref);
+ extra_edges = rotate_270(extra_edges);
+ diag_dir(extra_edges, line_start, line_end);
+ line_start = rotate_270(line_start);
+ line_end = rotate_270(line_end);
+ break;
+
+ /* Apex */
+ case APEX_XPOS:
+ case APEX_XNEG:
+ line_start = vec2(-0.5, 0.0);
+ line_end = vec2(0.5, 0.0);
+ break;
+ case APEX_YPOS:
+ case APEX_YNEG:
+ line_start = vec2(0.0, -0.5);
+ line_end = vec2(0.0, 0.5);
+ break;
+ default:
+ break;
+ }
+
+ lineOutput = pack_line_data(vec2(0.0), line_start, line_end);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
new file mode 100644
index 00000000000..8ef89b89eb3
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
@@ -0,0 +1,10 @@
+
+flat in int objectId;
+
+/* using uint because 16bit uint can contain more ids than int. */
+out uint outId;
+
+void main()
+{
+ outId = uint(objectId);
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl
index b32913dcd60..b32913dcd60 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
new file mode 100644
index 00000000000..8b9854b2d3e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
@@ -0,0 +1,70 @@
+
+uniform bool isTransform;
+
+in vec3 pos;
+
+#ifdef USE_GEOM
+out vec3 vPos;
+out int objectId_g;
+# define objectId objectId_g
+#else
+
+flat out int objectId;
+#endif
+
+int outline_colorid_get(void)
+{
+ int flag = int(abs(ObjectInfo.w));
+ bool is_from_dupli = (flag & DRW_BASE_FROM_DUPLI) != 0;
+ bool is_active = (flag & DRW_BASE_ACTIVE) != 0;
+
+ if (is_from_dupli) {
+ if (isTransform) {
+ return 0; /* colorTransform */
+ }
+ else {
+ return 2; /* colorDupliSelect */
+ }
+ }
+
+ if (isTransform) {
+ return 0; /* colorTransform */
+ }
+ else if (is_active) {
+ return 3; /* colorActive */
+ }
+ else {
+ return 1; /* colorSelect */
+ }
+
+ return 0;
+}
+
+/* Replace top 2 bits (of the 16bit output) by outlineId.
+ * This leaves 16K different IDs to create outlines between objects.
+ * SHIFT = (32 - (16 - 2)) */
+#define SHIFT 18u
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+#ifdef USE_GEOM
+ vPos = point_world_to_view(world_pos);
+#endif
+ gl_Position = point_world_to_ndc(world_pos);
+ /* Small bias to always be on top of the geom. */
+ gl_Position.z -= 1e-3;
+
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
+
+ /* Should be 2 bits only [0..3]. */
+ int outline_id = outline_colorid_get();
+
+ /* Combine for 16bit uint target. */
+ objectId = (outline_id << 14) | ((objectId << SHIFT) >> SHIFT);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/paint_face_selection_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl
index 4b5191ead07..2b5d586bdd1 100644
--- a/source/blender/draw/modes/shaders/paint_face_selection_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl
@@ -4,12 +4,17 @@ in vec4 nor; /* select flag on the 4th component */
void main()
{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
+ bool is_select = (nor.w > 0.0);
+ bool is_hidden = (nor.w < 0.0);
+
/* Don't draw faces that are selected. */
- if (nor.w > 0.0) {
- gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+ if (is_hidden || is_select) {
+ gl_Position = vec4(-2.0, -2.0, -2.0, 1.0);
}
else {
#ifdef USE_WORLD_CLIP_PLANES
diff --git a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl
new file mode 100644
index 00000000000..9d102bd4295
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl
@@ -0,0 +1,32 @@
+
+in vec3 pos;
+in vec4 nor; /* select flag on the 4th component */
+
+out vec4 finalColor;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ bool is_select = (nor.w > 0.0);
+ bool is_hidden = (nor.w < 0.0);
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+ /* Add offset in Z to avoid zfighting and render selected wires on top. */
+ /* TODO scale this bias using znear and zfar range. */
+ gl_Position.z -= (is_select ? 2e-4 : 1e-4);
+
+ if (is_hidden) {
+ gl_Position = vec4(-2.0, -2.0, -2.0, 1.0);
+ }
+
+ finalColor = (is_select) ? vec4(1.0) : colorWire;
+ finalColor.a = nor.w;
+
+ gl_PointSize = sizeVertex * 2.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl b/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl
new file mode 100644
index 00000000000..4d0692039a4
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl
@@ -0,0 +1,23 @@
+in vec2 uv_interp;
+
+out vec4 fragColor;
+
+uniform float opacity = 1.0;
+
+uniform sampler2D maskImage;
+uniform bool maskImagePremultiplied;
+uniform vec3 maskColor;
+uniform bool maskInvertStencil;
+
+void main()
+{
+ vec4 mask = vec4(texture_read_as_srgb(maskImage, maskImagePremultiplied, uv_interp).rgb, 1.0);
+ if (maskInvertStencil) {
+ mask.rgb = 1.0 - mask.rgb;
+ }
+ float mask_step = smoothstep(0, 3.0, mask.r + mask.g + mask.b);
+ mask.rgb *= maskColor;
+ mask.a = mask_step * opacity;
+
+ fragColor = mask;
+}
diff --git a/source/blender/draw/modes/shaders/paint_texture_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl
index ddfc2b51437..cb29fefb7ef 100644
--- a/source/blender/draw/modes/shaders/paint_texture_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl
@@ -2,14 +2,16 @@
in vec3 pos;
in vec2 mu; /* masking uv map */
-out vec2 masking_uv_interp;
+out vec2 uv_interp;
void main()
{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
- masking_uv_interp = mu;
+ uv_interp = mu;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
diff --git a/source/blender/draw/modes/shaders/paint_vertex_frag.glsl b/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl
index f03e3410ec3..2500ff83abe 100644
--- a/source/blender/draw/modes/shaders/paint_vertex_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl
@@ -2,7 +2,9 @@
in vec3 finalColor;
out vec4 fragColor;
+
uniform float opacity = 1.0;
+uniform bool useAlphaBlend = false;
vec3 linear_to_srgb_attr(vec3 c)
{
@@ -15,10 +17,12 @@ vec3 linear_to_srgb_attr(vec3 c)
void main()
{
vec3 color = linear_to_srgb_attr(finalColor);
-#ifdef DRW_STATE_BLEND_ALPHA
- fragColor = vec4(color, opacity);
-#else
- fragColor.rgb = mix(vec3(1.0), color, opacity);
- fragColor.a = 1.0;
-#endif
+
+ if (useAlphaBlend) {
+ fragColor = vec4(color, opacity);
+ }
+ else {
+ /* mix with 1.0 -> is like opacity when using multiply blend mode */
+ fragColor = vec4(mix(vec3(1.0), color, opacity), 1.0);
+ }
}
diff --git a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl
index 24033432a48..e060e33deba 100644
--- a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl
@@ -14,6 +14,8 @@ vec3 srgb_to_linear_attr(vec3 c)
void main()
{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
diff --git a/source/blender/draw/modes/shaders/paint_weight_frag.glsl b/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl
index 76b7719be64..0020d76ed6a 100644
--- a/source/blender/draw/modes/shaders/paint_weight_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl
@@ -6,6 +6,7 @@ out vec4 fragColor;
uniform float opacity = 1.0;
uniform sampler1D colorramp;
+uniform bool useAlphaBlend = false;
uniform bool drawContours = false;
float contours(float value, float steps, float width_px, float max_rel_width, float gradient)
@@ -95,11 +96,11 @@ void main()
color = mix(weight_color, colorVertexUnreferenced, alert * alert);
}
-#ifdef DRW_STATE_BLEND_ALPHA
- /* alpha blending mix */
- fragColor = vec4(color.rgb, opacity);
-#else
- /* mix with 1.0 -> is like opacity when using multiply blend mode */
- fragColor = vec4(mix(vec3(1.0), color.rgb, opacity), 1.0);
-#endif
+ if (useAlphaBlend) {
+ fragColor = vec4(color.rgb, opacity);
+ }
+ else {
+ /* mix with 1.0 -> is like opacity when using multiply blend mode */
+ fragColor = vec4(mix(vec3(1.0), color.rgb, opacity), 1.0);
+ }
}
diff --git a/source/blender/draw/modes/shaders/paint_weight_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl
index 330cc7d19f4..b3baa8c7b07 100644
--- a/source/blender/draw/modes/shaders/paint_weight_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl
@@ -6,6 +6,8 @@ out vec2 weight_interp; /* (weight, alert) */
void main()
{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
diff --git a/source/blender/draw/modes/shaders/paint_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl
index 5857ffc9960..d5a42d2d309 100644
--- a/source/blender/draw/modes/shaders/paint_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl
@@ -1,4 +1,6 @@
+uniform bool useSelect;
+
in vec3 pos;
in vec4 nor; /* flag stored in w */
@@ -6,13 +8,11 @@ flat out vec4 finalColor;
void main()
{
-#ifdef USE_SELECT
- bool is_select = (nor.w > 0.0);
- bool is_hidden = (nor.w < 0.0);
-#else
- bool is_select = false;
- bool is_hidden = false;
-#endif
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ bool is_select = (nor.w > 0.0) && useSelect;
+ bool is_hidden = (nor.w < 0.0) && useSelect;
+
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
/* Add offset in Z to avoid zfighting and render selected wires on top. */
@@ -23,30 +23,14 @@ void main()
gl_Position = vec4(-2.0, -2.0, -2.0, 1.0);
}
-#ifdef VERTEX_MODE
- vec4 colSel = colorEdgeSelect;
- colSel.rgb = clamp(colSel.rgb - 0.2, 0.0, 1.0);
-#else
- const vec4 colSel = vec4(1.0, 1.0, 1.0, 1.0);
-#endif
+ const vec4 colSel = vec4(1.0);
-#ifdef USE_SELECT
finalColor = (is_select) ? colSel : colorWire;
- finalColor.a = nor.w;
-#else
-# ifdef VERTEX_MODE
- finalColor.xyz = colorWire.xyz;
- finalColor.a = 1.0;
-# else
- /* Weight paint needs a light color to contrasts with dark weights. */
- finalColor = vec4(1, 1, 1, 0.2);
-# endif
-#endif
- /* Needed for Radeon (TM) RX 480 Graphics. */
-#if defined(GPU_ATI)
- gl_PointSize = sizeVertex * 2.0;
-#endif
+ /* Weight paint needs a light color to contrasts with dark weights. */
+ if (!useSelect) {
+ finalColor = vec4(1.0, 1.0, 1.0, 0.3);
+ }
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
diff --git a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl b/source/blender/draw/engines/overlay/shaders/particle_frag.glsl
new file mode 100644
index 00000000000..36928d0c776
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/particle_frag.glsl
@@ -0,0 +1,16 @@
+
+in vec4 finalColor;
+
+out vec4 fragColor;
+
+void main()
+{
+ float dist = length(gl_PointCoord - vec2(0.5));
+
+ if (dist > 0.5) {
+ discard;
+ }
+ /* Nice sphere falloff. */
+ float intensity = sqrt(1.0 - dist * 2.0) * 0.5 + 0.5;
+ fragColor = finalColor * vec4(intensity, intensity, intensity, 1.0);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl b/source/blender/draw/engines/overlay/shaders/particle_vert.glsl
new file mode 100644
index 00000000000..9ff2c42921d
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/particle_vert.glsl
@@ -0,0 +1,68 @@
+
+uniform sampler1D weightTex;
+uniform vec4 color; /* Drawsize packed in alpha */
+
+/* ---- Instantiated Attrs ---- */
+in vec3 pos;
+in int vclass;
+
+/* ---- Per instance Attrs ---- */
+in vec3 part_pos;
+in vec4 part_rot;
+in float part_val;
+
+#ifdef USE_DOTS
+out vec4 finalColor;
+#else
+flat out vec4 finalColor;
+#endif
+
+#define VCLASS_SCREENALIGNED (1 << 9)
+
+#define VCLASS_EMPTY_AXES (1 << 11)
+
+vec3 rotate(vec3 vec, vec4 quat)
+{
+ /* The quaternion representation here stores the w component in the first index */
+ return vec + 2.0 * cross(quat.yzw, cross(quat.yzw, vec) + quat.x * vec);
+}
+
+void main()
+{
+ float draw_size = color.a;
+
+ vec3 world_pos = part_pos;
+
+#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;
+#else
+
+ if ((vclass & VCLASS_SCREENALIGNED) != 0) {
+ /* World sized, camera facing geometry. */
+ world_pos += (screenVecs[0].xyz * pos.x + screenVecs[1].xyz * pos.y) * draw_size;
+ }
+ else {
+ world_pos += rotate(pos, part_rot) * draw_size;
+ }
+
+ gl_Position = point_world_to_ndc(world_pos);
+#endif
+
+ /* Coloring */
+ if ((vclass & VCLASS_EMPTY_AXES) != 0) {
+ /* see VBO construction for explanation. */
+ finalColor = vec4(clamp(pos * 10000.0, 0.0, 1.0), 1.0);
+ }
+ else if (part_val < 0.0) {
+ finalColor = vec4(color.rgb, 1.0);
+ }
+ else {
+ finalColor = vec4(texture(weightTex, part_val).rgb, 1.0);
+ }
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl b/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl
new file mode 100644
index 00000000000..38559677706
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl
@@ -0,0 +1,19 @@
+
+uniform float maskOpacity;
+
+in vec3 pos;
+in float msk;
+
+out vec4 finalColor;
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ finalColor = vec4(0.0, 0.0, 0.0, msk * maskOpacity);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/volume_velocity_vert.glsl b/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl
index 64f88bd74fa..752694301f7 100644
--- a/source/blender/draw/modes/shaders/volume_velocity_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl
@@ -6,11 +6,11 @@ uniform float displaySize = 1.0;
uniform float slicePosition;
uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
-/* SmokeDomainSettings.cell_size */
+/* FluidDomainSettings.cell_size */
uniform vec3 cellSize;
-/* SmokeDomainSettings.p0 */
+/* FluidDomainSettings.p0 */
uniform vec3 domainOriginOffset;
-/* SmokeDomainSettings.res_min */
+/* FluidDomainSettings.res_min */
uniform ivec3 adaptiveCellOffset;
flat out vec4 finalColor;
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl
new file mode 100644
index 00000000000..edfe720da0c
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl
@@ -0,0 +1,25 @@
+
+flat in vec2 edgeStart;
+
+#ifndef SELECT_EDGES
+in vec3 finalColor;
+noperspective in vec2 edgePos;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
+#endif
+
+void main()
+{
+ /* Needed only because of wireframe slider.
+ * If we could get rid of it would be nice because of performance drain of discard. */
+ if (edgeStart.r == -1.0) {
+ discard;
+ }
+
+#ifndef SELECT_EDGES
+ lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
+ fragColor.rgb = finalColor;
+ fragColor.a = 1.0;
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
new file mode 100644
index 00000000000..21f8bcf1791
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
@@ -0,0 +1,154 @@
+
+uniform float wireStepParam;
+uniform bool useColoring;
+uniform bool isTransform;
+uniform bool isObjectColor;
+uniform bool isRandomColor;
+
+in vec3 pos;
+in vec3 nor;
+in float wd; /* wiredata */
+
+flat out vec2 edgeStart;
+
+#ifndef SELECT_EDGES
+out vec3 finalColor;
+noperspective out vec2 edgePos;
+#endif
+
+float get_edge_sharpness(float wd)
+{
+ return ((wd == 0.0) ? -1.5 : wd) + wireStepParam;
+}
+
+void wire_color_get(out vec3 rim_col, out vec3 wire_col)
+{
+ int flag = int(abs(ObjectInfo.w));
+ bool is_selected = (flag & DRW_BASE_SELECTED) != 0;
+ bool is_from_dupli = (flag & DRW_BASE_FROM_DUPLI) != 0;
+ bool is_from_set = (flag & DRW_BASE_FROM_SET) != 0;
+ bool is_active = (flag & DRW_BASE_ACTIVE) != 0;
+
+ if (is_from_set) {
+ rim_col = colorDupli.rgb;
+ wire_col = colorDupli.rgb;
+ }
+ else if (is_from_dupli) {
+ if (is_selected) {
+ if (isTransform) {
+ rim_col = colorTransform.rgb;
+ }
+ else {
+ rim_col = colorDupliSelect.rgb;
+ }
+ }
+ else {
+ rim_col = colorDupli.rgb;
+ }
+ wire_col = colorDupli.rgb;
+ }
+ else if (is_selected && useColoring) {
+ if (isTransform) {
+ rim_col = colorTransform.rgb;
+ }
+ else if (is_active) {
+ rim_col = colorActive.rgb;
+ }
+ else {
+ rim_col = colorSelect.rgb;
+ }
+ wire_col = colorWire.rgb;
+ }
+ else {
+ rim_col = colorWire.rgb;
+ wire_col = colorBackground.rgb;
+ }
+}
+
+vec3 hsv_to_rgb(vec3 hsv)
+{
+ vec3 nrgb = abs(hsv.x * 6.0 - vec3(3.0, 2.0, 4.0)) * vec3(1, -1, -1) + vec3(-1, 2, 2);
+ nrgb = clamp(nrgb, 0.0, 1.0);
+ return ((nrgb - 1.0) * hsv.y + 1.0) * hsv.z;
+}
+
+void wire_object_color_get(out vec3 rim_col, out vec3 wire_col)
+{
+ int flag = int(abs(ObjectInfo.w));
+ bool is_selected = (flag & DRW_BASE_SELECTED) != 0;
+
+ if (isObjectColor) {
+ rim_col = wire_col = ObjectColor.rgb * 0.5;
+ }
+ else {
+ float hue = ObjectInfo.z;
+ vec3 hsv = vec3(hue, 0.75, 0.8);
+ rim_col = wire_col = hsv_to_rgb(hsv);
+ }
+
+ if (is_selected && useColoring) {
+ /* "Normalize" color. */
+ wire_col += 1e-4; /* Avoid division by 0. */
+ float brightness = max(wire_col.x, max(wire_col.y, wire_col.z));
+ wire_col *= 0.5 / brightness;
+ rim_col += 0.75;
+ }
+ else {
+ rim_col *= 0.5;
+ wire_col += 0.5;
+ }
+}
+
+void main()
+{
+ vec3 wpos = point_object_to_world(pos);
+ vec3 wnor = normalize(normal_object_to_world(nor));
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrix[2].xyz;
+
+ float facing = dot(wnor, V);
+ float facing_ratio = clamp(1.0 - facing * facing, 0.0, 1.0);
+ float flip = sign(facing); /* Flip when not facing the normal (i.e.: backfacing). */
+ float curvature = (1.0 - wd * 0.75); /* Avoid making things worse for curvy areas. */
+ vec3 wofs = wnor * (facing_ratio * curvature * flip);
+ wofs = normal_world_to_view(wofs);
+
+ gl_Position = point_world_to_ndc(wpos);
+
+ /* Push vertex half a pixel (maximum) in normal direction. */
+ gl_Position.xy += wofs.xy * sizeViewportInv.xy * gl_Position.w;
+
+ /* Push the vertex towards the camera. Helps a bit. */
+ gl_Position.z -= facing_ratio * curvature * 1e-4;
+
+ /* Convert to screen position [0..sizeVp]. */
+ edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+
+#ifndef SELECT_EDGES
+ edgePos = edgeStart;
+
+ vec3 rim_col, wire_col;
+ if (isObjectColor || isRandomColor) {
+ wire_object_color_get(rim_col, wire_col);
+ }
+ else {
+ wire_color_get(rim_col, wire_col);
+ }
+
+ facing = clamp(abs(facing), 0.0, 1.0);
+
+ vec3 final_front_col = mix(rim_col, wire_col, 0.4);
+ vec3 final_rim_col = mix(rim_col, wire_col, 0.1);
+ finalColor = mix(final_rim_col, final_front_col, facing);
+#endif
+
+ /* Cull flat edges below threshold. */
+ if (get_edge_sharpness(wd) < 0.0) {
+ edgeStart = vec2(-1.0);
+ }
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(wpos);
+#endif
+}
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index abfa57dd218..23399056582 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -147,8 +147,8 @@ static void select_engine_init(void *vedata)
/* Create view with depth offset */
stl->g_data->view_faces = (DRWView *)view_default;
- stl->g_data->view_edges = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.0f);
- stl->g_data->view_verts = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.1f);
+ stl->g_data->view_edges = DRW_view_create_with_zoffset(view_default, draw_ctx->rv3d, 1.0f);
+ stl->g_data->view_verts = DRW_view_create_with_zoffset(view_default, draw_ctx->rv3d, 1.1f);
}
}
@@ -223,6 +223,19 @@ static void select_cache_init(void *vedata)
/* Check if the viewport has changed. */
float(*persmat)[4] = draw_ctx->rv3d->persmat;
e_data.context.is_dirty = !compare_m4m4(e_data.context.persmat, persmat, FLT_EPSILON);
+
+ if (!e_data.context.is_dirty) {
+ /* Check if any of the drawn objects have been transformed. */
+ Object **ob = &e_data.context.objects_drawn[0];
+ for (uint i = e_data.context.objects_drawn_len; i--; ob++) {
+ DrawData *data = DRW_drawdata_get(&(*ob)->id, &draw_engine_select_type);
+ if (data && (data->recalc & ID_RECALC_TRANSFORM) != 0) {
+ data->recalc &= ~ID_RECALC_TRANSFORM;
+ e_data.context.is_dirty = true;
+ }
+ }
+ }
+
if (e_data.context.is_dirty) {
/* Remove all tags from drawn or culled objects. */
copy_m4_m4(e_data.context.persmat, persmat);
@@ -280,6 +293,7 @@ static void select_cache_populate(void *vedata, Object *ob)
sel_data = (SELECTID_ObjectData *)DRW_drawdata_ensure(
&ob->id, &draw_engine_select_type, sizeof(SELECTID_ObjectData), NULL, NULL);
}
+ sel_data->dd.recalc = 0;
sel_data->drawn_index = e_data.context.objects_drawn_len;
sel_data->is_drawn = true;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
index 092878e43aa..95ca2c0c297 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
@@ -9,8 +9,6 @@ uniform vec2 invertedViewportSize;
void main()
{
ivec2 texel = ivec2(gl_FragCoord.xy);
- float alpha = texelFetch(colorBuffer, texel, 0).a;
FragColor = FxaaPixelShader(
uvcoordsvar.st, colorBuffer, invertedViewportSize, 1.0, 0.166, 0.0833);
- FragColor.a = alpha;
}
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
index 3e63f05ca64..f07b21ebcc2 100644
--- a/source/blender/draw/engines/workbench/workbench_data.c
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -30,6 +30,77 @@
#include "GPU_batch.h"
+/* -------------------------------------------------------------------- */
+/** \name World Data
+ * \{ */
+
+static void workbench_world_data_free(DrawData *dd)
+{
+ WORKBENCH_WorldData *data = (WORKBENCH_WorldData *)dd;
+ DRW_UBO_FREE_SAFE(data->world_ubo);
+}
+
+/* Ensure the availability of the world_ubo in the given WORKBENCH_PrivateData
+ *
+ * See T70167: Some platforms create threads to upload ubo's.
+ *
+ * Reuses the last previous created `world_ubo`. Due to limitations of
+ * DrawData it will only be reused when there is a world attached to the Scene.
+ * Future development: The best location would be to store it in the View3D.
+ *
+ * We don't cache the data itself as there was no indication that that lead to
+ * an improvement.
+ *
+ * This functions also sets the `WORKBENCH_PrivateData.is_world_ubo_owner` that must
+ * be respected.
+ */
+static void workbench_world_data_ubo_ensure(const Scene *scene, WORKBENCH_PrivateData *wpd)
+{
+ World *world = scene->world;
+ if (world) {
+ WORKBENCH_WorldData *engine_world_data = (WORKBENCH_WorldData *)DRW_drawdata_ensure(
+ &world->id,
+ &draw_engine_workbench_solid,
+ sizeof(WORKBENCH_WorldData),
+ NULL,
+ &workbench_world_data_free);
+
+ if (engine_world_data->world_ubo == NULL) {
+ engine_world_data->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World),
+ &wpd->world_data);
+ }
+ else {
+ DRW_uniformbuffer_update(engine_world_data->world_ubo, &wpd->world_data);
+ }
+
+ /* Borrow world data ubo */
+ wpd->is_world_ubo_owner = false;
+ wpd->world_ubo = engine_world_data->world_ubo;
+ }
+ else {
+ /* there is no world so we cannot cache the UBO. */
+ BLI_assert(!wpd->world_ubo || wpd->is_world_ubo_owner);
+ if (!wpd->world_ubo) {
+ wpd->is_world_ubo_owner = true;
+ wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data);
+ }
+ }
+}
+
+static void workbench_world_data_update_shadow_direction_vs(WORKBENCH_PrivateData *wpd)
+{
+ WORKBENCH_UBO_World *wd = &wpd->world_data;
+ float light_direction[3];
+ float view_matrix[4][4];
+ DRW_view_viewmat_get(NULL, view_matrix, false);
+
+ workbench_private_data_get_light_direction(light_direction);
+
+ /* Shadow direction. */
+ mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, light_direction);
+}
+/* \} */
+
void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info)
{
effect_info->jitter_index = 0;
@@ -45,6 +116,8 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
wpd->preferences = &U;
View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) {
wpd->shading = scene->display.shading;
wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display));
@@ -122,24 +195,22 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
wd->curvature_valley = 0.7f / max_ff(SQUARE(wpd->shading.curvature_valley_factor), 1e-4f);
/* Will be NULL when rendering. */
- if (draw_ctx->rv3d != NULL) {
- RegionView3D *rv3d = draw_ctx->rv3d;
- if (rv3d->rflag & RV3D_CLIPPING) {
- wpd->world_clip_planes = rv3d->clip;
- UI_GetThemeColor4fv(TH_V3D_CLIPPING_BORDER, wpd->world_clip_planes_color);
- if (wpd->use_color_management) {
- srgb_to_linearrgb_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color);
- }
- else {
- copy_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color);
- }
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
+ wpd->world_clip_planes = rv3d->clip;
+ UI_GetThemeColor4fv(TH_V3D_CLIPPING_BORDER, wpd->world_clip_planes_color);
+ if (wpd->use_color_management) {
+ srgb_to_linearrgb_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color);
}
else {
- wpd->world_clip_planes = NULL;
+ copy_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color);
}
}
+ else {
+ wpd->world_clip_planes = NULL;
+ }
- wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data);
+ workbench_world_data_update_shadow_direction_vs(wpd);
+ workbench_world_data_ubo_ensure(scene, wpd);
/* Cavity settings */
{
@@ -203,31 +274,29 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
BLI_listbase_clear(&wpd->smoke_domains);
}
-void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd,
- float r_light_direction[3])
+void workbench_private_data_get_light_direction(float r_light_direction[3])
{
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- WORKBENCH_UBO_World *wd = &wpd->world_data;
- float view_matrix[4][4];
- DRW_view_viewmat_get(NULL, view_matrix, false);
copy_v3_v3(r_light_direction, scene->display.light_direction);
SWAP(float, r_light_direction[2], r_light_direction[1]);
r_light_direction[2] = -r_light_direction[2];
r_light_direction[0] = -r_light_direction[0];
-
- /* Shadow direction. */
- mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, r_light_direction);
-
- DRW_uniformbuffer_update(wpd->world_ubo, wd);
}
void workbench_private_data_free(WORKBENCH_PrivateData *wpd)
{
BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN);
BLI_ghash_free(wpd->material_transp_hash, NULL, MEM_freeN);
- DRW_UBO_FREE_SAFE(wpd->world_ubo);
+
+ if (wpd->is_world_ubo_owner) {
+ DRW_UBO_FREE_SAFE(wpd->world_ubo);
+ }
+ else {
+ wpd->world_ubo = NULL;
+ }
+
DRW_UBO_FREE_SAFE(wpd->dof_ubo);
GPU_BATCH_DISCARD_SAFE(wpd->world_clip_planes_batch);
}
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index 2e8b952f234..02a3af7fa73 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -34,6 +34,7 @@
#include "BKE_particle.h"
#include "DNA_image_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
@@ -74,7 +75,6 @@ static struct {
/* TODO(fclem) move everything below to wpd and custom viewlayer data. */
struct GPUTexture *oit_accum_tx; /* ref only, not alloced */
struct GPUTexture *oit_revealage_tx; /* ref only, not alloced */
- struct GPUTexture *ghost_depth_tx; /* ref only, not alloced */
struct GPUTexture *object_id_tx; /* ref only, not alloced */
struct GPUTexture *color_buffer_tx; /* ref only, not alloced */
struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */
@@ -214,16 +214,16 @@ static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature)
static GPUShader *ensure_deferred_prepass_shader(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
- bool is_texture_painting,
+ const WORKBENCH_ColorOverride color_override,
eGPUShaderConfig sh_cfg)
{
WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_cfg];
int index = workbench_material_get_prepass_shader_index(
- wpd, is_uniform_color, is_hair, is_texture_painting);
+ wpd, is_uniform_color, is_hair, color_override);
if (sh_data->prepass_sh_cache[index] == NULL) {
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
char *defines = workbench_material_build_defines(
- wpd, is_uniform_color, is_hair, is_texture_painting);
+ wpd, is_uniform_color, is_hair, color_override);
char *prepass_vert = workbench_build_prepass_vert(is_hair);
char *prepass_frag = workbench_build_prepass_frag();
sh_data->prepass_sh_cache[index] = GPU_shader_create_from_arrays({
@@ -242,7 +242,8 @@ static GPUShader *ensure_deferred_composite_shader(WORKBENCH_PrivateData *wpd)
{
int index = workbench_material_get_composite_shader_index(wpd);
if (e_data.composite_sh_cache[index] == NULL) {
- char *defines = workbench_material_build_defines(wpd, false, false, false);
+ char *defines = workbench_material_build_defines(
+ wpd, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
char *composite_frag = workbench_build_composite_frag(wpd);
e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
MEM_freeN(composite_frag);
@@ -269,11 +270,18 @@ static GPUShader *ensure_background_shader(WORKBENCH_PrivateData *wpd)
static void select_deferred_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
{
- wpd->prepass_sh = ensure_deferred_prepass_shader(wpd, false, false, false, sh_cfg);
- wpd->prepass_hair_sh = ensure_deferred_prepass_shader(wpd, false, true, false, sh_cfg);
- wpd->prepass_uniform_sh = ensure_deferred_prepass_shader(wpd, true, false, false, sh_cfg);
- wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader(wpd, true, true, false, sh_cfg);
- wpd->prepass_textured_sh = ensure_deferred_prepass_shader(wpd, false, false, true, sh_cfg);
+ wpd->prepass_sh = ensure_deferred_prepass_shader(
+ wpd, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd->prepass_hair_sh = ensure_deferred_prepass_shader(
+ wpd, false, true, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd->prepass_uniform_sh = ensure_deferred_prepass_shader(
+ wpd, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader(
+ wpd, true, true, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd->prepass_textured_sh = ensure_deferred_prepass_shader(
+ wpd, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
+ wpd->prepass_vertex_sh = ensure_deferred_prepass_shader(
+ wpd, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
wpd->composite_sh = ensure_deferred_composite_shader(wpd);
wpd->background_sh = ensure_background_shader(wpd);
}
@@ -568,21 +576,20 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
/* Prepass */
{
DRWShadingGroup *grp;
- const bool do_cull = CULL_BACKFACE_ENABLED(wpd);
+ DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0;
+ DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->prepass_pass = DRW_pass_create("Prepass",
- (do_cull) ? state | DRW_STATE_CULL_BACK : state);
- psl->prepass_hair_pass = DRW_pass_create("Prepass", state);
+ psl->prepass_pass = DRW_pass_create("Prepass", state | cull_state | clip_state);
+ psl->prepass_hair_pass = DRW_pass_create("Prepass", state | clip_state);
- psl->ghost_prepass_pass = DRW_pass_create("Prepass Ghost",
- (do_cull) ? state | DRW_STATE_CULL_BACK : state);
- psl->ghost_prepass_hair_pass = DRW_pass_create("Prepass Ghost", state);
+ psl->ghost_prepass_pass = DRW_pass_create("Prepass Ghost", state | cull_state | clip_state);
+ psl->ghost_prepass_hair_pass = DRW_pass_create("Prepass Ghost", state | clip_state);
psl->ghost_resolve_pass = DRW_pass_create("Resolve Ghost Depth",
DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
grp = DRW_shgroup_create(e_data.ghost_resolve_sh, psl->ghost_resolve_pass);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.ghost_depth_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front);
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
@@ -621,23 +628,6 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
}
}
-static void workbench_setup_ghost_framebuffer(WORKBENCH_FramebufferList *fbl)
-{
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
-
- e_data.ghost_depth_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_workbench_solid);
-
- GPU_framebuffer_ensure_config(&fbl->ghost_prepass_fb,
- {
- GPU_ATTACHMENT_TEXTURE(e_data.ghost_depth_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
- });
-}
-
void workbench_deferred_engine_free(void)
{
for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
@@ -735,7 +725,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
}
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- if (draw_ctx->rv3d && (draw_ctx->rv3d->rflag & RV3D_CLIPPING) && draw_ctx->rv3d->clipbb) {
+ if (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) {
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND);
grp = DRW_shgroup_create(shader, psl->background_pass);
wpd->world_clip_planes_batch = DRW_draw_background_clipping_batch_from_rv3d(draw_ctx->rv3d);
@@ -746,7 +736,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
/* Deferred Mix Pass */
{
- workbench_private_data_get_light_direction(wpd, e_data.display.light_direction);
+ workbench_private_data_get_light_direction(e_data.display.light_direction);
studiolight_update_light(wpd, e_data.display.light_direction);
if (SHADOW_ENABLED(wpd)) {
@@ -825,18 +815,19 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
* this in a clean way.
*/
if (OIT_ENABLED(wpd)) {
- const bool do_cull = CULL_BACKFACE_ENABLED(wpd);
- const int cull_state = (do_cull) ? DRW_STATE_CULL_BACK : 0;
+ DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0;
+ DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
/* Transparency Accum */
{
/* Same as forward but here we use depth test to
* not bleed through other solid objects. */
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_OIT | DRW_STATE_DEPTH_LESS | cull_state;
+ int state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND_OIT | cull_state |
+ clip_state;
psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state);
}
/* Depth */
{
- int state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state;
+ int state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state | clip_state;
psl->object_outline_pass = DRW_pass_create("Transparent Depth", state);
}
/* OIT Composite */
@@ -885,6 +876,9 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
shader = wpd->prepass_textured_sh;
}
+ if (color_type == V3D_SHADING_VERTEX_COLOR) {
+ shader = wpd->prepass_vertex_sh;
+ }
material->shgrp = DRW_shgroup_create(
shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass);
workbench_material_copy(material, &material_template);
@@ -981,6 +975,22 @@ static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata,
}
}
+static void workbench_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
+ WORKBENCH_MaterialData *material;
+
+ int color_type = workbench_material_determine_color_type(wpd, NULL, ob, use_sculpt_pbvh);
+ struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob);
+ material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, false);
+ DRW_shgroup_call(material->shgrp, geom, ob);
+}
+
void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
{
WORKBENCH_StorageList *stl = vedata->stl;
@@ -999,9 +1009,10 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
ModifierData *md;
if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (md = modifiers_findByType(ob, eModifierType_Fluid)) &&
(modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- (((SmokeModifierData *)md)->domain != NULL)) {
+ (((FluidModifierData *)md)->domain != NULL) &&
+ (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) {
workbench_volume_cache_populate(vedata, scene, ob, md);
return; /* Do not draw solid in this case. */
}
@@ -1021,14 +1032,22 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
const int materials_len = MAX2(1, ob->totcol);
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
bool has_transp_mat = false;
+ const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob);
const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
draw_ctx->v3d == NULL) &&
- workbench_is_object_in_texture_paint_mode(ob) && me &&
- me->mloopuv;
+ (color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) &&
+ me && me->mloopuv;
+ const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() &&
+ draw_ctx->v3d == NULL) &&
+ (color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) &&
+ me && me->mloopcol;
if (use_texture_paint_drawing) {
workbench_cache_populate_texture_paint_mode(vedata, ob);
}
+ else if (use_vertex_paint_drawing) {
+ workbench_cache_populate_vertex_paint_mode(vedata, ob);
+ }
else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) {
/* Draw textured */
struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
@@ -1217,8 +1236,33 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
}
}
-void workbench_deferred_cache_finish(WORKBENCH_Data *UNUSED(vedata))
+void workbench_deferred_cache_finish(WORKBENCH_Data *vedata)
{
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+
+ if (GHOST_ENABLED(psl)) {
+ /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
+
+ GPU_framebuffer_ensure_config(
+ &dfbl->default_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ GPU_framebuffer_ensure_config(
+ &dfbl->in_front_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+
+ GPU_framebuffer_ensure_config(&fbl->ghost_prepass_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
+ });
+ }
}
void workbench_deferred_draw_background(WORKBENCH_Data *vedata)
@@ -1252,6 +1296,7 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
WORKBENCH_FramebufferList *fbl = vedata->fbl;
WORKBENCH_PrivateData *wpd = stl->g_data;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
if (workbench_is_taa_enabled(wpd)) {
workbench_taa_draw_scene_start(vedata);
@@ -1262,12 +1307,17 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
DRW_draw_pass(psl->prepass_pass);
DRW_draw_pass(psl->prepass_hair_pass);
- if (GHOST_ENABLED(psl)) {
- /* meh, late init to not request a depth buffer we won't use. */
- workbench_setup_ghost_framebuffer(fbl);
-
+ if (fbl->ghost_prepass_fb) {
GPU_framebuffer_bind(fbl->ghost_prepass_fb);
GPU_framebuffer_clear_depth(fbl->ghost_prepass_fb, 1.0f);
+ }
+ else if (dtxl->depth_in_front) {
+ /* TODO(fclem) This clear should be done in a global place. */
+ GPU_framebuffer_bind(dfbl->in_front_fb);
+ GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
+ }
+
+ if (GHOST_ENABLED(psl)) {
DRW_draw_pass(psl->ghost_prepass_pass);
DRW_draw_pass(psl->ghost_prepass_hair_pass);
@@ -1318,6 +1368,7 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
/* In order to not draw on top of ghost objects, we clear the stencil
* to 0xFF and the ghost object to 0x00 and only draw overlays on top if
* stencil is not 0. */
+ /* TODO(fclem) Remove this hack. */
GPU_framebuffer_bind(dfbl->depth_only_fb);
GPU_framebuffer_clear_stencil(dfbl->depth_only_fb, 0xFF);
@@ -1335,7 +1386,6 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
DRW_draw_pass(psl->background_pass);
if (OIT_ENABLED(wpd) && !DRW_pass_is_empty(psl->transparent_accum_pass)) {
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
/* meh, late init to not request buffers we won't use. */
workbench_init_oit_framebuffer(fbl, dtxl);
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index d731b167c06..44f43fc7d09 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -22,8 +22,6 @@
#include "workbench_private.h"
-#include "BIF_gl.h"
-
#include "BLI_alloca.h"
#include "BLI_dynstr.h"
#include "BLI_string_utils.h"
@@ -35,6 +33,7 @@
#include "BKE_particle.h"
#include "DNA_image_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
@@ -227,16 +226,16 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
static GPUShader *ensure_forward_accum_shaders(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
- bool is_texture_painting,
+ const WORKBENCH_ColorOverride color_override,
eGPUShaderConfig sh_cfg)
{
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg];
int index = workbench_material_get_accum_shader_index(
- wpd, is_uniform_color, is_hair, is_texture_painting);
+ wpd, is_uniform_color, is_hair, color_override);
if (sh_data->transparent_accum_sh_cache[index] == NULL) {
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
char *defines = workbench_material_build_defines(
- wpd, is_uniform_color, is_hair, is_texture_painting);
+ wpd, is_uniform_color, is_hair, color_override);
char *transparent_accum_vert = workbench_build_forward_vert(is_hair);
char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag();
sh_data->transparent_accum_sh_cache[index] = GPU_shader_create_from_arrays({
@@ -255,7 +254,8 @@ static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd)
{
int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0;
if (e_data.composite_sh_cache[index] == NULL) {
- char *defines = workbench_material_build_defines(wpd, false, false, false);
+ char *defines = workbench_material_build_defines(
+ wpd, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
char *composite_frag = workbench_build_forward_composite_frag();
e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
MEM_freeN(composite_frag);
@@ -267,14 +267,18 @@ static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd)
void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
{
wpd->composite_sh = ensure_forward_composite_shaders(wpd);
- wpd->transparent_accum_sh = ensure_forward_accum_shaders(wpd, false, false, false, sh_cfg);
- wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(wpd, false, true, false, sh_cfg);
+ wpd->transparent_accum_sh = ensure_forward_accum_shaders(
+ wpd, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(
+ wpd, false, true, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders(
- wpd, true, false, false, sh_cfg);
+ wpd, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders(
- wpd, true, true, false, sh_cfg);
+ wpd, true, true, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->transparent_accum_textured_sh = ensure_forward_accum_shaders(
- wpd, false, false, true, sh_cfg);
+ wpd, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
+ wpd->transparent_accum_vertex_sh = ensure_forward_accum_shaders(
+ wpd, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
}
void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
@@ -283,9 +287,12 @@ void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUSh
if (sh_data->object_outline_sh == NULL) {
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- char *defines = workbench_material_build_defines(wpd, false, false, false);
- char *defines_texture = workbench_material_build_defines(wpd, true, false, false);
- char *defines_hair = workbench_material_build_defines(wpd, false, true, false);
+ char *defines = workbench_material_build_defines(
+ wpd, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
+ char *defines_texture = workbench_material_build_defines(
+ wpd, true, false, WORKBENCH_COLOR_OVERRIDE_OFF);
+ char *defines_hair = workbench_material_build_defines(
+ wpd, false, true, WORKBENCH_COLOR_OVERRIDE_OFF);
char *forward_vert = workbench_build_forward_vert(false);
char *forward_frag = workbench_build_forward_outline_frag();
char *forward_hair_vert = workbench_build_forward_vert(true);
@@ -337,8 +344,6 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata)
}
WORKBENCH_PrivateData *wpd = stl->g_data;
workbench_private_data_init(wpd);
- float light_direction[3];
- workbench_private_data_get_light_direction(wpd, light_direction);
if (!e_data.checker_depth_sh) {
e_data.checker_depth_sh = DRW_shader_create_fullscreen(
@@ -391,17 +396,19 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata)
});
workbench_volume_cache_init(vedata);
- const bool do_cull = CULL_BACKFACE_ENABLED(wpd);
- const int cull_state = (do_cull) ? DRW_STATE_CULL_BACK : 0;
+
+ DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0;
+ DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
/* Transparency Accum */
{
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_OIT | cull_state;
+ int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_OIT | cull_state | clip_state;
psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state);
}
/* Depth */
{
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state;
+ int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state |
+ clip_state;
psl->object_outline_pass = DRW_pass_create("Object Outline Pass", state);
}
/* Composite */
@@ -423,7 +430,7 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata)
/* TODO(campbell): displays but masks geometry,
* only use with wire or solid-without-xray for now. */
if ((wpd->shading.type != OB_WIRE && !XRAY_FLAG_ENABLED(wpd)) &&
- (draw_ctx->rv3d && (draw_ctx->rv3d->rflag & RV3D_CLIPPING) && draw_ctx->rv3d->clipbb)) {
+ RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) {
psl->background_pass = DRW_pass_create("Background",
DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND);
@@ -601,6 +608,23 @@ static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *
}
}
}
+static void workbench_forward_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
+ WORKBENCH_MaterialData *material;
+
+ int color_type = workbench_material_determine_color_type(wpd, NULL, ob, use_sculpt_pbvh);
+ struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob);
+ material = workbench_forward_get_or_create_material_data(
+ vedata, ob, NULL, NULL, NULL, color_type, false);
+ DRW_shgroup_call(material->shgrp, geom, ob);
+ DRW_shgroup_call(material->shgrp_object_outline, geom, ob);
+}
void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
{
@@ -620,9 +644,10 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
ModifierData *md;
if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (md = modifiers_findByType(ob, eModifierType_Fluid)) &&
(modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- (((SmokeModifierData *)md)->domain != NULL)) {
+ (((FluidModifierData *)md)->domain != NULL) &&
+ (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) {
workbench_volume_cache_populate(vedata, scene, ob, md);
return; /* Do not draw solid in this case. */
}
@@ -640,14 +665,22 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
!DRW_state_is_image_render();
const int materials_len = MAX2(1, ob->totcol);
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
+ const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob);
const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
draw_ctx->v3d == NULL) &&
- workbench_is_object_in_texture_paint_mode(ob) && me &&
- me->mloopuv;
+ (color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) &&
+ me && me->mloopuv;
+ const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() &&
+ draw_ctx->v3d == NULL) &&
+ (color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) &&
+ me && me->mloopcol;
if (use_texture_paint_drawing) {
workbench_forward_cache_populate_texture_paint_mode(vedata, ob);
}
+ else if (use_vertex_paint_drawing) {
+ workbench_forward_cache_populate_vertex_paint_mode(vedata, ob);
+ }
else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) {
struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
for (int i = 0; i < materials_len; i++) {
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index 0f9551a8cc9..16fcda54253 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -22,8 +22,6 @@
#include "workbench_private.h"
-#include "BIF_gl.h"
-
#include "BKE_image.h"
#include "BKE_node.h"
@@ -87,16 +85,26 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
- bool is_texture_painting)
+ const WORKBENCH_ColorOverride color_override)
{
char *str = NULL;
bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
!is_uniform_color;
- if (is_texture_painting) {
- use_textures = true;
- use_vertex_colors = false;
+ switch (color_override) {
+ case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
+ use_textures = true;
+ use_vertex_colors = false;
+ is_hair = false;
+ break;
+ case WORKBENCH_COLOR_OVERRIDE_VERTEX:
+ use_textures = false;
+ use_vertex_colors = true;
+ is_hair = false;
+ break;
+ case WORKBENCH_COLOR_OVERRIDE_OFF:
+ break;
}
DynStr *ds = BLI_dynstr_new();
@@ -203,15 +211,25 @@ int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
- bool is_texture_painting)
+ const WORKBENCH_ColorOverride color_override)
{
bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
!is_uniform_color;
- if (is_texture_painting) {
- use_textures = true;
- use_vertex_colors = false;
+
+ switch (color_override) {
+ case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
+ use_textures = true;
+ use_vertex_colors = false;
+ break;
+ case WORKBENCH_COLOR_OVERRIDE_VERTEX:
+ use_textures = false;
+ use_vertex_colors = true;
+ break;
+ case WORKBENCH_COLOR_OVERRIDE_OFF:
+ break;
}
+
/* NOTE: change MAX_PREPASS_SHADERS accordingly when modifying this function. */
int index = 0;
SET_FLAG_FROM_TEST(index, is_hair, 1 << 0);
@@ -228,15 +246,25 @@ int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
- bool is_texture_painting)
+ const WORKBENCH_ColorOverride color_override)
{
bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
!is_uniform_color;
- if (is_texture_painting) {
- use_textures = true;
- use_vertex_colors = false;
- is_hair = false;
+
+ switch (color_override) {
+ case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
+ use_textures = true;
+ use_vertex_colors = false;
+ is_hair = false;
+ break;
+ case WORKBENCH_COLOR_OVERRIDE_VERTEX:
+ use_textures = false;
+ use_vertex_colors = true;
+ is_hair = false;
+ break;
+ case WORKBENCH_COLOR_OVERRIDE_OFF:
+ break;
}
/* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */
@@ -269,12 +297,25 @@ int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
color_type = V3D_SHADING_OBJECT_COLOR;
}
- /* Force V3D_SHADING_TEXTURE_COLOR for active object when in texture painting
- * no matter the shading color that the user has chosen, when there is no
- * texture we will render the object with the error color */
- if (workbench_is_object_in_texture_paint_mode(ob)) {
- color_type = ima ? V3D_SHADING_TEXTURE_COLOR : V3D_SHADING_ERROR_COLOR;
+ switch (workbench_object_color_override_get(ob)) {
+ /* Force V3D_SHADING_TEXTURE_COLOR for active object when in texture painting
+ * no matter the shading color that the user has chosen, when there is no
+ * texture we will render the object with the error color */
+ case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
+ color_type = ima ? V3D_SHADING_TEXTURE_COLOR : V3D_SHADING_ERROR_COLOR;
+ break;
+
+ /* Force V3D_SHADING_VERTEX_COLOR for active object when in vertex painting
+ * no matter the shading color that the user has chosen, when there is no
+ * vertex color we will render the object with the error color */
+ case WORKBENCH_COLOR_OVERRIDE_VERTEX:
+ color_type = V3D_SHADING_VERTEX_COLOR;
+ break;
+
+ case WORKBENCH_COLOR_OVERRIDE_OFF:
+ break;
}
+
return color_type;
}
@@ -313,7 +354,7 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
const bool deferred,
const int interp)
{
- if (!(!deferred || workbench_is_matdata_pass_enabled(wpd))) {
+ if (deferred && !workbench_is_matdata_pass_enabled(wpd)) {
return;
}
@@ -333,10 +374,6 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
if (use_highlight) {
DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
}
-
- if (WORLD_CLIPPING_ENABLED(wpd)) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
}
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index 595b92d19d0..7c774ca7490 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -207,6 +207,7 @@ typedef struct WORKBENCH_PrivateData {
struct GPUShader *prepass_uniform_sh;
struct GPUShader *prepass_uniform_hair_sh;
struct GPUShader *prepass_textured_sh;
+ struct GPUShader *prepass_vertex_sh;
struct GPUShader *composite_sh;
struct GPUShader *background_sh;
struct GPUShader *transparent_accum_sh;
@@ -214,9 +215,15 @@ typedef struct WORKBENCH_PrivateData {
struct GPUShader *transparent_accum_uniform_sh;
struct GPUShader *transparent_accum_uniform_hair_sh;
struct GPUShader *transparent_accum_textured_sh;
+ struct GPUShader *transparent_accum_vertex_sh;
View3DShading shading;
StudioLight *studio_light;
const UserDef *preferences;
+ /* Does this instance owns the `world_ubo` field.
+ * Normally the field is borrowed from `WORKBENCH_WorldData`. In case that
+ * there is no World attached to the scene the UBO cannot be cached and should
+ * be freed after using. */
+ bool is_world_ubo_owner;
struct GPUUniformBuffer *world_ubo;
struct DRWShadingGroup *shadow_shgrp;
struct DRWShadingGroup *depth_shgrp;
@@ -307,6 +314,21 @@ typedef struct WORKBENCH_ObjectData {
bool shadow_bbox_dirty;
} WORKBENCH_ObjectData;
+typedef struct WORKBENCH_WorldData {
+ DrawData dd;
+ /* The cached `GPUUniformBuffer`, that is reused between draw calls. */
+ struct GPUUniformBuffer *world_ubo;
+} WORKBENCH_WorldData;
+
+/* Enumeration containing override options for base color rendering.
+ * This is used to during painting to force the base color to show what you are
+ * painting using the selected lighting model. */
+typedef enum WORKBENCH_ColorOverride {
+ WORKBENCH_COLOR_OVERRIDE_OFF = 0,
+ WORKBENCH_COLOR_OVERRIDE_TEXTURE = CTX_MODE_PAINT_TEXTURE,
+ WORKBENCH_COLOR_OVERRIDE_VERTEX = CTX_MODE_PAINT_VERTEX,
+} WORKBENCH_ColorOverride;
+
/* inline helper functions */
BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *wpd)
{
@@ -364,23 +386,35 @@ BLI_INLINE bool workbench_is_in_texture_paint_mode(void)
return draw_ctx->object_mode == OB_MODE_TEXTURE_PAINT;
}
-/** Is texture paint mode active for the given object */
-BLI_INLINE bool workbench_is_object_in_texture_paint_mode(Object *ob)
+/** Is vertex paint mode enabled (globally) */
+BLI_INLINE bool workbench_is_in_vertex_paint_mode(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ return draw_ctx->object_mode == OB_MODE_VERTEX_PAINT;
+}
+
+/* Must the `View3DShading.color_type` be overriden for the given object. */
+BLI_INLINE WORKBENCH_ColorOverride workbench_object_color_override_get(Object *ob)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
if (ob->type == OB_MESH && (draw_ctx->obact == ob)) {
const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
- return (mode == CTX_MODE_PAINT_TEXTURE);
+ if (mode == CTX_MODE_PAINT_TEXTURE) {
+ return WORKBENCH_COLOR_OVERRIDE_TEXTURE;
+ }
+ else if (mode == CTX_MODE_PAINT_VERTEX) {
+ return WORKBENCH_COLOR_OVERRIDE_VERTEX;
+ }
}
- return false;
+ return WORKBENCH_COLOR_OVERRIDE_OFF;
}
BLI_INLINE bool workbench_is_matdata_pass_enabled(WORKBENCH_PrivateData *wpd)
{
return (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) ||
- workbench_is_in_texture_paint_mode();
+ workbench_is_in_texture_paint_mode() || workbench_is_in_vertex_paint_mode();
}
/**
@@ -398,7 +432,7 @@ BLI_INLINE eGPUTextureFormat workbench_color_texture_format(const WORKBENCH_Priv
TEXTURE_DRAWING_ENABLED(wpd)) {
result = GPU_RGBA16F;
}
- else if (VERTEX_COLORS_ENABLED(wpd)) {
+ else if (workbench_is_in_vertex_paint_mode() || VERTEX_COLORS_ENABLED(wpd)) {
result = GPU_RGBA16;
}
else {
@@ -482,7 +516,7 @@ void workbench_material_get_image_and_mat(
char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
- bool is_texture_painting);
+ const WORKBENCH_ColorOverride color_override);
void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
Object *ob,
Material *mat,
@@ -493,11 +527,11 @@ int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd);
int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
- bool is_texture_painting);
+ const WORKBENCH_ColorOverride color_override);
int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
- bool is_texture_painting);
+ const WORKBENCH_ColorOverride color_override);
void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
@@ -526,8 +560,7 @@ bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info);
void workbench_private_data_init(WORKBENCH_PrivateData *wpd);
void workbench_private_data_free(WORKBENCH_PrivateData *wpd);
-void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd,
- float r_light_direction[3]);
+void workbench_private_data_get_light_direction(float r_light_direction[3]);
/* workbench_volume.c */
void workbench_volume_engine_init(void);
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 23f0898c138..2f7296fb40f 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -23,7 +23,7 @@
#include "workbench_private.h"
#include "BKE_object.h"
-#include "BKE_smoke.h"
+#include "BKE_fluid.h"
#include "BLI_rand.h"
#include "BLI_dynstr.h"
@@ -31,7 +31,7 @@
#include "DNA_modifier_types.h"
#include "DNA_object_force_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "GPU_draw.h"
@@ -119,57 +119,56 @@ void workbench_volume_cache_init(WORKBENCH_Data *vedata)
}
void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
- Scene *scene,
+ Scene *UNUSED(scene),
Object *ob,
ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
- SmokeDomainSettings *sds = smd->domain;
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ FluidDomainSettings *mds = mmd->domain;
WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
DRWShadingGroup *grp = NULL;
- /* Don't show smoke before simulation starts, this could be made an option in the future. */
- if (!sds->fluid || CFRA < sds->point_cache[0]->startframe) {
+ /* Don't try to show liquid domains here */
+ if (!mds->fluid || !(mds->type == FLUID_DOMAIN_TYPE_GAS)) {
return;
}
wpd->volumes_do = true;
- const bool show_highres = BKE_smoke_show_highres(scene, sds);
- if (sds->use_coba) {
- GPU_create_smoke_coba_field(smd);
+ if (mds->use_coba) {
+ GPU_create_smoke_coba_field(mmd);
}
- else if (!sds->wt || !show_highres) {
- GPU_create_smoke(smd, 0);
+ else if (!(mds->flags & FLUID_DOMAIN_USE_NOISE)) {
+ GPU_create_smoke(mmd, 0);
}
- else if (sds->wt && show_highres) {
- GPU_create_smoke(smd, 1);
+ else if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ GPU_create_smoke(mmd, 1);
}
- if ((!sds->use_coba && sds->tex == NULL) || (sds->use_coba && sds->tex_field == NULL)) {
+ if ((!mds->use_coba && mds->tex == NULL) || (mds->use_coba && mds->tex_field == NULL)) {
return;
}
- const bool use_slice = (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
- sds->axis_slice_method == AXIS_SLICE_SINGLE);
- const bool cubic_interp = (sds->interp_method == VOLUME_INTERP_CUBIC);
- GPUShader *sh = volume_shader_get(use_slice, sds->use_coba, cubic_interp);
+ const bool use_slice = (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED &&
+ mds->axis_slice_method == AXIS_SLICE_SINGLE);
+ const bool cubic_interp = (mds->interp_method == VOLUME_INTERP_CUBIC);
+ GPUShader *sh = volume_shader_get(use_slice, mds->use_coba, cubic_interp);
if (use_slice) {
float invviewmat[4][4];
DRW_view_viewmat_get(NULL, invviewmat, true);
- const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ?
+ const int axis = (mds->slice_axis == SLICE_AXIS_AUTO) ?
axis_dominant_v3_single(invviewmat[2]) :
- sds->slice_axis - 1;
+ mds->slice_axis - 1;
float dim[3];
BKE_object_dimensions_get(ob, dim);
/* 0.05f to achieve somewhat the same opacity as the full view. */
float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
- DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
+ DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth);
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
DRW_shgroup_state_disable(grp, DRW_STATE_CULL_FRONT);
@@ -178,8 +177,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
double noise_ofs;
BLI_halton_1d(3, 0.0, effect_info->jitter_index, &noise_ofs);
float dim[3], step_length, max_slice;
- float slice_ct[3] = {sds->res[0], sds->res[1], sds->res[2]};
- mul_v3_fl(slice_ct, max_ff(0.001f, sds->slice_per_voxel));
+ float slice_ct[3] = {mds->res[0], mds->res[1], mds->res[2]};
+ mul_v3_fl(slice_ct, max_ff(0.001f, mds->slice_per_voxel));
max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]);
BKE_object_dimensions_get(ob, dim);
invert_v3(slice_ct);
@@ -194,25 +193,25 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
}
- if (sds->use_coba) {
- DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex_field);
- DRW_shgroup_uniform_texture(grp, "transferTexture", sds->tex_coba);
+ if (mds->use_coba) {
+ DRW_shgroup_uniform_texture(grp, "densityTexture", mds->tex_field);
+ DRW_shgroup_uniform_texture(grp, "transferTexture", mds->tex_coba);
}
else {
static float white[3] = {1.0f, 1.0f, 1.0f};
- bool use_constant_color = ((sds->active_fields & SM_ACTIVE_COLORS) == 0 &&
- (sds->active_fields & SM_ACTIVE_COLOR_SET) != 0);
- DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex);
- DRW_shgroup_uniform_texture(grp, "shadowTexture", sds->tex_shadow);
+ bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
+ (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
+ DRW_shgroup_uniform_texture(grp, "densityTexture", mds->tex);
+ DRW_shgroup_uniform_texture(grp, "shadowTexture", mds->tex_shadow);
DRW_shgroup_uniform_texture(
- grp, "flameTexture", (sds->tex_flame) ? sds->tex_flame : e_data.dummy_tex);
+ grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : e_data.dummy_tex);
DRW_shgroup_uniform_texture(
- grp, "flameColorTexture", (sds->tex_flame) ? sds->tex_flame_coba : e_data.dummy_coba_tex);
+ grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : e_data.dummy_coba_tex);
DRW_shgroup_uniform_vec3(
- grp, "activeColor", (use_constant_color) ? sds->active_color : white, 1);
+ grp, "activeColor", (use_constant_color) ? mds->active_color : white, 1);
}
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
- DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * sds->display_thickness);
+ DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * mds->display_thickness);
if (use_slice) {
DRW_shgroup_call(grp, DRW_cache_quad_get(), ob);
@@ -221,7 +220,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
DRW_shgroup_call(grp, DRW_cache_cube_get(), ob);
}
- BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(smd));
+ BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(mmd));
}
void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
@@ -233,8 +232,8 @@ void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
* modifier is not used for display. We should share them for
* all viewport in a redraw at least. */
for (LinkData *link = wpd->smoke_domains.first; link; link = link->next) {
- SmokeModifierData *smd = (SmokeModifierData *)link->data;
- GPU_free_smoke(smd);
+ FluidModifierData *mmd = (FluidModifierData *)link->data;
+ GPU_free_smoke(mmd);
}
BLI_freelistN(&wpd->smoke_domains);
}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 2c51eb8b7f8..8037bd03383 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -101,41 +101,6 @@ typedef char DRWViewportEmptyList;
DRW_VIEWPORT_LIST_SIZE(*(((ty *)NULL)->stl)), \
}
-/* Use of multisample framebuffers. */
-#define MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl) \
- { \
- if (dfbl->multisample_fb != NULL && DRW_state_is_fbo()) { \
- DRW_stats_query_start("Multisample Blit"); \
- GPU_framebuffer_bind(dfbl->multisample_fb); \
- /* TODO clear only depth but need to do alpha to coverage for transparencies. */ \
- GPU_framebuffer_clear_color_depth(dfbl->multisample_fb, (const float[4]){0.0f}, 1.0f); \
- DRW_stats_query_end(); \
- } \
- } \
- ((void)0)
-
-#define MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl) \
- { \
- if (dfbl->multisample_fb != NULL && DRW_state_is_fbo()) { \
- DRW_stats_query_start("Multisample Resolve"); \
- GPU_framebuffer_bind(dfbl->default_fb); \
- DRW_multisamples_resolve(dtxl->multisample_depth, dtxl->multisample_color, true); \
- DRW_stats_query_end(); \
- } \
- } \
- ((void)0)
-
-#define MULTISAMPLE_SYNC_DISABLE_NO_DEPTH(dfbl, dtxl) \
- { \
- if (dfbl->multisample_fb != NULL && DRW_state_is_fbo()) { \
- DRW_stats_query_start("Multisample Resolve"); \
- GPU_framebuffer_bind(dfbl->default_fb); \
- DRW_multisamples_resolve(dtxl->multisample_depth, dtxl->multisample_color, false); \
- DRW_stats_query_end(); \
- } \
- } \
- ((void)0)
-
typedef struct DrawEngineDataSize {
int fbl_len;
int txl_len;
@@ -173,16 +138,15 @@ typedef struct DrawEngineType {
/* Buffer and textures used by the viewport by default */
typedef struct DefaultFramebufferList {
struct GPUFrameBuffer *default_fb;
+ struct GPUFrameBuffer *in_front_fb;
struct GPUFrameBuffer *color_only_fb;
struct GPUFrameBuffer *depth_only_fb;
- struct GPUFrameBuffer *multisample_fb;
} DefaultFramebufferList;
typedef struct DefaultTextureList {
struct GPUTexture *color;
struct GPUTexture *depth;
- struct GPUTexture *multisample_color;
- struct GPUTexture *multisample_depth;
+ struct GPUTexture *depth_in_front;
} DefaultTextureList;
#endif
@@ -344,9 +308,11 @@ typedef enum {
/** Use dual source blending. WARNING: Only one color buffer allowed. */
DRW_STATE_BLEND_CUSTOM = (1 << 23),
+ DRW_STATE_IN_FRONT_SELECT = (1 << 25),
+ DRW_STATE_LOGIC_INVERT = (1 << 26),
DRW_STATE_SHADOW_OFFSET = (1 << 27),
DRW_STATE_CLIP_PLANES = (1 << 28),
- DRW_STATE_WIRE_SMOOTH = (1 << 29),
+ // DRW_STATE_WIRE_SMOOTH = (1 << 29), /* UNUSED */
DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 30),
/** DO NOT USE. Assumed always enabled. Only used internally. */
DRW_STATE_PROGRAM_POINT_SIZE = (1u << 31),
@@ -429,11 +395,12 @@ void DRW_shgroup_call_range(DRWShadingGroup *shgroup,
void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_ct);
void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_ct);
void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, Object *ob, uint tri_ct);
-
+/* Warning: Only use with Shaders that have IN_PLACE_INSTANCES defined. */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
uint count);
+/* Warning: Only use with Shaders that have INSTANCED_ATTRIB defined. */
void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
@@ -449,6 +416,7 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shading_group,
struct GPUVertFormat *format,
struct GPUBatch *geom);
+void DRW_buffer_add_entry_struct(DRWCallBuffer *callbuf, const void *data);
void DRW_buffer_add_entry_array(DRWCallBuffer *buffer, const void *attr[], uint attr_len);
#define DRW_buffer_add_entry(buffer, ...) \
@@ -548,6 +516,7 @@ void DRW_pass_foreach_shgroup(DRWPass *pass,
void (*callback)(void *userData, DRWShadingGroup *shgrp),
void *userData);
void DRW_pass_sort_shgroup_z(DRWPass *pass);
+void DRW_pass_sort_shgroup_reverse(DRWPass *pass);
bool DRW_pass_is_empty(DRWPass *pass);
diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c
deleted file mode 100644
index 7e0110cbb99..00000000000
--- a/source/blender/draw/intern/draw_anim_viz.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2009/2018 by the Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "BLI_sys_types.h"
-
-#include "DNA_armature_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_math.h"
-
-#include "UI_resources.h"
-
-#include "DEG_depsgraph_query.h"
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
-#include "GPU_shader.h"
-#include "GPU_immediate.h"
-
-#include "draw_common.h"
-#include "draw_manager_text.h"
-
-#include "draw_mode_engines.h"
-
-/* ********************************* Lists ************************************** */
-/* All lists are per viewport specific datas.
- * They are all free when viewport changes engines
- * or is free itself.
- */
-
-/* XXX: How to show frame numbers, etc.? Currently only doing the dots and lines */
-typedef struct MPATH_PassList {
- struct DRWPass *lines;
- struct DRWPass *points;
-} MPATH_PassList;
-
-typedef struct MPATH_StorageList {
- struct MPATH_PrivateData *g_data;
-} MPATH_StorageList;
-
-typedef struct MPATH_Data {
- void *engine_type;
- DRWViewportEmptyList *fbl;
- DRWViewportEmptyList *txl;
- MPATH_PassList *psl;
- MPATH_StorageList *stl;
-} MPATH_Data;
-
-#if 0
-static struct {
- GPUShader *mpath_line_sh;
- GPUShader *mpath_points_sh;
-} e_data = {0};
-#endif
-
-/* *************************** Path Cache *********************************** */
-
-/* Just convert the CPU cache to GPU cache. */
-static GPUVertBuf *mpath_vbo_get(bMotionPath *mpath)
-{
- if (!mpath->points_vbo) {
- GPUVertFormat format = {0};
- /* Match structure of bMotionPathVert. */
- uint pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- GPU_vertformat_attr_add(&format, "flag", GPU_COMP_I32, 1, GPU_FETCH_INT);
- mpath->points_vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(mpath->points_vbo, mpath->length);
-
- /* meh... a useless memcpy. */
- GPUVertBufRaw raw_data;
- GPU_vertbuf_attr_get_raw_data(mpath->points_vbo, pos, &raw_data);
- memcpy(
- GPU_vertbuf_raw_step(&raw_data), mpath->points, sizeof(bMotionPathVert) * mpath->length);
- }
- return mpath->points_vbo;
-}
-
-static GPUBatch *mpath_batch_line_get(bMotionPath *mpath)
-{
- if (!mpath->batch_line) {
- mpath->batch_line = GPU_batch_create(GPU_PRIM_LINE_STRIP, mpath_vbo_get(mpath), NULL);
- }
- return mpath->batch_line;
-}
-
-static GPUBatch *mpath_batch_points_get(bMotionPath *mpath)
-{
- if (!mpath->batch_points) {
- mpath->batch_points = GPU_batch_create(GPU_PRIM_POINTS, mpath_vbo_get(mpath), NULL);
- }
- return mpath->batch_points;
-}
-
-/* *************************** Draw Engine Entrypoints ************************** */
-
-static void MPATH_engine_init(void *UNUSED(vedata))
-{
-}
-
-static void MPATH_engine_free(void)
-{
-}
-
-/* Here init all passes and shading groups
- * Assume that all Passes are NULL */
-static void MPATH_cache_init(void *vedata)
-{
- MPATH_PassList *psl = ((MPATH_Data *)vedata)->psl;
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR;
- psl->lines = DRW_pass_create("Motionpath Line Pass", state);
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR;
- psl->points = DRW_pass_create("Motionpath Point Pass", state);
- }
-}
-
-static void MPATH_get_frame_range_to_draw(bAnimVizSettings *avs,
- bMotionPath *mpath,
- int current_frame,
- int *r_start,
- int *r_end,
- int *r_step)
-{
- int start, end;
-
- if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
- start = current_frame - avs->path_bc;
- end = current_frame + avs->path_ac + 1;
- }
- else {
- start = avs->path_sf;
- end = avs->path_ef;
- }
-
- if (start > end) {
- SWAP(int, start, end);
- }
-
- CLAMP(start, mpath->start_frame, mpath->end_frame);
- CLAMP(end, mpath->start_frame, mpath->end_frame);
-
- *r_start = start;
- *r_end = end;
- *r_step = max_ii(avs->path_step, 1);
-}
-
-static void MPATH_cache_motion_path(MPATH_PassList *psl,
- Object *ob,
- bPoseChannel *pchan,
- bAnimVizSettings *avs,
- bMotionPath *mpath)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- struct DRWTextStore *dt = DRW_text_cache_ensure();
- int txt_flag = DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_ASCII;
- int cfra = (int)DEG_get_ctime(draw_ctx->depsgraph);
- bool sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->base_flag & BASE_SELECTED);
- bool show_keyframes = (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) != 0;
-
- int sfra, efra, stepsize;
- MPATH_get_frame_range_to_draw(avs, mpath, cfra, &sfra, &efra, &stepsize);
-
- int len = efra - sfra;
- if (len == 0) {
- return;
- }
- int start_index = sfra - mpath->start_frame;
-
- bool use_custom_col = (mpath->flag & MOTIONPATH_FLAG_CUSTOM) != 0;
-
- /* draw curve-line of path */
- /* Draw lines only if line drawing option is enabled */
- if (mpath->flag & MOTIONPATH_FLAG_LINES) {
- DRWShadingGroup *shgrp = DRW_shgroup_create(mpath_line_shader_get(), psl->lines);
- DRW_shgroup_uniform_int_copy(shgrp, "frameCurrent", cfra);
- DRW_shgroup_uniform_int_copy(shgrp, "frameStart", sfra);
- DRW_shgroup_uniform_int_copy(shgrp, "frameEnd", efra);
- DRW_shgroup_uniform_int_copy(shgrp, "cacheStart", mpath->start_frame);
- DRW_shgroup_uniform_int_copy(shgrp, "lineThickness", mpath->line_thickness);
- DRW_shgroup_uniform_bool_copy(shgrp, "selected", sel);
- DRW_shgroup_uniform_bool_copy(shgrp, "useCustomColor", use_custom_col);
- DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo);
- if (use_custom_col) {
- DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
- }
- /* Only draw the required range. */
- DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), start_index, len);
- }
-
- /* Draw points. */
- DRWShadingGroup *shgrp = DRW_shgroup_create(mpath_points_shader_get(), psl->points);
- DRW_shgroup_uniform_int_copy(shgrp, "frameCurrent", cfra);
- DRW_shgroup_uniform_int_copy(shgrp, "cacheStart", mpath->start_frame);
- DRW_shgroup_uniform_int_copy(shgrp, "pointSize", max_ii(mpath->line_thickness - 1, 1));
- DRW_shgroup_uniform_int_copy(shgrp, "stepSize", stepsize);
- DRW_shgroup_uniform_bool_copy(shgrp, "showKeyFrames", show_keyframes);
- DRW_shgroup_uniform_bool_copy(shgrp, "useCustomColor", use_custom_col);
- DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo);
- if (use_custom_col) {
- DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
- }
- /* Only draw the required range. */
- DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), start_index, len);
-
- /* Draw frame numbers at each framestep value */
- bool show_kf_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
- if ((avs->path_viewflag & (MOTIONPATH_VIEW_FNUMS)) || (show_kf_no && show_keyframes)) {
- int i;
- uchar col[4], col_kf[4];
- UI_GetThemeColor3ubv(TH_TEXT_HI, col);
- UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col_kf);
- col[3] = col_kf[3] = 255;
-
- bMotionPathVert *mpv;
- bMotionPathVert *mpv_start = mpath->points + start_index;
- for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) {
- int frame = sfra + i;
- char numstr[32];
- size_t numstr_len;
- bool is_keyframe = (mpv->flag & MOTIONPATH_VERT_KEY) != 0;
-
- if ((show_keyframes && show_kf_no && is_keyframe) ||
- ((avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) && (i == 0))) {
- numstr_len = sprintf(numstr, " %d", frame);
- DRW_text_cache_add(
- dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, (is_keyframe) ? col_kf : col);
- }
- else if (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) {
- bMotionPathVert *mpvP = (mpv - stepsize);
- bMotionPathVert *mpvN = (mpv + stepsize);
- /* only draw framenum if several consecutive highlighted points don't occur on same point
- */
- if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) {
- numstr_len = sprintf(numstr, " %d", frame);
- DRW_text_cache_add(dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, col);
- }
- }
- }
- }
-}
-
-/* Add geometry to shading groups. Execute for each objects */
-static void MPATH_cache_populate(void *vedata, Object *ob)
-{
- MPATH_PassList *psl = ((MPATH_Data *)vedata)->psl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- if (draw_ctx->v3d->overlay.flag & V3D_OVERLAY_HIDE_MOTION_PATHS) {
- return;
- }
-
- if (ob->type == OB_ARMATURE) {
- if (DRW_pose_mode_armature(ob, draw_ctx->obact)) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->mpath) {
- MPATH_cache_motion_path(psl, ob, pchan, &ob->pose->avs, pchan->mpath);
- }
- }
- }
- }
-
- if (ob->mpath) {
- MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath);
- }
-}
-
-/* Draw time! Control rendering pipeline from here */
-static void MPATH_draw_scene(void *vedata)
-{
- MPATH_PassList *psl = ((MPATH_Data *)vedata)->psl;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- if (DRW_pass_is_empty(psl->lines) && DRW_pass_is_empty(psl->points)) {
- /* Nothing to draw. */
- return;
- }
-
- MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
-
- DRW_draw_pass(psl->lines);
- DRW_draw_pass(psl->points);
-
- MULTISAMPLE_SYNC_DISABLE_NO_DEPTH(dfbl, dtxl);
-}
-
-/* *************************** Draw Engine Defines ****************************** */
-
-static const DrawEngineDataSize MPATH_data_size = DRW_VIEWPORT_DATA_SIZE(MPATH_Data);
-
-DrawEngineType draw_engine_motion_path_type = {
- NULL,
- NULL,
- N_("MotionPath"),
- &MPATH_data_size,
- &MPATH_engine_init,
- &MPATH_engine_free,
- &MPATH_cache_init,
- &MPATH_cache_populate,
- NULL,
- NULL,
- &MPATH_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
deleted file mode 100644
index e16dfb5004b..00000000000
--- a/source/blender/draw/intern/draw_armature.c
+++ /dev/null
@@ -1,2168 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_object_types.h"
-
-#include "DRW_render.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_armature.h"
-
-#include "DEG_depsgraph_query.h"
-
-#include "ED_armature.h"
-
-#include "UI_resources.h"
-
-#include "draw_common.h"
-#include "draw_manager_text.h"
-
-#define BONE_VAR(eBone, pchan, var) ((eBone) ? (eBone->var) : (pchan->var))
-#define BONE_FLAG(eBone, pchan) ((eBone) ? (eBone->flag) : (pchan->bone->flag))
-
-#define PT_DEFAULT_RAD 0.05f /* radius of the point batch. */
-
-/* For now just match 2.7x where possible. */
-// #define USE_SOLID_COLOR
-
-/* Reset for drawing each armature object */
-static struct {
- /* Current armature object */
- Object *ob;
- /* Reset when changing current_armature */
- DRWCallBuffer *bone_octahedral_solid;
- DRWCallBuffer *bone_octahedral_outline;
- DRWCallBuffer *bone_box_solid;
- DRWCallBuffer *bone_box_wire;
- DRWCallBuffer *bone_box_outline;
- DRWCallBuffer *bone_wire;
- DRWCallBuffer *bone_stick;
- DRWCallBuffer *bone_dof_sphere;
- DRWCallBuffer *bone_dof_lines;
- DRWCallBuffer *bone_envelope_solid;
- DRWCallBuffer *bone_envelope_distance;
- DRWCallBuffer *bone_envelope_wire;
- DRWCallBuffer *bone_point_solid;
- DRWCallBuffer *bone_point_wire;
- DRWCallBuffer *bone_axes;
- DRWCallBuffer *lines_relationship;
- DRWCallBuffer *lines_ik;
- DRWCallBuffer *lines_ik_no_target;
- DRWCallBuffer *lines_ik_spline;
-
- DRWEmptiesBufferList empties;
-
- DRWArmaturePasses passes;
-
- bool transparent;
-} g_data = {NULL};
-
-/**
- * Follow `TH_*` naming except for mixed colors.
- */
-static struct {
- float select_color[4];
- float edge_select_color[4];
- float bone_select_color[4]; /* tint */
- float wire_color[4];
- float wire_edit_color[4];
- float bone_solid_color[4];
- float bone_active_unselect_color[4]; /* mix */
- float bone_pose_color[4];
- float bone_pose_active_color[4];
- float bone_pose_active_unselect_color[4]; /* mix */
- float text_hi_color[4];
- float text_color[4];
- float vertex_select_color[4];
- float vertex_color[4];
-
- /* not a theme, this is an override */
- const float *const_color;
- float const_wire;
-} g_theme;
-
-/* -------------------------------------------------------------------- */
-/** \name Shader Groups (DRW_shgroup)
- * \{ */
-
-/* Octahedral */
-static void drw_shgroup_bone_octahedral(const float (*bone_mat)[4],
- const float bone_color[4],
- const float hint_color[4],
- const float outline_color[4],
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.bone_octahedral_outline == NULL) {
- struct GPUBatch *geom = DRW_cache_bone_octahedral_wire_get();
- g_data.bone_octahedral_outline = buffer_instance_bone_shape_outline(
- g_data.passes.bone_outline, geom, sh_cfg);
- }
- if (g_data.bone_octahedral_solid == NULL && g_data.passes.bone_solid != NULL) {
- struct GPUBatch *geom = DRW_cache_bone_octahedral_get();
- g_data.bone_octahedral_solid = buffer_instance_bone_shape_solid(
- g_data.passes.bone_solid, geom, g_data.transparent, sh_cfg);
- }
- float final_bonemat[4][4];
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- if (g_data.bone_octahedral_solid != NULL) {
- DRW_buffer_add_entry(g_data.bone_octahedral_solid, final_bonemat, bone_color, hint_color);
- }
- if (outline_color[3] > 0.0f) {
- DRW_buffer_add_entry(g_data.bone_octahedral_outline, final_bonemat, outline_color);
- }
-}
-
-/* Box / B-Bone */
-static void drw_shgroup_bone_box(const float (*bone_mat)[4],
- const float bone_color[4],
- const float hint_color[4],
- const float outline_color[4],
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.bone_box_wire == NULL) {
- struct GPUBatch *geom = DRW_cache_bone_box_wire_get();
- g_data.bone_box_outline = buffer_instance_bone_shape_outline(
- g_data.passes.bone_outline, geom, sh_cfg);
- }
- if (g_data.bone_box_solid == NULL && g_data.passes.bone_solid != NULL) {
- struct GPUBatch *geom = DRW_cache_bone_box_get();
- g_data.bone_box_solid = buffer_instance_bone_shape_solid(
- g_data.passes.bone_solid, geom, g_data.transparent, sh_cfg);
- }
- float final_bonemat[4][4];
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- if (g_data.bone_box_solid != NULL) {
- DRW_buffer_add_entry(g_data.bone_box_solid, final_bonemat, bone_color, hint_color);
- }
- if (outline_color[3] > 0.0f) {
- DRW_buffer_add_entry(g_data.bone_box_outline, final_bonemat, outline_color);
- }
-}
-
-/* Wire */
-static void drw_shgroup_bone_wire(const float (*bone_mat)[4],
- const float color[4],
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.bone_wire == NULL) {
- g_data.bone_wire = buffer_dynlines_flat_color(g_data.passes.bone_wire, sh_cfg);
- }
- float head[3], tail[3];
- mul_v3_m4v3(head, g_data.ob->obmat, bone_mat[3]);
- DRW_buffer_add_entry(g_data.bone_wire, head, color);
-
- add_v3_v3v3(tail, bone_mat[3], bone_mat[1]);
- mul_m4_v3(g_data.ob->obmat, tail);
- DRW_buffer_add_entry(g_data.bone_wire, tail, color);
-}
-
-/* Stick */
-static void drw_shgroup_bone_stick(const float (*bone_mat)[4],
- const float col_wire[4],
- const float col_bone[4],
- const float col_head[4],
- const float col_tail[4],
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.bone_stick == NULL) {
- g_data.bone_stick = buffer_instance_bone_stick(g_data.passes.bone_wire, sh_cfg);
- }
- float final_bonemat[4][4], tail[4];
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- add_v3_v3v3(tail, final_bonemat[3], final_bonemat[1]);
- DRW_buffer_add_entry(
- g_data.bone_stick, final_bonemat[3], tail, col_wire, col_bone, col_head, col_tail);
-}
-
-/* Envelope */
-static void drw_shgroup_bone_envelope_distance(const float (*bone_mat)[4],
- const float *radius_head,
- const float *radius_tail,
- const float *distance,
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.passes.bone_envelope != NULL) {
- if (g_data.bone_envelope_distance == NULL) {
- g_data.bone_envelope_distance = buffer_instance_bone_envelope_distance(
- g_data.passes.bone_envelope, sh_cfg);
- /* passes.bone_envelope should have the DRW_STATE_CULL_FRONT state enabled. */
- }
- float head_sphere[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sphere[4] = {0.0f, 1.0f, 0.0f, 1.0f};
- float final_bonemat[4][4];
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- /* We need matrix mul because we need shear applied. */
- /* NOTE: could be done in shader if that becomes a bottleneck. */
- mul_m4_v4(final_bonemat, head_sphere);
- mul_m4_v4(final_bonemat, tail_sphere);
- head_sphere[3] = *radius_head;
- head_sphere[3] += *distance;
- tail_sphere[3] = *radius_tail;
- tail_sphere[3] += *distance;
- DRW_buffer_add_entry(
- g_data.bone_envelope_distance, head_sphere, tail_sphere, final_bonemat[0]);
- }
-}
-
-static void drw_shgroup_bone_envelope(const float (*bone_mat)[4],
- const float bone_color[4],
- const float hint_color[4],
- const float outline_color[4],
- const float *radius_head,
- const float *radius_tail,
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.bone_point_wire == NULL) {
- g_data.bone_point_wire = buffer_instance_bone_sphere_outline(g_data.passes.bone_wire, sh_cfg);
- }
- if (g_data.bone_point_solid == NULL && g_data.passes.bone_solid != NULL) {
- g_data.bone_point_solid = buffer_instance_bone_sphere_solid(
- g_data.passes.bone_solid, g_data.transparent, sh_cfg);
- }
- if (g_data.bone_envelope_wire == NULL) {
- g_data.bone_envelope_wire = buffer_instance_bone_envelope_outline(g_data.passes.bone_wire,
- sh_cfg);
- }
- if (g_data.bone_envelope_solid == NULL && g_data.passes.bone_solid != NULL) {
- g_data.bone_envelope_solid = buffer_instance_bone_envelope_solid(
- g_data.passes.bone_solid, g_data.transparent, sh_cfg);
- }
-
- float head_sphere[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sphere[4] = {0.0f, 1.0f, 0.0f, 1.0f};
- float final_bonemat[4][4];
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- mul_m4_v4(final_bonemat, head_sphere);
- mul_m4_v4(final_bonemat, tail_sphere);
- head_sphere[3] = *radius_head;
- tail_sphere[3] = *radius_tail;
-
- if (head_sphere[3] < 0.0f) {
- /* Draw Tail only */
- float tmp[4][4] = {{0.0f}};
- tmp[0][0] = tmp[1][1] = tmp[2][2] = tail_sphere[3] / PT_DEFAULT_RAD;
- tmp[3][3] = 1.0f;
- copy_v3_v3(tmp[3], tail_sphere);
- if (g_data.bone_point_solid != NULL) {
- DRW_buffer_add_entry(g_data.bone_point_solid, tmp, bone_color, hint_color);
- }
- if (outline_color[3] > 0.0f) {
- DRW_buffer_add_entry(g_data.bone_point_wire, tmp, outline_color);
- }
- }
- else if (tail_sphere[3] < 0.0f) {
- /* Draw Head only */
- float tmp[4][4] = {{0.0f}};
- tmp[0][0] = tmp[1][1] = tmp[2][2] = head_sphere[3] / PT_DEFAULT_RAD;
- tmp[3][3] = 1.0f;
- copy_v3_v3(tmp[3], head_sphere);
- if (g_data.bone_point_solid != NULL) {
- DRW_buffer_add_entry(g_data.bone_point_solid, tmp, bone_color, hint_color);
- }
- if (outline_color[3] > 0.0f) {
- DRW_buffer_add_entry(g_data.bone_point_wire, tmp, outline_color);
- }
- }
- else {
- /* Draw Body */
- float tmp_sphere[4];
- float len = len_v3v3(tail_sphere, head_sphere);
- float fac_head = (len - head_sphere[3]) / len;
- float fac_tail = (len - tail_sphere[3]) / len;
-
- /* Small epsilon to avoid problem with float precision in shader. */
- if (len > (tail_sphere[3] + head_sphere[3]) + 1e-8f) {
-
- copy_v4_v4(tmp_sphere, head_sphere);
- interp_v4_v4v4(head_sphere, tail_sphere, head_sphere, fac_head);
- interp_v4_v4v4(tail_sphere, tmp_sphere, tail_sphere, fac_tail);
- if (g_data.bone_envelope_solid != NULL) {
- DRW_buffer_add_entry(g_data.bone_envelope_solid,
- head_sphere,
- tail_sphere,
- bone_color,
- hint_color,
- final_bonemat[0]);
- }
- if (outline_color[3] > 0.0f) {
- DRW_buffer_add_entry(
- g_data.bone_envelope_wire, head_sphere, tail_sphere, outline_color, final_bonemat[0]);
- }
- }
- else {
- float tmp[4][4] = {{0.0f}};
- float fac = max_ff(fac_head, 1.0f - fac_tail);
- interp_v4_v4v4(tmp_sphere, tail_sphere, head_sphere, clamp_f(fac, 0.0f, 1.0f));
- tmp[0][0] = tmp[1][1] = tmp[2][2] = tmp_sphere[3] / PT_DEFAULT_RAD;
- tmp[3][3] = 1.0f;
- copy_v3_v3(tmp[3], tmp_sphere);
- if (g_data.bone_point_solid != NULL) {
- DRW_buffer_add_entry(g_data.bone_point_solid, tmp, bone_color, hint_color);
- }
- if (outline_color[3] > 0.0f) {
- DRW_buffer_add_entry(g_data.bone_point_wire, tmp, outline_color);
- }
- }
- }
-}
-
-/* Custom (geometry) */
-
-extern void drw_batch_cache_validate(Object *custom);
-extern void drw_batch_cache_generate_requested(Object *custom);
-
-static void drw_shgroup_bone_custom_solid(const float (*bone_mat)[4],
- const float bone_color[4],
- const float hint_color[4],
- const float outline_color[4],
- const eGPUShaderConfig sh_cfg,
- Object *custom)
-{
- /* TODO(fclem) arg... less than ideal but we never iter on this object
- * to assure batch cache is valid. */
- drw_batch_cache_validate(custom);
-
- struct GPUBatch *surf = DRW_cache_object_surface_get(custom);
- struct GPUBatch *edges = DRW_cache_object_edge_detection_get(custom, NULL);
- struct GPUBatch *ledges = DRW_cache_object_loose_edges_get(custom);
- float final_bonemat[4][4];
-
- if (surf || edges || ledges) {
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- }
-
- BLI_assert(g_data.passes.custom_shapes != NULL);
-
- if (surf && g_data.passes.bone_solid != NULL) {
- DRWCallBuffer *buf_geom_solid = BLI_ghash_lookup(g_data.passes.custom_shapes, surf);
-
- if (buf_geom_solid == NULL) {
- /* TODO(fclem) needs to be moved elsewhere. */
- drw_batch_cache_generate_requested(custom);
-
- /* NOTE! g_data.transparent require a separate shading group if the
- * object is transparent. This is done by passing a different ghash
- * for transparent armature in pose mode. */
- buf_geom_solid = buffer_instance_bone_shape_solid(
- g_data.passes.bone_solid, surf, g_data.transparent, sh_cfg);
- BLI_ghash_insert(g_data.passes.custom_shapes, surf, buf_geom_solid);
- }
- DRW_buffer_add_entry(buf_geom_solid, final_bonemat, bone_color, hint_color);
- }
-
- if (edges && outline_color[3] > 0.0f) {
- DRWCallBuffer *buf_geom_wire = BLI_ghash_lookup(g_data.passes.custom_shapes, edges);
-
- if (buf_geom_wire == NULL) {
- /* TODO(fclem) needs to be moved elsewhere. */
- drw_batch_cache_generate_requested(custom);
-
- buf_geom_wire = buffer_instance_bone_shape_outline(
- g_data.passes.bone_outline, edges, sh_cfg);
-
- BLI_ghash_insert(g_data.passes.custom_shapes, edges, buf_geom_wire);
- }
- DRW_buffer_add_entry(buf_geom_wire, final_bonemat, outline_color);
- }
-
- if (ledges) {
- DRWCallBuffer *buf_geom_ledges = BLI_ghash_lookup(g_data.passes.custom_shapes, ledges);
-
- if (buf_geom_ledges == NULL) {
- /* TODO(fclem) needs to be moved elsewhere. */
- drw_batch_cache_generate_requested(custom);
-
- buf_geom_ledges = buffer_instance_wire(g_data.passes.bone_wire, ledges);
-
- BLI_ghash_insert(g_data.passes.custom_shapes, ledges, buf_geom_ledges);
- }
- float final_color[4] = {outline_color[0], outline_color[1], outline_color[2], 1.0f};
- DRW_buffer_add_entry(buf_geom_ledges, final_bonemat, final_color);
- }
-}
-
-static void drw_shgroup_bone_custom_wire(const float (*bone_mat)[4],
- const float color[4],
- Object *custom)
-{
- /* TODO(fclem) arg... less than ideal but we never iter on this object
- * to assure batch cache is valid. */
- drw_batch_cache_validate(custom);
-
- struct GPUBatch *geom = DRW_cache_object_all_edges_get(custom);
-
- if (geom) {
- DRWCallBuffer *buf_geom_wire = BLI_ghash_lookup(g_data.passes.custom_shapes, geom);
-
- if (buf_geom_wire == NULL) {
- /* TODO(fclem) needs to be moved elsewhere. */
- drw_batch_cache_generate_requested(custom);
-
- buf_geom_wire = buffer_instance_wire(g_data.passes.bone_wire, geom);
-
- BLI_ghash_insert(g_data.passes.custom_shapes, geom, buf_geom_wire);
- }
- float final_color[4] = {color[0], color[1], color[2], 1.0f};
- float final_bonemat[4][4];
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- DRW_buffer_add_entry(buf_geom_wire, final_bonemat, final_color);
- }
-}
-
-static void drw_shgroup_bone_custom_empty(const float (*bone_mat)[4],
- const float color[4],
- const eGPUShaderConfig sh_cfg,
- Object *custom)
-{
- DRWEmptiesBufferList *buffers = &g_data.empties;
- const float *draw_size = &custom->empty_drawsize;
-
- if (g_data.empties.plain_axes == NULL) {
- empties_callbuffers_create(g_data.passes.bone_wire, buffers, sh_cfg);
- }
-
- float final_color[4] = {color[0], color[1], color[2], 1.0f};
- float final_bonemat[4][4];
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
-
- switch (custom->empty_drawtype) {
- case OB_PLAINAXES:
- DRW_buffer_add_entry(buffers->plain_axes, final_color, draw_size, final_bonemat);
- break;
- case OB_SINGLE_ARROW:
- DRW_buffer_add_entry(buffers->single_arrow, final_color, draw_size, final_bonemat);
- DRW_buffer_add_entry(buffers->single_arrow_line, final_color, draw_size, final_bonemat);
- break;
- case OB_CUBE:
- DRW_buffer_add_entry(buffers->cube, final_color, draw_size, final_bonemat);
- break;
- case OB_CIRCLE:
- DRW_buffer_add_entry(buffers->circle, final_color, draw_size, final_bonemat);
- break;
- case OB_EMPTY_SPHERE:
- DRW_buffer_add_entry(buffers->sphere, final_color, draw_size, final_bonemat);
- break;
- case OB_EMPTY_CONE:
- DRW_buffer_add_entry(buffers->cone, final_color, draw_size, final_bonemat);
- break;
- case OB_ARROWS:
- DRW_buffer_add_entry(buffers->empty_axes, final_color, draw_size, final_bonemat);
- break;
- case OB_EMPTY_IMAGE:
- break;
- }
-}
-
-/* Head and tail sphere */
-static void drw_shgroup_bone_point(const float (*bone_mat)[4],
- const float bone_color[4],
- const float hint_color[4],
- const float outline_color[4],
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.bone_point_wire == NULL) {
- g_data.bone_point_wire = buffer_instance_bone_sphere_outline(g_data.passes.bone_wire, sh_cfg);
- }
- if (g_data.bone_point_solid == NULL && g_data.passes.bone_solid != NULL) {
- g_data.bone_point_solid = buffer_instance_bone_sphere_solid(
- g_data.passes.bone_solid, g_data.transparent, sh_cfg);
- }
- float final_bonemat[4][4];
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- if (g_data.bone_point_solid != NULL) {
- DRW_buffer_add_entry(g_data.bone_point_solid, final_bonemat, bone_color, hint_color);
- }
- if (outline_color[3] > 0.0f) {
- DRW_buffer_add_entry(g_data.bone_point_wire, final_bonemat, outline_color);
- }
-}
-
-/* Axes */
-static void drw_shgroup_bone_axes(const float (*bone_mat)[4],
- const float color[4],
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.bone_axes == NULL) {
- g_data.bone_axes = buffer_instance_bone_axes(g_data.passes.bone_axes, sh_cfg);
- }
- float final_bonemat[4][4];
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- DRW_buffer_add_entry(g_data.bone_axes, final_bonemat, color);
-}
-
-/* Relationship lines */
-static void drw_shgroup_bone_relationship_lines(const float start[3],
- const float end[3],
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.lines_relationship == NULL) {
- g_data.lines_relationship = buffer_dynlines_dashed_uniform_color(
- g_data.passes.relationship_lines, g_theme.wire_color, sh_cfg);
- }
- /* reverse order to have less stipple overlap */
- float v[3];
- mul_v3_m4v3(v, g_data.ob->obmat, end);
- DRW_buffer_add_entry(g_data.lines_relationship, v);
- mul_v3_m4v3(v, g_data.ob->obmat, start);
- DRW_buffer_add_entry(g_data.lines_relationship, v);
-}
-
-static void drw_shgroup_bone_ik_lines(const float start[3],
- const float end[3],
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.lines_ik == NULL) {
- static float fcolor[4] = {0.8f, 0.5f, 0.0f, 1.0f}; /* add theme! */
- g_data.lines_ik = buffer_dynlines_dashed_uniform_color(
- g_data.passes.relationship_lines, fcolor, sh_cfg);
- }
- /* reverse order to have less stipple overlap */
- float v[3];
- mul_v3_m4v3(v, g_data.ob->obmat, end);
- DRW_buffer_add_entry(g_data.lines_ik, v);
- mul_v3_m4v3(v, g_data.ob->obmat, start);
- DRW_buffer_add_entry(g_data.lines_ik, v);
-}
-
-static void drw_shgroup_bone_ik_no_target_lines(const float start[3],
- const float end[3],
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.lines_ik_no_target == NULL) {
- static float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */
- g_data.lines_ik_no_target = buffer_dynlines_dashed_uniform_color(
- g_data.passes.relationship_lines, fcolor, sh_cfg);
- }
- /* reverse order to have less stipple overlap */
- float v[3];
- mul_v3_m4v3(v, g_data.ob->obmat, end);
- DRW_buffer_add_entry(g_data.lines_ik_no_target, v);
- mul_v3_m4v3(v, g_data.ob->obmat, start);
- DRW_buffer_add_entry(g_data.lines_ik_no_target, v);
-}
-
-static void drw_shgroup_bone_ik_spline_lines(const float start[3],
- const float end[3],
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.lines_ik_spline == NULL) {
- static float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */
- g_data.lines_ik_spline = buffer_dynlines_dashed_uniform_color(
- g_data.passes.relationship_lines, fcolor, sh_cfg);
- }
- /* reverse order to have less stipple overlap */
- float v[3];
- mul_v3_m4v3(v, g_data.ob->obmat, end);
- DRW_buffer_add_entry(g_data.lines_ik_spline, v);
- mul_v3_m4v3(v, g_data.ob->obmat, start);
- DRW_buffer_add_entry(g_data.lines_ik_spline, v);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Drawing Theme Helpers
- *
- * Note, this section is duplicate of code in 'drawarmature.c'.
- *
- * \{ */
-
-/* global here is reset before drawing each bone */
-static struct {
- const ThemeWireColor *bcolor;
-} g_color;
-
-/* values of colCode for set_pchan_color */
-enum {
- PCHAN_COLOR_NORMAL = 0, /* normal drawing */
- PCHAN_COLOR_SOLID, /* specific case where "solid" color is needed */
- PCHAN_COLOR_CONSTS, /* "constraint" colors (which may/may-not be suppressed) */
-
- PCHAN_COLOR_SPHEREBONE_BASE, /* for the 'stick' of sphere (envelope) bones */
- PCHAN_COLOR_SPHEREBONE_END, /* for the ends of sphere (envelope) bones */
- PCHAN_COLOR_LINEBONE, /* for the middle of line-bones */
-};
-
-/* This function sets the color-set for coloring a certain bone */
-static void set_pchan_colorset(Object *ob, bPoseChannel *pchan)
-{
- bPose *pose = (ob) ? ob->pose : NULL;
- bArmature *arm = (ob) ? ob->data : NULL;
- bActionGroup *grp = NULL;
- short color_index = 0;
-
- /* sanity check */
- if (ELEM(NULL, ob, arm, pose, pchan)) {
- g_color.bcolor = NULL;
- return;
- }
-
- /* only try to set custom color if enabled for armature */
- if (arm->flag & ARM_COL_CUSTOM) {
- /* currently, a bone can only use a custom color set if it's group (if it has one),
- * has been set to use one
- */
- if (pchan->agrp_index) {
- grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1));
- if (grp) {
- color_index = grp->customCol;
- }
- }
- }
-
- /* bcolor is a pointer to the color set to use. If NULL, then the default
- * color set (based on the theme colors for 3d-view) is used.
- */
- if (color_index > 0) {
- bTheme *btheme = UI_GetTheme();
- g_color.bcolor = &btheme->tarm[(color_index - 1)];
- }
- else if (color_index == -1) {
- /* use the group's own custom color set (grp is always != NULL here) */
- g_color.bcolor = &grp->cs;
- }
- else {
- g_color.bcolor = NULL;
- }
-}
-
-/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */
-static void cp_shade_color3ub(uchar cp[3], const int offset)
-{
- int r, g, b;
-
- r = offset + (int)cp[0];
- CLAMP(r, 0, 255);
- g = offset + (int)cp[1];
- CLAMP(g, 0, 255);
- b = offset + (int)cp[2];
- CLAMP(b, 0, 255);
-
- cp[0] = r;
- cp[1] = g;
- cp[2] = b;
-}
-
-static void cp_shade_color3f(float cp[3], const float offset)
-{
- add_v3_fl(cp, offset);
- CLAMP(cp[0], 0, 255);
- CLAMP(cp[1], 0, 255);
- CLAMP(cp[2], 0, 255);
-}
-
-/* This function sets the gl-color for coloring a certain bone (based on bcolor) */
-static bool set_pchan_color(short colCode,
- const int boneflag,
- const short constflag,
- float r_color[4])
-{
- float *fcolor = r_color;
- const ThemeWireColor *bcolor = g_color.bcolor;
-
- switch (colCode) {
- case PCHAN_COLOR_NORMAL: {
- if (bcolor) {
- uchar cp[4] = {255};
-
- if (boneflag & BONE_DRAW_ACTIVE) {
- copy_v3_v3_uchar(cp, bcolor->active);
- if (!(boneflag & BONE_SELECTED)) {
- cp_shade_color3ub(cp, -80);
- }
- }
- else if (boneflag & BONE_SELECTED) {
- copy_v3_v3_uchar(cp, bcolor->select);
- }
- else {
- /* a bit darker than solid */
- copy_v3_v3_uchar(cp, bcolor->solid);
- cp_shade_color3ub(cp, -50);
- }
-
- rgb_uchar_to_float(fcolor, cp);
- }
- else {
- if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) {
- UI_GetThemeColor4fv(TH_BONE_POSE_ACTIVE, fcolor);
- }
- else if (boneflag & BONE_DRAW_ACTIVE) {
- UI_GetThemeColorBlendShade4fv(TH_WIRE, TH_BONE_POSE, 0.15f, 0, fcolor);
- }
- else if (boneflag & BONE_SELECTED) {
- UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
- }
- else {
- UI_GetThemeColor4fv(TH_WIRE, fcolor);
- }
- }
-
- return true;
- }
- case PCHAN_COLOR_SOLID: {
- UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
-
- if (bcolor) {
- float solid_bcolor[3];
- rgb_uchar_to_float(solid_bcolor, (uchar *)bcolor->solid);
- interp_v3_v3v3(fcolor, fcolor, solid_bcolor, 1.0f);
- }
-
- return true;
- }
- case PCHAN_COLOR_CONSTS: {
- if ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) {
- uchar cp[4];
- if (constflag & PCHAN_HAS_TARGET) {
- rgba_uchar_args_set(cp, 255, 150, 0, 80);
- }
- else if (constflag & PCHAN_HAS_IK) {
- rgba_uchar_args_set(cp, 255, 255, 0, 80);
- }
- else if (constflag & PCHAN_HAS_SPLINEIK) {
- rgba_uchar_args_set(cp, 200, 255, 0, 80);
- }
- else if (constflag & PCHAN_HAS_CONST) {
- rgba_uchar_args_set(cp, 0, 255, 120, 80);
- }
- else {
- return false;
- }
-
- rgba_uchar_to_float(fcolor, cp);
-
- return true;
- }
- return false;
- }
- case PCHAN_COLOR_SPHEREBONE_BASE: {
- if (bcolor) {
- uchar cp[4] = {255};
-
- if (boneflag & BONE_DRAW_ACTIVE) {
- copy_v3_v3_uchar(cp, bcolor->active);
- }
- else if (boneflag & BONE_SELECTED) {
- copy_v3_v3_uchar(cp, bcolor->select);
- }
- else {
- copy_v3_v3_uchar(cp, bcolor->solid);
- }
-
- rgb_uchar_to_float(fcolor, cp);
- }
- else {
- if (boneflag & BONE_DRAW_ACTIVE) {
- UI_GetThemeColorShade4fv(TH_BONE_POSE, 40, fcolor);
- }
- else if (boneflag & BONE_SELECTED) {
- UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
- }
- else {
- UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
- }
- }
-
- return true;
- }
- case PCHAN_COLOR_SPHEREBONE_END: {
- if (bcolor) {
- uchar cp[4] = {255};
-
- if (boneflag & BONE_DRAW_ACTIVE) {
- copy_v3_v3_uchar(cp, bcolor->active);
- cp_shade_color3ub(cp, 10);
- }
- else if (boneflag & BONE_SELECTED) {
- copy_v3_v3_uchar(cp, bcolor->select);
- cp_shade_color3ub(cp, -30);
- }
- else {
- copy_v3_v3_uchar(cp, bcolor->solid);
- cp_shade_color3ub(cp, -30);
- }
-
- rgb_uchar_to_float(fcolor, cp);
- }
- else {
- if (boneflag & BONE_DRAW_ACTIVE) {
- UI_GetThemeColorShade4fv(TH_BONE_POSE, 10, fcolor);
- }
- else if (boneflag & BONE_SELECTED) {
- UI_GetThemeColorShade4fv(TH_BONE_POSE, -30, fcolor);
- }
- else {
- UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor);
- }
- }
- break;
- }
- case PCHAN_COLOR_LINEBONE: {
- /* inner part in background color or constraint */
- if ((constflag) && ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS))) {
- uchar cp[4];
- if (constflag & PCHAN_HAS_TARGET) {
- rgba_uchar_args_set(cp, 255, 150, 0, 255);
- }
- else if (constflag & PCHAN_HAS_IK) {
- rgba_uchar_args_set(cp, 255, 255, 0, 255);
- }
- else if (constflag & PCHAN_HAS_SPLINEIK) {
- rgba_uchar_args_set(cp, 200, 255, 0, 255);
- }
- else if (constflag & PCHAN_HAS_CONST) {
- rgba_uchar_args_set(cp, 0, 255, 120, 255);
- }
- else if (constflag) {
- UI_GetThemeColor4ubv(TH_BONE_POSE, cp);
- } /* PCHAN_HAS_ACTION */
-
- rgb_uchar_to_float(fcolor, cp);
- }
- else {
- if (bcolor) {
- const uchar *cp = bcolor->solid;
- rgb_uchar_to_float(fcolor, (uchar *)cp);
- fcolor[3] = 204.f / 255.f;
- }
- else {
- UI_GetThemeColorShade4fv(TH_BACK, -30, fcolor);
- }
- }
-
- return true;
- }
- }
-
- return false;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Drawing Color Helpers
- * \{ */
-
-/** See: 'set_pchan_color'*/
-static void update_color(const Object *ob, const float const_color[4])
-{
- const bArmature *arm = ob->data;
- g_theme.const_color = const_color;
- g_theme.const_wire = (((ob->base_flag & BASE_SELECTED) || (arm->drawtype == ARM_WIRE)) ?
- 1.5f :
- ((g_data.transparent) ? 1.0f : 0.0f));
-
-#define NO_ALPHA(c) (((c)[3] = 1.0f), (c))
-
- UI_GetThemeColor3fv(TH_SELECT, NO_ALPHA(g_theme.select_color));
- UI_GetThemeColorShade3fv(TH_EDGE_SELECT, 60, NO_ALPHA(g_theme.edge_select_color));
- UI_GetThemeColorShade3fv(TH_EDGE_SELECT, -20, NO_ALPHA(g_theme.bone_select_color));
- UI_GetThemeColor3fv(TH_WIRE, NO_ALPHA(g_theme.wire_color));
- UI_GetThemeColor3fv(TH_WIRE_EDIT, NO_ALPHA(g_theme.wire_edit_color));
- UI_GetThemeColor3fv(TH_BONE_SOLID, NO_ALPHA(g_theme.bone_solid_color));
- UI_GetThemeColorBlendShade3fv(
- TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f, 0, NO_ALPHA(g_theme.bone_active_unselect_color));
- UI_GetThemeColor3fv(TH_BONE_POSE, NO_ALPHA(g_theme.bone_pose_color));
- UI_GetThemeColor3fv(TH_BONE_POSE_ACTIVE, NO_ALPHA(g_theme.bone_pose_active_color));
- UI_GetThemeColorBlendShade3fv(
- TH_WIRE, TH_BONE_POSE, 0.15f, 0, NO_ALPHA(g_theme.bone_pose_active_unselect_color));
- UI_GetThemeColor3fv(TH_TEXT_HI, NO_ALPHA(g_theme.text_hi_color));
- UI_GetThemeColor3fv(TH_TEXT, NO_ALPHA(g_theme.text_color));
- UI_GetThemeColor3fv(TH_VERTEX_SELECT, NO_ALPHA(g_theme.vertex_select_color));
- UI_GetThemeColor3fv(TH_VERTEX, NO_ALPHA(g_theme.vertex_color));
-
-#undef NO_ALPHA
-}
-
-static const float *get_bone_solid_color(const EditBone *UNUSED(eBone),
- const bPoseChannel *pchan,
- const bArmature *arm,
- const int boneflag,
- const short constflag)
-{
- if (g_theme.const_color) {
- return g_theme.bone_solid_color;
- }
-
- if (arm->flag & ARM_POSEMODE) {
- static float disp_color[4];
- copy_v4_v4(disp_color, pchan->draw_data->solid_color);
- set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag, disp_color);
- return disp_color;
- }
-
- return g_theme.bone_solid_color;
-}
-
-static const float *get_bone_solid_with_consts_color(const EditBone *eBone,
- const bPoseChannel *pchan,
- const bArmature *arm,
- const int boneflag,
- const short constflag)
-{
- if (g_theme.const_color) {
- return g_theme.bone_solid_color;
- }
-
- const float *col = get_bone_solid_color(eBone, pchan, arm, boneflag, constflag);
-
- static float consts_color[4];
- if (set_pchan_color(PCHAN_COLOR_CONSTS, boneflag, constflag, consts_color)) {
- interp_v3_v3v3(consts_color, col, consts_color, 0.5f);
- }
- else {
- copy_v4_v4(consts_color, col);
- }
- return consts_color;
-}
-
-static float get_bone_wire_thickness(int boneflag)
-{
- if (g_theme.const_color) {
- return g_theme.const_wire;
- }
- else if (boneflag & (BONE_DRAW_ACTIVE | BONE_SELECTED)) {
- return 2.0f;
- }
- else {
- return 1.0f;
- }
-}
-
-static const float *get_bone_wire_color(const EditBone *eBone,
- const bPoseChannel *pchan,
- const bArmature *arm,
- const int boneflag,
- const short constflag)
-{
- static float disp_color[4];
-
- if (g_theme.const_color) {
- copy_v3_v3(disp_color, g_theme.const_color);
- }
- else if (eBone) {
- if (boneflag & BONE_SELECTED) {
- if (boneflag & BONE_DRAW_ACTIVE) {
- copy_v3_v3(disp_color, g_theme.edge_select_color);
- }
- else {
- copy_v3_v3(disp_color, g_theme.bone_select_color);
- }
- }
- else {
- if (boneflag & BONE_DRAW_ACTIVE) {
- copy_v3_v3(disp_color, g_theme.bone_active_unselect_color);
- }
- else {
- copy_v3_v3(disp_color, g_theme.wire_edit_color);
- }
- }
- }
- else if (arm->flag & ARM_POSEMODE) {
- copy_v4_v4(disp_color, pchan->draw_data->wire_color);
- set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag, disp_color);
- }
- else {
- copy_v3_v3(disp_color, g_theme.vertex_color);
- }
-
- disp_color[3] = get_bone_wire_thickness(boneflag);
-
- return disp_color;
-}
-
-#define HINT_MUL 0.5f
-#define HINT_SHADE 0.2f
-
-static void bone_hint_color_shade(float hint_color[4], const float color[4])
-{
- mul_v3_v3fl(hint_color, color, HINT_MUL);
- cp_shade_color3f(hint_color, -HINT_SHADE);
- hint_color[3] = 1.0f;
-}
-
-static const float *get_bone_hint_color(const EditBone *eBone,
- const bPoseChannel *pchan,
- const bArmature *arm,
- const int boneflag,
- const short constflag)
-{
- static float hint_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
-
- if (g_theme.const_color) {
- bone_hint_color_shade(hint_color, g_theme.bone_solid_color);
- }
- else {
- const float *wire_color = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
- bone_hint_color_shade(hint_color, wire_color);
- }
-
- return hint_color;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Helper Utils
- * \{ */
-
-static void pchan_draw_data_init(bPoseChannel *pchan)
-{
- if (pchan->draw_data != NULL) {
- if (pchan->draw_data->bbone_matrix_len != pchan->bone->segments) {
- MEM_SAFE_FREE(pchan->draw_data);
- }
- }
-
- if (pchan->draw_data == NULL) {
- pchan->draw_data = MEM_mallocN(
- sizeof(*pchan->draw_data) + sizeof(Mat4) * pchan->bone->segments, __func__);
- pchan->draw_data->bbone_matrix_len = pchan->bone->segments;
- }
-}
-
-static void draw_bone_update_disp_matrix_default(EditBone *eBone, bPoseChannel *pchan)
-{
- float s[4][4], ebmat[4][4];
- float length;
- float(*bone_mat)[4];
- float(*disp_mat)[4];
- float(*disp_tail_mat)[4];
-
- /* TODO : This should be moved to depsgraph or armature refresh
- * and not be tight to the draw pass creation.
- * This would refresh armature without invalidating the draw cache */
- if (pchan) {
- length = pchan->bone->length;
- bone_mat = pchan->pose_mat;
- disp_mat = pchan->disp_mat;
- disp_tail_mat = pchan->disp_tail_mat;
- }
- else {
- eBone->length = len_v3v3(eBone->tail, eBone->head);
- ED_armature_ebone_to_mat4(eBone, ebmat);
-
- length = eBone->length;
- bone_mat = ebmat;
- disp_mat = eBone->disp_mat;
- disp_tail_mat = eBone->disp_tail_mat;
- }
-
- scale_m4_fl(s, length);
- mul_m4_m4m4(disp_mat, bone_mat, s);
- copy_m4_m4(disp_tail_mat, disp_mat);
- translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
-}
-
-/* compute connected child pointer for B-Bone drawing */
-static void edbo_compute_bbone_child(bArmature *arm)
-{
- EditBone *eBone;
-
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- eBone->bbone_child = NULL;
- }
-
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
- eBone->parent->bbone_child = eBone;
- }
- }
-}
-
-/* A version of BKE_pchan_bbone_spline_setup() for previewing editmode curve settings. */
-static void ebone_spline_preview(EditBone *ebone, float result_array[MAX_BBONE_SUBDIV][4][4])
-{
- BBoneSplineParameters param;
- EditBone *prev, *next;
- float imat[4][4], bonemat[4][4];
- float tmp[3];
-
- memset(&param, 0, sizeof(param));
-
- param.segments = ebone->segments;
- param.length = ebone->length;
-
- /* Get "next" and "prev" bones - these are used for handle calculations. */
- if (ebone->bbone_prev_type == BBONE_HANDLE_AUTO) {
- /* Use connected parent. */
- if (ebone->flag & BONE_CONNECTED) {
- prev = ebone->parent;
- }
- else {
- prev = NULL;
- }
- }
- else {
- prev = ebone->bbone_prev;
- }
-
- if (ebone->bbone_next_type == BBONE_HANDLE_AUTO) {
- /* Use connected child. */
- next = ebone->bbone_child;
- }
- else {
- next = ebone->bbone_next;
- }
-
- /* compute handles from connected bones */
- if (prev || next) {
- ED_armature_ebone_to_mat4(ebone, imat);
- invert_m4(imat);
-
- if (prev) {
- param.use_prev = true;
-
- if (ebone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
- zero_v3(param.prev_h);
- }
- else if (ebone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
- sub_v3_v3v3(tmp, prev->tail, prev->head);
- sub_v3_v3v3(tmp, ebone->head, tmp);
- mul_v3_m4v3(param.prev_h, imat, tmp);
- }
- else {
- param.prev_bbone = (prev->segments > 1);
-
- mul_v3_m4v3(param.prev_h, imat, prev->head);
- }
-
- if (!param.prev_bbone) {
- ED_armature_ebone_to_mat4(prev, bonemat);
- mul_m4_m4m4(param.prev_mat, imat, bonemat);
- }
- }
-
- if (next) {
- param.use_next = true;
-
- if (ebone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
- copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
- }
- else if (ebone->bbone_next_type == BBONE_HANDLE_TANGENT) {
- sub_v3_v3v3(tmp, next->tail, next->head);
- add_v3_v3v3(tmp, ebone->tail, tmp);
- mul_v3_m4v3(param.next_h, imat, tmp);
- }
- else {
- param.next_bbone = (next->segments > 1);
-
- mul_v3_m4v3(param.next_h, imat, next->tail);
- }
-
- ED_armature_ebone_to_mat4(next, bonemat);
- mul_m4_m4m4(param.next_mat, imat, bonemat);
- }
- }
-
- param.ease1 = ebone->ease1;
- param.ease2 = ebone->ease2;
- param.roll1 = ebone->roll1;
- param.roll2 = ebone->roll2;
-
- if (prev && (ebone->flag & BONE_ADD_PARENT_END_ROLL)) {
- param.roll1 += prev->roll2;
- }
-
- param.scale_in_x = ebone->scale_in_x;
- param.scale_in_y = ebone->scale_in_y;
-
- param.scale_out_x = ebone->scale_out_x;
- param.scale_out_y = ebone->scale_out_y;
-
- param.curve_in_x = ebone->curve_in_x;
- param.curve_in_y = ebone->curve_in_y;
-
- param.curve_out_x = ebone->curve_out_x;
- param.curve_out_y = ebone->curve_out_y;
-
- ebone->segments = BKE_pchan_bbone_spline_compute(&param, false, (Mat4 *)result_array);
-}
-
-static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pchan)
-{
- float s[4][4], ebmat[4][4];
- float length, xwidth, zwidth;
- float(*bone_mat)[4];
- short bbone_segments;
-
- /* TODO : This should be moved to depsgraph or armature refresh
- * and not be tight to the draw pass creation.
- * This would refresh armature without invalidating the draw cache */
- if (pchan) {
- length = pchan->bone->length;
- xwidth = pchan->bone->xwidth;
- zwidth = pchan->bone->zwidth;
- bone_mat = pchan->pose_mat;
- bbone_segments = pchan->bone->segments;
- }
- else {
- eBone->length = len_v3v3(eBone->tail, eBone->head);
- ED_armature_ebone_to_mat4(eBone, ebmat);
-
- length = eBone->length;
- xwidth = eBone->xwidth;
- zwidth = eBone->zwidth;
- bone_mat = ebmat;
- bbone_segments = eBone->segments;
- }
-
- size_to_mat4(s, (const float[3]){xwidth, length / bbone_segments, zwidth});
-
- /* Compute BBones segment matrices... */
- /* Note that we need this even for one-segment bones, because box drawing need specific weirdo
- * matrix for the box, that we cannot use to draw end points & co. */
- if (pchan) {
- Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
- if (bbone_segments > 1) {
- BKE_pchan_bbone_spline_setup(pchan, false, false, bbones_mat);
-
- for (int i = bbone_segments; i--; bbones_mat++) {
- mul_m4_m4m4(bbones_mat->mat, bbones_mat->mat, s);
- mul_m4_m4m4(bbones_mat->mat, bone_mat, bbones_mat->mat);
- }
- }
- else {
- mul_m4_m4m4(bbones_mat->mat, bone_mat, s);
- }
- }
- else {
- float(*bbones_mat)[4][4] = eBone->disp_bbone_mat;
-
- if (bbone_segments > 1) {
- ebone_spline_preview(eBone, bbones_mat);
-
- for (int i = bbone_segments; i--; bbones_mat++) {
- mul_m4_m4m4(*bbones_mat, *bbones_mat, s);
- mul_m4_m4m4(*bbones_mat, bone_mat, *bbones_mat);
- }
- }
- else {
- mul_m4_m4m4(*bbones_mat, bone_mat, s);
- }
- }
-
- /* Grrr... We need default display matrix to draw end points, axes, etc. :( */
- draw_bone_update_disp_matrix_default(eBone, pchan);
-}
-
-static void draw_bone_update_disp_matrix_custom(bPoseChannel *pchan)
-{
- float s[4][4];
- float length;
- float(*bone_mat)[4];
- float(*disp_mat)[4];
- float(*disp_tail_mat)[4];
-
- /* See TODO above */
- length = PCHAN_CUSTOM_DRAW_SIZE(pchan);
- bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
- disp_mat = pchan->disp_mat;
- disp_tail_mat = pchan->disp_tail_mat;
-
- scale_m4_fl(s, length);
- mul_m4_m4m4(disp_mat, bone_mat, s);
- copy_m4_m4(disp_tail_mat, disp_mat);
- translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
-}
-
-static void draw_axes(EditBone *eBone, bPoseChannel *pchan, const eGPUShaderConfig sh_cfg)
-{
- float final_col[4];
- const float *col = (g_theme.const_color) ?
- g_theme.const_color :
- (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? g_theme.text_hi_color :
- g_theme.text_color;
- copy_v4_v4(final_col, col);
- /* Mix with axes color. */
- final_col[3] = (g_theme.const_color) ? 1.0 :
- (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? 0.3 : 0.8;
- drw_shgroup_bone_axes(BONE_VAR(eBone, pchan, disp_mat), final_col, sh_cfg);
-}
-
-static void draw_points(const EditBone *eBone,
- const bPoseChannel *pchan,
- const bArmature *arm,
- const int boneflag,
- const short constflag,
- const eGPUShaderConfig sh_cfg,
- const int select_id)
-{
- float col_solid_root[4], col_solid_tail[4], col_wire_root[4], col_wire_tail[4];
- float col_hint_root[4], col_hint_tail[4];
-
- copy_v4_v4(col_solid_root, g_theme.bone_solid_color);
- copy_v4_v4(col_solid_tail, g_theme.bone_solid_color);
- copy_v4_v4(col_wire_root, (g_theme.const_color) ? g_theme.const_color : g_theme.vertex_color);
- copy_v4_v4(col_wire_tail, (g_theme.const_color) ? g_theme.const_color : g_theme.vertex_color);
-
- const bool is_envelope_draw = (arm->drawtype == ARM_ENVELOPE);
- static const float envelope_ignore = -1.0f;
-
- col_wire_tail[3] = col_wire_root[3] = get_bone_wire_thickness(boneflag);
-
- /* Edit bone points can be selected */
- if (eBone) {
- if (eBone->flag & BONE_ROOTSEL) {
- copy_v3_v3(col_wire_root, g_theme.vertex_select_color);
- }
- if (eBone->flag & BONE_TIPSEL) {
- copy_v3_v3(col_wire_tail, g_theme.vertex_select_color);
- }
- }
- else if (arm->flag & ARM_POSEMODE) {
- const float *solid_color = get_bone_solid_color(eBone, pchan, arm, boneflag, constflag);
- const float *wire_color = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
- copy_v4_v4(col_wire_tail, wire_color);
- copy_v4_v4(col_wire_root, wire_color);
- copy_v4_v4(col_solid_tail, solid_color);
- copy_v4_v4(col_solid_root, solid_color);
- }
-
- bone_hint_color_shade(col_hint_root, (g_theme.const_color) ? col_solid_root : col_wire_root);
- bone_hint_color_shade(col_hint_tail, (g_theme.const_color) ? col_solid_tail : col_wire_tail);
-
- /* Draw root point if we are not connected to our parent */
- if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
- (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
- if (select_id != -1) {
- DRW_select_load_id(select_id | BONESEL_ROOT);
- }
-
- if (eBone) {
- if (is_envelope_draw) {
- drw_shgroup_bone_envelope(eBone->disp_mat,
- col_solid_root,
- col_hint_root,
- col_wire_root,
- &eBone->rad_head,
- &envelope_ignore,
- sh_cfg);
- }
- else {
- drw_shgroup_bone_point(
- eBone->disp_mat, col_solid_root, col_hint_root, col_wire_root, sh_cfg);
- }
- }
- else {
- Bone *bone = pchan->bone;
- if (is_envelope_draw) {
- drw_shgroup_bone_envelope(pchan->disp_mat,
- col_solid_root,
- col_hint_root,
- col_wire_root,
- &bone->rad_head,
- &envelope_ignore,
- sh_cfg);
- }
- else {
- drw_shgroup_bone_point(
- pchan->disp_mat, col_solid_root, col_hint_root, col_wire_root, sh_cfg);
- }
- }
- }
-
- /* Draw tip point */
- if (select_id != -1) {
- DRW_select_load_id(select_id | BONESEL_TIP);
- }
-
- if (is_envelope_draw) {
- const float *rad_tail = eBone ? &eBone->rad_tail : &pchan->bone->rad_tail;
- drw_shgroup_bone_envelope(BONE_VAR(eBone, pchan, disp_mat),
- col_solid_tail,
- col_hint_tail,
- col_wire_tail,
- &envelope_ignore,
- rad_tail,
- sh_cfg);
- }
- else {
- drw_shgroup_bone_point(BONE_VAR(eBone, pchan, disp_tail_mat),
- col_solid_tail,
- col_hint_tail,
- col_wire_tail,
- sh_cfg);
- }
-
- if (select_id != -1) {
- DRW_select_load_id(-1);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Draw Bones
- * \{ */
-
-static void draw_bone_custom_shape(EditBone *eBone,
- bPoseChannel *pchan,
- bArmature *arm,
- const int boneflag,
- const short constflag,
- const eGPUShaderConfig sh_cfg,
- const int select_id)
-{
- const float *col_solid = get_bone_solid_color(eBone, pchan, arm, boneflag, constflag);
- const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
- const float *col_hint = get_bone_hint_color(eBone, pchan, arm, boneflag, constflag);
- const float(*disp_mat)[4] = pchan->disp_mat;
-
- if (select_id != -1) {
- DRW_select_load_id(select_id | BONESEL_BONE);
- }
-
- if (pchan->custom->type == OB_EMPTY) {
- Object *ob = pchan->custom;
- if (ob->empty_drawtype != OB_EMPTY_IMAGE) {
- drw_shgroup_bone_custom_empty(disp_mat, col_wire, sh_cfg, pchan->custom);
- }
- }
- if ((boneflag & BONE_DRAWWIRE) == 0) {
- drw_shgroup_bone_custom_solid(disp_mat, col_solid, col_hint, col_wire, sh_cfg, pchan->custom);
- }
- else {
- drw_shgroup_bone_custom_wire(disp_mat, col_wire, pchan->custom);
- }
-
- if (select_id != -1) {
- DRW_select_load_id(-1);
- }
-}
-
-static void draw_bone_envelope(EditBone *eBone,
- bPoseChannel *pchan,
- bArmature *arm,
- const int boneflag,
- const short constflag,
- const eGPUShaderConfig sh_cfg,
- const int select_id)
-{
- const float *col_solid = get_bone_solid_with_consts_color(
- eBone, pchan, arm, boneflag, constflag);
- const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
- const float *col_hint = get_bone_hint_color(eBone, pchan, arm, boneflag, constflag);
-
- float *rad_head, *rad_tail, *distance;
- if (eBone) {
- rad_tail = &eBone->rad_tail;
- distance = &eBone->dist;
- rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail :
- &eBone->rad_head;
- }
- else {
- rad_tail = &pchan->bone->rad_tail;
- distance = &pchan->bone->dist;
- rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail :
- &pchan->bone->rad_head;
- }
-
- if ((select_id == -1) && (boneflag & BONE_NO_DEFORM) == 0 &&
- ((boneflag & BONE_SELECTED) || (eBone && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL))))) {
- drw_shgroup_bone_envelope_distance(
- BONE_VAR(eBone, pchan, disp_mat), rad_head, rad_tail, distance, sh_cfg);
- }
-
- if (select_id != -1) {
- DRW_select_load_id(select_id | BONESEL_BONE);
- }
-
- drw_shgroup_bone_envelope(
- BONE_VAR(eBone, pchan, disp_mat), col_solid, col_hint, col_wire, rad_head, rad_tail, sh_cfg);
-
- if (select_id != -1) {
- DRW_select_load_id(-1);
- }
-
- draw_points(eBone, pchan, arm, boneflag, constflag, sh_cfg, select_id);
-}
-
-static void draw_bone_line(EditBone *eBone,
- bPoseChannel *pchan,
- bArmature *arm,
- const int boneflag,
- const short constflag,
- const eGPUShaderConfig sh_cfg,
- const int select_id)
-{
- const float *col_bone = get_bone_solid_with_consts_color(eBone, pchan, arm, boneflag, constflag);
- const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
- const float no_display[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- const float *col_head = no_display;
- const float *col_tail = col_bone;
-
- if (g_theme.const_color != NULL) {
- col_wire = no_display; /* actually shrink the display. */
- col_bone = col_head = col_tail = g_theme.const_color;
- }
- else {
- if (eBone) {
- if (eBone->flag & BONE_TIPSEL) {
- col_tail = g_theme.vertex_select_color;
- }
- if (boneflag & BONE_SELECTED) {
- col_bone = g_theme.edge_select_color;
- }
- col_wire = g_theme.wire_color;
- }
-
- /* Draw root point if we are not connected to our parent. */
- if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
- (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
-
- if (eBone) {
- col_head = (eBone->flag & BONE_ROOTSEL) ? g_theme.vertex_select_color : col_bone;
- }
- else {
- col_head = col_bone;
- }
- }
- }
-
- if (select_id == -1) {
- /* Not in selection mode, draw everything at once. */
- drw_shgroup_bone_stick(
- BONE_VAR(eBone, pchan, disp_mat), col_wire, col_bone, col_head, col_tail, sh_cfg);
- }
- else {
- /* In selection mode, draw bone, root and tip separately. */
- DRW_select_load_id(select_id | BONESEL_BONE);
- drw_shgroup_bone_stick(
- BONE_VAR(eBone, pchan, disp_mat), col_wire, col_bone, no_display, no_display, sh_cfg);
-
- if (col_head[3] > 0.0f) {
- DRW_select_load_id(select_id | BONESEL_ROOT);
- drw_shgroup_bone_stick(
- BONE_VAR(eBone, pchan, disp_mat), col_wire, no_display, col_head, no_display, sh_cfg);
- }
-
- DRW_select_load_id(select_id | BONESEL_TIP);
- drw_shgroup_bone_stick(
- BONE_VAR(eBone, pchan, disp_mat), col_wire, no_display, no_display, col_tail, sh_cfg);
-
- DRW_select_load_id(-1);
- }
-}
-
-static void draw_bone_wire(EditBone *eBone,
- bPoseChannel *pchan,
- bArmature *arm,
- const int boneflag,
- const short constflag,
- const eGPUShaderConfig sh_cfg,
- const int select_id)
-{
- const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
-
- if (select_id != -1) {
- DRW_select_load_id(select_id | BONESEL_BONE);
- }
-
- if (pchan) {
- Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
- BLI_assert(bbones_mat != NULL);
-
- for (int i = pchan->bone->segments; i--; bbones_mat++) {
- drw_shgroup_bone_wire(bbones_mat->mat, col_wire, sh_cfg);
- }
- }
- else if (eBone) {
- for (int i = 0; i < eBone->segments; i++) {
- drw_shgroup_bone_wire(eBone->disp_bbone_mat[i], col_wire, sh_cfg);
- }
- }
-
- if (select_id != -1) {
- DRW_select_load_id(-1);
- }
-
- if (eBone) {
- draw_points(eBone, pchan, arm, boneflag, constflag, sh_cfg, select_id);
- }
-}
-
-static void draw_bone_box(EditBone *eBone,
- bPoseChannel *pchan,
- bArmature *arm,
- const int boneflag,
- const short constflag,
- const eGPUShaderConfig sh_cfg,
- const int select_id)
-{
- const float *col_solid = get_bone_solid_with_consts_color(
- eBone, pchan, arm, boneflag, constflag);
- const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
- const float *col_hint = get_bone_hint_color(eBone, pchan, arm, boneflag, constflag);
-
- if (select_id != -1) {
- DRW_select_load_id(select_id | BONESEL_BONE);
- }
-
- if (pchan) {
- Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
- BLI_assert(bbones_mat != NULL);
-
- for (int i = pchan->bone->segments; i--; bbones_mat++) {
- drw_shgroup_bone_box(bbones_mat->mat, col_solid, col_hint, col_wire, sh_cfg);
- }
- }
- else if (eBone) {
- for (int i = 0; i < eBone->segments; i++) {
- drw_shgroup_bone_box(eBone->disp_bbone_mat[i], col_solid, col_hint, col_wire, sh_cfg);
- }
- }
-
- if (select_id != -1) {
- DRW_select_load_id(-1);
- }
-
- if (eBone) {
- draw_points(eBone, pchan, arm, boneflag, constflag, sh_cfg, select_id);
- }
-}
-
-static void draw_bone_octahedral(EditBone *eBone,
- bPoseChannel *pchan,
- bArmature *arm,
- const int boneflag,
- const short constflag,
- const eGPUShaderConfig sh_cfg,
- const int select_id)
-{
- const float *col_solid = get_bone_solid_with_consts_color(
- eBone, pchan, arm, boneflag, constflag);
- const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
- const float *col_hint = get_bone_hint_color(eBone, pchan, arm, boneflag, constflag);
-
- if (select_id != -1) {
- DRW_select_load_id(select_id | BONESEL_BONE);
- }
-
- drw_shgroup_bone_octahedral(
- BONE_VAR(eBone, pchan, disp_mat), col_solid, col_hint, col_wire, sh_cfg);
-
- if (select_id != -1) {
- DRW_select_load_id(-1);
- }
-
- draw_points(eBone, pchan, arm, boneflag, constflag, sh_cfg, select_id);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Draw Degrees of Freedom
- * \{ */
-
-static void draw_bone_dofs(bPoseChannel *pchan)
-{
- float final_bonemat[4][4], posetrans[4][4], mat[4][4];
- float amin[2], amax[2], xminmax[2], zminmax[2];
- float col_sphere[4] = {0.25f, 0.25f, 0.25f, 0.25f};
- float col_lines[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- float col_xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
- float col_zaxis[4] = {0.0f, 0.0f, 1.0f, 1.0f};
-
- if (g_data.passes.bone_envelope == NULL) {
- return;
- }
-
- if (g_data.bone_dof_sphere == NULL) {
- g_data.bone_dof_lines = buffer_instance_bone_dof(
- g_data.passes.bone_wire, DRW_cache_bone_dof_lines_get(), false);
- g_data.bone_dof_sphere = buffer_instance_bone_dof(
- g_data.passes.bone_envelope, DRW_cache_bone_dof_sphere_get(), true);
- }
-
- /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
- xminmax[0] = sinf(pchan->limitmin[0] * 0.5f);
- xminmax[1] = sinf(pchan->limitmax[0] * 0.5f);
- zminmax[0] = sinf(pchan->limitmin[2] * 0.5f);
- zminmax[1] = sinf(pchan->limitmax[2] * 0.5f);
-
- unit_m4(posetrans);
- translate_m4(posetrans, pchan->pose_mat[3][0], pchan->pose_mat[3][1], pchan->pose_mat[3][2]);
- /* in parent-bone pose space... */
- if (pchan->parent) {
- copy_m4_m4(mat, pchan->parent->pose_mat);
- mat[3][0] = mat[3][1] = mat[3][2] = 0.0f;
- mul_m4_m4m4(posetrans, posetrans, mat);
- }
- /* ... but own restspace */
- mul_m4_m4m3(posetrans, posetrans, pchan->bone->bone_mat);
-
- float scale = pchan->bone->length * pchan->size[1];
- scale_m4_fl(mat, scale);
- mat[1][1] = -mat[1][1];
- mul_m4_m4m4(posetrans, posetrans, mat);
-
- /* into world space. */
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, posetrans);
-
- if ((pchan->ikflag & BONE_IK_XLIMIT) && (pchan->ikflag & BONE_IK_ZLIMIT)) {
- amin[0] = xminmax[0];
- amax[0] = xminmax[1];
- amin[1] = zminmax[0];
- amax[1] = zminmax[1];
- DRW_buffer_add_entry(g_data.bone_dof_sphere, final_bonemat, col_sphere, amin, amax);
- DRW_buffer_add_entry(g_data.bone_dof_lines, final_bonemat, col_lines, amin, amax);
- }
- if (pchan->ikflag & BONE_IK_XLIMIT) {
- amin[0] = xminmax[0];
- amax[0] = xminmax[1];
- amin[1] = amax[1] = 0.0f;
- DRW_buffer_add_entry(g_data.bone_dof_lines, final_bonemat, col_xaxis, amin, amax);
- }
- if (pchan->ikflag & BONE_IK_ZLIMIT) {
- amin[1] = zminmax[0];
- amax[1] = zminmax[1];
- amin[0] = amax[0] = 0.0f;
- DRW_buffer_add_entry(g_data.bone_dof_lines, final_bonemat, col_zaxis, amin, amax);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Draw Relationships
- * \{ */
-
-static void pchan_draw_ik_lines(bPoseChannel *pchan,
- const bool only_temp,
- const int constflag,
- const eGPUShaderConfig sh_cfg)
-{
- bConstraint *con;
- bPoseChannel *parchan;
- float *line_start = NULL, *line_end = NULL;
-
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->enforce == 0.0f) {
- continue;
- }
-
- switch (con->type) {
- case CONSTRAINT_TYPE_KINEMATIC: {
- bKinematicConstraint *data = (bKinematicConstraint *)con->data;
- int segcount = 0;
-
- /* if only_temp, only draw if it is a temporary ik-chain */
- if (only_temp && !(data->flag & CONSTRAINT_IK_TEMP)) {
- continue;
- }
-
- /* exclude tip from chain? */
- parchan = ((data->flag & CONSTRAINT_IK_TIP) == 0) ? pchan->parent : pchan;
- line_start = parchan->pose_tail;
-
- /* Find the chain's root */
- while (parchan->parent) {
- segcount++;
- if (segcount == data->rootbone || segcount > 255) {
- break; /* 255 is weak */
- }
- parchan = parchan->parent;
- }
-
- if (parchan) {
- line_end = parchan->pose_head;
-
- if (constflag & PCHAN_HAS_TARGET) {
- drw_shgroup_bone_ik_lines(line_start, line_end, sh_cfg);
- }
- else {
- drw_shgroup_bone_ik_no_target_lines(line_start, line_end, sh_cfg);
- }
- }
- break;
- }
- case CONSTRAINT_TYPE_SPLINEIK: {
- bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
- int segcount = 0;
-
- /* don't draw if only_temp, as Spline IK chains cannot be temporary */
- if (only_temp) {
- continue;
- }
-
- parchan = pchan;
- line_start = parchan->pose_tail;
-
- /* Find the chain's root */
- while (parchan->parent) {
- segcount++;
- /* FIXME: revise the breaking conditions */
- if (segcount == data->chainlen || segcount > 255) {
- break; /* 255 is weak */
- }
- parchan = parchan->parent;
- }
- /* Only draw line in case our chain is more than one bone long! */
- if (parchan != pchan) { /* XXX revise the breaking conditions to only stop at the tail? */
- line_end = parchan->pose_head;
- drw_shgroup_bone_ik_spline_lines(line_start, line_end, sh_cfg);
- }
- break;
- }
- }
- }
-}
-
-static void draw_bone_relations(EditBone *ebone,
- bPoseChannel *pchan,
- bArmature *arm,
- const int boneflag,
- const short constflag,
- const bool do_relations,
- const eGPUShaderConfig sh_cfg)
-{
- if (g_data.passes.relationship_lines) {
- if (ebone && ebone->parent) {
- if (do_relations) {
- /* Always draw for unconnected bones, regardless of selection,
- * since riggers will want to know about the links between bones
- */
- if ((boneflag & BONE_CONNECTED) == 0) {
- drw_shgroup_bone_relationship_lines(ebone->head, ebone->parent->tail, sh_cfg);
- }
- }
- }
- else if (pchan && pchan->parent) {
- if (do_relations) {
- /* Only draw if bone or its parent is selected - reduces viewport complexity with complex
- * rigs */
- if ((boneflag & BONE_SELECTED) ||
- (pchan->parent->bone && (pchan->parent->bone->flag & BONE_SELECTED))) {
- if ((boneflag & BONE_CONNECTED) == 0) {
- drw_shgroup_bone_relationship_lines(
- pchan->pose_head, pchan->parent->pose_tail, sh_cfg);
- }
- }
- }
-
- /* Draw a line to IK root bone if bone is selected. */
- if (arm->flag & ARM_POSEMODE) {
- if (constflag & (PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK)) {
- if (boneflag & BONE_SELECTED) {
- pchan_draw_ik_lines(pchan, !do_relations, constflag, sh_cfg);
- }
- }
- }
- }
- }
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Main Draw Loops
- * \{ */
-
-static void draw_armature_edit(Object *ob)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- EditBone *eBone;
- int index;
- const bool is_select = DRW_state_is_select();
-
- const bool show_text = DRW_state_show_text();
- const bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0);
-
- const Object *ob_orig = DEG_get_original_object(ob);
- /* FIXME(campbell): We should be able to use the CoW object,
- * however the active bone isn't updated. Long term solution is an 'EditArmature' struct.
- * for now we can draw from the original armature. See: T66773. */
- // bArmature *arm = ob->data;
- bArmature *arm = ob_orig->data;
-
- update_color(ob, NULL);
- edbo_compute_bbone_child(arm);
-
- for (eBone = arm->edbo->first, index = ob_orig->runtime.select_id; eBone;
- eBone = eBone->next, index += 0x10000) {
- if (eBone->layer & arm->layer) {
- if ((eBone->flag & BONE_HIDDEN_A) == 0) {
- const int select_id = is_select ? index : (uint)-1;
-
- const short constflag = 0;
-
- /* catch exception for bone with hidden parent */
- int boneflag = eBone->flag;
- if ((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent)) {
- boneflag &= ~BONE_CONNECTED;
- }
-
- /* set temporary flag for drawing bone as active, but only if selected */
- if (eBone == arm->act_edbone) {
- boneflag |= BONE_DRAW_ACTIVE;
- }
-
- draw_bone_relations(
- eBone, NULL, arm, boneflag, constflag, show_relations, draw_ctx->sh_cfg);
-
- if (arm->drawtype == ARM_ENVELOPE) {
- draw_bone_update_disp_matrix_default(eBone, NULL);
- draw_bone_envelope(eBone, NULL, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
- else if (arm->drawtype == ARM_LINE) {
- draw_bone_update_disp_matrix_default(eBone, NULL);
- draw_bone_line(eBone, NULL, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
- else if (arm->drawtype == ARM_WIRE) {
- draw_bone_update_disp_matrix_bbone(eBone, NULL);
- draw_bone_wire(eBone, NULL, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
- else if (arm->drawtype == ARM_B_BONE) {
- draw_bone_update_disp_matrix_bbone(eBone, NULL);
- draw_bone_box(eBone, NULL, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
- else {
- draw_bone_update_disp_matrix_default(eBone, NULL);
- draw_bone_octahedral(eBone, NULL, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
-
- /* Draw names of bone */
- if (show_text && (arm->flag & ARM_DRAWNAMES)) {
- uchar color[4];
- UI_GetThemeColor4ubv((eBone->flag & BONE_SELECTED) ? TH_TEXT_HI : TH_TEXT, color);
-
- float vec[3];
- mid_v3_v3v3(vec, eBone->head, eBone->tail);
- mul_m4_v3(ob->obmat, vec);
-
- struct DRWTextStore *dt = DRW_text_cache_ensure();
- DRW_text_cache_add(dt,
- vec,
- eBone->name,
- strlen(eBone->name),
- 10,
- 0,
- DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
- color);
- }
-
- /* Draw additional axes */
- if (arm->flag & ARM_DRAWAXES) {
- draw_axes(eBone, NULL, draw_ctx->sh_cfg);
- }
- }
- }
- }
-}
-
-/* if const_color is NULL do pose mode coloring */
-static void draw_armature_pose(Object *ob, const float const_color[4])
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene = draw_ctx->scene;
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
- int index = -1;
- Bone *bone;
-
- update_color(ob, const_color);
-
- /* We can't safely draw non-updated pose, might contain NULL bone pointers... */
- if (ob->pose->flag & POSE_RECALC) {
- return;
- }
-
- bool is_pose_select = false;
- /* Object can be edited in the scene. */
- if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
- if ((draw_ctx->object_mode & OB_MODE_POSE) || (ob == draw_ctx->object_pose)) {
- arm->flag |= ARM_POSEMODE;
- }
- is_pose_select =
- /* If we're in pose-mode or object-mode with the ability to enter pose mode. */
- (
- /* Draw as if in pose mode (when selection is possible). */
- (arm->flag & ARM_POSEMODE) ||
- /* When we're in object mode, which may select bones. */
- ((ob->mode & OB_MODE_POSE) &&
- (
- /* Switch from object mode when object lock is disabled. */
- ((draw_ctx->object_mode == OB_MODE_OBJECT) &&
- (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) ||
- /* Allow selection when in weight-paint mode
- * (selection code ensures this wont become active). */
- ((draw_ctx->object_mode == OB_MODE_WEIGHT_PAINT) &&
- (draw_ctx->object_pose != NULL))))) &&
- DRW_state_is_select();
-
- if (is_pose_select) {
- const Object *ob_orig = DEG_get_original_object(ob);
- index = ob_orig->runtime.select_id;
- }
- }
-
- const bool show_text = DRW_state_show_text();
- const bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0);
-
- /* being set below */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
-
- /* bone must be visible */
- if ((bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) {
- if (bone->layer & arm->layer) {
- const int select_id = is_pose_select ? index : (uint)-1;
-
- const short constflag = pchan->constflag;
-
- pchan_draw_data_init(pchan);
-
- if (const_color) {
- /* keep color */
- }
- else {
- /* set color-set to use */
- set_pchan_colorset(ob, pchan);
- }
-
- int boneflag = bone->flag;
- /* catch exception for bone with hidden parent */
- boneflag = bone->flag;
- if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
- boneflag &= ~BONE_CONNECTED;
- }
-
- /* set temporary flag for drawing bone as active, but only if selected */
- if (bone == arm->act_bone) {
- boneflag |= BONE_DRAW_ACTIVE;
- }
-
- draw_bone_relations(
- NULL, pchan, arm, boneflag, constflag, show_relations, draw_ctx->sh_cfg);
-
- if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) {
- draw_bone_update_disp_matrix_custom(pchan);
- draw_bone_custom_shape(
- NULL, pchan, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
- else if (arm->drawtype == ARM_ENVELOPE) {
- draw_bone_update_disp_matrix_default(NULL, pchan);
- draw_bone_envelope(NULL, pchan, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
- else if (arm->drawtype == ARM_LINE) {
- draw_bone_update_disp_matrix_default(NULL, pchan);
- draw_bone_line(NULL, pchan, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
- else if (arm->drawtype == ARM_WIRE) {
- draw_bone_update_disp_matrix_bbone(NULL, pchan);
- draw_bone_wire(NULL, pchan, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
- else if (arm->drawtype == ARM_B_BONE) {
- draw_bone_update_disp_matrix_bbone(NULL, pchan);
- draw_bone_box(NULL, pchan, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
- else {
- draw_bone_update_disp_matrix_default(NULL, pchan);
- draw_bone_octahedral(NULL, pchan, arm, boneflag, constflag, draw_ctx->sh_cfg, select_id);
- }
-
- if (!is_pose_select && show_relations && (arm->flag & ARM_POSEMODE) &&
- (bone->flag & BONE_SELECTED) && ((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT))) {
- draw_bone_dofs(pchan);
- }
-
- /* Draw names of bone */
- if (show_text && (arm->flag & ARM_DRAWNAMES)) {
- uchar color[4];
- UI_GetThemeColor4ubv(
- (arm->flag & ARM_POSEMODE) && (bone->flag & BONE_SELECTED) ? TH_TEXT_HI : TH_TEXT,
- color);
- float vec[3];
- mid_v3_v3v3(vec, pchan->pose_head, pchan->pose_tail);
- mul_m4_v3(ob->obmat, vec);
-
- struct DRWTextStore *dt = DRW_text_cache_ensure();
- DRW_text_cache_add(dt,
- vec,
- pchan->name,
- strlen(pchan->name),
- 10,
- 0,
- DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
- color);
- }
-
- /* Draw additional axes */
- if (arm->flag & ARM_DRAWAXES) {
- draw_axes(NULL, pchan, draw_ctx->sh_cfg);
- }
- }
- }
- if (is_pose_select) {
- index += 0x10000;
- }
- }
-
- arm->flag &= ~ARM_POSEMODE;
-}
-
-/**
- * This function set the object space to use for all subsequent `DRW_shgroup_bone_*` calls.
- */
-static void drw_shgroup_armature(Object *ob, DRWArmaturePasses passes, bool transp)
-{
- memset(&g_data, 0x0, sizeof(g_data));
- g_data.ob = ob;
- g_data.passes = passes;
- g_data.transparent = transp;
- memset(&g_color, 0x0, sizeof(g_color));
-}
-
-void DRW_shgroup_armature_object(Object *ob,
- ViewLayer *view_layer,
- DRWArmaturePasses passes,
- bool transp)
-{
- float *color;
- DRW_object_wire_theme_get(ob, view_layer, &color);
- passes.bone_envelope = NULL; /* Don't do envelope distance in object mode. */
- drw_shgroup_armature(ob, passes, transp);
- draw_armature_pose(ob, color);
-}
-
-void DRW_shgroup_armature_pose(Object *ob, DRWArmaturePasses passes, bool transp)
-{
- drw_shgroup_armature(ob, passes, transp);
- draw_armature_pose(ob, NULL);
-}
-
-void DRW_shgroup_armature_edit(Object *ob, DRWArmaturePasses passes, bool transp)
-{
- drw_shgroup_armature(ob, passes, transp);
- draw_armature_edit(ob);
-}
-
-/** \} */
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index b085d402e81..69135f8ade3 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -44,12 +44,41 @@
#include "draw_cache_impl.h"
#include "draw_manager.h"
+#define VCLASS_LIGHT_AREA_SHAPE (1 << 0)
+#define VCLASS_LIGHT_SPOT_SHAPE (1 << 1)
+#define VCLASS_LIGHT_SPOT_BLEND (1 << 2)
+#define VCLASS_LIGHT_SPOT_CONE (1 << 3)
+#define VCLASS_LIGHT_DIST (1 << 4)
+
+#define VCLASS_CAMERA_FRAME (1 << 5)
+#define VCLASS_CAMERA_DIST (1 << 6)
+#define VCLASS_CAMERA_VOLUME (1 << 7)
+
+#define VCLASS_SCREENSPACE (1 << 8)
+#define VCLASS_SCREENALIGNED (1 << 9)
+
+#define VCLASS_EMPTY_SCALED (1 << 10)
+#define VCLASS_EMPTY_AXES (1 << 11)
+#define VCLASS_EMPTY_AXES_NAME (1 << 12)
+#define VCLASS_EMPTY_AXES_SHADOW (1 << 13)
+#define VCLASS_EMPTY_SIZE (1 << 14)
+
+typedef struct Vert {
+ float pos[3];
+ int class;
+} Vert;
+
+typedef struct VertShaded {
+ float pos[3];
+ int class;
+ float nor[3];
+} VertShaded;
+
/* Batch's only (free'd as an array) */
static struct DRWShapeCache {
GPUBatch *drw_procedural_verts;
GPUBatch *drw_procedural_lines;
GPUBatch *drw_procedural_tris;
- GPUBatch *drw_single_vertice;
GPUBatch *drw_cursor;
GPUBatch *drw_cursor_only_circle;
GPUBatch *drw_fullscreen_quad;
@@ -57,37 +86,31 @@ static struct DRWShapeCache {
GPUBatch *drw_quad_wires;
GPUBatch *drw_grid;
GPUBatch *drw_sphere;
- GPUBatch *drw_screenspace_circle;
GPUBatch *drw_plain_axes;
GPUBatch *drw_single_arrow;
GPUBatch *drw_cube;
GPUBatch *drw_circle;
- GPUBatch *drw_square;
- GPUBatch *drw_line;
- GPUBatch *drw_line_endpoints;
+ GPUBatch *drw_normal_arrow;
GPUBatch *drw_empty_cube;
GPUBatch *drw_empty_sphere;
GPUBatch *drw_empty_cylinder;
GPUBatch *drw_empty_capsule_body;
GPUBatch *drw_empty_capsule_cap;
GPUBatch *drw_empty_cone;
- GPUBatch *drw_image_plane;
- GPUBatch *drw_image_plane_wire;
GPUBatch *drw_field_wind;
GPUBatch *drw_field_force;
GPUBatch *drw_field_vortex;
+ GPUBatch *drw_field_curve;
GPUBatch *drw_field_tube_limit;
GPUBatch *drw_field_cone_limit;
- GPUBatch *drw_light;
- GPUBatch *drw_light_shadows;
- GPUBatch *drw_light_sunrays;
- GPUBatch *drw_light_area_square;
- GPUBatch *drw_light_area_disk;
- GPUBatch *drw_light_hemi;
- GPUBatch *drw_light_spot;
+ GPUBatch *drw_field_sphere_limit;
+ GPUBatch *drw_ground_line;
+ GPUBatch *drw_light_point_lines;
+ GPUBatch *drw_light_sun_lines;
+ GPUBatch *drw_light_spot_lines;
GPUBatch *drw_light_spot_volume;
- GPUBatch *drw_light_spot_square;
- GPUBatch *drw_light_spot_square_volume;
+ GPUBatch *drw_light_area_disk_lines;
+ GPUBatch *drw_light_area_square_lines;
GPUBatch *drw_speaker;
GPUBatch *drw_lightprobe_cube;
GPUBatch *drw_lightprobe_planar;
@@ -104,13 +127,15 @@ static struct DRWShapeCache {
GPUBatch *drw_bone_arrows;
GPUBatch *drw_bone_dof_sphere;
GPUBatch *drw_bone_dof_lines;
- GPUBatch *drw_camera;
GPUBatch *drw_camera_frame;
GPUBatch *drw_camera_tria;
+ GPUBatch *drw_camera_tria_wire;
+ GPUBatch *drw_camera_distances;
+ GPUBatch *drw_camera_volume;
+ GPUBatch *drw_camera_volume_wire;
GPUBatch *drw_particle_cross;
GPUBatch *drw_particle_circle;
GPUBatch *drw_particle_axis;
- GPUBatch *drw_gpencil_axes;
} SHC = {NULL};
void DRW_shape_cache_free(void)
@@ -187,6 +212,14 @@ GPUBatch *drw_cache_procedural_triangles_get(void)
/** \name Helper functions
* \{ */
+static GPUVertFormat extra_vert_format(void)
+{
+ GPUVertFormat format = {0};
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "vclass", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ return format;
+}
+
static void UNUSED_FUNCTION(add_fancy_edge)(GPUVertBuf *vbo,
uint pos_id,
uint n1_id,
@@ -274,21 +307,16 @@ static GPUVertBuf *fill_arrows_vbo(const float scale)
}
#endif /* UNUSED */
-static GPUVertBuf *sphere_wire_vbo(const float rad)
+static GPUVertBuf *sphere_wire_vbo(const float rad, int flag)
{
#define NSEGMENTS 32
/* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 2 * 3);
+ int v = 0;
/* a single ring of vertices */
float p[NSEGMENTS][2];
for (int i = 0; i < NSEGMENTS; i++) {
@@ -300,21 +328,20 @@ static GPUVertBuf *sphere_wire_vbo(const float rad)
for (int axis = 0; axis < 3; axis++) {
for (int i = 0; i < NSEGMENTS; i++) {
for (int j = 0; j < 2; j++) {
- float cv[2], v[3];
+ float cv[2];
cv[0] = p[(i + j) % NSEGMENTS][0];
cv[1] = p[(i + j) % NSEGMENTS][1];
if (axis == 0) {
- ARRAY_SET_ITEMS(v, cv[0], cv[1], 0.0f);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{cv[0], cv[1], 0.0f}, flag});
}
else if (axis == 1) {
- ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{cv[0], 0.0f, cv[1]}, flag});
}
else {
- ARRAY_SET_ITEMS(v, 0.0f, cv[0], cv[1]);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, cv[0], cv[1]}, flag});
}
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + j + (NSEGMENTS * 2 * axis), v);
}
}
}
@@ -362,25 +389,16 @@ GPUBatch *DRW_cache_fullscreen_quad_get(void)
GPUBatch *DRW_cache_quad_get(void)
{
if (!SHC.drw_quad) {
- float pos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {1.0f, 1.0f}, {-1.0f, 1.0f}};
- float uvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
-
- /* Position Only 2D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos, uvs;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 4);
- for (int i = 0; i < 4; i++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
- GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
+ int v = 0;
+ int flag = VCLASS_EMPTY_SCALED;
+ float p[4][2] = {{-1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, -1.0f}};
+ for (int a = 0; a < 4; a++) {
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[a][0], p[a][1], 0.0f}, flag});
}
SHC.drw_quad = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
@@ -392,26 +410,19 @@ GPUBatch *DRW_cache_quad_get(void)
GPUBatch *DRW_cache_quad_wires_get(void)
{
if (!SHC.drw_quad_wires) {
- float pos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {1.0f, 1.0f}, {-1.0f, 1.0f}};
-
- /* Position Only 2D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 8);
+ GPU_vertbuf_data_alloc(vbo, 5);
- for (int i = 0; i < 4; i++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2, pos[i % 4]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + 1, pos[(i + 1) % 4]);
+ int v = 0;
+ int flag = VCLASS_EMPTY_SCALED;
+ float p[4][2] = {{-1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, -1.0f}};
+ for (int a = 0; a < 5; a++) {
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[a % 4][0], p[a % 4][1], 0.0f}, flag});
}
- SHC.drw_quad_wires = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_quad_wires = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_quad_wires;
}
@@ -461,10 +472,51 @@ GPUBatch *DRW_cache_grid_get(void)
}
/* Sphere */
+static void sphere_lat_lon_vert(GPUVertBuf *vbo, int *v_ofs, float lat, float lon)
+{
+ float x = sinf(lat) * cosf(lon);
+ float y = cosf(lat);
+ float z = sinf(lat) * sinf(lon);
+ GPU_vertbuf_vert_set(vbo, *v_ofs, &(VertShaded){{x, y, z}, VCLASS_EMPTY_SCALED, {x, y, z}});
+ (*v_ofs)++;
+}
+
GPUBatch *DRW_cache_sphere_get(void)
{
if (!SHC.drw_sphere) {
- SHC.drw_sphere = gpu_batch_sphere(32, 24);
+ const int lat_res = 32;
+ const int lon_res = 24;
+
+ GPUVertFormat format = extra_vert_format();
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ int v_len = (lat_res - 1) * lon_res * 6;
+ GPU_vertbuf_data_alloc(vbo, v_len);
+
+ const float lon_inc = 2 * M_PI / lon_res;
+ const float lat_inc = M_PI / lat_res;
+ float lon, lat;
+
+ int v = 0;
+ lon = 0.0f;
+ for (int i = 0; i < lon_res; i++, lon += lon_inc) {
+ lat = 0.0f;
+ for (int j = 0; j < lat_res; j++, lat += lat_inc) {
+ if (j != lat_res - 1) { /* Pole */
+ sphere_lat_lon_vert(vbo, &v, lat + lat_inc, lon + lon_inc);
+ sphere_lat_lon_vert(vbo, &v, lat + lat_inc, lon);
+ sphere_lat_lon_vert(vbo, &v, lat, lon);
+ }
+ if (j != 0) { /* Pole */
+ sphere_lat_lon_vert(vbo, &v, lat, lon + lon_inc);
+ sphere_lat_lon_vert(vbo, &v, lat + lat_inc, lon + lon_inc);
+ sphere_lat_lon_vert(vbo, &v, lat, lon);
+ }
+ }
+ }
+
+ SHC.drw_sphere = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_sphere;
}
@@ -475,285 +527,213 @@ GPUBatch *DRW_cache_sphere_get(void)
/** \name Common
* \{ */
-GPUBatch *DRW_cache_cube_get(void)
+static void circle_verts(
+ GPUVertBuf *vbo, int *vert_idx, int segments, float radius, float z, int flag)
{
- if (!SHC.drw_cube) {
- const GLfloat verts[8][3] = {
- {-1.0f, -1.0f, -1.0f},
- {-1.0f, -1.0f, 1.0f},
- {-1.0f, 1.0f, -1.0f},
- {-1.0f, 1.0f, 1.0f},
- {1.0f, -1.0f, -1.0f},
- {1.0f, -1.0f, 1.0f},
- {1.0f, 1.0f, -1.0f},
- {1.0f, 1.0f, 1.0f},
- };
-
- const uint indices[36] = {
- 0, 1, 2, 1, 3, 2, 0, 4, 1, 4, 5, 1, 6, 5, 4, 6, 7, 5,
- 2, 7, 6, 2, 3, 7, 3, 1, 7, 1, 5, 7, 0, 2, 4, 2, 6, 4,
- };
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ for (int a = 0; a < segments; a++) {
+ for (int b = 0; b < 2; b++) {
+ float angle = (2.0f * M_PI * (a + b)) / segments;
+ float s = sinf(angle) * radius;
+ float c = cosf(angle) * radius;
+ int v = *vert_idx;
+ *vert_idx = v + 1;
+ GPU_vertbuf_vert_set(vbo, v, &(Vert){{s, c, z}, flag});
}
+ }
+}
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 36);
-
- for (int i = 0; i < 36; i++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
+static void circle_dashed_verts(
+ GPUVertBuf *vbo, int *vert_idx, int segments, float radius, float z, int flag)
+{
+ for (int a = 0; a < segments * 2; a += 2) {
+ for (int b = 0; b < 2; b++) {
+ float angle = (2.0f * M_PI * (a + b)) / (segments * 2);
+ float s = sinf(angle) * radius;
+ float c = cosf(angle) * radius;
+ int v = *vert_idx;
+ *vert_idx = v + 1;
+ GPU_vertbuf_vert_set(vbo, v, &(Vert){{s, c, z}, flag});
}
-
- SHC.drw_cube = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_cube;
}
-GPUBatch *DRW_cache_empty_cube_get(void)
-{
- if (!SHC.drw_empty_cube) {
- const GLfloat verts[8][3] = {
- {-1.0f, -1.0f, -1.0f},
- {-1.0f, -1.0f, 1.0f},
- {-1.0f, 1.0f, -1.0f},
- {-1.0f, 1.0f, 1.0f},
- {1.0f, -1.0f, -1.0f},
- {1.0f, -1.0f, 1.0f},
- {1.0f, 1.0f, -1.0f},
- {1.0f, 1.0f, 1.0f},
- };
+/* XXX TODO move that 1 unit cube to more common/generic place? */
+static const float bone_box_verts[8][3] = {
+ {1.0f, 0.0f, 1.0f},
+ {1.0f, 0.0f, -1.0f},
+ {-1.0f, 0.0f, -1.0f},
+ {-1.0f, 0.0f, 1.0f},
+ {1.0f, 1.0f, 1.0f},
+ {1.0f, 1.0f, -1.0f},
+ {-1.0f, 1.0f, -1.0f},
+ {-1.0f, 1.0f, 1.0f},
+};
- const GLubyte indices[24] = {
- 0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6,
- };
+static const float bone_box_smooth_normals[8][3] = {
+ {M_SQRT3, -M_SQRT3, M_SQRT3},
+ {M_SQRT3, -M_SQRT3, -M_SQRT3},
+ {-M_SQRT3, -M_SQRT3, -M_SQRT3},
+ {-M_SQRT3, -M_SQRT3, M_SQRT3},
+ {M_SQRT3, M_SQRT3, M_SQRT3},
+ {M_SQRT3, M_SQRT3, -M_SQRT3},
+ {-M_SQRT3, M_SQRT3, -M_SQRT3},
+ {-M_SQRT3, M_SQRT3, M_SQRT3},
+};
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+static const uint bone_box_wire[24] = {
+ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7,
+};
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 24);
+#if 0 /* UNUSED */
+/* aligned with bone_octahedral_wire
+ * Contains adjacent normal index */
+static const uint bone_box_wire_adjacent_face[24] = {
+ 0, 2, 0, 4, 1, 6, 1, 8, 3, 10, 5, 10, 7, 11, 9, 11, 3, 8, 2, 5, 4, 7, 6, 9,
+};
+#endif
- for (int i = 0; i < 24; i++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
- }
+static const uint bone_box_solid_tris[12][3] = {
+ {0, 2, 1}, /* bottom */
+ {0, 3, 2},
- SHC.drw_empty_cube = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- return SHC.drw_empty_cube;
-}
+ {0, 1, 5}, /* sides */
+ {0, 5, 4},
-GPUBatch *DRW_cache_circle_get(void)
-{
-#define CIRCLE_RESOL 64
- if (!SHC.drw_circle) {
- float v[3] = {0.0f, 0.0f, 0.0f};
+ {1, 2, 6},
+ {1, 6, 5},
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ {2, 3, 7},
+ {2, 7, 6},
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
+ {3, 0, 4},
+ {3, 4, 7},
- for (int a = 0; a < CIRCLE_RESOL; a++) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[2] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[1] = 0.0f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
- }
+ {4, 5, 6}, /* top */
+ {4, 6, 7},
+};
- SHC.drw_circle = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- return SHC.drw_circle;
-#undef CIRCLE_RESOL
-}
+/**
+ * Store indices of generated verts from bone_box_solid_tris to define adjacency infos.
+ * See bone_octahedral_solid_tris for more infos.
+ */
+static const uint bone_box_wire_lines_adjacency[12][4] = {
+ {4, 2, 0, 11},
+ {0, 1, 2, 8},
+ {2, 4, 1, 14},
+ {1, 0, 4, 20}, /* bottom */
+ {0, 8, 11, 14},
+ {2, 14, 8, 20},
+ {1, 20, 14, 11},
+ {4, 11, 20, 8}, /* top */
+ {20, 0, 11, 2},
+ {11, 2, 8, 1},
+ {8, 1, 14, 4},
+ {14, 4, 20, 0}, /* sides */
+};
-GPUBatch *DRW_cache_square_get(void)
-{
- if (!SHC.drw_square) {
- const float p[4][3] = {
- {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 1.0f}};
+#if 0 /* UNUSED */
+static const uint bone_box_solid_tris_adjacency[12][6] = {
+ {0, 5, 1, 14, 2, 8},
+ {3, 26, 4, 20, 5, 1},
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ {6, 2, 7, 16, 8, 11},
+ {9, 7, 10, 32, 11, 24},
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 8);
+ {12, 0, 13, 22, 14, 17},
+ {15, 13, 16, 30, 17, 6},
- for (int i = 0; i < 4; i++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2, p[i % 4]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + 1, p[(i + 1) % 4]);
- }
+ {18, 3, 19, 28, 20, 23},
+ {21, 19, 22, 33, 23, 12},
- SHC.drw_square = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- return SHC.drw_square;
-}
+ {24, 4, 25, 10, 26, 29},
+ {27, 25, 28, 34, 29, 18},
-GPUBatch *DRW_cache_single_line_get(void)
-{
- /* Z axis line */
- if (!SHC.drw_line) {
- float v1[3] = {0.0f, 0.0f, 0.0f};
- float v2[3] = {0.0f, 0.0f, 1.0f};
+ {30, 9, 31, 15, 32, 35},
+ {33, 31, 34, 21, 35, 27},
+};
+#endif
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+/* aligned with bone_box_solid_tris */
+static const float bone_box_solid_normals[12][3] = {
+ {0.0f, -1.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f},
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 2);
+ {1.0f, 0.0f, 0.0f},
+ {1.0f, 0.0f, 0.0f},
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
+ {0.0f, 0.0f, -1.0f},
+ {0.0f, 0.0f, -1.0f},
- SHC.drw_line = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- return SHC.drw_line;
-}
+ {-1.0f, 0.0f, 0.0f},
+ {-1.0f, 0.0f, 0.0f},
-GPUBatch *DRW_cache_single_line_endpoints_get(void)
-{
- /* Z axis line */
- if (!SHC.drw_line_endpoints) {
- float v1[3] = {0.0f, 0.0f, 0.0f};
- float v2[3] = {0.0f, 0.0f, 1.0f};
+ {0.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 1.0f},
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ {0.0f, 1.0f, 0.0f},
+ {0.0f, 1.0f, 0.0f},
+};
+
+GPUBatch *DRW_cache_cube_get(void)
+{
+ if (!SHC.drw_cube) {
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 2);
+ GPU_vertbuf_data_alloc(vbo, ARRAY_SIZE(bone_box_solid_tris) * 3);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
+ int v = 0;
+ for (int i = 0; i < ARRAY_SIZE(bone_box_solid_tris); i++) {
+ for (int a = 0; a < 3; a++) {
+ float x = bone_box_verts[bone_box_solid_tris[i][a]][0];
+ float y = bone_box_verts[bone_box_solid_tris[i][a]][1] * 2.0f - 1.0f;
+ float z = bone_box_verts[bone_box_solid_tris[i][a]][2];
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, z}, VCLASS_EMPTY_SCALED});
+ }
+ }
- SHC.drw_line_endpoints = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_cube = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_line_endpoints;
+ return SHC.drw_cube;
}
-GPUBatch *DRW_cache_screenspace_circle_get(void)
+GPUBatch *DRW_cache_circle_get(void)
{
-#define CIRCLE_RESOL 32
- if (!SHC.drw_screenspace_circle) {
- float v[3] = {0.0f, 0.0f, 0.0f};
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+#define CIRCLE_RESOL 64
+ if (!SHC.drw_circle) {
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL + 1);
- for (int a = 0; a <= CIRCLE_RESOL; a++) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
+ int v = 0;
+ for (int a = 0; a < CIRCLE_RESOL + 1; a++) {
+ float x = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ float z = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ float y = 0.0f;
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, z}, VCLASS_EMPTY_SCALED});
}
- SHC.drw_screenspace_circle = GPU_batch_create_ex(
- GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_circle = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_screenspace_circle;
+ return SHC.drw_circle;
#undef CIRCLE_RESOL
}
-/* Grease Pencil object */
-GPUBatch *DRW_cache_gpencil_axes_get(void)
-{
- if (!SHC.drw_gpencil_axes) {
- int axis;
- float v1[3] = {0.0f, 0.0f, 0.0f};
- float v2[3] = {0.0f, 0.0f, 0.0f};
-
- /* cube data */
- const GLfloat verts[8][3] = {
- {-0.25f, -0.25f, -0.25f},
- {-0.25f, -0.25f, 0.25f},
- {-0.25f, 0.25f, -0.25f},
- {-0.25f, 0.25f, 0.25f},
- {0.25f, -0.25f, -0.25f},
- {0.25f, -0.25f, 0.25f},
- {0.25f, 0.25f, -0.25f},
- {0.25f, 0.25f, 0.25f},
- };
-
- const GLubyte indices[24] = {
- 0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6,
- };
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static uint pos_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+GPUBatch *DRW_cache_normal_arrow_get(void)
+{
+ if (!SHC.drw_normal_arrow) {
+ GPUVertFormat format = {0};
+ GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 2);
- /* alloc 30 elements for cube and 3 axis */
- GPU_vertbuf_data_alloc(vbo, ARRAY_SIZE(indices) + 6);
-
- /* draw axis */
- for (axis = 0; axis < 3; axis++) {
- v1[axis] = 1.0f;
- v2[axis] = -1.0f;
-
- GPU_vertbuf_attr_set(vbo, pos_id, axis * 2, v1);
- GPU_vertbuf_attr_set(vbo, pos_id, axis * 2 + 1, v2);
-
- /* reset v1 & v2 to zero for next axis */
- v1[axis] = v2[axis] = 0.0f;
- }
-
- /* draw cube */
- for (int i = 0; i < 24; i++) {
- GPU_vertbuf_attr_set(vbo, pos_id, i + 6, verts[indices[i]]);
- }
+ /* TODO real arrow. For now, it's a line positioned in the vertex shader. */
- SHC.drw_gpencil_axes = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_normal_arrow = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_gpencil_axes;
+ return SHC.drw_normal_arrow;
}
/* -------------------------------------------------------------------- */
@@ -887,78 +867,79 @@ GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
GPUBatch *DRW_cache_plain_axes_get(void)
{
if (!SHC.drw_plain_axes) {
- int axis;
- float v1[3] = {0.0f, 0.0f, 0.0f};
- float v2[3] = {0.0f, 0.0f, 0.0f};
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 6);
- for (axis = 0; axis < 3; axis++) {
- v1[axis] = 1.0f;
- v2[axis] = -1.0f;
-
- GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 2, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 2 + 1, v2);
-
- /* reset v1 & v2 to zero for next axis */
- v1[axis] = v2[axis] = 0.0f;
- }
+ int v = 0;
+ int flag = VCLASS_EMPTY_SCALED;
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, -1.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 1.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{-1.0f, 0.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{1.0f, 0.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, -1.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, 1.0f}, flag});
SHC.drw_plain_axes = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_plain_axes;
}
-GPUBatch *DRW_cache_single_arrow_get(void)
+GPUBatch *DRW_cache_empty_cube_get(void)
{
- if (!SHC.drw_single_arrow) {
- float v1[3] = {0.0f, 0.0f, 1.0f}, v2[3], v3[3];
+ if (!SHC.drw_empty_cube) {
+ GPUVertFormat format = extra_vert_format();
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, ARRAY_SIZE(bone_box_wire));
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ int v = 0;
+ for (int i = 0; i < ARRAY_SIZE(bone_box_wire); i++) {
+ float x = bone_box_verts[bone_box_wire[i]][0];
+ float y = bone_box_verts[bone_box_wire[i]][1] * 2.0 - 1.0f;
+ float z = bone_box_verts[bone_box_wire[i]][2];
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, z}, VCLASS_EMPTY_SCALED});
}
- /* Square Pyramid */
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 12);
+ SHC.drw_empty_cube = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_empty_cube;
+}
- v2[0] = 0.035f;
- v2[1] = 0.035f;
- v3[0] = -0.035f;
- v3[1] = 0.035f;
- v2[2] = v3[2] = 0.75f;
+GPUBatch *DRW_cache_single_arrow_get(void)
+{
+ if (!SHC.drw_single_arrow) {
+ GPUVertFormat format = extra_vert_format();
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 4 * 2 * 2 + 2);
+ int v = 0;
+ int flag = VCLASS_EMPTY_SCALED;
+ float p[3][3] = {{0}};
+ p[0][2] = 1.0f;
+ p[1][0] = 0.035f;
+ p[1][1] = 0.035f;
+ p[2][0] = -0.035f;
+ p[2][1] = 0.035f;
+ p[1][2] = p[2][2] = 0.75f;
for (int sides = 0; sides < 4; sides++) {
if (sides % 2 == 1) {
- v2[0] = -v2[0];
- v3[1] = -v3[1];
+ p[1][0] = -p[1][0];
+ p[2][1] = -p[2][1];
}
else {
- v2[1] = -v2[1];
- v3[0] = -v3[0];
+ p[1][1] = -p[1][1];
+ p[2][0] = -p[2][0];
+ }
+ for (int i = 0, a = 1; i < 2; i++, a++) {
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[i][0], p[i][1], p[i][2]}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[a][0], p[a][1], p[a][2]}, flag});
}
-
- GPU_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 0, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 1, v2);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 2, v3);
}
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, 0.0}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, 0.75f}, flag});
- SHC.drw_single_arrow = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_single_arrow = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_single_arrow;
}
@@ -966,7 +947,7 @@ GPUBatch *DRW_cache_single_arrow_get(void)
GPUBatch *DRW_cache_empty_sphere_get(void)
{
if (!SHC.drw_empty_sphere) {
- GPUVertBuf *vbo = sphere_wire_vbo(1.0f);
+ GPUVertBuf *vbo = sphere_wire_vbo(1.0f, VCLASS_EMPTY_SCALED);
SHC.drw_empty_sphere = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_empty_sphere;
@@ -976,6 +957,12 @@ GPUBatch *DRW_cache_empty_cone_get(void)
{
#define NSEGMENTS 8
if (!SHC.drw_empty_cone) {
+ GPUVertFormat format = extra_vert_format();
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
+
+ int v = 0;
+ int flag = VCLASS_EMPTY_SCALED;
/* a single ring of vertices */
float p[NSEGMENTS][2];
for (int i = 0; i < NSEGMENTS; i++) {
@@ -983,37 +970,20 @@ GPUBatch *DRW_cache_empty_cone_get(void)
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
}
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
-
for (int i = 0; i < NSEGMENTS; i++) {
- float cv[2], v[3];
+ float cv[2];
cv[0] = p[(i) % NSEGMENTS][0];
cv[1] = p[(i) % NSEGMENTS][1];
/* cone sides */
- ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v);
- ARRAY_SET_ITEMS(v, 0.0f, 2.0f, 0.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{cv[0], 0.0f, cv[1]}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 2.0f, 0.0f}, flag});
/* end ring */
- ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 2, v);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{cv[0], 0.0f, cv[1]}, flag});
cv[0] = p[(i + 1) % NSEGMENTS][0];
cv[1] = p[(i + 1) % NSEGMENTS][1];
- ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{cv[0], 0.0f, cv[1]}, flag});
}
SHC.drw_empty_cone = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
@@ -1026,50 +996,35 @@ GPUBatch *DRW_cache_empty_cylinder_get(void)
{
#define NSEGMENTS 12
if (!SHC.drw_empty_cylinder) {
+ GPUVertFormat format = extra_vert_format();
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 6);
+
/* a single ring of vertices */
+ int v = 0;
+ int flag = VCLASS_EMPTY_SCALED;
float p[NSEGMENTS][2];
for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
}
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 6);
-
for (int i = 0; i < NSEGMENTS; i++) {
- float cv[2], pv[2], v[3];
+ float cv[2], pv[2];
cv[0] = p[(i) % NSEGMENTS][0];
cv[1] = p[(i) % NSEGMENTS][1];
pv[0] = p[(i + 1) % NSEGMENTS][0];
pv[1] = p[(i + 1) % NSEGMENTS][1];
/* cylinder sides */
- copy_v3_fl3(v, cv[0], cv[1], -1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6, v);
- copy_v3_fl3(v, cv[0], cv[1], 1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 1, v);
-
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{cv[0], cv[1], -1.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{cv[0], cv[1], 1.0f}, flag});
/* top ring */
- copy_v3_fl3(v, cv[0], cv[1], 1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 2, v);
- copy_v3_fl3(v, pv[0], pv[1], 1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 3, v);
-
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{cv[0], cv[1], 1.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{pv[0], pv[1], 1.0f}, flag});
/* bottom ring */
- copy_v3_fl3(v, cv[0], cv[1], -1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 4, v);
- copy_v3_fl3(v, pv[0], pv[1], -1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 5, v);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{cv[0], cv[1], -1.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{pv[0], pv[1], -1.0f}, flag});
}
SHC.drw_empty_cylinder = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
@@ -1167,84 +1122,22 @@ GPUBatch *DRW_cache_empty_capsule_cap_get(void)
#undef NSEGMENTS
}
-GPUBatch *DRW_cache_image_plane_get(void)
-{
- if (!SHC.drw_image_plane) {
- const float quad[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
- static GPUVertFormat format = {0};
- static struct {
- uint pos, texCoords;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- attr_id.texCoords = GPU_vertformat_attr_add(
- &format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 4);
- for (uint j = 0; j < 4; j++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, j, quad[j]);
- GPU_vertbuf_attr_set(vbo, attr_id.texCoords, j, quad[j]);
- }
- SHC.drw_image_plane = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- return SHC.drw_image_plane;
-}
-
-GPUBatch *DRW_cache_image_plane_wire_get(void)
-{
- if (!SHC.drw_image_plane_wire) {
- const float quad[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 4);
- for (uint j = 0; j < 4; j++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, j, quad[j]);
- }
- SHC.drw_image_plane_wire = GPU_batch_create_ex(
- GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- return SHC.drw_image_plane_wire;
-}
-
/* Force Field */
GPUBatch *DRW_cache_field_wind_get(void)
{
#define CIRCLE_RESOL 32
if (!SHC.drw_field_wind) {
- float v[3] = {0.0f, 0.0f, 0.0f};
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 * (CIRCLE_RESOL * 4);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 4);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+ int v = 0;
+ int flag = VCLASS_EMPTY_SIZE;
for (int i = 0; i < 4; i++) {
float z = 0.05f * (float)i;
- for (int a = 0; a < CIRCLE_RESOL; a++) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[2] = z;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2, v);
-
- v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- v[2] = z;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2 + 1, v);
- }
+ circle_verts(vbo, &v, CIRCLE_RESOL, 1.0f, z, flag);
}
SHC.drw_field_wind = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
@@ -1257,33 +1150,17 @@ GPUBatch *DRW_cache_field_force_get(void)
{
#define CIRCLE_RESOL 32
if (!SHC.drw_field_force) {
- float v[3] = {0.0f, 0.0f, 0.0f};
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 * (CIRCLE_RESOL * 3);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 3);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+ int v = 0;
+ int flag = VCLASS_EMPTY_SIZE | VCLASS_SCREENALIGNED;
for (int i = 0; i < 3; i++) {
- float radius = 1.0f + 0.5f * (float)i;
- for (int a = 0; a < CIRCLE_RESOL; a++) {
- v[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[2] = 0.0f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2, v);
-
- v[0] = radius * sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- v[1] = radius * cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- v[2] = 0.0f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2 + 1, v);
- }
+ float radius = 1.0f + 0.5f * i;
+ circle_verts(vbo, &v, CIRCLE_RESOL, radius, 0.0f, flag);
}
SHC.drw_field_force = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
@@ -1296,33 +1173,23 @@ GPUBatch *DRW_cache_field_vortex_get(void)
{
#define SPIRAL_RESOL 32
if (!SHC.drw_field_vortex) {
- float v[3] = {0.0f, 0.0f, 0.0f};
- uint v_idx = 0;
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
+ int v_len = SPIRAL_RESOL * 2 + 1;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, SPIRAL_RESOL * 2 + 1);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+ int v = 0;
+ int flag = VCLASS_EMPTY_SIZE;
for (int a = SPIRAL_RESOL; a > -1; a--) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
- v[1] = cosf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
-
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ float r = a / (float)SPIRAL_RESOL;
+ float angle = (2.0f * M_PI * a) / SPIRAL_RESOL;
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{sinf(angle) * r, cosf(angle) * r, 0.0f}, flag});
}
-
for (int a = 1; a <= SPIRAL_RESOL; a++) {
- v[0] = -sinf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
- v[1] = -cosf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
-
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ float r = a / (float)SPIRAL_RESOL;
+ float angle = (2.0f * M_PI * a) / SPIRAL_RESOL;
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{sinf(angle) * -r, cosf(angle) * -r, 0.0f}, flag});
}
SHC.drw_field_vortex = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
@@ -1331,48 +1198,50 @@ GPUBatch *DRW_cache_field_vortex_get(void)
#undef SPIRAL_RESOL
}
+/* Screenaligned circle. */
+GPUBatch *DRW_cache_field_curve_get(void)
+{
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_field_curve) {
+ GPUVertFormat format = extra_vert_format();
+
+ int v_len = 2 * (CIRCLE_RESOL);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+
+ int v = 0;
+ int flag = VCLASS_EMPTY_SIZE | VCLASS_SCREENALIGNED;
+ circle_verts(vbo, &v, CIRCLE_RESOL, 1.0f, 0.0f, flag);
+
+ SHC.drw_field_curve = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_field_curve;
+#undef CIRCLE_RESOL
+}
+
GPUBatch *DRW_cache_field_tube_limit_get(void)
{
#define CIRCLE_RESOL 32
if (!SHC.drw_field_tube_limit) {
- float v[3] = {0.0f, 0.0f, 0.0f};
- uint v_idx = 0;
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 * (CIRCLE_RESOL * 2 + 4);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 + 8);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+ int v = 0;
+ int flag = VCLASS_EMPTY_SIZE;
/* Caps */
for (int i = 0; i < 2; i++) {
float z = (float)i * 2.0f - 1.0f;
- for (int a = 0; a < CIRCLE_RESOL; a++) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[2] = z;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
-
- v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- v[2] = z;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
- }
+ circle_verts(vbo, &v, CIRCLE_RESOL, 1.0f, z, flag);
}
/* Side Edges */
for (int a = 0; a < 4; a++) {
for (int i = 0; i < 2; i++) {
float z = (float)i * 2.0f - 1.0f;
- v[0] = sinf((2.0f * M_PI * a) / 4.0f);
- v[1] = cosf((2.0f * M_PI * a) / 4.0f);
- v[2] = z;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ float angle = (2.0f * M_PI * a) / 4.0f;
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{sinf(angle), cosf(angle), z}, flag});
}
}
@@ -1386,44 +1255,25 @@ GPUBatch *DRW_cache_field_cone_limit_get(void)
{
#define CIRCLE_RESOL 32
if (!SHC.drw_field_cone_limit) {
- float v[3] = {0.0f, 0.0f, 0.0f};
- uint v_idx = 0;
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 * (CIRCLE_RESOL * 2 + 4);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 + 8);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+ int v = 0;
+ int flag = VCLASS_EMPTY_SIZE;
/* Caps */
for (int i = 0; i < 2; i++) {
float z = (float)i * 2.0f - 1.0f;
- for (int a = 0; a < CIRCLE_RESOL; a++) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[2] = z;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
-
- v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- v[2] = z;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
- }
+ circle_verts(vbo, &v, CIRCLE_RESOL, 1.0f, z, flag);
}
/* Side Edges */
for (int a = 0; a < 4; a++) {
for (int i = 0; i < 2; i++) {
float z = (float)i * 2.0f - 1.0f;
- v[0] = z * sinf((2.0f * M_PI * a) / 4.0f);
- v[1] = z * cosf((2.0f * M_PI * a) / 4.0f);
- v[2] = z;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ float angle = (2.0f * M_PI * a) / 4.0f;
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{sinf(angle) * z, cosf(angle) * z, z}, flag});
}
}
@@ -1433,444 +1283,285 @@ GPUBatch *DRW_cache_field_cone_limit_get(void)
#undef CIRCLE_RESOL
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Lights
- * \{ */
-
-GPUBatch *DRW_cache_light_get(void)
+/* Screenaligned dashed circle */
+GPUBatch *DRW_cache_field_sphere_limit_get(void)
{
-#define NSEGMENTS 8
- if (!SHC.drw_light) {
- float v[2];
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_field_sphere_limit) {
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 * CIRCLE_RESOL;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
-
- for (int a = 0; a < NSEGMENTS * 2; a += 2) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
- v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
+ GPU_vertbuf_data_alloc(vbo, v_len);
- v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
- v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v);
- }
+ int v = 0;
+ int flag = VCLASS_EMPTY_SIZE | VCLASS_SCREENALIGNED;
+ circle_dashed_verts(vbo, &v, CIRCLE_RESOL, 1.0f, 0.0f, flag);
- SHC.drw_light = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_field_sphere_limit = GPU_batch_create_ex(
+ GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_light;
-#undef NSEGMENTS
+ return SHC.drw_field_sphere_limit;
+#undef CIRCLE_RESOL
}
-GPUBatch *DRW_cache_light_shadows_get(void)
-{
-#define NSEGMENTS 10
- if (!SHC.drw_light_shadows) {
- float v[2];
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
-
- for (int a = 0; a < NSEGMENTS * 2; a += 2) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
- v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
+/** \} */
- v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
- v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v);
- }
+/* -------------------------------------------------------------------- */
+/** \name Lights
+ * \{ */
- SHC.drw_light_shadows = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- return SHC.drw_light_shadows;
-#undef NSEGMENTS
-}
+#define DIAMOND_NSEGMENTS 4
+#define INNER_NSEGMENTS 8
+#define OUTER_NSEGMENTS 10
+#define CIRCLE_NSEGMENTS 32
-GPUBatch *DRW_cache_light_sunrays_get(void)
+static float light_distance_z_get(char axis, const bool start)
{
- if (!SHC.drw_light_sunrays) {
- float v[2], v1[2], v2[2];
-
- /* Position Only 2D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 32);
-
- for (int a = 0; a < 8; a++) {
- v[0] = sinf((2.0f * M_PI * a) / 8.0f);
- v[1] = cosf((2.0f * M_PI * a) / 8.0f);
-
- mul_v2_v2fl(v1, v, 1.6f);
- mul_v2_v2fl(v2, v, 1.9f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 1, v2);
-
- mul_v2_v2fl(v1, v, 2.2f);
- mul_v2_v2fl(v2, v, 2.5f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 2, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 3, v2);
- }
-
- SHC.drw_light_sunrays = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ switch (axis) {
+ case 'x': /* - X */
+ return start ? 0.4f : 0.3f;
+ case 'X': /* + X */
+ return start ? 0.6f : 0.7f;
+ case 'y': /* - Y */
+ return start ? 1.4f : 1.3f;
+ case 'Y': /* + Y */
+ return start ? 1.6f : 1.7f;
+ case 'z': /* - Z */
+ return start ? 2.4f : 2.3f;
+ case 'Z': /* + Z */
+ return start ? 2.6f : 2.7f;
}
- return SHC.drw_light_sunrays;
+ return 0.0;
}
-GPUBatch *DRW_cache_light_area_square_get(void)
+GPUBatch *DRW_cache_groundline_get(void)
{
- if (!SHC.drw_light_area_square) {
- float v1[3] = {0.0f, 0.0f, 0.0f};
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ if (!SHC.drw_ground_line) {
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 * (1 + DIAMOND_NSEGMENTS);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 8);
+ GPU_vertbuf_data_alloc(vbo, v_len);
- v1[0] = v1[1] = 0.5f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
- v1[0] = -0.5f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 1, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 2, v1);
- v1[1] = -0.5f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 3, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 4, v1);
- v1[0] = 0.5f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 5, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 6, v1);
- v1[1] = 0.5f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 7, v1);
+ int v = 0;
+ /* Ground Point */
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.35f, 0.0f, 0);
+ /* Ground Line */
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, 1.0}, 0});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, 0.0}, 0});
- SHC.drw_light_area_square = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_ground_line = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_light_area_square;
+ return SHC.drw_ground_line;
}
-GPUBatch *DRW_cache_light_area_disk_get(void)
+GPUBatch *DRW_cache_light_point_lines_get(void)
{
-#define NSEGMENTS 32
- if (!SHC.drw_light_area_disk) {
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ if (!SHC.drw_light_point_lines) {
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 * (DIAMOND_NSEGMENTS + INNER_NSEGMENTS + OUTER_NSEGMENTS + CIRCLE_NSEGMENTS);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 2 * NSEGMENTS);
+ GPU_vertbuf_data_alloc(vbo, v_len);
- float v[3] = {0.0f, 0.5f, 0.0f};
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v);
- for (int a = 1; a < NSEGMENTS; a++) {
- v[0] = 0.5f * sinf(2.0f * (float)M_PI * a / NSEGMENTS);
- v[1] = 0.5f * cosf(2.0f * (float)M_PI * a / NSEGMENTS);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 2 * a - 1, v);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 2 * a, v);
- }
- copy_v3_fl3(v, 0.0f, 0.5f, 0.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, (2 * NSEGMENTS) - 1, v);
+ const float r = 9.0f;
+ int v = 0;
+ /* Light Icon */
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
+ circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
+ circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
+ /* Light area */
+ int flag = VCLASS_SCREENALIGNED | VCLASS_LIGHT_AREA_SHAPE;
+ circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 1.0f, 0.0f, flag);
- SHC.drw_light_area_disk = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_light_point_lines = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_light_area_disk;
-#undef NSEGMENTS
+ return SHC.drw_light_point_lines;
}
-GPUBatch *DRW_cache_light_hemi_get(void)
+GPUBatch *DRW_cache_light_sun_lines_get(void)
{
-#define CIRCLE_RESOL 32
- if (!SHC.drw_light_hemi) {
- float v[3];
- int vidx = 0;
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ if (!SHC.drw_light_sun_lines) {
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 * (DIAMOND_NSEGMENTS + INNER_NSEGMENTS + OUTER_NSEGMENTS + 8 * 2 + 1);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 - 6 * 2 * 2);
-
- /* XZ plane */
- for (int a = 3; a < CIRCLE_RESOL / 2 - 3; a++) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL) - M_PI / 2);
- v[2] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL) - M_PI / 2) - 1.0f;
- v[1] = 0.0f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
-
- v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL) - M_PI / 2);
- v[2] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL) - M_PI / 2) - 1.0f;
- v[1] = 0.0f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
- }
-
- /* XY plane */
- for (int a = 3; a < CIRCLE_RESOL / 2 - 3; a++) {
- v[2] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)) - 1.0f;
- v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[0] = 0.0f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ GPU_vertbuf_data_alloc(vbo, v_len);
- v[2] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL)) - 1.0f;
- v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- v[0] = 0.0f;
- GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
- }
-
- /* YZ plane full circle */
- /* lease v[2] as it is */
- const float rad = cosf((2.0f * M_PI * 3) / ((float)CIRCLE_RESOL));
- for (int a = 0; a < CIRCLE_RESOL; a++) {
- v[1] = rad * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[0] = rad * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
-
- v[1] = rad * sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- v[0] = rad * cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
- GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ const float r = 9.0f;
+ int v = 0;
+ /* Light Icon */
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
+ circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
+ circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
+ /* Sun Rays */
+ for (int a = 0; a < 8; a++) {
+ float angle = (2.0f * M_PI * a) / 8.0f;
+ float s = sinf(angle) * r;
+ float c = cosf(angle) * r;
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 1.6f, c * 1.6f, 0.0f}, VCLASS_SCREENSPACE});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 1.9f, c * 1.9f, 0.0f}, VCLASS_SCREENSPACE});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 2.2f, c * 2.2f, 0.0f}, VCLASS_SCREENSPACE});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 2.5f, c * 2.5f, 0.0f}, VCLASS_SCREENSPACE});
}
+ /* Direction Line */
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, 0.0}, 0});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, -20.0}, 0}); /* Good default. */
- SHC.drw_light_hemi = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_light_sun_lines = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_light_hemi;
-#undef CIRCLE_RESOL
+ return SHC.drw_light_sun_lines;
}
-GPUBatch *DRW_cache_light_spot_get(void)
+GPUBatch *DRW_cache_light_spot_lines_get(void)
{
-#define NSEGMENTS 32
- if (!SHC.drw_light_spot) {
- /* a single ring of vertices */
- float p[NSEGMENTS][2];
- float n[NSEGMENTS][3];
- float neg[NSEGMENTS][3];
- float half_angle = 2 * M_PI / ((float)NSEGMENTS * 2);
- for (int i = 0; i < NSEGMENTS; i++) {
- float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
- p[i][0] = cosf(angle);
- p[i][1] = sinf(angle);
-
- n[i][0] = cosf(angle - half_angle);
- n[i][1] = sinf(angle - half_angle);
- n[i][2] = cosf(M_PI / 16.0f); /* slope of the cone */
- normalize_v3(n[i]); /* necessary ? */
- negate_v3_v3(neg[i], n[i]);
- }
-
- static GPUVertFormat format = {0};
- static struct {
- uint pos, n1, n2;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- attr_id.n1 = GPU_vertformat_attr_add(&format, "N1", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- attr_id.n2 = GPU_vertformat_attr_add(&format, "N2", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ if (!SHC.drw_light_spot_lines) {
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 * (DIAMOND_NSEGMENTS * 3 + INNER_NSEGMENTS + OUTER_NSEGMENTS +
+ CIRCLE_NSEGMENTS * 4 + 1);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
-
- for (int i = 0; i < NSEGMENTS; i++) {
- float cv[2], v[3];
- cv[0] = p[i % NSEGMENTS][0];
- cv[1] = p[i % NSEGMENTS][1];
-
- /* cone sides */
- ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v);
- ARRAY_SET_ITEMS(v, 0.0f, 0.0f, 0.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v);
-
- GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4, n[(i) % NSEGMENTS]);
- GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 1, n[(i) % NSEGMENTS]);
- GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4, n[(i + 1) % NSEGMENTS]);
- GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 1, n[(i + 1) % NSEGMENTS]);
+ GPU_vertbuf_data_alloc(vbo, v_len);
- /* end ring */
- ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 2, v);
- cv[0] = p[(i + 1) % NSEGMENTS][0];
- cv[1] = p[(i + 1) % NSEGMENTS][1];
- ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v);
-
- GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 2, n[(i) % NSEGMENTS]);
- GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 3, n[(i) % NSEGMENTS]);
- GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 2, neg[(i) % NSEGMENTS]);
- GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 3, neg[(i) % NSEGMENTS]);
- }
-
- SHC.drw_light_spot = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- return SHC.drw_light_spot;
-#undef NSEGMENTS
+ const float r = 9.0f;
+ int v = 0;
+ /* Light Icon */
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
+ circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
+ circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
+ /* Light area */
+ int flag = VCLASS_SCREENALIGNED | VCLASS_LIGHT_AREA_SHAPE;
+ circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 1.0f, 0.0f, flag);
+ /* Cone cap */
+ flag = VCLASS_LIGHT_SPOT_SHAPE;
+ circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 1.0f, 0.0f, flag);
+ flag = VCLASS_LIGHT_SPOT_SHAPE | VCLASS_LIGHT_SPOT_BLEND;
+ circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 1.0f, 0.0f, flag);
+ /* Cone silhouette */
+ flag = VCLASS_LIGHT_SPOT_SHAPE | VCLASS_LIGHT_SPOT_CONE;
+ for (int a = 0; a < CIRCLE_NSEGMENTS; a++) {
+ float angle = (2.0f * M_PI * a) / CIRCLE_NSEGMENTS;
+ float s = sinf(angle);
+ float c = cosf(angle);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, 0.0f}, 0});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s, c, -1.0f}, flag});
+ }
+ /* Direction Line */
+ float zsta = light_distance_z_get('z', true);
+ float zend = light_distance_z_get('z', false);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, zsta}, VCLASS_LIGHT_DIST});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, zend}, VCLASS_LIGHT_DIST});
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.2f, zsta, VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE);
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.2f, zend, VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE);
+
+ SHC.drw_light_spot_lines = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_light_spot_lines;
}
GPUBatch *DRW_cache_light_spot_volume_get(void)
{
-#define NSEGMENTS 32
if (!SHC.drw_light_spot_volume) {
- /* a single ring of vertices */
- float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; i++) {
- float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
- p[i][0] = cosf(angle);
- p[i][1] = sinf(angle);
- }
-
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
+ int v_len = CIRCLE_NSEGMENTS + 1 + 1;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 3);
-
- uint v_idx = 0;
- for (int i = 0; i < NSEGMENTS; i++) {
- float cv[2], v[3];
-
- ARRAY_SET_ITEMS(v, 0.0f, 0.0f, 0.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ GPU_vertbuf_data_alloc(vbo, v_len);
- cv[0] = p[i % NSEGMENTS][0];
- cv[1] = p[i % NSEGMENTS][1];
- ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
-
- cv[0] = p[(i + 1) % NSEGMENTS][0];
- cv[1] = p[(i + 1) % NSEGMENTS][1];
- ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ int v = 0;
+ /* Cone apex */
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, 0.0f}, 0});
+ /* Cone silhouette */
+ int flag = VCLASS_LIGHT_SPOT_SHAPE;
+ for (int a = 0; a < CIRCLE_NSEGMENTS + 1; a++) {
+ float angle = (2.0f * M_PI * a) / CIRCLE_NSEGMENTS;
+ float s = sinf(-angle);
+ float c = cosf(-angle);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s, c, -1.0f}, flag});
}
- SHC.drw_light_spot_volume = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_light_spot_volume = GPU_batch_create_ex(
+ GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_light_spot_volume;
-#undef NSEGMENTS
}
-GPUBatch *DRW_cache_light_spot_square_get(void)
+GPUBatch *DRW_cache_light_area_disk_lines_get(void)
{
- if (!SHC.drw_light_spot_square) {
- const float p[5][3] = {
- {0.0f, 0.0f, 0.0f},
- {1.0f, 1.0f, -1.0f},
- {1.0f, -1.0f, -1.0f},
- {-1.0f, -1.0f, -1.0f},
- {-1.0f, 1.0f, -1.0f},
- };
-
- uint v_idx = 0;
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ if (!SHC.drw_light_area_disk_lines) {
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 *
+ (DIAMOND_NSEGMENTS * 3 + INNER_NSEGMENTS + OUTER_NSEGMENTS + CIRCLE_NSEGMENTS + 1);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 16);
+ GPU_vertbuf_data_alloc(vbo, v_len);
- /* piramid sides */
- for (int i = 1; i <= 4; i++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[i]);
-
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[(i % 4) + 1]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[((i + 1) % 4) + 1]);
- }
-
- SHC.drw_light_spot_square = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ const float r = 9.0f;
+ int v = 0;
+ /* Light Icon */
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
+ circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
+ circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
+ /* Light area */
+ circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 0.5f, 0.0f, VCLASS_LIGHT_AREA_SHAPE);
+ /* Direction Line */
+ float zsta = light_distance_z_get('z', true);
+ float zend = light_distance_z_get('z', false);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, zsta}, VCLASS_LIGHT_DIST});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, zend}, VCLASS_LIGHT_DIST});
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.2f, zsta, VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE);
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.2f, zend, VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE);
+
+ SHC.drw_light_area_disk_lines = GPU_batch_create_ex(
+ GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_light_spot_square;
+ return SHC.drw_light_area_disk_lines;
}
-GPUBatch *DRW_cache_light_spot_square_volume_get(void)
+GPUBatch *DRW_cache_light_area_square_lines_get(void)
{
- if (!SHC.drw_light_spot_square_volume) {
- const float p[5][3] = {
- {0.0f, 0.0f, 0.0f},
- {1.0f, 1.0f, -1.0f},
- {1.0f, -1.0f, -1.0f},
- {-1.0f, -1.0f, -1.0f},
- {-1.0f, 1.0f, -1.0f},
- };
-
- uint v_idx = 0;
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ if (!SHC.drw_light_area_square_lines) {
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 12);
+ int v_len = 2 * (DIAMOND_NSEGMENTS * 3 + INNER_NSEGMENTS + OUTER_NSEGMENTS + 4 + 1);
+ GPU_vertbuf_data_alloc(vbo, v_len);
- /* piramid sides */
- for (int i = 1; i <= 4; i++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[((i + 1) % 4) + 1]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[(i % 4) + 1]);
+ const float r = 9.0f;
+ int v = 0;
+ /* Light Icon */
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
+ circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
+ circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
+ /* Light area */
+ int flag = VCLASS_LIGHT_AREA_SHAPE;
+ for (int a = 0; a < 4; a++) {
+ for (int b = 0; b < 2; b++) {
+ float p[4][2] = {{-1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, -1.0f}};
+ float x = p[(a + b) % 4][0];
+ float y = p[(a + b) % 4][1];
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x * 0.5f, y * 0.5f, 0.0f}, flag});
+ }
}
+ /* Direction Line */
+ float zsta = light_distance_z_get('z', true);
+ float zend = light_distance_z_get('z', false);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, zsta}, VCLASS_LIGHT_DIST});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, zend}, VCLASS_LIGHT_DIST});
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.2f, zsta, VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE);
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.2f, zend, VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE);
- SHC.drw_light_spot_square_volume = GPU_batch_create_ex(
- GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_light_area_square_lines = GPU_batch_create_ex(
+ GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_light_spot_square_volume;
+ return SHC.drw_light_area_square_lines;
}
+#undef CIRCLE_NSEGMENTS
+#undef OUTER_NSEGMENTS
+#undef INNER_NSEGMENTS
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1992,56 +1683,59 @@ GPUBatch *DRW_cache_lightprobe_cube_get(void)
GPUBatch *DRW_cache_lightprobe_grid_get(void)
{
if (!SHC.drw_lightprobe_grid) {
- int v_idx = 0;
- const float sin_pi_3 = 0.86602540378f;
- const float cos_pi_3 = 0.5f;
- const float v[7][3] = {
- {0.0f, 1.0f, 0.0f},
- {sin_pi_3, cos_pi_3, 0.0f},
- {sin_pi_3, -cos_pi_3, 0.0f},
- {0.0f, -1.0f, 0.0f},
- {-sin_pi_3, -cos_pi_3, 0.0f},
- {-sin_pi_3, cos_pi_3, 0.0f},
- {0.0f, 0.0f, 0.0f},
- };
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
+ int v_len = (6 * 2 + 3 + (1 + 2 * DIAMOND_NSEGMENTS) * 6) * 2;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, (6 * 2 + 3) * 2);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+ const float r = 14.0f;
+ int v = 0;
+ int flag = VCLASS_SCREENSPACE;
+ /* Icon */
+ const float sin_pi_3 = 0.86602540378f;
+ const float cos_pi_3 = 0.5f;
+ const float p[7][2] = {
+ {0.0f, 1.0f},
+ {sin_pi_3, cos_pi_3},
+ {sin_pi_3, -cos_pi_3},
+ {0.0f, -1.0f},
+ {-sin_pi_3, -cos_pi_3},
+ {-sin_pi_3, cos_pi_3},
+ {0.0f, 0.0f},
+ };
for (int i = 0; i < 6; i++) {
- float tmp_v1[3], tmp_v2[3], tmp_tr[3];
- copy_v3_v3(tmp_v1, v[i]);
- copy_v3_v3(tmp_v2, v[(i + 1) % 6]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
-
+ float t1[2], t2[2], tr[2];
+ copy_v2_v2(t1, p[i]);
+ copy_v2_v2(t2, p[(i + 1) % 6]);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{t1[0] * r, t1[1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{t2[0] * r, t2[1] * r, 0.0f}, flag});
/* Internal wires. */
for (int j = 1; j < 2; j++) {
- mul_v3_v3fl(tmp_tr, v[(i / 2) * 2 + 1], -0.5f * j);
- add_v3_v3v3(tmp_v1, v[i], tmp_tr);
- add_v3_v3v3(tmp_v2, v[(i + 1) % 6], tmp_tr);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
+ mul_v2_v2fl(tr, p[(i / 2) * 2 + 1], -0.5f * j);
+ add_v2_v2v2(t1, p[i], tr);
+ add_v2_v2v2(t2, p[(i + 1) % 6], tr);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{t1[0] * r, t1[1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{t2[0] * r, t2[1] * r, 0.0f}, flag});
}
}
-
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[1]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
-
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[5]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
-
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[3]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[1][0] * r, p[1][1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[6][0] * r, p[6][1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[5][0] * r, p[5][1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[6][0] * r, p[6][1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[3][0] * r, p[3][1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[6][0] * r, p[6][1] * r, 0.0f}, flag});
+ /* Direction Lines */
+ flag = VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE;
+ for (int i = 0; i < 6; i++) {
+ char axes[] = "zZyYxX";
+ float zsta = light_distance_z_get(axes[i], true);
+ float zend = light_distance_z_get(axes[i], false);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, zsta}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, zend}, flag});
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.2f, zsta, flag);
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.2f, zend, flag);
+ }
SHC.drw_lightprobe_grid = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
@@ -2051,30 +1745,28 @@ GPUBatch *DRW_cache_lightprobe_grid_get(void)
GPUBatch *DRW_cache_lightprobe_planar_get(void)
{
if (!SHC.drw_lightprobe_planar) {
- int v_idx = 0;
- const float sin_pi_3 = 0.86602540378f;
- const float v[4][3] = {
- {0.0f, 0.5f, 0.0f},
- {sin_pi_3, 0.0f, 0.0f},
- {0.0f, -0.5f, 0.0f},
- {-sin_pi_3, 0.0f, 0.0f},
- };
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
+ int v_len = 2 * 4;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 4 * 2);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+ const float r = 20.0f;
+ int v = 0;
+ /* Icon */
+ const float sin_pi_3 = 0.86602540378f;
+ const float p[4][2] = {
+ {0.0f, 0.5f},
+ {sin_pi_3, 0.0f},
+ {0.0f, -0.5f},
+ {-sin_pi_3, 0.0f},
+ };
for (int i = 0; i < 4; i++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 4]);
+ for (int a = 0; a < 2; a++) {
+ float x = p[(i + a) % 4][0] * r;
+ float y = p[(i + a) % 4][1] * r;
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, 0.0}, VCLASS_SCREENSPACE});
+ }
}
SHC.drw_lightprobe_planar = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
@@ -2251,123 +1943,6 @@ GPUBatch *DRW_cache_bone_octahedral_wire_get(void)
return SHC.drw_bone_octahedral_wire;
}
-/* XXX TODO move that 1 unit cube to more common/generic place? */
-static const float bone_box_verts[8][3] = {
- {1.0f, 0.0f, 1.0f},
- {1.0f, 0.0f, -1.0f},
- {-1.0f, 0.0f, -1.0f},
- {-1.0f, 0.0f, 1.0f},
- {1.0f, 1.0f, 1.0f},
- {1.0f, 1.0f, -1.0f},
- {-1.0f, 1.0f, -1.0f},
- {-1.0f, 1.0f, 1.0f},
-};
-
-static const float bone_box_smooth_normals[8][3] = {
- {M_SQRT3, -M_SQRT3, M_SQRT3},
- {M_SQRT3, -M_SQRT3, -M_SQRT3},
- {-M_SQRT3, -M_SQRT3, -M_SQRT3},
- {-M_SQRT3, -M_SQRT3, M_SQRT3},
- {M_SQRT3, M_SQRT3, M_SQRT3},
- {M_SQRT3, M_SQRT3, -M_SQRT3},
- {-M_SQRT3, M_SQRT3, -M_SQRT3},
- {-M_SQRT3, M_SQRT3, M_SQRT3},
-};
-
-#if 0 /* UNUSED */
-static const uint bone_box_wire[24] = {
- 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7,
-};
-
-/* aligned with bone_octahedral_wire
- * Contains adjacent normal index */
-static const uint bone_box_wire_adjacent_face[24] = {
- 0, 2, 0, 4, 1, 6, 1, 8, 3, 10, 5, 10, 7, 11, 9, 11, 3, 8, 2, 5, 4, 7, 6, 9,
-};
-#endif
-
-static const uint bone_box_solid_tris[12][3] = {
- {0, 2, 1}, /* bottom */
- {0, 3, 2},
-
- {0, 1, 5}, /* sides */
- {0, 5, 4},
-
- {1, 2, 6},
- {1, 6, 5},
-
- {2, 3, 7},
- {2, 7, 6},
-
- {3, 0, 4},
- {3, 4, 7},
-
- {4, 5, 6}, /* top */
- {4, 6, 7},
-};
-
-/**
- * Store indices of generated verts from bone_box_solid_tris to define adjacency infos.
- * See bone_octahedral_solid_tris for more infos.
- */
-static const uint bone_box_wire_lines_adjacency[12][4] = {
- {4, 2, 0, 11},
- {0, 1, 2, 8},
- {2, 4, 1, 14},
- {1, 0, 4, 20}, /* bottom */
- {0, 8, 11, 14},
- {2, 14, 8, 20},
- {1, 20, 14, 11},
- {4, 11, 20, 8}, /* top */
- {20, 0, 11, 2},
- {11, 2, 8, 1},
- {8, 1, 14, 4},
- {14, 4, 20, 0}, /* sides */
-};
-
-#if 0 /* UNUSED */
-static const uint bone_box_solid_tris_adjacency[12][6] = {
- {0, 5, 1, 14, 2, 8},
- {3, 26, 4, 20, 5, 1},
-
- {6, 2, 7, 16, 8, 11},
- {9, 7, 10, 32, 11, 24},
-
- {12, 0, 13, 22, 14, 17},
- {15, 13, 16, 30, 17, 6},
-
- {18, 3, 19, 28, 20, 23},
- {21, 19, 22, 33, 23, 12},
-
- {24, 4, 25, 10, 26, 29},
- {27, 25, 28, 34, 29, 18},
-
- {30, 9, 31, 15, 32, 35},
- {33, 31, 34, 21, 35, 27},
-};
-#endif
-
-/* aligned with bone_box_solid_tris */
-static const float bone_box_solid_normals[12][3] = {
- {0.0f, -1.0f, 0.0f},
- {0.0f, -1.0f, 0.0f},
-
- {1.0f, 0.0f, 0.0f},
- {1.0f, 0.0f, 0.0f},
-
- {0.0f, 0.0f, -1.0f},
- {0.0f, 0.0f, -1.0f},
-
- {-1.0f, 0.0f, 0.0f},
- {-1.0f, 0.0f, 0.0f},
-
- {0.0f, 0.0f, 1.0f},
- {0.0f, 0.0f, 1.0f},
-
- {0.0f, 1.0f, 0.0f},
- {0.0f, 1.0f, 0.0f},
-};
-
GPUBatch *DRW_cache_bone_box_get(void)
{
if (!SHC.drw_bone_box) {
@@ -2504,7 +2079,7 @@ GPUBatch *DRW_cache_bone_envelope_outline_get(void)
}
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL + 1);
v0[0] = radius * sinf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
v0[1] = radius * cosf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
@@ -2513,29 +2088,18 @@ GPUBatch *DRW_cache_bone_envelope_outline_get(void)
/* Output 4 verts for each position. See shader for explanation. */
uint v = 0;
- for (int a = 0; a < CIRCLE_RESOL; a++) {
+ for (int a = 0; a <= CIRCLE_RESOL; a++) {
v2[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
v2[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
- GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
copy_v2_v2(v0, v1);
copy_v2_v2(v1, v2);
}
- v2[0] = 0.0f;
- v2[1] = radius;
- GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
- GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
SHC.drw_bone_envelope_outline = GPU_batch_create_ex(
- GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
#undef CIRCLE_RESOL
}
return SHC.drw_bone_envelope_outline;
@@ -2624,44 +2188,30 @@ GPUBatch *DRW_cache_bone_point_wire_outline_get(void)
SHC.drw_bone_point_wire = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
#else
# define CIRCLE_RESOL 64
- float v0[2], v1[2];
const float radius = 0.05f;
/* Position Only 2D format */
static GPUVertFormat format = {0};
static struct {
- uint pos0, pos1;
+ uint pos;
} attr_id;
if (format.attr_len == 0) {
- attr_id.pos0 = GPU_vertformat_attr_add(&format, "pos0", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- attr_id.pos1 = GPU_vertformat_attr_add(&format, "pos1", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
}
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
-
- v0[0] = radius * sinf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
- v0[1] = radius * cosf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL + 1);
uint v = 0;
- for (int a = 0; a < CIRCLE_RESOL; a++) {
- v1[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v1[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
- copy_v2_v2(v0, v1);
+ for (int a = 0; a <= CIRCLE_RESOL; a++) {
+ float pos[2];
+ pos[0] = radius * sinf((2.0f * M_PI * a) / CIRCLE_RESOL);
+ pos[1] = radius * cosf((2.0f * M_PI * a) / CIRCLE_RESOL);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v++, pos);
}
- v1[0] = 0.0f;
- v1[1] = radius;
- GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
- GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
SHC.drw_bone_point_wire = GPU_batch_create_ex(
- GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
# undef CIRCLE_RESOL
#endif
}
@@ -2749,21 +2299,6 @@ GPUBatch *DRW_cache_bone_stick_get(void)
return SHC.drw_bone_stick;
}
-static void set_bone_axis_vert(GPUVertBuf *vbo,
- uint axis,
- uint pos,
- uint col,
- uint *v,
- const float *a,
- const float *p,
- const float *c)
-{
- GPU_vertbuf_attr_set(vbo, axis, *v, a);
- GPU_vertbuf_attr_set(vbo, pos, *v, p);
- GPU_vertbuf_attr_set(vbo, col, *v, c);
- *v += 1;
-}
-
#define S_X 0.0215f
#define S_Y 0.025f
static float x_axis_name[4][2] = {
@@ -2836,103 +2371,38 @@ static float axis_marker[8][2] = {
#undef S_X
#undef S_Y
-#define S_X 0.0007f
-#define S_Y 0.0007f
-#define O_X 0.001f
-#define O_Y -0.001f
-static float axis_name_shadow[8][2] = {
- {-S_X + O_X, S_Y + O_Y},
- {S_X + O_X, S_Y + O_Y},
- {S_X + O_X, S_Y + O_Y},
- {S_X + O_X, -S_Y + O_Y},
- {S_X + O_X, -S_Y + O_Y},
- {-S_X + O_X, -S_Y + O_Y},
- {-S_X + O_X, -S_Y + O_Y},
- {-S_X + O_X, S_Y + O_Y},
-};
-// #define SHADOW_RES (sizeof(axis_name_shadow) / (sizeof(float) * 2))
-#define SHADOW_RES 0
-#undef O_X
-#undef O_Y
-#undef S_X
-#undef S_Y
-
GPUBatch *DRW_cache_bone_arrows_get(void)
{
if (!SHC.drw_bone_arrows) {
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint axis, pos, col;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.axis = GPU_vertformat_attr_add(&format, "axis", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- attr_id.pos = GPU_vertformat_attr_add(
- &format, "screenPos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- attr_id.col = GPU_vertformat_attr_add(
- &format, "colorAxis", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
-
- /* Line */
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo,
- (2 + MARKER_LEN * MARKER_FILL_LAYER) * 3 +
- (X_LEN + Y_LEN + Z_LEN) * (1 + SHADOW_RES));
-
- uint v = 0;
+ int v_len = (2 + MARKER_LEN * MARKER_FILL_LAYER) * 3 + (X_LEN + Y_LEN + Z_LEN);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+ int v = 0;
for (int axis = 0; axis < 3; axis++) {
- float pos[2] = {0.0f, 0.0f};
- float c[3] = {0.0f, 0.0f, 0.0f};
- float a = 0.0f;
+ int flag = VCLASS_EMPTY_AXES | VCLASS_SCREENALIGNED;
+ /* Vertex layout is XY screen position and axis in Z.
+ * Fractional part of Z is a positive offset at axis unit position.*/
+ float p[3] = {0.0f, 0.0f, axis};
/* center to axis line */
- set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, pos, c);
- c[axis] = 0.5f;
- a = axis + 0.25f;
- set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, pos, c);
-
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, 0.0f}, 0});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[0], p[1], p[2]}, flag});
/* Axis end marker */
for (int j = 1; j < MARKER_FILL_LAYER + 1; j++) {
for (int i = 0; i < MARKER_LEN; i++) {
- float tmp[2];
- mul_v2_v2fl(tmp, axis_marker[i], j / (float)MARKER_FILL_LAYER);
- set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, tmp, c);
- }
- }
-
- a = axis + 0.31f;
- /* Axis name */
- int axis_v_len;
- float(*axis_verts)[2];
- if (axis == 0) {
- axis_verts = x_axis_name;
- axis_v_len = X_LEN;
- }
- else if (axis == 1) {
- axis_verts = y_axis_name;
- axis_v_len = Y_LEN;
- }
- else {
- axis_verts = z_axis_name;
- axis_v_len = Z_LEN;
- }
-
- /* Axis name shadows */
- copy_v3_fl(c, 0.0f);
- c[axis] = 0.3f;
- for (int j = 0; j < SHADOW_RES; j++) {
- for (int i = 0; i < axis_v_len; i++) {
- float tmp[2];
- add_v2_v2v2(tmp, axis_verts[i], axis_name_shadow[j]);
- set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, tmp, c);
+ mul_v2_v2fl(p, axis_marker[i], 4.0f * j / (float)MARKER_FILL_LAYER);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[0], p[1], p[2]}, flag});
}
}
-
/* Axis name */
- copy_v3_fl(c, 0.1f);
- c[axis] = 1.0f;
- for (int i = 0; i < axis_v_len; i++) {
- set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, axis_verts[i], c);
+ flag = VCLASS_EMPTY_AXES | VCLASS_EMPTY_AXES_NAME | VCLASS_SCREENALIGNED;
+ int axis_v_len[] = {X_LEN, Y_LEN, Z_LEN};
+ float(*axis_v)[2] = (axis == 0) ? x_axis_name : ((axis == 1) ? y_axis_name : z_axis_name);
+ p[2] = axis + 0.25f;
+ for (int i = 0; i < axis_v_len[axis]; i++) {
+ mul_v2_v2fl(p, axis_v[i], 4.0f);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[0], p[1], p[2]}, flag});
}
}
@@ -3060,185 +2530,155 @@ GPUBatch *DRW_cache_bone_dof_lines_get(void)
/** \name Camera
* \{ */
-/**
- * We could make these more generic functions.
- * although filling 1d lines is not common.
- *
- * \note Use x coordinate to identify the vertex the vertex shader take care to place it
- * appropriately.
- */
+GPUBatch *DRW_cache_camera_frame_get(void)
+{
+ if (!SHC.drw_camera_frame) {
+ GPUVertFormat format = extra_vert_format();
-static const float camera_coords_frame_bounds[5] = {
- 0.0f, /* center point */
- 1.0f, /* + X + Y */
- 2.0f, /* + X - Y */
- 3.0f, /* - X - Y */
- 4.0f, /* - X + Y */
-};
+ const int v_len = 2 * (4 + 4);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, v_len);
-static const float camera_coords_frame_tri[3] = {
- 5.0f, /* tria + X */
- 6.0f, /* tria - X */
- 7.0f, /* tria + Y */
-};
+ int v = 0;
+ float p[4][2] = {{-1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, -1.0f}};
+ /* Frame */
+ for (int a = 0; a < 4; a++) {
+ for (int b = 0; b < 2; b++) {
+ float x = p[(a + b) % 4][0];
+ float y = p[(a + b) % 4][1];
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, 1.0f}, VCLASS_CAMERA_FRAME});
+ }
+ }
+ /* Wires to origin. */
+ for (int a = 0; a < 4; a++) {
+ float x = p[a][0];
+ float y = p[a][1];
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, 1.0f}, VCLASS_CAMERA_FRAME});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, 0.0f}, VCLASS_CAMERA_FRAME});
+ }
-/** Draw a loop of lines. */
-static void camera_fill_lines_loop_fl_v1(GPUVertBufRaw *pos_step,
- const float *coords,
- const uint coords_len)
-{
- for (uint i = 0, i_prev = coords_len - 1; i < coords_len; i_prev = i++) {
- *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i_prev];
- *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i];
+ SHC.drw_camera_frame = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
+ return SHC.drw_camera_frame;
}
-/** Fan lines out from the first vertex. */
-static void camera_fill_lines_fan_fl_v1(GPUVertBufRaw *pos_step,
- const float *coords,
- const uint coords_len)
+GPUBatch *DRW_cache_camera_volume_get(void)
{
- for (uint i = 1; i < coords_len; i++) {
- *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[0];
- *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i];
- }
-}
+ if (!SHC.drw_camera_volume) {
+ GPUVertFormat format = extra_vert_format();
-/** Simply fill the array. */
-static void camera_fill_array_fl_v1(GPUVertBufRaw *pos_step,
- const float *coords,
- const uint coords_len)
-{
- for (uint i = 0; i < coords_len; i++) {
- *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i];
+ const int v_len = ARRAY_SIZE(bone_box_solid_tris) * 3;
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+
+ int v = 0;
+ int flag = VCLASS_CAMERA_FRAME | VCLASS_CAMERA_VOLUME;
+ for (int i = 0; i < ARRAY_SIZE(bone_box_solid_tris); i++) {
+ for (int a = 0; a < 3; a++) {
+ float x = bone_box_verts[bone_box_solid_tris[i][a]][2];
+ float y = bone_box_verts[bone_box_solid_tris[i][a]][0];
+ float z = bone_box_verts[bone_box_solid_tris[i][a]][1];
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, z}, flag});
+ }
+ }
+
+ SHC.drw_camera_volume = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
+ return SHC.drw_camera_volume;
}
-GPUBatch *DRW_cache_camera_get(void)
+GPUBatch *DRW_cache_camera_volume_wire_get(void)
{
- if (!SHC.drw_camera) {
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
+ if (!SHC.drw_camera_volume_wire) {
+ GPUVertFormat format = extra_vert_format();
- /* Vertices */
+ const int v_len = ARRAY_SIZE(bone_box_wire);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- const int vbo_len_capacity = 22;
- GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
- GPUVertBufRaw pos_step;
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
-
- /* camera cone (from center to frame) */
- camera_fill_lines_fan_fl_v1(
- &pos_step, camera_coords_frame_bounds, ARRAY_SIZE(camera_coords_frame_bounds));
+ GPU_vertbuf_data_alloc(vbo, v_len);
- /* camera frame (skip center) */
- camera_fill_lines_loop_fl_v1(
- &pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1);
-
- /* camera triangle (above the frame) */
- camera_fill_lines_loop_fl_v1(
- &pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri));
-
- BLI_assert(vbo_len_capacity == GPU_vertbuf_raw_used(&pos_step));
+ int v = 0;
+ int flag = VCLASS_CAMERA_FRAME | VCLASS_CAMERA_VOLUME;
+ for (int i = 0; i < ARRAY_SIZE(bone_box_wire); i++) {
+ float x = bone_box_verts[bone_box_wire[i]][2];
+ float y = bone_box_verts[bone_box_wire[i]][0];
+ float z = bone_box_verts[bone_box_wire[i]][1];
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, z}, flag});
+ }
- SHC.drw_camera = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_camera_volume_wire = GPU_batch_create_ex(
+ GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_camera;
+ return SHC.drw_camera_volume_wire;
}
-GPUBatch *DRW_cache_camera_frame_get(void)
+GPUBatch *DRW_cache_camera_tria_wire_get(void)
{
- if (!SHC.drw_camera_frame) {
+ if (!SHC.drw_camera_tria_wire) {
+ GPUVertFormat format = extra_vert_format();
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
-
- /* Vertices */
+ const int v_len = 2 * 3;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- const int vbo_len_capacity = 8;
- GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
- GPUVertBufRaw pos_step;
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+ GPU_vertbuf_data_alloc(vbo, v_len);
- /* camera frame (skip center) */
- camera_fill_lines_loop_fl_v1(
- &pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1);
-
- BLI_assert(vbo_len_capacity == GPU_vertbuf_raw_used(&pos_step));
+ int v = 0;
+ float p[3][2] = {{-1.0f, 1.0f}, {1.0f, 1.0f}, {0.0f, 0.0f}};
+ for (int a = 0; a < 3; a++) {
+ for (int b = 0; b < 2; b++) {
+ float x = p[(a + b) % 3][0];
+ float y = p[(a + b) % 3][1];
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, 1.0f}, VCLASS_CAMERA_FRAME});
+ }
+ }
- SHC.drw_camera_frame = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_camera_tria_wire = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_camera_frame;
+ return SHC.drw_camera_tria_wire;
}
GPUBatch *DRW_cache_camera_tria_get(void)
{
if (!SHC.drw_camera_tria) {
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
+ GPUVertFormat format = extra_vert_format();
- /* Vertices */
+ const int v_len = 3;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- const int vbo_len_capacity = 3;
- GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
- GPUVertBufRaw pos_step;
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
-
- /* camera triangle (above the frame) */
- camera_fill_array_fl_v1(
- &pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri));
+ GPU_vertbuf_data_alloc(vbo, v_len);
- BLI_assert(vbo_len_capacity == GPU_vertbuf_raw_used(&pos_step));
+ int v = 0;
+ /* Use camera frame position */
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{-1.0f, 1.0f, 1.0f}, VCLASS_CAMERA_FRAME});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{1.0f, 1.0f, 1.0f}, VCLASS_CAMERA_FRAME});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, 1.0f}, VCLASS_CAMERA_FRAME});
SHC.drw_camera_tria = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_camera_tria;
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Object Mode Helpers
- * \{ */
-
-/* Object Center */
-GPUBatch *DRW_cache_single_vert_get(void)
+GPUBatch *DRW_cache_camera_distances_get(void)
{
- if (!SHC.drw_single_vertice) {
- float v1[3] = {0.0f, 0.0f, 0.0f};
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
+ if (!SHC.drw_camera_distances) {
+ GPUVertFormat format = extra_vert_format();
+ const int v_len = 2 * (1 + DIAMOND_NSEGMENTS * 2 + 2);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, 1);
+ GPU_vertbuf_data_alloc(vbo, v_len);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
+ int v = 0;
+ /* Direction Line */
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, 0.0}, VCLASS_CAMERA_DIST});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, 1.0}, VCLASS_CAMERA_DIST});
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.5f, 0.0f, VCLASS_CAMERA_DIST | VCLASS_SCREENSPACE);
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.5f, 1.0f, VCLASS_CAMERA_DIST | VCLASS_SCREENSPACE);
+ /* Focus cross */
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{1.0, 0.0, 2.0}, VCLASS_CAMERA_DIST});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{-1.0, 0.0, 2.0}, VCLASS_CAMERA_DIST});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 1.0, 2.0}, VCLASS_CAMERA_DIST});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, -1.0, 2.0}, VCLASS_CAMERA_DIST});
- SHC.drw_single_vertice = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ SHC.drw_camera_distances = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
- return SHC.drw_single_vertice;
+ return SHC.drw_camera_distances;
}
/** \} */
@@ -3498,10 +2938,14 @@ GPUBatch **DRW_cache_mball_surface_shaded_get(Object *ob,
GPUBatch *DRW_cache_text_edge_wire_get(Object *ob)
{
BLI_assert(ob->type == OB_FONT);
-
struct Curve *cu = ob->data;
struct Mesh *mesh_eval = ob->runtime.mesh_eval;
- if (mesh_eval != NULL) {
+ const bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f ||
+ cu->ext2 != 0.0f;
+ if (!has_surface) {
+ return NULL;
+ }
+ else if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
}
else {
@@ -3767,46 +3211,18 @@ GPUBatch *DRW_cache_particles_get_prim(int type)
switch (type) {
case PART_DRAW_CROSS:
if (!SHC.drw_particle_cross) {
- static GPUVertFormat format = {0};
- static uint pos_id, axis_id;
-
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "inst_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- axis_id = GPU_vertformat_attr_add(&format, "axis", GPU_COMP_I32, 1, GPU_FETCH_INT);
- }
-
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 6);
- /* X axis */
- float co[3] = {-1.0f, 0.0f, 0.0f};
- int axis = -1;
- GPU_vertbuf_attr_set(vbo, pos_id, 0, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 0, &axis);
-
- co[0] = 1.0f;
- GPU_vertbuf_attr_set(vbo, pos_id, 1, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 1, &axis);
-
- /* Y axis */
- co[0] = 0.0f;
- co[1] = -1.0f;
- GPU_vertbuf_attr_set(vbo, pos_id, 2, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 2, &axis);
-
- co[1] = 1.0f;
- GPU_vertbuf_attr_set(vbo, pos_id, 3, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 3, &axis);
-
- /* Z axis */
- co[1] = 0.0f;
- co[2] = -1.0f;
- GPU_vertbuf_attr_set(vbo, pos_id, 4, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 4, &axis);
-
- co[2] = 1.0f;
- GPU_vertbuf_attr_set(vbo, pos_id, 5, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 5, &axis);
+ int v = 0;
+ int flag = 0;
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, -1.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 1.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{-1.0f, 0.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{1.0f, 0.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, -1.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, 1.0f}, flag});
SHC.drw_particle_cross = GPU_batch_create_ex(
GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
@@ -3815,46 +3231,19 @@ GPUBatch *DRW_cache_particles_get_prim(int type)
return SHC.drw_particle_cross;
case PART_DRAW_AXIS:
if (!SHC.drw_particle_axis) {
- static GPUVertFormat format = {0};
- static uint pos_id, axis_id;
-
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "inst_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- axis_id = GPU_vertformat_attr_add(&format, "axis", GPU_COMP_I32, 1, GPU_FETCH_INT);
- }
-
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 6);
- /* X axis */
- float co[3] = {0.0f, 0.0f, 0.0f};
- int axis = 0;
- GPU_vertbuf_attr_set(vbo, pos_id, 0, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 0, &axis);
-
- co[0] = 1.0f;
- GPU_vertbuf_attr_set(vbo, pos_id, 1, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 1, &axis);
-
- /* Y axis */
- co[0] = 0.0f;
- axis = 1;
- GPU_vertbuf_attr_set(vbo, pos_id, 2, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 2, &axis);
-
- co[1] = 1.0f;
- GPU_vertbuf_attr_set(vbo, pos_id, 3, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 3, &axis);
-
- /* Z axis */
- co[1] = 0.0f;
- axis = 2;
- GPU_vertbuf_attr_set(vbo, pos_id, 4, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 4, &axis);
-
- co[2] = 1.0f;
- GPU_vertbuf_attr_set(vbo, pos_id, 5, co);
- GPU_vertbuf_attr_set(vbo, axis_id, 5, &axis);
+ int v = 0;
+ int flag = VCLASS_EMPTY_AXES;
+ /* Set minimum to 0.001f so we can easilly normalize to get the color. */
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0001f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 2.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0001f, 0.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{2.0f, 0.0f, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, 0.0001f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, 2.0f}, flag});
SHC.drw_particle_axis = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
@@ -3863,30 +3252,21 @@ GPUBatch *DRW_cache_particles_get_prim(int type)
case PART_DRAW_CIRC:
#define CIRCLE_RESOL 32
if (!SHC.drw_particle_circle) {
- float v[3] = {0.0f, 0.0f, 0.0f};
- int axis = -1;
-
- static GPUVertFormat format = {0};
- static uint pos_id, axis_id;
-
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "inst_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- axis_id = GPU_vertformat_attr_add(&format, "axis", GPU_COMP_I32, 1, GPU_FETCH_INT);
- }
-
+ GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
-
- for (int a = 0; a < CIRCLE_RESOL; a++) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
- v[2] = 0.0f;
- GPU_vertbuf_attr_set(vbo, pos_id, a, v);
- GPU_vertbuf_attr_set(vbo, axis_id, a, &axis);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL + 1);
+
+ int v = 0;
+ int flag = VCLASS_SCREENALIGNED;
+ for (int a = 0; a <= CIRCLE_RESOL; a++) {
+ float angle = (2.0f * M_PI * a) / CIRCLE_RESOL;
+ float x = sinf(angle);
+ float y = cosf(angle);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{x, y, 0.0f}, flag});
}
SHC.drw_particle_circle = GPU_batch_create_ex(
- GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_particle_circle;
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 273e97c6e49..11564464546 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -37,16 +37,15 @@ void DRW_shape_cache_reset(void);
struct GPUBatch *DRW_cache_cursor_get(bool crosshair_lines);
/* Common Shapes */
+struct GPUBatch *DRW_cache_groundline_get(void);
struct GPUBatch *DRW_cache_grid_get(void);
struct GPUBatch *DRW_cache_fullscreen_quad_get(void);
struct GPUBatch *DRW_cache_quad_get(void);
struct GPUBatch *DRW_cache_quad_wires_get(void);
struct GPUBatch *DRW_cache_cube_get(void);
struct GPUBatch *DRW_cache_sphere_get(void);
-struct GPUBatch *DRW_cache_single_vert_get(void);
-struct GPUBatch *DRW_cache_single_line_get(void);
-struct GPUBatch *DRW_cache_single_line_endpoints_get(void);
struct GPUBatch *DRW_cache_screenspace_circle_get(void);
+struct GPUBatch *DRW_cache_normal_arrow_get(void);
/* Common Object */
struct GPUBatch *DRW_cache_object_all_edges_get(struct Object *ob);
@@ -66,41 +65,36 @@ struct GPUBatch *DRW_cache_plain_axes_get(void);
struct GPUBatch *DRW_cache_single_arrow_get(void);
struct GPUBatch *DRW_cache_empty_cube_get(void);
struct GPUBatch *DRW_cache_circle_get(void);
-struct GPUBatch *DRW_cache_square_get(void);
struct GPUBatch *DRW_cache_empty_sphere_get(void);
struct GPUBatch *DRW_cache_empty_cylinder_get(void);
struct GPUBatch *DRW_cache_empty_cone_get(void);
struct GPUBatch *DRW_cache_empty_capsule_cap_get(void);
struct GPUBatch *DRW_cache_empty_capsule_body_get(void);
-struct GPUBatch *DRW_cache_image_plane_get(void);
-struct GPUBatch *DRW_cache_image_plane_wire_get(void);
/* Force Field */
struct GPUBatch *DRW_cache_field_wind_get(void);
struct GPUBatch *DRW_cache_field_force_get(void);
struct GPUBatch *DRW_cache_field_vortex_get(void);
+struct GPUBatch *DRW_cache_field_curve_get(void);
struct GPUBatch *DRW_cache_field_tube_limit_get(void);
struct GPUBatch *DRW_cache_field_cone_limit_get(void);
-
-/* Grease Pencil */
-struct GPUBatch *DRW_cache_gpencil_axes_get(void);
+struct GPUBatch *DRW_cache_field_sphere_limit_get(void);
/* Lights */
-struct GPUBatch *DRW_cache_light_get(void);
-struct GPUBatch *DRW_cache_light_shadows_get(void);
-struct GPUBatch *DRW_cache_light_sunrays_get(void);
-struct GPUBatch *DRW_cache_light_area_square_get(void);
-struct GPUBatch *DRW_cache_light_area_disk_get(void);
-struct GPUBatch *DRW_cache_light_hemi_get(void);
-struct GPUBatch *DRW_cache_light_spot_get(void);
+struct GPUBatch *DRW_cache_light_point_lines_get(void);
+struct GPUBatch *DRW_cache_light_sun_lines_get(void);
+struct GPUBatch *DRW_cache_light_spot_lines_get(void);
+struct GPUBatch *DRW_cache_light_area_disk_lines_get(void);
+struct GPUBatch *DRW_cache_light_area_square_lines_get(void);
struct GPUBatch *DRW_cache_light_spot_volume_get(void);
-struct GPUBatch *DRW_cache_light_spot_square_get(void);
-struct GPUBatch *DRW_cache_light_spot_square_volume_get(void);
/* Camera */
-struct GPUBatch *DRW_cache_camera_get(void);
struct GPUBatch *DRW_cache_camera_frame_get(void);
+struct GPUBatch *DRW_cache_camera_volume_get(void);
+struct GPUBatch *DRW_cache_camera_volume_wire_get(void);
+struct GPUBatch *DRW_cache_camera_tria_wire_get(void);
struct GPUBatch *DRW_cache_camera_tria_get(void);
+struct GPUBatch *DRW_cache_camera_distances_get(void);
/* Speaker */
struct GPUBatch *DRW_cache_speaker_get(void);
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index b1eab3c73ae..7ee02c3c556 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -115,8 +115,9 @@ typedef struct MeshBufferCache {
* Only need to be updated when topology changes. */
struct {
/* Indices to vloops. */
- GPUIndexBuf *tris; /* Ordered per material. */
- GPUIndexBuf *lines; /* Loose edges last. */
+ GPUIndexBuf *tris; /* Ordered per material. */
+ GPUIndexBuf *lines; /* Loose edges last. */
+ GPUIndexBuf *lines_loose; /* sub buffer of `lines` only containing the loose edges. */
GPUIndexBuf *points;
GPUIndexBuf *fdots;
/* 3D overlays. */
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index 7bc5c0ca91e..711be9ee776 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -634,20 +634,10 @@ static void extract_lines_ledge_mesh(const MeshRenderData *mr,
GPU_indexbuf_set_line_restart(elb, edge_idx);
}
-static void extract_lines_finish(const MeshRenderData *mr, void *ibo, void *elb)
+static void extract_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb)
{
GPU_indexbuf_build_in_place(elb, ibo);
MEM_freeN(elb);
- /* HACK Create ibo subranges and assign them to GPUBatch. */
- if (mr->use_final_mesh && mr->cache->batch.loose_edges) {
- BLI_assert(mr->cache->batch.loose_edges->elem == ibo);
- /* Multiply by 2 because these are edges indices. */
- int start = mr->edge_len * 2;
- int len = mr->edge_loose_len * 2;
- GPUIndexBuf *sub_ibo = GPU_indexbuf_create_subrange(ibo, start, len);
- /* WARNING: We modify the GPUBatch here! */
- GPU_batch_elembuf_set(mr->cache->batch.loose_edges, sub_ibo, true);
- }
}
static const MeshExtract extract_lines = {
@@ -668,6 +658,68 @@ static const MeshExtract extract_lines = {
/** \} */
/* ---------------------------------------------------------------------- */
+/** \name Extract Loose Edges Indices
+ * \{ */
+
+static void *extract_lines_loose_init(const MeshRenderData *UNUSED(mr), void *UNUSED(buf))
+{
+ return NULL;
+}
+
+static void extract_lines_loose_ledge_mesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(e),
+ const MEdge *UNUSED(medge),
+ void *UNUSED(elb))
+{
+ /* This function is intentionally empty. The existence of this functions ensures that
+ * `iter_type` `MR_ITER_LVERT` is set when initializing the `MeshRenderData` (See
+ * `mesh_extract_iter_type`). This flag ensures that `mr->edge_loose_len` field is filled. This
+ * field we use in the `extract_lines_loose_finish` function to create a subrange from the
+ * `ibo.lines`. */
+}
+
+static void extract_lines_loose_ledge_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(e),
+ BMEdge *UNUSED(eed),
+ void *UNUSED(elb))
+{
+ /* This function is intentionally empty. The existence of this functions ensures that
+ * `iter_type` `MR_ITER_LVERT` is set when initializing the `MeshRenderData` (See
+ * `mesh_extract_iter_type`). This flag ensures that `mr->edge_loose_len` field is filled. This
+ * field we use in the `extract_lines_loose_finish` function to create a subrange from the
+ * `ibo.lines`. */
+}
+
+static void extract_lines_loose_finish(const MeshRenderData *mr,
+ void *UNUSED(ibo),
+ void *UNUSED(elb))
+{
+ /* Multiply by 2 because these are edges indices. */
+ const int start = mr->edge_len * 2;
+ const int len = mr->edge_loose_len * 2;
+ GPU_indexbuf_create_subrange_in_place(
+ mr->cache->final.ibo.lines_loose, mr->cache->final.ibo.lines, start, len);
+ mr->cache->no_loose_wire = (len == 0);
+}
+
+static const MeshExtract extract_lines_loose = {
+ extract_lines_loose_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_lines_loose_ledge_bmesh,
+ extract_lines_loose_ledge_mesh,
+ NULL,
+ NULL,
+ extract_lines_loose_finish,
+ 0,
+ false,
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
/** \name Extract Point Indices
* \{ */
@@ -2681,7 +2733,7 @@ static void *extract_stretch_area_init(const MeshRenderData *mr, void *buf)
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPUVertBuf *vbo = buf;
@@ -2748,7 +2800,7 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *
/* Convert in place to avoid an extra allocation */
uint16_t *poly_stretch = (uint16_t *)area_ratio;
for (int p = 0; p < mr->poly_len; p++) {
- poly_stretch[p] = area_ratio[p] * 65534.0f;
+ poly_stretch[p] = area_ratio[p] * SHRT_MAX;
}
/* Copy face data for each loop. */
@@ -4369,6 +4421,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
TEST_ASSIGN(IBO, ibo, fdots);
TEST_ASSIGN(IBO, ibo, lines_paint_mask);
TEST_ASSIGN(IBO, ibo, lines_adjacency);
+ TEST_ASSIGN(IBO, ibo, lines_loose);
TEST_ASSIGN(IBO, ibo, edituv_tris);
TEST_ASSIGN(IBO, ibo, edituv_lines);
TEST_ASSIGN(IBO, ibo, edituv_points);
@@ -4442,14 +4495,22 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
EXTRACT(ibo, edituv_points);
EXTRACT(ibo, edituv_fdots);
-#undef EXTRACT
-
/* TODO(fclem) Ideally, we should have one global pool for all
* objects and wait for finish only before drawing when buffers
* need to be ready. */
BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
+ /* The next task(s) rely on the result of the tasks above. */
+
+ /* The `lines_loose` is a sub buffer from `ibo.lines`.
+ * We schedule it here due to potential synchronization issues.*/
+ EXTRACT(ibo, lines_loose);
+
+ BLI_task_pool_work_and_wait(task_pool);
+
+#undef EXTRACT
+
+ BLI_task_pool_free(task_pool);
MEM_freeN(task_counters);
mesh_render_data_free(mr);
diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c
index 01cd2b52ae3..8e5e22a4bcd 100644
--- a/source/blender/draw/intern/draw_cache_impl_lattice.c
+++ b/source/blender/draw/intern/draw_cache_impl_lattice.c
@@ -212,62 +212,6 @@ static const BPoint *lattice_render_data_vert_bpoint(const LatticeRenderData *rd
return &rdata->bp[vert_idx];
}
-/* TODO, move into shader? */
-static void rgb_from_weight(float r_rgb[3], const float weight)
-{
- const float blend = ((weight / 2.0f) + 0.5f);
-
- if (weight <= 0.25f) { /* blue->cyan */
- r_rgb[0] = 0.0f;
- r_rgb[1] = blend * weight * 4.0f;
- r_rgb[2] = blend;
- }
- else if (weight <= 0.50f) { /* cyan->green */
- r_rgb[0] = 0.0f;
- r_rgb[1] = blend;
- r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f));
- }
- else if (weight <= 0.75f) { /* green->yellow */
- r_rgb[0] = blend * ((weight - 0.50f) * 4.0f);
- r_rgb[1] = blend;
- r_rgb[2] = 0.0f;
- }
- else if (weight <= 1.0f) { /* yellow->red */
- r_rgb[0] = blend;
- r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f));
- r_rgb[2] = 0.0f;
- }
- else {
- /* exceptional value, unclamped or nan,
- * avoid uninitialized memory use */
- r_rgb[0] = 1.0f;
- r_rgb[1] = 0.0f;
- r_rgb[2] = 1.0f;
- }
-}
-
-static void lattice_render_data_weight_col_get(const LatticeRenderData *rdata,
- const int vert_idx,
- const int actdef,
- float r_col[4])
-{
- if (actdef > -1) {
- float weight = defvert_find_weight(rdata->dvert + vert_idx, actdef);
-
- if (U.flag & USER_CUSTOM_RANGE) {
- BKE_colorband_evaluate(&U.coba_weight, weight, r_col);
- }
- else {
- rgb_from_weight(r_col, weight);
- }
-
- r_col[3] = 1.0f;
- }
- else {
- zero_v4(r_col);
- }
-}
-
/* ---------------------------------------------------------------------- */
/* Lattice GPUBatch Cache */
@@ -402,18 +346,14 @@ static GPUVertBuf *lattice_batch_cache_get_pos(LatticeRenderData *rdata,
BLI_assert(rdata->types & LR_DATATYPE_VERT);
if (cache->pos == NULL) {
- static GPUVertFormat format = {0};
- static struct {
+ GPUVertFormat format = {0};
+ struct {
uint pos, col;
} attr_id;
- GPU_vertformat_clear(&format);
-
- /* initialize vertex format */
attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
if (use_weight) {
- attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ attr_id.col = GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
const int vert_len = lattice_render_data_verts_len_get(rdata);
@@ -425,11 +365,10 @@ static GPUVertBuf *lattice_batch_cache_get_pos(LatticeRenderData *rdata,
GPU_vertbuf_attr_set(cache->pos, attr_id.pos, i, bp->vec);
if (use_weight) {
- float w_col[4];
- lattice_render_data_weight_col_get(rdata, i, actdef, w_col);
- w_col[3] = 1.0f;
-
- GPU_vertbuf_attr_set(cache->pos, attr_id.col, i, w_col);
+ const float no_active_weight = 666.0f;
+ float weight = (actdef > -1) ? defvert_find_weight(rdata->dvert + i, actdef) :
+ no_active_weight;
+ GPU_vertbuf_attr_set(cache->pos, attr_id.col, i, &weight);
}
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index ca185fa7d7d..7c7178eae85 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -1228,7 +1228,8 @@ void DRW_mesh_batch_cache_create_requested(
DRW_vbo_request(cache->batch.all_edges, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.loose_edges, &mbufcache->ibo.lines);
+ DRW_ibo_request(NULL, &mbufcache->ibo.lines);
+ DRW_ibo_request(cache->batch.loose_edges, &mbufcache->ibo.lines_loose);
DRW_vbo_request(cache->batch.loose_edges, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) {
@@ -1326,17 +1327,8 @@ void DRW_mesh_batch_cache_create_requested(
DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_pos);
DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_nor);
}
- if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_LINES)) {
+ if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache->batch.edit_skin_roots, &mbufcache->vbo.skin_roots);
- /* HACK(fclem): This is to workaround the deferred batch init
- * that prevent drawing using DRW_shgroup_call_instances_with_attribs.
- * So we instead create the whole instancing batch here.
- * Note that we use GPU_PRIM_LINES instead of expected GPU_PRIM_LINE_STRIP
- * in order to mimic the old stipple pattern. */
- cache->batch.edit_skin_roots->inst = cache->batch.edit_skin_roots->verts[0];
- cache->batch.edit_skin_roots->verts[0] = NULL;
- GPUBatch *circle = DRW_cache_screenspace_circle_get();
- GPU_batch_vertbuf_add(cache->batch.edit_skin_roots, circle->verts[0]);
}
/* Selection */
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 3c586e6daec..0a9984762b0 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -1339,9 +1339,9 @@ static void particle_batch_cache_ensure_pos(Object *object,
if (format.attr_len == 0) {
/* initialize vertex format */
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- rot_id = GPU_vertformat_attr_add(&format, "rot", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- val_id = GPU_vertformat_attr_add(&format, "val", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ pos_id = GPU_vertformat_attr_add(&format, "part_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ val_id = GPU_vertformat_attr_add(&format, "part_val", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ rot_id = GPU_vertformat_attr_add(&format, "part_rot", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
}
point_cache->pos = GPU_vertbuf_create_with_format(&format);
diff --git a/source/blender/draw/intern/draw_cache_inline.h b/source/blender/draw/intern/draw_cache_inline.h
index 12dc0a47a68..f14d23dafcf 100644
--- a/source/blender/draw/intern/draw_cache_inline.h
+++ b/source/blender/draw/intern/draw_cache_inline.h
@@ -72,8 +72,10 @@ BLI_INLINE void DRW_ibo_request(GPUBatch *batch, GPUIndexBuf **ibo)
if (*ibo == NULL) {
*ibo = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
}
- GPU_batch_vao_cache_clear(batch);
- batch->elem = *ibo;
+ if (batch != NULL) {
+ GPU_batch_vao_cache_clear(batch);
+ batch->elem = *ibo;
+ }
}
BLI_INLINE bool DRW_ibo_requested(GPUIndexBuf *ibo)
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index c04425ded3f..65365ef7119 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -64,6 +64,7 @@ void DRW_globals_update(void)
UI_GetThemeColor4fv(TH_LIGHT, gb->colorLight);
UI_GetThemeColor4fv(TH_SPEAKER, gb->colorSpeaker);
UI_GetThemeColor4fv(TH_CAMERA, gb->colorCamera);
+ UI_GetThemeColor4fv(TH_CAMERA_PATH, gb->colorCameraPath);
UI_GetThemeColor4fv(TH_EMPTY, gb->colorEmpty);
UI_GetThemeColor4fv(TH_VERTEX, gb->colorVertex);
UI_GetThemeColor4fv(TH_VERTEX_SELECT, gb->colorVertexSelect);
@@ -79,6 +80,8 @@ void DRW_globals_update(void)
UI_GetThemeColor4fv(TH_EDGE_FACESEL, gb->colorEdgeFaceSelect);
UI_GetThemeColor4fv(TH_FACE, gb->colorFace);
UI_GetThemeColor4fv(TH_FACE_SELECT, gb->colorFaceSelect);
+ UI_GetThemeColor4fv(TH_FACE_BACK, gb->colorFaceBack);
+ UI_GetThemeColor4fv(TH_FACE_FRONT, gb->colorFaceFront);
UI_GetThemeColor4fv(TH_NORMAL, gb->colorNormal);
UI_GetThemeColor4fv(TH_VNORMAL, gb->colorVNormal);
UI_GetThemeColor4fv(TH_LNORMAL, gb->colorLNormal);
@@ -145,6 +148,8 @@ void DRW_globals_update(void)
UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, gb->colorOutline);
UI_GetThemeColorShadeAlpha4fv(TH_LIGHT, 0, 255, gb->colorLightNoAlpha);
+ gb->sizePixel = U.pixelsize;
+ gb->sizeObjectCenter = (UI_GetThemeValuef(TH_OBCENTER_DIA) + 1.0f) * U.pixelsize;
gb->sizeLightCenter = (UI_GetThemeValuef(TH_OBCENTER_DIA) + 1.5f) * U.pixelsize;
gb->sizeLightCircle = U.pixelsize * 9.0f;
gb->sizeLightCircleShadow = gb->sizeLightCircle + U.pixelsize * 3.0f;
@@ -156,6 +161,17 @@ void DRW_globals_update(void)
gb->sizeEdge = U.pixelsize * (1.0f / 2.0f); /* TODO Theme */
gb->sizeEdgeFix = U.pixelsize * (0.5f + 2.0f * (2.0f * (gb->sizeEdge * (float)M_SQRT1_2)));
+ const float(*screen_vecs)[3] = (float(*)[3])DRW_viewport_screenvecs_get();
+ for (int i = 0; i < 2; i++) {
+ copy_v3_v3(gb->screenVecs[i], screen_vecs[i]);
+ }
+
+ gb->pixelFac = *DRW_viewport_pixelsize_get();
+
+ copy_v2_v2(gb->sizeViewport, DRW_viewport_size_get());
+ copy_v2_v2(gb->sizeViewportInv, gb->sizeViewport);
+ invert_v2(gb->sizeViewportInv);
+
/* Color management. */
if (!DRW_state_do_color_management()) {
float *color = gb->UBO_FIRST_COLOR;
@@ -213,912 +229,18 @@ void DRW_globals_update(void)
/* ********************************* SHGROUP ************************************* */
-extern char datatoc_animviz_mpath_lines_vert_glsl[];
-extern char datatoc_animviz_mpath_lines_geom_glsl[];
-extern char datatoc_animviz_mpath_points_vert_glsl[];
-
-extern char datatoc_volume_velocity_vert_glsl[];
-
-extern char datatoc_armature_axes_vert_glsl[];
-extern char datatoc_armature_sphere_solid_vert_glsl[];
-extern char datatoc_armature_sphere_solid_frag_glsl[];
-extern char datatoc_armature_sphere_outline_vert_glsl[];
-extern char datatoc_armature_envelope_solid_vert_glsl[];
-extern char datatoc_armature_envelope_solid_frag_glsl[];
-extern char datatoc_armature_envelope_outline_vert_glsl[];
-extern char datatoc_armature_envelope_distance_frag_glsl[];
-extern char datatoc_armature_shape_solid_vert_glsl[];
-extern char datatoc_armature_shape_solid_frag_glsl[];
-extern char datatoc_armature_shape_outline_vert_glsl[];
-extern char datatoc_armature_shape_outline_geom_glsl[];
-extern char datatoc_armature_stick_vert_glsl[];
-extern char datatoc_armature_stick_frag_glsl[];
-extern char datatoc_armature_dof_vert_glsl[];
-
-extern char datatoc_common_globals_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-extern char datatoc_gpu_shader_flat_color_frag_glsl[];
-extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
-extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
-
-extern char datatoc_object_mball_handles_vert_glsl[];
-extern char datatoc_object_empty_axes_vert_glsl[];
-extern char datatoc_object_color_axes_vert_glsl[];
-
-typedef struct COMMON_Shaders {
- struct GPUShader *shape_outline;
- struct GPUShader *shape_solid;
- struct GPUShader *bone_axes;
- struct GPUShader *bone_envelope;
- struct GPUShader *bone_envelope_distance;
- struct GPUShader *bone_envelope_outline;
- struct GPUShader *bone_sphere;
- struct GPUShader *bone_sphere_outline;
- struct GPUShader *bone_stick;
- struct GPUShader *bone_dofs;
-
- struct GPUShader *mpath_line_sh;
- struct GPUShader *mpath_points_sh;
-
- struct GPUShader *volume_velocity_needle_sh;
- struct GPUShader *volume_velocity_sh;
- struct GPUShader *empty_axes_sh;
- struct GPUShader *color_axes_sh;
-
- struct GPUShader *mball_handles;
-} COMMON_Shaders;
-
-static COMMON_Shaders g_shaders[GPU_SHADER_CFG_LEN] = {{NULL}};
-
-static struct {
- struct GPUVertFormat *instance_screenspace;
- struct GPUVertFormat *instance_color;
- struct GPUVertFormat *instance_screen_aligned;
- struct GPUVertFormat *instance_scaled;
- struct GPUVertFormat *instance_sized;
- struct GPUVertFormat *instance_outline;
- struct GPUVertFormat *instance_camera;
- struct GPUVertFormat *instance_distance_lines;
- struct GPUVertFormat *instance_spot;
- struct GPUVertFormat *instance_bone;
- struct GPUVertFormat *instance_bone_dof;
- struct GPUVertFormat *instance_bone_stick;
- struct GPUVertFormat *instance_bone_outline;
- struct GPUVertFormat *instance_bone_envelope;
- struct GPUVertFormat *instance_bone_envelope_distance;
- struct GPUVertFormat *instance_bone_envelope_outline;
- struct GPUVertFormat *instance_mball_handles;
- struct GPUVertFormat *pos_color;
- struct GPUVertFormat *pos;
-} g_formats = {NULL};
-
void DRW_globals_free(void)
{
- struct GPUVertFormat **format = &g_formats.instance_screenspace;
- for (int i = 0; i < sizeof(g_formats) / sizeof(void *); i++, format++) {
- MEM_SAFE_FREE(*format);
- }
-
- for (int j = 0; j < GPU_SHADER_CFG_LEN; j++) {
- struct GPUShader **shader = &g_shaders[j].shape_outline;
- for (int i = 0; i < sizeof(g_shaders[j]) / sizeof(void *); i++, shader++) {
- DRW_SHADER_FREE_SAFE(*shader);
- }
- }
-}
-
-struct DRWCallBuffer *buffer_dynlines_flat_color(DRWPass *pass, eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_FLAT_COLOR, sh_cfg);
-
- DRW_shgroup_instance_format(g_formats.pos_color,
- {
- {"pos", DRW_ATTR_FLOAT, 3},
- {"color", DRW_ATTR_FLOAT, 4},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer(grp, g_formats.pos_color, GPU_PRIM_LINES);
-}
-
-struct DRWCallBuffer *buffer_dynlines_dashed_uniform_color(DRWPass *pass,
- const float color[4],
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh = GPU_shader_get_builtin_shader_with_config(
- GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR, sh_cfg);
-
- static float dash_width = 6.0f;
- static float dash_factor = 0.5f;
-
- DRW_shgroup_instance_format(g_formats.pos, {{"pos", DRW_ATTR_FLOAT, 3}});
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_vec4(grp, "color", color, 1);
- DRW_shgroup_uniform_vec2(grp, "viewport_size", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_float(grp, "dash_width", &dash_width, 1);
- DRW_shgroup_uniform_float(grp, "dash_factor", &dash_factor, 1);
- DRW_shgroup_uniform_int_copy(grp, "colors_len", 0); /* "simple" mode */
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer(grp, g_formats.pos, GPU_PRIM_LINES);
-}
-
-struct DRWCallBuffer *buffer_dynpoints_uniform_color(DRWShadingGroup *grp)
-{
- DRW_shgroup_instance_format(g_formats.pos, {{"pos", DRW_ATTR_FLOAT, 3}});
-
- return DRW_shgroup_call_buffer(grp, g_formats.pos, GPU_PRIM_POINTS);
-}
-
-struct DRWCallBuffer *buffer_groundlines_uniform_color(DRWPass *pass,
- const float color[4],
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_GROUNDLINE, sh_cfg);
-
- DRW_shgroup_instance_format(g_formats.pos, {{"pos", DRW_ATTR_FLOAT, 3}});
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_vec4(grp, "color", color, 1);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer(grp, g_formats.pos, GPU_PRIM_POINTS);
-}
-
-struct DRWCallBuffer *buffer_groundpoints_uniform_color(DRWPass *pass,
- const float color[4],
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_GROUNDPOINT, sh_cfg);
-
- DRW_shgroup_instance_format(g_formats.pos, {{"pos", DRW_ATTR_FLOAT, 3}});
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_vec4(grp, "color", color, 1);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer(grp, g_formats.pos, GPU_PRIM_POINTS);
-}
-
-struct DRWCallBuffer *buffer_instance_screenspace(DRWPass *pass,
- struct GPUBatch *geom,
- const float *size,
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh = GPU_shader_get_builtin_shader_with_config(
- GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR, sh_cfg);
-
- DRW_shgroup_instance_format(g_formats.instance_screenspace,
- {
- {"world_pos", DRW_ATTR_FLOAT, 3},
- {"color", DRW_ATTR_FLOAT, 3},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_float(grp, "size", size, 1);
- DRW_shgroup_uniform_float(grp, "pixel_size", DRW_viewport_pixelsize_get(), 1);
- DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_screenspace, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_solid(DRWPass *pass, struct GPUBatch *geom)
-{
- static float light[3] = {0.0f, 0.0f, 1.0f};
- GPUShader *sh = GPU_shader_get_builtin_shader(
- GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR);
-
- DRW_shgroup_instance_format(g_formats.instance_color,
- {
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- {"color", DRW_ATTR_FLOAT, 4},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_vec3(grp, "light", light, 1);
-
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_color, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_wire(DRWPass *pass, struct GPUBatch *geom)
-{
- GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR);
-
- DRW_shgroup_instance_format(g_formats.instance_color,
- {
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- {"color", DRW_ATTR_FLOAT, 4},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
-
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_color, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_screen_aligned(DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED,
- sh_cfg);
-
- DRW_shgroup_instance_format(g_formats.instance_screen_aligned,
- {
- {"color", DRW_ATTR_FLOAT, 3},
- {"size", DRW_ATTR_FLOAT, 1},
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_screen_aligned, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_scaled(DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config(
- GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE, sh_cfg);
-
- DRW_shgroup_instance_format(g_formats.instance_scaled,
- {
- {"color", DRW_ATTR_FLOAT, 3},
- {"size", DRW_ATTR_FLOAT, 3},
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_scaled, geom);
-}
-
-struct DRWCallBuffer *buffer_instance(DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config(
- GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, sh_cfg);
-
- DRW_shgroup_instance_format(g_formats.instance_sized,
- {
- {"color", DRW_ATTR_FLOAT, 4},
- {"size", DRW_ATTR_FLOAT, 1},
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass);
- DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_alpha(DRWShadingGroup *grp, struct GPUBatch *geom)
-{
- DRW_shgroup_instance_format(g_formats.instance_sized,
- {
- {"color", DRW_ATTR_FLOAT, 4},
- {"size", DRW_ATTR_FLOAT, 1},
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- });
-
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_empty_axes(DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->empty_axes_sh == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->empty_axes_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_empty_axes_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_sized,
- {
- {"color", DRW_ATTR_FLOAT, 3},
- {"size", DRW_ATTR_FLOAT, 1},
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->empty_axes_sh, pass);
- DRW_shgroup_uniform_vec3(grp, "screenVecs[0]", DRW_viewport_screenvecs_get(), 2);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_color_axes(DRWPass *pass,
- struct GPUBatch *geom,
- DRWShadingGroup **r_grp,
- eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->color_axes_sh == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->color_axes_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_color_axes_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_sized,
- {
- {"color", DRW_ATTR_FLOAT, 3},
- {"size", DRW_ATTR_FLOAT, 1},
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->color_axes_sh, pass);
- DRW_shgroup_uniform_vec3(grp, "screenVecs[0]", DRW_viewport_screenvecs_get(), 2);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- *r_grp = grp;
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_outline(DRWPass *pass,
- struct GPUBatch *geom,
- const int *baseid,
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config(
- GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE, sh_cfg);
-
- DRW_shgroup_instance_format(g_formats.instance_outline,
- {
- {"callId", DRW_ATTR_INT, 1},
- {"size", DRW_ATTR_FLOAT, 1},
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass);
- DRW_shgroup_uniform_int(grp, "baseId", baseid, 1);
-
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_outline, geom);
-}
-
-struct DRWCallBuffer *buffer_camera_instance(DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_CAMERA, sh_cfg);
-
- DRW_shgroup_instance_format(g_formats.instance_camera,
- {
- {"color", DRW_ATTR_FLOAT, 3},
- {"corners", DRW_ATTR_FLOAT, 8},
- {"depth", DRW_ATTR_FLOAT, 1},
- {"tria", DRW_ATTR_FLOAT, 4},
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_camera, geom);
-}
-
-struct DRWCallBuffer *buffer_distance_lines_instance(DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_DISTANCE_LINES,
- sh_cfg);
- static float point_size = 4.0f;
-
- DRW_shgroup_instance_format(g_formats.instance_distance_lines,
- {
- {"color", DRW_ATTR_FLOAT, 3},
- {"start", DRW_ATTR_FLOAT, 1},
- {"end", DRW_ATTR_FLOAT, 1},
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass);
- DRW_shgroup_uniform_float(grp, "size", &point_size, 1);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_distance_lines, geom);
-}
-
-struct DRWCallBuffer *buffer_spot_instance(DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg)
-{
- GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config(
- GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR, sh_cfg);
- static const int True = true;
- static const int False = false;
-
- DRW_shgroup_instance_format(g_formats.instance_spot,
- {
- {"color", DRW_ATTR_FLOAT, 3},
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass);
- DRW_shgroup_uniform_bool(grp, "drawFront", &False, 1);
- DRW_shgroup_uniform_bool(grp, "drawBack", &False, 1);
- DRW_shgroup_uniform_bool(grp, "drawSilhouette", &True, 1);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_spot, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_bone_axes(DRWPass *pass, eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->bone_axes == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->bone_axes = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_armature_axes_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_color,
- {
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- {"color", DRW_ATTR_FLOAT, 4},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_axes, pass);
- DRW_shgroup_uniform_vec3(grp, "screenVecs[0]", DRW_viewport_screenvecs_get(), 2);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(
- grp, g_formats.instance_color, DRW_cache_bone_arrows_get());
-}
-
-struct DRWCallBuffer *buffer_instance_bone_envelope_outline(DRWPass *pass, eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->bone_envelope_outline == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->bone_envelope_outline = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){sh_cfg_data->lib, datatoc_armature_envelope_outline_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_bone_envelope_outline,
- {
- {"headSphere", DRW_ATTR_FLOAT, 4},
- {"tailSphere", DRW_ATTR_FLOAT, 4},
- {"outlineColorSize", DRW_ATTR_FLOAT, 4},
- {"xAxis", DRW_ATTR_FLOAT, 3},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_envelope_outline, pass);
- DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(
- grp, g_formats.instance_bone_envelope_outline, DRW_cache_bone_envelope_outline_get());
-}
-
-struct DRWCallBuffer *buffer_instance_bone_envelope_distance(DRWPass *pass,
- eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->bone_envelope_distance == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->bone_envelope_distance = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){sh_cfg_data->lib, datatoc_armature_envelope_solid_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_armature_envelope_distance_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_bone_envelope_distance,
- {
- {"headSphere", DRW_ATTR_FLOAT, 4},
- {"tailSphere", DRW_ATTR_FLOAT, 4},
- {"xAxis", DRW_ATTR_FLOAT, 3},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_envelope_distance, pass);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(
- grp, g_formats.instance_bone_envelope_distance, DRW_cache_bone_envelope_solid_get());
-}
-
-struct DRWCallBuffer *buffer_instance_bone_envelope_solid(DRWPass *pass,
- bool transp,
- eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->bone_envelope == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->bone_envelope = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){sh_cfg_data->lib, datatoc_armature_envelope_solid_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_armature_envelope_solid_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_bone_envelope,
- {
- {"headSphere", DRW_ATTR_FLOAT, 4},
- {"tailSphere", DRW_ATTR_FLOAT, 4},
- {"boneColor", DRW_ATTR_FLOAT, 3},
- {"stateColor", DRW_ATTR_FLOAT, 3},
- {"xAxis", DRW_ATTR_FLOAT, 3},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_envelope, pass);
- /* We can have a lot of overdraw if we don't do this. Also envelope are not subject to
- * inverted matrix. */
- DRW_shgroup_state_enable(grp, DRW_STATE_CULL_BACK);
- DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.6f : 1.0f);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(
- grp, g_formats.instance_bone_envelope, DRW_cache_bone_envelope_solid_get());
-}
-
-struct DRWCallBuffer *buffer_instance_mball_handles(DRWPass *pass, eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->mball_handles == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->mball_handles = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_mball_handles_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_mball_handles,
- {
- {"ScaleTranslationMatrix", DRW_ATTR_FLOAT, 12},
- {"radius", DRW_ATTR_FLOAT, 1},
- {"color", DRW_ATTR_FLOAT, 3},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->mball_handles, pass);
- DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(
- grp, g_formats.instance_mball_handles, DRW_cache_screenspace_circle_get());
-}
-
-/* Only works with batches with adjacency infos. */
-struct DRWCallBuffer *buffer_instance_bone_shape_outline(DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->shape_outline == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->shape_outline = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_armature_shape_outline_vert_glsl,
- NULL},
- .geom = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_armature_shape_outline_geom_glsl,
- NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_bone_outline,
- {
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- {"outlineColorSize", DRW_ATTR_FLOAT, 4},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->shape_outline, pass);
- DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_bone_outline, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_bone_shape_solid(DRWPass *pass,
- struct GPUBatch *geom,
- bool transp,
- eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->shape_solid == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->shape_solid = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_armature_shape_solid_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_armature_shape_solid_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_bone,
- {
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- {"boneColor", DRW_ATTR_FLOAT, 3},
- {"stateColor", DRW_ATTR_FLOAT, 3},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->shape_solid, pass);
- DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.6f : 1.0f);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_bone, geom);
-}
-
-struct DRWCallBuffer *buffer_instance_bone_sphere_solid(DRWPass *pass,
- bool transp,
- eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->bone_sphere == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->bone_sphere = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_armature_sphere_solid_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_armature_sphere_solid_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_bone,
- {
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- {"boneColor", DRW_ATTR_FLOAT, 3},
- {"stateColor", DRW_ATTR_FLOAT, 3},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_sphere, pass);
- /* More transparent than the shape to be less distractive. */
- DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.4f : 1.0f);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(
- grp, g_formats.instance_bone, DRW_cache_bone_point_get());
-}
-
-struct DRWCallBuffer *buffer_instance_bone_sphere_outline(DRWPass *pass, eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->bone_sphere_outline == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->bone_sphere_outline = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){sh_cfg_data->lib, datatoc_armature_sphere_outline_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(g_formats.instance_bone_outline,
- {
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- {"outlineColorSize", DRW_ATTR_FLOAT, 4},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_sphere_outline, pass);
- DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(
- grp, g_formats.instance_bone_outline, DRW_cache_bone_point_wire_outline_get());
-}
-
-struct DRWCallBuffer *buffer_instance_bone_stick(DRWPass *pass, eGPUShaderConfig sh_cfg)
-{
- COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
- if (sh_data->bone_stick == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- sh_data->bone_stick = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_armature_stick_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_armature_stick_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- DRW_shgroup_instance_format(
- g_formats.instance_bone_stick,
- {
- {"boneStart", DRW_ATTR_FLOAT, 3},
- {"boneEnd", DRW_ATTR_FLOAT, 3},
- {"wireColor", DRW_ATTR_FLOAT, 4}, /* TODO port these to uchar color */
- {"boneColor", DRW_ATTR_FLOAT, 4},
- {"headColor", DRW_ATTR_FLOAT, 4},
- {"tailColor", DRW_ATTR_FLOAT, 4},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_stick, pass);
- DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_float_copy(grp, "stickSize", 5.0f * U.pixelsize);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return DRW_shgroup_call_buffer_instance(
- grp, g_formats.instance_bone_stick, DRW_cache_bone_stick_get());
-}
-
-struct DRWCallBuffer *buffer_instance_bone_dof(struct DRWPass *pass,
- struct GPUBatch *geom,
- bool blend)
-{
- COMMON_Shaders *sh_data = &g_shaders[GPU_SHADER_CFG_DEFAULT];
- if (sh_data->bone_dofs == NULL) {
- sh_data->bone_dofs = DRW_shader_create(
- datatoc_armature_dof_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl, NULL);
- }
-
- DRW_shgroup_instance_format(g_formats.instance_bone_dof,
- {
- {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
- {"color", DRW_ATTR_FLOAT, 4},
- {"amin", DRW_ATTR_FLOAT, 2},
- {"amax", DRW_ATTR_FLOAT, 2},
- });
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_dofs, pass);
- if (blend) {
- DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
- DRW_shgroup_state_disable(grp, DRW_STATE_CULL_FRONT);
- }
- return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_bone_dof, geom);
-}
-
-void empties_callbuffers_create(struct DRWPass *pass,
- DRWEmptiesBufferList *buffers,
- eGPUShaderConfig sh_cfg)
-{
- struct GPUBatch *geom;
-
- geom = DRW_cache_plain_axes_get();
- buffers->plain_axes = buffer_instance(pass, geom, sh_cfg);
-
- geom = DRW_cache_empty_cube_get();
- buffers->cube = buffer_instance(pass, geom, sh_cfg);
-
- geom = DRW_cache_circle_get();
- buffers->circle = buffer_instance(pass, geom, sh_cfg);
-
- geom = DRW_cache_empty_sphere_get();
- buffers->sphere = buffer_instance(pass, geom, sh_cfg);
-
- geom = DRW_cache_sphere_get();
- buffers->sphere_solid = buffer_instance_solid(pass, geom);
-
- geom = DRW_cache_empty_cylinder_get();
- buffers->cylinder = buffer_instance(pass, geom, sh_cfg);
-
- geom = DRW_cache_empty_capsule_cap_get();
- buffers->capsule_cap = buffer_instance(pass, geom, sh_cfg);
-
- geom = DRW_cache_empty_capsule_body_get();
- buffers->capsule_body = buffer_instance(pass, geom, sh_cfg);
-
- geom = DRW_cache_empty_cone_get();
- buffers->cone = buffer_instance(pass, geom, sh_cfg);
-
- geom = DRW_cache_single_arrow_get();
- buffers->single_arrow = buffer_instance(pass, geom, sh_cfg);
-
- geom = DRW_cache_single_line_get();
- buffers->single_arrow_line = buffer_instance(pass, geom, sh_cfg);
-
- geom = DRW_cache_bone_arrows_get();
- buffers->empty_axes = buffer_instance_empty_axes(pass, geom, sh_cfg);
-}
-
-struct GPUShader *mpath_line_shader_get(void)
-{
- COMMON_Shaders *sh_data = &g_shaders[GPU_SHADER_CFG_DEFAULT];
- if (sh_data->mpath_line_sh == NULL) {
- sh_data->mpath_line_sh = DRW_shader_create_with_lib(
- datatoc_animviz_mpath_lines_vert_glsl,
- datatoc_animviz_mpath_lines_geom_glsl,
- datatoc_gpu_shader_3D_smooth_color_frag_glsl,
- datatoc_common_globals_lib_glsl,
- NULL);
- }
- return sh_data->mpath_line_sh;
-}
-
-struct GPUShader *mpath_points_shader_get(void)
-{
- COMMON_Shaders *sh_data = &g_shaders[GPU_SHADER_CFG_DEFAULT];
- if (sh_data->mpath_points_sh == NULL) {
- sh_data->mpath_points_sh = DRW_shader_create_with_lib(
- datatoc_animviz_mpath_points_vert_glsl,
- NULL,
- datatoc_gpu_shader_point_varying_color_frag_glsl,
- datatoc_common_globals_lib_glsl,
- NULL);
- }
- return sh_data->mpath_points_sh;
-}
-
-struct GPUShader *volume_velocity_shader_get(bool use_needle)
-{
- COMMON_Shaders *sh_data = &g_shaders[GPU_SHADER_CFG_DEFAULT];
- if (use_needle) {
- if (sh_data->volume_velocity_needle_sh == NULL) {
- sh_data->volume_velocity_needle_sh = DRW_shader_create_with_lib(
- datatoc_volume_velocity_vert_glsl,
- NULL,
- datatoc_gpu_shader_flat_color_frag_glsl,
- datatoc_common_view_lib_glsl,
- "#define USE_NEEDLE\n");
- }
- return sh_data->volume_velocity_needle_sh;
- }
- else {
- if (sh_data->volume_velocity_sh == NULL) {
- sh_data->volume_velocity_sh = DRW_shader_create_with_lib(
- datatoc_volume_velocity_vert_glsl,
- NULL,
- datatoc_gpu_shader_flat_color_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
- }
- return sh_data->volume_velocity_sh;
- }
}
-DRWView *DRW_view_create_with_zoffset(const RegionView3D *rv3d, float offset)
+DRWView *DRW_view_create_with_zoffset(const DRWView *parent_view,
+ const RegionView3D *rv3d,
+ float offset)
{
/* Create view with depth offset */
- const DRWView *default_view = DRW_view_default_get();
float viewmat[4][4], winmat[4][4];
- DRW_view_viewmat_get(default_view, viewmat, false);
- DRW_view_winmat_get(default_view, winmat, false);
+ DRW_view_viewmat_get(parent_view, viewmat, false);
+ DRW_view_winmat_get(parent_view, winmat, false);
float viewdist = rv3d->dist;
@@ -1129,7 +251,7 @@ DRWView *DRW_view_create_with_zoffset(const RegionView3D *rv3d, float offset)
winmat[3][2] -= bglPolygonOffsetCalc((float *)winmat, viewdist, offset);
- return DRW_view_create_sub(default_view, viewmat, winmat);
+ return DRW_view_create_sub(parent_view, viewmat, winmat);
}
/* ******************************************** COLOR UTILS ************************************ */
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 01c0946247a..97afb5e6aa4 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -23,10 +23,8 @@
#ifndef __DRAW_COMMON_H__
#define __DRAW_COMMON_H__
-struct DRWCallBuffer;
struct DRWPass;
struct DRWShadingGroup;
-struct GPUBatch;
struct GPUMaterial;
struct ModifierData;
struct Object;
@@ -34,7 +32,7 @@ struct ParticleSystem;
struct ViewLayer;
#define UBO_FIRST_COLOR colorWire
-#define UBO_LAST_COLOR colorGridAxisZ
+#define UBO_LAST_COLOR colorFaceFront
/* Used as ubo but colors can be directly referenced as well */
/* Keep in sync with: common_globals_lib.glsl (globalsBlock) */
@@ -53,6 +51,7 @@ typedef struct GlobalsUboStorage {
float colorLight[4];
float colorSpeaker[4];
float colorCamera[4];
+ float colorCameraPath[4];
float colorEmpty[4];
float colorVertex[4];
float colorVertexSelect[4];
@@ -108,13 +107,19 @@ typedef struct GlobalsUboStorage {
float colorGridAxisY[4];
float colorGridAxisZ[4];
+ float colorFaceBack[4];
+ float colorFaceFront[4];
+
/* NOTE! Put all color before UBO_LAST_COLOR */
+ float screenVecs[2][4]; /* padded as vec4 */
+ float sizeViewport[2], sizeViewportInv[2]; /* packed as vec4 in glsl */
/* Pack individual float at the end of the buffer to avoid alignment errors */
- float sizeLightCenter, sizeLightCircle, sizeLightCircleShadow;
+ float sizePixel, pixelFac;
+ float sizeObjectCenter, sizeLightCenter, sizeLightCircle, sizeLightCircleShadow;
float sizeVertex, sizeEdge, sizeEdgeFix, sizeFaceDot;
- float pad_globalsBlock;
+ float pad_globalsBlock[2];
} GlobalsUboStorage;
/* Keep in sync with globalsBlock in shaders */
BLI_STATIC_ASSERT_ALIGN(GlobalsUboStorage, 16)
@@ -122,105 +127,9 @@ BLI_STATIC_ASSERT_ALIGN(GlobalsUboStorage, 16)
void DRW_globals_update(void);
void DRW_globals_free(void);
-typedef struct DRWEmptiesBufferList {
- struct DRWCallBuffer *plain_axes;
- struct DRWCallBuffer *cube;
- struct DRWCallBuffer *circle;
- struct DRWCallBuffer *sphere;
- struct DRWCallBuffer *sphere_solid;
- struct DRWCallBuffer *cylinder;
- struct DRWCallBuffer *capsule_cap;
- struct DRWCallBuffer *capsule_body;
- struct DRWCallBuffer *cone;
- struct DRWCallBuffer *single_arrow;
- struct DRWCallBuffer *single_arrow_line;
- struct DRWCallBuffer *empty_axes;
-} DRWEmptiesBufferList;
-
-/* TODO(fclem) ideally, most of the DRWCallBuffer functions shouldn't create a shgroup. */
-struct DRWCallBuffer *buffer_dynlines_flat_color(struct DRWPass *pass, eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_dynlines_dashed_uniform_color(struct DRWPass *pass,
- const float color[4],
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_dynpoints_uniform_color(struct DRWShadingGroup *grp);
-struct DRWCallBuffer *buffer_groundlines_uniform_color(struct DRWPass *pass,
- const float color[4],
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_groundpoints_uniform_color(struct DRWPass *pass,
- const float color[4],
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_screenspace(struct DRWPass *pass,
- struct GPUBatch *geom,
- const float *size,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_solid(struct DRWPass *pass, struct GPUBatch *geom);
-struct DRWCallBuffer *buffer_instance_wire(struct DRWPass *pass, struct GPUBatch *geom);
-struct DRWCallBuffer *buffer_instance_screen_aligned(struct DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_empty_axes(struct DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_color_axes(struct DRWPass *pass,
- struct GPUBatch *geom,
- struct DRWShadingGroup **r_grp,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_scaled(struct DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance(struct DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_alpha(struct DRWShadingGroup *grp, struct GPUBatch *geom);
-struct DRWCallBuffer *buffer_instance_outline(struct DRWPass *pass,
- struct GPUBatch *geom,
- const int *baseid,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_camera_instance(struct DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_distance_lines_instance(struct DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_spot_instance(struct DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_mball_handles(struct DRWPass *pass, eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_bone_axes(struct DRWPass *pass, eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_bone_envelope_distance(struct DRWPass *pass,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_bone_envelope_outline(struct DRWPass *pass,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_bone_envelope_solid(struct DRWPass *pass,
- bool transp,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_bone_shape_outline(struct DRWPass *pass,
- struct GPUBatch *geom,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_bone_shape_solid(struct DRWPass *pass,
- struct GPUBatch *geom,
- bool transp,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_bone_sphere_outline(struct DRWPass *pass,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_bone_sphere_solid(struct DRWPass *pass,
- bool transp,
- eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_bone_stick(struct DRWPass *pass, eGPUShaderConfig sh_cfg);
-struct DRWCallBuffer *buffer_instance_bone_dof(struct DRWPass *pass,
- struct GPUBatch *geom,
- bool blend);
-
-void empties_callbuffers_create(struct DRWPass *pass,
- struct DRWEmptiesBufferList *buffers,
- eGPUShaderConfig sh_cfg);
-
-struct GPUShader *mpath_line_shader_get(void);
-struct GPUShader *mpath_points_shader_get(void);
-
-struct GPUShader *volume_velocity_shader_get(bool use_needle);
-
-struct DRWView *DRW_view_create_with_zoffset(const RegionView3D *rv3d, float offset);
+struct DRWView *DRW_view_create_with_zoffset(const struct DRWView *parent_view,
+ const RegionView3D *rv3d,
+ float offset);
int DRW_object_wire_theme_get(struct Object *ob, struct ViewLayer *view_layer, float **r_color);
float *DRW_color_background_blend_get(int theme_id);
@@ -228,24 +137,6 @@ float *DRW_color_background_blend_get(int theme_id);
bool DRW_object_is_flat(Object *ob, int *r_axis);
bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis);
-/* draw_armature.c */
-typedef struct DRWArmaturePasses {
- struct DRWPass *bone_solid;
- struct DRWPass *bone_outline;
- struct DRWPass *bone_wire;
- struct DRWPass *bone_envelope;
- struct DRWPass *bone_axes;
- struct DRWPass *relationship_lines;
- struct GHash *custom_shapes;
-} DRWArmaturePasses;
-
-void DRW_shgroup_armature_object(struct Object *ob,
- struct ViewLayer *view_layer,
- struct DRWArmaturePasses passes,
- bool transp);
-void DRW_shgroup_armature_pose(struct Object *ob, struct DRWArmaturePasses passes, bool transp);
-void DRW_shgroup_armature_edit(struct Object *ob, struct DRWArmaturePasses passes, bool transp);
-
/* draw_hair.c */
/* This creates a shading group with display hairs.
@@ -266,9 +157,6 @@ void DRW_hair_init(void);
void DRW_hair_update(void);
void DRW_hair_free(void);
-/* pose_mode.c */
-bool DRW_pose_mode_armature(struct Object *ob, struct Object *active_ob);
-
/* draw_common.c */
struct DRW_Global {
/** If needed, contains all global/Theme colors
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 81b10e095c3..5712fd0ccde 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -134,15 +134,20 @@ GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
/* NOTE: Does not return a valid drawable batch until DRW_instance_buffer_finish has run. */
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
+ GPUBatch *instancer,
GPUBatch *geom)
{
/* Do not call this with a batch that is already an instancing batch. */
- BLI_assert(geom->inst == NULL);
+ BLI_assert(geom->inst[0] == NULL);
+ /* Only call with one of them. */
+ BLI_assert((instancer != NULL) != (buf != NULL));
GPUBatch *batch = BLI_memblock_alloc(idatalist->pool_instancing);
- bool is_compatible = (batch->gl_prim_type == geom->gl_prim_type) && (batch->inst == buf) &&
- (buf->vbo_id != 0) && (batch->phase == GPU_BATCH_READY_TO_DRAW) &&
- (batch->elem == geom->elem);
+ bool instancer_compat = buf ? ((batch->inst[0] == buf) && (buf->vbo_id != 0)) :
+ ((batch->inst[0] == instancer->inst[0]) &&
+ (batch->inst[1] == instancer->inst[1]));
+ bool is_compatible = (batch->gl_prim_type == geom->gl_prim_type) && instancer_compat &&
+ (batch->phase == GPU_BATCH_READY_TO_DRAW) && (batch->elem == geom->elem);
for (int i = 0; i < GPU_BATCH_VBO_MAX_LEN && is_compatible; i++) {
if (batch->verts[i] != geom->verts[i]) {
is_compatible = false;
@@ -152,7 +157,8 @@ GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
if (!is_compatible) {
GPU_batch_clear(batch);
/* Save args and init later */
- batch->inst = buf;
+ batch->inst[0] = buf;
+ batch->inst[1] = (void *)instancer; /* HACK to save the pointer without other alloc. */
batch->phase = GPU_BATCH_READY_TO_BUILD;
batch->verts[0] = (void *)geom; /* HACK to save the pointer without other alloc. */
@@ -205,10 +211,19 @@ void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist)
BLI_memblock_iternew(idatalist->pool_instancing, &iter);
while ((batch = BLI_memblock_iterstep(&iter))) {
if (batch->phase == GPU_BATCH_READY_TO_BUILD) {
- GPUVertBuf *inst = batch->inst;
- GPUBatch *geom = (void *)batch->verts[0]; /* HACK see DRW_temp_batch_instance_request. */
+ GPUVertBuf *inst_buf = batch->inst[0];
+ /* HACK see DRW_temp_batch_instance_request. */
+ GPUBatch *inst_batch = (void *)batch->inst[1];
+ GPUBatch *geom = (void *)batch->verts[0];
GPU_batch_copy(batch, geom);
- GPU_batch_instbuf_set(batch, inst, false);
+ if (inst_batch != NULL) {
+ for (int i = 0; i < GPU_BATCH_INST_VBO_MAX_LEN && inst_batch->verts[i]; i++) {
+ GPU_batch_instbuf_add_ex(batch, inst_batch->verts[i], false);
+ }
+ }
+ else {
+ GPU_batch_instbuf_add_ex(batch, inst_buf, false);
+ }
}
}
/* Resize pools and free unused. */
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
index 524c4cd96d8..f891d380ee3 100644
--- a/source/blender/draw/intern/draw_instance_data.h
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -43,6 +43,7 @@ GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
int *vert_len);
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
+ GPUBatch *instancer,
GPUBatch *geom);
GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index e88f7c5f633..0a707eb9489 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -84,13 +84,13 @@
/* only for callbacks */
#include "draw_cache_impl.h"
-#include "draw_mode_engines.h"
#include "engines/eevee/eevee_engine.h"
#include "engines/basic/basic_engine.h"
#include "engines/workbench/workbench_engine.h"
#include "engines/external/external_engine.h"
#include "engines/gpencil/gpencil_engine.h"
#include "engines/select/select_engine.h"
+#include "engines/overlay/overlay_engine.h"
#include "GPU_context.h"
@@ -584,7 +584,7 @@ static void drw_context_state_init(void)
}
DST.draw_ctx.sh_cfg = GPU_SHADER_CFG_DEFAULT;
- if (DST.draw_ctx.rv3d && DST.draw_ctx.rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(DST.draw_ctx.v3d, DST.draw_ctx.rv3d)) {
DST.draw_ctx.sh_cfg = GPU_SHADER_CFG_CLIPPED;
}
}
@@ -603,7 +603,7 @@ static void draw_unit_state_create(void)
infos->ob_index = 0;
infos->ob_random = 0.0f;
- infos->ob_neg_scale = 1.0f;
+ infos->ob_flag = 1.0f;
copy_v3_fl(infos->ob_color, 1.0f);
/* TODO(fclem) get rid of this. */
@@ -1235,7 +1235,7 @@ static void drw_engines_draw_text(void)
PROFILE_START(stime);
if (data->text_draw_cache) {
- DRW_text_cache_draw(data->text_draw_cache, DST.draw_ctx.ar);
+ DRW_text_cache_draw(data->text_draw_cache, DST.draw_ctx.ar, DST.draw_ctx.v3d);
}
PROFILE_END_UPDATE(data->render_time, stime);
@@ -1336,80 +1336,7 @@ static void drw_engines_enable_from_engine(RenderEngineType *engine_type,
}
}
-static void drw_engines_enable_from_object_mode(void)
-{
- use_drw_engine(&draw_engine_object_type);
- /* TODO(fclem) remove this, it does not belong to it's own engine. */
- use_drw_engine(&draw_engine_motion_path_type);
-}
-
-static void drw_engines_enable_from_paint_mode(int mode)
-{
- switch (mode) {
- case CTX_MODE_SCULPT:
- use_drw_engine(&draw_engine_sculpt_type);
- break;
- case CTX_MODE_PAINT_WEIGHT:
- case CTX_MODE_PAINT_VERTEX:
- use_drw_engine(&draw_engine_paint_vertex_type);
- break;
- case CTX_MODE_PAINT_TEXTURE:
- use_drw_engine(&draw_engine_paint_texture_type);
- break;
- default:
- break;
- }
-}
-
-static void drw_engines_enable_from_mode(int mode)
-{
- switch (mode) {
- case CTX_MODE_EDIT_MESH:
- use_drw_engine(&draw_engine_edit_mesh_type);
- break;
- case CTX_MODE_EDIT_SURFACE:
- case CTX_MODE_EDIT_CURVE:
- use_drw_engine(&draw_engine_edit_curve_type);
- break;
- case CTX_MODE_EDIT_TEXT:
- use_drw_engine(&draw_engine_edit_text_type);
- break;
- case CTX_MODE_EDIT_ARMATURE:
- use_drw_engine(&draw_engine_edit_armature_type);
- break;
- case CTX_MODE_EDIT_METABALL:
- use_drw_engine(&draw_engine_edit_metaball_type);
- break;
- case CTX_MODE_EDIT_LATTICE:
- use_drw_engine(&draw_engine_edit_lattice_type);
- break;
- case CTX_MODE_PARTICLE:
- use_drw_engine(&draw_engine_particle_type);
- break;
- case CTX_MODE_POSE:
- case CTX_MODE_PAINT_WEIGHT:
- /* The pose engine clears the depth of the default framebuffer
- * to draw an object with `OB_DRAWXRAY`.
- * (different of workbench that has its own framebuffer).
- * So make sure you call its `draw_scene` after all the other engines. */
- use_drw_engine(&draw_engine_pose_type);
- break;
- case CTX_MODE_SCULPT:
- case CTX_MODE_PAINT_VERTEX:
- case CTX_MODE_PAINT_TEXTURE:
- case CTX_MODE_OBJECT:
- case CTX_MODE_PAINT_GPENCIL:
- case CTX_MODE_EDIT_GPENCIL:
- case CTX_MODE_SCULPT_GPENCIL:
- case CTX_MODE_WEIGHT_GPENCIL:
- break;
- default:
- BLI_assert(!"Draw mode invalid");
- break;
- }
-}
-
-static void drw_engines_enable_from_overlays(int UNUSED(overlay_flag))
+static void drw_engines_enable_overlays(void)
{
use_drw_engine(&draw_engine_overlay_type);
}
@@ -1421,36 +1348,19 @@ static void drw_engines_enable_basic(void)
use_drw_engine(DRW_engine_viewport_basic_type.draw_engine);
}
-static void drw_engines_enable(ViewLayer *view_layer,
+static void drw_engines_enable(ViewLayer *UNUSED(view_layer),
RenderEngineType *engine_type,
bool gpencil_engine_needed)
{
- Object *obact = OBACT(view_layer);
- const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
- DST.draw_ctx.object_edit, obact, DST.draw_ctx.object_mode);
View3D *v3d = DST.draw_ctx.v3d;
const int drawtype = v3d->shading.type;
const bool use_xray = XRAY_ENABLED(v3d);
drw_engines_enable_from_engine(engine_type, drawtype, use_xray);
- /* grease pencil */
if (gpencil_engine_needed) {
use_drw_engine(&draw_engine_gpencil_type);
}
-
- if (DRW_state_draw_support()) {
- /* Draw paint modes first so that they are drawn below the wireframes. */
- drw_engines_enable_from_paint_mode(mode);
- drw_engines_enable_from_overlays(v3d->overlay.flag);
- drw_engines_enable_from_object_mode();
- drw_engines_enable_from_mode(mode);
- }
- else {
- /* Force enable overlays engine for wireframe mode */
- if (v3d->shading.type == OB_WIRE) {
- drw_engines_enable_from_overlays(v3d->overlay.flag);
- }
- }
+ drw_engines_enable_overlays();
}
static void drw_engines_disable(void)
@@ -2243,7 +2153,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
bool use_obedit = false;
/* obedit_ctx_mode is used for selecting the right draw engines */
- eContextObjectMode obedit_ctx_mode;
+ // eContextObjectMode obedit_ctx_mode;
/* object_mode is used for filtering objects in the depsgraph */
eObjectMode object_mode;
int object_type = 0;
@@ -2252,11 +2162,11 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
object_mode = obedit->mode;
if (obedit->type == OB_MBALL) {
use_obedit = true;
- obedit_ctx_mode = CTX_MODE_EDIT_METABALL;
+ // obedit_ctx_mode = CTX_MODE_EDIT_METABALL;
}
else if (obedit->type == OB_ARMATURE) {
use_obedit = true;
- obedit_ctx_mode = CTX_MODE_EDIT_ARMATURE;
+ // obedit_ctx_mode = CTX_MODE_EDIT_ARMATURE;
}
}
if (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT) {
@@ -2278,7 +2188,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
use_obedit = true;
object_type = obpose->type;
object_mode = obpose->mode;
- obedit_ctx_mode = CTX_MODE_POSE;
+ // obedit_ctx_mode = CTX_MODE_POSE;
}
}
}
@@ -2292,23 +2202,21 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/* Get list of enabled engines */
if (use_obedit) {
- drw_engines_enable_from_paint_mode(obedit_ctx_mode);
- drw_engines_enable_from_mode(obedit_ctx_mode);
+ drw_engines_enable_overlays();
}
else if (!draw_surface) {
/* grease pencil selection */
use_drw_engine(&draw_engine_gpencil_type);
- drw_engines_enable_from_overlays(v3d->overlay.flag);
- drw_engines_enable_from_object_mode();
+ drw_engines_enable_overlays();
}
else {
+ /* Draw surface for occlusion. */
drw_engines_enable_basic();
/* grease pencil selection */
use_drw_engine(&draw_engine_gpencil_type);
- drw_engines_enable_from_overlays(v3d->overlay.flag);
- drw_engines_enable_from_object_mode();
+ drw_engines_enable_overlays();
}
drw_engines_data_validate();
@@ -2560,9 +2468,12 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
/* Get list of enabled engines */
{
+ /* Required by `DRW_state_draw_support()` */
+ DST.draw_ctx.v3d = v3d;
+
drw_engines_enable_basic();
if (DRW_state_draw_support()) {
- drw_engines_enable_from_object_mode();
+ drw_engines_enable_overlays();
}
}
@@ -2663,11 +2574,14 @@ static void draw_world_clip_planes_from_rv3d(GPUBatch *batch, const float world_
/**
* Clears the Depth Buffer and draws only the specified object.
*/
-void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object)
+void DRW_draw_depth_object(ARegion *ar, View3D *v3d, GPUViewport *viewport, Object *object)
{
RegionView3D *rv3d = ar->regiondata;
DRW_opengl_context_enable();
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
+ GPU_matrix_mul(object->obmat);
/* Setup framebuffer */
DefaultFramebufferList *fbl = GPU_viewport_framebuffer_list_get(viewport);
@@ -2675,10 +2589,9 @@ void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object)
GPU_framebuffer_bind(fbl->depth_only_fb);
GPU_framebuffer_clear_depth(fbl->depth_only_fb, 1.0f);
GPU_depth_test(true);
- GPU_matrix_mul(object->obmat);
const float(*world_clip_planes)[4] = NULL;
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_set(rv3d);
ED_view3d_clipping_local(rv3d, object->obmat);
world_clip_planes = rv3d->clip_local;
@@ -2715,7 +2628,7 @@ void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object)
break;
}
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_disable();
}
@@ -2865,21 +2778,9 @@ void DRW_engines_register(void)
DRW_engine_register(&draw_engine_workbench_solid);
DRW_engine_register(&draw_engine_workbench_transparent);
- DRW_engine_register(&draw_engine_object_type);
- DRW_engine_register(&draw_engine_edit_armature_type);
- DRW_engine_register(&draw_engine_edit_curve_type);
- DRW_engine_register(&draw_engine_edit_lattice_type);
- DRW_engine_register(&draw_engine_edit_mesh_type);
- DRW_engine_register(&draw_engine_edit_metaball_type);
- DRW_engine_register(&draw_engine_edit_text_type);
- DRW_engine_register(&draw_engine_motion_path_type);
- DRW_engine_register(&draw_engine_overlay_type);
- DRW_engine_register(&draw_engine_paint_texture_type);
- DRW_engine_register(&draw_engine_paint_vertex_type);
- DRW_engine_register(&draw_engine_particle_type);
- DRW_engine_register(&draw_engine_pose_type);
- DRW_engine_register(&draw_engine_sculpt_type);
DRW_engine_register(&draw_engine_gpencil_type);
+
+ DRW_engine_register(&draw_engine_overlay_type);
DRW_engine_register(&draw_engine_select_type);
/* setup callbacks */
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index ce8155dc85f..f040afc794c 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -170,7 +170,7 @@ typedef struct DRWObjectInfos {
float ob_index;
float pad; /* UNUSED*/
float ob_random;
- float ob_neg_scale;
+ float ob_flag; /* sign is negative scaling, */
} DRWObjectInfos;
BLI_STATIC_ASSERT_ALIGN(DRWObjectMatrix, 16)
@@ -208,6 +208,7 @@ typedef struct DRWCommandDrawInstance {
GPUBatch *batch;
DRWResourceHandle handle;
uint inst_count;
+ uint use_attribs; /* bool */
} DRWCommandDrawInstance;
typedef struct DRWCommandDrawProcedural {
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 330f72eda18..98474c81209 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -25,6 +25,7 @@
#include "BKE_anim.h"
#include "BKE_curve.h"
#include "BKE_global.h"
+#include "BKE_image.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -506,8 +507,14 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
* put it in ob->runtime and make depsgraph ensure it is up to date. */
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF);
+ /* Object State. */
+ ob_infos->ob_flag = 1.0f; /* Required to have a correct sign */
+ ob_infos->ob_flag += (ob->base_flag & BASE_SELECTED) ? (1 << 1) : 0;
+ ob_infos->ob_flag += (ob->base_flag & BASE_FROM_DUPLI) ? (1 << 2) : 0;
+ ob_infos->ob_flag += (ob->base_flag & BASE_FROM_SET) ? (1 << 3) : 0;
+ ob_infos->ob_flag += (ob == DST.draw_ctx.obact) ? (1 << 4) : 0;
/* Negative scalling. */
- ob_infos->ob_neg_scale = (ob->transflag & OB_NEG_SCALE) ? -1.0f : 1.0f;
+ ob_infos->ob_flag *= (ob->transflag & OB_NEG_SCALE) ? -1.0f : 1.0f;
/* Object Color. */
copy_v4_v4(ob_infos->ob_color, ob->color);
}
@@ -643,12 +650,14 @@ static void drw_command_draw_range(DRWShadingGroup *shgroup,
static void drw_command_draw_instance(DRWShadingGroup *shgroup,
GPUBatch *batch,
DRWResourceHandle handle,
- uint count)
+ uint count,
+ bool use_attrib)
{
DRWCommandDrawInstance *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE);
cmd->batch = batch;
cmd->handle = handle;
cmd->inst_count = count;
+ cmd->use_attribs = use_attrib;
}
static void drw_command_draw_procedural(DRWShadingGroup *shgroup,
@@ -788,7 +797,7 @@ void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
drw_command_set_select_id(shgroup, NULL, DST.select_id);
}
DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
- drw_command_draw_instance(shgroup, geom, handle, count);
+ drw_command_draw_instance(shgroup, geom, handle, count, false);
}
void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
@@ -797,14 +806,13 @@ void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
struct GPUBatch *inst_attributes)
{
BLI_assert(geom != NULL);
- BLI_assert(inst_attributes->verts[0] != NULL);
+ BLI_assert(inst_attributes != NULL);
if (G.f & G_FLAG_PICKSEL) {
drw_command_set_select_id(shgroup, NULL, DST.select_id);
}
DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
- GPUVertBuf *buf_inst = inst_attributes->verts[0];
- GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom);
- drw_command_draw(shgroup, batch, handle);
+ GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, NULL, inst_attributes, geom);
+ drw_command_draw_instance(shgroup, batch, handle, 0, true);
}
#define SCULPT_DEBUG_BUFFERS (G.debug_value == 889)
@@ -1027,12 +1035,33 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup,
}
DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL);
- GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, callbuf->buf, geom);
+ GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, callbuf->buf, NULL, geom);
drw_command_draw(shgroup, batch, handle);
return callbuf;
}
+void DRW_buffer_add_entry_struct(DRWCallBuffer *callbuf, const void *data)
+{
+ GPUVertBuf *buf = callbuf->buf;
+ const bool resize = (callbuf->count == buf->vertex_alloc);
+
+ if (UNLIKELY(resize)) {
+ GPU_vertbuf_data_resize(buf, callbuf->count + DRW_BUFFER_VERTS_CHUNK);
+ }
+
+ GPU_vertbuf_vert_set(buf, callbuf->count, data);
+
+ if (G.f & G_FLAG_PICKSEL) {
+ if (UNLIKELY(resize)) {
+ GPU_vertbuf_data_resize(callbuf->buf_select, callbuf->count + DRW_BUFFER_VERTS_CHUNK);
+ }
+ GPU_vertbuf_attr_set(callbuf->buf_select, 0, callbuf->count, &DST.select_id);
+ }
+
+ callbuf->count++;
+}
+
void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint attr_len)
{
GPUVertBuf *buf = callbuf->buf;
@@ -1185,9 +1214,17 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp,
GPUTexture *tex = NULL;
if (input->ima) {
+ /* If there's no specified iuser but we need a different tile, create a temporary one. */
+ ImageUser local_iuser;
+ BKE_imageuser_default(&local_iuser);
+ local_iuser.tile = input->image_tile;
+
+ ImageUser *iuser = input->iuser ? input->iuser : &local_iuser;
+ iuser->tile = input->image_tile;
+
GPUTexture **tex_ref = BLI_memblock_alloc(DST.vmempool->images);
- *tex_ref = tex = GPU_texture_from_blender(input->ima, input->iuser, GL_TEXTURE_2D);
+ *tex_ref = tex = GPU_texture_from_blender(input->ima, iuser, GL_TEXTURE_2D);
GPU_texture_ref(tex);
}
@@ -1379,53 +1416,19 @@ static void draw_frustum_boundbox_calc(const float (*viewinv)[4],
}
}
-static void draw_frustum_culling_planes_calc(const BoundBox *bbox, float (*frustum_planes)[4])
+static void draw_frustum_culling_planes_calc(const float (*persmat)[4], float (*frustum_planes)[4])
{
- /* TODO See if planes_from_projmat cannot do the job. */
+ planes_from_projmat(persmat,
+ frustum_planes[0],
+ frustum_planes[5],
+ frustum_planes[3],
+ frustum_planes[1],
+ frustum_planes[4],
+ frustum_planes[2]);
- /* Compute clip planes using the world space frustum corners. */
+ /* Normalize. */
for (int p = 0; p < 6; p++) {
- int q, r, s;
- switch (p) {
- case 0:
- q = 1;
- r = 2;
- s = 3;
- break; /* -X */
- case 1:
- q = 0;
- r = 4;
- s = 5;
- break; /* -Y */
- case 2:
- q = 1;
- r = 5;
- s = 6;
- break; /* +Z (far) */
- case 3:
- q = 2;
- r = 6;
- s = 7;
- break; /* +Y */
- case 4:
- q = 0;
- r = 3;
- s = 7;
- break; /* -Z (near) */
- default:
- q = 4;
- r = 7;
- s = 6;
- break; /* +X */
- }
-
- normal_quad_v3(frustum_planes[p], bbox->vec[p], bbox->vec[q], bbox->vec[r], bbox->vec[s]);
- /* Increase precision and use the mean of all 4 corners. */
- frustum_planes[p][3] = -dot_v3v3(frustum_planes[p], bbox->vec[p]);
- frustum_planes[p][3] += -dot_v3v3(frustum_planes[p], bbox->vec[q]);
- frustum_planes[p][3] += -dot_v3v3(frustum_planes[p], bbox->vec[r]);
- frustum_planes[p][3] += -dot_v3v3(frustum_planes[p], bbox->vec[s]);
- frustum_planes[p][3] *= 0.25f;
+ frustum_planes[p][3] /= normalize_v3(frustum_planes[p]);
}
}
@@ -1595,13 +1598,17 @@ DRWView *DRW_view_create_sub(const DRWView *parent_view,
const float viewmat[4][4],
const float winmat[4][4])
{
- BLI_assert(parent_view && parent_view->parent == NULL);
+ /* Search original parent. */
+ const DRWView *ori_view = parent_view;
+ while (ori_view->parent != NULL) {
+ ori_view = ori_view->parent;
+ }
DRWView *view = BLI_memblock_alloc(DST.vmempool->views);
/* Perform copy. */
- *view = *parent_view;
- view->parent = (DRWView *)parent_view;
+ *view = *ori_view;
+ view->parent = (DRWView *)ori_view;
DRW_view_update_sub(view, viewmat, winmat);
@@ -1679,7 +1686,7 @@ void DRW_view_update(DRWView *view,
}
draw_frustum_boundbox_calc(viewinv, winmat, &view->frustum_corners);
- draw_frustum_culling_planes_calc(&view->frustum_corners, view->frustum_planes);
+ draw_frustum_culling_planes_calc(view->storage.persmat, view->frustum_planes);
draw_frustum_bound_sphere_calc(
&view->frustum_corners, viewinv, winmat, wininv, &view->frustum_bsphere);
@@ -1929,4 +1936,14 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass)
pass->shgroups.last = last;
}
+/**
+ * Reverse Shading group submission order.
+ */
+void DRW_pass_sort_shgroup_reverse(DRWPass *pass)
+{
+ pass->shgroups.last = pass->shgroups.first;
+ /* WARNING: Assume that DRWShadingGroup->next is the first member. */
+ BLI_linklist_reverse((LinkNode **)&pass->shgroups.first);
+}
+
/** \} */
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index fa7c44c1b1f..9d14b77119f 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -230,21 +230,6 @@ void drw_state_set(DRWState state)
}
}
- /* Wire Width */
- {
- int test;
- if ((test = CHANGED_TO(DRW_STATE_WIRE_SMOOTH))) {
- if (test == 1) {
- GPU_line_width(2.0f);
- GPU_line_smooth(true);
- }
- else {
- GPU_line_width(1.0f);
- GPU_line_smooth(false);
- }
- }
- }
-
/* Blending (all buffer) */
{
int test;
@@ -321,6 +306,38 @@ void drw_state_set(DRWState state)
}
}
+ /* In Front objects selection */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_IN_FRONT_SELECT))) {
+ if (test == 1) {
+ /* XXX `GPU_depth_range` is not a perfect solution
+ * since very distant geometries can still be occluded.
+ * Also the depth test precision of these geometries is impaired.
+ * However, it solves the selection for the vast majority of cases. */
+ GPU_depth_range(0.0f, 0.01f);
+ }
+ else {
+ GPU_depth_range(0.0f, 1.0f);
+ }
+ }
+ }
+
+ /* Logic Ops */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_LOGIC_INVERT))) {
+ if (test == 1) {
+ glLogicOp(GL_INVERT);
+ glEnable(GL_COLOR_LOGIC_OP);
+ }
+ else {
+ glLogicOp(GL_COPY);
+ glDisable(GL_COLOR_LOGIC_OP);
+ }
+ }
+ }
+
/* Clip Planes */
{
int test;
@@ -421,7 +438,11 @@ void DRW_state_reset(void)
{
DRW_state_reset_ex(DRW_STATE_DEFAULT);
+ /* Should stay constant during the whole rendering. */
GPU_point_size(5);
+ GPU_line_smooth(false);
+ /* Bypass U.pixelsize factor. */
+ glLineWidth(1.0f);
/* Reset blending function */
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
@@ -990,10 +1011,10 @@ BLI_INLINE void draw_select_buffer(DRWShadingGroup *shgroup,
GPUBatch *batch,
const DRWResourceHandle *handle)
{
- const bool is_instancing = (batch->inst != NULL);
+ const bool is_instancing = (batch->inst[0] != NULL);
int start = 0;
int count = 1;
- int tot = is_instancing ? batch->inst->vertex_len : batch->verts[0]->vertex_len;
+ int tot = is_instancing ? batch->inst[0]->vertex_len : batch->verts[0]->vertex_len;
/* Hack : get "vbo" data without actually drawing. */
int *select_id = (void *)state->select_buf->data;
@@ -1091,7 +1112,8 @@ static void draw_call_single_do(DRWShadingGroup *shgroup,
DRWResourceHandle handle,
int vert_first,
int vert_count,
- int inst_count)
+ int inst_count,
+ bool do_base_instance)
{
draw_call_batching_flush(shgroup, state);
@@ -1118,7 +1140,7 @@ static void draw_call_single_do(DRWShadingGroup *shgroup,
batch,
vert_first,
vert_count,
- DRW_handle_id_get(&handle),
+ do_base_instance ? DRW_handle_id_get(&handle) : 0,
inst_count,
state->baseinst_loc);
}
@@ -1292,7 +1314,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
case DRW_CMD_DRAW:
if (!USE_BATCHING || state.obmats_loc == -1 || (G.f & G_FLAG_PICKSEL) ||
cmd->draw.batch->inst) {
- draw_call_single_do(shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0);
+ draw_call_single_do(shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0, true);
}
else {
draw_call_batching_do(shgroup, &state, &cmd->draw);
@@ -1305,7 +1327,8 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
cmd->procedural.handle,
0,
cmd->procedural.vert_count,
- 1);
+ 1,
+ true);
break;
case DRW_CMD_DRAW_INSTANCE:
draw_call_single_do(shgroup,
@@ -1314,7 +1337,8 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
cmd->instance.handle,
0,
0,
- cmd->instance.inst_count);
+ cmd->instance.inst_count,
+ cmd->instance.use_attribs == 0);
break;
case DRW_CMD_DRAW_RANGE:
draw_call_single_do(shgroup,
@@ -1323,7 +1347,8 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
(DRWResourceHandle)0,
cmd->range.vert_first,
cmd->range.vert_count,
- 1);
+ 1,
+ true);
break;
}
}
diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c
index 6e06998f1cc..47fafbdcbd8 100644
--- a/source/blender/draw/intern/draw_manager_text.c
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -24,6 +24,17 @@
#include "BLI_memiter.h"
#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_global.h"
+#include "BKE_unit.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
#include "GPU_matrix.h"
@@ -31,6 +42,7 @@
#include "ED_view3d.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "WM_api.h"
#include "BLF_api.h"
@@ -107,7 +119,7 @@ void DRW_text_cache_add(DRWTextStore *dt,
}
}
-void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar)
+void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar, struct View3D *v3d)
{
RegionView3D *rv3d = ar->regiondata;
ViewCachedString *vos;
@@ -135,7 +147,7 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar)
if (tot) {
int col_pack_prev = 0;
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_disable();
}
@@ -173,8 +185,351 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar)
GPU_matrix_pop();
GPU_matrix_projection_set(original_proj);
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_enable();
}
}
}
+
+/* Copied from drawobject.c */
+void DRW_text_edit_mesh_measure_stats(ARegion *ar,
+ View3D *v3d,
+ Object *ob,
+ const UnitSettings *unit)
+{
+ /* Do not use ascii when using non-default unit system, some unit chars are utf8 (micro, square,
+ * etc.). See bug #36090.
+ */
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ const short txt_flag = DRW_TEXT_CACHE_GLOBALSPACE | (unit->system ? 0 : DRW_TEXT_CACHE_ASCII);
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_mesh;
+ float v1[3], v2[3], v3[3], vmid[3], fvec[3];
+ char numstr[32]; /* Stores the measurement display text here */
+ size_t numstr_len;
+ const char *conv_float; /* Use a float conversion matching the grid size */
+ uchar col[4] = {0, 0, 0, 255}; /* color of the text to draw */
+ float area; /* area of the face */
+ float grid = unit->system ? unit->scale_length : v3d->grid;
+ const bool do_global = (v3d->flag & V3D_GLOBAL_STATS) != 0;
+ const bool do_moving = (G.moving & G_TRANSFORM_EDIT) != 0;
+ float clip_planes[4][4];
+ /* allow for displaying shape keys and deform mods */
+ BMIter iter;
+
+ /* when 2 or more edge-info options are enabled, space apart */
+ short edge_tex_count = 0;
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) {
+ edge_tex_count += 1;
+ }
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_ANG) {
+ edge_tex_count += 1;
+ }
+ if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_INDICES) && (em->selectmode & SCE_SELECT_EDGE)) {
+ edge_tex_count += 1;
+ }
+ const short edge_tex_sep = (short)((edge_tex_count - 1) * 5.0f * U.dpi_fac);
+
+ /* make the precision of the display value proportionate to the gridsize */
+
+ if (grid <= 0.01f) {
+ conv_float = "%.6g";
+ }
+ else if (grid <= 0.1f) {
+ conv_float = "%.5g";
+ }
+ else if (grid <= 1.0f) {
+ conv_float = "%.4g";
+ }
+ else if (grid <= 10.0f) {
+ conv_float = "%.3g";
+ }
+ else {
+ conv_float = "%.2g";
+ }
+
+ if (v3d->overlay.edit_flag &
+ (V3D_OVERLAY_EDIT_EDGE_LEN | V3D_OVERLAY_EDIT_EDGE_ANG | V3D_OVERLAY_EDIT_INDICES)) {
+ BoundBox bb;
+ const rcti rect = {0, ar->winx, 0, ar->winy};
+
+ ED_view3d_clipping_calc(&bb, clip_planes, ar, em->ob, &rect);
+ }
+
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) {
+ BMEdge *eed;
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ /* draw selected edges, or edges next to selected verts while dragging */
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
+ (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)))) {
+ float v1_clip[3], v2_clip[3];
+
+ copy_v3_v3(v1, eed->v1->co);
+ copy_v3_v3(v2, eed->v2->co);
+
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
+
+ mid_v3_v3v3(vmid, v1_clip, v2_clip);
+ mul_m4_v3(ob->obmat, vmid);
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ }
+
+ if (unit->system) {
+ numstr_len = bUnit_AsString2(numstr,
+ sizeof(numstr),
+ len_v3v3(v1, v2) * unit->scale_length,
+ 3,
+ B_UNIT_LENGTH,
+ unit,
+ false);
+ }
+ else {
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
+ }
+
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, edge_tex_sep, txt_flag, col);
+ }
+ }
+ }
+ }
+
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_ANG) {
+ const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
+ BMEdge *eed;
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col);
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
+ /* Draw selected edges, or edges next to selected verts while dragging. */
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
+ (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
+ /* Special case, this is useful to show when verts connected
+ * to this edge via a face are being transformed. */
+ BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(l_b->prev->v, BM_ELEM_SELECT)))) {
+ float v1_clip[3], v2_clip[3];
+
+ copy_v3_v3(v1, eed->v1->co);
+ copy_v3_v3(v2, eed->v2->co);
+
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
+ float no_a[3], no_b[3];
+ float angle;
+
+ mid_v3_v3v3(vmid, v1_clip, v2_clip);
+ mul_m4_v3(ob->obmat, vmid);
+
+ copy_v3_v3(no_a, l_a->f->no);
+ copy_v3_v3(no_b, l_b->f->no);
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->imat, no_a);
+ mul_mat3_m4_v3(ob->imat, no_b);
+ normalize_v3(no_a);
+ normalize_v3(no_b);
+ }
+
+ angle = angle_normalized_v3v3(no_a, no_b);
+
+ numstr_len = BLI_snprintf_rlen(numstr,
+ sizeof(numstr),
+ "%.3f%s",
+ (is_rad) ? angle : RAD2DEGF(angle),
+ (is_rad) ? "r" : "°");
+
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, -edge_tex_sep, txt_flag, col);
+ }
+ }
+ }
+ }
+ }
+
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_AREA) {
+ /* would be nice to use BM_face_calc_area, but that is for 2d faces
+ * so instead add up tessellation triangle areas */
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
+
+ int i, n, numtri;
+ BMFace *f = NULL;
+ BM_ITER_MESH_INDEX (f, &iter, em->bm, BM_FACES_OF_MESH, i) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ n = 0;
+ numtri = f->len - 2;
+ area = 0;
+ zero_v3(vmid);
+ BMLoop *(*l)[3] = &em->looptris[poly_to_tri_count(i, BM_elem_index_get(f->l_first))];
+ for (int j = 0; j < numtri; j++) {
+ copy_v3_v3(v1, l[j][0]->v->co);
+ copy_v3_v3(v2, l[j][1]->v->co);
+ copy_v3_v3(v3, l[j][2]->v->co);
+
+ add_v3_v3(vmid, v1);
+ add_v3_v3(vmid, v2);
+ add_v3_v3(vmid, v3);
+ n += 3;
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ mul_mat3_m4_v3(ob->obmat, v3);
+ }
+
+ area += area_tri_v3(v1, v2, v3);
+ }
+
+ mul_v3_fl(vmid, 1.0f / (float)n);
+ mul_m4_v3(ob->obmat, vmid);
+
+ if (unit->system) {
+ numstr_len = bUnit_AsString2(numstr,
+ sizeof(numstr),
+ (double)(area * unit->scale_length * unit->scale_length),
+ 3,
+ B_UNIT_AREA,
+ unit,
+ false);
+ }
+ else {
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area);
+ }
+
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_ANG) {
+ BMFace *efa;
+ const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ const bool is_face_sel = BM_elem_flag_test_bool(efa, BM_ELEM_SELECT);
+
+ if (is_face_sel || do_moving) {
+ BMIter liter;
+ BMLoop *loop;
+ bool is_first = true;
+
+ BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (is_face_sel || (do_moving && (BM_elem_flag_test(loop->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(loop->prev->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(loop->next->v, BM_ELEM_SELECT)))) {
+ float v2_local[3];
+
+ /* lazy init center calc */
+ if (is_first) {
+ BM_face_calc_center_bounds(efa, vmid);
+ is_first = false;
+ }
+ copy_v3_v3(v1, loop->prev->v->co);
+ copy_v3_v3(v2, loop->v->co);
+ copy_v3_v3(v3, loop->next->v->co);
+
+ copy_v3_v3(v2_local, v2);
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ mul_mat3_m4_v3(ob->obmat, v3);
+ }
+
+ float angle = angle_v3v3v3(v1, v2, v3);
+
+ numstr_len = BLI_snprintf_rlen(numstr,
+ sizeof(numstr),
+ "%.3f%s",
+ (is_rad) ? angle : RAD2DEGF(angle),
+ (is_rad) ? "r" : "°");
+ interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
+ mul_m4_v3(ob->obmat, fvec);
+ DRW_text_cache_add(dt, fvec, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+ }
+
+ /* This option is for mesh ops and addons debugging; only available in UI if Blender starts with
+ * --debug */
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_INDICES) {
+ int i;
+
+ /* For now, reuse an appropriate theme color */
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
+
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *v;
+
+ BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ float vec[3];
+ mul_v3_m4v3(vec, ob->obmat, v->co);
+
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
+ DRW_text_cache_add(dt, vec, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+
+ if (em->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *e;
+
+ const bool use_edge_tex_sep = (edge_tex_count == 2);
+ const bool use_edge_tex_len = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN);
+
+ BM_ITER_MESH_INDEX (e, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ float v1_clip[3], v2_clip[3];
+
+ copy_v3_v3(v1, e->v1->co);
+ copy_v3_v3(v2, e->v2->co);
+
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
+ mid_v3_v3v3(vmid, v1_clip, v2_clip);
+ mul_m4_v3(ob->obmat, vmid);
+
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
+ DRW_text_cache_add(
+ dt,
+ vmid,
+ numstr,
+ numstr_len,
+ 0,
+ (use_edge_tex_sep) ? (use_edge_tex_len) ? -edge_tex_sep : edge_tex_sep : 0,
+ txt_flag,
+ col);
+ }
+ }
+ }
+ }
+
+ if (em->selectmode & SCE_SELECT_FACE) {
+ BMFace *f;
+
+ BM_ITER_MESH_INDEX (f, &iter, em->bm, BM_FACES_OF_MESH, i) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_face_calc_center_median(f, v1);
+ mul_m4_v3(ob->obmat, v1);
+
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
+ DRW_text_cache_add(dt, v1, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/draw/intern/draw_manager_text.h b/source/blender/draw/intern/draw_manager_text.h
index 9f5dd1d4beb..393645e614a 100644
--- a/source/blender/draw/intern/draw_manager_text.h
+++ b/source/blender/draw/intern/draw_manager_text.h
@@ -23,7 +23,11 @@
#ifndef __DRAW_MANAGER_TEXT_H__
#define __DRAW_MANAGER_TEXT_H__
+struct ARegion;
struct DRWTextStore;
+struct Object;
+struct UnitSettings;
+struct View3D;
struct DRWTextStore *DRW_text_cache_create(void);
void DRW_text_cache_destroy(struct DRWTextStore *dt);
@@ -37,7 +41,12 @@ void DRW_text_cache_add(struct DRWTextStore *dt,
short flag,
const uchar col[4]);
-void DRW_text_cache_draw(struct DRWTextStore *dt, struct ARegion *ar);
+void DRW_text_cache_draw(struct DRWTextStore *dt, struct ARegion *ar, struct View3D *v3d);
+
+void DRW_text_edit_mesh_measure_stats(struct ARegion *ar,
+ struct View3D *v3d,
+ struct Object *ob,
+ const struct UnitSettings *unit);
enum {
DRW_TEXT_CACHE_ASCII = (1 << 0),
diff --git a/source/blender/draw/modes/shaders/common_colormanagement_lib.glsl b/source/blender/draw/intern/shaders/common_colormanagement_lib.glsl
index 45f711296f3..45f711296f3 100644
--- a/source/blender/draw/modes/shaders/common_colormanagement_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_colormanagement_lib.glsl
diff --git a/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl
index 8a7fb97d98c..8a7fb97d98c 100644
--- a/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl
+++ b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl
diff --git a/source/blender/draw/modes/shaders/common_fxaa_lib.glsl b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
index 9928f350fd0..9eaba00988d 100644
--- a/source/blender/draw/modes/shaders/common_fxaa_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
@@ -879,6 +879,6 @@ vec4 FxaaPixelShader(
if (horzSpan) {
posM.y += pixelOffsetSubpix * lengthSign;
}
- return vec4(FxaaTexTop(tex, posM).xyz, lumaM);
+ return FxaaTexTop(tex, posM);
}
/*==========================================================================*/
diff --git a/source/blender/draw/modes/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl
index d147b193ccf..676492f227d 100644
--- a/source/blender/draw/modes/shaders/common_globals_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl
@@ -1,3 +1,4 @@
+#define COMMON_GLOBALS_LIB
/* keep in sync with GlobalsUboStorage */
layout(std140) uniform globalsBlock
@@ -14,6 +15,7 @@ layout(std140) uniform globalsBlock
vec4 colorLight;
vec4 colorSpeaker;
vec4 colorCamera;
+ vec4 colorCameraPath;
vec4 colorEmpty;
vec4 colorVertex;
vec4 colorVertexSelect;
@@ -68,6 +70,15 @@ layout(std140) uniform globalsBlock
vec4 colorGridAxisY;
vec4 colorGridAxisZ;
+ vec4 colorFaceBack;
+ vec4 colorFaceFront;
+
+ vec4 screenVecs[2];
+ vec4 sizeViewport; /* Inverted size in zw. */
+
+ float sizePixel; /* This one is for dpi scalling */
+ float pixelFac; /* To use with mul_project_m4_v3_zfac() */
+ float sizeObjectCenter;
float sizeLightCenter;
float sizeLightCircle;
float sizeLightCircleShadow;
@@ -79,6 +90,8 @@ layout(std140) uniform globalsBlock
float pad_globalsBlock;
};
+#define sizeViewportInv (sizeViewport.zw)
+
/* data[0] (1st byte flags) */
#define FACE_ACTIVE (1 << 0)
#define FACE_SELECTED (1 << 1)
diff --git a/source/blender/draw/modes/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index cbcdc947bc7..cbcdc947bc7 100644
--- a/source/blender/draw/modes/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
diff --git a/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl b/source/blender/draw/intern/shaders/common_hair_refine_vert.glsl
index 3f5e3f8226f..3f5e3f8226f 100644
--- a/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_refine_vert.glsl
diff --git a/source/blender/draw/intern/shaders/common_smaa_lib.glsl b/source/blender/draw/intern/shaders/common_smaa_lib.glsl
new file mode 100644
index 00000000000..09b573d4bb5
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_smaa_lib.glsl
@@ -0,0 +1,1436 @@
+/**
+ * Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com)
+ * Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
+ * Copyright (C) 2013 Belen Masia (bmasia@unizar.es)
+ * Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com)
+ * Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to
+ * do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software. As clarification, there
+ * is no requirement that the copyright notice and permission be included in
+ * binary distributions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * _______ ___ ___ ___ ___
+ * / || \/ | / \ / \
+ * | (---- | \ / | / ^ \ / ^ \
+ * \ \ | |\/| | / /_\ \ / /_\ \
+ * ----) | | | | | / _____ \ / _____ \
+ * |_______/ |__| |__| /__/ \__\ /__/ \__\
+ *
+ * E N H A N C E D
+ * S U B P I X E L M O R P H O L O G I C A L A N T I A L I A S I N G
+ *
+ * http://www.iryoku.com/smaa/
+ *
+ * Hi, welcome aboard!
+ *
+ * Here you'll find instructions to get the shader up and running as fast as
+ * possible.
+ *
+ * IMPORTANTE NOTICE: when updating, remember to update both this file and the
+ * precomputed textures! They may change from version to version.
+ *
+ * The shader has three passes, chained together as follows:
+ *
+ * |input|------------------�
+ * v |
+ * [ SMAA*EdgeDetection ] |
+ * v |
+ * |edgesTex| |
+ * v |
+ * [ SMAABlendingWeightCalculation ] |
+ * v |
+ * |blendTex| |
+ * v |
+ * [ SMAANeighborhoodBlending ] <------�
+ * v
+ * |output|
+ *
+ * Note that each [pass] has its own vertex and pixel shader. Remember to use
+ * oversized triangles instead of quads to avoid overshading along the
+ * diagonal.
+ *
+ * You've three edge detection methods to choose from: luma, color or depth.
+ * They represent different quality/performance and anti-aliasing/sharpness
+ * tradeoffs, so our recommendation is for you to choose the one that best
+ * suits your particular scenario:
+ *
+ * - Depth edge detection is usually the fastest but it may miss some edges.
+ *
+ * - Luma edge detection is usually more expensive than depth edge detection,
+ * but catches visible edges that depth edge detection can miss.
+ *
+ * - Color edge detection is usually the most expensive one but catches
+ * chroma-only edges.
+ *
+ * For quickstarters: just use luma edge detection.
+ *
+ * The general advice is to not rush the integration process and ensure each
+ * step is done correctly (don't try to integrate SMAA T2x with predicated edge
+ * detection from the start!). Ok then, let's go!
+ *
+ * 1. The first step is to create two RGBA temporal render targets for holding
+ * |edgesTex| and |blendTex|.
+ *
+ * In DX10 or DX11, you can use a RG render target for the edges texture.
+ * In the case of NVIDIA GPUs, using RG render targets seems to actually be
+ * slower.
+ *
+ * On the Xbox 360, you can use the same render target for resolving both
+ * |edgesTex| and |blendTex|, as they aren't needed simultaneously.
+ *
+ * 2. Both temporal render targets |edgesTex| and |blendTex| must be cleared
+ * each frame. Do not forget to clear the alpha channel!
+ *
+ * 3. The next step is loading the two supporting precalculated textures,
+ * 'areaTex' and 'searchTex'. You'll find them in the 'Textures' folder as
+ * C++ headers, and also as regular DDS files. They'll be needed for the
+ * 'SMAABlendingWeightCalculation' pass.
+ *
+ * If you use the C++ headers, be sure to load them in the format specified
+ * inside of them.
+ *
+ * You can also compress 'areaTex' and 'searchTex' using BC5 and BC4
+ * respectively, if you have that option in your content processor pipeline.
+ * When compressing then, you get a non-perceptible quality decrease, and a
+ * marginal performance increase.
+ *
+ * 4. All samplers must be set to linear filtering and clamp.
+ *
+ * After you get the technique working, remember that 64-bit inputs have
+ * half-rate linear filtering on GCN.
+ *
+ * If SMAA is applied to 64-bit color buffers, switching to point filtering
+ * when accesing them will increase the performance. Search for
+ * 'SMAASamplePoint' to see which textures may benefit from point
+ * filtering, and where (which is basically the color input in the edge
+ * detection and resolve passes).
+ *
+ * 5. All texture reads and buffer writes must be non-sRGB, with the exception
+ * of the input read and the output write in
+ * 'SMAANeighborhoodBlending' (and only in this pass!). If sRGB reads in
+ * this last pass are not possible, the technique will work anyway, but
+ * will perform antialiasing in gamma space.
+ *
+ * IMPORTANT: for best results the input read for the color/luma edge
+ * detection should *NOT* be sRGB.
+ *
+ * 6. Before including SMAA.h you'll have to setup the render target metrics,
+ * the target and any optional configuration defines. Optionally you can
+ * use a preset.
+ *
+ * You have the following targets available:
+ * SMAA_HLSL_3
+ * SMAA_HLSL_4
+ * SMAA_HLSL_4_1
+ * SMAA_GLSL_3 *
+ * SMAA_GLSL_4 *
+ *
+ * * (See SMAA_INCLUDE_VS and SMAA_INCLUDE_PS below).
+ *
+ * And four presets:
+ * SMAA_PRESET_LOW (%60 of the quality)
+ * SMAA_PRESET_MEDIUM (%80 of the quality)
+ * SMAA_PRESET_HIGH (%95 of the quality)
+ * SMAA_PRESET_ULTRA (%99 of the quality)
+ *
+ * For example:
+ * #define SMAA_RT_METRICS float4(1.0 / 1280.0, 1.0 / 720.0, 1280.0, 720.0)
+ * #define SMAA_HLSL_4
+ * #define SMAA_PRESET_HIGH
+ * #include "SMAA.h"
+ *
+ * Note that SMAA_RT_METRICS doesn't need to be a macro, it can be a
+ * uniform variable. The code is designed to minimize the impact of not
+ * using a constant value, but it is still better to hardcode it.
+ *
+ * Depending on how you encoded 'areaTex' and 'searchTex', you may have to
+ * add (and customize) the following defines before including SMAA.h:
+ * #define SMAA_AREATEX_SELECT(sample) sample.rg
+ * #define SMAA_SEARCHTEX_SELECT(sample) sample.r
+ *
+ * If your engine is already using porting macros, you can define
+ * SMAA_CUSTOM_SL, and define the porting functions by yourself.
+ *
+ * 7. Then, you'll have to setup the passes as indicated in the scheme above.
+ * You can take a look into SMAA.fx, to see how we did it for our demo.
+ * Checkout the function wrappers, you may want to copy-paste them!
+ *
+ * 8. It's recommended to validate the produced |edgesTex| and |blendTex|.
+ * You can use a screenshot from your engine to compare the |edgesTex|
+ * and |blendTex| produced inside of the engine with the results obtained
+ * with the reference demo.
+ *
+ * 9. After you get the last pass to work, it's time to optimize. You'll have
+ * to initialize a stencil buffer in the first pass (discard is already in
+ * the code), then mask execution by using it the second pass. The last
+ * pass should be executed in all pixels.
+ *
+ *
+ * After this point you can choose to enable predicated thresholding,
+ * temporal supersampling and motion blur integration:
+ *
+ * a) If you want to use predicated thresholding, take a look into
+ * SMAA_PREDICATION; you'll need to pass an extra texture in the edge
+ * detection pass.
+ *
+ * b) If you want to enable temporal supersampling (SMAA T2x):
+ *
+ * 1. The first step is to render using subpixel jitters. I won't go into
+ * detail, but it's as simple as moving each vertex position in the
+ * vertex shader, you can check how we do it in our DX10 demo.
+ *
+ * 2. Then, you must setup the temporal resolve. You may want to take a look
+ * into SMAAResolve for resolving 2x modes. After you get it working, you'll
+ * probably see ghosting everywhere. But fear not, you can enable the
+ * CryENGINE temporal reprojection by setting the SMAA_REPROJECTION macro.
+ * Check out SMAA_DECODE_VELOCITY if your velocity buffer is encoded.
+ *
+ * 3. The next step is to apply SMAA to each subpixel jittered frame, just as
+ * done for 1x.
+ *
+ * 4. At this point you should already have something usable, but for best
+ * results the proper area textures must be set depending on current jitter.
+ * For this, the parameter 'subsampleIndices' of
+ * 'SMAABlendingWeightCalculationPS' must be set as follows, for our T2x
+ * mode:
+ *
+ * @SUBSAMPLE_INDICES
+ *
+ * | S# | Camera Jitter | subsampleIndices |
+ * +----+------------------+---------------------+
+ * | 0 | ( 0.25, -0.25) | float4(1, 1, 1, 0) |
+ * | 1 | (-0.25, 0.25) | float4(2, 2, 2, 0) |
+ *
+ * These jitter positions assume a bottom-to-top y axis. S# stands for the
+ * sample number.
+ *
+ * More information about temporal supersampling here:
+ * http://iryoku.com/aacourse/downloads/13-Anti-Aliasing-Methods-in-CryENGINE-3.pdf
+ *
+ * c) If you want to enable spatial multisampling (SMAA S2x):
+ *
+ * 1. The scene must be rendered using MSAA 2x. The MSAA 2x buffer must be
+ * created with:
+ * - DX10: see below (*)
+ * - DX10.1: D3D10_STANDARD_MULTISAMPLE_PATTERN or
+ * - DX11: D3D11_STANDARD_MULTISAMPLE_PATTERN
+ *
+ * This allows to ensure that the subsample order matches the table in
+ * @SUBSAMPLE_INDICES.
+ *
+ * (*) In the case of DX10, we refer the reader to:
+ * - SMAA::detectMSAAOrder and
+ * - SMAA::msaaReorder
+ *
+ * These functions allow to match the standard multisample patterns by
+ * detecting the subsample order for a specific GPU, and reordering
+ * them appropriately.
+ *
+ * 2. A shader must be run to output each subsample into a separate buffer
+ * (DX10 is required). You can use SMAASeparate for this purpose, or just do
+ * it in an existing pass (for example, in the tone mapping pass, which has
+ * the advantage of feeding tone mapped subsamples to SMAA, which will yield
+ * better results).
+ *
+ * 3. The full SMAA 1x pipeline must be run for each separated buffer, storing
+ * the results in the final buffer. The second run should alpha blend with
+ * the existing final buffer using a blending factor of 0.5.
+ * 'subsampleIndices' must be adjusted as in the SMAA T2x case (see point
+ * b).
+ *
+ * d) If you want to enable temporal supersampling on top of SMAA S2x
+ * (which actually is SMAA 4x):
+ *
+ * 1. SMAA 4x consists on temporally jittering SMAA S2x, so the first step is
+ * to calculate SMAA S2x for current frame. In this case, 'subsampleIndices'
+ * must be set as follows:
+ *
+ * | F# | S# | Camera Jitter | Net Jitter | subsampleIndices |
+ * +----+----+--------------------+-------------------+----------------------+
+ * | 0 | 0 | ( 0.125, 0.125) | ( 0.375, -0.125) | float4(5, 3, 1, 3) |
+ * | 0 | 1 | ( 0.125, 0.125) | (-0.125, 0.375) | float4(4, 6, 2, 3) |
+ * +----+----+--------------------+-------------------+----------------------+
+ * | 1 | 2 | (-0.125, -0.125) | ( 0.125, -0.375) | float4(3, 5, 1, 4) |
+ * | 1 | 3 | (-0.125, -0.125) | (-0.375, 0.125) | float4(6, 4, 2, 4) |
+ *
+ * These jitter positions assume a bottom-to-top y axis. F# stands for the
+ * frame number. S# stands for the sample number.
+ *
+ * 2. After calculating SMAA S2x for current frame (with the new subsample
+ * indices), previous frame must be reprojected as in SMAA T2x mode (see
+ * point b).
+ *
+ * e) If motion blur is used, you may want to do the edge detection pass
+ * together with motion blur. This has two advantages:
+ *
+ * 1. Pixels under heavy motion can be omitted from the edge detection process.
+ * For these pixels we can just store "no edge", as motion blur will take
+ * care of them.
+ * 2. The center pixel tap is reused.
+ *
+ * Note that in this case depth testing should be used instead of stenciling,
+ * as we have to write all the pixels in the motion blur pass.
+ *
+ * That's it!
+ */
+
+//-----------------------------------------------------------------------------
+// SMAA Presets
+
+/**
+ * Note that if you use one of these presets, the following configuration
+ * macros will be ignored if set in the "Configurable Defines" section.
+ */
+
+#if defined(SMAA_PRESET_LOW)
+# define SMAA_THRESHOLD 0.15
+# define SMAA_MAX_SEARCH_STEPS 4
+# define SMAA_DISABLE_DIAG_DETECTION
+# define SMAA_DISABLE_CORNER_DETECTION
+#elif defined(SMAA_PRESET_MEDIUM)
+# define SMAA_THRESHOLD 0.1
+# define SMAA_MAX_SEARCH_STEPS 8
+# define SMAA_DISABLE_DIAG_DETECTION
+# define SMAA_DISABLE_CORNER_DETECTION
+#elif defined(SMAA_PRESET_HIGH)
+# define SMAA_THRESHOLD 0.1
+# define SMAA_MAX_SEARCH_STEPS 16
+# define SMAA_MAX_SEARCH_STEPS_DIAG 8
+# define SMAA_CORNER_ROUNDING 25
+#elif defined(SMAA_PRESET_ULTRA)
+# define SMAA_THRESHOLD 0.05
+# define SMAA_MAX_SEARCH_STEPS 32
+# define SMAA_MAX_SEARCH_STEPS_DIAG 16
+# define SMAA_CORNER_ROUNDING 25
+#endif
+
+//-----------------------------------------------------------------------------
+// Configurable Defines
+
+/**
+ * SMAA_THRESHOLD specifies the threshold or sensitivity to edges.
+ * Lowering this value you will be able to detect more edges at the expense of
+ * performance.
+ *
+ * Range: [0, 0.5]
+ * 0.1 is a reasonable value, and allows to catch most visible edges.
+ * 0.05 is a rather overkill value, that allows to catch 'em all.
+ *
+ * If temporal supersampling is used, 0.2 could be a reasonable value, as low
+ * contrast edges are properly filtered by just 2x.
+ */
+#ifndef SMAA_THRESHOLD
+# define SMAA_THRESHOLD 0.1
+#endif
+
+/**
+ * SMAA_DEPTH_THRESHOLD specifies the threshold for depth edge detection.
+ *
+ * Range: depends on the depth range of the scene.
+ */
+#ifndef SMAA_DEPTH_THRESHOLD
+# define SMAA_DEPTH_THRESHOLD (0.1 * SMAA_THRESHOLD)
+#endif
+
+/**
+ * SMAA_MAX_SEARCH_STEPS specifies the maximum steps performed in the
+ * horizontal/vertical pattern searches, at each side of the pixel.
+ *
+ * In number of pixels, it's actually the double. So the maximum line length
+ * perfectly handled by, for example 16, is 64 (by perfectly, we meant that
+ * longer lines won't look as good, but still antialiased).
+ *
+ * Range: [0, 112]
+ */
+#ifndef SMAA_MAX_SEARCH_STEPS
+# define SMAA_MAX_SEARCH_STEPS 16
+#endif
+
+/**
+ * SMAA_MAX_SEARCH_STEPS_DIAG specifies the maximum steps performed in the
+ * diagonal pattern searches, at each side of the pixel. In this case we jump
+ * one pixel at time, instead of two.
+ *
+ * Range: [0, 20]
+ *
+ * On high-end machines it is cheap (between a 0.8x and 0.9x slower for 16
+ * steps), but it can have a significant impact on older machines.
+ *
+ * Define SMAA_DISABLE_DIAG_DETECTION to disable diagonal processing.
+ */
+#ifndef SMAA_MAX_SEARCH_STEPS_DIAG
+# define SMAA_MAX_SEARCH_STEPS_DIAG 8
+#endif
+
+/**
+ * SMAA_CORNER_ROUNDING specifies how much sharp corners will be rounded.
+ *
+ * Range: [0, 100]
+ *
+ * Define SMAA_DISABLE_CORNER_DETECTION to disable corner processing.
+ */
+#ifndef SMAA_CORNER_ROUNDING
+# define SMAA_CORNER_ROUNDING 25
+#endif
+
+/**
+ * If there is an neighbor edge that has SMAA_LOCAL_CONTRAST_FACTOR times
+ * bigger contrast than current edge, current edge will be discarded.
+ *
+ * This allows to eliminate spurious crossing edges, and is based on the fact
+ * that, if there is too much contrast in a direction, that will hide
+ * perceptually contrast in the other neighbors.
+ */
+#ifndef SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR
+# define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 2.0
+#endif
+
+/**
+ * Predicated thresholding allows to better preserve texture details and to
+ * improve performance, by decreasing the number of detected edges using an
+ * additional buffer like the light accumulation buffer, object ids or even the
+ * depth buffer (the depth buffer usage may be limited to indoor or short range
+ * scenes).
+ *
+ * It locally decreases the luma or color threshold if an edge is found in an
+ * additional buffer (so the global threshold can be higher).
+ *
+ * This method was developed by Playstation EDGE MLAA team, and used in
+ * Killzone 3, by using the light accumulation buffer. More information here:
+ * http://iryoku.com/aacourse/downloads/06-MLAA-on-PS3.pptx
+ */
+#ifndef SMAA_PREDICATION
+# define SMAA_PREDICATION 0
+#endif
+
+/**
+ * Threshold to be used in the additional predication buffer.
+ *
+ * Range: depends on the input, so you'll have to find the magic number that
+ * works for you.
+ */
+#ifndef SMAA_PREDICATION_THRESHOLD
+# define SMAA_PREDICATION_THRESHOLD 0.01
+#endif
+
+/**
+ * How much to scale the global threshold used for luma or color edge
+ * detection when using predication.
+ *
+ * Range: [1, 5]
+ */
+#ifndef SMAA_PREDICATION_SCALE
+# define SMAA_PREDICATION_SCALE 2.0
+#endif
+
+/**
+ * How much to locally decrease the threshold.
+ *
+ * Range: [0, 1]
+ */
+#ifndef SMAA_PREDICATION_STRENGTH
+# define SMAA_PREDICATION_STRENGTH 0.4
+#endif
+
+/**
+ * Temporal reprojection allows to remove ghosting artifacts when using
+ * temporal supersampling. We use the CryEngine 3 method which also introduces
+ * velocity weighting. This feature is of extreme importance for totally
+ * removing ghosting. More information here:
+ * http://iryoku.com/aacourse/downloads/13-Anti-Aliasing-Methods-in-CryENGINE-3.pdf
+ *
+ * Note that you'll need to setup a velocity buffer for enabling reprojection.
+ * For static geometry, saving the previous depth buffer is a viable
+ * alternative.
+ */
+#ifndef SMAA_REPROJECTION
+# define SMAA_REPROJECTION 0
+#endif
+
+/**
+ * SMAA_REPROJECTION_WEIGHT_SCALE controls the velocity weighting. It allows to
+ * remove ghosting trails behind the moving object, which are not removed by
+ * just using reprojection. Using low values will exhibit ghosting, while using
+ * high values will disable temporal supersampling under motion.
+ *
+ * Behind the scenes, velocity weighting removes temporal supersampling when
+ * the velocity of the subsamples differs (meaning they are different objects).
+ *
+ * Range: [0, 80]
+ */
+#ifndef SMAA_REPROJECTION_WEIGHT_SCALE
+# define SMAA_REPROJECTION_WEIGHT_SCALE 30.0
+#endif
+
+/**
+ * On some compilers, discard cannot be used in vertex shaders. Thus, they need
+ * to be compiled separately.
+ */
+#ifndef SMAA_INCLUDE_VS
+# define SMAA_INCLUDE_VS 1
+#endif
+#ifndef SMAA_INCLUDE_PS
+# define SMAA_INCLUDE_PS 1
+#endif
+
+//-----------------------------------------------------------------------------
+// Texture Access Defines
+
+#ifndef SMAA_AREATEX_SELECT
+# if defined(SMAA_HLSL_3)
+# define SMAA_AREATEX_SELECT(sample) sample.ra
+# else
+# define SMAA_AREATEX_SELECT(sample) sample.rg
+# endif
+#endif
+
+#ifndef SMAA_SEARCHTEX_SELECT
+# define SMAA_SEARCHTEX_SELECT(sample) sample.r
+#endif
+
+#ifndef SMAA_DECODE_VELOCITY
+# define SMAA_DECODE_VELOCITY(sample) sample.rg
+#endif
+
+//-----------------------------------------------------------------------------
+// Non-Configurable Defines
+
+#define SMAA_AREATEX_MAX_DISTANCE 16
+#define SMAA_AREATEX_MAX_DISTANCE_DIAG 20
+#define SMAA_AREATEX_PIXEL_SIZE (1.0 / float2(160.0, 560.0))
+#define SMAA_AREATEX_SUBTEX_SIZE (1.0 / 7.0)
+#define SMAA_SEARCHTEX_SIZE float2(66.0, 33.0)
+#define SMAA_SEARCHTEX_PACKED_SIZE float2(64.0, 16.0)
+#define SMAA_CORNER_ROUNDING_NORM (float(SMAA_CORNER_ROUNDING) / 100.0)
+
+//-----------------------------------------------------------------------------
+// Porting Functions
+
+#if defined(SMAA_HLSL_3)
+# define SMAATexture2D(tex) sampler2D tex
+# define SMAATexturePass2D(tex) tex
+# define SMAASampleLevelZero(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0))
+# define SMAASampleLevelZeroPoint(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0))
+# define SMAASampleLevelZeroOffset(tex, coord, offset) \
+ tex2Dlod(tex, float4(coord + offset * SMAA_RT_METRICS.xy, 0.0, 0.0))
+# define SMAASample(tex, coord) tex2D(tex, coord)
+# define SMAASamplePoint(tex, coord) tex2D(tex, coord)
+# define SMAASampleOffset(tex, coord, offset) tex2D(tex, coord + offset * SMAA_RT_METRICS.xy)
+# define SMAA_FLATTEN [flatten]
+# define SMAA_BRANCH [branch]
+#endif
+#if defined(SMAA_HLSL_4) || defined(SMAA_HLSL_4_1)
+SamplerState LinearSampler
+{
+ Filter = MIN_MAG_LINEAR_MIP_POINT;
+ AddressU = Clamp;
+ AddressV = Clamp;
+};
+SamplerState PointSampler
+{
+ Filter = MIN_MAG_MIP_POINT;
+ AddressU = Clamp;
+ AddressV = Clamp;
+};
+# define SMAATexture2D(tex) Texture2D tex
+# define SMAATexturePass2D(tex) tex
+# define SMAASampleLevelZero(tex, coord) tex.SampleLevel(LinearSampler, coord, 0)
+# define SMAASampleLevelZeroPoint(tex, coord) tex.SampleLevel(PointSampler, coord, 0)
+# define SMAASampleLevelZeroOffset(tex, coord, offset) \
+ tex.SampleLevel(LinearSampler, coord, 0, offset)
+# define SMAASample(tex, coord) tex.Sample(LinearSampler, coord)
+# define SMAASamplePoint(tex, coord) tex.Sample(PointSampler, coord)
+# define SMAASampleOffset(tex, coord, offset) tex.Sample(LinearSampler, coord, offset)
+# define SMAA_FLATTEN [flatten]
+# define SMAA_BRANCH [branch]
+# define SMAATexture2DMS2(tex) Texture2DMS<float4, 2> tex
+# define SMAALoad(tex, pos, sample) tex.Load(pos, sample)
+# if defined(SMAA_HLSL_4_1)
+# define SMAAGather(tex, coord) tex.Gather(LinearSampler, coord, 0)
+# endif
+#endif
+#if defined(SMAA_GLSL_3) || defined(SMAA_GLSL_4)
+# define SMAATexture2D(tex) sampler2D tex
+# define SMAATexturePass2D(tex) tex
+# define SMAASampleLevelZero(tex, coord) textureLod(tex, coord, 0.0)
+# define SMAASampleLevelZeroPoint(tex, coord) textureLod(tex, coord, 0.0)
+# define SMAASampleLevelZeroOffset(tex, coord, offset) textureLodOffset(tex, coord, 0.0, offset)
+# define SMAASample(tex, coord) texture(tex, coord)
+# define SMAASamplePoint(tex, coord) texture(tex, coord)
+# define SMAASampleOffset(tex, coord, offset) texture(tex, coord, offset)
+# define SMAA_FLATTEN
+# define SMAA_BRANCH
+# define lerp(a, b, t) mix(a, b, t)
+# define saturate(a) clamp(a, 0.0, 1.0)
+# if defined(SMAA_GLSL_4)
+# define mad(a, b, c) fma(a, b, c)
+# define SMAAGather(tex, coord) textureGather(tex, coord)
+# else
+# define mad(a, b, c) (a * b + c)
+# endif
+# define float2 vec2
+# define float3 vec3
+# define float4 vec4
+# define int2 ivec2
+# define int3 ivec3
+# define int4 ivec4
+# define bool2 bvec2
+# define bool3 bvec3
+# define bool4 bvec4
+#endif
+
+#if !defined(SMAA_HLSL_3) && !defined(SMAA_HLSL_4) && !defined(SMAA_HLSL_4_1) && \
+ !defined(SMAA_GLSL_3) && !defined(SMAA_GLSL_4) && !defined(SMAA_CUSTOM_SL)
+# error you must define the shading language: SMAA_HLSL_*, SMAA_GLSL_* or SMAA_CUSTOM_SL
+#endif
+
+//-----------------------------------------------------------------------------
+// Misc functions
+
+/**
+ * Gathers current pixel, and the top-left neighbors.
+ */
+float3 SMAAGatherNeighbours(float2 texcoord, float4 offset[3], SMAATexture2D(tex))
+{
+#ifdef SMAAGather
+ return SMAAGather(tex, texcoord + SMAA_RT_METRICS.xy * float2(-0.5, -0.5)).grb;
+#else
+ float P = SMAASamplePoint(tex, texcoord).r;
+ float Pleft = SMAASamplePoint(tex, offset[0].xy).r;
+ float Ptop = SMAASamplePoint(tex, offset[0].zw).r;
+ return float3(P, Pleft, Ptop);
+#endif
+}
+
+/**
+ * Adjusts the threshold by means of predication.
+ */
+float2 SMAACalculatePredicatedThreshold(float2 texcoord,
+ float4 offset[3],
+ SMAATexture2D(predicationTex))
+{
+ float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(predicationTex));
+ float2 delta = abs(neighbours.xx - neighbours.yz);
+ float2 edges = step(SMAA_PREDICATION_THRESHOLD, delta);
+ return SMAA_PREDICATION_SCALE * SMAA_THRESHOLD * (1.0 - SMAA_PREDICATION_STRENGTH * edges);
+}
+
+/**
+ * Conditional move:
+ */
+void SMAAMovc(bool2 cond, inout float2 variable, float2 value)
+{
+ SMAA_FLATTEN if (cond.x) variable.x = value.x;
+ SMAA_FLATTEN if (cond.y) variable.y = value.y;
+}
+
+void SMAAMovc(bool4 cond, inout float4 variable, float4 value)
+{
+ SMAAMovc(cond.xy, variable.xy, value.xy);
+ SMAAMovc(cond.zw, variable.zw, value.zw);
+}
+
+#if SMAA_INCLUDE_VS
+//-----------------------------------------------------------------------------
+// Vertex Shaders
+
+/**
+ * Edge Detection Vertex Shader
+ */
+void SMAAEdgeDetectionVS(float2 texcoord, out float4 offset[3])
+{
+ offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-1.0, 0.0, 0.0, -1.0), texcoord.xyxy);
+ offset[1] = mad(SMAA_RT_METRICS.xyxy, float4(1.0, 0.0, 0.0, 1.0), texcoord.xyxy);
+ offset[2] = mad(SMAA_RT_METRICS.xyxy, float4(-2.0, 0.0, 0.0, -2.0), texcoord.xyxy);
+}
+
+/**
+ * Blend Weight Calculation Vertex Shader
+ */
+void SMAABlendingWeightCalculationVS(float2 texcoord, out float2 pixcoord, out float4 offset[3])
+{
+ pixcoord = texcoord * SMAA_RT_METRICS.zw;
+
+ // We will use these offsets for the searches later on (see @PSEUDO_GATHER4):
+ offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-0.25, -0.125, 1.25, -0.125), texcoord.xyxy);
+ offset[1] = mad(SMAA_RT_METRICS.xyxy, float4(-0.125, -0.25, -0.125, 1.25), texcoord.xyxy);
+
+ // And these for the searches, they indicate the ends of the loops:
+ offset[2] = mad(SMAA_RT_METRICS.xxyy,
+ float4(-2.0, 2.0, -2.0, 2.0) * float(SMAA_MAX_SEARCH_STEPS),
+ float4(offset[0].xz, offset[1].yw));
+}
+
+/**
+ * Neighborhood Blending Vertex Shader
+ */
+void SMAANeighborhoodBlendingVS(float2 texcoord, out float4 offset)
+{
+ offset = mad(SMAA_RT_METRICS.xyxy, float4(1.0, 0.0, 0.0, 1.0), texcoord.xyxy);
+}
+#endif // SMAA_INCLUDE_VS
+
+#if SMAA_INCLUDE_PS
+//-----------------------------------------------------------------------------
+// Edge Detection Pixel Shaders (First Pass)
+
+/**
+ * Luma Edge Detection
+ *
+ * IMPORTANT NOTICE: luma edge detection requires gamma-corrected colors, and
+ * thus 'colorTex' should be a non-sRGB texture.
+ */
+float2 SMAALumaEdgeDetectionPS(float2 texcoord,
+ float4 offset[3],
+ SMAATexture2D(colorTex)
+# if SMAA_PREDICATION
+ ,
+ SMAATexture2D(predicationTex)
+# endif
+)
+{
+// Calculate the threshold:
+# if SMAA_PREDICATION
+ float2 threshold = SMAACalculatePredicatedThreshold(
+ texcoord, offset, SMAATexturePass2D(predicationTex));
+# else
+ float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD);
+# endif
+
+ // Calculate lumas:
+ float4 weights = float4(0.2126 * 0.5, 0.7152 * 0.5, 0.0722 * 0.5, 0.5);
+ float L = dot(SMAASamplePoint(colorTex, texcoord).rgba, weights);
+
+ float Lleft = dot(SMAASamplePoint(colorTex, offset[0].xy).rgba, weights);
+ float Ltop = dot(SMAASamplePoint(colorTex, offset[0].zw).rgba, weights);
+
+ // We do the usual threshold:
+ float4 delta;
+ delta.xy = abs(L - float2(Lleft, Ltop));
+ float2 edges = step(threshold, delta.xy);
+
+ // Then discard if there is no edge:
+ if (dot(edges, float2(1.0, 1.0)) == 0.0)
+ discard;
+
+ // Calculate right and bottom deltas:
+ float Lright = dot(SMAASamplePoint(colorTex, offset[1].xy).rgba, weights);
+ float Lbottom = dot(SMAASamplePoint(colorTex, offset[1].zw).rgba, weights);
+ delta.zw = abs(L - float2(Lright, Lbottom));
+
+ // Calculate the maximum delta in the direct neighborhood:
+ float2 maxDelta = max(delta.xy, delta.zw);
+
+ // Calculate left-left and top-top deltas:
+ float Lleftleft = dot(SMAASamplePoint(colorTex, offset[2].xy).rgba, weights);
+ float Ltoptop = dot(SMAASamplePoint(colorTex, offset[2].zw).rgba, weights);
+ delta.zw = abs(float2(Lleft, Ltop) - float2(Lleftleft, Ltoptop));
+
+ // Calculate the final maximum delta:
+ maxDelta = max(maxDelta.xy, delta.zw);
+ float finalDelta = max(maxDelta.x, maxDelta.y);
+
+ // Local contrast adaptation:
+# if !defined(SHADER_API_OPENGL)
+ edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy);
+# endif
+
+ return edges;
+}
+
+/**
+ * Color Edge Detection
+ *
+ * IMPORTANT NOTICE: color edge detection requires gamma-corrected colors, and
+ * thus 'colorTex' should be a non-sRGB texture.
+ */
+float2 SMAAColorEdgeDetectionPS(float2 texcoord,
+ float4 offset[3],
+ SMAATexture2D(colorTex)
+# if SMAA_PREDICATION
+ ,
+ SMAATexture2D(predicationTex)
+# endif
+)
+{
+// Calculate the threshold:
+# if SMAA_PREDICATION
+ float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, predicationTex);
+# else
+ float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD);
+# endif
+
+ // Calculate color deltas:
+ float4 delta;
+ float3 C = SMAASamplePoint(colorTex, texcoord).rgb;
+
+ float3 Cleft = SMAASamplePoint(colorTex, offset[0].xy).rgb;
+ float3 t = abs(C - Cleft);
+ delta.x = max(max(t.r, t.g), t.b);
+
+ float3 Ctop = SMAASamplePoint(colorTex, offset[0].zw).rgb;
+ t = abs(C - Ctop);
+ delta.y = max(max(t.r, t.g), t.b);
+
+ // We do the usual threshold:
+ float2 edges = step(threshold, delta.xy);
+
+ // Then discard if there is no edge:
+ if (dot(edges, float2(1.0, 1.0)) == 0.0)
+ discard;
+
+ // Calculate right and bottom deltas:
+ float3 Cright = SMAASamplePoint(colorTex, offset[1].xy).rgb;
+ t = abs(C - Cright);
+ delta.z = max(max(t.r, t.g), t.b);
+
+ float3 Cbottom = SMAASamplePoint(colorTex, offset[1].zw).rgb;
+ t = abs(C - Cbottom);
+ delta.w = max(max(t.r, t.g), t.b);
+
+ // Calculate the maximum delta in the direct neighborhood:
+ float2 maxDelta = max(delta.xy, delta.zw);
+
+ // Calculate left-left and top-top deltas:
+ float3 Cleftleft = SMAASamplePoint(colorTex, offset[2].xy).rgb;
+ t = abs(C - Cleftleft);
+ delta.z = max(max(t.r, t.g), t.b);
+
+ float3 Ctoptop = SMAASamplePoint(colorTex, offset[2].zw).rgb;
+ t = abs(C - Ctoptop);
+ delta.w = max(max(t.r, t.g), t.b);
+
+ // Calculate the final maximum delta:
+ maxDelta = max(maxDelta.xy, delta.zw);
+ float finalDelta = max(maxDelta.x, maxDelta.y);
+
+ // Local contrast adaptation:
+# if !defined(SHADER_API_OPENGL)
+ edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy);
+# endif
+
+ return edges;
+}
+
+/**
+ * Depth Edge Detection
+ */
+float2 SMAADepthEdgeDetectionPS(float2 texcoord, float4 offset[3], SMAATexture2D(depthTex))
+{
+ float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(depthTex));
+ float2 delta = abs(neighbours.xx - float2(neighbours.y, neighbours.z));
+ float2 edges = step(SMAA_DEPTH_THRESHOLD, delta);
+
+ if (dot(edges, float2(1.0, 1.0)) == 0.0)
+ discard;
+
+ return edges;
+}
+
+//-----------------------------------------------------------------------------
+// Diagonal Search Functions
+
+# if !defined(SMAA_DISABLE_DIAG_DETECTION)
+
+/**
+ * Allows to decode two binary values from a bilinear-filtered access.
+ */
+float2 SMAADecodeDiagBilinearAccess(float2 e)
+{
+ // Bilinear access for fetching 'e' have a 0.25 offset, and we are
+ // interested in the R and G edges:
+ //
+ // +---G---+-------+
+ // | x o R x |
+ // +-------+-------+
+ //
+ // Then, if one of these edge is enabled:
+ // Red: (0.75 * X + 0.25 * 1) => 0.25 or 1.0
+ // Green: (0.75 * 1 + 0.25 * X) => 0.75 or 1.0
+ //
+ // This function will unpack the values (mad + mul + round):
+ // wolframalpha.com: round(x * abs(5 * x - 5 * 0.75)) plot 0 to 1
+ e.r = e.r * abs(5.0 * e.r - 5.0 * 0.75);
+ return round(e);
+}
+
+float4 SMAADecodeDiagBilinearAccess(float4 e)
+{
+ e.rb = e.rb * abs(5.0 * e.rb - 5.0 * 0.75);
+ return round(e);
+}
+
+/**
+ * These functions allows to perform diagonal pattern searches.
+ */
+float2 SMAASearchDiag1(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e)
+{
+ float4 coord = float4(texcoord, -1.0, 1.0);
+ float3 t = float3(SMAA_RT_METRICS.xy, 1.0);
+ while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) && coord.w > 0.9) {
+ coord.xyz = mad(t, float3(dir, 1.0), coord.xyz);
+ e = SMAASampleLevelZero(edgesTex, coord.xy).rg;
+ coord.w = dot(e, float2(0.5, 0.5));
+ }
+ return coord.zw;
+}
+
+float2 SMAASearchDiag2(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e)
+{
+ float4 coord = float4(texcoord, -1.0, 1.0);
+ coord.x += 0.25 * SMAA_RT_METRICS.x; // See @SearchDiag2Optimization
+ float3 t = float3(SMAA_RT_METRICS.xy, 1.0);
+ while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) && coord.w > 0.9) {
+ coord.xyz = mad(t, float3(dir, 1.0), coord.xyz);
+
+ // @SearchDiag2Optimization
+ // Fetch both edges at once using bilinear filtering:
+ e = SMAASampleLevelZero(edgesTex, coord.xy).rg;
+ e = SMAADecodeDiagBilinearAccess(e);
+
+ // Non-optimized version:
+ // e.g = SMAASampleLevelZero(edgesTex, coord.xy).g;
+ // e.r = SMAASampleLevelZeroOffset(edgesTex, coord.xy, int2(1, 0)).r;
+
+ coord.w = dot(e, float2(0.5, 0.5));
+ }
+ return coord.zw;
+}
+
+/**
+ * Similar to SMAAArea, this calculates the area corresponding to a certain
+ * diagonal distance and crossing edges 'e'.
+ */
+float2 SMAAAreaDiag(SMAATexture2D(areaTex), float2 dist, float2 e, float offset)
+{
+ float2 texcoord = mad(
+ float2(SMAA_AREATEX_MAX_DISTANCE_DIAG, SMAA_AREATEX_MAX_DISTANCE_DIAG), e, dist);
+
+ // We do a scale and bias for mapping to texel space:
+ texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE);
+
+ // Diagonal areas are on the second half of the texture:
+ texcoord.x += 0.5;
+
+ // Move to proper place, according to the subpixel offset:
+ texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;
+
+ // Do it!
+ return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord));
+}
+
+/**
+ * This searches for diagonal patterns and returns the corresponding weights.
+ */
+float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex),
+ SMAATexture2D(areaTex),
+ float2 texcoord,
+ float2 e,
+ float4 subsampleIndices)
+{
+ float2 weights = float2(0.0, 0.0);
+
+ // Search for the line ends:
+ float4 d;
+ float2 end;
+ if (e.r > 0.0) {
+ d.xz = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, 1.0), end);
+ d.x += float(end.y > 0.9);
+ }
+ else
+ d.xz = float2(0.0, 0.0);
+ d.yw = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, -1.0), end);
+
+ SMAA_BRANCH
+ if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3
+ // Fetch the crossing edges:
+ float4 coords = mad(
+ float4(-d.x + 0.25, d.x, d.y, -d.y - 0.25), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
+ float4 c;
+ c.xy = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).rg;
+ c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2(1, 0)).rg;
+ c.yxwz = SMAADecodeDiagBilinearAccess(c.xyzw);
+
+ // Non-optimized version:
+ // float4 coords = mad(float4(-d.x, d.x, d.y, -d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
+ // float4 c;
+ // c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g;
+ // c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, 0)).r;
+ // c.z = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).g;
+ // c.w = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, -1)).r;
+
+ // Merge crossing edges at each side into a single value:
+ float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw);
+
+ // Remove the crossing edge if we didn't found the end of the line:
+ SMAAMovc(bool2(step(0.9, d.zw)), cc, float2(0.0, 0.0));
+
+ // Fetch the areas for this line:
+ weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.z);
+ }
+
+ // Search for the line ends:
+ d.xz = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, -1.0), end);
+ if (SMAASampleLevelZeroOffset(edgesTex, texcoord, int2(1, 0)).r > 0.0) {
+ d.yw = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, 1.0), end);
+ d.y += float(end.y > 0.9);
+ }
+ else
+ d.yw = float2(0.0, 0.0);
+
+ SMAA_BRANCH
+ if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3
+ // Fetch the crossing edges:
+ float4 coords = mad(float4(-d.x, -d.x, d.y, d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
+ float4 c;
+ c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g;
+ c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(0, -1)).r;
+ c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2(1, 0)).gr;
+ float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw);
+
+ // Remove the crossing edge if we didn't found the end of the line:
+ SMAAMovc(bool2(step(0.9, d.zw)), cc, float2(0.0, 0.0));
+
+ // Fetch the areas for this line:
+ weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.w).gr;
+ }
+
+ return weights;
+}
+# endif
+
+//-----------------------------------------------------------------------------
+// Horizontal/Vertical Search Functions
+
+/**
+ * This allows to determine how much length should we add in the last step
+ * of the searches. It takes the bilinearly interpolated edge (see
+ * @PSEUDO_GATHER4), and adds 0, 1 or 2, depending on which edges and
+ * crossing edges are active.
+ */
+float SMAASearchLength(SMAATexture2D(searchTex), float2 e, float offset)
+{
+ // The texture is flipped vertically, with left and right cases taking half
+ // of the space horizontally:
+ float2 scale = SMAA_SEARCHTEX_SIZE * float2(0.5, -1.0);
+ float2 bias = SMAA_SEARCHTEX_SIZE * float2(offset, 1.0);
+
+ // Scale and bias to access texel centers:
+ scale += float2(-1.0, 1.0);
+ bias += float2(0.5, -0.5);
+
+ // Convert from pixel coordinates to texcoords:
+ // (We use SMAA_SEARCHTEX_PACKED_SIZE because the texture is cropped)
+ scale *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE;
+ bias *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE;
+
+ // Lookup the search texture:
+ return SMAA_SEARCHTEX_SELECT(SMAASampleLevelZero(searchTex, mad(scale, e, bias)));
+}
+
+/**
+ * Horizontal/vertical search functions for the 2nd pass.
+ */
+float SMAASearchXLeft(SMAATexture2D(edgesTex),
+ SMAATexture2D(searchTex),
+ float2 texcoord,
+ float end)
+{
+ /**
+ * @PSEUDO_GATHER4
+ * This texcoord has been offset by (-0.25, -0.125) in the vertex shader to
+ * sample between edge, thus fetching four edges in a row.
+ * Sampling with different offsets in each direction allows to disambiguate
+ * which edges are active from the four fetched ones.
+ */
+ float2 e = float2(0.0, 1.0);
+ while (texcoord.x > end && e.g > 0.8281 && // Is there some edge not activated?
+ e.r == 0.0) { // Or is there a crossing edge that breaks the line?
+ e = SMAASampleLevelZero(edgesTex, texcoord).rg;
+ texcoord = mad(-float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord);
+ }
+
+ float offset = mad(
+ -(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0), 3.25);
+ return mad(SMAA_RT_METRICS.x, offset, texcoord.x);
+
+ // Non-optimized version:
+ // We correct the previous (-0.25, -0.125) offset we applied:
+ // texcoord.x += 0.25 * SMAA_RT_METRICS.x;
+
+ // The searches are bias by 1, so adjust the coords accordingly:
+ // texcoord.x += SMAA_RT_METRICS.x;
+
+ // Disambiguate the length added by the last step:
+ // texcoord.x += 2.0 * SMAA_RT_METRICS.x; // Undo last step
+ // texcoord.x -= SMAA_RT_METRICS.x * (255.0 / 127.0) *
+ // SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0); return mad(SMAA_RT_METRICS.x, offset,
+ // texcoord.x);
+}
+
+float SMAASearchXRight(SMAATexture2D(edgesTex),
+ SMAATexture2D(searchTex),
+ float2 texcoord,
+ float end)
+{
+ float2 e = float2(0.0, 1.0);
+ while (texcoord.x < end && e.g > 0.8281 && // Is there some edge not activated?
+ e.r == 0.0) { // Or is there a crossing edge that breaks the line?
+ e = SMAASampleLevelZero(edgesTex, texcoord).rg;
+ texcoord = mad(float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord);
+ }
+ float offset = mad(
+ -(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.5), 3.25);
+ return mad(-SMAA_RT_METRICS.x, offset, texcoord.x);
+}
+
+float SMAASearchYUp(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end)
+{
+ float2 e = float2(1.0, 0.0);
+ while (texcoord.y > end && e.r > 0.8281 && // Is there some edge not activated?
+ e.g == 0.0) { // Or is there a crossing edge that breaks the line?
+ e = SMAASampleLevelZero(edgesTex, texcoord).rg;
+ texcoord = mad(-float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord);
+ }
+ float offset = mad(
+ -(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.0), 3.25);
+ return mad(SMAA_RT_METRICS.y, offset, texcoord.y);
+}
+
+float SMAASearchYDown(SMAATexture2D(edgesTex),
+ SMAATexture2D(searchTex),
+ float2 texcoord,
+ float end)
+{
+ float2 e = float2(1.0, 0.0);
+ while (texcoord.y < end && e.r > 0.8281 && // Is there some edge not activated?
+ e.g == 0.0) { // Or is there a crossing edge that breaks the line?
+ e = SMAASampleLevelZero(edgesTex, texcoord).rg;
+ texcoord = mad(float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord);
+ }
+ float offset = mad(
+ -(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.5), 3.25);
+ return mad(-SMAA_RT_METRICS.y, offset, texcoord.y);
+}
+
+/**
+ * Ok, we have the distance and both crossing edges. So, what are the areas
+ * at each side of current edge?
+ */
+float2 SMAAArea(SMAATexture2D(areaTex), float2 dist, float e1, float e2, float offset)
+{
+ // Rounding prevents precision errors of bilinear filtering:
+ float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE, SMAA_AREATEX_MAX_DISTANCE),
+ round(4.0 * float2(e1, e2)),
+ dist);
+
+ // We do a scale and bias for mapping to texel space:
+ texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE);
+
+ // Move to proper place, according to the subpixel offset:
+ texcoord.y = mad(SMAA_AREATEX_SUBTEX_SIZE, offset, texcoord.y);
+
+ // Do it!
+ return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord));
+}
+
+//-----------------------------------------------------------------------------
+// Corner Detection Functions
+
+void SMAADetectHorizontalCornerPattern(SMAATexture2D(edgesTex),
+ inout float2 weights,
+ float4 texcoord,
+ float2 d)
+{
+# if !defined(SMAA_DISABLE_CORNER_DETECTION)
+ float2 leftRight = step(d.xy, d.yx);
+ float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight;
+
+ rounding /= leftRight.x + leftRight.y; // Reduce blending for pixels in the center of a line.
+
+ float2 factor = float2(1.0, 1.0);
+ factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, 1)).r;
+ factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, 1)).r;
+ factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, -2)).r;
+ factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, -2)).r;
+
+ weights *= saturate(factor);
+# endif
+}
+
+void SMAADetectVerticalCornerPattern(SMAATexture2D(edgesTex),
+ inout float2 weights,
+ float4 texcoord,
+ float2 d)
+{
+# if !defined(SMAA_DISABLE_CORNER_DETECTION)
+ float2 leftRight = step(d.xy, d.yx);
+ float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight;
+
+ rounding /= leftRight.x + leftRight.y;
+
+ float2 factor = float2(1.0, 1.0);
+ factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(1, 0)).g;
+ factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, 1)).g;
+ factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(-2, 0)).g;
+ factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(-2, 1)).g;
+
+ weights *= saturate(factor);
+# endif
+}
+
+//-----------------------------------------------------------------------------
+// Blending Weight Calculation Pixel Shader (Second Pass)
+
+float4 SMAABlendingWeightCalculationPS(float2 texcoord,
+ float2 pixcoord,
+ float4 offset[3],
+ SMAATexture2D(edgesTex),
+ SMAATexture2D(areaTex),
+ SMAATexture2D(searchTex),
+ float4 subsampleIndices)
+{ // Just pass zero for SMAA 1x, see @SUBSAMPLE_INDICES.
+ float4 weights = float4(0.0, 0.0, 0.0, 0.0);
+
+ float2 e = SMAASample(edgesTex, texcoord).rg;
+
+ SMAA_BRANCH
+ if (e.g > 0.0) { // Edge at north
+# if !defined(SMAA_DISABLE_DIAG_DETECTION)
+ // Diagonals have both north and west edges, so searching for them in
+ // one of the boundaries is enough.
+ weights.rg = SMAACalculateDiagWeights(
+ SMAATexturePass2D(edgesTex), SMAATexturePass2D(areaTex), texcoord, e, subsampleIndices);
+
+ // We give priority to diagonals, so if we find a diagonal we skip
+ // horizontal/vertical processing.
+ SMAA_BRANCH
+ if (weights.r == -weights.g) { // weights.r + weights.g == 0.0
+# endif
+
+ float2 d;
+
+ // Find the distance to the left:
+ float3 coords;
+ coords.x = SMAASearchXLeft(
+ SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].xy, offset[2].x);
+ coords.y =
+ offset[1].y; // offset[1].y = texcoord.y - 0.25 * SMAA_RT_METRICS.y (@CROSSING_OFFSET)
+ d.x = coords.x;
+
+ // Now fetch the left crossing edges, two at a time using bilinear
+ // filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to
+ // discern what value each edge has:
+ float e1 = SMAASampleLevelZero(edgesTex, coords.xy).r;
+
+ // Find the distance to the right:
+ coords.z = SMAASearchXRight(
+ SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].zw, offset[2].y);
+ d.y = coords.z;
+
+ // We want the distances to be in pixel units (doing this here allow to
+ // better interleave arithmetic and memory accesses):
+ d = abs(round(mad(SMAA_RT_METRICS.zz, d, -pixcoord.xx)));
+
+ // SMAAArea below needs a sqrt, as the areas texture is compressed
+ // quadratically:
+ float2 sqrt_d = sqrt(d);
+
+ // Fetch the right crossing edges:
+ float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.zy, int2(1, 0)).r;
+
+ // Ok, we know how this pattern looks like, now it is time for getting
+ // the actual area:
+ weights.rg = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.y);
+
+ // Fix corners:
+ coords.y = texcoord.y;
+ SMAADetectHorizontalCornerPattern(SMAATexturePass2D(edgesTex), weights.rg, coords.xyzy, d);
+
+# if !defined(SMAA_DISABLE_DIAG_DETECTION)
+ }
+ else
+ e.r = 0.0; // Skip vertical processing.
+# endif
+ }
+
+ SMAA_BRANCH
+ if (e.r > 0.0) { // Edge at west
+ float2 d;
+
+ // Find the distance to the top:
+ float3 coords;
+ coords.y = SMAASearchYUp(
+ SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].xy, offset[2].z);
+ coords.x = offset[0].x; // offset[1].x = texcoord.x - 0.25 * SMAA_RT_METRICS.x;
+ d.x = coords.y;
+
+ // Fetch the top crossing edges:
+ float e1 = SMAASampleLevelZero(edgesTex, coords.xy).g;
+
+ // Find the distance to the bottom:
+ coords.z = SMAASearchYDown(
+ SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].zw, offset[2].w);
+ d.y = coords.z;
+
+ // We want the distances to be in pixel units:
+ d = abs(round(mad(SMAA_RT_METRICS.ww, d, -pixcoord.yy)));
+
+ // SMAAArea below needs a sqrt, as the areas texture is compressed
+ // quadratically:
+ float2 sqrt_d = sqrt(d);
+
+ // Fetch the bottom crossing edges:
+ float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.xz, int2(0, 1)).g;
+
+ // Get the area for this direction:
+ weights.ba = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.x);
+
+ // Fix corners:
+ coords.x = texcoord.x;
+ SMAADetectVerticalCornerPattern(SMAATexturePass2D(edgesTex), weights.ba, coords.xyxz, d);
+ }
+
+ return weights;
+}
+
+//-----------------------------------------------------------------------------
+// Neighborhood Blending Pixel Shader (Third Pass)
+
+float4 SMAANeighborhoodBlendingPS(float2 texcoord,
+ float4 offset,
+ SMAATexture2D(colorTex),
+ SMAATexture2D(blendTex)
+# if SMAA_REPROJECTION
+ ,
+ SMAATexture2D(velocityTex)
+# endif
+)
+{
+ // Fetch the blending weights for current pixel:
+ float4 a;
+ a.x = SMAASample(blendTex, offset.xy).a; // Right
+ a.y = SMAASample(blendTex, offset.zw).g; // Top
+ a.wz = SMAASample(blendTex, texcoord).xz; // Bottom / Left
+
+ // Is there any blending weight with a value greater than 0.0?
+ SMAA_BRANCH
+ if (dot(a, float4(1.0, 1.0, 1.0, 1.0)) < 1e-5) {
+ float4 color = SMAASampleLevelZero(colorTex, texcoord);
+
+# if SMAA_REPROJECTION
+ float2 velocity = SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, texcoord));
+
+ // Pack velocity into the alpha channel:
+ color.a = sqrt(5.0 * length(velocity));
+# endif
+
+ return color;
+ }
+ else {
+ bool h = max(a.x, a.z) > max(a.y, a.w); // max(horizontal) > max(vertical)
+
+ // Calculate the blending offsets:
+ float4 blendingOffset = float4(0.0, a.y, 0.0, a.w);
+ float2 blendingWeight = a.yw;
+ SMAAMovc(bool4(h, h, h, h), blendingOffset, float4(a.x, 0.0, a.z, 0.0));
+ SMAAMovc(bool2(h, h), blendingWeight, a.xz);
+ blendingWeight /= dot(blendingWeight, float2(1.0, 1.0));
+
+ // Calculate the texture coordinates:
+ float4 blendingCoord = mad(
+ blendingOffset, float4(SMAA_RT_METRICS.xy, -SMAA_RT_METRICS.xy), texcoord.xyxy);
+
+ // We exploit bilinear filtering to mix current pixel with the chosen
+ // neighbor:
+ float4 color = blendingWeight.x * SMAASampleLevelZero(colorTex, blendingCoord.xy);
+ color += blendingWeight.y * SMAASampleLevelZero(colorTex, blendingCoord.zw);
+
+# if SMAA_REPROJECTION
+ // Antialias velocity for proper reprojection in a later stage:
+ float2 velocity = blendingWeight.x *
+ SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.xy));
+ velocity += blendingWeight.y *
+ SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.zw));
+
+ // Pack velocity into the alpha channel:
+ color.a = sqrt(5.0 * length(velocity));
+# endif
+
+ return color;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Temporal Resolve Pixel Shader (Optional Pass)
+
+float4 SMAAResolvePS(float2 texcoord,
+ SMAATexture2D(currentColorTex),
+ SMAATexture2D(previousColorTex)
+# if SMAA_REPROJECTION
+ ,
+ SMAATexture2D(velocityTex)
+# endif
+)
+{
+# if SMAA_REPROJECTION
+ // Velocity is assumed to be calculated for motion blur, so we need to
+ // inverse it for reprojection:
+ float2 velocity = -SMAA_DECODE_VELOCITY(SMAASamplePoint(velocityTex, texcoord).rg);
+
+ // Fetch current pixel:
+ float4 current = SMAASamplePoint(currentColorTex, texcoord);
+
+ // Reproject current coordinates and fetch previous pixel:
+ float4 previous = SMAASamplePoint(previousColorTex, texcoord + velocity);
+
+ // Attenuate the previous pixel if the velocity is different:
+ float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0;
+ float weight = 0.5 * saturate(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE);
+
+ // Blend the pixels according to the calculated weight:
+ return lerp(current, previous, weight);
+# else
+ // Just blend the pixels:
+ float4 current = SMAASamplePoint(currentColorTex, texcoord);
+ float4 previous = SMAASamplePoint(previousColorTex, texcoord);
+ return lerp(current, previous, 0.5);
+# endif
+}
+
+//-----------------------------------------------------------------------------
+// Separate Multisamples Pixel Shader (Optional Pass)
+
+# ifdef SMAALoad
+void SMAASeparatePS(float4 position,
+ float2 texcoord,
+ out float4 target0,
+ out float4 target1,
+ SMAATexture2DMS2(colorTexMS))
+{
+ int2 pos = int2(position.xy);
+ target0 = SMAALoad(colorTexMS, pos, 0);
+ target1 = SMAALoad(colorTexMS, pos, 1);
+}
+# endif
+
+//-----------------------------------------------------------------------------
+#endif // SMAA_INCLUDE_PS
diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index 76089d1ae41..6605e1165d4 100644
--- a/source/blender/draw/modes/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -24,6 +24,50 @@ layout(std140) uniform viewBlock
_world_clip_planes_calc_clip_distance(p, clipPlanes)
#endif
+#ifdef COMMON_GLOBALS_LIB
+float mul_project_m4_v3_zfac(in vec3 co)
+{
+ return pixelFac * ((ViewProjectionMatrix[0][3] * co.x) + (ViewProjectionMatrix[1][3] * co.y) +
+ (ViewProjectionMatrix[2][3] * co.z) + ViewProjectionMatrix[3][3]);
+}
+#endif
+
+/* Not the right place but need to be common to all overlay's.
+ * TODO Split to an overlay lib. */
+mat4 extract_matrix_packed_data(mat4 mat, out vec4 dataA, out vec4 dataB)
+{
+ const float div = 1.0 / 255.0;
+ int a = int(mat[0][3]);
+ int b = int(mat[1][3]);
+ int c = int(mat[2][3]);
+ int d = int(mat[3][3]);
+ dataA = vec4(a & 0xFF, a >> 8, b & 0xFF, b >> 8) * div;
+ dataB = vec4(c & 0xFF, c >> 8, d & 0xFF, d >> 8) * div;
+ mat[0][3] = mat[1][3] = mat[2][3] = 0.0;
+ mat[3][3] = 1.0;
+ return mat;
+}
+
+/* Same here, Not the right place but need to be common to all overlay's.
+ * TODO Split to an overlay lib. */
+/* edge_start and edge_pos needs to be in the range [0..sizeViewport]. */
+vec4 pack_line_data(vec2 frag_co, vec2 edge_start, vec2 edge_pos)
+{
+ vec2 edge = edge_start - edge_pos;
+ float len = length(edge);
+ if (len > 0.0) {
+ edge /= len;
+ vec2 perp = vec2(-edge.y, edge.x);
+ float dist = dot(perp, frag_co - edge_start);
+ /* Add 0.1 to diffenrentiate with cleared pixels. */
+ return vec4(perp * 0.5 + 0.5, dist * 0.25 + 0.5 + 0.1, 0.0);
+ }
+ else {
+ /* Default line if the origin is perfectly aligned with a pixel. */
+ return vec4(1.0, 0.0, 0.5 + 0.1, 0.0);
+ }
+}
+
uniform int resourceChunk;
#ifdef GPU_VERTEX_SHADER
@@ -33,7 +77,7 @@ uniform int resourceChunk;
uniform int baseInstance;
# endif
-# ifdef IN_PLACE_INSTANCES
+# if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTRIB)
/* When drawing instances of an object at the same position. */
# define instanceId 0
# elif defined(GPU_DEPRECATED_AMD_DRIVER)
@@ -71,7 +115,10 @@ flat in int resourceIDFrag;
# define resource_id resourceIDFrag
#endif
-#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC)
+/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
+/* clang-format off */
+#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTRIB)
+/* clang-format on */
struct ObjectMatrices {
mat4 drw_modelMatrix;
mat4 drw_modelMatrixInverse;
@@ -135,3 +182,8 @@ uniform mat4 ModelMatrixInverse;
#else
# define GPU_INTEL_VERTEX_SHADER_WORKAROUND
#endif
+
+#define DRW_BASE_SELECTED (1 << 1)
+#define DRW_BASE_FROM_DUPLI (1 << 2)
+#define DRW_BASE_FROM_SET (1 << 3)
+#define DRW_BASE_ACTIVE (1 << 4)
diff --git a/source/blender/draw/intern/smaa_textures.h b/source/blender/draw/intern/smaa_textures.h
new file mode 100644
index 00000000000..74b8260fbe6
--- /dev/null
+++ b/source/blender/draw/intern/smaa_textures.h
@@ -0,0 +1,15086 @@
+/**
+ * Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com)
+ * Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
+ * Copyright (C) 2013 Belen Masia (bmasia@unizar.es)
+ * Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com)
+ * Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to
+ * do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software. As clarification, there
+ * is no requirement that the copyright notice and permission be included in
+ * binary distributions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __SMAA_TEXTURES_H__
+#define __SMAA_TEXTURES_H__
+
+#define AREATEX_WIDTH 160
+#define AREATEX_HEIGHT 560
+#define AREATEX_PITCH (AREATEX_WIDTH * 2)
+#define AREATEX_SIZE (AREATEX_HEIGHT * AREATEX_PITCH)
+
+/* Don't re-wrap large data definitions. */
+/* clang-format off */
+
+/**
+ * Stored in R8G8 format. Load it in the following format:
+ * - DX10: DXGI_FORMAT_R8G8_UNORM
+ */
+static const unsigned char areaTexBytes[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x44, 0x7b, 0x41, 0x5d,
+ 0x42, 0x54, 0x41, 0x4f, 0x42, 0x4b, 0x42, 0x49, 0x42, 0x48, 0x41, 0x47,
+ 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x44, 0x42, 0x44, 0x42, 0x44,
+ 0x42, 0x43, 0x41, 0x43, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43,
+ 0x04, 0x7f, 0x22, 0x3d, 0x2b, 0x3d, 0x30, 0x3d, 0x33, 0x3d, 0x35, 0x3d,
+ 0x37, 0x3d, 0x38, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
+ 0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d,
+ 0x3c, 0x3d, 0x3c, 0x3d, 0x40, 0x7f, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x62, 0x20, 0x4d, 0x2a, 0x48, 0x30, 0x44, 0x33,
+ 0x44, 0x35, 0x44, 0x36, 0x43, 0x37, 0x42, 0x38, 0x43, 0x39, 0x42, 0x39,
+ 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x41, 0x3b,
+ 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x00, 0x5d, 0x0c, 0x49,
+ 0x16, 0x43, 0x1d, 0x41, 0x22, 0x40, 0x26, 0x3f, 0x29, 0x3f, 0x2c, 0x3f,
+ 0x2e, 0x3e, 0x2f, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e, 0x33, 0x3e,
+ 0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x37, 0x3e, 0x37, 0x3e,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x00, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x6d, 0x0b, 0x57, 0x16, 0x4f, 0x1d, 0x4a, 0x22, 0x48, 0x26, 0x47, 0x29,
+ 0x46, 0x2b, 0x44, 0x2d, 0x44, 0x2f, 0x44, 0x30, 0x44, 0x31, 0x44, 0x32,
+ 0x43, 0x33, 0x43, 0x34, 0x43, 0x34, 0x42, 0x35, 0x43, 0x36, 0x42, 0x36,
+ 0x42, 0x37, 0x42, 0x37, 0x00, 0x68, 0x06, 0x54, 0x0d, 0x4b, 0x14, 0x47,
+ 0x19, 0x44, 0x1d, 0x43, 0x20, 0x41, 0x23, 0x41, 0x26, 0x40, 0x27, 0x40,
+ 0x29, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f, 0x2d, 0x3f, 0x2e, 0x3f, 0x2f, 0x3f,
+ 0x30, 0x3f, 0x30, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c,
+ 0x00, 0x2d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x72, 0x06, 0x5f, 0x0d,
+ 0x56, 0x14, 0x4f, 0x19, 0x4d, 0x1d, 0x4a, 0x20, 0x49, 0x23, 0x47, 0x25,
+ 0x46, 0x27, 0x46, 0x29, 0x45, 0x2a, 0x45, 0x2c, 0x44, 0x2d, 0x44, 0x2e,
+ 0x44, 0x2f, 0x43, 0x30, 0x44, 0x30, 0x44, 0x31, 0x43, 0x32, 0x43, 0x33,
+ 0x00, 0x6d, 0x04, 0x5b, 0x09, 0x51, 0x0e, 0x4c, 0x13, 0x48, 0x17, 0x46,
+ 0x1a, 0x44, 0x1d, 0x43, 0x1f, 0x42, 0x22, 0x42, 0x24, 0x41, 0x25, 0x41,
+ 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f,
+ 0x2d, 0x3f, 0x2e, 0x3f, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00,
+ 0x48, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x75, 0x03, 0x64, 0x09, 0x5a, 0x0e, 0x54, 0x13,
+ 0x51, 0x17, 0x4e, 0x1a, 0x4c, 0x1d, 0x49, 0x1f, 0x49, 0x22, 0x48, 0x23,
+ 0x47, 0x25, 0x46, 0x26, 0x46, 0x28, 0x45, 0x29, 0x45, 0x2a, 0x44, 0x2b,
+ 0x44, 0x2c, 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2e, 0x00, 0x70, 0x02, 0x60,
+ 0x07, 0x56, 0x0b, 0x50, 0x0f, 0x4c, 0x12, 0x49, 0x16, 0x47, 0x18, 0x46,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x43, 0x21, 0x42, 0x22, 0x42, 0x24, 0x41,
+ 0x25, 0x41, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00,
+ 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x77, 0x02, 0x68, 0x06, 0x5f, 0x0b, 0x58, 0x0f, 0x54, 0x12, 0x51, 0x15,
+ 0x4f, 0x18, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1f, 0x49, 0x21, 0x48, 0x22,
+ 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x45, 0x27, 0x45, 0x28, 0x45, 0x29,
+ 0x45, 0x2a, 0x44, 0x2b, 0x00, 0x72, 0x02, 0x64, 0x05, 0x5b, 0x08, 0x54,
+ 0x0c, 0x50, 0x0f, 0x4d, 0x12, 0x4a, 0x14, 0x48, 0x17, 0x47, 0x19, 0x46,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x44, 0x20, 0x42, 0x21, 0x42, 0x22, 0x42,
+ 0x24, 0x41, 0x25, 0x41, 0x26, 0x41, 0x27, 0x40, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75,
+ 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x78, 0x02, 0x6b, 0x05,
+ 0x62, 0x08, 0x5b, 0x0c, 0x57, 0x0f, 0x54, 0x12, 0x51, 0x14, 0x4e, 0x17,
+ 0x4d, 0x19, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e, 0x49, 0x20, 0x48, 0x21,
+ 0x48, 0x22, 0x46, 0x24, 0x46, 0x25, 0x46, 0x26, 0x46, 0x27, 0x45, 0x27,
+ 0x00, 0x74, 0x01, 0x66, 0x04, 0x5e, 0x07, 0x57, 0x0a, 0x53, 0x0d, 0x4f,
+ 0x10, 0x4d, 0x12, 0x4b, 0x14, 0x49, 0x16, 0x48, 0x18, 0x46, 0x1a, 0x45,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x20, 0x43, 0x21, 0x42, 0x22, 0x42,
+ 0x23, 0x42, 0x24, 0x41, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56,
+ 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00,
+ 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x79, 0x01, 0x6d, 0x04, 0x65, 0x07, 0x5e, 0x0a,
+ 0x5a, 0x0d, 0x56, 0x0f, 0x54, 0x12, 0x51, 0x14, 0x4f, 0x16, 0x4e, 0x18,
+ 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e, 0x49, 0x1f, 0x48, 0x21,
+ 0x48, 0x22, 0x48, 0x23, 0x47, 0x23, 0x46, 0x25, 0x00, 0x75, 0x01, 0x69,
+ 0x03, 0x61, 0x06, 0x5a, 0x08, 0x56, 0x0b, 0x52, 0x0d, 0x4f, 0x10, 0x4d,
+ 0x12, 0x4b, 0x14, 0x4a, 0x16, 0x48, 0x17, 0x47, 0x19, 0x46, 0x1a, 0x45,
+ 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x20, 0x43, 0x21, 0x42,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37,
+ 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00,
+ 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7a, 0x01, 0x6f, 0x03, 0x67, 0x06, 0x60, 0x08, 0x5d, 0x0b, 0x59, 0x0d,
+ 0x56, 0x10, 0x53, 0x11, 0x51, 0x14, 0x50, 0x15, 0x4e, 0x17, 0x4d, 0x19,
+ 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x48, 0x1e, 0x49, 0x1f, 0x49, 0x20,
+ 0x48, 0x21, 0x48, 0x22, 0x00, 0x76, 0x01, 0x6b, 0x03, 0x63, 0x05, 0x5d,
+ 0x07, 0x58, 0x09, 0x54, 0x0c, 0x52, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c,
+ 0x13, 0x4a, 0x15, 0x49, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x45,
+ 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a,
+ 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00,
+ 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x01, 0x71, 0x02,
+ 0x69, 0x05, 0x63, 0x07, 0x5f, 0x09, 0x5b, 0x0c, 0x58, 0x0e, 0x55, 0x10,
+ 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4e, 0x16, 0x4e, 0x18, 0x4c, 0x19,
+ 0x4c, 0x1a, 0x4a, 0x1c, 0x4b, 0x1d, 0x49, 0x1e, 0x49, 0x1f, 0x49, 0x20,
+ 0x00, 0x77, 0x00, 0x6c, 0x02, 0x65, 0x04, 0x5f, 0x06, 0x5a, 0x08, 0x57,
+ 0x0a, 0x54, 0x0c, 0x51, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c, 0x13, 0x4a,
+ 0x15, 0x49, 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x1a, 0x46, 0x1b, 0x45,
+ 0x1c, 0x45, 0x1d, 0x45, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69,
+ 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00,
+ 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x00, 0x72, 0x02, 0x6b, 0x04, 0x64, 0x06,
+ 0x61, 0x08, 0x5d, 0x0a, 0x5a, 0x0c, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11,
+ 0x52, 0x13, 0x50, 0x15, 0x4f, 0x16, 0x4e, 0x17, 0x4d, 0x18, 0x4b, 0x1a,
+ 0x4b, 0x1a, 0x4b, 0x1c, 0x4b, 0x1d, 0x49, 0x1d, 0x00, 0x77, 0x00, 0x6e,
+ 0x02, 0x66, 0x04, 0x61, 0x05, 0x5c, 0x07, 0x59, 0x09, 0x56, 0x0b, 0x53,
+ 0x0d, 0x51, 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a,
+ 0x15, 0x48, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x46, 0x1b, 0x45,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53,
+ 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7c, 0x00, 0x73, 0x02, 0x6c, 0x03, 0x66, 0x05, 0x63, 0x07, 0x5e, 0x09,
+ 0x5c, 0x0b, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13,
+ 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x17, 0x4c, 0x18, 0x4c, 0x19, 0x4c, 0x1a,
+ 0x4b, 0x1a, 0x4b, 0x1c, 0x00, 0x77, 0x00, 0x6f, 0x02, 0x68, 0x03, 0x63,
+ 0x05, 0x5e, 0x06, 0x5a, 0x08, 0x57, 0x0a, 0x55, 0x0b, 0x53, 0x0d, 0x50,
+ 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x49,
+ 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x19, 0x46, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c,
+ 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e,
+ 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00,
+ 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7c, 0x00, 0x74, 0x02,
+ 0x6e, 0x03, 0x68, 0x05, 0x64, 0x06, 0x60, 0x08, 0x5d, 0x0a, 0x5a, 0x0b,
+ 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x14,
+ 0x50, 0x15, 0x4d, 0x16, 0x4e, 0x18, 0x4c, 0x18, 0x4c, 0x19, 0x4c, 0x1a,
+ 0x00, 0x78, 0x00, 0x70, 0x01, 0x69, 0x03, 0x64, 0x04, 0x60, 0x06, 0x5c,
+ 0x07, 0x59, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x52, 0x0d, 0x50, 0x0f, 0x4f,
+ 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x48,
+ 0x17, 0x48, 0x18, 0x47, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71,
+ 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c,
+ 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
+ 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00,
+ 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x75, 0x01, 0x6f, 0x02, 0x69, 0x04,
+ 0x65, 0x06, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0b, 0x5a, 0x0c, 0x58, 0x0d,
+ 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x13, 0x4f, 0x15,
+ 0x4e, 0x15, 0x4e, 0x17, 0x4d, 0x18, 0x4c, 0x18, 0x00, 0x78, 0x00, 0x71,
+ 0x01, 0x6a, 0x03, 0x66, 0x04, 0x61, 0x05, 0x5d, 0x06, 0x5a, 0x08, 0x58,
+ 0x09, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0e, 0x50, 0x0f, 0x4e, 0x10, 0x4e,
+ 0x11, 0x4c, 0x13, 0x4c, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x49, 0x16, 0x48,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62,
+ 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e,
+ 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00,
+ 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00,
+ 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7d, 0x00, 0x76, 0x01, 0x70, 0x02, 0x6a, 0x03, 0x67, 0x05, 0x63, 0x06,
+ 0x60, 0x08, 0x5d, 0x09, 0x5b, 0x0b, 0x59, 0x0c, 0x57, 0x0d, 0x55, 0x0e,
+ 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x4f, 0x13, 0x50, 0x15, 0x4f, 0x15,
+ 0x4e, 0x16, 0x4e, 0x18, 0x00, 0x79, 0x00, 0x71, 0x01, 0x6c, 0x02, 0x66,
+ 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5c, 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55,
+ 0x0b, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c,
+ 0x13, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x4a, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
+ 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51,
+ 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00,
+ 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00,
+ 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x76, 0x01,
+ 0x71, 0x02, 0x6c, 0x03, 0x68, 0x05, 0x64, 0x06, 0x61, 0x07, 0x5e, 0x09,
+ 0x5c, 0x0a, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0e, 0x55, 0x0e, 0x55, 0x11,
+ 0x52, 0x11, 0x51, 0x12, 0x51, 0x13, 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x15,
+ 0x00, 0x79, 0x00, 0x72, 0x01, 0x6d, 0x02, 0x68, 0x03, 0x63, 0x04, 0x60,
+ 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x53,
+ 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c,
+ 0x13, 0x4b, 0x14, 0x4a, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x1f, 0x00, 0x3f,
+ 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c,
+ 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x58, 0x00, 0x70, 0x00, 0x77,
+ 0x00, 0x79, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x3f,
+ 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c,
+ 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x1f, 0x1f, 0x00, 0x3f, 0x00, 0x66, 0x00, 0x72,
+ 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x77, 0x01, 0x72, 0x02, 0x6d, 0x03,
+ 0x69, 0x04, 0x66, 0x06, 0x63, 0x07, 0x5f, 0x08, 0x5e, 0x09, 0x5c, 0x0b,
+ 0x5a, 0x0c, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x51, 0x11,
+ 0x52, 0x12, 0x51, 0x13, 0x50, 0x14, 0x50, 0x15, 0x00, 0x79, 0x00, 0x73,
+ 0x01, 0x6d, 0x02, 0x69, 0x03, 0x65, 0x04, 0x61, 0x05, 0x5e, 0x06, 0x5c,
+ 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54, 0x0d, 0x53, 0x0d, 0x51,
+ 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c, 0x13, 0x4b,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x3f, 0x00, 0x5c,
+ 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a,
+ 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d,
+ 0x00, 0x58, 0x00, 0x44, 0x00, 0x55, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x72,
+ 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c,
+ 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c,
+ 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a,
+ 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d,
+ 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71,
+ 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c,
+ 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7d, 0x00, 0x78, 0x01, 0x72, 0x02, 0x6e, 0x02, 0x6a, 0x03, 0x67, 0x05,
+ 0x64, 0x06, 0x60, 0x07, 0x5f, 0x09, 0x5c, 0x0a, 0x5b, 0x0b, 0x5a, 0x0c,
+ 0x57, 0x0c, 0x56, 0x0e, 0x55, 0x0f, 0x53, 0x11, 0x52, 0x11, 0x52, 0x12,
+ 0x51, 0x13, 0x50, 0x13, 0x00, 0x79, 0x00, 0x73, 0x01, 0x6e, 0x02, 0x69,
+ 0x03, 0x66, 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58,
+ 0x09, 0x56, 0x0b, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50,
+ 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4d, 0x12, 0x4c, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59,
+ 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76,
+ 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x70, 0x00, 0x55,
+ 0x00, 0x20, 0x00, 0x3e, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x63, 0x00, 0x6a,
+ 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78,
+ 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x3f, 0x00, 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59,
+ 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76,
+ 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x66, 0x00, 0x3f, 0x00,
+ 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a,
+ 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78,
+ 0x00, 0x79, 0x00, 0x7a, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x01,
+ 0x73, 0x02, 0x6e, 0x02, 0x6b, 0x03, 0x68, 0x05, 0x65, 0x06, 0x61, 0x07,
+ 0x5f, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0d,
+ 0x56, 0x0e, 0x54, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12, 0x51, 0x13,
+ 0x00, 0x79, 0x00, 0x74, 0x00, 0x6f, 0x02, 0x6a, 0x03, 0x66, 0x04, 0x63,
+ 0x05, 0x60, 0x05, 0x5e, 0x06, 0x5b, 0x07, 0x59, 0x09, 0x58, 0x09, 0x55,
+ 0x0b, 0x55, 0x0c, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50, 0x0f, 0x4e,
+ 0x11, 0x4e, 0x11, 0x4d, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56,
+ 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71,
+ 0x00, 0x73, 0x00, 0x75, 0x00, 0x77, 0x00, 0x67, 0x00, 0x3e, 0x00, 0x0d,
+ 0x00, 0x28, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64,
+ 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00,
+ 0x2d, 0x00, 0x01, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56,
+ 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71,
+ 0x00, 0x73, 0x00, 0x75, 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x00, 0x01, 0x01,
+ 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64,
+ 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x00, 0x74, 0x01, 0x6f, 0x02,
+ 0x6c, 0x03, 0x68, 0x04, 0x65, 0x05, 0x62, 0x06, 0x61, 0x07, 0x5f, 0x09,
+ 0x5c, 0x09, 0x5b, 0x0b, 0x5a, 0x0b, 0x58, 0x0c, 0x57, 0x0d, 0x55, 0x0e,
+ 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12, 0x00, 0x79, 0x00, 0x74,
+ 0x00, 0x70, 0x01, 0x6b, 0x02, 0x67, 0x03, 0x64, 0x04, 0x61, 0x05, 0x5f,
+ 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54,
+ 0x0c, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54,
+ 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e,
+ 0x00, 0x79, 0x00, 0x6e, 0x00, 0x50, 0x00, 0x28, 0x00, 0x01, 0x00, 0x1b,
+ 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61,
+ 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00,
+ 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54,
+ 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e,
+ 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x1b,
+ 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61,
+ 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x21, 0x5d, 0x0c, 0x68,
+ 0x06, 0x6d, 0x04, 0x71, 0x02, 0x72, 0x02, 0x74, 0x01, 0x75, 0x01, 0x76,
+ 0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79,
+ 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x7a,
+ 0x42, 0x40, 0x17, 0x55, 0x0c, 0x60, 0x08, 0x66, 0x05, 0x6a, 0x04, 0x6d,
+ 0x03, 0x6f, 0x02, 0x71, 0x02, 0x73, 0x01, 0x73, 0x01, 0x74, 0x01, 0x75,
+ 0x01, 0x76, 0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78,
+ 0x00, 0x78, 0x00, 0x78, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x21, 0x5d, 0x0c, 0x68,
+ 0x06, 0x6d, 0x04, 0x71, 0x02, 0x72, 0x02, 0x74, 0x01, 0x75, 0x01, 0x76,
+ 0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79,
+ 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x7a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53,
+ 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x7b, 0x00, 0x72,
+ 0x00, 0x5a, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x16, 0x00, 0x28,
+ 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e,
+ 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53,
+ 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x7a, 0x00, 0x71, 0x00,
+ 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x28,
+ 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e,
+ 0x00, 0x62, 0x00, 0x65, 0x2b, 0x49, 0x16, 0x53, 0x0d, 0x5b, 0x09, 0x60,
+ 0x07, 0x64, 0x05, 0x67, 0x04, 0x69, 0x03, 0x6b, 0x03, 0x6c, 0x02, 0x6e,
+ 0x02, 0x6f, 0x02, 0x70, 0x01, 0x71, 0x01, 0x71, 0x01, 0x72, 0x01, 0x73,
+ 0x01, 0x73, 0x01, 0x74, 0x00, 0x74, 0x00, 0x75, 0x57, 0x16, 0x2d, 0x2c,
+ 0x1b, 0x3b, 0x12, 0x45, 0x0d, 0x4d, 0x0b, 0x53, 0x08, 0x57, 0x07, 0x5b,
+ 0x05, 0x5e, 0x05, 0x61, 0x04, 0x63, 0x04, 0x65, 0x03, 0x67, 0x02, 0x68,
+ 0x02, 0x69, 0x02, 0x6b, 0x02, 0x6c, 0x01, 0x6d, 0x01, 0x6e, 0x01, 0x6f,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x2b, 0x49, 0x16, 0x53, 0x0d, 0x5b, 0x09, 0x60,
+ 0x07, 0x64, 0x05, 0x67, 0x04, 0x69, 0x03, 0x6b, 0x03, 0x6c, 0x02, 0x6e,
+ 0x02, 0x6f, 0x02, 0x70, 0x01, 0x71, 0x01, 0x71, 0x01, 0x72, 0x01, 0x73,
+ 0x01, 0x73, 0x01, 0x74, 0x00, 0x74, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
+ 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52,
+ 0x00, 0x57, 0x00, 0x5b, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a,
+ 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30,
+ 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00,
+ 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13,
+ 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52,
+ 0x00, 0x57, 0x00, 0x5b, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00,
+ 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30,
+ 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b,
+ 0x31, 0x43, 0x1d, 0x4b, 0x14, 0x51, 0x0e, 0x56, 0x0b, 0x5b, 0x08, 0x5e,
+ 0x07, 0x61, 0x06, 0x63, 0x05, 0x65, 0x04, 0x67, 0x04, 0x68, 0x03, 0x69,
+ 0x03, 0x6a, 0x03, 0x6c, 0x02, 0x6d, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x6f,
+ 0x02, 0x70, 0x01, 0x70, 0x61, 0x0c, 0x3b, 0x1b, 0x28, 0x28, 0x1d, 0x32,
+ 0x16, 0x3a, 0x11, 0x41, 0x0e, 0x47, 0x0c, 0x4b, 0x0a, 0x4f, 0x09, 0x53,
+ 0x07, 0x55, 0x06, 0x58, 0x05, 0x5a, 0x05, 0x5c, 0x05, 0x5e, 0x04, 0x60,
+ 0x04, 0x61, 0x04, 0x63, 0x03, 0x64, 0x02, 0x66, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x31, 0x43, 0x1d, 0x4b, 0x14, 0x51, 0x0e, 0x56, 0x0b, 0x5b, 0x08, 0x5e,
+ 0x07, 0x61, 0x06, 0x63, 0x05, 0x65, 0x04, 0x67, 0x04, 0x68, 0x03, 0x69,
+ 0x03, 0x6a, 0x03, 0x6c, 0x02, 0x6d, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x6f,
+ 0x02, 0x70, 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51,
+ 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28,
+ 0x00, 0x13, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35,
+ 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00,
+ 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51,
+ 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00,
+ 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35,
+ 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x33, 0x41, 0x22, 0x46,
+ 0x19, 0x4c, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5d,
+ 0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x66, 0x04, 0x66,
+ 0x04, 0x68, 0x03, 0x69, 0x03, 0x69, 0x03, 0x6a, 0x03, 0x6b, 0x02, 0x6c,
+ 0x67, 0x07, 0x45, 0x12, 0x32, 0x1d, 0x26, 0x26, 0x1e, 0x2e, 0x18, 0x34,
+ 0x14, 0x3a, 0x11, 0x3f, 0x0f, 0x44, 0x0c, 0x47, 0x0b, 0x4b, 0x0a, 0x4d,
+ 0x09, 0x51, 0x07, 0x52, 0x07, 0x55, 0x06, 0x57, 0x05, 0x58, 0x05, 0x5a,
+ 0x05, 0x5c, 0x04, 0x5d, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x33, 0x41, 0x22, 0x46,
+ 0x19, 0x4c, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5d,
+ 0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x66, 0x04, 0x66,
+ 0x04, 0x68, 0x03, 0x69, 0x03, 0x69, 0x03, 0x6a, 0x03, 0x6b, 0x02, 0x6c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27,
+ 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x7d, 0x00, 0x79,
+ 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39,
+ 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00,
+ 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27,
+ 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x7d, 0x00, 0x79, 0x00,
+ 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39,
+ 0x00, 0x40, 0x00, 0x46, 0x35, 0x40, 0x27, 0x44, 0x1d, 0x48, 0x17, 0x4c,
+ 0x12, 0x50, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5e, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63, 0x04, 0x65,
+ 0x04, 0x66, 0x04, 0x66, 0x04, 0x67, 0x03, 0x68, 0x6b, 0x05, 0x4d, 0x0d,
+ 0x3b, 0x16, 0x2e, 0x1e, 0x25, 0x25, 0x1f, 0x2b, 0x1a, 0x31, 0x16, 0x36,
+ 0x13, 0x3a, 0x10, 0x3e, 0x0f, 0x42, 0x0d, 0x45, 0x0c, 0x47, 0x0a, 0x4a,
+ 0x0a, 0x4c, 0x09, 0x4f, 0x07, 0x51, 0x07, 0x52, 0x07, 0x54, 0x06, 0x56,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x35, 0x40, 0x27, 0x44, 0x1d, 0x48, 0x17, 0x4c,
+ 0x12, 0x50, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5e, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63, 0x04, 0x65,
+ 0x04, 0x66, 0x04, 0x66, 0x04, 0x67, 0x03, 0x68, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c,
+ 0x00, 0x34, 0x00, 0x3b, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64,
+ 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00,
+ 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c,
+ 0x00, 0x34, 0x00, 0x3b, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00,
+ 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b,
+ 0x37, 0x3f, 0x29, 0x43, 0x21, 0x46, 0x1a, 0x49, 0x16, 0x4d, 0x12, 0x50,
+ 0x10, 0x52, 0x0d, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5d, 0x06, 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63,
+ 0x04, 0x64, 0x04, 0x65, 0x6e, 0x04, 0x53, 0x0a, 0x41, 0x11, 0x34, 0x18,
+ 0x2b, 0x1f, 0x24, 0x24, 0x1f, 0x29, 0x1b, 0x2e, 0x17, 0x33, 0x15, 0x37,
+ 0x12, 0x3a, 0x10, 0x3d, 0x0f, 0x40, 0x0d, 0x43, 0x0c, 0x45, 0x0c, 0x48,
+ 0x0a, 0x4a, 0x0a, 0x4c, 0x09, 0x4e, 0x07, 0x4f, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x37, 0x3f, 0x29, 0x43, 0x21, 0x46, 0x1a, 0x49, 0x16, 0x4d, 0x12, 0x50,
+ 0x10, 0x52, 0x0d, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5d, 0x06, 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63,
+ 0x04, 0x64, 0x04, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30,
+ 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b,
+ 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c,
+ 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00,
+ 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30,
+ 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00,
+ 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x0c,
+ 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x38, 0x3f, 0x2c, 0x41,
+ 0x23, 0x44, 0x1d, 0x47, 0x19, 0x4a, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x52,
+ 0x0e, 0x54, 0x0c, 0x56, 0x0b, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x61, 0x05, 0x61, 0x05, 0x62,
+ 0x70, 0x03, 0x58, 0x08, 0x47, 0x0e, 0x3a, 0x14, 0x31, 0x1a, 0x29, 0x1f,
+ 0x24, 0x24, 0x20, 0x28, 0x1c, 0x2d, 0x19, 0x31, 0x16, 0x34, 0x14, 0x37,
+ 0x12, 0x3a, 0x10, 0x3d, 0x0f, 0x3f, 0x0e, 0x42, 0x0c, 0x44, 0x0c, 0x46,
+ 0x0b, 0x47, 0x0a, 0x4a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x38, 0x3f, 0x2c, 0x41,
+ 0x23, 0x44, 0x1d, 0x47, 0x19, 0x4a, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x52,
+ 0x0e, 0x54, 0x0c, 0x56, 0x0b, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x61, 0x05, 0x61, 0x05, 0x62,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x7e, 0x00, 0x7c,
+ 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35,
+ 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15,
+ 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00,
+ 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x7e, 0x00, 0x7c, 0x00,
+ 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00,
+ 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15,
+ 0x00, 0x1e, 0x00, 0x26, 0x39, 0x3f, 0x2e, 0x41, 0x26, 0x43, 0x20, 0x46,
+ 0x1b, 0x48, 0x17, 0x4b, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x51, 0x0e, 0x53,
+ 0x0d, 0x55, 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x60, 0x71, 0x02, 0x5b, 0x07,
+ 0x4c, 0x0c, 0x3f, 0x11, 0x36, 0x16, 0x2e, 0x1b, 0x29, 0x20, 0x24, 0x23,
+ 0x20, 0x28, 0x1d, 0x2b, 0x19, 0x2f, 0x17, 0x32, 0x16, 0x35, 0x12, 0x37,
+ 0x12, 0x3a, 0x10, 0x3c, 0x0f, 0x3f, 0x0e, 0x41, 0x0c, 0x42, 0x0c, 0x45,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x39, 0x3f, 0x2e, 0x41, 0x26, 0x43, 0x20, 0x46,
+ 0x1b, 0x48, 0x17, 0x4b, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x51, 0x0e, 0x53,
+ 0x0d, 0x55, 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x13, 0x00, 0x1b, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f,
+ 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23,
+ 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00,
+ 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00,
+ 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x13, 0x00, 0x1b, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00,
+ 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00,
+ 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b,
+ 0x39, 0x3e, 0x2f, 0x40, 0x28, 0x42, 0x22, 0x45, 0x1d, 0x47, 0x19, 0x49,
+ 0x16, 0x4b, 0x14, 0x4d, 0x11, 0x4f, 0x10, 0x51, 0x0f, 0x53, 0x0d, 0x54,
+ 0x0c, 0x55, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x07, 0x5c, 0x07, 0x5e, 0x73, 0x02, 0x5e, 0x05, 0x4f, 0x0a, 0x44, 0x0f,
+ 0x3a, 0x13, 0x33, 0x18, 0x2d, 0x1c, 0x27, 0x20, 0x23, 0x23, 0x20, 0x27,
+ 0x1d, 0x2a, 0x1a, 0x2d, 0x18, 0x30, 0x16, 0x33, 0x14, 0x35, 0x12, 0x38,
+ 0x12, 0x3a, 0x10, 0x3c, 0x0f, 0x3e, 0x0f, 0x41, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x39, 0x3e, 0x2f, 0x40, 0x28, 0x42, 0x22, 0x45, 0x1d, 0x47, 0x19, 0x49,
+ 0x16, 0x4b, 0x14, 0x4d, 0x11, 0x4f, 0x10, 0x51, 0x0f, 0x53, 0x0d, 0x54,
+ 0x0c, 0x55, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x07, 0x5c, 0x07, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12,
+ 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e,
+ 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15,
+ 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00,
+ 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00,
+ 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12,
+ 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00,
+ 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x3a, 0x3e, 0x31, 0x40,
+ 0x29, 0x42, 0x23, 0x44, 0x1f, 0x46, 0x1b, 0x48, 0x18, 0x4a, 0x15, 0x4c,
+ 0x13, 0x4d, 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x55,
+ 0x0b, 0x56, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x74, 0x01, 0x62, 0x05, 0x53, 0x08, 0x47, 0x0c, 0x3e, 0x11, 0x37, 0x15,
+ 0x31, 0x19, 0x2b, 0x1d, 0x27, 0x20, 0x23, 0x23, 0x20, 0x26, 0x1d, 0x2a,
+ 0x1b, 0x2c, 0x19, 0x2f, 0x16, 0x31, 0x16, 0x34, 0x13, 0x35, 0x12, 0x38,
+ 0x12, 0x3b, 0x0f, 0x3b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3a, 0x3e, 0x31, 0x40,
+ 0x29, 0x42, 0x23, 0x44, 0x1f, 0x46, 0x1b, 0x48, 0x18, 0x4a, 0x15, 0x4c,
+ 0x13, 0x4d, 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x55,
+ 0x0b, 0x56, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x7e, 0x00, 0x7d,
+ 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c,
+ 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00,
+ 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00,
+ 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7e, 0x00, 0x7d, 0x00,
+ 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00,
+ 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x3a, 0x3e, 0x32, 0x3f, 0x2b, 0x41, 0x25, 0x43,
+ 0x21, 0x45, 0x1d, 0x46, 0x1a, 0x48, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e,
+ 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55,
+ 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x58, 0x09, 0x59, 0x75, 0x01, 0x64, 0x04,
+ 0x56, 0x07, 0x4b, 0x0b, 0x42, 0x0f, 0x3a, 0x12, 0x34, 0x16, 0x2f, 0x19,
+ 0x2a, 0x1d, 0x26, 0x20, 0x23, 0x23, 0x21, 0x26, 0x1d, 0x29, 0x1b, 0x2b,
+ 0x19, 0x2e, 0x18, 0x30, 0x16, 0x32, 0x15, 0x35, 0x12, 0x35, 0x12, 0x38,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x3a, 0x3e, 0x32, 0x3f, 0x2b, 0x41, 0x25, 0x43,
+ 0x21, 0x45, 0x1d, 0x46, 0x1a, 0x48, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e,
+ 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55,
+ 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x58, 0x09, 0x59, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75,
+ 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b,
+ 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
+ 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00,
+ 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00,
+ 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x3b, 0x3e, 0x33, 0x3f, 0x2c, 0x41, 0x27, 0x42, 0x22, 0x44, 0x1f, 0x45,
+ 0x1c, 0x47, 0x19, 0x49, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e, 0x11, 0x4f,
+ 0x10, 0x50, 0x0f, 0x51, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x0b, 0x55,
+ 0x0b, 0x57, 0x0a, 0x58, 0x76, 0x01, 0x66, 0x04, 0x58, 0x06, 0x4d, 0x0a,
+ 0x45, 0x0d, 0x3e, 0x10, 0x37, 0x14, 0x32, 0x17, 0x2d, 0x1a, 0x2a, 0x1d,
+ 0x26, 0x21, 0x22, 0x22, 0x21, 0x26, 0x1d, 0x28, 0x1c, 0x2b, 0x19, 0x2c,
+ 0x19, 0x30, 0x16, 0x30, 0x16, 0x33, 0x14, 0x35, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x3b, 0x3e, 0x33, 0x3f, 0x2c, 0x41, 0x27, 0x42, 0x22, 0x44, 0x1f, 0x45,
+ 0x1c, 0x47, 0x19, 0x49, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e, 0x11, 0x4f,
+ 0x10, 0x50, 0x0f, 0x51, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x0b, 0x55,
+ 0x0b, 0x57, 0x0a, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3e, 0x33, 0x3f,
+ 0x2d, 0x40, 0x28, 0x42, 0x24, 0x44, 0x20, 0x45, 0x1d, 0x46, 0x1a, 0x48,
+ 0x18, 0x49, 0x16, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x10, 0x50,
+ 0x0f, 0x51, 0x0f, 0x53, 0x0d, 0x53, 0x0d, 0x55, 0x0b, 0x55, 0x0b, 0x56,
+ 0x77, 0x01, 0x67, 0x03, 0x5a, 0x05, 0x51, 0x09, 0x48, 0x0c, 0x40, 0x0f,
+ 0x3a, 0x12, 0x35, 0x16, 0x30, 0x18, 0x2c, 0x1b, 0x29, 0x1d, 0x26, 0x21,
+ 0x22, 0x22, 0x21, 0x26, 0x1d, 0x27, 0x1d, 0x2b, 0x1a, 0x2b, 0x19, 0x2e,
+ 0x17, 0x30, 0x16, 0x31, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3b, 0x3e, 0x33, 0x3f,
+ 0x2d, 0x40, 0x28, 0x42, 0x24, 0x44, 0x20, 0x45, 0x1d, 0x46, 0x1a, 0x48,
+ 0x18, 0x49, 0x16, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x10, 0x50,
+ 0x0f, 0x51, 0x0f, 0x53, 0x0d, 0x53, 0x0d, 0x55, 0x0b, 0x55, 0x0b, 0x56,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3e, 0x34, 0x3f, 0x2e, 0x40, 0x29, 0x41,
+ 0x25, 0x43, 0x21, 0x44, 0x1e, 0x45, 0x1c, 0x47, 0x19, 0x48, 0x18, 0x4a,
+ 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50,
+ 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x77, 0x01, 0x68, 0x02,
+ 0x5d, 0x05, 0x52, 0x07, 0x4a, 0x0a, 0x43, 0x0d, 0x3d, 0x10, 0x38, 0x12,
+ 0x33, 0x16, 0x2f, 0x19, 0x2b, 0x1b, 0x28, 0x1d, 0x26, 0x21, 0x22, 0x22,
+ 0x21, 0x26, 0x1e, 0x26, 0x1d, 0x2a, 0x1a, 0x2b, 0x19, 0x2d, 0x18, 0x30,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x3b, 0x3e, 0x34, 0x3f, 0x2e, 0x40, 0x29, 0x41,
+ 0x25, 0x43, 0x21, 0x44, 0x1e, 0x45, 0x1c, 0x47, 0x19, 0x48, 0x18, 0x4a,
+ 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50,
+ 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x3e, 0x35, 0x3f, 0x2f, 0x40, 0x2a, 0x41, 0x26, 0x42, 0x22, 0x44,
+ 0x20, 0x45, 0x1d, 0x46, 0x1b, 0x48, 0x18, 0x48, 0x17, 0x4a, 0x15, 0x4b,
+ 0x13, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x52,
+ 0x0d, 0x53, 0x0d, 0x53, 0x77, 0x00, 0x6a, 0x02, 0x5e, 0x04, 0x55, 0x07,
+ 0x4c, 0x0a, 0x45, 0x0c, 0x40, 0x0f, 0x3a, 0x12, 0x35, 0x14, 0x31, 0x16,
+ 0x2e, 0x19, 0x2b, 0x1c, 0x27, 0x1d, 0x26, 0x22, 0x21, 0x22, 0x21, 0x25,
+ 0x1e, 0x26, 0x1d, 0x29, 0x1b, 0x2b, 0x19, 0x2b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x3c, 0x3e, 0x35, 0x3f, 0x2f, 0x40, 0x2a, 0x41, 0x26, 0x42, 0x22, 0x44,
+ 0x20, 0x45, 0x1d, 0x46, 0x1b, 0x48, 0x18, 0x48, 0x17, 0x4a, 0x15, 0x4b,
+ 0x13, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x52,
+ 0x0d, 0x53, 0x0d, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x35, 0x3f,
+ 0x30, 0x3f, 0x2b, 0x40, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44, 0x1e, 0x45,
+ 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a, 0x15, 0x4c, 0x13, 0x4c,
+ 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x0e, 0x53,
+ 0x78, 0x00, 0x6b, 0x02, 0x60, 0x04, 0x57, 0x06, 0x4f, 0x09, 0x48, 0x0c,
+ 0x42, 0x0e, 0x3c, 0x10, 0x38, 0x12, 0x34, 0x16, 0x30, 0x18, 0x2d, 0x19,
+ 0x2b, 0x1d, 0x26, 0x1e, 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1e, 0x26,
+ 0x1d, 0x28, 0x1c, 0x2b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x35, 0x3f,
+ 0x30, 0x3f, 0x2b, 0x40, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44, 0x1e, 0x45,
+ 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a, 0x15, 0x4c, 0x13, 0x4c,
+ 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x0e, 0x53,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x36, 0x3f, 0x30, 0x3f, 0x2c, 0x40,
+ 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47,
+ 0x19, 0x48, 0x18, 0x4a, 0x15, 0x4a, 0x15, 0x4c, 0x13, 0x4c, 0x13, 0x4e,
+ 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x78, 0x00, 0x6d, 0x02,
+ 0x61, 0x04, 0x58, 0x05, 0x51, 0x07, 0x4a, 0x0a, 0x44, 0x0c, 0x3f, 0x0f,
+ 0x3a, 0x12, 0x35, 0x14, 0x32, 0x16, 0x30, 0x19, 0x2b, 0x19, 0x2a, 0x1d,
+ 0x26, 0x1e, 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1e, 0x26, 0x1d, 0x27,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x36, 0x3f, 0x30, 0x3f, 0x2c, 0x40,
+ 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47,
+ 0x19, 0x48, 0x18, 0x4a, 0x15, 0x4a, 0x15, 0x4c, 0x13, 0x4c, 0x13, 0x4e,
+ 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x3e, 0x37, 0x3e, 0x31, 0x3f, 0x2d, 0x40, 0x29, 0x41, 0x26, 0x42,
+ 0x23, 0x44, 0x20, 0x45, 0x1e, 0x45, 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x48,
+ 0x17, 0x4a, 0x15, 0x4a, 0x14, 0x4c, 0x13, 0x4c, 0x12, 0x4e, 0x11, 0x4e,
+ 0x11, 0x50, 0x0f, 0x50, 0x78, 0x00, 0x6d, 0x02, 0x63, 0x04, 0x5a, 0x05,
+ 0x53, 0x07, 0x4c, 0x0a, 0x46, 0x0c, 0x41, 0x0f, 0x3c, 0x0f, 0x38, 0x12,
+ 0x35, 0x16, 0x30, 0x16, 0x2e, 0x19, 0x2b, 0x1a, 0x29, 0x1d, 0x26, 0x1e,
+ 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1f, 0x26, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x3c, 0x3e, 0x37, 0x3e, 0x31, 0x3f, 0x2d, 0x40, 0x29, 0x41, 0x26, 0x42,
+ 0x23, 0x44, 0x20, 0x45, 0x1e, 0x45, 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x48,
+ 0x17, 0x4a, 0x15, 0x4a, 0x14, 0x4c, 0x13, 0x4c, 0x12, 0x4e, 0x11, 0x4e,
+ 0x11, 0x50, 0x0f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3e,
+ 0x32, 0x3f, 0x2e, 0x40, 0x2a, 0x41, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44,
+ 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a,
+ 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x11, 0x50,
+ 0x78, 0x00, 0x6e, 0x01, 0x65, 0x03, 0x5c, 0x05, 0x54, 0x07, 0x4e, 0x09,
+ 0x48, 0x0b, 0x43, 0x0c, 0x3e, 0x0f, 0x3b, 0x12, 0x36, 0x12, 0x33, 0x16,
+ 0x30, 0x17, 0x2d, 0x19, 0x2b, 0x1b, 0x28, 0x1d, 0x26, 0x1e, 0x25, 0x22,
+ 0x21, 0x22, 0x21, 0x24, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x37, 0x3e,
+ 0x32, 0x3f, 0x2e, 0x40, 0x2a, 0x41, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44,
+ 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a,
+ 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x11, 0x50,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3e, 0x33, 0x3f, 0x2e, 0x3f,
+ 0x2b, 0x40, 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x20, 0x45, 0x1e, 0x45,
+ 0x1c, 0x46, 0x1b, 0x48, 0x19, 0x48, 0x18, 0x4a, 0x16, 0x4a, 0x15, 0x4b,
+ 0x13, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x79, 0x00, 0x6f, 0x01,
+ 0x66, 0x02, 0x5d, 0x04, 0x56, 0x06, 0x4f, 0x07, 0x4a, 0x0a, 0x45, 0x0c,
+ 0x41, 0x0f, 0x3b, 0x0f, 0x38, 0x12, 0x35, 0x14, 0x31, 0x16, 0x30, 0x18,
+ 0x2b, 0x19, 0x2b, 0x1c, 0x27, 0x1d, 0x26, 0x1f, 0x24, 0x22, 0x21, 0x22,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x37, 0x3e, 0x33, 0x3f, 0x2e, 0x3f,
+ 0x2b, 0x40, 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x20, 0x45, 0x1e, 0x45,
+ 0x1c, 0x46, 0x1b, 0x48, 0x19, 0x48, 0x18, 0x4a, 0x16, 0x4a, 0x15, 0x4b,
+ 0x13, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x62, 0x00, 0x6c, 0x00, 0x72, 0x00, 0x74, 0x00, 0x77, 0x00, 0x79, 0x00,
+ 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00,
+ 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x08, 0x00, 0x44, 0x00,
+ 0x56, 0x00, 0x61, 0x00, 0x67, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x70, 0x00,
+ 0x71, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, 0x76, 0x00,
+ 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00,
+ 0x44, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x71, 0x00, 0x75, 0x00, 0x77, 0x00,
+ 0x79, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00,
+ 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x0b, 0x57, 0x06,
+ 0x5f, 0x03, 0x63, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6d, 0x01, 0x6e, 0x01,
+ 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00,
+ 0x76, 0x00, 0x76, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79, 0x00,
+ 0x82, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x40, 0x17, 0x17, 0x2c, 0x0c, 0x3b, 0x07,
+ 0x45, 0x05, 0x4d, 0x04, 0x53, 0x03, 0x57, 0x02, 0x5c, 0x02, 0x5e, 0x01,
+ 0x61, 0x01, 0x63, 0x01, 0x66, 0x01, 0x67, 0x01, 0x68, 0x00, 0x69, 0x00,
+ 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x41, 0x20, 0x4d, 0x0b,
+ 0x58, 0x06, 0x5e, 0x03, 0x64, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6c, 0x01,
+ 0x6f, 0x01, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00,
+ 0x76, 0x00, 0x75, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x47, 0x15, 0x4f, 0x0d, 0x56, 0x09, 0x59, 0x06,
+ 0x5f, 0x05, 0x62, 0x04, 0x65, 0x03, 0x67, 0x02, 0x69, 0x02, 0x6b, 0x02,
+ 0x6c, 0x02, 0x6e, 0x01, 0x6f, 0x01, 0x70, 0x01, 0x71, 0x01, 0x70, 0x01,
+ 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x74, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x55, 0x0c, 0x2c, 0x1b, 0x1b, 0x27, 0x12, 0x32, 0x0d, 0x3a, 0x0b,
+ 0x41, 0x08, 0x47, 0x07, 0x4c, 0x05, 0x4f, 0x05, 0x53, 0x04, 0x56, 0x04,
+ 0x58, 0x03, 0x5a, 0x02, 0x5d, 0x02, 0x5e, 0x02, 0x60, 0x02, 0x61, 0x01,
+ 0x63, 0x01, 0x64, 0x01, 0x41, 0x2a, 0x47, 0x16, 0x4f, 0x0d, 0x54, 0x09,
+ 0x5b, 0x06, 0x5f, 0x05, 0x62, 0x04, 0x64, 0x03, 0x67, 0x02, 0x69, 0x02,
+ 0x6b, 0x02, 0x6c, 0x02, 0x6e, 0x01, 0x6f, 0x01, 0x70, 0x01, 0x70, 0x01,
+ 0x71, 0x01, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x1d, 0x4a, 0x14, 0x50, 0x0e, 0x54, 0x0b, 0x59, 0x08, 0x5c, 0x07,
+ 0x5f, 0x06, 0x60, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03, 0x68, 0x02,
+ 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02, 0x6c, 0x02, 0x6e, 0x02, 0x6f, 0x01,
+ 0x70, 0x01, 0x70, 0x01, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x60, 0x08, 0x3b,
+ 0x12, 0x28, 0x1d, 0x1d, 0x26, 0x16, 0x2e, 0x11, 0x34, 0x0e, 0x3a, 0x0c,
+ 0x3f, 0x0a, 0x44, 0x08, 0x47, 0x07, 0x4b, 0x06, 0x4d, 0x05, 0x51, 0x05,
+ 0x52, 0x04, 0x55, 0x04, 0x57, 0x04, 0x58, 0x04, 0x5a, 0x03, 0x5c, 0x02,
+ 0x42, 0x30, 0x45, 0x1d, 0x4b, 0x14, 0x4f, 0x0e, 0x55, 0x0b, 0x59, 0x08,
+ 0x5c, 0x07, 0x5e, 0x06, 0x61, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03,
+ 0x68, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6b, 0x02, 0x6d, 0x02, 0x6e, 0x02,
+ 0x6f, 0x01, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x22, 0x48, 0x19,
+ 0x4d, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5c, 0x07,
+ 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03,
+ 0x68, 0x03, 0x68, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02, 0x6d, 0x02,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x66, 0x05, 0x45, 0x0d, 0x32, 0x16, 0x26,
+ 0x1e, 0x1e, 0x25, 0x18, 0x2b, 0x14, 0x31, 0x11, 0x36, 0x0f, 0x3a, 0x0c,
+ 0x3e, 0x0b, 0x42, 0x0a, 0x45, 0x09, 0x47, 0x07, 0x4a, 0x07, 0x4c, 0x06,
+ 0x4f, 0x05, 0x51, 0x05, 0x52, 0x05, 0x54, 0x04, 0x41, 0x33, 0x44, 0x22,
+ 0x48, 0x19, 0x4c, 0x13, 0x51, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x08,
+ 0x5d, 0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03,
+ 0x67, 0x03, 0x67, 0x03, 0x69, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x43, 0x26, 0x47, 0x1d, 0x4a, 0x17, 0x4d, 0x12,
+ 0x51, 0x0f, 0x54, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5b, 0x08, 0x5d, 0x07,
+ 0x5f, 0x06, 0x60, 0x06, 0x62, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03,
+ 0x67, 0x03, 0x67, 0x03, 0x68, 0x03, 0x69, 0x02, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x6a, 0x04, 0x4d, 0x0b, 0x3a, 0x11, 0x2e, 0x18, 0x25, 0x1f, 0x1f,
+ 0x24, 0x1a, 0x29, 0x16, 0x2e, 0x13, 0x33, 0x11, 0x37, 0x0f, 0x3a, 0x0d,
+ 0x3d, 0x0c, 0x40, 0x0a, 0x43, 0x0a, 0x45, 0x09, 0x48, 0x07, 0x4a, 0x07,
+ 0x4c, 0x07, 0x4e, 0x06, 0x41, 0x35, 0x43, 0x26, 0x47, 0x1d, 0x49, 0x17,
+ 0x4e, 0x12, 0x51, 0x0f, 0x54, 0x0d, 0x55, 0x0b, 0x59, 0x09, 0x5b, 0x08,
+ 0x5d, 0x07, 0x5f, 0x06, 0x60, 0x06, 0x62, 0x05, 0x63, 0x05, 0x63, 0x04,
+ 0x65, 0x03, 0x67, 0x03, 0x67, 0x03, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x43, 0x29, 0x45, 0x20, 0x49, 0x1a, 0x4b, 0x15, 0x4f, 0x12, 0x51, 0x0f,
+ 0x54, 0x0d, 0x55, 0x0b, 0x58, 0x0a, 0x5a, 0x09, 0x5b, 0x08, 0x5d, 0x07,
+ 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x64, 0x05, 0x65, 0x04,
+ 0x65, 0x03, 0x66, 0x03, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x6d, 0x03, 0x52,
+ 0x08, 0x41, 0x0e, 0x34, 0x14, 0x2b, 0x1a, 0x24, 0x1f, 0x1f, 0x24, 0x1b,
+ 0x28, 0x17, 0x2d, 0x15, 0x31, 0x12, 0x34, 0x10, 0x37, 0x0f, 0x3a, 0x0d,
+ 0x3d, 0x0c, 0x40, 0x0b, 0x42, 0x0a, 0x44, 0x0a, 0x46, 0x09, 0x47, 0x07,
+ 0x41, 0x36, 0x43, 0x29, 0x46, 0x20, 0x48, 0x1a, 0x4c, 0x15, 0x4f, 0x12,
+ 0x51, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x0a, 0x5a, 0x09, 0x5b, 0x08,
+ 0x5d, 0x07, 0x5f, 0x06, 0x60, 0x06, 0x60, 0x05, 0x62, 0x05, 0x64, 0x05,
+ 0x65, 0x04, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x2b, 0x45, 0x23,
+ 0x48, 0x1d, 0x49, 0x18, 0x4d, 0x14, 0x4f, 0x12, 0x51, 0x10, 0x53, 0x0e,
+ 0x55, 0x0c, 0x57, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5c, 0x08, 0x5d, 0x07,
+ 0x5f, 0x07, 0x5f, 0x06, 0x61, 0x06, 0x62, 0x05, 0x63, 0x05, 0x64, 0x05,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x6f, 0x02, 0x57, 0x07, 0x47, 0x0c, 0x3a,
+ 0x11, 0x31, 0x16, 0x29, 0x1b, 0x24, 0x20, 0x20, 0x23, 0x1c, 0x28, 0x19,
+ 0x2b, 0x16, 0x2f, 0x14, 0x32, 0x12, 0x35, 0x10, 0x38, 0x0f, 0x3a, 0x0e,
+ 0x3c, 0x0c, 0x3f, 0x0c, 0x41, 0x0b, 0x42, 0x0a, 0x41, 0x37, 0x43, 0x2b,
+ 0x45, 0x23, 0x47, 0x1d, 0x4a, 0x18, 0x4d, 0x14, 0x4f, 0x12, 0x51, 0x10,
+ 0x53, 0x0e, 0x55, 0x0c, 0x57, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5c, 0x08,
+ 0x5d, 0x07, 0x5e, 0x07, 0x60, 0x06, 0x61, 0x06, 0x62, 0x05, 0x63, 0x05,
+ 0x1f, 0x00, 0x3f, 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00,
+ 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x1f, 0x1f, 0x3f, 0x00,
+ 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00,
+ 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0x00, 0x58, 0x00, 0x70, 0x00, 0x77, 0x00, 0x79, 0x00, 0x7b, 0x00,
+ 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x1f, 0x1f, 0x3f, 0x00,
+ 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00,
+ 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x43, 0x2d, 0x44, 0x25, 0x46, 0x1f, 0x48, 0x1b,
+ 0x4b, 0x17, 0x4d, 0x14, 0x50, 0x12, 0x51, 0x10, 0x53, 0x0e, 0x55, 0x0c,
+ 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x08, 0x5c, 0x07,
+ 0x5f, 0x07, 0x60, 0x06, 0x61, 0x06, 0x62, 0x06, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x71, 0x02, 0x5b, 0x05, 0x4b, 0x0a, 0x3f, 0x0f, 0x36, 0x13, 0x2e,
+ 0x18, 0x29, 0x1c, 0x23, 0x20, 0x20, 0x23, 0x1d, 0x27, 0x19, 0x2a, 0x17,
+ 0x2d, 0x16, 0x30, 0x12, 0x33, 0x12, 0x35, 0x10, 0x38, 0x0f, 0x3b, 0x0e,
+ 0x3c, 0x0c, 0x3e, 0x0c, 0x41, 0x38, 0x43, 0x2d, 0x44, 0x25, 0x45, 0x1f,
+ 0x49, 0x1b, 0x4b, 0x17, 0x4d, 0x14, 0x4f, 0x11, 0x51, 0x10, 0x53, 0x0e,
+ 0x55, 0x0c, 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5b, 0x08,
+ 0x5e, 0x07, 0x5f, 0x07, 0x60, 0x06, 0x61, 0x06, 0x00, 0x00, 0x0a, 0x00,
+ 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00,
+ 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00,
+ 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00,
+ 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
+ 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x44, 0x00,
+ 0x55, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x75, 0x00, 0x78, 0x00,
+ 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00,
+ 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00,
+ 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
+ 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00,
+ 0x42, 0x2f, 0x44, 0x27, 0x46, 0x22, 0x47, 0x1d, 0x4a, 0x19, 0x4c, 0x16,
+ 0x4e, 0x13, 0x4f, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c,
+ 0x58, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x07, 0x5e, 0x07,
+ 0x5f, 0x07, 0x5f, 0x06, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x73, 0x01, 0x5e,
+ 0x05, 0x4f, 0x08, 0x44, 0x0c, 0x3a, 0x10, 0x33, 0x15, 0x2d, 0x19, 0x28,
+ 0x1d, 0x23, 0x20, 0x20, 0x23, 0x1d, 0x26, 0x1a, 0x2a, 0x18, 0x2c, 0x16,
+ 0x2f, 0x14, 0x31, 0x12, 0x34, 0x12, 0x35, 0x0f, 0x38, 0x0f, 0x3b, 0x0f,
+ 0x41, 0x39, 0x42, 0x2f, 0x44, 0x27, 0x45, 0x22, 0x48, 0x1d, 0x4a, 0x19,
+ 0x4c, 0x16, 0x4d, 0x14, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d,
+ 0x56, 0x0c, 0x58, 0x0b, 0x59, 0x0a, 0x59, 0x09, 0x5c, 0x09, 0x5c, 0x07,
+ 0x5e, 0x07, 0x5f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2d, 0x00,
+ 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00,
+ 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
+ 0x00, 0x66, 0x00, 0x3f, 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00,
+ 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00,
+ 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x55, 0x00, 0x20, 0x00, 0x3e, 0x00,
+ 0x50, 0x00, 0x5a, 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00,
+ 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
+ 0x00, 0x66, 0x00, 0x3f, 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00,
+ 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00,
+ 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x42, 0x30, 0x44, 0x29,
+ 0x45, 0x23, 0x46, 0x1f, 0x49, 0x1b, 0x4b, 0x18, 0x4c, 0x15, 0x4d, 0x13,
+ 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0b,
+ 0x59, 0x0b, 0x59, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x5c, 0x07, 0x5e, 0x07,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x73, 0x01, 0x61, 0x04, 0x52, 0x07, 0x47,
+ 0x0b, 0x3e, 0x0f, 0x37, 0x12, 0x31, 0x16, 0x2b, 0x19, 0x27, 0x1d, 0x23,
+ 0x20, 0x20, 0x23, 0x1d, 0x26, 0x1b, 0x29, 0x19, 0x2b, 0x16, 0x2e, 0x16,
+ 0x30, 0x13, 0x32, 0x12, 0x35, 0x12, 0x36, 0x0f, 0x41, 0x39, 0x42, 0x30,
+ 0x44, 0x29, 0x44, 0x23, 0x47, 0x1f, 0x49, 0x1b, 0x4b, 0x18, 0x4c, 0x15,
+ 0x4e, 0x13, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c,
+ 0x57, 0x0b, 0x57, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x5c, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00,
+ 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00,
+ 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x72, 0x00, 0x5c,
+ 0x00, 0x2d, 0x01, 0x01, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00,
+ 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00,
+ 0x73, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x67, 0x00, 0x3e, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x3a, 0x00,
+ 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00,
+ 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x72, 0x00, 0x5c,
+ 0x00, 0x2d, 0x01, 0x01, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00,
+ 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00,
+ 0x73, 0x00, 0x75, 0x00, 0x42, 0x32, 0x44, 0x2a, 0x45, 0x25, 0x46, 0x21,
+ 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x17, 0x4c, 0x15, 0x4e, 0x13, 0x50, 0x11,
+ 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x55, 0x0c, 0x57, 0x0c, 0x57, 0x0b,
+ 0x5a, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x74, 0x01, 0x64, 0x04, 0x55, 0x06, 0x4a, 0x0a, 0x42, 0x0d, 0x3a,
+ 0x10, 0x34, 0x14, 0x2f, 0x17, 0x2a, 0x1a, 0x26, 0x1d, 0x23, 0x21, 0x21,
+ 0x22, 0x1d, 0x26, 0x1b, 0x28, 0x19, 0x2b, 0x18, 0x2c, 0x16, 0x30, 0x15,
+ 0x30, 0x12, 0x33, 0x12, 0x41, 0x3a, 0x42, 0x32, 0x44, 0x2a, 0x44, 0x25,
+ 0x46, 0x21, 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x17, 0x4d, 0x15, 0x4e, 0x13,
+ 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x55, 0x0c, 0x56, 0x0c,
+ 0x58, 0x0b, 0x5a, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00,
+ 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00,
+ 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22,
+ 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00,
+ 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x6e, 0x00,
+ 0x50, 0x00, 0x28, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00,
+ 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00,
+ 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22,
+ 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00,
+ 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00,
+ 0x42, 0x32, 0x43, 0x2c, 0x44, 0x26, 0x45, 0x22, 0x48, 0x1f, 0x49, 0x1b,
+ 0x4b, 0x19, 0x4c, 0x16, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10,
+ 0x53, 0x0e, 0x55, 0x0e, 0x55, 0x0c, 0x56, 0x0c, 0x57, 0x0b, 0x59, 0x0b,
+ 0x5a, 0x0a, 0x5a, 0x09, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x75, 0x01, 0x65,
+ 0x03, 0x58, 0x05, 0x4d, 0x09, 0x45, 0x0c, 0x3e, 0x0f, 0x37, 0x12, 0x32,
+ 0x16, 0x2d, 0x18, 0x2a, 0x1b, 0x26, 0x1d, 0x22, 0x21, 0x21, 0x22, 0x1d,
+ 0x26, 0x1c, 0x27, 0x19, 0x2b, 0x19, 0x2b, 0x16, 0x2e, 0x16, 0x30, 0x14,
+ 0x41, 0x3a, 0x42, 0x32, 0x43, 0x2c, 0x44, 0x26, 0x46, 0x22, 0x48, 0x1f,
+ 0x49, 0x1b, 0x4a, 0x19, 0x4c, 0x16, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x11,
+ 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0e, 0x54, 0x0c, 0x57, 0x0c, 0x57, 0x0b,
+ 0x59, 0x0b, 0x5a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00,
+ 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00,
+ 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00,
+ 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00,
+ 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x3a, 0x00,
+ 0x1b, 0x00, 0x01, 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00,
+ 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00,
+ 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00,
+ 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00,
+ 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x42, 0x33, 0x43, 0x2d,
+ 0x44, 0x28, 0x45, 0x23, 0x47, 0x20, 0x48, 0x1d, 0x4a, 0x1a, 0x4a, 0x18,
+ 0x4c, 0x16, 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e,
+ 0x55, 0x0e, 0x54, 0x0d, 0x57, 0x0c, 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x0b,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x76, 0x01, 0x67, 0x02, 0x5a, 0x05, 0x50,
+ 0x07, 0x47, 0x0a, 0x40, 0x0d, 0x3a, 0x10, 0x35, 0x12, 0x30, 0x16, 0x2c,
+ 0x19, 0x29, 0x1b, 0x26, 0x1d, 0x22, 0x21, 0x21, 0x22, 0x1d, 0x26, 0x1d,
+ 0x26, 0x1a, 0x2a, 0x19, 0x2b, 0x17, 0x2d, 0x16, 0x41, 0x3b, 0x42, 0x33,
+ 0x43, 0x2d, 0x44, 0x28, 0x45, 0x23, 0x47, 0x20, 0x48, 0x1d, 0x49, 0x1a,
+ 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10,
+ 0x53, 0x0e, 0x54, 0x0e, 0x55, 0x0d, 0x57, 0x0c, 0x57, 0x0b, 0x58, 0x0b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00,
+ 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x7c, 0x00, 0x75,
+ 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00,
+ 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00,
+ 0x57, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00,
+ 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00,
+ 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x7c, 0x00, 0x75,
+ 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00,
+ 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00,
+ 0x57, 0x00, 0x5b, 0x00, 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29, 0x45, 0x25,
+ 0x46, 0x21, 0x48, 0x1e, 0x49, 0x1b, 0x4a, 0x19, 0x4c, 0x17, 0x4d, 0x15,
+ 0x4e, 0x14, 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x53, 0x0e,
+ 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0c, 0x57, 0x0b, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x77, 0x00, 0x68, 0x02, 0x5c, 0x05, 0x52, 0x07, 0x4a, 0x0a, 0x43,
+ 0x0c, 0x3d, 0x0f, 0x37, 0x12, 0x33, 0x14, 0x2f, 0x16, 0x2b, 0x19, 0x28,
+ 0x1c, 0x26, 0x1d, 0x22, 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1a,
+ 0x29, 0x19, 0x2b, 0x18, 0x41, 0x3b, 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29,
+ 0x45, 0x25, 0x46, 0x21, 0x48, 0x1e, 0x48, 0x1b, 0x4b, 0x19, 0x4c, 0x17,
+ 0x4d, 0x15, 0x4e, 0x14, 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x51, 0x0f,
+ 0x54, 0x0e, 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00,
+ 0x4c, 0x00, 0x51, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56,
+ 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00,
+ 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00,
+ 0x4c, 0x00, 0x51, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56,
+ 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00,
+ 0x42, 0x34, 0x43, 0x2f, 0x44, 0x2a, 0x44, 0x26, 0x46, 0x22, 0x47, 0x1f,
+ 0x48, 0x1d, 0x49, 0x1a, 0x4b, 0x18, 0x4c, 0x17, 0x4e, 0x15, 0x4e, 0x13,
+ 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x51, 0x0f, 0x54, 0x0e, 0x55, 0x0d,
+ 0x56, 0x0c, 0x57, 0x0c, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x77, 0x00, 0x69,
+ 0x02, 0x5e, 0x04, 0x55, 0x06, 0x4c, 0x09, 0x45, 0x0c, 0x3f, 0x0e, 0x3a,
+ 0x10, 0x35, 0x12, 0x31, 0x16, 0x2e, 0x18, 0x2b, 0x19, 0x27, 0x1d, 0x26,
+ 0x1e, 0x22, 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1b, 0x28, 0x19,
+ 0x41, 0x3b, 0x42, 0x34, 0x43, 0x2f, 0x43, 0x2a, 0x45, 0x26, 0x46, 0x22,
+ 0x47, 0x1f, 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x18, 0x4c, 0x17, 0x4e, 0x15,
+ 0x4e, 0x13, 0x50, 0x13, 0x50, 0x11, 0x51, 0x11, 0x52, 0x0f, 0x54, 0x0e,
+ 0x55, 0x0d, 0x56, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
+ 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00,
+ 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37,
+ 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00,
+ 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00,
+ 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00,
+ 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00,
+ 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37,
+ 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00,
+ 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x42, 0x35, 0x43, 0x30,
+ 0x44, 0x2b, 0x44, 0x27, 0x45, 0x24, 0x46, 0x21, 0x48, 0x1e, 0x48, 0x1c,
+ 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x15, 0x4e, 0x13, 0x50, 0x12,
+ 0x50, 0x11, 0x51, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e, 0x55, 0x0c,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x77, 0x00, 0x6b, 0x02, 0x60, 0x04, 0x57,
+ 0x05, 0x4f, 0x07, 0x48, 0x0a, 0x42, 0x0c, 0x3c, 0x0f, 0x38, 0x12, 0x34,
+ 0x14, 0x30, 0x16, 0x2c, 0x19, 0x2b, 0x19, 0x26, 0x1d, 0x25, 0x1e, 0x22,
+ 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1c, 0x41, 0x3b, 0x42, 0x35,
+ 0x43, 0x30, 0x43, 0x2b, 0x44, 0x27, 0x45, 0x24, 0x46, 0x21, 0x47, 0x1e,
+ 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x15, 0x4e, 0x13,
+ 0x50, 0x12, 0x50, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00,
+ 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x7d, 0x00, 0x7a,
+ 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0e, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00,
+ 0x34, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00,
+ 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00,
+ 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x7d, 0x00, 0x7a,
+ 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0e, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00,
+ 0x34, 0x00, 0x3b, 0x00, 0x42, 0x36, 0x43, 0x30, 0x44, 0x2c, 0x44, 0x28,
+ 0x45, 0x25, 0x46, 0x22, 0x48, 0x1f, 0x48, 0x1d, 0x49, 0x1a, 0x4b, 0x19,
+ 0x4c, 0x18, 0x4d, 0x15, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x12, 0x50, 0x11,
+ 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x77, 0x00, 0x6c, 0x02, 0x61, 0x04, 0x58, 0x05, 0x51, 0x07, 0x4a,
+ 0x0a, 0x44, 0x0c, 0x3f, 0x0f, 0x3a, 0x10, 0x35, 0x12, 0x32, 0x16, 0x30,
+ 0x16, 0x2b, 0x19, 0x2a, 0x1a, 0x26, 0x1d, 0x25, 0x1e, 0x22, 0x21, 0x22,
+ 0x21, 0x1e, 0x25, 0x1d, 0x41, 0x3b, 0x42, 0x36, 0x43, 0x30, 0x43, 0x2c,
+ 0x44, 0x28, 0x45, 0x25, 0x46, 0x22, 0x47, 0x1f, 0x49, 0x1d, 0x49, 0x1a,
+ 0x4b, 0x19, 0x4c, 0x18, 0x4d, 0x15, 0x4e, 0x15, 0x4f, 0x13, 0x4f, 0x12,
+ 0x51, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00,
+ 0x29, 0x00, 0x30, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69,
+ 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d,
+ 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00,
+ 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00,
+ 0x29, 0x00, 0x30, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69,
+ 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d,
+ 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00,
+ 0x42, 0x36, 0x42, 0x31, 0x43, 0x2d, 0x44, 0x29, 0x45, 0x26, 0x46, 0x23,
+ 0x47, 0x20, 0x47, 0x1e, 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x17,
+ 0x4d, 0x15, 0x4e, 0x14, 0x4f, 0x13, 0x4f, 0x12, 0x51, 0x11, 0x52, 0x11,
+ 0x52, 0x0f, 0x54, 0x0e, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x78, 0x00, 0x6d,
+ 0x01, 0x62, 0x03, 0x5a, 0x05, 0x52, 0x07, 0x4c, 0x09, 0x46, 0x0b, 0x41,
+ 0x0c, 0x3c, 0x0f, 0x38, 0x12, 0x35, 0x12, 0x30, 0x16, 0x2e, 0x17, 0x2b,
+ 0x19, 0x29, 0x1b, 0x26, 0x1d, 0x25, 0x1e, 0x22, 0x21, 0x22, 0x21, 0x1f,
+ 0x41, 0x3c, 0x42, 0x36, 0x42, 0x31, 0x43, 0x2d, 0x44, 0x29, 0x45, 0x26,
+ 0x46, 0x23, 0x46, 0x20, 0x48, 0x1e, 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18,
+ 0x4c, 0x17, 0x4d, 0x15, 0x4e, 0x14, 0x4e, 0x13, 0x50, 0x12, 0x51, 0x11,
+ 0x52, 0x11, 0x52, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00,
+ 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53,
+ 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00,
+ 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00,
+ 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53,
+ 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00,
+ 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x42, 0x37, 0x42, 0x32,
+ 0x43, 0x2d, 0x44, 0x2a, 0x45, 0x27, 0x45, 0x23, 0x46, 0x21, 0x47, 0x1f,
+ 0x49, 0x1d, 0x49, 0x1a, 0x4b, 0x19, 0x4c, 0x18, 0x4c, 0x16, 0x4e, 0x15,
+ 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x12, 0x51, 0x11, 0x52, 0x11, 0x52, 0x0f,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x78, 0x00, 0x6e, 0x01, 0x64, 0x02, 0x5b,
+ 0x04, 0x54, 0x06, 0x4e, 0x07, 0x47, 0x0a, 0x42, 0x0c, 0x3e, 0x0f, 0x3b,
+ 0x0f, 0x35, 0x12, 0x33, 0x14, 0x30, 0x16, 0x2d, 0x19, 0x2b, 0x19, 0x28,
+ 0x1c, 0x26, 0x1d, 0x25, 0x1f, 0x22, 0x21, 0x22, 0x41, 0x3c, 0x42, 0x37,
+ 0x42, 0x32, 0x43, 0x2d, 0x44, 0x2a, 0x45, 0x27, 0x45, 0x23, 0x46, 0x21,
+ 0x48, 0x1f, 0x49, 0x1d, 0x49, 0x1a, 0x4b, 0x19, 0x4c, 0x18, 0x4c, 0x16,
+ 0x4e, 0x15, 0x4d, 0x14, 0x50, 0x13, 0x50, 0x12, 0x51, 0x11, 0x52, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x7e, 0x00, 0x7c,
+ 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e,
+ 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00,
+ 0x13, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00,
+ 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x7e, 0x00, 0x7c,
+ 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e,
+ 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00,
+ 0x13, 0x00, 0x1b, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x61, 0x20, 0x4d, 0x2a,
+ 0x48, 0x30, 0x44, 0x33, 0x44, 0x35, 0x44, 0x36, 0x43, 0x37, 0x42, 0x38,
+ 0x43, 0x39, 0x42, 0x39, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3b,
+ 0x42, 0x3b, 0x41, 0x3b, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c,
+ 0x04, 0x3d, 0x22, 0x3d, 0x2b, 0x3d, 0x30, 0x3d, 0x33, 0x3d, 0x35, 0x3d,
+ 0x37, 0x3d, 0x38, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
+ 0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d,
+ 0x3c, 0x3d, 0x3c, 0x3d, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x12, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71,
+ 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c,
+ 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
+ 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00,
+ 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x12, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71,
+ 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c,
+ 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x6c, 0x0b, 0x57, 0x16, 0x4f, 0x1d, 0x4a, 0x22,
+ 0x48, 0x26, 0x47, 0x29, 0x46, 0x2b, 0x44, 0x2d, 0x44, 0x2f, 0x44, 0x30,
+ 0x44, 0x31, 0x44, 0x32, 0x43, 0x33, 0x43, 0x34, 0x43, 0x34, 0x42, 0x35,
+ 0x43, 0x36, 0x42, 0x36, 0x42, 0x37, 0x42, 0x37, 0x00, 0x5d, 0x0c, 0x49,
+ 0x16, 0x43, 0x1d, 0x41, 0x22, 0x40, 0x26, 0x3f, 0x29, 0x3f, 0x2c, 0x3f,
+ 0x2e, 0x3e, 0x2f, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e, 0x33, 0x3e,
+ 0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x37, 0x3e, 0x37, 0x3e,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62,
+ 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e,
+ 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00,
+ 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00,
+ 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62,
+ 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e,
+ 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x08, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x72, 0x06, 0x5f, 0x0d, 0x56, 0x14, 0x4f, 0x19, 0x4d, 0x1d, 0x4a, 0x20,
+ 0x49, 0x23, 0x47, 0x25, 0x46, 0x27, 0x46, 0x29, 0x45, 0x2a, 0x45, 0x2c,
+ 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2f, 0x43, 0x30, 0x44, 0x30, 0x44, 0x31,
+ 0x43, 0x32, 0x43, 0x33, 0x00, 0x68, 0x06, 0x54, 0x0d, 0x4b, 0x14, 0x47,
+ 0x19, 0x44, 0x1d, 0x43, 0x20, 0x41, 0x23, 0x41, 0x26, 0x40, 0x27, 0x40,
+ 0x29, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f, 0x2d, 0x3f, 0x2e, 0x3f, 0x2f, 0x3f,
+ 0x30, 0x3f, 0x30, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
+ 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51,
+ 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00,
+ 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00,
+ 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
+ 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51,
+ 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12,
+ 0x00, 0x08, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x75, 0x03, 0x64, 0x09,
+ 0x5a, 0x0e, 0x54, 0x13, 0x51, 0x17, 0x4e, 0x1a, 0x4c, 0x1d, 0x49, 0x1f,
+ 0x49, 0x22, 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x46, 0x28, 0x45, 0x29,
+ 0x45, 0x2a, 0x44, 0x2b, 0x44, 0x2c, 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2e,
+ 0x00, 0x6d, 0x04, 0x5b, 0x09, 0x51, 0x0e, 0x4c, 0x13, 0x48, 0x17, 0x46,
+ 0x1a, 0x44, 0x1d, 0x43, 0x1f, 0x42, 0x22, 0x42, 0x24, 0x41, 0x25, 0x41,
+ 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f,
+ 0x2d, 0x3f, 0x2e, 0x3f, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x3f, 0x00, 0x66, 0x00, 0x72, 0x00,
+ 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x3f,
+ 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c,
+ 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x77, 0x02, 0x68, 0x06, 0x5f, 0x0b, 0x58, 0x0f,
+ 0x54, 0x12, 0x51, 0x15, 0x4f, 0x18, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1f,
+ 0x49, 0x21, 0x48, 0x22, 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x45, 0x27,
+ 0x45, 0x28, 0x45, 0x29, 0x45, 0x2a, 0x44, 0x2b, 0x00, 0x70, 0x02, 0x60,
+ 0x07, 0x56, 0x0b, 0x50, 0x0f, 0x4c, 0x12, 0x49, 0x16, 0x47, 0x18, 0x46,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x43, 0x21, 0x42, 0x22, 0x42, 0x24, 0x41,
+ 0x25, 0x41, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71, 0x00,
+ 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00,
+ 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c,
+ 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a,
+ 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x78, 0x02, 0x6b, 0x05, 0x62, 0x08, 0x5b, 0x0c, 0x57, 0x0f, 0x54, 0x12,
+ 0x51, 0x14, 0x4e, 0x17, 0x4d, 0x19, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e,
+ 0x49, 0x20, 0x48, 0x21, 0x48, 0x22, 0x46, 0x24, 0x46, 0x25, 0x46, 0x26,
+ 0x46, 0x27, 0x45, 0x27, 0x00, 0x72, 0x02, 0x64, 0x05, 0x5b, 0x08, 0x54,
+ 0x0c, 0x50, 0x0f, 0x4d, 0x12, 0x4a, 0x14, 0x48, 0x17, 0x47, 0x19, 0x46,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x44, 0x20, 0x42, 0x21, 0x42, 0x22, 0x42,
+ 0x24, 0x41, 0x25, 0x41, 0x26, 0x41, 0x27, 0x40, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x3f,
+ 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a, 0x00,
+ 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00,
+ 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x3f, 0x00, 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59,
+ 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76,
+ 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x79, 0x01, 0x6d, 0x04,
+ 0x65, 0x07, 0x5e, 0x0a, 0x5a, 0x0d, 0x56, 0x0f, 0x54, 0x12, 0x51, 0x14,
+ 0x4f, 0x16, 0x4e, 0x18, 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e,
+ 0x49, 0x1f, 0x48, 0x21, 0x48, 0x22, 0x48, 0x23, 0x47, 0x23, 0x46, 0x25,
+ 0x00, 0x74, 0x01, 0x66, 0x04, 0x5e, 0x07, 0x57, 0x0a, 0x53, 0x0d, 0x4f,
+ 0x10, 0x4d, 0x12, 0x4b, 0x14, 0x49, 0x16, 0x48, 0x18, 0x46, 0x1a, 0x45,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x20, 0x43, 0x21, 0x42, 0x22, 0x42,
+ 0x23, 0x42, 0x24, 0x41, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x01, 0x01,
+ 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00,
+ 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00,
+ 0x2d, 0x00, 0x01, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56,
+ 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71,
+ 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7a, 0x01, 0x6f, 0x03, 0x67, 0x06, 0x60, 0x08,
+ 0x5d, 0x0b, 0x59, 0x0d, 0x56, 0x10, 0x53, 0x11, 0x51, 0x14, 0x50, 0x15,
+ 0x4e, 0x17, 0x4d, 0x19, 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x48, 0x1e,
+ 0x49, 0x1f, 0x49, 0x20, 0x48, 0x21, 0x48, 0x22, 0x00, 0x75, 0x01, 0x69,
+ 0x03, 0x61, 0x06, 0x5a, 0x08, 0x56, 0x0b, 0x52, 0x0d, 0x4f, 0x10, 0x4d,
+ 0x12, 0x4b, 0x14, 0x4a, 0x16, 0x48, 0x17, 0x47, 0x19, 0x46, 0x1a, 0x45,
+ 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x20, 0x43, 0x21, 0x42,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00, 0x00, 0x1b, 0x00,
+ 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00,
+ 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00,
+ 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54,
+ 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7b, 0x01, 0x71, 0x02, 0x69, 0x05, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0c,
+ 0x58, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4e, 0x16,
+ 0x4e, 0x18, 0x4c, 0x19, 0x4c, 0x1a, 0x4a, 0x1c, 0x4b, 0x1d, 0x49, 0x1e,
+ 0x49, 0x1f, 0x49, 0x20, 0x00, 0x76, 0x01, 0x6b, 0x03, 0x63, 0x05, 0x5d,
+ 0x07, 0x58, 0x09, 0x54, 0x0c, 0x52, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c,
+ 0x13, 0x4a, 0x15, 0x49, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x45,
+ 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x71,
+ 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x16, 0x00, 0x28, 0x00,
+ 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00,
+ 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53,
+ 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x00, 0x72, 0x02,
+ 0x6b, 0x04, 0x64, 0x06, 0x61, 0x08, 0x5d, 0x0a, 0x5a, 0x0c, 0x56, 0x0e,
+ 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4f, 0x16, 0x4e, 0x17,
+ 0x4d, 0x18, 0x4b, 0x1a, 0x4b, 0x1a, 0x4b, 0x1c, 0x4b, 0x1d, 0x49, 0x1d,
+ 0x00, 0x77, 0x00, 0x6c, 0x02, 0x65, 0x04, 0x5f, 0x06, 0x5a, 0x08, 0x57,
+ 0x0a, 0x54, 0x0c, 0x51, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c, 0x13, 0x4a,
+ 0x15, 0x49, 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x1a, 0x46, 0x1b, 0x45,
+ 0x1c, 0x45, 0x1d, 0x45, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a,
+ 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00,
+ 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13,
+ 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52,
+ 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7c, 0x00, 0x73, 0x02, 0x6c, 0x03, 0x66, 0x05,
+ 0x63, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x10,
+ 0x53, 0x11, 0x52, 0x13, 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x17, 0x4c, 0x18,
+ 0x4c, 0x19, 0x4c, 0x1a, 0x4b, 0x1a, 0x4b, 0x1c, 0x00, 0x77, 0x00, 0x6e,
+ 0x02, 0x66, 0x04, 0x61, 0x05, 0x5c, 0x07, 0x59, 0x09, 0x56, 0x0b, 0x53,
+ 0x0d, 0x51, 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a,
+ 0x15, 0x48, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x46, 0x1b, 0x45,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28,
+ 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00,
+ 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00,
+ 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7c, 0x00, 0x74, 0x02, 0x6e, 0x03, 0x68, 0x05, 0x64, 0x06, 0x60, 0x08,
+ 0x5d, 0x0a, 0x5a, 0x0b, 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11,
+ 0x52, 0x13, 0x50, 0x14, 0x50, 0x15, 0x4d, 0x16, 0x4e, 0x18, 0x4c, 0x18,
+ 0x4c, 0x19, 0x4c, 0x1a, 0x00, 0x77, 0x00, 0x6f, 0x02, 0x68, 0x03, 0x63,
+ 0x05, 0x5e, 0x06, 0x5a, 0x08, 0x57, 0x0a, 0x55, 0x0b, 0x53, 0x0d, 0x50,
+ 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x49,
+ 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x19, 0x46, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79,
+ 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10,
+ 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00,
+ 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00,
+ 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27,
+ 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x75, 0x01,
+ 0x6f, 0x02, 0x69, 0x04, 0x65, 0x06, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0b,
+ 0x5a, 0x0c, 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13,
+ 0x50, 0x13, 0x4f, 0x15, 0x4e, 0x15, 0x4e, 0x17, 0x4d, 0x18, 0x4c, 0x18,
+ 0x00, 0x78, 0x00, 0x70, 0x01, 0x69, 0x03, 0x64, 0x04, 0x60, 0x06, 0x5c,
+ 0x07, 0x59, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x52, 0x0d, 0x50, 0x0f, 0x4f,
+ 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x48,
+ 0x17, 0x48, 0x18, 0x47, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64,
+ 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00,
+ 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00,
+ 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c,
+ 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x76, 0x01, 0x70, 0x02, 0x6a, 0x03,
+ 0x67, 0x05, 0x63, 0x06, 0x60, 0x08, 0x5d, 0x09, 0x5b, 0x0b, 0x59, 0x0c,
+ 0x57, 0x0d, 0x55, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x4f, 0x13,
+ 0x50, 0x15, 0x4f, 0x15, 0x4e, 0x16, 0x4e, 0x18, 0x00, 0x78, 0x00, 0x71,
+ 0x01, 0x6a, 0x03, 0x66, 0x04, 0x61, 0x05, 0x5d, 0x06, 0x5a, 0x08, 0x58,
+ 0x09, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0e, 0x50, 0x0f, 0x4e, 0x10, 0x4e,
+ 0x11, 0x4c, 0x13, 0x4c, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x49, 0x16, 0x48,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b,
+ 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x0c, 0x00,
+ 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00,
+ 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7d, 0x00, 0x76, 0x01, 0x71, 0x02, 0x6c, 0x03, 0x68, 0x05, 0x64, 0x06,
+ 0x61, 0x07, 0x5e, 0x09, 0x5c, 0x0a, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0e,
+ 0x55, 0x0e, 0x55, 0x11, 0x52, 0x11, 0x51, 0x12, 0x51, 0x13, 0x50, 0x14,
+ 0x4f, 0x15, 0x4e, 0x15, 0x00, 0x79, 0x00, 0x71, 0x01, 0x6c, 0x02, 0x66,
+ 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5c, 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55,
+ 0x0b, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c,
+ 0x13, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x4a, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c,
+ 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35,
+ 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00,
+ 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00,
+ 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x77, 0x01,
+ 0x72, 0x02, 0x6d, 0x03, 0x69, 0x04, 0x66, 0x06, 0x63, 0x07, 0x5f, 0x08,
+ 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0c, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x0f,
+ 0x54, 0x11, 0x51, 0x11, 0x52, 0x12, 0x51, 0x13, 0x50, 0x14, 0x50, 0x15,
+ 0x00, 0x79, 0x00, 0x72, 0x01, 0x6d, 0x02, 0x68, 0x03, 0x63, 0x04, 0x60,
+ 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x53,
+ 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c,
+ 0x13, 0x4b, 0x14, 0x4a, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f,
+ 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23,
+ 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00,
+ 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00,
+ 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x78, 0x01, 0x72, 0x02, 0x6e, 0x02,
+ 0x6a, 0x03, 0x67, 0x05, 0x64, 0x06, 0x60, 0x07, 0x5f, 0x09, 0x5c, 0x0a,
+ 0x5b, 0x0b, 0x5a, 0x0c, 0x57, 0x0c, 0x56, 0x0e, 0x55, 0x0f, 0x53, 0x11,
+ 0x52, 0x11, 0x52, 0x12, 0x51, 0x13, 0x50, 0x13, 0x00, 0x79, 0x00, 0x73,
+ 0x01, 0x6d, 0x02, 0x69, 0x03, 0x65, 0x04, 0x61, 0x05, 0x5e, 0x06, 0x5c,
+ 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54, 0x0d, 0x53, 0x0d, 0x51,
+ 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c, 0x13, 0x4b,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e,
+ 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15,
+ 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00,
+ 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00,
+ 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7e, 0x00, 0x78, 0x01, 0x73, 0x02, 0x6e, 0x02, 0x6b, 0x03, 0x68, 0x05,
+ 0x65, 0x06, 0x62, 0x07, 0x5f, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0b,
+ 0x59, 0x0c, 0x57, 0x0d, 0x56, 0x0e, 0x54, 0x0f, 0x54, 0x11, 0x52, 0x11,
+ 0x52, 0x12, 0x51, 0x13, 0x00, 0x79, 0x00, 0x73, 0x01, 0x6e, 0x02, 0x69,
+ 0x03, 0x66, 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58,
+ 0x09, 0x56, 0x0b, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50,
+ 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4d, 0x12, 0x4c, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
+ 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c,
+ 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00,
+ 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00,
+ 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x00,
+ 0x74, 0x01, 0x6f, 0x02, 0x6c, 0x03, 0x68, 0x04, 0x65, 0x05, 0x62, 0x06,
+ 0x61, 0x07, 0x5f, 0x09, 0x5c, 0x09, 0x5b, 0x0b, 0x5a, 0x0b, 0x58, 0x0c,
+ 0x57, 0x0d, 0x55, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12,
+ 0x00, 0x79, 0x00, 0x74, 0x00, 0x6f, 0x02, 0x6a, 0x03, 0x66, 0x04, 0x63,
+ 0x05, 0x60, 0x05, 0x5e, 0x06, 0x5b, 0x07, 0x59, 0x09, 0x58, 0x09, 0x55,
+ 0x0b, 0x55, 0x0c, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50, 0x0f, 0x4e,
+ 0x11, 0x4e, 0x11, 0x4d, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75,
+ 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b,
+ 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
+ 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00,
+ 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x79, 0x00, 0x74, 0x01, 0x70, 0x02,
+ 0x6c, 0x03, 0x69, 0x03, 0x66, 0x05, 0x63, 0x06, 0x62, 0x07, 0x5f, 0x07,
+ 0x5e, 0x09, 0x5c, 0x0a, 0x5a, 0x0b, 0x5a, 0x0c, 0x57, 0x0c, 0x56, 0x0e,
+ 0x55, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x00, 0x79, 0x00, 0x74,
+ 0x00, 0x70, 0x01, 0x6b, 0x02, 0x67, 0x03, 0x64, 0x04, 0x61, 0x05, 0x5f,
+ 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54,
+ 0x0c, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x66, 0x7f, 0x4d, 0x68, 0x49, 0x5c, 0x47, 0x55, 0x45, 0x51, 0x45, 0x4e,
+ 0x44, 0x4c, 0x43, 0x4a, 0x43, 0x49, 0x43, 0x48, 0x43, 0x47, 0x42, 0x47,
+ 0x42, 0x46, 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x45, 0x42, 0x44,
+ 0x42, 0x44, 0x42, 0x44, 0x57, 0x7f, 0x2e, 0x58, 0x34, 0x4d, 0x37, 0x49,
+ 0x39, 0x47, 0x3a, 0x45, 0x3b, 0x44, 0x3b, 0x44, 0x3c, 0x43, 0x3c, 0x43,
+ 0x3c, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x41,
+ 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x99, 0x7f, 0x4d, 0x58,
+ 0x49, 0x4d, 0x47, 0x49, 0x45, 0x47, 0x45, 0x45, 0x44, 0x44, 0x43, 0x44,
+ 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xa5, 0x16, 0x74, 0x23,
+ 0x62, 0x29, 0x59, 0x2d, 0x53, 0x30, 0x50, 0x32, 0x4e, 0x34, 0x4c, 0x35,
+ 0x4a, 0x36, 0x49, 0x37, 0x48, 0x38, 0x48, 0x38, 0x47, 0x39, 0x46, 0x39,
+ 0x46, 0x39, 0x46, 0x3a, 0x45, 0x3a, 0x45, 0x3a, 0x45, 0x3a, 0x44, 0x3b,
+ 0x23, 0x2f, 0x25, 0x35, 0x2a, 0x37, 0x2e, 0x39, 0x31, 0x3a, 0x33, 0x3b,
+ 0x34, 0x3b, 0x35, 0x3c, 0x37, 0x3c, 0x37, 0x3c, 0x38, 0x3d, 0x38, 0x3d,
+ 0x39, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
+ 0x3b, 0x3d, 0x3b, 0x3d, 0x77, 0x27, 0x5f, 0x31, 0x56, 0x35, 0x52, 0x38,
+ 0x4f, 0x39, 0x4c, 0x3a, 0x4b, 0x3b, 0x49, 0x3b, 0x48, 0x3c, 0x48, 0x3c,
+ 0x47, 0x3c, 0x47, 0x3c, 0x46, 0x3d, 0x46, 0x3d, 0x45, 0x3d, 0x45, 0x3d,
+ 0x45, 0x3d, 0x44, 0x3d, 0x44, 0x3d, 0x44, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x5f, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xbb, 0x01, 0x91, 0x09, 0x78, 0x11, 0x6b, 0x17,
+ 0x62, 0x1c, 0x5c, 0x20, 0x58, 0x23, 0x55, 0x25, 0x52, 0x28, 0x51, 0x2a,
+ 0x4f, 0x2b, 0x4e, 0x2c, 0x4d, 0x2e, 0x4c, 0x2f, 0x4b, 0x30, 0x4a, 0x31,
+ 0x49, 0x31, 0x49, 0x32, 0x48, 0x33, 0x47, 0x33, 0x22, 0x25, 0x23, 0x2a,
+ 0x26, 0x2e, 0x2a, 0x31, 0x2c, 0x33, 0x2e, 0x34, 0x30, 0x36, 0x31, 0x37,
+ 0x32, 0x37, 0x33, 0x38, 0x34, 0x38, 0x35, 0x39, 0x36, 0x39, 0x36, 0x3a,
+ 0x37, 0x3a, 0x37, 0x3a, 0x38, 0x3a, 0x38, 0x3b, 0x39, 0x3b, 0x39, 0x3b,
+ 0x7a, 0x1a, 0x68, 0x24, 0x5f, 0x2a, 0x5a, 0x2e, 0x55, 0x31, 0x53, 0x33,
+ 0x51, 0x34, 0x4f, 0x35, 0x4d, 0x36, 0x4c, 0x37, 0x4b, 0x38, 0x4b, 0x38,
+ 0x4a, 0x39, 0x49, 0x39, 0x49, 0x39, 0x48, 0x3a, 0x47, 0x3a, 0x47, 0x3a,
+ 0x46, 0x3b, 0x46, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x39, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x8b, 0x00, 0x44, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xc6, 0x00, 0xa3, 0x02, 0x8a, 0x07, 0x7a, 0x0c, 0x6f, 0x11, 0x68, 0x15,
+ 0x62, 0x18, 0x5e, 0x1b, 0x5b, 0x1d, 0x58, 0x20, 0x56, 0x22, 0x54, 0x23,
+ 0x53, 0x25, 0x51, 0x26, 0x50, 0x28, 0x4e, 0x29, 0x4d, 0x2a, 0x4d, 0x2b,
+ 0x4d, 0x2c, 0x4c, 0x2c, 0x22, 0x23, 0x22, 0x27, 0x25, 0x2a, 0x27, 0x2c,
+ 0x2a, 0x2e, 0x2b, 0x30, 0x2d, 0x32, 0x2e, 0x33, 0x30, 0x34, 0x31, 0x34,
+ 0x32, 0x35, 0x33, 0x36, 0x33, 0x36, 0x34, 0x37, 0x34, 0x37, 0x35, 0x38,
+ 0x36, 0x38, 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x7b, 0x16, 0x6d, 0x1f,
+ 0x65, 0x24, 0x5f, 0x28, 0x5b, 0x2b, 0x58, 0x2d, 0x55, 0x2f, 0x54, 0x31,
+ 0x52, 0x32, 0x50, 0x33, 0x4f, 0x34, 0x4e, 0x35, 0x4d, 0x35, 0x4c, 0x36,
+ 0x4b, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x4a, 0x38, 0x4a, 0x39, 0x49, 0x39,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35,
+ 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xb3, 0x00, 0x9f, 0x00, 0x6d, 0x00, 0x33, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xcc, 0x00, 0xaf, 0x00,
+ 0x98, 0x03, 0x87, 0x06, 0x7b, 0x0a, 0x73, 0x0e, 0x6c, 0x11, 0x67, 0x13,
+ 0x63, 0x16, 0x5f, 0x18, 0x5c, 0x1a, 0x5a, 0x1c, 0x58, 0x1e, 0x56, 0x20,
+ 0x55, 0x21, 0x54, 0x22, 0x52, 0x24, 0x51, 0x25, 0x50, 0x26, 0x4f, 0x27,
+ 0x22, 0x22, 0x22, 0x25, 0x24, 0x27, 0x26, 0x2a, 0x28, 0x2b, 0x29, 0x2d,
+ 0x2b, 0x2f, 0x2c, 0x30, 0x2d, 0x31, 0x2f, 0x32, 0x30, 0x33, 0x30, 0x33,
+ 0x31, 0x34, 0x32, 0x35, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36, 0x34, 0x36,
+ 0x35, 0x36, 0x35, 0x37, 0x7c, 0x15, 0x71, 0x1b, 0x68, 0x20, 0x63, 0x24,
+ 0x5f, 0x27, 0x5c, 0x29, 0x59, 0x2c, 0x57, 0x2d, 0x55, 0x2f, 0x54, 0x30,
+ 0x53, 0x31, 0x51, 0x32, 0x50, 0x32, 0x4f, 0x33, 0x4f, 0x34, 0x4e, 0x35,
+ 0x4d, 0x35, 0x4c, 0x35, 0x4b, 0x35, 0x4a, 0x36, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1d,
+ 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa, 0x00,
+ 0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xcf, 0x00, 0xb7, 0x00, 0xa2, 0x00, 0x92, 0x03,
+ 0x85, 0x06, 0x7c, 0x09, 0x75, 0x0b, 0x6f, 0x0e, 0x6a, 0x11, 0x66, 0x13,
+ 0x63, 0x15, 0x5f, 0x17, 0x5e, 0x19, 0x5c, 0x1a, 0x5a, 0x1c, 0x57, 0x1d,
+ 0x56, 0x1f, 0x55, 0x1f, 0x55, 0x21, 0x54, 0x22, 0x22, 0x22, 0x22, 0x24,
+ 0x23, 0x26, 0x25, 0x28, 0x26, 0x29, 0x28, 0x2b, 0x29, 0x2c, 0x2b, 0x2d,
+ 0x2c, 0x2f, 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x31, 0x30, 0x32, 0x30, 0x33,
+ 0x30, 0x33, 0x32, 0x33, 0x32, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36,
+ 0x7c, 0x14, 0x73, 0x19, 0x6c, 0x1e, 0x67, 0x22, 0x63, 0x24, 0x5f, 0x26,
+ 0x5c, 0x28, 0x5a, 0x2a, 0x58, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2f,
+ 0x53, 0x30, 0x52, 0x31, 0x51, 0x31, 0x4f, 0x32, 0x4f, 0x33, 0x4f, 0x33,
+ 0x4f, 0x34, 0x4e, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00,
+ 0x48, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xd2, 0x00, 0xbd, 0x00, 0xaa, 0x00, 0x9b, 0x01, 0x8e, 0x03, 0x84, 0x05,
+ 0x7c, 0x08, 0x76, 0x0a, 0x71, 0x0c, 0x6c, 0x0f, 0x69, 0x11, 0x66, 0x12,
+ 0x63, 0x14, 0x60, 0x16, 0x5e, 0x17, 0x5d, 0x19, 0x5b, 0x1a, 0x59, 0x1b,
+ 0x57, 0x1c, 0x56, 0x1e, 0x22, 0x22, 0x22, 0x23, 0x23, 0x25, 0x24, 0x27,
+ 0x25, 0x28, 0x27, 0x29, 0x28, 0x2b, 0x29, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d,
+ 0x2d, 0x2f, 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x30, 0x30, 0x32, 0x30, 0x33,
+ 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x7d, 0x13, 0x75, 0x18,
+ 0x6e, 0x1c, 0x69, 0x1f, 0x65, 0x22, 0x62, 0x24, 0x60, 0x26, 0x5c, 0x28,
+ 0x5b, 0x29, 0x59, 0x2a, 0x57, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2f, 0x53, 0x31, 0x51, 0x31, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x32,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c,
+ 0x00, 0x35, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd3, 0x00, 0xc2, 0x00,
+ 0xb1, 0x00, 0xa2, 0x00, 0x96, 0x02, 0x8c, 0x03, 0x83, 0x05, 0x7d, 0x07,
+ 0x77, 0x09, 0x73, 0x0b, 0x6f, 0x0d, 0x6a, 0x0f, 0x68, 0x11, 0x66, 0x12,
+ 0x63, 0x14, 0x60, 0x15, 0x5f, 0x16, 0x5e, 0x18, 0x5c, 0x19, 0x5a, 0x1a,
+ 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x27, 0x26, 0x29,
+ 0x27, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2e,
+ 0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x30, 0x31, 0x30, 0x32,
+ 0x30, 0x33, 0x30, 0x33, 0x7d, 0x13, 0x76, 0x17, 0x70, 0x1b, 0x6b, 0x1e,
+ 0x68, 0x20, 0x65, 0x22, 0x61, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x29,
+ 0x5a, 0x2a, 0x58, 0x2b, 0x57, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2f, 0x53, 0x30, 0x53, 0x31, 0x51, 0x31, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f,
+ 0x00, 0x25, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6, 0x00,
+ 0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xd4, 0x00, 0xc5, 0x00, 0xb6, 0x00, 0xa8, 0x00,
+ 0x9c, 0x00, 0x92, 0x02, 0x8a, 0x03, 0x82, 0x05, 0x7d, 0x07, 0x78, 0x09,
+ 0x74, 0x0a, 0x71, 0x0c, 0x6c, 0x0e, 0x69, 0x0f, 0x68, 0x11, 0x65, 0x12,
+ 0x63, 0x13, 0x60, 0x14, 0x5f, 0x16, 0x5e, 0x17, 0x21, 0x22, 0x22, 0x23,
+ 0x22, 0x24, 0x23, 0x25, 0x24, 0x26, 0x25, 0x27, 0x27, 0x28, 0x27, 0x29,
+ 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2e,
+ 0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x31,
+ 0x7d, 0x12, 0x77, 0x16, 0x71, 0x19, 0x6d, 0x1c, 0x69, 0x1f, 0x66, 0x20,
+ 0x64, 0x23, 0x61, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x28, 0x5b, 0x2a,
+ 0x58, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x54, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21,
+ 0x00, 0x18, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00,
+ 0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xd5, 0x00, 0xc7, 0x00, 0xba, 0x00, 0xad, 0x00, 0xa2, 0x00, 0x98, 0x01,
+ 0x8f, 0x02, 0x88, 0x03, 0x82, 0x05, 0x7e, 0x07, 0x78, 0x08, 0x74, 0x0a,
+ 0x72, 0x0b, 0x6e, 0x0c, 0x6b, 0x0e, 0x69, 0x0f, 0x67, 0x11, 0x65, 0x12,
+ 0x63, 0x13, 0x60, 0x14, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+ 0x24, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28, 0x27, 0x29, 0x28, 0x2b,
+ 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d, 0x2a, 0x2d, 0x2c, 0x2d, 0x2d, 0x2e,
+ 0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x7d, 0x12, 0x77, 0x15,
+ 0x72, 0x18, 0x6e, 0x1b, 0x6b, 0x1d, 0x68, 0x20, 0x65, 0x21, 0x64, 0x23,
+ 0x60, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x59, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x54, 0x2e, 0x53, 0x2e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d,
+ 0x00, 0x3a, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15,
+ 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00,
+ 0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd6, 0x00, 0xc9, 0x00,
+ 0xbd, 0x00, 0xb2, 0x00, 0xa7, 0x00, 0x9d, 0x00, 0x95, 0x01, 0x8e, 0x02,
+ 0x87, 0x03, 0x82, 0x05, 0x7e, 0x06, 0x79, 0x08, 0x75, 0x09, 0x73, 0x0b,
+ 0x70, 0x0c, 0x6c, 0x0d, 0x6a, 0x0e, 0x68, 0x0f, 0x67, 0x11, 0x65, 0x12,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x26,
+ 0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b,
+ 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e,
+ 0x2d, 0x2f, 0x2d, 0x30, 0x7d, 0x12, 0x78, 0x15, 0x73, 0x18, 0x70, 0x1a,
+ 0x6d, 0x1d, 0x69, 0x1e, 0x67, 0x20, 0x65, 0x21, 0x63, 0x23, 0x60, 0x24,
+ 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x5a, 0x2a, 0x58, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36,
+ 0x00, 0x30, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00,
+ 0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00,
+ 0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xd7, 0x00, 0xcb, 0x00, 0xc0, 0x00, 0xb5, 0x00,
+ 0xab, 0x00, 0xa2, 0x00, 0x9a, 0x00, 0x92, 0x02, 0x8d, 0x02, 0x87, 0x03,
+ 0x81, 0x05, 0x7e, 0x06, 0x79, 0x07, 0x76, 0x09, 0x74, 0x0a, 0x71, 0x0b,
+ 0x6e, 0x0c, 0x6b, 0x0d, 0x6a, 0x0e, 0x68, 0x10, 0x21, 0x22, 0x22, 0x22,
+ 0x22, 0x23, 0x23, 0x24, 0x23, 0x25, 0x24, 0x25, 0x25, 0x27, 0x25, 0x27,
+ 0x27, 0x28, 0x27, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x2a, 0x2b,
+ 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e,
+ 0x7e, 0x12, 0x79, 0x15, 0x75, 0x17, 0x71, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d,
+ 0x69, 0x1f, 0x65, 0x20, 0x65, 0x22, 0x62, 0x23, 0x60, 0x23, 0x60, 0x25,
+ 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x5c, 0x29, 0x59, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c,
+ 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00,
+ 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xd7, 0x00, 0xcc, 0x00, 0xc2, 0x00, 0xb9, 0x00, 0xae, 0x00, 0xa6, 0x00,
+ 0x9e, 0x00, 0x97, 0x01, 0x90, 0x02, 0x8b, 0x02, 0x85, 0x04, 0x81, 0x05,
+ 0x7e, 0x06, 0x7a, 0x07, 0x76, 0x08, 0x74, 0x09, 0x72, 0x0b, 0x6f, 0x0c,
+ 0x6c, 0x0c, 0x6a, 0x0e, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+ 0x23, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28,
+ 0x26, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x7e, 0x12, 0x79, 0x15,
+ 0x75, 0x17, 0x72, 0x19, 0x6e, 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x68, 0x20,
+ 0x65, 0x20, 0x65, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27,
+ 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x5a, 0x2a, 0x58, 0x2a, 0x57, 0x2a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e,
+ 0x00, 0x3c, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22,
+ 0x00, 0x1c, 0x00, 0x16, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00,
+ 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd8, 0x00, 0xce, 0x00,
+ 0xc5, 0x00, 0xbb, 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa1, 0x00, 0x9b, 0x00,
+ 0x94, 0x01, 0x8f, 0x02, 0x8a, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06,
+ 0x7b, 0x07, 0x77, 0x08, 0x75, 0x09, 0x73, 0x0a, 0x71, 0x0b, 0x6e, 0x0c,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25,
+ 0x24, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28,
+ 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c,
+ 0x2b, 0x2d, 0x2b, 0x2d, 0x7e, 0x12, 0x7a, 0x14, 0x76, 0x16, 0x72, 0x18,
+ 0x6f, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20,
+ 0x64, 0x23, 0x61, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27,
+ 0x5c, 0x27, 0x5c, 0x28, 0x5b, 0x2a, 0x59, 0x2a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39,
+ 0x00, 0x35, 0x00, 0x31, 0x00, 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a,
+ 0x00, 0x14, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00,
+ 0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00,
+ 0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbd, 0x00,
+ 0xb5, 0x00, 0xad, 0x00, 0xa6, 0x00, 0x9e, 0x00, 0x99, 0x00, 0x92, 0x01,
+ 0x8e, 0x02, 0x89, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06, 0x7b, 0x07,
+ 0x77, 0x07, 0x75, 0x09, 0x73, 0x09, 0x72, 0x0b, 0x21, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25,
+ 0x25, 0x27, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28,
+ 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d,
+ 0x7e, 0x12, 0x7a, 0x14, 0x76, 0x15, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a,
+ 0x6c, 0x1d, 0x69, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x65, 0x21, 0x64, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0x5c, 0x27, 0x5c, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32,
+ 0x00, 0x2d, 0x00, 0x28, 0x00, 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13,
+ 0x00, 0x0d, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00,
+ 0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00,
+ 0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xd8, 0x00, 0xd0, 0x00, 0xc7, 0x00, 0xbf, 0x00, 0xb8, 0x00, 0xaf, 0x00,
+ 0xa9, 0x00, 0xa1, 0x00, 0x9c, 0x00, 0x96, 0x01, 0x90, 0x02, 0x8d, 0x02,
+ 0x88, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7b, 0x07, 0x77, 0x07,
+ 0x76, 0x09, 0x74, 0x09, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23,
+ 0x23, 0x24, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x26, 0x25, 0x27,
+ 0x26, 0x27, 0x27, 0x27, 0x26, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a,
+ 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x7e, 0x11, 0x7a, 0x13,
+ 0x76, 0x15, 0x74, 0x18, 0x72, 0x19, 0x6e, 0x1a, 0x6d, 0x1c, 0x69, 0x1d,
+ 0x69, 0x1e, 0x67, 0x20, 0x65, 0x20, 0x65, 0x21, 0x63, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3c, 0x00, 0x3d,
+ 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f,
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x58, 0x00, 0x3d,
+ 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x42, 0x00, 0x3e, 0x00, 0x3e,
+ 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x0b, 0x07, 0x17, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3a, 0x00, 0x3c,
+ 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x47, 0x07, 0x0f, 0x0f,
+ 0x00, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3d,
+ 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f,
+ 0x00, 0x3f, 0x00, 0x3f, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd9, 0x00, 0xd1, 0x00,
+ 0xc9, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xb2, 0x00, 0xac, 0x00, 0xa5, 0x00,
+ 0x9e, 0x00, 0x9a, 0x00, 0x93, 0x01, 0x8f, 0x02, 0x8c, 0x02, 0x88, 0x03,
+ 0x83, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7b, 0x06, 0x78, 0x07, 0x76, 0x08,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24,
+ 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x25, 0x27, 0x27, 0x27,
+ 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b,
+ 0x2a, 0x2b, 0x2b, 0x2b, 0x7e, 0x11, 0x7b, 0x13, 0x77, 0x15, 0x75, 0x17,
+ 0x72, 0x18, 0x6f, 0x1a, 0x6d, 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x69, 0x1f,
+ 0x65, 0x20, 0x65, 0x20, 0x65, 0x22, 0x62, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x25, 0x5f, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x35, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c,
+ 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
+ 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x39, 0x00, 0x42,
+ 0x00, 0x41, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d,
+ 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x27, 0x02,
+ 0x02, 0x12, 0x00, 0x25, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x38, 0x00, 0x3a,
+ 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e,
+ 0x00, 0x3e, 0x00, 0x3e, 0x7f, 0x00, 0x3f, 0x00, 0x05, 0x05, 0x00, 0x1c,
+ 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3b,
+ 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xd9, 0x00, 0xd2, 0x00, 0xca, 0x00, 0xc3, 0x00,
+ 0xbb, 0x00, 0xb5, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x9d, 0x00,
+ 0x98, 0x00, 0x92, 0x01, 0x8e, 0x02, 0x8b, 0x02, 0x87, 0x03, 0x83, 0x04,
+ 0x81, 0x05, 0x7f, 0x06, 0x7c, 0x06, 0x78, 0x07, 0x21, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25,
+ 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x27, 0x27, 0x28,
+ 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b,
+ 0x7e, 0x11, 0x7b, 0x13, 0x77, 0x15, 0x76, 0x17, 0x72, 0x18, 0x71, 0x1a,
+ 0x6d, 0x1a, 0x6d, 0x1c, 0x69, 0x1d, 0x69, 0x1d, 0x68, 0x20, 0x65, 0x20,
+ 0x65, 0x20, 0x65, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x25,
+ 0x5f, 0x27, 0x5c, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16,
+ 0x00, 0x24, 0x00, 0x2c, 0x00, 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39,
+ 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d,
+ 0x00, 0x4c, 0x00, 0x39, 0x00, 0x16, 0x00, 0x28, 0x00, 0x2f, 0x00, 0x2e,
+ 0x00, 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b,
+ 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x6f, 0x00, 0x22, 0x00, 0x09, 0x0b,
+ 0x00, 0x16, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x35,
+ 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c,
+ 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x09, 0x00, 0x19,
+ 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36,
+ 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xd9, 0x00, 0xd2, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xbd, 0x00, 0xb7, 0x00,
+ 0xb0, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9f, 0x00, 0x9b, 0x00, 0x95, 0x01,
+ 0x91, 0x01, 0x8e, 0x02, 0x8a, 0x02, 0x86, 0x03, 0x83, 0x04, 0x81, 0x05,
+ 0x7f, 0x06, 0x7c, 0x06, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23,
+ 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25,
+ 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x7f, 0x11, 0x7b, 0x13,
+ 0x77, 0x15, 0x76, 0x16, 0x72, 0x18, 0x72, 0x19, 0x6d, 0x1a, 0x6d, 0x1b,
+ 0x6b, 0x1d, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20, 0x65, 0x20,
+ 0x64, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x24, 0x5f, 0x26,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1d,
+ 0x00, 0x25, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36,
+ 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x4c, 0x00, 0x42,
+ 0x00, 0x28, 0x00, 0x09, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b,
+ 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38,
+ 0x00, 0x39, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xaf, 0x00, 0x93, 0x00, 0x58, 0x00, 0x21, 0x00, 0x0e, 0x08, 0x02, 0x0e,
+ 0x00, 0x18, 0x00, 0x20, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x31,
+ 0x00, 0x33, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38, 0xb2, 0x00, 0x9c, 0x00,
+ 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05, 0x00, 0x00, 0x0b, 0x00, 0x16,
+ 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32,
+ 0x00, 0x33, 0x00, 0x35, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xda, 0x00, 0xd2, 0x00,
+ 0xcb, 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xac, 0x00,
+ 0xa8, 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x01, 0x90, 0x02,
+ 0x8d, 0x02, 0x89, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05, 0x7f, 0x06,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23,
+ 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27,
+ 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x29, 0x27, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x29, 0x7f, 0x11, 0x7b, 0x13, 0x78, 0x15, 0x76, 0x15,
+ 0x73, 0x18, 0x72, 0x18, 0x6f, 0x1a, 0x6d, 0x1a, 0x6d, 0x1c, 0x69, 0x1d,
+ 0x69, 0x1d, 0x69, 0x1f, 0x65, 0x20, 0x65, 0x20, 0x65, 0x21, 0x64, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x24, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f,
+ 0x00, 0x25, 0x00, 0x2a, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34,
+ 0x00, 0x35, 0x00, 0x37, 0x00, 0x48, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16,
+ 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a,
+ 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x00, 0xa4, 0x00,
+ 0x7a, 0x00, 0x4a, 0x00, 0x20, 0x00, 0x12, 0x06, 0x07, 0x0c, 0x00, 0x10,
+ 0x00, 0x18, 0x00, 0x1f, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2c, 0x00, 0x2e,
+ 0x00, 0x30, 0x00, 0x32, 0xb7, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x62, 0x00,
+ 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14,
+ 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2e,
+ 0x33, 0x22, 0x28, 0x22, 0x25, 0x22, 0x24, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21,
+ 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21,
+ 0x22, 0x21, 0x22, 0x21, 0x9d, 0x05, 0x6b, 0x0d, 0x51, 0x12, 0x45, 0x15,
+ 0x3d, 0x17, 0x38, 0x18, 0x35, 0x1a, 0x32, 0x1b, 0x30, 0x1b, 0x2f, 0x1c,
+ 0x2d, 0x1c, 0x2d, 0x1c, 0x2c, 0x1d, 0x2b, 0x1d, 0x2a, 0x1e, 0x2a, 0x1e,
+ 0x29, 0x1e, 0x29, 0x1e, 0x28, 0x1e, 0x28, 0x1e, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x5f, 0x13, 0x46, 0x17, 0x39, 0x1a, 0x33, 0x1b, 0x2f, 0x1c, 0x2d, 0x1d,
+ 0x2b, 0x1e, 0x2a, 0x1e, 0x29, 0x1e, 0x28, 0x1f, 0x27, 0x1f, 0x27, 0x1f,
+ 0x27, 0x1f, 0x26, 0x1f, 0x26, 0x20, 0x26, 0x20, 0x25, 0x20, 0x25, 0x20,
+ 0x25, 0x20, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21,
+ 0x00, 0x25, 0x00, 0x29, 0x00, 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32,
+ 0x00, 0x42, 0x00, 0x3d, 0x00, 0x2e, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29,
+ 0x00, 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, 0xad, 0x00, 0x8f, 0x00, 0x68, 0x00,
+ 0x42, 0x00, 0x20, 0x00, 0x14, 0x05, 0x0b, 0x0a, 0x04, 0x0d, 0x00, 0x12,
+ 0x00, 0x19, 0x00, 0x1e, 0x00, 0x23, 0x00, 0x26, 0x00, 0x29, 0x00, 0x2c,
+ 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5b, 0x00, 0x3f, 0x00,
+ 0x29, 0x00, 0x16, 0x00, 0x08, 0x00, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x13,
+ 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25, 0x37, 0x28, 0x2d, 0x25,
+ 0x28, 0x23, 0x26, 0x23, 0x25, 0x23, 0x24, 0x22, 0x24, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0xbc, 0x00, 0x8e, 0x01, 0x73, 0x04, 0x60, 0x08, 0x55, 0x0b, 0x4c, 0x0d,
+ 0x47, 0x0f, 0x42, 0x11, 0x3e, 0x12, 0x3b, 0x13, 0x39, 0x14, 0x37, 0x15,
+ 0x36, 0x16, 0x34, 0x16, 0x33, 0x17, 0x32, 0x18, 0x31, 0x18, 0x30, 0x19,
+ 0x2f, 0x19, 0x2f, 0x19, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x6f, 0x11, 0x58, 0x11,
+ 0x4a, 0x13, 0x41, 0x15, 0x3b, 0x16, 0x37, 0x17, 0x34, 0x18, 0x32, 0x19,
+ 0x30, 0x1a, 0x2e, 0x1a, 0x2d, 0x1b, 0x2c, 0x1b, 0x2c, 0x1c, 0x2b, 0x1c,
+ 0x2a, 0x1c, 0x2a, 0x1d, 0x29, 0x1d, 0x29, 0x1d, 0x28, 0x1d, 0x28, 0x1d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22,
+ 0x00, 0x26, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x3e, 0x00, 0x3a,
+ 0x00, 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x09,
+ 0x00, 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29,
+ 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xba, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x7d, 0x00, 0x5c, 0x00, 0x3c, 0x00,
+ 0x20, 0x00, 0x16, 0x04, 0x0e, 0x08, 0x07, 0x0c, 0x02, 0x0e, 0x00, 0x13,
+ 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x25, 0xbb, 0x00, 0xb5, 0x00,
+ 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x2c, 0x00,
+ 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x12,
+ 0x00, 0x17, 0x00, 0x1c, 0x38, 0x2c, 0x30, 0x28, 0x2b, 0x26, 0x29, 0x25,
+ 0x27, 0x24, 0x26, 0x24, 0x25, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xc6, 0x00, 0xa4, 0x00,
+ 0x89, 0x00, 0x77, 0x02, 0x67, 0x04, 0x5e, 0x06, 0x55, 0x08, 0x50, 0x0a,
+ 0x4b, 0x0c, 0x47, 0x0d, 0x44, 0x0e, 0x41, 0x0f, 0x3e, 0x10, 0x3d, 0x11,
+ 0x3b, 0x12, 0x39, 0x12, 0x38, 0x13, 0x37, 0x14, 0x35, 0x15, 0x35, 0x16,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x74, 0x11, 0x63, 0x11, 0x55, 0x11, 0x4c, 0x12,
+ 0x44, 0x13, 0x40, 0x14, 0x3b, 0x15, 0x39, 0x16, 0x36, 0x17, 0x34, 0x17,
+ 0x33, 0x18, 0x31, 0x18, 0x30, 0x19, 0x2f, 0x19, 0x2e, 0x1a, 0x2d, 0x1a,
+ 0x2d, 0x1a, 0x2c, 0x1b, 0x2b, 0x1b, 0x2b, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22,
+ 0x00, 0x26, 0x00, 0x28, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b,
+ 0x00, 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f,
+ 0x00, 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb5, 0x00,
+ 0xa4, 0x00, 0x8b, 0x00, 0x6f, 0x00, 0x52, 0x00, 0x37, 0x00, 0x20, 0x00,
+ 0x17, 0x04, 0x10, 0x07, 0x0a, 0x0a, 0x05, 0x0d, 0x00, 0x0f, 0x00, 0x14,
+ 0x00, 0x19, 0x00, 0x1d, 0xbc, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x96, 0x00,
+ 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x20, 0x00,
+ 0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11,
+ 0x3a, 0x2f, 0x32, 0x2b, 0x2e, 0x28, 0x2b, 0x27, 0x28, 0x25, 0x27, 0x25,
+ 0x27, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23,
+ 0x24, 0x23, 0x23, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0xcd, 0x00, 0xb0, 0x00, 0x9a, 0x00, 0x87, 0x00,
+ 0x78, 0x01, 0x6c, 0x03, 0x64, 0x04, 0x5c, 0x05, 0x57, 0x07, 0x51, 0x09,
+ 0x4e, 0x0a, 0x4a, 0x0b, 0x48, 0x0c, 0x45, 0x0c, 0x43, 0x0e, 0x40, 0x0f,
+ 0x3f, 0x0f, 0x3d, 0x0f, 0x3c, 0x11, 0x3b, 0x12, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x77, 0x11, 0x69, 0x11, 0x5e, 0x11, 0x54, 0x11, 0x4d, 0x11, 0x47, 0x12,
+ 0x43, 0x13, 0x3f, 0x13, 0x3c, 0x14, 0x39, 0x15, 0x38, 0x16, 0x36, 0x16,
+ 0x35, 0x17, 0x33, 0x17, 0x32, 0x18, 0x31, 0x18, 0x30, 0x18, 0x2f, 0x18,
+ 0x2f, 0x19, 0x2e, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x0d, 0x00, 0x13, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23,
+ 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b,
+ 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13,
+ 0x00, 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xaa, 0x00, 0x96, 0x00,
+ 0x7e, 0x00, 0x64, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x20, 0x00, 0x18, 0x03,
+ 0x11, 0x06, 0x0c, 0x09, 0x07, 0x0c, 0x03, 0x0e, 0x00, 0x10, 0x00, 0x15,
+ 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x8b, 0x00, 0x77, 0x00,
+ 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30, 0x00, 0x23, 0x00, 0x18, 0x00,
+ 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3b, 0x32, 0x34, 0x2d,
+ 0x2f, 0x2a, 0x2c, 0x28, 0x2a, 0x27, 0x29, 0x26, 0x27, 0x25, 0x27, 0x25,
+ 0x26, 0x24, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x23, 0x24, 0x23,
+ 0x24, 0x23, 0x24, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x22,
+ 0xcf, 0x00, 0xb9, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x85, 0x00, 0x7a, 0x01,
+ 0x70, 0x02, 0x68, 0x03, 0x61, 0x04, 0x5c, 0x05, 0x57, 0x07, 0x53, 0x07,
+ 0x50, 0x09, 0x4c, 0x0a, 0x4a, 0x0a, 0x48, 0x0c, 0x45, 0x0c, 0x44, 0x0c,
+ 0x42, 0x0d, 0x41, 0x0f, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x78, 0x11, 0x6d, 0x11,
+ 0x63, 0x11, 0x5b, 0x11, 0x53, 0x11, 0x4e, 0x11, 0x49, 0x12, 0x45, 0x12,
+ 0x41, 0x13, 0x3f, 0x13, 0x3c, 0x14, 0x3a, 0x14, 0x39, 0x15, 0x37, 0x16,
+ 0x36, 0x16, 0x35, 0x17, 0x33, 0x17, 0x33, 0x17, 0x32, 0x17, 0x31, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c,
+ 0x00, 0x11, 0x00, 0x16, 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x3e, 0x00, 0x3d,
+ 0x00, 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16,
+ 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9d, 0x00, 0x89, 0x00, 0x73, 0x00,
+ 0x5c, 0x00, 0x46, 0x00, 0x32, 0x00, 0x20, 0x00, 0x19, 0x03, 0x13, 0x06,
+ 0x0e, 0x08, 0x09, 0x0b, 0x05, 0x0d, 0x01, 0x0e, 0xbd, 0x00, 0xba, 0x00,
+ 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5e, 0x00,
+ 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26, 0x00, 0x1c, 0x00, 0x13, 0x00,
+ 0x0b, 0x00, 0x03, 0x00, 0x3c, 0x34, 0x35, 0x2f, 0x31, 0x2c, 0x2e, 0x2a,
+ 0x2c, 0x28, 0x2a, 0x27, 0x28, 0x27, 0x28, 0x26, 0x27, 0x25, 0x27, 0x25,
+ 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x23,
+ 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x23, 0xd2, 0x00, 0xbe, 0x00,
+ 0xad, 0x00, 0x9d, 0x00, 0x90, 0x00, 0x84, 0x00, 0x7a, 0x00, 0x72, 0x01,
+ 0x6b, 0x02, 0x65, 0x04, 0x60, 0x04, 0x5b, 0x05, 0x58, 0x06, 0x54, 0x07,
+ 0x51, 0x07, 0x4f, 0x09, 0x4c, 0x0a, 0x4a, 0x0a, 0x48, 0x0b, 0x46, 0x0c,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x7a, 0x11, 0x70, 0x11, 0x67, 0x11, 0x5f, 0x11,
+ 0x59, 0x11, 0x53, 0x11, 0x4e, 0x11, 0x4a, 0x11, 0x46, 0x12, 0x43, 0x13,
+ 0x41, 0x13, 0x3e, 0x13, 0x3d, 0x14, 0x3b, 0x14, 0x39, 0x14, 0x38, 0x15,
+ 0x37, 0x16, 0x36, 0x16, 0x35, 0x16, 0x34, 0x17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10,
+ 0x00, 0x14, 0x00, 0x18, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34,
+ 0x00, 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06,
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00,
+ 0xb1, 0x00, 0xa3, 0x00, 0x92, 0x00, 0x7e, 0x00, 0x6a, 0x00, 0x56, 0x00,
+ 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x19, 0x03, 0x14, 0x05, 0x0f, 0x08,
+ 0x0b, 0x0a, 0x07, 0x0c, 0xbd, 0x00, 0xbb, 0x00, 0xb4, 0x00, 0xa9, 0x00,
+ 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4d, 0x00,
+ 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0e, 0x00,
+ 0x3c, 0x35, 0x36, 0x31, 0x32, 0x2e, 0x2f, 0x2b, 0x2d, 0x2a, 0x2b, 0x28,
+ 0x2a, 0x28, 0x28, 0x27, 0x28, 0x27, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25,
+ 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x24,
+ 0x24, 0x23, 0x24, 0x23, 0xd3, 0x00, 0xc2, 0x00, 0xb2, 0x00, 0xa4, 0x00,
+ 0x98, 0x00, 0x8d, 0x00, 0x83, 0x00, 0x7b, 0x00, 0x73, 0x01, 0x6e, 0x02,
+ 0x67, 0x02, 0x63, 0x04, 0x5f, 0x04, 0x5b, 0x05, 0x58, 0x05, 0x55, 0x07,
+ 0x52, 0x07, 0x50, 0x07, 0x4e, 0x09, 0x4c, 0x0a, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x7a, 0x11, 0x72, 0x11, 0x6a, 0x11, 0x63, 0x11, 0x5d, 0x11, 0x57, 0x11,
+ 0x52, 0x11, 0x4e, 0x11, 0x4a, 0x11, 0x48, 0x12, 0x44, 0x12, 0x42, 0x13,
+ 0x40, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x14, 0x3a, 0x14, 0x39, 0x14,
+ 0x38, 0x15, 0x37, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29,
+ 0x00, 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa8, 0x00,
+ 0x99, 0x00, 0x87, 0x00, 0x75, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00,
+ 0x2e, 0x00, 0x1f, 0x00, 0x1a, 0x02, 0x15, 0x05, 0x10, 0x07, 0x0c, 0x09,
+ 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac, 0x00, 0xa0, 0x00, 0x93, 0x00,
+ 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3f, 0x00,
+ 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19, 0x00, 0x3c, 0x36, 0x37, 0x32,
+ 0x33, 0x2f, 0x30, 0x2d, 0x2e, 0x2b, 0x2d, 0x2a, 0x2b, 0x28, 0x2a, 0x28,
+ 0x28, 0x27, 0x28, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25,
+ 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x24,
+ 0xd5, 0x00, 0xc5, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x9f, 0x00, 0x95, 0x00,
+ 0x8b, 0x00, 0x83, 0x00, 0x7c, 0x00, 0x75, 0x01, 0x6f, 0x01, 0x69, 0x02,
+ 0x66, 0x02, 0x61, 0x04, 0x5e, 0x04, 0x5a, 0x05, 0x58, 0x05, 0x55, 0x06,
+ 0x53, 0x07, 0x51, 0x07, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7b, 0x11, 0x73, 0x11,
+ 0x6c, 0x11, 0x66, 0x11, 0x60, 0x11, 0x5b, 0x11, 0x56, 0x11, 0x52, 0x11,
+ 0x4f, 0x11, 0x4b, 0x11, 0x48, 0x11, 0x45, 0x12, 0x44, 0x12, 0x41, 0x13,
+ 0x40, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x14, 0x3a, 0x14, 0x39, 0x14,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x3f, 0x00, 0x3e,
+ 0x00, 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f,
+ 0x00, 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x8f, 0x00,
+ 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2d, 0x00,
+ 0x1f, 0x00, 0x1a, 0x02, 0x16, 0x04, 0x11, 0x06, 0xbe, 0x00, 0xbc, 0x00,
+ 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x8b, 0x00, 0x7e, 0x00,
+ 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a, 0x00, 0x3f, 0x00, 0x35, 0x00,
+ 0x2c, 0x00, 0x23, 0x00, 0x3c, 0x37, 0x38, 0x33, 0x34, 0x30, 0x31, 0x2e,
+ 0x2f, 0x2c, 0x2d, 0x2a, 0x2c, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x27,
+ 0x28, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x25, 0x25,
+ 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0xd5, 0x00, 0xc8, 0x00,
+ 0xbb, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x92, 0x00, 0x8a, 0x00,
+ 0x82, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x70, 0x01, 0x6c, 0x02, 0x67, 0x02,
+ 0x64, 0x03, 0x60, 0x04, 0x5d, 0x04, 0x5b, 0x05, 0x58, 0x05, 0x55, 0x05,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x7b, 0x11, 0x75, 0x11, 0x6e, 0x11, 0x68, 0x11,
+ 0x63, 0x11, 0x5e, 0x11, 0x5a, 0x11, 0x56, 0x11, 0x52, 0x11, 0x4f, 0x11,
+ 0x4c, 0x11, 0x49, 0x11, 0x47, 0x12, 0x44, 0x12, 0x43, 0x12, 0x41, 0x13,
+ 0x3f, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x09, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38,
+ 0x00, 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16,
+ 0x00, 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00,
+ 0xb7, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x95, 0x00, 0x86, 0x00, 0x77, 0x00,
+ 0x67, 0x00, 0x57, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2c, 0x00, 0x1f, 0x00,
+ 0x1b, 0x02, 0x16, 0x04, 0xbe, 0x00, 0xbd, 0x00, 0xb8, 0x00, 0xb1, 0x00,
+ 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6c, 0x00,
+ 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2d, 0x00,
+ 0x3d, 0x38, 0x38, 0x34, 0x35, 0x31, 0x33, 0x2f, 0x30, 0x2d, 0x2e, 0x2c,
+ 0x2d, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x27, 0x28, 0x27,
+ 0x28, 0x27, 0x27, 0x27, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25,
+ 0x25, 0x25, 0x25, 0x24, 0xd6, 0x00, 0xca, 0x00, 0xbe, 0x00, 0xb3, 0x00,
+ 0xaa, 0x00, 0xa0, 0x00, 0x98, 0x00, 0x90, 0x00, 0x88, 0x00, 0x82, 0x00,
+ 0x7d, 0x00, 0x77, 0x00, 0x71, 0x01, 0x6d, 0x01, 0x69, 0x02, 0x66, 0x02,
+ 0x63, 0x04, 0x60, 0x04, 0x5d, 0x04, 0x5b, 0x05, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x7c, 0x11, 0x76, 0x11, 0x70, 0x11, 0x6a, 0x11, 0x66, 0x11, 0x61, 0x11,
+ 0x5d, 0x11, 0x59, 0x11, 0x55, 0x11, 0x52, 0x11, 0x4f, 0x11, 0x4c, 0x11,
+ 0x49, 0x11, 0x47, 0x11, 0x45, 0x12, 0x44, 0x12, 0x42, 0x13, 0x41, 0x13,
+ 0x3f, 0x13, 0x3e, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31,
+ 0x00, 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f,
+ 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xb0, 0x00,
+ 0xa6, 0x00, 0x9a, 0x00, 0x8d, 0x00, 0x7f, 0x00, 0x70, 0x00, 0x61, 0x00,
+ 0x53, 0x00, 0x45, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x1b, 0x02,
+ 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3, 0x00, 0xab, 0x00, 0xa1, 0x00,
+ 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74, 0x00, 0x68, 0x00, 0x5d, 0x00,
+ 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x3d, 0x38, 0x39, 0x35,
+ 0x36, 0x32, 0x33, 0x30, 0x31, 0x2e, 0x30, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b,
+ 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27,
+ 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25,
+ 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb7, 0x00, 0xad, 0x00, 0xa5, 0x00,
+ 0x9d, 0x00, 0x96, 0x00, 0x8f, 0x00, 0x88, 0x00, 0x81, 0x00, 0x7d, 0x00,
+ 0x77, 0x00, 0x73, 0x01, 0x6f, 0x01, 0x6b, 0x02, 0x67, 0x02, 0x64, 0x02,
+ 0x62, 0x04, 0x5f, 0x04, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7c, 0x11, 0x77, 0x11,
+ 0x71, 0x11, 0x6c, 0x11, 0x67, 0x11, 0x63, 0x11, 0x5f, 0x11, 0x5c, 0x11,
+ 0x58, 0x11, 0x55, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4c, 0x11, 0x4a, 0x11,
+ 0x48, 0x11, 0x46, 0x12, 0x44, 0x12, 0x43, 0x12, 0x42, 0x13, 0x40, 0x13,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e,
+ 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28,
+ 0x00, 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xa9, 0x00, 0x9e, 0x00,
+ 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x5c, 0x00, 0x4f, 0x00,
+ 0x42, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0xbe, 0x00, 0xbd, 0x00,
+ 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x91, 0x00,
+ 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00,
+ 0x48, 0x00, 0x3f, 0x00, 0x3d, 0x39, 0x39, 0x36, 0x36, 0x33, 0x33, 0x30,
+ 0x32, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2a, 0x2c, 0x2b, 0x2b, 0x29,
+ 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27,
+ 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0xd7, 0x00, 0xcc, 0x00,
+ 0xc3, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa0, 0x00, 0x99, 0x00,
+ 0x93, 0x00, 0x8d, 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00,
+ 0x74, 0x00, 0x70, 0x01, 0x6c, 0x01, 0x69, 0x02, 0x66, 0x02, 0x63, 0x02,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x7c, 0x11, 0x77, 0x11, 0x72, 0x11, 0x6e, 0x11,
+ 0x69, 0x11, 0x65, 0x11, 0x61, 0x11, 0x5d, 0x11, 0x5a, 0x11, 0x57, 0x11,
+ 0x54, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x49, 0x11,
+ 0x47, 0x11, 0x45, 0x12, 0x44, 0x12, 0x42, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x39, 0x39, 0x36, 0x36, 0x33, 0x34, 0x32, 0x33, 0x30, 0x30, 0x2e,
+ 0x30, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28,
+ 0x29, 0x28, 0x28, 0x28, 0x28, 0x27, 0x29, 0x27, 0x27, 0x27, 0x27, 0x27,
+ 0x27, 0x27, 0x27, 0x25, 0xd7, 0x00, 0xce, 0x00, 0xc5, 0x00, 0xbc, 0x00,
+ 0xb4, 0x00, 0xac, 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x91, 0x00,
+ 0x8c, 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x75, 0x00,
+ 0x71, 0x01, 0x6d, 0x01, 0x6b, 0x02, 0x68, 0x02, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x7c, 0x11, 0x78, 0x11, 0x73, 0x11, 0x6f, 0x11, 0x6b, 0x11, 0x67, 0x11,
+ 0x63, 0x11, 0x60, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x57, 0x11, 0x54, 0x11,
+ 0x51, 0x11, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x49, 0x11, 0x47, 0x11,
+ 0x46, 0x12, 0x45, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x39, 0x3a, 0x36,
+ 0x37, 0x34, 0x35, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2d, 0x2e, 0x2d,
+ 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28,
+ 0x28, 0x28, 0x28, 0x27, 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27,
+ 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb6, 0x00, 0xaf, 0x00,
+ 0xa8, 0x00, 0xa1, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x90, 0x00, 0x8a, 0x00,
+ 0x86, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x75, 0x00, 0x72, 0x01,
+ 0x6f, 0x01, 0x6b, 0x01, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x78, 0x11,
+ 0x74, 0x11, 0x70, 0x11, 0x6c, 0x11, 0x68, 0x11, 0x65, 0x11, 0x61, 0x11,
+ 0x5f, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x56, 0x11, 0x54, 0x11, 0x51, 0x11,
+ 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x4a, 0x11, 0x48, 0x11, 0x46, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3a, 0x37, 0x38, 0x35, 0x36, 0x33,
+ 0x33, 0x31, 0x32, 0x30, 0x30, 0x2e, 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2b,
+ 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28,
+ 0x28, 0x27, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0xd8, 0x00, 0xd0, 0x00,
+ 0xc8, 0x00, 0xc0, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa5, 0x00,
+ 0x9f, 0x00, 0x99, 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8a, 0x00, 0x86, 0x00,
+ 0x81, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x76, 0x00, 0x73, 0x00, 0x70, 0x01,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x79, 0x11, 0x75, 0x11, 0x71, 0x11,
+ 0x6d, 0x11, 0x6a, 0x11, 0x66, 0x11, 0x63, 0x11, 0x60, 0x11, 0x5d, 0x11,
+ 0x5b, 0x11, 0x58, 0x11, 0x56, 0x11, 0x54, 0x11, 0x51, 0x11, 0x4f, 0x11,
+ 0x4d, 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x49, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x3a, 0x3a, 0x37, 0x38, 0x36, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30,
+ 0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2c, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x27, 0x29, 0x27, 0xd9, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc2, 0x00,
+ 0xbb, 0x00, 0xb4, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa2, 0x00, 0x9c, 0x00,
+ 0x97, 0x00, 0x92, 0x00, 0x8e, 0x00, 0x89, 0x00, 0x85, 0x00, 0x81, 0x00,
+ 0x7d, 0x00, 0x7a, 0x00, 0x76, 0x00, 0x73, 0x00, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x7d, 0x11, 0x79, 0x11, 0x75, 0x11, 0x72, 0x11, 0x6e, 0x11, 0x6b, 0x11,
+ 0x68, 0x11, 0x65, 0x11, 0x62, 0x11, 0x5f, 0x11, 0x5c, 0x11, 0x5a, 0x11,
+ 0x58, 0x11, 0x55, 0x11, 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11,
+ 0x4c, 0x11, 0x4a, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3b, 0x38,
+ 0x39, 0x36, 0x36, 0x33, 0x34, 0x33, 0x33, 0x30, 0x32, 0x30, 0x30, 0x2e,
+ 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27,
+ 0xd9, 0x00, 0xd1, 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbc, 0x00, 0xb6, 0x00,
+ 0xb0, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9a, 0x00, 0x96, 0x00,
+ 0x91, 0x00, 0x8d, 0x00, 0x89, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00,
+ 0x7a, 0x00, 0x77, 0x00, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x79, 0x11,
+ 0x76, 0x11, 0x72, 0x11, 0x6f, 0x11, 0x6c, 0x11, 0x69, 0x11, 0x66, 0x11,
+ 0x63, 0x11, 0x61, 0x11, 0x5e, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x57, 0x11,
+ 0x55, 0x11, 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11, 0x4c, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3b, 0x39, 0x39, 0x36, 0x36, 0x34,
+ 0x35, 0x33, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d,
+ 0x2d, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x29,
+ 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0xd9, 0x00, 0xd2, 0x00,
+ 0xcb, 0x00, 0xc4, 0x00, 0xbe, 0x00, 0xb8, 0x00, 0xb2, 0x00, 0xad, 0x00,
+ 0xa8, 0x00, 0xa2, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x94, 0x00, 0x90, 0x00,
+ 0x8b, 0x00, 0x88, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7b, 0x00,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x7a, 0x11, 0x76, 0x11, 0x73, 0x11,
+ 0x70, 0x11, 0x6d, 0x11, 0x6a, 0x11, 0x67, 0x11, 0x65, 0x11, 0x62, 0x11,
+ 0x5f, 0x11, 0x5d, 0x11, 0x5b, 0x11, 0x59, 0x11, 0x56, 0x11, 0x55, 0x11,
+ 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x3b, 0x3b, 0x39, 0x3a, 0x36, 0x36, 0x35, 0x36, 0x33, 0x33, 0x32,
+ 0x33, 0x30, 0x31, 0x30, 0x30, 0x2f, 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+ 0x2d, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x2b, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0xd9, 0x00, 0xd3, 0x00, 0xcc, 0x00, 0xc6, 0x00,
+ 0xc0, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa5, 0x00,
+ 0xa0, 0x00, 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x00, 0x8b, 0x00,
+ 0x88, 0x00, 0x83, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x7d, 0x11, 0x7a, 0x11, 0x77, 0x11, 0x74, 0x11, 0x71, 0x11, 0x6e, 0x11,
+ 0x6b, 0x11, 0x68, 0x11, 0x66, 0x11, 0x63, 0x11, 0x61, 0x11, 0x5e, 0x11,
+ 0x5c, 0x11, 0x5a, 0x11, 0x58, 0x11, 0x56, 0x11, 0x55, 0x11, 0x52, 0x11,
+ 0x51, 0x11, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3b, 0x3b, 0x39,
+ 0x39, 0x36, 0x37, 0x36, 0x36, 0x33, 0x34, 0x33, 0x33, 0x31, 0x32, 0x30,
+ 0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28,
+ 0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc7, 0x00, 0xc1, 0x00, 0xbc, 0x00,
+ 0xb7, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa7, 0x00, 0xa2, 0x00, 0x9e, 0x00,
+ 0x9a, 0x00, 0x95, 0x00, 0x93, 0x00, 0x8e, 0x00, 0x8b, 0x00, 0x87, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x7a, 0x11,
+ 0x77, 0x11, 0x74, 0x11, 0x71, 0x11, 0x6f, 0x11, 0x6c, 0x11, 0x69, 0x11,
+ 0x67, 0x11, 0x64, 0x11, 0x62, 0x11, 0x60, 0x11, 0x5e, 0x11, 0x5b, 0x11,
+ 0x5a, 0x11, 0x58, 0x11, 0x56, 0x11, 0x54, 0x11, 0x52, 0x11, 0x51, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0xb8, 0x00, 0xc5, 0x00, 0xcb, 0x00,
+ 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00,
+ 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9, 0x00,
+ 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x44, 0x00, 0x9d, 0x00, 0xbc, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xcf, 0x00,
+ 0xd2, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00,
+ 0xd7, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00,
+ 0xd9, 0x00, 0xd9, 0x00, 0x90, 0x00, 0xbd, 0x00, 0xcc, 0x00, 0xd1, 0x00,
+ 0xd5, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00,
+ 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00,
+ 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x68, 0x01, 0x8b, 0x00, 0xa0, 0x00, 0xad, 0x00, 0xb6, 0x00, 0xbc, 0x00,
+ 0xc1, 0x00, 0xc4, 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00,
+ 0xcd, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd2, 0x00,
+ 0xd2, 0x00, 0xd3, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x25, 0x05, 0x6b, 0x00,
+ 0x8e, 0x00, 0xa4, 0x00, 0xb0, 0x00, 0xb9, 0x00, 0xbe, 0x00, 0xc2, 0x00,
+ 0xc5, 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xce, 0x00,
+ 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00,
+ 0x81, 0x02, 0xa4, 0x00, 0xb5, 0x00, 0xc0, 0x00, 0xc6, 0x00, 0xcb, 0x00,
+ 0xcd, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00,
+ 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00,
+ 0xd7, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x09, 0x72, 0x02,
+ 0x87, 0x00, 0x96, 0x00, 0xa0, 0x00, 0xa9, 0x00, 0xb0, 0x00, 0xb5, 0x00,
+ 0xb9, 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc6, 0x00,
+ 0xc7, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x23, 0x0d, 0x51, 0x01, 0x73, 0x00, 0x89, 0x00,
+ 0x9a, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbb, 0x00,
+ 0xbe, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc8, 0x00,
+ 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0x80, 0x06, 0x97, 0x00,
+ 0xa8, 0x00, 0xb3, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc7, 0x00,
+ 0xca, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xd0, 0x00, 0xd1, 0x00,
+ 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4f, 0x11, 0x65, 0x07, 0x76, 0x03, 0x84, 0x01,
+ 0x8f, 0x00, 0x99, 0x00, 0xa1, 0x00, 0xa7, 0x00, 0xad, 0x00, 0xb1, 0x00,
+ 0xb4, 0x00, 0xb8, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc0, 0x00,
+ 0xc2, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x22, 0x12, 0x45, 0x04, 0x60, 0x00, 0x77, 0x00, 0x87, 0x00, 0x94, 0x00,
+ 0x9d, 0x00, 0xa4, 0x00, 0xaa, 0x00, 0xaf, 0x00, 0xb3, 0x00, 0xb7, 0x00,
+ 0xba, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc3, 0x00,
+ 0xc4, 0x00, 0xc6, 0x00, 0x7f, 0x09, 0x91, 0x02, 0x9e, 0x00, 0xaa, 0x00,
+ 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc6, 0x00,
+ 0xc8, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00,
+ 0xcf, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4b, 0x17, 0x5d, 0x0c, 0x6c, 0x06, 0x78, 0x03, 0x83, 0x01, 0x8c, 0x00,
+ 0x94, 0x00, 0x9b, 0x00, 0xa1, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xae, 0x00,
+ 0xb1, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd, 0x00,
+ 0xbe, 0x00, 0xbf, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x15, 0x3d, 0x08,
+ 0x55, 0x02, 0x67, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00, 0x98, 0x00,
+ 0x9f, 0x00, 0xa5, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xb1, 0x00, 0xb4, 0x00,
+ 0xb6, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00,
+ 0x7f, 0x0a, 0x8d, 0x04, 0x99, 0x01, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00,
+ 0xb6, 0x00, 0xba, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc3, 0x00, 0xc5, 0x00,
+ 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcc, 0x00,
+ 0xcd, 0x00, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x1c, 0x57, 0x11,
+ 0x64, 0x0a, 0x70, 0x06, 0x79, 0x03, 0x82, 0x02, 0x8a, 0x00, 0x91, 0x00,
+ 0x97, 0x00, 0x9c, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xad, 0x00,
+ 0xaf, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xba, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x17, 0x38, 0x0b, 0x4c, 0x04, 0x5e, 0x01,
+ 0x6c, 0x00, 0x7a, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x95, 0x00, 0x9b, 0x00,
+ 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00,
+ 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0x7f, 0x0b, 0x8a, 0x05,
+ 0x94, 0x02, 0x9d, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb5, 0x00,
+ 0xb9, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00,
+ 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x47, 0x20, 0x54, 0x15, 0x5f, 0x0e, 0x69, 0x09,
+ 0x72, 0x05, 0x7a, 0x03, 0x82, 0x02, 0x88, 0x01, 0x8f, 0x00, 0x94, 0x00,
+ 0x99, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa8, 0x00, 0xac, 0x00,
+ 0xae, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x22, 0x18, 0x35, 0x0d, 0x47, 0x06, 0x55, 0x03, 0x64, 0x01, 0x70, 0x00,
+ 0x7a, 0x00, 0x83, 0x00, 0x8b, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00,
+ 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00,
+ 0xb2, 0x00, 0xb4, 0x00, 0x7f, 0x0c, 0x89, 0x06, 0x92, 0x03, 0x99, 0x01,
+ 0xa0, 0x00, 0xa6, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb4, 0x00, 0xb7, 0x00,
+ 0xba, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00,
+ 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x46, 0x23, 0x50, 0x18, 0x5b, 0x11, 0x64, 0x0b, 0x6c, 0x08, 0x74, 0x05,
+ 0x7b, 0x03, 0x82, 0x02, 0x87, 0x01, 0x8c, 0x00, 0x91, 0x00, 0x95, 0x00,
+ 0x9a, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xab, 0x00,
+ 0xac, 0x00, 0xaf, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1a, 0x32, 0x0f,
+ 0x42, 0x08, 0x50, 0x04, 0x5c, 0x02, 0x68, 0x00, 0x72, 0x00, 0x7b, 0x00,
+ 0x83, 0x00, 0x8a, 0x00, 0x90, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9e, 0x00,
+ 0xa1, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00,
+ 0x7f, 0x0d, 0x88, 0x07, 0x8f, 0x04, 0x96, 0x02, 0x9c, 0x01, 0xa2, 0x00,
+ 0xa7, 0x00, 0xac, 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb9, 0x00,
+ 0xbb, 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00,
+ 0xc5, 0x00, 0xc6, 0x00, 0x2f, 0x00, 0x5f, 0x00, 0x99, 0x00, 0xac, 0x00,
+ 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00,
+ 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00,
+ 0x3b, 0x0b, 0x6f, 0x00, 0x9f, 0x00, 0xaf, 0x00, 0xb5, 0x00, 0xb9, 0x00,
+ 0xba, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00,
+ 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x6d, 0x00, 0x8d, 0x00, 0x9b, 0x00,
+ 0xa6, 0x00, 0xb2, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00,
+ 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00,
+ 0x47, 0x07, 0x7f, 0x00, 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba, 0x00,
+ 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00,
+ 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x45, 0x25, 0x4e, 0x1b,
+ 0x57, 0x13, 0x60, 0x0e, 0x68, 0x0a, 0x6f, 0x07, 0x76, 0x05, 0x7b, 0x03,
+ 0x82, 0x02, 0x86, 0x02, 0x8b, 0x01, 0x90, 0x00, 0x93, 0x00, 0x97, 0x00,
+ 0x9b, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa6, 0x00, 0xaa, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1b, 0x30, 0x11, 0x3e, 0x0a, 0x4b, 0x05,
+ 0x57, 0x03, 0x61, 0x01, 0x6b, 0x00, 0x73, 0x00, 0x7c, 0x00, 0x82, 0x00,
+ 0x88, 0x00, 0x8f, 0x00, 0x93, 0x00, 0x97, 0x00, 0x9c, 0x00, 0x9f, 0x00,
+ 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0x7f, 0x0d, 0x86, 0x08,
+ 0x8d, 0x05, 0x94, 0x02, 0x9a, 0x01, 0x9f, 0x00, 0xa4, 0x00, 0xa8, 0x00,
+ 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00,
+ 0xbc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00,
+ 0x00, 0x00, 0x0f, 0x00, 0x5f, 0x00, 0x8b, 0x00, 0x9f, 0x00, 0xaa, 0x00,
+ 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00,
+ 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x07, 0x17, 0x27, 0x02,
+ 0x6f, 0x00, 0x93, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb2, 0x00, 0xb5, 0x00,
+ 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00,
+ 0xbc, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6d, 0x00, 0x54, 0x00, 0x6b, 0x00, 0x87, 0x00, 0x98, 0x00, 0xa6, 0x00,
+ 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00,
+ 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x0f, 0x0f, 0x3f, 0x00,
+ 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7, 0x00,
+ 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00,
+ 0xbd, 0x00, 0xbd, 0x00, 0x45, 0x28, 0x4d, 0x1d, 0x55, 0x16, 0x5d, 0x11,
+ 0x64, 0x0c, 0x6b, 0x09, 0x71, 0x07, 0x77, 0x05, 0x7b, 0x03, 0x81, 0x02,
+ 0x85, 0x02, 0x8a, 0x01, 0x8e, 0x00, 0x92, 0x00, 0x95, 0x00, 0x98, 0x00,
+ 0x9d, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x21, 0x1b, 0x2f, 0x12, 0x3b, 0x0c, 0x47, 0x07, 0x51, 0x04, 0x5c, 0x02,
+ 0x65, 0x01, 0x6e, 0x00, 0x75, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00,
+ 0x8d, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9c, 0x00, 0xa0, 0x00,
+ 0xa2, 0x00, 0xa5, 0x00, 0x7f, 0x0d, 0x86, 0x09, 0x8c, 0x06, 0x92, 0x03,
+ 0x97, 0x02, 0x9c, 0x01, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xac, 0x00,
+ 0xaf, 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00,
+ 0xbc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x44, 0x00, 0x6d, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00,
+ 0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00,
+ 0xb6, 0x00, 0xb7, 0x00, 0x00, 0x2c, 0x02, 0x12, 0x22, 0x00, 0x58, 0x00,
+ 0x7a, 0x00, 0x8f, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xaa, 0x00, 0xae, 0x00,
+ 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x6b, 0x00,
+ 0x28, 0x00, 0x52, 0x00, 0x70, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00,
+ 0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00,
+ 0xb6, 0x00, 0xb7, 0x00, 0x00, 0x26, 0x05, 0x05, 0x3f, 0x00, 0x6d, 0x00,
+ 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00,
+ 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00,
+ 0x44, 0x2a, 0x4b, 0x20, 0x53, 0x18, 0x5a, 0x13, 0x61, 0x0f, 0x67, 0x0b,
+ 0x6d, 0x09, 0x73, 0x07, 0x77, 0x05, 0x7c, 0x03, 0x81, 0x02, 0x85, 0x02,
+ 0x88, 0x01, 0x8d, 0x01, 0x90, 0x00, 0x93, 0x00, 0x96, 0x00, 0x9a, 0x00,
+ 0x9d, 0x00, 0x9f, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1c, 0x2d, 0x13,
+ 0x39, 0x0d, 0x44, 0x09, 0x4e, 0x05, 0x57, 0x04, 0x60, 0x02, 0x67, 0x01,
+ 0x6f, 0x00, 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x87, 0x00, 0x8c, 0x00,
+ 0x90, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9d, 0x00, 0xa0, 0x00,
+ 0x7f, 0x0e, 0x85, 0x09, 0x8b, 0x06, 0x90, 0x04, 0x95, 0x02, 0x9a, 0x02,
+ 0x9e, 0x01, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xad, 0x00, 0xaf, 0x00,
+ 0xb2, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00,
+ 0xbd, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x33, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00,
+ 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00,
+ 0x00, 0x36, 0x00, 0x25, 0x09, 0x0b, 0x21, 0x00, 0x4a, 0x00, 0x68, 0x00,
+ 0x7d, 0x00, 0x8b, 0x00, 0x96, 0x00, 0x9d, 0x00, 0xa3, 0x00, 0xa8, 0x00,
+ 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x87, 0x00, 0x52, 0x00, 0x11, 0x00,
+ 0x39, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00,
+ 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00,
+ 0x00, 0x33, 0x00, 0x1c, 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a, 0x00,
+ 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac, 0x00,
+ 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0x43, 0x2b, 0x4a, 0x22,
+ 0x51, 0x1a, 0x57, 0x15, 0x5e, 0x11, 0x63, 0x0d, 0x69, 0x0a, 0x6e, 0x08,
+ 0x74, 0x06, 0x78, 0x05, 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x87, 0x02,
+ 0x8c, 0x01, 0x8f, 0x00, 0x92, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9b, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1c, 0x2d, 0x14, 0x37, 0x0e, 0x41, 0x0a,
+ 0x4a, 0x07, 0x53, 0x04, 0x5b, 0x02, 0x63, 0x01, 0x69, 0x00, 0x70, 0x00,
+ 0x77, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x87, 0x00, 0x8a, 0x00, 0x8f, 0x00,
+ 0x92, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x7f, 0x0e, 0x85, 0x0a,
+ 0x8a, 0x07, 0x8f, 0x05, 0x93, 0x03, 0x98, 0x02, 0x9c, 0x01, 0xa0, 0x00,
+ 0xa3, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2, 0x00,
+ 0xb3, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, 0x00,
+ 0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00,
+ 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x3a, 0x00, 0x2f,
+ 0x00, 0x16, 0x0e, 0x08, 0x20, 0x00, 0x42, 0x00, 0x5c, 0x00, 0x6f, 0x00,
+ 0x7e, 0x00, 0x89, 0x00, 0x92, 0x00, 0x99, 0x00, 0x9e, 0x00, 0xa2, 0x00,
+ 0xa6, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xa6, 0x00, 0x98, 0x00, 0x70, 0x00, 0x39, 0x00, 0x02, 0x00, 0x28, 0x00,
+ 0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00,
+ 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x38, 0x00, 0x2a,
+ 0x00, 0x09, 0x1d, 0x00, 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f, 0x00,
+ 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00,
+ 0xab, 0x00, 0xad, 0x00, 0x43, 0x2c, 0x49, 0x23, 0x50, 0x1c, 0x56, 0x17,
+ 0x5b, 0x12, 0x61, 0x0f, 0x66, 0x0c, 0x6b, 0x0a, 0x6f, 0x08, 0x75, 0x06,
+ 0x78, 0x05, 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x87, 0x02, 0x8b, 0x01,
+ 0x8e, 0x01, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x22, 0x1c, 0x2c, 0x15, 0x36, 0x0f, 0x3e, 0x0b, 0x48, 0x07, 0x50, 0x05,
+ 0x58, 0x04, 0x5f, 0x02, 0x66, 0x01, 0x6c, 0x00, 0x71, 0x00, 0x77, 0x00,
+ 0x7d, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00,
+ 0x94, 0x00, 0x97, 0x00, 0x7f, 0x0e, 0x84, 0x0a, 0x89, 0x07, 0x8d, 0x05,
+ 0x92, 0x03, 0x96, 0x02, 0x9a, 0x02, 0x9e, 0x01, 0xa1, 0x00, 0xa4, 0x00,
+ 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00,
+ 0xb5, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x3d, 0x00,
+ 0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00,
+ 0x93, 0x00, 0x98, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x02, 0x0e,
+ 0x12, 0x06, 0x20, 0x00, 0x3c, 0x00, 0x52, 0x00, 0x64, 0x00, 0x73, 0x00,
+ 0x7e, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x00, 0xa6, 0x00,
+ 0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00,
+ 0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00,
+ 0x93, 0x00, 0x98, 0x00, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x05, 0x00,
+ 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82, 0x00,
+ 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00,
+ 0x43, 0x2e, 0x48, 0x25, 0x4e, 0x1e, 0x54, 0x19, 0x59, 0x14, 0x5f, 0x11,
+ 0x63, 0x0e, 0x69, 0x0b, 0x6c, 0x09, 0x71, 0x07, 0x76, 0x06, 0x78, 0x05,
+ 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x86, 0x02, 0x8a, 0x01, 0x8e, 0x01,
+ 0x90, 0x00, 0x92, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1d, 0x2b, 0x16,
+ 0x34, 0x10, 0x3d, 0x0c, 0x45, 0x09, 0x4c, 0x06, 0x54, 0x04, 0x5b, 0x02,
+ 0x61, 0x02, 0x67, 0x01, 0x6d, 0x00, 0x73, 0x00, 0x78, 0x00, 0x7d, 0x00,
+ 0x81, 0x00, 0x86, 0x00, 0x89, 0x00, 0x8d, 0x00, 0x90, 0x00, 0x93, 0x00,
+ 0x7f, 0x0e, 0x84, 0x0b, 0x88, 0x08, 0x8d, 0x06, 0x91, 0x04, 0x94, 0x03,
+ 0x98, 0x02, 0x9c, 0x01, 0x9f, 0x01, 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00,
+ 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00,
+ 0xb6, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00,
+ 0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00,
+ 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x18, 0x07, 0x0c, 0x14, 0x05,
+ 0x20, 0x00, 0x37, 0x00, 0x4c, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x75, 0x00,
+ 0x7e, 0x00, 0x86, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00,
+ 0x48, 0x00, 0x21, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00,
+ 0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00,
+ 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x0f, 0x00, 0x29, 0x00,
+ 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84, 0x00,
+ 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b, 0x00, 0x42, 0x2f, 0x48, 0x26,
+ 0x4d, 0x20, 0x52, 0x1a, 0x58, 0x16, 0x5c, 0x12, 0x61, 0x0f, 0x66, 0x0c,
+ 0x6b, 0x0b, 0x6d, 0x09, 0x73, 0x07, 0x76, 0x06, 0x79, 0x05, 0x7d, 0x04,
+ 0x81, 0x03, 0x83, 0x02, 0x86, 0x02, 0x89, 0x02, 0x8d, 0x01, 0x8f, 0x01,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1d, 0x2a, 0x16, 0x33, 0x11, 0x3b, 0x0c,
+ 0x43, 0x0a, 0x4a, 0x07, 0x51, 0x05, 0x58, 0x04, 0x5e, 0x02, 0x64, 0x01,
+ 0x69, 0x01, 0x6f, 0x00, 0x74, 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00,
+ 0x85, 0x00, 0x89, 0x00, 0x8b, 0x00, 0x8f, 0x00, 0x7f, 0x0e, 0x83, 0x0b,
+ 0x88, 0x08, 0x8c, 0x06, 0x90, 0x05, 0x93, 0x03, 0x97, 0x02, 0x9a, 0x02,
+ 0x9d, 0x01, 0xa0, 0x00, 0xa3, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00,
+ 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00,
+ 0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x3d, 0x00, 0x3a,
+ 0x00, 0x2f, 0x00, 0x20, 0x00, 0x10, 0x0b, 0x0a, 0x16, 0x04, 0x20, 0x00,
+ 0x34, 0x00, 0x46, 0x00, 0x56, 0x00, 0x62, 0x00, 0x6d, 0x00, 0x77, 0x00,
+ 0x7f, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00,
+ 0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x3d, 0x00, 0x38,
+ 0x00, 0x2a, 0x00, 0x16, 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f, 0x00,
+ 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85, 0x00,
+ 0x8b, 0x00, 0x91, 0x00, 0x42, 0x30, 0x47, 0x28, 0x4c, 0x21, 0x51, 0x1c,
+ 0x56, 0x17, 0x5a, 0x14, 0x60, 0x11, 0x63, 0x0e, 0x68, 0x0c, 0x6c, 0x0a,
+ 0x6f, 0x08, 0x74, 0x07, 0x77, 0x06, 0x79, 0x05, 0x7d, 0x04, 0x81, 0x03,
+ 0x83, 0x02, 0x85, 0x02, 0x88, 0x02, 0x8c, 0x01, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x21, 0x1e, 0x2a, 0x17, 0x32, 0x12, 0x39, 0x0e, 0x40, 0x0a, 0x48, 0x07,
+ 0x4f, 0x05, 0x55, 0x04, 0x5a, 0x03, 0x60, 0x02, 0x66, 0x01, 0x6b, 0x00,
+ 0x70, 0x00, 0x75, 0x00, 0x79, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00,
+ 0x88, 0x00, 0x8b, 0x00, 0x7f, 0x0f, 0x83, 0x0b, 0x87, 0x09, 0x8b, 0x07,
+ 0x8e, 0x05, 0x92, 0x03, 0x96, 0x02, 0x99, 0x02, 0x9b, 0x01, 0x9e, 0x01,
+ 0xa1, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00,
+ 0xaf, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00,
+ 0x60, 0x00, 0x6a, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x33, 0x00, 0x27,
+ 0x00, 0x18, 0x04, 0x0d, 0x0e, 0x08, 0x17, 0x04, 0x20, 0x00, 0x32, 0x00,
+ 0x42, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x70, 0x00, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6, 0x00,
+ 0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00,
+ 0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00,
+ 0x60, 0x00, 0x6a, 0x00, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f,
+ 0x00, 0x0b, 0x08, 0x00, 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e, 0x00,
+ 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86, 0x00,
+ 0x42, 0x31, 0x47, 0x29, 0x4b, 0x22, 0x50, 0x1d, 0x55, 0x19, 0x58, 0x15,
+ 0x5e, 0x12, 0x61, 0x0f, 0x65, 0x0d, 0x6a, 0x0b, 0x6c, 0x09, 0x70, 0x08,
+ 0x75, 0x07, 0x77, 0x06, 0x79, 0x05, 0x7d, 0x04, 0x81, 0x03, 0x83, 0x02,
+ 0x85, 0x02, 0x87, 0x02, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x29, 0x18,
+ 0x31, 0x12, 0x38, 0x0f, 0x3f, 0x0c, 0x45, 0x09, 0x4c, 0x07, 0x52, 0x05,
+ 0x58, 0x04, 0x5d, 0x02, 0x63, 0x02, 0x67, 0x01, 0x6c, 0x00, 0x71, 0x00,
+ 0x75, 0x00, 0x79, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00,
+ 0x7f, 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8a, 0x07, 0x8e, 0x06, 0x91, 0x04,
+ 0x94, 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d, 0x01, 0xa0, 0x01, 0xa2, 0x00,
+ 0xa4, 0x00, 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00,
+ 0xb0, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00,
+ 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x12,
+ 0x07, 0x0c, 0x10, 0x07, 0x18, 0x03, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00,
+ 0x4c, 0x00, 0x57, 0x00, 0x61, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00,
+ 0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00,
+ 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02,
+ 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58, 0x00,
+ 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x42, 0x31, 0x46, 0x2a,
+ 0x4a, 0x24, 0x4f, 0x1f, 0x53, 0x1a, 0x58, 0x16, 0x5c, 0x13, 0x60, 0x11,
+ 0x63, 0x0e, 0x67, 0x0c, 0x6b, 0x0b, 0x6d, 0x09, 0x72, 0x07, 0x75, 0x07,
+ 0x77, 0x06, 0x79, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x29, 0x18, 0x30, 0x13, 0x37, 0x0f,
+ 0x3d, 0x0c, 0x44, 0x0a, 0x4a, 0x07, 0x50, 0x05, 0x55, 0x04, 0x5b, 0x04,
+ 0x60, 0x02, 0x64, 0x01, 0x69, 0x01, 0x6d, 0x00, 0x72, 0x00, 0x76, 0x00,
+ 0x7a, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x83, 0x00, 0x7f, 0x0f, 0x83, 0x0c,
+ 0x86, 0x09, 0x8a, 0x07, 0x8d, 0x06, 0x90, 0x05, 0x93, 0x03, 0x96, 0x02,
+ 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0, 0x00, 0xa3, 0x00, 0xa5, 0x00,
+ 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x3e, 0x00, 0x3c,
+ 0x00, 0x37, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x02, 0x0e, 0x0a, 0x0a,
+ 0x11, 0x06, 0x19, 0x03, 0x1f, 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00,
+ 0x53, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00,
+ 0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x3e, 0x00, 0x3c,
+ 0x00, 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x04, 0x00, 0x14, 0x00,
+ 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60, 0x00,
+ 0x68, 0x00, 0x70, 0x00, 0x42, 0x32, 0x46, 0x2b, 0x49, 0x25, 0x4f, 0x1f,
+ 0x52, 0x1b, 0x57, 0x18, 0x59, 0x14, 0x5f, 0x12, 0x62, 0x0f, 0x65, 0x0d,
+ 0x6a, 0x0c, 0x6c, 0x0a, 0x6e, 0x09, 0x73, 0x07, 0x76, 0x06, 0x78, 0x06,
+ 0x7a, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x21, 0x1e, 0x28, 0x19, 0x2f, 0x14, 0x35, 0x0f, 0x3c, 0x0c, 0x42, 0x0a,
+ 0x48, 0x07, 0x4e, 0x06, 0x53, 0x05, 0x58, 0x04, 0x5d, 0x02, 0x62, 0x02,
+ 0x66, 0x01, 0x6b, 0x01, 0x6f, 0x00, 0x73, 0x00, 0x76, 0x00, 0x7a, 0x00,
+ 0x7d, 0x00, 0x81, 0x00, 0x7f, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x07,
+ 0x8c, 0x06, 0x8f, 0x05, 0x92, 0x03, 0x95, 0x03, 0x98, 0x02, 0x9a, 0x02,
+ 0x9d, 0x01, 0x9f, 0x01, 0xa1, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00,
+ 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2d, 0x00, 0x39, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x31,
+ 0x00, 0x28, 0x00, 0x1e, 0x00, 0x13, 0x05, 0x0d, 0x0c, 0x09, 0x13, 0x06,
+ 0x19, 0x03, 0x1f, 0x00, 0x2d, 0x00, 0x3a, 0x00, 0x45, 0x00, 0x4f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00,
+ 0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00,
+ 0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2d, 0x00, 0x39, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d,
+ 0x00, 0x21, 0x00, 0x13, 0x00, 0x04, 0x0a, 0x00, 0x18, 0x00, 0x26, 0x00,
+ 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65, 0x00,
+ 0x42, 0x33, 0x45, 0x2c, 0x48, 0x26, 0x4e, 0x21, 0x50, 0x1c, 0x56, 0x19,
+ 0x58, 0x16, 0x5c, 0x13, 0x60, 0x11, 0x62, 0x0e, 0x67, 0x0c, 0x6a, 0x0b,
+ 0x6d, 0x0a, 0x70, 0x09, 0x74, 0x07, 0x76, 0x06, 0x78, 0x06, 0x7a, 0x05,
+ 0x7e, 0x04, 0x81, 0x03, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x28, 0x19,
+ 0x2f, 0x15, 0x35, 0x11, 0x3b, 0x0d, 0x41, 0x0b, 0x46, 0x09, 0x4c, 0x07,
+ 0x51, 0x05, 0x55, 0x04, 0x5b, 0x04, 0x5f, 0x02, 0x63, 0x02, 0x68, 0x01,
+ 0x6b, 0x00, 0x70, 0x00, 0x73, 0x00, 0x77, 0x00, 0x7b, 0x00, 0x7d, 0x00,
+ 0x7f, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x08, 0x8c, 0x06, 0x8f, 0x05,
+ 0x91, 0x04, 0x94, 0x03, 0x97, 0x02, 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01,
+ 0xa0, 0x01, 0xa2, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00,
+ 0xac, 0x00, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00,
+ 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x33, 0x00, 0x2c, 0x00, 0x23,
+ 0x00, 0x19, 0x00, 0x0f, 0x07, 0x0c, 0x0e, 0x08, 0x14, 0x05, 0x1a, 0x02,
+ 0x1f, 0x00, 0x2c, 0x00, 0x38, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00,
+ 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00,
+ 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19,
+ 0x00, 0x0c, 0x01, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34, 0x00,
+ 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b, 0x00, 0x5d, 0x1a, 0x6d, 0x16,
+ 0x72, 0x15, 0x75, 0x14, 0x77, 0x13, 0x78, 0x13, 0x79, 0x13, 0x7a, 0x12,
+ 0x7a, 0x12, 0x7b, 0x12, 0x7b, 0x12, 0x7b, 0x12, 0x7c, 0x12, 0x7c, 0x11,
+ 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7d, 0x11,
+ 0xbd, 0x02, 0xa4, 0x06, 0x97, 0x09, 0x91, 0x0a, 0x8d, 0x0b, 0x8a, 0x0c,
+ 0x89, 0x0d, 0x88, 0x0d, 0x86, 0x0d, 0x86, 0x0e, 0x85, 0x0e, 0x85, 0x0e,
+ 0x84, 0x0e, 0x84, 0x0e, 0x83, 0x0f, 0x83, 0x0f, 0x83, 0x0f, 0x83, 0x0f,
+ 0x82, 0x0f, 0x82, 0x0f, 0x33, 0x11, 0x5f, 0x11, 0x6f, 0x11, 0x74, 0x11,
+ 0x77, 0x11, 0x78, 0x11, 0x7a, 0x11, 0x7a, 0x11, 0x7b, 0x11, 0x7b, 0x11,
+ 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7d, 0x11, 0x7d, 0x11,
+ 0x7d, 0x11, 0x7d, 0x11, 0x7d, 0x11, 0x7d, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x3f, 0x00, 0x3e,
+ 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1d, 0x00, 0x14,
+ 0x03, 0x0e, 0x09, 0x0b, 0x0f, 0x08, 0x15, 0x05, 0x1a, 0x02, 0x1f, 0x00,
+ 0x2b, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00,
+ 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x3f, 0x00, 0x3d,
+ 0x00, 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06,
+ 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f, 0x00,
+ 0x49, 0x00, 0x51, 0x00, 0x50, 0x24, 0x5f, 0x1f, 0x66, 0x1b, 0x6b, 0x19,
+ 0x6e, 0x18, 0x70, 0x17, 0x73, 0x16, 0x73, 0x15, 0x75, 0x15, 0x76, 0x15,
+ 0x76, 0x15, 0x77, 0x14, 0x77, 0x14, 0x78, 0x13, 0x78, 0x13, 0x79, 0x13,
+ 0x79, 0x13, 0x7a, 0x13, 0x7a, 0x13, 0x7b, 0x13, 0xcc, 0x00, 0xb5, 0x00,
+ 0xa8, 0x02, 0x9e, 0x04, 0x99, 0x05, 0x94, 0x06, 0x92, 0x07, 0x8f, 0x08,
+ 0x8d, 0x09, 0x8c, 0x09, 0x8b, 0x0a, 0x8a, 0x0a, 0x89, 0x0b, 0x88, 0x0b,
+ 0x88, 0x0b, 0x87, 0x0c, 0x87, 0x0c, 0x86, 0x0c, 0x86, 0x0c, 0x86, 0x0c,
+ 0x23, 0x13, 0x46, 0x11, 0x58, 0x11, 0x63, 0x11, 0x69, 0x11, 0x6d, 0x11,
+ 0x70, 0x11, 0x72, 0x11, 0x73, 0x11, 0x75, 0x11, 0x76, 0x11, 0x77, 0x11,
+ 0x77, 0x11, 0x78, 0x11, 0x78, 0x11, 0x79, 0x11, 0x79, 0x11, 0x79, 0x11,
+ 0x7a, 0x11, 0x7a, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36,
+ 0x00, 0x30, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00, 0x10, 0x05, 0x0d,
+ 0x0b, 0x0a, 0x10, 0x07, 0x16, 0x04, 0x1b, 0x02, 0x1f, 0x00, 0x2a, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00,
+ 0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00,
+ 0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33,
+ 0x00, 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00,
+ 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x00,
+ 0x4a, 0x2a, 0x57, 0x24, 0x5f, 0x20, 0x64, 0x1e, 0x68, 0x1c, 0x6a, 0x1b,
+ 0x6d, 0x19, 0x6e, 0x18, 0x70, 0x18, 0x72, 0x17, 0x72, 0x17, 0x73, 0x16,
+ 0x74, 0x15, 0x75, 0x15, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15,
+ 0x76, 0x15, 0x77, 0x14, 0xd1, 0x00, 0xc0, 0x00, 0xb3, 0x00, 0xaa, 0x01,
+ 0xa2, 0x02, 0x9d, 0x03, 0x99, 0x04, 0x96, 0x05, 0x94, 0x06, 0x92, 0x06,
+ 0x90, 0x07, 0x8f, 0x07, 0x8d, 0x08, 0x8d, 0x08, 0x8c, 0x09, 0x8b, 0x09,
+ 0x8a, 0x09, 0x8a, 0x0a, 0x89, 0x0a, 0x89, 0x0b, 0x22, 0x17, 0x39, 0x11,
+ 0x4a, 0x11, 0x55, 0x11, 0x5e, 0x11, 0x63, 0x11, 0x67, 0x11, 0x6a, 0x11,
+ 0x6c, 0x11, 0x6e, 0x11, 0x70, 0x11, 0x71, 0x11, 0x72, 0x11, 0x73, 0x11,
+ 0x74, 0x11, 0x75, 0x11, 0x75, 0x11, 0x76, 0x11, 0x76, 0x11, 0x77, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00, 0x32, 0x00, 0x2c,
+ 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x01, 0x0e, 0x07, 0x0c, 0x0c, 0x09,
+ 0x11, 0x06, 0x16, 0x04, 0x1b, 0x02, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00,
+ 0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00,
+ 0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25,
+ 0x00, 0x1c, 0x00, 0x11, 0x00, 0x07, 0x03, 0x00, 0x0e, 0x00, 0x19, 0x00,
+ 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x2e, 0x53, 0x28,
+ 0x5a, 0x24, 0x5f, 0x22, 0x63, 0x1f, 0x66, 0x1e, 0x69, 0x1c, 0x6a, 0x1b,
+ 0x6c, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x70, 0x18, 0x71, 0x18, 0x72, 0x18,
+ 0x72, 0x17, 0x72, 0x17, 0x73, 0x16, 0x74, 0x15, 0x75, 0x15, 0x76, 0x15,
+ 0xd5, 0x00, 0xc6, 0x00, 0xbb, 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x01,
+ 0xa0, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x97, 0x04, 0x95, 0x05, 0x93, 0x05,
+ 0x92, 0x06, 0x91, 0x06, 0x90, 0x07, 0x8e, 0x07, 0x8e, 0x07, 0x8d, 0x07,
+ 0x8c, 0x08, 0x8c, 0x09, 0x22, 0x1a, 0x33, 0x13, 0x41, 0x11, 0x4c, 0x11,
+ 0x54, 0x11, 0x5b, 0x11, 0x5f, 0x11, 0x63, 0x11, 0x66, 0x11, 0x68, 0x11,
+ 0x6a, 0x11, 0x6c, 0x11, 0x6e, 0x11, 0x6f, 0x11, 0x70, 0x11, 0x71, 0x11,
+ 0x72, 0x11, 0x72, 0x11, 0x73, 0x11, 0x74, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x07, 0x7f, 0x00,
+ 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00,
+ 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00,
+ 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x47, 0x07, 0x0f, 0x0f, 0x00, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a,
+ 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
+ 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x46, 0x31, 0x50, 0x2b, 0x56, 0x27, 0x5b, 0x24,
+ 0x5f, 0x22, 0x62, 0x20, 0x65, 0x1f, 0x67, 0x1d, 0x69, 0x1d, 0x6a, 0x1b,
+ 0x6c, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x6f, 0x18, 0x71, 0x18,
+ 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x72, 0x17, 0xd6, 0x00, 0xcb, 0x00,
+ 0xc0, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xab, 0x00, 0xa6, 0x01, 0xa2, 0x01,
+ 0x9f, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x98, 0x03, 0x96, 0x04, 0x94, 0x05,
+ 0x93, 0x05, 0x92, 0x06, 0x91, 0x06, 0x90, 0x06, 0x8f, 0x06, 0x8f, 0x07,
+ 0x22, 0x1b, 0x2f, 0x15, 0x3b, 0x12, 0x44, 0x11, 0x4d, 0x11, 0x53, 0x11,
+ 0x59, 0x11, 0x5d, 0x11, 0x60, 0x11, 0x63, 0x11, 0x66, 0x11, 0x67, 0x11,
+ 0x69, 0x11, 0x6b, 0x11, 0x6c, 0x11, 0x6d, 0x11, 0x6e, 0x11, 0x6f, 0x11,
+ 0x70, 0x11, 0x71, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x3f, 0x00, 0x7f, 0x00, 0x9c, 0x00,
+ 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba, 0x00,
+ 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x3f, 0x00,
+ 0x05, 0x05, 0x00, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38,
+ 0x00, 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d,
+ 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x33, 0x4d, 0x2e, 0x53, 0x29, 0x58, 0x26, 0x5c, 0x24, 0x5f, 0x22,
+ 0x61, 0x21, 0x65, 0x20, 0x65, 0x1e, 0x68, 0x1d, 0x69, 0x1d, 0x6a, 0x1b,
+ 0x6b, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x6f, 0x18,
+ 0x71, 0x18, 0x72, 0x18, 0xd7, 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbd, 0x00,
+ 0xb6, 0x00, 0xb0, 0x00, 0xab, 0x00, 0xa7, 0x00, 0xa4, 0x01, 0xa1, 0x02,
+ 0x9e, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x98, 0x03, 0x97, 0x03, 0x96, 0x04,
+ 0x94, 0x05, 0x93, 0x05, 0x92, 0x05, 0x91, 0x06, 0x21, 0x1c, 0x2d, 0x16,
+ 0x37, 0x13, 0x40, 0x11, 0x47, 0x11, 0x4e, 0x11, 0x53, 0x11, 0x57, 0x11,
+ 0x5b, 0x11, 0x5e, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x67, 0x11,
+ 0x68, 0x11, 0x6a, 0x11, 0x6b, 0x11, 0x6c, 0x11, 0x6d, 0x11, 0x6e, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x26, 0x05, 0x05, 0x3f, 0x00, 0x6d, 0x00, 0x88, 0x00, 0x99, 0x00,
+ 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00,
+ 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12, 0x00,
+ 0x00, 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32,
+ 0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x34, 0x4c, 0x2f,
+ 0x51, 0x2c, 0x56, 0x28, 0x5a, 0x26, 0x5c, 0x24, 0x60, 0x23, 0x61, 0x21,
+ 0x64, 0x20, 0x65, 0x1f, 0x66, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c,
+ 0x6b, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19,
+ 0xd8, 0x00, 0xcf, 0x00, 0xc7, 0x00, 0xc0, 0x00, 0xba, 0x00, 0xb5, 0x00,
+ 0xb0, 0x00, 0xac, 0x00, 0xa8, 0x00, 0xa5, 0x01, 0xa2, 0x01, 0xa0, 0x02,
+ 0x9e, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99, 0x03, 0x97, 0x03, 0x96, 0x03,
+ 0x95, 0x04, 0x94, 0x05, 0x22, 0x1d, 0x2b, 0x17, 0x34, 0x14, 0x3b, 0x12,
+ 0x43, 0x11, 0x49, 0x11, 0x4e, 0x11, 0x52, 0x11, 0x56, 0x11, 0x5a, 0x11,
+ 0x5d, 0x11, 0x5f, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11,
+ 0x68, 0x11, 0x69, 0x11, 0x6a, 0x11, 0x6b, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1c,
+ 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a, 0x00, 0x8a, 0x00, 0x96, 0x00,
+ 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb1, 0x00,
+ 0xb3, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05, 0x00,
+ 0x00, 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d,
+ 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x36, 0x4a, 0x31, 0x50, 0x2d, 0x54, 0x2a,
+ 0x57, 0x28, 0x5b, 0x26, 0x5c, 0x24, 0x60, 0x23, 0x61, 0x21, 0x63, 0x20,
+ 0x65, 0x20, 0x65, 0x1e, 0x67, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c,
+ 0x6a, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0xd9, 0x00, 0xd1, 0x00,
+ 0xca, 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb4, 0x00, 0xb0, 0x00,
+ 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0x9f, 0x02,
+ 0x9d, 0x02, 0x9b, 0x02, 0x9a, 0x02, 0x99, 0x03, 0x98, 0x03, 0x97, 0x03,
+ 0x21, 0x1e, 0x2a, 0x18, 0x32, 0x15, 0x39, 0x13, 0x3f, 0x12, 0x45, 0x11,
+ 0x4a, 0x11, 0x4e, 0x11, 0x52, 0x11, 0x56, 0x11, 0x59, 0x11, 0x5c, 0x11,
+ 0x5d, 0x11, 0x60, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11,
+ 0x67, 0x11, 0x68, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x09, 0x1d, 0x00,
+ 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f, 0x00, 0x8b, 0x00, 0x94, 0x00,
+ 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xad, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa, 0x00,
+ 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29,
+ 0x00, 0x2b, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x43, 0x36, 0x49, 0x32, 0x4e, 0x2f, 0x52, 0x2c, 0x56, 0x29, 0x58, 0x27,
+ 0x5b, 0x26, 0x5d, 0x24, 0x60, 0x23, 0x60, 0x22, 0x62, 0x20, 0x65, 0x20,
+ 0x65, 0x1f, 0x66, 0x1e, 0x68, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c,
+ 0x6a, 0x1b, 0x6c, 0x1a, 0xd9, 0x00, 0xd2, 0x00, 0xcc, 0x00, 0xc6, 0x00,
+ 0xc1, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xb3, 0x00, 0xaf, 0x00, 0xac, 0x00,
+ 0xa9, 0x00, 0xa6, 0x00, 0xa4, 0x01, 0xa2, 0x01, 0xa0, 0x01, 0x9e, 0x02,
+ 0x9d, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99, 0x02, 0x22, 0x1e, 0x29, 0x19,
+ 0x30, 0x16, 0x36, 0x13, 0x3c, 0x12, 0x41, 0x11, 0x46, 0x11, 0x4a, 0x11,
+ 0x4f, 0x11, 0x52, 0x11, 0x55, 0x11, 0x58, 0x11, 0x5a, 0x11, 0x5c, 0x11,
+ 0x5f, 0x11, 0x60, 0x11, 0x62, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x05, 0x00, 0x24, 0x00, 0x3f, 0x00,
+ 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82, 0x00, 0x8b, 0x00, 0x93, 0x00,
+ 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a, 0x00,
+ 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16, 0x00, 0x08, 0x00, 0x00, 0x02,
+ 0x00, 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x37, 0x48, 0x33,
+ 0x4d, 0x30, 0x51, 0x2d, 0x54, 0x2a, 0x57, 0x29, 0x59, 0x27, 0x5c, 0x26,
+ 0x5d, 0x24, 0x60, 0x23, 0x60, 0x22, 0x62, 0x20, 0x65, 0x20, 0x65, 0x20,
+ 0x65, 0x1f, 0x66, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1d,
+ 0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc8, 0x00, 0xc3, 0x00, 0xbe, 0x00,
+ 0xba, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00,
+ 0xa7, 0x00, 0xa5, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0xa0, 0x02, 0x9e, 0x02,
+ 0x9d, 0x02, 0x9c, 0x02, 0x21, 0x1e, 0x28, 0x1a, 0x2e, 0x17, 0x34, 0x14,
+ 0x39, 0x13, 0x3f, 0x12, 0x43, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4f, 0x11,
+ 0x52, 0x11, 0x55, 0x11, 0x57, 0x11, 0x59, 0x11, 0x5c, 0x11, 0x5d, 0x11,
+ 0x5f, 0x11, 0x61, 0x11, 0x62, 0x11, 0x63, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35,
+ 0x00, 0x23, 0x00, 0x0b, 0x0f, 0x00, 0x29, 0x00, 0x3f, 0x00, 0x53, 0x00,
+ 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x92, 0x00,
+ 0x97, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56, 0x00,
+ 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x04,
+ 0x00, 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x43, 0x38, 0x48, 0x34, 0x4c, 0x31, 0x4f, 0x2e,
+ 0x53, 0x2c, 0x56, 0x2a, 0x57, 0x28, 0x5a, 0x27, 0x5c, 0x26, 0x5d, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x61, 0x21, 0x64, 0x20, 0x65, 0x20, 0x65, 0x20,
+ 0x65, 0x1e, 0x67, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0xd9, 0x00, 0xd4, 0x00,
+ 0xce, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xc1, 0x00, 0xbd, 0x00, 0xb9, 0x00,
+ 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa8, 0x00,
+ 0xa6, 0x00, 0xa4, 0x01, 0xa2, 0x01, 0xa0, 0x01, 0x9f, 0x02, 0x9e, 0x02,
+ 0x22, 0x1f, 0x27, 0x1a, 0x2d, 0x17, 0x33, 0x15, 0x38, 0x13, 0x3c, 0x13,
+ 0x41, 0x12, 0x44, 0x11, 0x48, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11,
+ 0x54, 0x11, 0x57, 0x11, 0x59, 0x11, 0x5b, 0x11, 0x5c, 0x11, 0x5e, 0x11,
+ 0x5f, 0x11, 0x61, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x16,
+ 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f, 0x00, 0x50, 0x00, 0x5e, 0x00,
+ 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x91, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb7, 0x00,
+ 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f, 0x00,
+ 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06,
+ 0x00, 0x0c, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x43, 0x38, 0x47, 0x35, 0x4b, 0x32, 0x4e, 0x2f, 0x52, 0x2d, 0x53, 0x2b,
+ 0x57, 0x2a, 0x58, 0x27, 0x5b, 0x27, 0x5c, 0x25, 0x5d, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x61, 0x21, 0x64, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x1f,
+ 0x66, 0x1e, 0x68, 0x1d, 0xda, 0x00, 0xd4, 0x00, 0xd0, 0x00, 0xcb, 0x00,
+ 0xc7, 0x00, 0xc2, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb5, 0x00,
+ 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa8, 0x00, 0xa6, 0x00,
+ 0xa4, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0xa0, 0x01, 0x21, 0x1f, 0x27, 0x1b,
+ 0x2c, 0x18, 0x31, 0x16, 0x36, 0x14, 0x3a, 0x13, 0x3e, 0x12, 0x42, 0x11,
+ 0x45, 0x11, 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11,
+ 0x56, 0x11, 0x58, 0x11, 0x5a, 0x11, 0x5c, 0x11, 0x5d, 0x11, 0x5e, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x0b, 0x08, 0x00,
+ 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x66, 0x00,
+ 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00,
+ 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30, 0x00,
+ 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x46, 0x35,
+ 0x4a, 0x32, 0x4e, 0x30, 0x50, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x29,
+ 0x58, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5d, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x22, 0x63, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x1f,
+ 0xda, 0x00, 0xd5, 0x00, 0xd1, 0x00, 0xcc, 0x00, 0xc8, 0x00, 0xc4, 0x00,
+ 0xc1, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb7, 0x00, 0xb4, 0x00, 0xb2, 0x00,
+ 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa9, 0x00, 0xa7, 0x00, 0xa5, 0x00,
+ 0xa4, 0x01, 0xa2, 0x01, 0x22, 0x1f, 0x27, 0x1b, 0x2c, 0x18, 0x30, 0x16,
+ 0x35, 0x14, 0x39, 0x13, 0x3d, 0x13, 0x40, 0x12, 0x44, 0x11, 0x47, 0x11,
+ 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11, 0x56, 0x11,
+ 0x58, 0x11, 0x59, 0x11, 0x5b, 0x11, 0x5c, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b,
+ 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02, 0x0f, 0x00, 0x20, 0x00,
+ 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58, 0x00, 0x63, 0x00, 0x6c, 0x00,
+ 0x74, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82, 0x00,
+ 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26, 0x00,
+ 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x46, 0x36, 0x4a, 0x33, 0x4d, 0x31,
+ 0x4f, 0x2e, 0x52, 0x2d, 0x53, 0x2b, 0x57, 0x2a, 0x57, 0x28, 0x5a, 0x27,
+ 0x5c, 0x27, 0x5c, 0x25, 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22,
+ 0x62, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0xda, 0x00, 0xd6, 0x00,
+ 0xd1, 0x00, 0xcd, 0x00, 0xc9, 0x00, 0xc6, 0x00, 0xc2, 0x00, 0xbf, 0x00,
+ 0xbc, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00,
+ 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa7, 0x00, 0xa6, 0x00, 0xa4, 0x00,
+ 0x21, 0x1f, 0x26, 0x1c, 0x2b, 0x19, 0x2f, 0x17, 0x33, 0x15, 0x37, 0x14,
+ 0x3b, 0x13, 0x3e, 0x12, 0x41, 0x12, 0x44, 0x11, 0x47, 0x11, 0x4a, 0x11,
+ 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11, 0x55, 0x11, 0x57, 0x11,
+ 0x59, 0x11, 0x5a, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x29,
+ 0x00, 0x1b, 0x00, 0x0c, 0x04, 0x00, 0x14, 0x00, 0x23, 0x00, 0x32, 0x00,
+ 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00,
+ 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b, 0x00,
+ 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f, 0x00,
+ 0x16, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x39, 0x45, 0x36, 0x49, 0x34, 0x4c, 0x31, 0x4f, 0x30, 0x51, 0x2e,
+ 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a, 0x57, 0x28, 0x5b, 0x27, 0x5c, 0x27,
+ 0x5c, 0x25, 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22, 0x61, 0x21,
+ 0x64, 0x20, 0x65, 0x20, 0xda, 0x00, 0xd6, 0x00, 0xd2, 0x00, 0xce, 0x00,
+ 0xcb, 0x00, 0xc7, 0x00, 0xc4, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00,
+ 0xb8, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00,
+ 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x00, 0xa6, 0x00, 0x22, 0x1f, 0x26, 0x1c,
+ 0x2a, 0x19, 0x2e, 0x17, 0x32, 0x16, 0x36, 0x14, 0x39, 0x13, 0x3d, 0x13,
+ 0x40, 0x12, 0x43, 0x11, 0x45, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4d, 0x11,
+ 0x4f, 0x11, 0x51, 0x11, 0x53, 0x11, 0x55, 0x11, 0x56, 0x11, 0x58, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x21, 0x00, 0x13,
+ 0x00, 0x04, 0x0a, 0x00, 0x18, 0x00, 0x26, 0x00, 0x33, 0x00, 0x3f, 0x00,
+ 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac, 0x00,
+ 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58, 0x00,
+ 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3a, 0x45, 0x37,
+ 0x48, 0x35, 0x4a, 0x32, 0x4e, 0x31, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2b,
+ 0x57, 0x2a, 0x57, 0x29, 0x58, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x25,
+ 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x61, 0x21, 0x64, 0x20,
+ 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xc8, 0x00,
+ 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc, 0x00, 0xba, 0x00, 0xb7, 0x00,
+ 0xb5, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00,
+ 0xa9, 0x00, 0xa8, 0x00, 0x21, 0x20, 0x26, 0x1c, 0x2a, 0x1a, 0x2d, 0x18,
+ 0x31, 0x16, 0x35, 0x14, 0x38, 0x13, 0x3b, 0x13, 0x3e, 0x12, 0x41, 0x12,
+ 0x44, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11,
+ 0x51, 0x11, 0x53, 0x11, 0x55, 0x11, 0x56, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d,
+ 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x01, 0x00,
+ 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34, 0x00, 0x3f, 0x00, 0x49, 0x00,
+ 0x53, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00,
+ 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a, 0x00,
+ 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3a, 0x45, 0x37, 0x48, 0x35, 0x4a, 0x33,
+ 0x4d, 0x31, 0x4f, 0x2f, 0x52, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a,
+ 0x57, 0x29, 0x59, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5f, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22, 0xdb, 0x00, 0xd7, 0x00,
+ 0xd3, 0x00, 0xd0, 0x00, 0xcc, 0x00, 0xc9, 0x00, 0xc6, 0x00, 0xc3, 0x00,
+ 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb9, 0x00, 0xb7, 0x00, 0xb5, 0x00,
+ 0xb3, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xaa, 0x00,
+ 0x21, 0x20, 0x25, 0x1d, 0x29, 0x1a, 0x2d, 0x18, 0x30, 0x17, 0x33, 0x15,
+ 0x37, 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f, 0x12, 0x42, 0x12, 0x44, 0x11,
+ 0x47, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x11,
+ 0x53, 0x11, 0x55, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32,
+ 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06, 0x06, 0x00, 0x13, 0x00,
+ 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x51, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00,
+ 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85, 0x00,
+ 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f, 0x00,
+ 0x36, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3a, 0x45, 0x38, 0x47, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x30,
+ 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2b, 0x56, 0x2a, 0x57, 0x2a, 0x57, 0x28,
+ 0x5a, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5f, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0xdb, 0x00, 0xd7, 0x00, 0xd4, 0x00, 0xd0, 0x00,
+ 0xcd, 0x00, 0xca, 0x00, 0xc7, 0x00, 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00,
+ 0xbd, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4, 0x00, 0xb2, 0x00,
+ 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xac, 0x00, 0x21, 0x20, 0x25, 0x1d,
+ 0x29, 0x1a, 0x2c, 0x18, 0x2f, 0x17, 0x33, 0x16, 0x36, 0x14, 0x39, 0x13,
+ 0x3b, 0x13, 0x3e, 0x13, 0x41, 0x12, 0x43, 0x11, 0x45, 0x11, 0x47, 0x11,
+ 0x4a, 0x11, 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x52, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x22,
+ 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x21, 0x00,
+ 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3, 0x00,
+ 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74, 0x00,
+ 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39,
+ 0x46, 0x35, 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x27, 0x5b, 0x27,
+ 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x24, 0x5f, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0xdb, 0x00, 0xd8, 0x00, 0xd4, 0x00, 0xd1, 0x00, 0xce, 0x00, 0xcb, 0x00,
+ 0xc8, 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbc, 0x00,
+ 0xba, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00,
+ 0xaf, 0x00, 0xad, 0x00, 0x21, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x18,
+ 0x2f, 0x17, 0x32, 0x16, 0x35, 0x14, 0x38, 0x14, 0x3a, 0x13, 0x3d, 0x13,
+ 0x3f, 0x12, 0x42, 0x12, 0x44, 0x11, 0x46, 0x11, 0x48, 0x11, 0x4a, 0x11,
+ 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e,
+ 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25, 0x00, 0x1c, 0x00, 0x11,
+ 0x00, 0x07, 0x03, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2d, 0x00,
+ 0x36, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5, 0x00,
+ 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65, 0x00,
+ 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x36, 0x4a, 0x35,
+ 0x4a, 0x32, 0x4e, 0x31, 0x4f, 0x2f, 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2b,
+ 0x56, 0x2a, 0x57, 0x2a, 0x57, 0x29, 0x59, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0x5c, 0x26, 0x5c, 0x24, 0x5f, 0x23, 0x60, 0x23, 0xdb, 0x00, 0xd8, 0x00,
+ 0xd5, 0x00, 0xd2, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xc6, 0x00,
+ 0xc4, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb9, 0x00,
+ 0xb8, 0x00, 0xb5, 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00,
+ 0x21, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x19, 0x2e, 0x17, 0x31, 0x16,
+ 0x34, 0x15, 0x37, 0x14, 0x39, 0x13, 0x3b, 0x13, 0x3e, 0x13, 0x40, 0x12,
+ 0x42, 0x12, 0x45, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4a, 0x11, 0x4c, 0x11,
+ 0x4e, 0x11, 0x4f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x27, 0x68, 0x32, 0x51, 0x36, 0x4a, 0x38, 0x47,
+ 0x3a, 0x46, 0x3a, 0x45, 0x3b, 0x44, 0x3c, 0x43, 0x3c, 0x43, 0x3c, 0x43,
+ 0x3c, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x41,
+ 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x41, 0x0e, 0x16, 0x27,
+ 0x23, 0x31, 0x2a, 0x35, 0x2e, 0x38, 0x31, 0x39, 0x33, 0x3a, 0x34, 0x3b,
+ 0x35, 0x3b, 0x36, 0x3c, 0x37, 0x3c, 0x38, 0x3c, 0x38, 0x3c, 0x39, 0x3d,
+ 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3b, 0x3d,
+ 0x68, 0x00, 0x32, 0x27, 0x36, 0x31, 0x38, 0x35, 0x3a, 0x38, 0x3a, 0x39,
+ 0x3b, 0x3a, 0x3c, 0x3b, 0x3c, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3c,
+ 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+ 0x3d, 0x3d, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x22, 0x32, 0x28, 0x36, 0x2c, 0x38, 0x2f, 0x3a, 0x32, 0x3a, 0x34, 0x3b,
+ 0x35, 0x3c, 0x36, 0x3c, 0x37, 0x3c, 0x37, 0x3c, 0x38, 0x3d, 0x39, 0x3d,
+ 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
+ 0x3b, 0x3d, 0x3b, 0x3d, 0x00, 0x97, 0x01, 0x67, 0x09, 0x56, 0x11, 0x4f,
+ 0x17, 0x4b, 0x1c, 0x49, 0x20, 0x47, 0x23, 0x46, 0x25, 0x45, 0x28, 0x44,
+ 0x2a, 0x44, 0x2b, 0x43, 0x2c, 0x43, 0x2e, 0x43, 0x2f, 0x42, 0x30, 0x42,
+ 0x31, 0x42, 0x31, 0x42, 0x32, 0x42, 0x33, 0x42, 0x1a, 0x5c, 0x25, 0x4f,
+ 0x2a, 0x4a, 0x2e, 0x48, 0x31, 0x46, 0x33, 0x45, 0x34, 0x44, 0x36, 0x44,
+ 0x37, 0x43, 0x37, 0x43, 0x38, 0x43, 0x38, 0x42, 0x39, 0x42, 0x39, 0x42,
+ 0x39, 0x41, 0x3a, 0x41, 0x3a, 0x41, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x5f,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x33, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x28, 0x25, 0x2d,
+ 0x28, 0x30, 0x2b, 0x32, 0x2e, 0x34, 0x2f, 0x35, 0x31, 0x36, 0x32, 0x37,
+ 0x33, 0x38, 0x34, 0x38, 0x35, 0x39, 0x36, 0x39, 0x36, 0x39, 0x36, 0x3a,
+ 0x37, 0x3a, 0x37, 0x3a, 0x38, 0x3b, 0x38, 0x3b, 0x39, 0x3b, 0x39, 0x3b,
+ 0x00, 0xb7, 0x00, 0x8b, 0x02, 0x72, 0x07, 0x65, 0x0c, 0x5c, 0x11, 0x57,
+ 0x15, 0x53, 0x18, 0x50, 0x1b, 0x4e, 0x1d, 0x4d, 0x20, 0x4b, 0x22, 0x4a,
+ 0x23, 0x49, 0x25, 0x48, 0x26, 0x48, 0x28, 0x47, 0x29, 0x47, 0x2a, 0x46,
+ 0x2b, 0x46, 0x2c, 0x45, 0x16, 0x6d, 0x1f, 0x5f, 0x24, 0x57, 0x28, 0x53,
+ 0x2b, 0x50, 0x2d, 0x4d, 0x2f, 0x4c, 0x31, 0x4a, 0x32, 0x49, 0x33, 0x48,
+ 0x34, 0x48, 0x35, 0x47, 0x35, 0x46, 0x36, 0x46, 0x36, 0x45, 0x37, 0x45,
+ 0x38, 0x45, 0x38, 0x45, 0x39, 0x44, 0x39, 0x44, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x8b, 0x00, 0x44, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x2e, 0x00,
+ 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x25, 0x23, 0x28, 0x26, 0x2b, 0x28, 0x2e,
+ 0x2a, 0x2f, 0x2c, 0x31, 0x2e, 0x32, 0x2f, 0x33, 0x30, 0x34, 0x31, 0x35,
+ 0x32, 0x36, 0x33, 0x36, 0x33, 0x36, 0x34, 0x37, 0x35, 0x38, 0x36, 0x38,
+ 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x00, 0xc5, 0x00, 0xa0,
+ 0x00, 0x87, 0x03, 0x76, 0x06, 0x6b, 0x0a, 0x64, 0x0e, 0x5f, 0x11, 0x5b,
+ 0x13, 0x57, 0x16, 0x55, 0x18, 0x53, 0x1a, 0x51, 0x1c, 0x50, 0x1e, 0x4e,
+ 0x20, 0x4d, 0x21, 0x4c, 0x22, 0x4b, 0x24, 0x4a, 0x25, 0x49, 0x26, 0x48,
+ 0x15, 0x72, 0x1b, 0x66, 0x20, 0x5f, 0x24, 0x5a, 0x27, 0x56, 0x29, 0x53,
+ 0x2c, 0x51, 0x2d, 0x50, 0x2f, 0x4e, 0x30, 0x4d, 0x31, 0x4c, 0x32, 0x4b,
+ 0x32, 0x4a, 0x33, 0x49, 0x34, 0x49, 0x35, 0x48, 0x35, 0x48, 0x35, 0x47,
+ 0x35, 0x46, 0x36, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x6d, 0x00, 0x33, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x24, 0x00, 0x11, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x22, 0x24, 0x23, 0x26, 0x25, 0x29, 0x27, 0x2b, 0x28, 0x2c, 0x2a, 0x2e,
+ 0x2c, 0x2f, 0x2d, 0x30, 0x2e, 0x31, 0x2f, 0x32, 0x30, 0x33, 0x30, 0x33,
+ 0x32, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36, 0x33, 0x36, 0x34, 0x36,
+ 0x35, 0x36, 0x36, 0x37, 0x00, 0xcb, 0x00, 0xad, 0x00, 0x96, 0x01, 0x84,
+ 0x03, 0x78, 0x06, 0x70, 0x09, 0x69, 0x0b, 0x64, 0x0e, 0x60, 0x10, 0x5d,
+ 0x13, 0x59, 0x15, 0x57, 0x17, 0x56, 0x19, 0x54, 0x1a, 0x52, 0x1c, 0x51,
+ 0x1d, 0x50, 0x1f, 0x4f, 0x1f, 0x4f, 0x21, 0x4e, 0x14, 0x75, 0x19, 0x6b,
+ 0x1e, 0x64, 0x22, 0x5f, 0x24, 0x5b, 0x27, 0x58, 0x29, 0x56, 0x2a, 0x54,
+ 0x2c, 0x52, 0x2d, 0x51, 0x2e, 0x4f, 0x2f, 0x4e, 0x30, 0x4e, 0x31, 0x4d,
+ 0x31, 0x4c, 0x32, 0x4a, 0x33, 0x4a, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa,
+ 0x00, 0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x23, 0x23, 0x25,
+ 0x24, 0x27, 0x25, 0x28, 0x27, 0x2a, 0x28, 0x2c, 0x2a, 0x2d, 0x2b, 0x2e,
+ 0x2c, 0x2f, 0x2d, 0x30, 0x2e, 0x31, 0x2f, 0x32, 0x30, 0x32, 0x30, 0x33,
+ 0x31, 0x33, 0x32, 0x33, 0x33, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36,
+ 0x00, 0xcf, 0x00, 0xb6, 0x00, 0xa0, 0x00, 0x8f, 0x01, 0x83, 0x03, 0x79,
+ 0x05, 0x72, 0x08, 0x6c, 0x0a, 0x68, 0x0c, 0x64, 0x0f, 0x61, 0x10, 0x5e,
+ 0x12, 0x5b, 0x14, 0x59, 0x16, 0x58, 0x17, 0x56, 0x19, 0x55, 0x1a, 0x53,
+ 0x1b, 0x52, 0x1c, 0x50, 0x13, 0x77, 0x18, 0x6e, 0x1c, 0x68, 0x1f, 0x63,
+ 0x22, 0x5f, 0x24, 0x5c, 0x26, 0x59, 0x28, 0x57, 0x29, 0x56, 0x2a, 0x54,
+ 0x2c, 0x53, 0x2d, 0x52, 0x2e, 0x50, 0x2e, 0x4f, 0x2f, 0x4f, 0x31, 0x4e,
+ 0x31, 0x4d, 0x31, 0x4d, 0x31, 0x4c, 0x32, 0x4a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70,
+ 0x00, 0x48, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3a, 0x00,
+ 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x23, 0x22, 0x24, 0x24, 0x26, 0x25, 0x27,
+ 0x26, 0x29, 0x27, 0x2a, 0x28, 0x2b, 0x2a, 0x2d, 0x2a, 0x2d, 0x2c, 0x2e,
+ 0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33,
+ 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x34, 0x00, 0xd1, 0x00, 0xbc,
+ 0x00, 0xa9, 0x00, 0x99, 0x00, 0x8c, 0x02, 0x82, 0x03, 0x7a, 0x05, 0x74,
+ 0x07, 0x6f, 0x09, 0x6b, 0x0b, 0x67, 0x0d, 0x63, 0x0f, 0x61, 0x10, 0x5f,
+ 0x12, 0x5c, 0x14, 0x5a, 0x15, 0x58, 0x16, 0x58, 0x18, 0x57, 0x19, 0x56,
+ 0x13, 0x78, 0x17, 0x70, 0x1b, 0x6a, 0x1e, 0x66, 0x20, 0x62, 0x22, 0x5f,
+ 0x24, 0x5c, 0x26, 0x5b, 0x27, 0x58, 0x29, 0x57, 0x2a, 0x56, 0x2b, 0x53,
+ 0x2c, 0x53, 0x2d, 0x52, 0x2e, 0x51, 0x2e, 0x50, 0x2f, 0x4f, 0x30, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d,
+ 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00,
+ 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x22, 0x22, 0x22, 0x24, 0x23, 0x25, 0x24, 0x27, 0x25, 0x27, 0x27, 0x28,
+ 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2e,
+ 0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x33,
+ 0x30, 0x33, 0x31, 0x33, 0x00, 0xd3, 0x00, 0xc1, 0x00, 0xaf, 0x00, 0xa1,
+ 0x00, 0x94, 0x00, 0x8a, 0x02, 0x82, 0x03, 0x7b, 0x05, 0x76, 0x07, 0x71,
+ 0x09, 0x6d, 0x0a, 0x69, 0x0c, 0x66, 0x0e, 0x63, 0x0f, 0x61, 0x10, 0x60,
+ 0x12, 0x5d, 0x13, 0x5c, 0x14, 0x59, 0x16, 0x58, 0x13, 0x79, 0x16, 0x72,
+ 0x19, 0x6d, 0x1c, 0x69, 0x1f, 0x65, 0x20, 0x61, 0x23, 0x60, 0x24, 0x5c,
+ 0x26, 0x5b, 0x27, 0x59, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53,
+ 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2e, 0x51, 0x2e, 0x4f, 0x2f, 0x4f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6,
+ 0x00, 0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b, 0x00,
+ 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x23,
+ 0x23, 0x24, 0x24, 0x25, 0x25, 0x27, 0x26, 0x28, 0x26, 0x28, 0x28, 0x2a,
+ 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2d, 0x2a, 0x2d, 0x2c, 0x2d, 0x2d, 0x2e,
+ 0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32,
+ 0x00, 0xd4, 0x00, 0xc4, 0x00, 0xb5, 0x00, 0xa7, 0x00, 0x9b, 0x00, 0x91,
+ 0x01, 0x88, 0x02, 0x82, 0x03, 0x7b, 0x05, 0x77, 0x07, 0x73, 0x08, 0x6e,
+ 0x0a, 0x6b, 0x0b, 0x69, 0x0c, 0x66, 0x0e, 0x63, 0x0f, 0x61, 0x10, 0x60,
+ 0x12, 0x5f, 0x13, 0x5c, 0x12, 0x79, 0x15, 0x73, 0x18, 0x6e, 0x1b, 0x6a,
+ 0x1d, 0x67, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x24, 0x5d, 0x26, 0x5c,
+ 0x27, 0x5a, 0x27, 0x58, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53,
+ 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97,
+ 0x00, 0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00,
+ 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25,
+ 0x24, 0x26, 0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b,
+ 0x2a, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f,
+ 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x30, 0x30, 0x30, 0x00, 0xd5, 0x00, 0xc7,
+ 0x00, 0xb9, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8f, 0x01, 0x87,
+ 0x02, 0x82, 0x03, 0x7b, 0x05, 0x77, 0x06, 0x74, 0x08, 0x6f, 0x09, 0x6c,
+ 0x0b, 0x6b, 0x0c, 0x68, 0x0d, 0x65, 0x0e, 0x63, 0x0f, 0x62, 0x10, 0x60,
+ 0x12, 0x7a, 0x15, 0x75, 0x18, 0x70, 0x1a, 0x6c, 0x1d, 0x69, 0x1e, 0x65,
+ 0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x24, 0x5d, 0x26, 0x5c, 0x27, 0x5b,
+ 0x27, 0x58, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53,
+ 0x2c, 0x53, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71,
+ 0x00, 0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34, 0x00,
+ 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x25, 0x25, 0x27,
+ 0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f,
+ 0x2d, 0x30, 0x2d, 0x30, 0x00, 0xd6, 0x00, 0xc9, 0x00, 0xbc, 0x00, 0xb1,
+ 0x00, 0xa6, 0x00, 0x9c, 0x00, 0x94, 0x00, 0x8c, 0x02, 0x86, 0x02, 0x81,
+ 0x03, 0x7c, 0x05, 0x78, 0x06, 0x75, 0x07, 0x71, 0x09, 0x6d, 0x0a, 0x6c,
+ 0x0b, 0x6a, 0x0c, 0x67, 0x0d, 0x65, 0x0e, 0x62, 0x12, 0x7b, 0x15, 0x76,
+ 0x18, 0x72, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x63,
+ 0x22, 0x60, 0x23, 0x60, 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5a,
+ 0x28, 0x57, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2a, 0x55, 0x2b, 0x53,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba,
+ 0x00, 0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50,
+ 0x00, 0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00,
+ 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x21, 0x22, 0x22, 0x23,
+ 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x27, 0x26, 0x27,
+ 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x2c, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f,
+ 0x00, 0xd6, 0x00, 0xcb, 0x00, 0xbf, 0x00, 0xb4, 0x00, 0xab, 0x00, 0xa1,
+ 0x00, 0x99, 0x00, 0x91, 0x01, 0x8b, 0x02, 0x85, 0x02, 0x81, 0x04, 0x7c,
+ 0x05, 0x78, 0x06, 0x76, 0x07, 0x73, 0x08, 0x6f, 0x09, 0x6c, 0x0b, 0x6b,
+ 0x0c, 0x6a, 0x0c, 0x67, 0x12, 0x7b, 0x15, 0x76, 0x17, 0x72, 0x19, 0x6e,
+ 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x66, 0x20, 0x65, 0x20, 0x62, 0x22, 0x60,
+ 0x23, 0x60, 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x27, 0x58,
+ 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7,
+ 0x00, 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35,
+ 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+ 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f, 0x00,
+ 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+ 0x24, 0x25, 0x24, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28,
+ 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c,
+ 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x00, 0xd7, 0x00, 0xcc,
+ 0x00, 0xc2, 0x00, 0xb8, 0x00, 0xae, 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x95,
+ 0x00, 0x90, 0x01, 0x8a, 0x02, 0x85, 0x03, 0x81, 0x04, 0x7c, 0x05, 0x78,
+ 0x06, 0x76, 0x07, 0x74, 0x08, 0x70, 0x09, 0x6d, 0x0a, 0x6c, 0x0b, 0x6a,
+ 0x12, 0x7b, 0x14, 0x77, 0x16, 0x73, 0x18, 0x70, 0x1a, 0x6d, 0x1c, 0x6a,
+ 0x1d, 0x69, 0x1e, 0x65, 0x20, 0x65, 0x20, 0x62, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x59, 0x28, 0x57,
+ 0x2a, 0x57, 0x2a, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d,
+ 0x00, 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00,
+ 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16, 0x00,
+ 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x25,
+ 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28, 0x26, 0x28, 0x28, 0x28,
+ 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d,
+ 0x2b, 0x2d, 0x2c, 0x2d, 0x00, 0xd7, 0x00, 0xcd, 0x00, 0xc4, 0x00, 0xbb,
+ 0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa1, 0x00, 0x9a, 0x00, 0x93, 0x00, 0x8e,
+ 0x01, 0x88, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7c, 0x05, 0x79, 0x06, 0x77,
+ 0x07, 0x75, 0x07, 0x72, 0x09, 0x6e, 0x09, 0x6d, 0x12, 0x7b, 0x14, 0x77,
+ 0x15, 0x73, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6b, 0x1d, 0x69, 0x1d, 0x67,
+ 0x1f, 0x65, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e,
+ 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5a, 0x27, 0x58, 0x29, 0x57,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc,
+ 0x00, 0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72,
+ 0x00, 0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31, 0x00,
+ 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f, 0x00,
+ 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x26,
+ 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x26, 0x28, 0x28, 0x28, 0x28, 0x29,
+ 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d,
+ 0x00, 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbd, 0x00, 0xb4, 0x00, 0xad,
+ 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x92, 0x01, 0x8d, 0x02, 0x88,
+ 0x02, 0x84, 0x03, 0x81, 0x04, 0x7d, 0x05, 0x79, 0x06, 0x77, 0x07, 0x75,
+ 0x07, 0x73, 0x09, 0x70, 0x12, 0x7c, 0x13, 0x78, 0x15, 0x75, 0x18, 0x72,
+ 0x19, 0x6e, 0x1a, 0x6d, 0x1c, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65,
+ 0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e, 0x25, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x27, 0x59, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf,
+ 0x00, 0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59,
+ 0x00, 0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+ 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28, 0x00,
+ 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+ 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x25, 0x27,
+ 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b,
+ 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x00, 0xd8, 0x00, 0xd0,
+ 0x00, 0xc7, 0x00, 0xbe, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa8, 0x00, 0xa1,
+ 0x00, 0x9b, 0x00, 0x95, 0x00, 0x90, 0x01, 0x8c, 0x02, 0x87, 0x02, 0x84,
+ 0x03, 0x81, 0x04, 0x7d, 0x05, 0x79, 0x06, 0x77, 0x06, 0x76, 0x07, 0x74,
+ 0x11, 0x7c, 0x13, 0x78, 0x15, 0x76, 0x17, 0x72, 0x18, 0x6f, 0x1a, 0x6d,
+ 0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x65, 0x20, 0x64,
+ 0x22, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e, 0x25, 0x5c, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x00, 0x2f, 0x00, 0x5f, 0x00, 0x99, 0x00, 0xac,
+ 0x00, 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc,
+ 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe,
+ 0x00, 0x9a, 0x00, 0x6d, 0x00, 0x8d, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0xb2,
+ 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd,
+ 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0b, 0x3b, 0x00, 0x6f, 0x00, 0x9f, 0x00, 0xaf,
+ 0x00, 0xb5, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd,
+ 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe,
+ 0x07, 0x47, 0x00, 0x7f, 0x00, 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba,
+ 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe,
+ 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24,
+ 0x24, 0x25, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x27,
+ 0x27, 0x29, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2b, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc0,
+ 0x00, 0xba, 0x00, 0xb1, 0x00, 0xac, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x98,
+ 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8b, 0x02, 0x86, 0x02, 0x83, 0x03, 0x81,
+ 0x04, 0x7d, 0x05, 0x79, 0x06, 0x78, 0x06, 0x76, 0x11, 0x7c, 0x13, 0x79,
+ 0x15, 0x76, 0x17, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6d, 0x1c, 0x69,
+ 0x1d, 0x69, 0x1d, 0x66, 0x20, 0x65, 0x20, 0x65, 0x20, 0x63, 0x22, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x5f, 0x00, 0x8b, 0x00, 0x9f, 0x00, 0xaa,
+ 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba,
+ 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x6d, 0x00, 0x54,
+ 0x00, 0x6b, 0x00, 0x87, 0x00, 0x98, 0x00, 0xa6, 0x00, 0xb0, 0x00, 0xb3,
+ 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbb,
+ 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x17, 0x07, 0x02, 0x27, 0x00, 0x6f, 0x00, 0x93, 0x00, 0xa4, 0x00, 0xad,
+ 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb,
+ 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x0f, 0x0f, 0x00, 0x3f,
+ 0x00, 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7,
+ 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd,
+ 0x00, 0xbd, 0x00, 0xbd, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25,
+ 0x25, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28,
+ 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x2a, 0x2b,
+ 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xc9, 0x00, 0xc2, 0x00, 0xbb, 0x00, 0xb4,
+ 0x00, 0xae, 0x00, 0xa7, 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x96, 0x00, 0x92,
+ 0x01, 0x8e, 0x01, 0x89, 0x02, 0x86, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e,
+ 0x05, 0x7a, 0x06, 0x78, 0x11, 0x7c, 0x13, 0x79, 0x15, 0x76, 0x16, 0x73,
+ 0x18, 0x72, 0x19, 0x6e, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x69,
+ 0x1e, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x62, 0x22, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x5f, 0x24, 0x5c, 0x26, 0x5c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x44, 0x00, 0x6d, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f,
+ 0x00, 0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5,
+ 0x00, 0xb6, 0x00, 0xb7, 0x00, 0x8d, 0x00, 0x6b, 0x00, 0x28, 0x00, 0x52,
+ 0x00, 0x70, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00, 0xa6, 0x00, 0xab,
+ 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x12, 0x02,
+ 0x00, 0x22, 0x00, 0x58, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9c, 0x00, 0xa4,
+ 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb7,
+ 0x00, 0xb8, 0x00, 0xb9, 0x26, 0x00, 0x05, 0x05, 0x00, 0x3f, 0x00, 0x6d,
+ 0x00, 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1,
+ 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23,
+ 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x25,
+ 0x25, 0x27, 0x26, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x00, 0xd9, 0x00, 0xd2,
+ 0x00, 0xca, 0x00, 0xc4, 0x00, 0xbd, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xaa,
+ 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x91, 0x01, 0x8e,
+ 0x02, 0x89, 0x02, 0x85, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e, 0x05, 0x7a,
+ 0x11, 0x7c, 0x13, 0x7a, 0x15, 0x76, 0x15, 0x74, 0x18, 0x72, 0x18, 0x6f,
+ 0x1a, 0x6d, 0x1a, 0x6c, 0x1c, 0x69, 0x1d, 0x69, 0x1d, 0x67, 0x1f, 0x65,
+ 0x20, 0x65, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x5f, 0x24, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x33, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97,
+ 0x00, 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf,
+ 0x00, 0x9b, 0x00, 0x87, 0x00, 0x52, 0x00, 0x11, 0x00, 0x39, 0x00, 0x57,
+ 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00, 0x9e, 0x00, 0xa3,
+ 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x25, 0x00, 0x0b, 0x09, 0x00, 0x21,
+ 0x00, 0x4a, 0x00, 0x68, 0x00, 0x7d, 0x00, 0x8b, 0x00, 0x96, 0x00, 0x9d,
+ 0x00, 0xa3, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2,
+ 0x33, 0x00, 0x1c, 0x00, 0x00, 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a,
+ 0x00, 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac,
+ 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24,
+ 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x25, 0x27,
+ 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x2a, 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xcb, 0x00, 0xc6,
+ 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb1, 0x00, 0xac, 0x00, 0xa6, 0x00, 0xa1,
+ 0x00, 0x9d, 0x00, 0x97, 0x00, 0x93, 0x00, 0x90, 0x01, 0x8d, 0x02, 0x88,
+ 0x02, 0x85, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e, 0x11, 0x7c, 0x13, 0x7a,
+ 0x15, 0x76, 0x15, 0x75, 0x18, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6d,
+ 0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20, 0x65,
+ 0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28,
+ 0x00, 0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91,
+ 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0x98,
+ 0x00, 0x70, 0x00, 0x39, 0x00, 0x02, 0x00, 0x28, 0x00, 0x48, 0x00, 0x5f,
+ 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00, 0x98, 0x00, 0x9d,
+ 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3a, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x08, 0x0e, 0x00, 0x20, 0x00, 0x42,
+ 0x00, 0x5c, 0x00, 0x6f, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x92, 0x00, 0x99,
+ 0x00, 0x9e, 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x38, 0x00, 0x2a, 0x00,
+ 0x09, 0x00, 0x00, 0x1d, 0x00, 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f,
+ 0x00, 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8,
+ 0x00, 0xab, 0x00, 0xad, 0x16, 0xa4, 0x01, 0xbb, 0x00, 0xc6, 0x00, 0xcc,
+ 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6,
+ 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9,
+ 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x05, 0x9d, 0x00, 0xbc,
+ 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd5,
+ 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd8,
+ 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x02, 0xbd, 0x00, 0xcc, 0x00, 0xd1, 0x00, 0xd5,
+ 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9,
+ 0x00, 0xd9, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xdb,
+ 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x3d,
+ 0x00, 0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d,
+ 0x00, 0x93, 0x00, 0x98, 0x00, 0xb2, 0x00, 0xa6, 0x00, 0x85, 0x00, 0x57,
+ 0x00, 0x28, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x52, 0x00, 0x64,
+ 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00, 0x93, 0x00, 0x98,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00,
+ 0x23, 0x00, 0x0e, 0x02, 0x06, 0x12, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x52,
+ 0x00, 0x64, 0x00, 0x73, 0x00, 0x7e, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x95,
+ 0x00, 0x9a, 0x00, 0x9e, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x00, 0x00, 0x05,
+ 0x00, 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82,
+ 0x00, 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5,
+ 0x23, 0x74, 0x09, 0x91, 0x02, 0xa3, 0x00, 0xaf, 0x00, 0xb7, 0x00, 0xbd,
+ 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc,
+ 0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd2,
+ 0x00, 0xd2, 0x00, 0xd3, 0x0d, 0x6b, 0x01, 0x8e, 0x00, 0xa4, 0x00, 0xb0,
+ 0x00, 0xb9, 0x00, 0xbe, 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc8, 0x00, 0xca,
+ 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1,
+ 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x06, 0xa4, 0x00, 0xb5, 0x00, 0xc0, 0x00, 0xc6, 0x00, 0xcb, 0x00, 0xcd,
+ 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4,
+ 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd7,
+ 0x00, 0xd8, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48,
+ 0x00, 0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89,
+ 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00, 0x48, 0x00, 0x21,
+ 0x00, 0x01, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00, 0x59, 0x00, 0x66,
+ 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x18, 0x00,
+ 0x0c, 0x07, 0x05, 0x14, 0x00, 0x20, 0x00, 0x37, 0x00, 0x4c, 0x00, 0x5c,
+ 0x00, 0x6a, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x86, 0x00, 0x8d, 0x00, 0x92,
+ 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x00, 0x00, 0x0f, 0x00, 0x29,
+ 0x00, 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84,
+ 0x00, 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b, 0x2a, 0x61, 0x11, 0x78,
+ 0x07, 0x8a, 0x03, 0x98, 0x01, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6,
+ 0x00, 0xba, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc6,
+ 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc,
+ 0x12, 0x51, 0x04, 0x73, 0x00, 0x89, 0x00, 0x9a, 0x00, 0xa4, 0x00, 0xad,
+ 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbb, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc3,
+ 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb,
+ 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x09, 0x97, 0x02, 0xa8,
+ 0x00, 0xb3, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc7, 0x00, 0xca,
+ 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd1,
+ 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd5,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50,
+ 0x00, 0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0xbb, 0x00, 0xb3,
+ 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x1c, 0x00, 0x00,
+ 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00, 0x5d, 0x00, 0x68,
+ 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0a, 0x0b,
+ 0x04, 0x16, 0x00, 0x20, 0x00, 0x34, 0x00, 0x46, 0x00, 0x56, 0x00, 0x62,
+ 0x00, 0x6d, 0x00, 0x77, 0x00, 0x7f, 0x00, 0x85, 0x3d, 0x00, 0x38, 0x00,
+ 0x2a, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f,
+ 0x00, 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85,
+ 0x00, 0x8b, 0x00, 0x91, 0x2e, 0x59, 0x17, 0x6b, 0x0c, 0x7a, 0x06, 0x87,
+ 0x03, 0x92, 0x01, 0x9b, 0x00, 0xa2, 0x00, 0xa8, 0x00, 0xad, 0x00, 0xb1,
+ 0x00, 0xb5, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1,
+ 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7, 0x15, 0x45, 0x08, 0x60,
+ 0x02, 0x77, 0x00, 0x87, 0x00, 0x94, 0x00, 0x9d, 0x00, 0xa4, 0x00, 0xaa,
+ 0x00, 0xaf, 0x00, 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbc, 0x00, 0xbe,
+ 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0a, 0x91, 0x04, 0x9e, 0x01, 0xaa, 0x00, 0xb2,
+ 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc6, 0x00, 0xc8,
+ 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf,
+ 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55,
+ 0x00, 0x60, 0x00, 0x6a, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xa6, 0x00, 0x8e,
+ 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00, 0x00, 0x00, 0x16,
+ 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00, 0x60, 0x00, 0x6a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00,
+ 0x33, 0x00, 0x27, 0x00, 0x18, 0x00, 0x0d, 0x04, 0x08, 0x0e, 0x04, 0x17,
+ 0x00, 0x20, 0x00, 0x32, 0x00, 0x42, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x67,
+ 0x00, 0x70, 0x00, 0x78, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f, 0x00,
+ 0x0b, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e,
+ 0x00, 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86,
+ 0x31, 0x53, 0x1c, 0x62, 0x11, 0x70, 0x0a, 0x7b, 0x06, 0x85, 0x03, 0x8e,
+ 0x02, 0x96, 0x00, 0x9c, 0x00, 0xa2, 0x00, 0xa7, 0x00, 0xab, 0x00, 0xae,
+ 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd,
+ 0x00, 0xbe, 0x00, 0xbf, 0x17, 0x3d, 0x0b, 0x55, 0x04, 0x67, 0x01, 0x78,
+ 0x00, 0x85, 0x00, 0x90, 0x00, 0x98, 0x00, 0x9f, 0x00, 0xa5, 0x00, 0xaa,
+ 0x00, 0xad, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xbb,
+ 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0b, 0x8d, 0x05, 0x99, 0x02, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6,
+ 0x00, 0xba, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc3, 0x00, 0xc5, 0x00, 0xc7,
+ 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcd,
+ 0x00, 0xce, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59,
+ 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00, 0x7e, 0x00, 0x64,
+ 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x25,
+ 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00,
+ 0x1f, 0x00, 0x12, 0x00, 0x0c, 0x07, 0x07, 0x10, 0x03, 0x18, 0x00, 0x20,
+ 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4c, 0x00, 0x57, 0x00, 0x61, 0x00, 0x6a,
+ 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02, 0x00,
+ 0x00, 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58,
+ 0x00, 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b, 0x33, 0x50, 0x20, 0x5c,
+ 0x15, 0x68, 0x0e, 0x72, 0x09, 0x7c, 0x05, 0x84, 0x03, 0x8c, 0x02, 0x92,
+ 0x01, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad,
+ 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba,
+ 0x18, 0x38, 0x0d, 0x4c, 0x06, 0x5e, 0x03, 0x6c, 0x01, 0x7a, 0x00, 0x84,
+ 0x00, 0x8d, 0x00, 0x95, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8,
+ 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8,
+ 0x00, 0xba, 0x00, 0xbc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0c, 0x8a, 0x06, 0x94,
+ 0x03, 0x9d, 0x01, 0xa4, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb5, 0x00, 0xb9,
+ 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc6,
+ 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
+ 0x00, 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0xbd, 0x00, 0xb9,
+ 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00, 0x59, 0x00, 0x41,
+ 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x22, 0x00, 0x30,
+ 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x00,
+ 0x0e, 0x02, 0x0a, 0x0a, 0x06, 0x11, 0x03, 0x19, 0x00, 0x1f, 0x00, 0x2e,
+ 0x00, 0x3c, 0x00, 0x48, 0x00, 0x53, 0x00, 0x5c, 0x3e, 0x00, 0x3c, 0x00,
+ 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x00, 0x00, 0x04, 0x00, 0x14,
+ 0x00, 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60,
+ 0x00, 0x68, 0x00, 0x70, 0x34, 0x4e, 0x23, 0x58, 0x18, 0x62, 0x10, 0x6c,
+ 0x0b, 0x75, 0x08, 0x7c, 0x05, 0x83, 0x03, 0x8a, 0x02, 0x8f, 0x01, 0x95,
+ 0x00, 0x9a, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xac,
+ 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb5, 0x1a, 0x35, 0x0f, 0x47,
+ 0x08, 0x55, 0x04, 0x64, 0x02, 0x70, 0x00, 0x7a, 0x00, 0x83, 0x00, 0x8b,
+ 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8,
+ 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb7,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0d, 0x89, 0x07, 0x92, 0x04, 0x99, 0x02, 0xa0,
+ 0x01, 0xa6, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0xba,
+ 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc5,
+ 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xca, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0x2d, 0x00, 0x39, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa3,
+ 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00, 0x3a, 0x00, 0x25,
+ 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x39,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00,
+ 0x38, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x0d, 0x05,
+ 0x09, 0x0c, 0x06, 0x13, 0x03, 0x19, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x3a,
+ 0x00, 0x45, 0x00, 0x4f, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d, 0x00,
+ 0x21, 0x00, 0x13, 0x00, 0x04, 0x00, 0x00, 0x0a, 0x00, 0x18, 0x00, 0x26,
+ 0x00, 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65,
+ 0x35, 0x4c, 0x26, 0x55, 0x1b, 0x5e, 0x13, 0x67, 0x0e, 0x6f, 0x0a, 0x76,
+ 0x07, 0x7d, 0x05, 0x82, 0x03, 0x88, 0x02, 0x8e, 0x02, 0x92, 0x01, 0x97,
+ 0x00, 0x9b, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab,
+ 0x00, 0xac, 0x00, 0xaf, 0x1b, 0x33, 0x10, 0x42, 0x0a, 0x50, 0x05, 0x5c,
+ 0x03, 0x68, 0x01, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x8a, 0x00, 0x90,
+ 0x00, 0x96, 0x00, 0x99, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa8,
+ 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0d, 0x88, 0x08, 0x8f, 0x05, 0x96, 0x02, 0x9c, 0x01, 0xa2, 0x00, 0xa7,
+ 0x00, 0xac, 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xbb,
+ 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc5,
+ 0x00, 0xc6, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29,
+ 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00, 0x98, 0x00, 0x85,
+ 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00, 0x22, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x33, 0x00,
+ 0x2c, 0x00, 0x23, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x0c, 0x07, 0x08, 0x0e,
+ 0x05, 0x14, 0x02, 0x1a, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x38, 0x00, 0x42,
+ 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19, 0x00,
+ 0x0c, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34,
+ 0x00, 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b, 0x36, 0x4a, 0x28, 0x52,
+ 0x1d, 0x5b, 0x16, 0x63, 0x10, 0x6a, 0x0c, 0x71, 0x09, 0x77, 0x07, 0x7d,
+ 0x05, 0x82, 0x03, 0x87, 0x02, 0x8c, 0x02, 0x90, 0x01, 0x94, 0x00, 0x99,
+ 0x00, 0x9c, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xaa,
+ 0x1b, 0x30, 0x12, 0x3e, 0x0c, 0x4b, 0x07, 0x57, 0x04, 0x61, 0x02, 0x6b,
+ 0x01, 0x73, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00, 0x8f, 0x00, 0x93,
+ 0x00, 0x97, 0x00, 0x9c, 0x00, 0x9f, 0x00, 0xa2, 0x00, 0xa5, 0x00, 0xa8,
+ 0x00, 0xaa, 0x00, 0xac, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0d, 0x86, 0x09, 0x8d,
+ 0x06, 0x94, 0x03, 0x9a, 0x02, 0x9f, 0x01, 0xa4, 0x00, 0xa8, 0x00, 0xac,
+ 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbc,
+ 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0xbe, 0x00, 0xbb,
+ 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00, 0x7b, 0x00, 0x68,
+ 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x26, 0x00,
+ 0x1d, 0x00, 0x14, 0x00, 0x0e, 0x03, 0x0b, 0x09, 0x08, 0x0f, 0x05, 0x15,
+ 0x02, 0x1a, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x3f, 0x00, 0x3d, 0x00,
+ 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06, 0x00,
+ 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f,
+ 0x00, 0x49, 0x00, 0x51, 0x37, 0x49, 0x2a, 0x51, 0x20, 0x58, 0x18, 0x5f,
+ 0x13, 0x66, 0x0f, 0x6c, 0x0b, 0x73, 0x09, 0x78, 0x07, 0x7e, 0x05, 0x82,
+ 0x03, 0x86, 0x02, 0x8b, 0x02, 0x8f, 0x01, 0x92, 0x01, 0x96, 0x00, 0x9a,
+ 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa4, 0x1c, 0x2f, 0x13, 0x3b,
+ 0x0d, 0x47, 0x09, 0x51, 0x05, 0x5c, 0x04, 0x65, 0x02, 0x6e, 0x01, 0x75,
+ 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00, 0x8d, 0x00, 0x91, 0x00, 0x96,
+ 0x00, 0x99, 0x00, 0x9c, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa5, 0x00, 0xa7,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x86, 0x09, 0x8c, 0x06, 0x92, 0x04, 0x97,
+ 0x02, 0x9c, 0x02, 0xa1, 0x01, 0xa5, 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf,
+ 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc,
+ 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0d, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xad,
+ 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00, 0x60, 0x00, 0x4f,
+ 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+ 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00,
+ 0x10, 0x00, 0x0d, 0x05, 0x0a, 0x0b, 0x07, 0x10, 0x04, 0x16, 0x02, 0x1b,
+ 0x00, 0x1f, 0x00, 0x2a, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33, 0x00,
+ 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0b,
+ 0x00, 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48,
+ 0x38, 0x48, 0x2b, 0x4f, 0x22, 0x56, 0x1a, 0x5c, 0x15, 0x63, 0x11, 0x69,
+ 0x0d, 0x6e, 0x0a, 0x74, 0x08, 0x78, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x85,
+ 0x03, 0x8a, 0x02, 0x8e, 0x02, 0x90, 0x01, 0x93, 0x00, 0x98, 0x00, 0x9b,
+ 0x00, 0x9d, 0x00, 0x9f, 0x1c, 0x2d, 0x14, 0x39, 0x0e, 0x44, 0x0a, 0x4e,
+ 0x07, 0x57, 0x04, 0x60, 0x02, 0x67, 0x01, 0x6f, 0x00, 0x76, 0x00, 0x7d,
+ 0x00, 0x81, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90, 0x00, 0x94, 0x00, 0x97,
+ 0x00, 0x9a, 0x00, 0x9d, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0e, 0x85, 0x0a, 0x8b, 0x07, 0x90, 0x05, 0x95, 0x03, 0x9a, 0x02, 0x9e,
+ 0x01, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2,
+ 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd,
+ 0x00, 0xbe, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x98,
+ 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00, 0x49, 0x00, 0x39,
+ 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00,
+ 0x32, 0x00, 0x2c, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0e, 0x01,
+ 0x0c, 0x07, 0x09, 0x0c, 0x06, 0x11, 0x04, 0x16, 0x02, 0x1b, 0x00, 0x1f,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25, 0x00,
+ 0x1c, 0x00, 0x11, 0x00, 0x07, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x19,
+ 0x00, 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f, 0x38, 0x48, 0x2d, 0x4e,
+ 0x23, 0x54, 0x1c, 0x5a, 0x17, 0x5f, 0x12, 0x66, 0x0f, 0x6a, 0x0c, 0x71,
+ 0x0a, 0x74, 0x08, 0x79, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x89,
+ 0x02, 0x8d, 0x02, 0x8f, 0x01, 0x92, 0x01, 0x95, 0x00, 0x99, 0x00, 0x9b,
+ 0x1c, 0x2d, 0x15, 0x37, 0x0f, 0x41, 0x0b, 0x4a, 0x07, 0x53, 0x05, 0x5b,
+ 0x04, 0x63, 0x02, 0x69, 0x01, 0x70, 0x00, 0x77, 0x00, 0x7d, 0x00, 0x81,
+ 0x00, 0x87, 0x00, 0x8a, 0x00, 0x8f, 0x00, 0x92, 0x00, 0x96, 0x00, 0x99,
+ 0x00, 0x9b, 0x00, 0x9e, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x85, 0x0a, 0x8a,
+ 0x07, 0x8f, 0x05, 0x93, 0x03, 0x98, 0x02, 0x9c, 0x02, 0xa0, 0x01, 0xa3,
+ 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb3,
+ 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x39, 0x47, 0x2e, 0x4d, 0x25, 0x53, 0x1e, 0x58,
+ 0x19, 0x5e, 0x14, 0x63, 0x11, 0x68, 0x0e, 0x6c, 0x0b, 0x72, 0x09, 0x75,
+ 0x07, 0x79, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x88, 0x02, 0x8c,
+ 0x02, 0x8e, 0x01, 0x91, 0x01, 0x93, 0x00, 0x97, 0x1d, 0x2c, 0x16, 0x36,
+ 0x10, 0x3e, 0x0c, 0x48, 0x09, 0x50, 0x06, 0x58, 0x04, 0x5f, 0x02, 0x66,
+ 0x02, 0x6c, 0x01, 0x71, 0x00, 0x77, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x86,
+ 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9a,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x84, 0x0b, 0x89, 0x08, 0x8d, 0x06, 0x92,
+ 0x04, 0x96, 0x03, 0x9a, 0x02, 0x9e, 0x01, 0xa1, 0x01, 0xa4, 0x00, 0xa7,
+ 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5,
+ 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x39, 0x46, 0x2f, 0x4c, 0x26, 0x51, 0x20, 0x56, 0x1a, 0x5c, 0x16, 0x60,
+ 0x12, 0x66, 0x0f, 0x69, 0x0c, 0x6e, 0x0b, 0x73, 0x09, 0x76, 0x07, 0x7a,
+ 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x88, 0x02, 0x8b, 0x02, 0x8e,
+ 0x02, 0x90, 0x01, 0x92, 0x1d, 0x2b, 0x16, 0x34, 0x11, 0x3d, 0x0c, 0x45,
+ 0x0a, 0x4c, 0x07, 0x54, 0x05, 0x5b, 0x04, 0x61, 0x02, 0x67, 0x01, 0x6d,
+ 0x01, 0x73, 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x86, 0x00, 0x89,
+ 0x00, 0x8d, 0x00, 0x90, 0x00, 0x93, 0x00, 0x95, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0e, 0x84, 0x0b, 0x88, 0x08, 0x8d, 0x06, 0x91, 0x05, 0x94, 0x03, 0x98,
+ 0x02, 0x9c, 0x02, 0x9f, 0x01, 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa,
+ 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb6,
+ 0x00, 0xb8, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x46, 0x30, 0x4b,
+ 0x28, 0x50, 0x21, 0x55, 0x1c, 0x59, 0x17, 0x5e, 0x14, 0x63, 0x10, 0x68,
+ 0x0e, 0x6b, 0x0c, 0x70, 0x0a, 0x74, 0x08, 0x76, 0x07, 0x7b, 0x06, 0x7e,
+ 0x05, 0x81, 0x04, 0x83, 0x03, 0x87, 0x02, 0x8a, 0x02, 0x8d, 0x02, 0x8f,
+ 0x1e, 0x2a, 0x17, 0x33, 0x12, 0x3b, 0x0e, 0x43, 0x0a, 0x4a, 0x07, 0x51,
+ 0x05, 0x58, 0x04, 0x5e, 0x03, 0x64, 0x02, 0x69, 0x01, 0x6f, 0x00, 0x74,
+ 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85, 0x00, 0x89, 0x00, 0x8b,
+ 0x00, 0x8f, 0x00, 0x93, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0b, 0x88,
+ 0x09, 0x8c, 0x07, 0x90, 0x05, 0x93, 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d,
+ 0x01, 0xa0, 0x01, 0xa3, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xad,
+ 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x31, 0x4a, 0x29, 0x4e, 0x22, 0x54,
+ 0x1d, 0x57, 0x19, 0x5d, 0x15, 0x60, 0x12, 0x65, 0x0f, 0x69, 0x0d, 0x6c,
+ 0x0b, 0x71, 0x09, 0x74, 0x08, 0x77, 0x07, 0x7b, 0x06, 0x7f, 0x05, 0x81,
+ 0x04, 0x83, 0x03, 0x86, 0x02, 0x8a, 0x02, 0x8c, 0x1e, 0x2a, 0x18, 0x32,
+ 0x12, 0x39, 0x0f, 0x40, 0x0c, 0x48, 0x09, 0x4f, 0x07, 0x55, 0x05, 0x5a,
+ 0x04, 0x60, 0x02, 0x66, 0x02, 0x6b, 0x01, 0x70, 0x00, 0x75, 0x00, 0x79,
+ 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8b, 0x07, 0x8e,
+ 0x06, 0x92, 0x04, 0x96, 0x03, 0x99, 0x02, 0x9b, 0x02, 0x9e, 0x01, 0xa1,
+ 0x01, 0xa4, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf,
+ 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3a, 0x45, 0x31, 0x49, 0x2a, 0x4d, 0x24, 0x52, 0x1f, 0x56, 0x1a, 0x5b,
+ 0x16, 0x5f, 0x13, 0x63, 0x10, 0x67, 0x0e, 0x6a, 0x0c, 0x6e, 0x0b, 0x72,
+ 0x09, 0x75, 0x07, 0x77, 0x07, 0x7b, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83,
+ 0x03, 0x85, 0x02, 0x89, 0x1e, 0x29, 0x18, 0x31, 0x13, 0x38, 0x0f, 0x3f,
+ 0x0c, 0x45, 0x0a, 0x4c, 0x07, 0x52, 0x05, 0x58, 0x04, 0x5d, 0x04, 0x63,
+ 0x02, 0x67, 0x01, 0x6c, 0x01, 0x71, 0x00, 0x75, 0x00, 0x79, 0x00, 0x7d,
+ 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00, 0x8b, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8a, 0x07, 0x8e, 0x06, 0x91, 0x05, 0x94,
+ 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d, 0x02, 0xa0, 0x01, 0xa2, 0x00, 0xa4,
+ 0x00, 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0,
+ 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x45, 0x32, 0x48,
+ 0x2b, 0x4d, 0x25, 0x51, 0x20, 0x55, 0x1b, 0x59, 0x18, 0x5e, 0x14, 0x60,
+ 0x12, 0x65, 0x0f, 0x68, 0x0d, 0x6b, 0x0c, 0x6f, 0x0a, 0x73, 0x09, 0x75,
+ 0x07, 0x77, 0x06, 0x7b, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85,
+ 0x1e, 0x29, 0x19, 0x30, 0x14, 0x37, 0x0f, 0x3d, 0x0c, 0x44, 0x0a, 0x4a,
+ 0x07, 0x50, 0x06, 0x55, 0x05, 0x5b, 0x04, 0x60, 0x02, 0x64, 0x02, 0x69,
+ 0x01, 0x6d, 0x01, 0x72, 0x00, 0x76, 0x00, 0x7a, 0x00, 0x7d, 0x00, 0x81,
+ 0x00, 0x83, 0x00, 0x87, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0c, 0x86,
+ 0x0a, 0x8a, 0x07, 0x8d, 0x06, 0x90, 0x05, 0x93, 0x03, 0x96, 0x03, 0x99,
+ 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0, 0x01, 0xa3, 0x00, 0xa5, 0x00, 0xa7,
+ 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb2,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3b, 0x45, 0x33, 0x48, 0x2c, 0x4d, 0x26, 0x4f,
+ 0x21, 0x55, 0x1c, 0x57, 0x19, 0x5c, 0x16, 0x5f, 0x13, 0x63, 0x10, 0x67,
+ 0x0e, 0x6a, 0x0c, 0x6c, 0x0b, 0x71, 0x0a, 0x73, 0x09, 0x76, 0x07, 0x78,
+ 0x06, 0x7c, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x1e, 0x28, 0x19, 0x2f,
+ 0x15, 0x35, 0x10, 0x3c, 0x0d, 0x42, 0x0b, 0x48, 0x09, 0x4e, 0x07, 0x53,
+ 0x05, 0x58, 0x04, 0x5d, 0x04, 0x62, 0x02, 0x66, 0x02, 0x6b, 0x01, 0x6f,
+ 0x00, 0x73, 0x00, 0x76, 0x00, 0x7a, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x83,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x08, 0x8c,
+ 0x06, 0x8f, 0x05, 0x92, 0x04, 0x95, 0x03, 0x98, 0x02, 0x9a, 0x02, 0x9d,
+ 0x02, 0x9f, 0x01, 0xa1, 0x01, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xa9,
+ 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x44, 0x33, 0x47, 0x2c, 0x4c, 0x27, 0x4f, 0x22, 0x54, 0x1e, 0x56,
+ 0x1a, 0x5a, 0x17, 0x5e, 0x14, 0x60, 0x12, 0x65, 0x10, 0x68, 0x0e, 0x6a,
+ 0x0c, 0x6e, 0x0b, 0x72, 0x09, 0x74, 0x08, 0x76, 0x07, 0x78, 0x06, 0x7c,
+ 0x06, 0x7f, 0x05, 0x81, 0x1e, 0x28, 0x19, 0x2f, 0x16, 0x35, 0x12, 0x3b,
+ 0x0f, 0x41, 0x0c, 0x46, 0x0a, 0x4c, 0x07, 0x51, 0x05, 0x55, 0x05, 0x5b,
+ 0x04, 0x5f, 0x02, 0x63, 0x02, 0x68, 0x01, 0x6b, 0x01, 0x70, 0x00, 0x73,
+ 0x00, 0x77, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x81, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0f, 0x82, 0x0c, 0x86, 0x0b, 0x89, 0x09, 0x8c, 0x07, 0x8f, 0x06, 0x91,
+ 0x05, 0x94, 0x03, 0x97, 0x02, 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0,
+ 0x01, 0xa2, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xac,
+ 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x23, 0x25, 0x22,
+ 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0x44, 0x05, 0x25, 0x0d, 0x23, 0x12, 0x22,
+ 0x15, 0x22, 0x17, 0x22, 0x18, 0x22, 0x1a, 0x22, 0x1b, 0x22, 0x1b, 0x22,
+ 0x1c, 0x22, 0x1c, 0x22, 0x1c, 0x22, 0x1d, 0x22, 0x1d, 0x22, 0x1e, 0x22,
+ 0x1e, 0x22, 0x1e, 0x22, 0x1e, 0x22, 0x1e, 0x22, 0x10, 0x33, 0x13, 0x23,
+ 0x17, 0x22, 0x1a, 0x22, 0x1b, 0x22, 0x1c, 0x22, 0x1d, 0x22, 0x1e, 0x22,
+ 0x1e, 0x22, 0x1e, 0x22, 0x1f, 0x22, 0x1f, 0x22, 0x1f, 0x22, 0x1f, 0x22,
+ 0x1f, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x35, 0x25, 0x2b, 0x23, 0x27, 0x22, 0x25, 0x22,
+ 0x24, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0x9d, 0x00, 0x6b, 0x01, 0x51, 0x04, 0x45, 0x08, 0x3d, 0x0b, 0x38,
+ 0x0d, 0x35, 0x0f, 0x33, 0x10, 0x30, 0x12, 0x2f, 0x13, 0x2d, 0x14, 0x2d,
+ 0x15, 0x2c, 0x16, 0x2b, 0x16, 0x2a, 0x17, 0x2a, 0x18, 0x29, 0x18, 0x29,
+ 0x19, 0x28, 0x19, 0x28, 0x10, 0x5f, 0x10, 0x46, 0x11, 0x39, 0x13, 0x33,
+ 0x15, 0x2f, 0x16, 0x2d, 0x17, 0x2b, 0x18, 0x2a, 0x19, 0x29, 0x1a, 0x28,
+ 0x1a, 0x27, 0x1b, 0x27, 0x1b, 0x27, 0x1c, 0x26, 0x1c, 0x26, 0x1c, 0x26,
+ 0x1d, 0x25, 0x1d, 0x25, 0x1d, 0x25, 0x1d, 0x25, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x2a, 0x2e, 0x26, 0x2a, 0x25, 0x27, 0x24, 0x26, 0x23, 0x25, 0x23,
+ 0x24, 0x23, 0x24, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xbc, 0x00, 0x8e,
+ 0x00, 0x73, 0x00, 0x60, 0x02, 0x55, 0x04, 0x4c, 0x06, 0x47, 0x08, 0x42,
+ 0x0a, 0x3e, 0x0c, 0x3b, 0x0d, 0x39, 0x0e, 0x37, 0x0f, 0x36, 0x10, 0x34,
+ 0x11, 0x33, 0x12, 0x32, 0x12, 0x31, 0x13, 0x30, 0x14, 0x2f, 0x15, 0x2f,
+ 0x10, 0x6f, 0x10, 0x58, 0x10, 0x4a, 0x11, 0x41, 0x12, 0x3b, 0x13, 0x37,
+ 0x14, 0x34, 0x15, 0x32, 0x16, 0x30, 0x17, 0x2e, 0x17, 0x2d, 0x18, 0x2c,
+ 0x18, 0x2c, 0x19, 0x2b, 0x19, 0x2a, 0x1a, 0x2a, 0x1a, 0x29, 0x1a, 0x29,
+ 0x1b, 0x28, 0x1b, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x2e, 0x31, 0x29,
+ 0x2c, 0x27, 0x2a, 0x26, 0x28, 0x25, 0x27, 0x24, 0x25, 0x24, 0x25, 0x23,
+ 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xc6, 0x00, 0xa4, 0x00, 0x89, 0x00, 0x77,
+ 0x00, 0x67, 0x01, 0x5e, 0x03, 0x55, 0x04, 0x50, 0x05, 0x4b, 0x07, 0x47,
+ 0x09, 0x44, 0x0a, 0x41, 0x0b, 0x3e, 0x0c, 0x3d, 0x0c, 0x3b, 0x0e, 0x39,
+ 0x0f, 0x38, 0x0f, 0x37, 0x0f, 0x35, 0x10, 0x35, 0x10, 0x74, 0x10, 0x63,
+ 0x10, 0x55, 0x10, 0x4c, 0x11, 0x44, 0x11, 0x40, 0x12, 0x3b, 0x13, 0x39,
+ 0x13, 0x36, 0x14, 0x34, 0x15, 0x33, 0x16, 0x31, 0x16, 0x30, 0x17, 0x2f,
+ 0x17, 0x2e, 0x18, 0x2d, 0x18, 0x2d, 0x18, 0x2c, 0x18, 0x2b, 0x19, 0x2b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0x31, 0x33, 0x2c, 0x2f, 0x29, 0x2b, 0x28,
+ 0x29, 0x26, 0x28, 0x25, 0x27, 0x25, 0x26, 0x24, 0x25, 0x24, 0x25, 0x24,
+ 0x25, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x23,
+ 0x23, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xcd, 0x00, 0xb0, 0x00, 0x9a, 0x00, 0x87, 0x00, 0x78, 0x00, 0x6c,
+ 0x01, 0x64, 0x02, 0x5c, 0x03, 0x57, 0x04, 0x51, 0x05, 0x4e, 0x07, 0x4a,
+ 0x07, 0x48, 0x09, 0x45, 0x0a, 0x43, 0x0a, 0x40, 0x0c, 0x3f, 0x0c, 0x3d,
+ 0x0c, 0x3c, 0x0d, 0x3b, 0x10, 0x77, 0x10, 0x69, 0x10, 0x5e, 0x10, 0x54,
+ 0x10, 0x4d, 0x11, 0x47, 0x11, 0x43, 0x12, 0x3f, 0x12, 0x3c, 0x13, 0x39,
+ 0x13, 0x38, 0x14, 0x36, 0x14, 0x35, 0x15, 0x33, 0x16, 0x32, 0x16, 0x31,
+ 0x17, 0x30, 0x17, 0x2f, 0x17, 0x2f, 0x17, 0x2e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x33, 0x34, 0x2e, 0x30, 0x2b, 0x2d, 0x29, 0x2b, 0x28, 0x29, 0x27,
+ 0x29, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x24, 0x25, 0x24, 0x25, 0x24,
+ 0x25, 0x24, 0x24, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xcf, 0x00, 0xb9,
+ 0x00, 0xa4, 0x00, 0x94, 0x00, 0x85, 0x00, 0x7a, 0x00, 0x70, 0x00, 0x68,
+ 0x01, 0x61, 0x02, 0x5c, 0x04, 0x57, 0x04, 0x53, 0x05, 0x50, 0x06, 0x4c,
+ 0x07, 0x4a, 0x07, 0x48, 0x09, 0x45, 0x0a, 0x44, 0x0a, 0x42, 0x0b, 0x41,
+ 0x10, 0x78, 0x10, 0x6d, 0x10, 0x63, 0x10, 0x5b, 0x10, 0x53, 0x10, 0x4e,
+ 0x11, 0x49, 0x11, 0x45, 0x11, 0x41, 0x12, 0x3f, 0x13, 0x3c, 0x13, 0x3a,
+ 0x13, 0x39, 0x14, 0x37, 0x14, 0x36, 0x14, 0x35, 0x15, 0x33, 0x16, 0x33,
+ 0x16, 0x32, 0x16, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x34, 0x36, 0x30,
+ 0x32, 0x2d, 0x2f, 0x2b, 0x2d, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27,
+ 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
+ 0x25, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xd2, 0x00, 0xbe, 0x00, 0xad, 0x00, 0x9d,
+ 0x00, 0x90, 0x00, 0x84, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x6b, 0x01, 0x65,
+ 0x02, 0x60, 0x02, 0x5b, 0x04, 0x58, 0x04, 0x54, 0x05, 0x51, 0x05, 0x4f,
+ 0x07, 0x4c, 0x07, 0x4a, 0x07, 0x48, 0x09, 0x46, 0x10, 0x7a, 0x10, 0x70,
+ 0x10, 0x67, 0x10, 0x5f, 0x10, 0x59, 0x10, 0x53, 0x10, 0x4e, 0x11, 0x4a,
+ 0x11, 0x46, 0x11, 0x43, 0x12, 0x41, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
+ 0x13, 0x39, 0x13, 0x38, 0x14, 0x37, 0x14, 0x36, 0x14, 0x35, 0x15, 0x34,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x35, 0x37, 0x31, 0x33, 0x2e, 0x30, 0x2c,
+ 0x2d, 0x2a, 0x2c, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27, 0x28, 0x27,
+ 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
+ 0x25, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xd3, 0x00, 0xc2, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x98, 0x00, 0x8d,
+ 0x00, 0x83, 0x00, 0x7b, 0x00, 0x73, 0x00, 0x6e, 0x01, 0x67, 0x01, 0x63,
+ 0x02, 0x5f, 0x02, 0x5b, 0x04, 0x58, 0x04, 0x55, 0x05, 0x52, 0x05, 0x50,
+ 0x06, 0x4e, 0x07, 0x4c, 0x10, 0x7a, 0x10, 0x72, 0x10, 0x6a, 0x10, 0x63,
+ 0x10, 0x5d, 0x10, 0x57, 0x10, 0x52, 0x10, 0x4e, 0x11, 0x4a, 0x11, 0x48,
+ 0x11, 0x44, 0x11, 0x42, 0x12, 0x40, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
+ 0x13, 0x3a, 0x13, 0x39, 0x14, 0x38, 0x14, 0x37, 0x0f, 0x00, 0x1f, 0x00,
+ 0x33, 0x00, 0x39, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
+ 0x3f, 0x00, 0x3f, 0x00, 0x0b, 0x3b, 0x17, 0x07, 0x2c, 0x00, 0x36, 0x00,
+ 0x3a, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x00,
+ 0x4c, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x42, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
+ 0x3f, 0x00, 0x3f, 0x00, 0x07, 0x47, 0x0f, 0x0f, 0x26, 0x00, 0x33, 0x00,
+ 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00,
+ 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
+ 0x3c, 0x37, 0x37, 0x32, 0x34, 0x30, 0x31, 0x2d, 0x2f, 0x2c, 0x2d, 0x2b,
+ 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27, 0x28, 0x27, 0x27, 0x26,
+ 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
+ 0x25, 0x24, 0x24, 0x24, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd5, 0x00, 0xc5,
+ 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x9f, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x83,
+ 0x00, 0x7c, 0x00, 0x75, 0x00, 0x6f, 0x00, 0x69, 0x01, 0x66, 0x02, 0x61,
+ 0x02, 0x5e, 0x03, 0x5a, 0x04, 0x58, 0x04, 0x55, 0x05, 0x53, 0x05, 0x51,
+ 0x10, 0x7b, 0x10, 0x73, 0x10, 0x6c, 0x10, 0x66, 0x10, 0x60, 0x10, 0x5b,
+ 0x10, 0x56, 0x10, 0x52, 0x10, 0x4f, 0x11, 0x4b, 0x11, 0x48, 0x11, 0x45,
+ 0x11, 0x44, 0x12, 0x41, 0x12, 0x40, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
+ 0x13, 0x3a, 0x13, 0x39, 0x00, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x2e, 0x00,
+ 0x35, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00,
+ 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x00, 0x6f, 0x02, 0x27, 0x12, 0x02, 0x25, 0x00, 0x2f, 0x00, 0x35, 0x00,
+ 0x38, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00,
+ 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x39, 0x00, 0x42, 0x00,
+ 0x41, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00,
+ 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x00, 0x7f, 0x00, 0x3f, 0x05, 0x05, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00,
+ 0x35, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00,
+ 0x3d, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3c, 0x37, 0x38, 0x33,
+ 0x34, 0x31, 0x32, 0x2f, 0x30, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x29,
+ 0x2b, 0x28, 0x29, 0x28, 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x25,
+ 0x27, 0x25, 0x27, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xd5, 0x00, 0xc8, 0x00, 0xbb, 0x00, 0xaf,
+ 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x92, 0x00, 0x8a, 0x00, 0x82, 0x00, 0x7c,
+ 0x00, 0x76, 0x00, 0x70, 0x00, 0x6c, 0x01, 0x67, 0x01, 0x64, 0x02, 0x60,
+ 0x02, 0x5d, 0x04, 0x5b, 0x04, 0x58, 0x04, 0x55, 0x10, 0x7b, 0x10, 0x75,
+ 0x10, 0x6e, 0x10, 0x68, 0x10, 0x63, 0x10, 0x5e, 0x10, 0x5a, 0x10, 0x56,
+ 0x10, 0x52, 0x10, 0x4f, 0x11, 0x4c, 0x11, 0x49, 0x11, 0x47, 0x11, 0x44,
+ 0x11, 0x43, 0x12, 0x41, 0x12, 0x3f, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16, 0x00, 0x24, 0x00, 0x2c, 0x00,
+ 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00,
+ 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0x9f, 0x00, 0x6f,
+ 0x00, 0x22, 0x0b, 0x09, 0x16, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00,
+ 0x33, 0x00, 0x35, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00,
+ 0x3b, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x39, 0x00, 0x16, 0x00, 0x28, 0x00, 0x2f, 0x00, 0x2e, 0x00,
+ 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00,
+ 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0xa5, 0x00, 0x7f,
+ 0x00, 0x3f, 0x00, 0x12, 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00,
+ 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00,
+ 0x3a, 0x00, 0x3a, 0x00, 0x3d, 0x38, 0x39, 0x34, 0x35, 0x32, 0x33, 0x30,
+ 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2b, 0x2c, 0x2b, 0x2b, 0x29, 0x2b, 0x28,
+ 0x29, 0x28, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25,
+ 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x25, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xd6, 0x00, 0xca, 0x00, 0xbe, 0x00, 0xb3, 0x00, 0xaa, 0x00, 0xa0,
+ 0x00, 0x98, 0x00, 0x90, 0x00, 0x88, 0x00, 0x82, 0x00, 0x7d, 0x00, 0x77,
+ 0x00, 0x71, 0x00, 0x6d, 0x01, 0x69, 0x01, 0x66, 0x02, 0x63, 0x02, 0x60,
+ 0x02, 0x5d, 0x04, 0x5b, 0x10, 0x7c, 0x10, 0x76, 0x10, 0x70, 0x10, 0x6a,
+ 0x10, 0x65, 0x10, 0x61, 0x10, 0x5d, 0x10, 0x59, 0x10, 0x55, 0x10, 0x52,
+ 0x10, 0x4f, 0x11, 0x4c, 0x11, 0x49, 0x11, 0x47, 0x11, 0x45, 0x11, 0x44,
+ 0x12, 0x42, 0x12, 0x41, 0x12, 0x3f, 0x13, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, 0x00,
+ 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00,
+ 0x39, 0x00, 0x3a, 0x00, 0x00, 0xaf, 0x00, 0x93, 0x00, 0x58, 0x00, 0x21,
+ 0x08, 0x0e, 0x0e, 0x02, 0x18, 0x00, 0x20, 0x00, 0x27, 0x00, 0x2b, 0x00,
+ 0x2f, 0x00, 0x31, 0x00, 0x33, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x42, 0x00,
+ 0x28, 0x00, 0x09, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, 0x00,
+ 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00,
+ 0x39, 0x00, 0x3a, 0x00, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f,
+ 0x00, 0x1d, 0x00, 0x05, 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00,
+ 0x29, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00,
+ 0x3d, 0x38, 0x39, 0x35, 0x36, 0x33, 0x33, 0x30, 0x31, 0x2f, 0x30, 0x2d,
+ 0x2e, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x2b, 0x28, 0x28, 0x28,
+ 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25,
+ 0x27, 0x25, 0x25, 0x25, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd6, 0x00, 0xcc,
+ 0x00, 0xc0, 0x00, 0xb7, 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9d, 0x00, 0x96,
+ 0x00, 0x8f, 0x00, 0x88, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x77, 0x00, 0x73,
+ 0x00, 0x6f, 0x00, 0x6b, 0x01, 0x67, 0x01, 0x64, 0x02, 0x62, 0x02, 0x5f,
+ 0x10, 0x7c, 0x10, 0x77, 0x10, 0x71, 0x10, 0x6c, 0x10, 0x67, 0x10, 0x63,
+ 0x10, 0x5f, 0x10, 0x5c, 0x10, 0x58, 0x10, 0x55, 0x10, 0x51, 0x10, 0x4f,
+ 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x48, 0x11, 0x46, 0x11, 0x44, 0x11, 0x43,
+ 0x12, 0x42, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a, 0x00,
+ 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37, 0x00,
+ 0x00, 0xb5, 0x00, 0xa4, 0x00, 0x7a, 0x00, 0x4a, 0x00, 0x20, 0x06, 0x12,
+ 0x0c, 0x07, 0x10, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x24, 0x00, 0x28, 0x00,
+ 0x2c, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a, 0x00,
+ 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37, 0x00,
+ 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24,
+ 0x00, 0x0f, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00,
+ 0x25, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2e, 0x00, 0x3d, 0x39, 0x3a, 0x36,
+ 0x36, 0x33, 0x34, 0x31, 0x32, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2b,
+ 0x2d, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x27,
+ 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x25, 0x27, 0x25,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xd7, 0x00, 0xcc, 0x00, 0xc3, 0x00, 0xba,
+ 0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa0, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8d,
+ 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x74, 0x00, 0x70,
+ 0x00, 0x6c, 0x01, 0x69, 0x01, 0x66, 0x02, 0x63, 0x10, 0x7c, 0x10, 0x77,
+ 0x10, 0x72, 0x10, 0x6e, 0x10, 0x69, 0x10, 0x65, 0x10, 0x61, 0x10, 0x5d,
+ 0x10, 0x5a, 0x10, 0x57, 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d,
+ 0x11, 0x4b, 0x11, 0x49, 0x11, 0x47, 0x11, 0x45, 0x11, 0x44, 0x12, 0x42,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00,
+ 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0xb9, 0x00, 0xad,
+ 0x00, 0x8f, 0x00, 0x68, 0x00, 0x42, 0x00, 0x20, 0x05, 0x14, 0x0a, 0x0b,
+ 0x0d, 0x04, 0x12, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x23, 0x00, 0x26, 0x00,
+ 0x29, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x00, 0x3d, 0x00, 0x2e, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00,
+ 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0xba, 0x00, 0xb1,
+ 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16,
+ 0x00, 0x08, 0x02, 0x00, 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00,
+ 0x22, 0x00, 0x25, 0x00, 0x3d, 0x39, 0x3a, 0x36, 0x37, 0x34, 0x35, 0x32,
+ 0x33, 0x30, 0x31, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2a, 0x2c, 0x2b,
+ 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27,
+ 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x26, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xd7, 0x00, 0xce, 0x00, 0xc5, 0x00, 0xbc, 0x00, 0xb4, 0x00, 0xac,
+ 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x91, 0x00, 0x8c, 0x00, 0x87,
+ 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x75, 0x00, 0x71, 0x00, 0x6d,
+ 0x01, 0x6b, 0x01, 0x68, 0x10, 0x7c, 0x10, 0x78, 0x10, 0x73, 0x10, 0x6f,
+ 0x10, 0x6b, 0x10, 0x67, 0x10, 0x63, 0x10, 0x60, 0x10, 0x5c, 0x10, 0x59,
+ 0x10, 0x57, 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4b,
+ 0x11, 0x49, 0x11, 0x47, 0x11, 0x46, 0x11, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29, 0x00,
+ 0x2b, 0x00, 0x2d, 0x00, 0x00, 0xba, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x7d,
+ 0x00, 0x5c, 0x00, 0x3c, 0x00, 0x20, 0x04, 0x16, 0x08, 0x0e, 0x0c, 0x07,
+ 0x0e, 0x02, 0x13, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x25, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3a, 0x00,
+ 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29, 0x00,
+ 0x2b, 0x00, 0x2d, 0x00, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a,
+ 0x00, 0x6f, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f,
+ 0x00, 0x04, 0x04, 0x00, 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00,
+ 0x3d, 0x39, 0x3a, 0x36, 0x37, 0x34, 0x35, 0x33, 0x33, 0x30, 0x32, 0x30,
+ 0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2c, 0x2d, 0x2a, 0x2c, 0x2b, 0x2b, 0x2a,
+ 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27,
+ 0x27, 0x27, 0x27, 0x27, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd8, 0x00, 0xcf,
+ 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb6, 0x00, 0xaf, 0x00, 0xa8, 0x00, 0xa1,
+ 0x00, 0x9c, 0x00, 0x96, 0x00, 0x90, 0x00, 0x8a, 0x00, 0x86, 0x00, 0x81,
+ 0x00, 0x7d, 0x00, 0x79, 0x00, 0x75, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6b,
+ 0x10, 0x7d, 0x10, 0x78, 0x10, 0x74, 0x10, 0x70, 0x10, 0x6c, 0x10, 0x68,
+ 0x10, 0x65, 0x10, 0x61, 0x10, 0x5f, 0x10, 0x5c, 0x10, 0x59, 0x10, 0x56,
+ 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x4a,
+ 0x11, 0x48, 0x11, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
+ 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28, 0x00,
+ 0x00, 0xbc, 0x00, 0xb5, 0x00, 0xa4, 0x00, 0x8b, 0x00, 0x6f, 0x00, 0x52,
+ 0x00, 0x37, 0x00, 0x20, 0x04, 0x17, 0x07, 0x10, 0x0a, 0x0a, 0x0d, 0x05,
+ 0x0f, 0x00, 0x14, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00,
+ 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
+ 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28, 0x00,
+ 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68,
+ 0x00, 0x53, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a,
+ 0x00, 0x01, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x3d, 0x3a, 0x3a, 0x37,
+ 0x38, 0x35, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30, 0x30, 0x2f, 0x30, 0x2d,
+ 0x2e, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28,
+ 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x29, 0x27, 0x27, 0x27,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xd8, 0x00, 0xd0, 0x00, 0xc8, 0x00, 0xc0,
+ 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa5, 0x00, 0x9f, 0x00, 0x99,
+ 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8a, 0x00, 0x86, 0x00, 0x81, 0x00, 0x7d,
+ 0x00, 0x79, 0x00, 0x76, 0x00, 0x73, 0x00, 0x70, 0x10, 0x7d, 0x10, 0x79,
+ 0x10, 0x75, 0x10, 0x71, 0x10, 0x6d, 0x10, 0x6a, 0x10, 0x66, 0x10, 0x63,
+ 0x10, 0x60, 0x10, 0x5d, 0x10, 0x5b, 0x10, 0x58, 0x10, 0x56, 0x10, 0x54,
+ 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x49,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00,
+ 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0xbc, 0x00, 0xb8,
+ 0x00, 0xaa, 0x00, 0x96, 0x00, 0x7e, 0x00, 0x64, 0x00, 0x4c, 0x00, 0x34,
+ 0x00, 0x20, 0x03, 0x18, 0x06, 0x11, 0x09, 0x0c, 0x0c, 0x07, 0x0e, 0x03,
+ 0x10, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b, 0x00,
+ 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00,
+ 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0xbd, 0x00, 0xb9,
+ 0x00, 0xae, 0x00, 0x9e, 0x00, 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50,
+ 0x00, 0x3f, 0x00, 0x30, 0x00, 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06,
+ 0x00, 0x00, 0x07, 0x00, 0x3d, 0x3a, 0x3a, 0x38, 0x38, 0x36, 0x36, 0x33,
+ 0x34, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2d,
+ 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x28, 0x27, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xd9, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc2, 0x00, 0xbb, 0x00, 0xb4,
+ 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa2, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x92,
+ 0x00, 0x8e, 0x00, 0x89, 0x00, 0x85, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7a,
+ 0x00, 0x76, 0x00, 0x73, 0x10, 0x7d, 0x10, 0x79, 0x10, 0x75, 0x10, 0x72,
+ 0x10, 0x6e, 0x10, 0x6b, 0x10, 0x68, 0x10, 0x65, 0x10, 0x62, 0x10, 0x5f,
+ 0x10, 0x5c, 0x10, 0x5a, 0x10, 0x58, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51,
+ 0x10, 0x4f, 0x11, 0x4e, 0x11, 0x4c, 0x11, 0x4a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16, 0x00,
+ 0x1a, 0x00, 0x1d, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9d,
+ 0x00, 0x89, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x46, 0x00, 0x32, 0x00, 0x20,
+ 0x03, 0x19, 0x06, 0x13, 0x08, 0x0e, 0x0b, 0x09, 0x0d, 0x05, 0x0e, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00,
+ 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16, 0x00,
+ 0x1a, 0x00, 0x1d, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4,
+ 0x00, 0x94, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f,
+ 0x00, 0x32, 0x00, 0x26, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03,
+ 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x36, 0x34, 0x35, 0x33, 0x33, 0x31,
+ 0x32, 0x30, 0x30, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2c, 0x2d, 0x2a,
+ 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd9, 0x00, 0xd1,
+ 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xaa,
+ 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x91, 0x00, 0x8d,
+ 0x00, 0x89, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x77,
+ 0x10, 0x7d, 0x10, 0x79, 0x10, 0x76, 0x10, 0x72, 0x10, 0x6f, 0x10, 0x6c,
+ 0x10, 0x69, 0x10, 0x66, 0x10, 0x63, 0x10, 0x61, 0x10, 0x5e, 0x10, 0x5c,
+ 0x10, 0x59, 0x10, 0x57, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51, 0x10, 0x4f,
+ 0x11, 0x4e, 0x11, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00,
+ 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa3, 0x00, 0x92, 0x00, 0x7e,
+ 0x00, 0x6a, 0x00, 0x56, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x03, 0x19,
+ 0x05, 0x14, 0x08, 0x0f, 0x0a, 0x0b, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34, 0x00,
+ 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00,
+ 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b,
+ 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33,
+ 0x00, 0x28, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0e, 0x3d, 0x3b, 0x3b, 0x39,
+ 0x3a, 0x36, 0x36, 0x35, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30, 0x30, 0x30,
+ 0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xcb, 0x00, 0xc4,
+ 0x00, 0xbe, 0x00, 0xb8, 0x00, 0xb2, 0x00, 0xad, 0x00, 0xa8, 0x00, 0xa2,
+ 0x00, 0x9d, 0x00, 0x99, 0x00, 0x94, 0x00, 0x90, 0x00, 0x8b, 0x00, 0x88,
+ 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7b, 0x10, 0x7d, 0x10, 0x7a,
+ 0x10, 0x76, 0x10, 0x73, 0x10, 0x70, 0x10, 0x6d, 0x10, 0x6a, 0x10, 0x67,
+ 0x10, 0x65, 0x10, 0x62, 0x10, 0x5f, 0x10, 0x5d, 0x10, 0x5b, 0x10, 0x59,
+ 0x10, 0x56, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0xbd, 0x00, 0xbb,
+ 0x00, 0xb3, 0x00, 0xa8, 0x00, 0x99, 0x00, 0x87, 0x00, 0x75, 0x00, 0x62,
+ 0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x02, 0x1a, 0x05, 0x15,
+ 0x07, 0x10, 0x09, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00,
+ 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0xbe, 0x00, 0xbc,
+ 0x00, 0xb6, 0x00, 0xac, 0x00, 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75,
+ 0x00, 0x66, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a,
+ 0x00, 0x21, 0x00, 0x19, 0x3d, 0x3b, 0x3b, 0x39, 0x39, 0x36, 0x37, 0x35,
+ 0x36, 0x33, 0x33, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2f, 0x30, 0x2d,
+ 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcc, 0x00, 0xc6, 0x00, 0xc0, 0x00, 0xba,
+ 0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9b,
+ 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x00, 0x8b, 0x00, 0x88, 0x00, 0x83,
+ 0x00, 0x81, 0x00, 0x7d, 0x10, 0x7d, 0x10, 0x7a, 0x10, 0x77, 0x10, 0x74,
+ 0x10, 0x71, 0x10, 0x6e, 0x10, 0x6b, 0x10, 0x68, 0x10, 0x65, 0x10, 0x63,
+ 0x10, 0x61, 0x10, 0x5e, 0x10, 0x5c, 0x10, 0x5a, 0x10, 0x58, 0x10, 0x56,
+ 0x10, 0x55, 0x10, 0x52, 0x10, 0x51, 0x10, 0x4f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x09, 0x00, 0x0d, 0x00, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xab,
+ 0x00, 0x9e, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c,
+ 0x00, 0x3c, 0x00, 0x2d, 0x00, 0x1f, 0x02, 0x1a, 0x04, 0x16, 0x06, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+ 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f, 0x00,
+ 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x09, 0x00, 0x0d, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf,
+ 0x00, 0xa5, 0x00, 0x99, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63,
+ 0x00, 0x56, 0x00, 0x4a, 0x00, 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23,
+ 0x27, 0x76, 0x1a, 0x79, 0x16, 0x7b, 0x15, 0x7c, 0x14, 0x7c, 0x13, 0x7d,
+ 0x13, 0x7d, 0x13, 0x7d, 0x12, 0x7d, 0x12, 0x7d, 0x12, 0x7e, 0x12, 0x7e,
+ 0x12, 0x7e, 0x12, 0x7e, 0x12, 0x7e, 0x11, 0x7e, 0x11, 0x7e, 0x11, 0x7e,
+ 0x11, 0x7f, 0x11, 0x7f, 0x13, 0x5f, 0x10, 0x6f, 0x10, 0x74, 0x10, 0x77,
+ 0x10, 0x78, 0x10, 0x7a, 0x10, 0x7a, 0x10, 0x7b, 0x10, 0x7b, 0x10, 0x7c,
+ 0x10, 0x7c, 0x10, 0x7c, 0x10, 0x7c, 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d,
+ 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d, 0x00, 0x90, 0x02, 0x81,
+ 0x06, 0x80, 0x09, 0x7f, 0x0a, 0x7f, 0x0b, 0x7f, 0x0c, 0x7f, 0x0d, 0x7f,
+ 0x0d, 0x7f, 0x0d, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f,
+ 0x0e, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00,
+ 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x95,
+ 0x00, 0x86, 0x00, 0x77, 0x00, 0x67, 0x00, 0x57, 0x00, 0x48, 0x00, 0x3a,
+ 0x00, 0x2c, 0x00, 0x1f, 0x02, 0x1b, 0x04, 0x16, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00,
+ 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16, 0x00,
+ 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00,
+ 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d,
+ 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54,
+ 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2d, 0x32, 0x5f, 0x25, 0x68,
+ 0x1f, 0x6d, 0x1c, 0x71, 0x19, 0x72, 0x18, 0x74, 0x17, 0x76, 0x16, 0x77,
+ 0x16, 0x77, 0x15, 0x78, 0x15, 0x79, 0x15, 0x79, 0x14, 0x7a, 0x14, 0x7a,
+ 0x13, 0x7a, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b,
+ 0x17, 0x46, 0x11, 0x58, 0x10, 0x63, 0x10, 0x69, 0x10, 0x6d, 0x10, 0x70,
+ 0x10, 0x72, 0x10, 0x73, 0x10, 0x75, 0x10, 0x76, 0x10, 0x77, 0x10, 0x77,
+ 0x10, 0x78, 0x10, 0x78, 0x10, 0x79, 0x10, 0x79, 0x10, 0x79, 0x10, 0x7a,
+ 0x10, 0x7a, 0x10, 0x7a, 0x00, 0xbd, 0x00, 0xa4, 0x00, 0x97, 0x02, 0x91,
+ 0x04, 0x8d, 0x05, 0x8a, 0x06, 0x89, 0x07, 0x88, 0x08, 0x86, 0x09, 0x86,
+ 0x09, 0x85, 0x0a, 0x85, 0x0a, 0x84, 0x0b, 0x84, 0x0b, 0x83, 0x0b, 0x83,
+ 0x0c, 0x83, 0x0c, 0x83, 0x0c, 0x82, 0x0c, 0x82, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x00, 0xbc,
+ 0x00, 0xb8, 0x00, 0xb0, 0x00, 0xa6, 0x00, 0x9a, 0x00, 0x8d, 0x00, 0x7f,
+ 0x00, 0x70, 0x00, 0x61, 0x00, 0x53, 0x00, 0x45, 0x00, 0x38, 0x00, 0x2b,
+ 0x00, 0x1f, 0x02, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31, 0x00,
+ 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f, 0x00,
+ 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x00, 0xbd,
+ 0x00, 0xb9, 0x00, 0xb3, 0x00, 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b,
+ 0x00, 0x80, 0x00, 0x74, 0x00, 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49,
+ 0x00, 0x3f, 0x00, 0x36, 0x36, 0x56, 0x2a, 0x5f, 0x24, 0x65, 0x20, 0x68,
+ 0x1e, 0x6c, 0x1c, 0x6e, 0x1b, 0x70, 0x19, 0x71, 0x18, 0x72, 0x18, 0x73,
+ 0x18, 0x75, 0x17, 0x75, 0x16, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15, 0x77,
+ 0x15, 0x77, 0x15, 0x77, 0x15, 0x78, 0x15, 0x79, 0x1a, 0x39, 0x13, 0x4a,
+ 0x11, 0x55, 0x10, 0x5e, 0x10, 0x63, 0x10, 0x67, 0x10, 0x6a, 0x10, 0x6c,
+ 0x10, 0x6e, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72, 0x10, 0x73, 0x10, 0x74,
+ 0x10, 0x75, 0x10, 0x75, 0x10, 0x76, 0x10, 0x76, 0x10, 0x77, 0x10, 0x77,
+ 0x00, 0xcc, 0x00, 0xb5, 0x00, 0xa8, 0x00, 0x9e, 0x01, 0x99, 0x02, 0x94,
+ 0x03, 0x92, 0x04, 0x8f, 0x05, 0x8d, 0x06, 0x8c, 0x06, 0x8b, 0x07, 0x8a,
+ 0x07, 0x89, 0x08, 0x88, 0x08, 0x88, 0x09, 0x87, 0x09, 0x87, 0x09, 0x86,
+ 0x0a, 0x86, 0x0a, 0x86, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb2,
+ 0x00, 0xa9, 0x00, 0x9e, 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6a,
+ 0x00, 0x5c, 0x00, 0x4f, 0x00, 0x42, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+ 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28, 0x00,
+ 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4,
+ 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b,
+ 0x00, 0x70, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f,
+ 0x38, 0x52, 0x2e, 0x59, 0x28, 0x5f, 0x24, 0x63, 0x22, 0x67, 0x1f, 0x69,
+ 0x1e, 0x6b, 0x1c, 0x6d, 0x1b, 0x6e, 0x1a, 0x70, 0x1a, 0x71, 0x19, 0x72,
+ 0x18, 0x72, 0x18, 0x72, 0x18, 0x73, 0x17, 0x75, 0x17, 0x76, 0x16, 0x76,
+ 0x15, 0x76, 0x15, 0x76, 0x1b, 0x33, 0x15, 0x41, 0x12, 0x4c, 0x11, 0x54,
+ 0x10, 0x5b, 0x10, 0x5f, 0x10, 0x63, 0x10, 0x66, 0x10, 0x68, 0x10, 0x6a,
+ 0x10, 0x6c, 0x10, 0x6e, 0x10, 0x6f, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72,
+ 0x10, 0x72, 0x10, 0x73, 0x10, 0x74, 0x10, 0x74, 0x00, 0xd1, 0x00, 0xc0,
+ 0x00, 0xb3, 0x00, 0xaa, 0x00, 0xa2, 0x00, 0x9d, 0x01, 0x99, 0x02, 0x96,
+ 0x02, 0x94, 0x03, 0x92, 0x04, 0x90, 0x05, 0x8f, 0x05, 0x8d, 0x06, 0x8d,
+ 0x06, 0x8c, 0x07, 0x8b, 0x07, 0x8a, 0x07, 0x8a, 0x07, 0x89, 0x08, 0x89,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x47, 0x0f, 0x0f, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a, 0x00,
+ 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x47, 0x00, 0x7f, 0x00, 0xa5, 0x00, 0xb2,
+ 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd,
+ 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x4f, 0x31, 0x55,
+ 0x2b, 0x5b, 0x27, 0x5f, 0x24, 0x63, 0x22, 0x65, 0x20, 0x68, 0x1f, 0x69,
+ 0x1d, 0x6b, 0x1d, 0x6d, 0x1b, 0x6d, 0x1a, 0x6e, 0x1a, 0x6f, 0x1a, 0x71,
+ 0x19, 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x73, 0x18, 0x74,
+ 0x1c, 0x2f, 0x16, 0x3b, 0x13, 0x44, 0x11, 0x4d, 0x11, 0x53, 0x10, 0x59,
+ 0x10, 0x5d, 0x10, 0x60, 0x10, 0x63, 0x10, 0x65, 0x10, 0x67, 0x10, 0x69,
+ 0x10, 0x6b, 0x10, 0x6c, 0x10, 0x6d, 0x10, 0x6e, 0x10, 0x6f, 0x10, 0x70,
+ 0x10, 0x71, 0x10, 0x71, 0x00, 0xd5, 0x00, 0xc6, 0x00, 0xbb, 0x00, 0xb2,
+ 0x00, 0xaa, 0x00, 0xa4, 0x00, 0xa0, 0x01, 0x9c, 0x01, 0x9a, 0x02, 0x97,
+ 0x02, 0x95, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91, 0x05, 0x90, 0x05, 0x8e,
+ 0x06, 0x8e, 0x06, 0x8d, 0x06, 0x8c, 0x06, 0x8c, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x3f,
+ 0x05, 0x05, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38, 0x00,
+ 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00,
+ 0x3d, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0f, 0x0f, 0x00, 0x3f, 0x00, 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1,
+ 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc,
+ 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0x4c, 0x33, 0x53, 0x2e, 0x58, 0x29, 0x5c,
+ 0x27, 0x5f, 0x24, 0x62, 0x22, 0x64, 0x20, 0x66, 0x20, 0x68, 0x1e, 0x69,
+ 0x1d, 0x6a, 0x1d, 0x6c, 0x1c, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x1a, 0x6f,
+ 0x1a, 0x71, 0x19, 0x72, 0x18, 0x72, 0x18, 0x72, 0x1d, 0x2d, 0x17, 0x37,
+ 0x14, 0x40, 0x12, 0x47, 0x11, 0x4e, 0x11, 0x53, 0x10, 0x57, 0x10, 0x5b,
+ 0x10, 0x5e, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x67, 0x10, 0x68,
+ 0x10, 0x6a, 0x10, 0x6b, 0x10, 0x6c, 0x10, 0x6d, 0x10, 0x6e, 0x10, 0x6f,
+ 0x00, 0xd6, 0x00, 0xcb, 0x00, 0xc0, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xab,
+ 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9f, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x98,
+ 0x02, 0x96, 0x03, 0x94, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91, 0x05, 0x90,
+ 0x05, 0x8f, 0x05, 0x8f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12,
+ 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32, 0x00,
+ 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x05, 0x05,
+ 0x00, 0x3f, 0x00, 0x6d, 0x00, 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa,
+ 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8,
+ 0x00, 0xb9, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x4b, 0x34, 0x51, 0x2f, 0x55, 0x2c, 0x59, 0x29, 0x5c, 0x26, 0x60,
+ 0x24, 0x61, 0x23, 0x64, 0x21, 0x65, 0x20, 0x67, 0x1f, 0x69, 0x1d, 0x69,
+ 0x1d, 0x6a, 0x1d, 0x6c, 0x1c, 0x6d, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d,
+ 0x1a, 0x6f, 0x1a, 0x71, 0x1e, 0x2b, 0x18, 0x34, 0x15, 0x3b, 0x13, 0x43,
+ 0x12, 0x49, 0x11, 0x4e, 0x11, 0x52, 0x10, 0x56, 0x10, 0x5a, 0x10, 0x5d,
+ 0x10, 0x5f, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x66, 0x10, 0x68,
+ 0x10, 0x69, 0x10, 0x6a, 0x10, 0x6b, 0x10, 0x6c, 0x00, 0xd7, 0x00, 0xcd,
+ 0x00, 0xc5, 0x00, 0xbd, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xab, 0x00, 0xa7,
+ 0x00, 0xa4, 0x00, 0xa1, 0x01, 0x9e, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x98,
+ 0x02, 0x97, 0x02, 0x96, 0x03, 0x94, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05,
+ 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00,
+ 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1c, 0x00, 0x00, 0x12, 0x00, 0x3f,
+ 0x00, 0x62, 0x00, 0x7a, 0x00, 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4,
+ 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x49, 0x36, 0x4f,
+ 0x31, 0x54, 0x2d, 0x57, 0x2a, 0x5a, 0x28, 0x5c, 0x26, 0x60, 0x24, 0x61,
+ 0x23, 0x64, 0x21, 0x65, 0x20, 0x65, 0x20, 0x68, 0x1e, 0x69, 0x1d, 0x69,
+ 0x1d, 0x69, 0x1d, 0x6b, 0x1c, 0x6d, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d,
+ 0x1e, 0x2a, 0x19, 0x32, 0x16, 0x39, 0x13, 0x3f, 0x12, 0x45, 0x11, 0x4a,
+ 0x11, 0x4e, 0x11, 0x52, 0x10, 0x56, 0x10, 0x59, 0x10, 0x5c, 0x10, 0x5d,
+ 0x10, 0x60, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x66, 0x10, 0x67,
+ 0x10, 0x68, 0x10, 0x69, 0x00, 0xd8, 0x00, 0xcf, 0x00, 0xc7, 0x00, 0xc0,
+ 0x00, 0xba, 0x00, 0xb5, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa8, 0x00, 0xa5,
+ 0x00, 0xa2, 0x00, 0xa0, 0x01, 0x9e, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x99,
+ 0x02, 0x97, 0x02, 0x96, 0x03, 0x95, 0x03, 0x94, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa,
+ 0x00, 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00,
+ 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00,
+ 0x2b, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x2a, 0x00, 0x09, 0x00, 0x00, 0x1d, 0x00, 0x3f, 0x00, 0x5b,
+ 0x00, 0x6f, 0x00, 0x7f, 0x00, 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0,
+ 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xad, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x48, 0x37, 0x4d, 0x32, 0x51, 0x2f, 0x55,
+ 0x2c, 0x58, 0x29, 0x5b, 0x27, 0x5d, 0x26, 0x60, 0x24, 0x60, 0x23, 0x63,
+ 0x22, 0x65, 0x20, 0x65, 0x20, 0x66, 0x1f, 0x68, 0x1e, 0x69, 0x1d, 0x69,
+ 0x1d, 0x69, 0x1d, 0x6b, 0x1c, 0x6d, 0x1b, 0x6d, 0x1e, 0x29, 0x1a, 0x30,
+ 0x17, 0x36, 0x14, 0x3c, 0x13, 0x41, 0x12, 0x46, 0x11, 0x4a, 0x11, 0x4f,
+ 0x11, 0x52, 0x10, 0x55, 0x10, 0x58, 0x10, 0x5a, 0x10, 0x5c, 0x10, 0x5f,
+ 0x10, 0x60, 0x10, 0x62, 0x10, 0x63, 0x10, 0x65, 0x10, 0x65, 0x10, 0x67,
+ 0x00, 0xd9, 0x00, 0xd1, 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xb9,
+ 0x00, 0xb4, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa3,
+ 0x00, 0xa1, 0x01, 0x9f, 0x01, 0x9d, 0x01, 0x9b, 0x02, 0x9a, 0x02, 0x99,
+ 0x02, 0x98, 0x02, 0x97, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a,
+ 0x00, 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16, 0x00, 0x08, 0x02, 0x00,
+ 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x31, 0x00,
+ 0x19, 0x00, 0x00, 0x05, 0x00, 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68,
+ 0x00, 0x77, 0x00, 0x82, 0x00, 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d,
+ 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x48, 0x37, 0x4c, 0x33, 0x50, 0x30, 0x54, 0x2d, 0x57, 0x2a, 0x59,
+ 0x29, 0x5c, 0x27, 0x5d, 0x26, 0x60, 0x24, 0x60, 0x23, 0x62, 0x22, 0x65,
+ 0x20, 0x65, 0x20, 0x65, 0x20, 0x67, 0x1f, 0x69, 0x1d, 0x69, 0x1d, 0x69,
+ 0x1d, 0x69, 0x1d, 0x6a, 0x1f, 0x28, 0x1a, 0x2e, 0x17, 0x34, 0x15, 0x39,
+ 0x13, 0x3f, 0x13, 0x43, 0x12, 0x48, 0x11, 0x4b, 0x11, 0x4f, 0x11, 0x52,
+ 0x10, 0x55, 0x10, 0x57, 0x10, 0x59, 0x10, 0x5c, 0x10, 0x5d, 0x10, 0x5f,
+ 0x10, 0x61, 0x10, 0x62, 0x10, 0x63, 0x10, 0x64, 0x00, 0xd9, 0x00, 0xd2,
+ 0x00, 0xcc, 0x00, 0xc6, 0x00, 0xc1, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xb3,
+ 0x00, 0xaf, 0x00, 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa2,
+ 0x00, 0xa0, 0x01, 0x9e, 0x01, 0x9d, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56,
+ 0x00, 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x04, 0x00,
+ 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x00,
+ 0x00, 0x0f, 0x00, 0x29, 0x00, 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70,
+ 0x00, 0x7b, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x38, 0x4b,
+ 0x34, 0x4f, 0x31, 0x53, 0x2e, 0x55, 0x2c, 0x57, 0x2a, 0x5a, 0x28, 0x5c,
+ 0x27, 0x5d, 0x26, 0x60, 0x23, 0x60, 0x23, 0x61, 0x23, 0x64, 0x21, 0x65,
+ 0x20, 0x65, 0x20, 0x65, 0x20, 0x68, 0x1e, 0x69, 0x1d, 0x69, 0x1d, 0x69,
+ 0x1f, 0x27, 0x1b, 0x2d, 0x18, 0x33, 0x16, 0x38, 0x14, 0x3c, 0x13, 0x41,
+ 0x12, 0x44, 0x11, 0x48, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54,
+ 0x10, 0x57, 0x10, 0x59, 0x10, 0x5b, 0x10, 0x5c, 0x10, 0x5e, 0x10, 0x5f,
+ 0x10, 0x61, 0x10, 0x62, 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc8,
+ 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xba, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf,
+ 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa7, 0x00, 0xa5, 0x00, 0xa3, 0x00, 0xa1,
+ 0x01, 0xa0, 0x01, 0x9e, 0x01, 0x9d, 0x02, 0x9c, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb7,
+ 0x00, 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f,
+ 0x00, 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00,
+ 0x0c, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16,
+ 0x00, 0x2c, 0x00, 0x3f, 0x00, 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75,
+ 0x00, 0x7e, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x47, 0x38, 0x4b, 0x35, 0x4e, 0x32, 0x51,
+ 0x2f, 0x53, 0x2d, 0x57, 0x2b, 0x58, 0x2a, 0x5b, 0x27, 0x5c, 0x27, 0x5d,
+ 0x25, 0x60, 0x23, 0x60, 0x23, 0x61, 0x23, 0x64, 0x21, 0x65, 0x20, 0x65,
+ 0x20, 0x65, 0x20, 0x66, 0x1f, 0x69, 0x1e, 0x69, 0x1f, 0x27, 0x1b, 0x2c,
+ 0x18, 0x31, 0x16, 0x36, 0x14, 0x3a, 0x13, 0x3e, 0x13, 0x42, 0x12, 0x45,
+ 0x11, 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x56,
+ 0x10, 0x58, 0x10, 0x5a, 0x10, 0x5c, 0x10, 0x5d, 0x10, 0x5e, 0x10, 0x60,
+ 0x00, 0xd9, 0x00, 0xd4, 0x00, 0xce, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xc1,
+ 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad,
+ 0x00, 0xaa, 0x00, 0xa8, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0,
+ 0x01, 0x9f, 0x01, 0x9e, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e,
+ 0x00, 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30,
+ 0x00, 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x39, 0x00,
+ 0x2f, 0x00, 0x1f, 0x00, 0x0b, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x2e,
+ 0x00, 0x3f, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78,
+ 0x00, 0x80, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x46, 0x39, 0x4a, 0x35, 0x4d, 0x32, 0x50, 0x30, 0x53, 0x2e, 0x55,
+ 0x2c, 0x57, 0x2a, 0x58, 0x29, 0x5c, 0x27, 0x5c, 0x27, 0x5d, 0x25, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x63, 0x22, 0x65, 0x20, 0x65, 0x20, 0x65,
+ 0x20, 0x65, 0x20, 0x67, 0x1f, 0x27, 0x1c, 0x2c, 0x19, 0x30, 0x17, 0x35,
+ 0x15, 0x39, 0x14, 0x3d, 0x13, 0x40, 0x12, 0x44, 0x12, 0x47, 0x11, 0x49,
+ 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x56, 0x10, 0x58,
+ 0x10, 0x59, 0x10, 0x5b, 0x10, 0x5c, 0x10, 0x5e, 0x00, 0xda, 0x00, 0xd4,
+ 0x00, 0xd0, 0x00, 0xcb, 0x00, 0xc7, 0x00, 0xc2, 0x00, 0xbe, 0x00, 0xbb,
+ 0x00, 0xb8, 0x00, 0xb5, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa,
+ 0x00, 0xa8, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa3, 0x00, 0xa1, 0x01, 0xa0,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82,
+ 0x00, 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26,
+ 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f,
+ 0x00, 0x4d, 0x00, 0x58, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x46, 0x39, 0x49,
+ 0x36, 0x4c, 0x33, 0x4f, 0x31, 0x52, 0x2e, 0x53, 0x2d, 0x57, 0x2b, 0x57,
+ 0x2a, 0x59, 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x62, 0x22, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65,
+ 0x1f, 0x26, 0x1c, 0x2b, 0x19, 0x2f, 0x17, 0x33, 0x16, 0x37, 0x14, 0x3b,
+ 0x13, 0x3e, 0x13, 0x41, 0x12, 0x44, 0x11, 0x47, 0x11, 0x4a, 0x11, 0x4d,
+ 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x55, 0x10, 0x57, 0x10, 0x59,
+ 0x10, 0x5a, 0x10, 0x5b, 0x00, 0xda, 0x00, 0xd5, 0x00, 0xd1, 0x00, 0xcc,
+ 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc1, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb7,
+ 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa9,
+ 0x00, 0xa7, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xa2, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb,
+ 0x00, 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b,
+ 0x00, 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f,
+ 0x00, 0x16, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x00,
+ 0x00, 0x04, 0x00, 0x14, 0x00, 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b,
+ 0x00, 0x56, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x39, 0x48, 0x36, 0x4b, 0x34, 0x4f,
+ 0x31, 0x50, 0x30, 0x53, 0x2e, 0x55, 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x5a,
+ 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x61, 0x22, 0x64, 0x21, 0x65, 0x20, 0x65, 0x20, 0x26, 0x1c, 0x2a,
+ 0x1a, 0x2e, 0x18, 0x32, 0x16, 0x36, 0x14, 0x39, 0x13, 0x3d, 0x13, 0x40,
+ 0x12, 0x43, 0x12, 0x45, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f,
+ 0x11, 0x51, 0x10, 0x53, 0x10, 0x55, 0x10, 0x56, 0x10, 0x58, 0x10, 0x5a,
+ 0x00, 0xda, 0x00, 0xd6, 0x00, 0xd1, 0x00, 0xcd, 0x00, 0xc9, 0x00, 0xc6,
+ 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb3,
+ 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa7,
+ 0x00, 0xa6, 0x00, 0xa4, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac,
+ 0x00, 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58,
+ 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00,
+ 0x36, 0x00, 0x2d, 0x00, 0x21, 0x00, 0x13, 0x00, 0x04, 0x00, 0x00, 0x0a,
+ 0x00, 0x18, 0x00, 0x26, 0x00, 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54,
+ 0x00, 0x5d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x45, 0x3a, 0x48, 0x37, 0x4a, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x53,
+ 0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57, 0x2a, 0x58, 0x29, 0x5b, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x61,
+ 0x23, 0x64, 0x21, 0x65, 0x20, 0x26, 0x1d, 0x2a, 0x1a, 0x2d, 0x18, 0x31,
+ 0x17, 0x35, 0x15, 0x38, 0x14, 0x3b, 0x13, 0x3e, 0x13, 0x41, 0x12, 0x44,
+ 0x12, 0x46, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51,
+ 0x10, 0x53, 0x10, 0x55, 0x10, 0x56, 0x10, 0x58, 0x00, 0xda, 0x00, 0xd6,
+ 0x00, 0xd2, 0x00, 0xce, 0x00, 0xcb, 0x00, 0xc7, 0x00, 0xc4, 0x00, 0xc1,
+ 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1,
+ 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x00, 0xa6,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99,
+ 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a,
+ 0x00, 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00,
+ 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x1c,
+ 0x00, 0x28, 0x00, 0x34, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x3a, 0x47,
+ 0x38, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x54,
+ 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x59, 0x29, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
+ 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x63,
+ 0x20, 0x25, 0x1d, 0x29, 0x1a, 0x2d, 0x18, 0x30, 0x17, 0x33, 0x16, 0x37,
+ 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f, 0x13, 0x42, 0x12, 0x44, 0x11, 0x47,
+ 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x53,
+ 0x10, 0x55, 0x10, 0x56, 0x00, 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xcf,
+ 0x00, 0xcc, 0x00, 0xc8, 0x00, 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc,
+ 0x00, 0xba, 0x00, 0xb7, 0x00, 0xb5, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf,
+ 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd,
+ 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85,
+ 0x00, 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f,
+ 0x00, 0x36, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00,
+ 0x12, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a,
+ 0x00, 0x35, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3a, 0x47, 0x38, 0x4a, 0x35, 0x4c,
+ 0x33, 0x4f, 0x31, 0x50, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57,
+ 0x2a, 0x57, 0x2a, 0x5a, 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5f,
+ 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x20, 0x25, 0x1d, 0x29,
+ 0x1b, 0x2c, 0x18, 0x2f, 0x17, 0x33, 0x16, 0x36, 0x14, 0x39, 0x14, 0x3b,
+ 0x13, 0x3e, 0x13, 0x41, 0x12, 0x43, 0x12, 0x45, 0x11, 0x47, 0x11, 0x4a,
+ 0x11, 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x52, 0x10, 0x54,
+ 0x00, 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xd0, 0x00, 0xcc, 0x00, 0xc9,
+ 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb9,
+ 0x00, 0xb7, 0x00, 0xb5, 0x00, 0xb3, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad,
+ 0x00, 0xab, 0x00, 0xaa, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3,
+ 0x00, 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74,
+ 0x00, 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00,
+ 0x3a, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36,
+ 0x00, 0x3f, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x44, 0x3b, 0x46, 0x39, 0x4a, 0x35, 0x4b, 0x34, 0x4f, 0x31, 0x4f,
+ 0x31, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x58,
+ 0x2a, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5f, 0x24, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x19, 0x2f,
+ 0x17, 0x32, 0x16, 0x35, 0x15, 0x38, 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f,
+ 0x13, 0x42, 0x12, 0x44, 0x12, 0x46, 0x11, 0x48, 0x11, 0x4a, 0x11, 0x4c,
+ 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x52, 0x00, 0xdb, 0x00, 0xd7,
+ 0x00, 0xd4, 0x00, 0xd0, 0x00, 0xcd, 0x00, 0xca, 0x00, 0xc7, 0x00, 0xc5,
+ 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6,
+ 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xac,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5,
+ 0x00, 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65,
+ 0x00, 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00,
+ 0x2e, 0x00, 0x25, 0x00, 0x1c, 0x00, 0x11, 0x00, 0x07, 0x00, 0x00, 0x03,
+ 0x00, 0x0e, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3b, 0x46,
+ 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x51, 0x2f, 0x53,
+ 0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x29, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x26, 0x5f, 0x24, 0x60, 0x23, 0x60,
+ 0x20, 0x25, 0x1d, 0x28, 0x1c, 0x2b, 0x1a, 0x2e, 0x18, 0x31, 0x17, 0x34,
+ 0x16, 0x37, 0x14, 0x39, 0x13, 0x3b, 0x13, 0x3e, 0x13, 0x40, 0x12, 0x42,
+ 0x12, 0x45, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4a, 0x11, 0x4c, 0x11, 0x4e,
+ 0x11, 0x4f, 0x11, 0x51, 0x00, 0xdb, 0x00, 0xd8, 0x00, 0xd4, 0x00, 0xd1,
+ 0x00, 0xce, 0x00, 0xcb, 0x00, 0xc8, 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1,
+ 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xba, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4,
+ 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x56, 0x7f, 0x47, 0x63,
+ 0x44, 0x57, 0x43, 0x52, 0x43, 0x4e, 0x42, 0x4c, 0x42, 0x4a, 0x42, 0x49,
+ 0x42, 0x48, 0x42, 0x47, 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x45,
+ 0x42, 0x44, 0x42, 0x44, 0x42, 0x44, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43,
+ 0x4c, 0x7f, 0x27, 0x4d, 0x2f, 0x46, 0x33, 0x44, 0x36, 0x43, 0x37, 0x43,
+ 0x39, 0x42, 0x3a, 0x41, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41,
+ 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3d, 0x41,
+ 0x3d, 0x41, 0x3d, 0x41, 0x8e, 0x7f, 0x47, 0x4d, 0x44, 0x46, 0x43, 0x44,
+ 0x43, 0x43, 0x42, 0x43, 0x42, 0x42, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41,
+ 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41,
+ 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x85, 0x1b, 0x60, 0x27, 0x54, 0x2d, 0x4e, 0x30,
+ 0x4b, 0x33, 0x49, 0x34, 0x47, 0x35, 0x46, 0x37, 0x45, 0x38, 0x45, 0x38,
+ 0x44, 0x39, 0x43, 0x39, 0x43, 0x3a, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b,
+ 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x09, 0x43, 0x16, 0x3f,
+ 0x1f, 0x3e, 0x25, 0x3e, 0x29, 0x3e, 0x2c, 0x3e, 0x2f, 0x3e, 0x30, 0x3e,
+ 0x32, 0x3e, 0x33, 0x3e, 0x34, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x36, 0x3e,
+ 0x37, 0x3e, 0x37, 0x3e, 0x38, 0x3e, 0x38, 0x3e, 0x38, 0x3e, 0x39, 0x3e,
+ 0x59, 0x31, 0x4f, 0x38, 0x4b, 0x3a, 0x48, 0x3b, 0x47, 0x3c, 0x46, 0x3c,
+ 0x45, 0x3d, 0x45, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x4c, 0x00, 0x2f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x4f, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x96, 0x05, 0x74, 0x0f, 0x63, 0x17, 0x5a, 0x1d, 0x54, 0x21, 0x51, 0x24,
+ 0x4e, 0x27, 0x4c, 0x29, 0x4a, 0x2b, 0x49, 0x2d, 0x49, 0x2e, 0x48, 0x2f,
+ 0x48, 0x31, 0x47, 0x31, 0x46, 0x32, 0x46, 0x33, 0x44, 0x33, 0x44, 0x34,
+ 0x43, 0x34, 0x43, 0x35, 0x09, 0x43, 0x11, 0x3e, 0x18, 0x3c, 0x1d, 0x3c,
+ 0x22, 0x3c, 0x25, 0x3c, 0x27, 0x3c, 0x2a, 0x3c, 0x2c, 0x3d, 0x2d, 0x3d,
+ 0x2f, 0x3d, 0x30, 0x3e, 0x31, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e,
+ 0x33, 0x3e, 0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x5b, 0x2a, 0x53, 0x31,
+ 0x4f, 0x34, 0x4c, 0x36, 0x4b, 0x38, 0x4a, 0x39, 0x48, 0x39, 0x47, 0x3a,
+ 0x46, 0x3b, 0x46, 0x3b, 0x46, 0x3c, 0x46, 0x3c, 0x46, 0x3d, 0x45, 0x3d,
+ 0x44, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x45,
+ 0x00, 0x22, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8f, 0x00, 0x73, 0x00, 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x9e, 0x01, 0x81, 0x06,
+ 0x6f, 0x0d, 0x64, 0x12, 0x5d, 0x16, 0x58, 0x1a, 0x54, 0x1d, 0x53, 0x20,
+ 0x50, 0x22, 0x4e, 0x24, 0x4c, 0x26, 0x4b, 0x27, 0x4a, 0x29, 0x49, 0x2a,
+ 0x49, 0x2b, 0x49, 0x2c, 0x48, 0x2d, 0x48, 0x2e, 0x48, 0x2f, 0x47, 0x2f,
+ 0x09, 0x44, 0x0f, 0x3e, 0x14, 0x3c, 0x19, 0x3c, 0x1d, 0x3b, 0x20, 0x3b,
+ 0x23, 0x3b, 0x25, 0x3c, 0x27, 0x3c, 0x28, 0x3c, 0x2a, 0x3b, 0x2c, 0x3b,
+ 0x2c, 0x3b, 0x2d, 0x3b, 0x2f, 0x3c, 0x2f, 0x3c, 0x30, 0x3d, 0x31, 0x3e,
+ 0x32, 0x3e, 0x32, 0x3e, 0x5c, 0x28, 0x56, 0x2d, 0x52, 0x31, 0x4f, 0x33,
+ 0x4e, 0x35, 0x4b, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x49, 0x39, 0x47, 0x39,
+ 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x3a, 0x46, 0x3a, 0x46, 0x3b,
+ 0x46, 0x3c, 0x46, 0x3c, 0x46, 0x3d, 0x45, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x19,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x84, 0x00,
+ 0x5b, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xa4, 0x00, 0x8a, 0x03, 0x78, 0x07, 0x6d, 0x0c,
+ 0x65, 0x10, 0x60, 0x13, 0x5b, 0x16, 0x57, 0x19, 0x55, 0x1b, 0x53, 0x1e,
+ 0x52, 0x1f, 0x4f, 0x22, 0x4d, 0x23, 0x4c, 0x24, 0x4b, 0x25, 0x4b, 0x27,
+ 0x4a, 0x28, 0x49, 0x29, 0x49, 0x29, 0x49, 0x2b, 0x09, 0x45, 0x0d, 0x40,
+ 0x11, 0x3d, 0x16, 0x3c, 0x19, 0x3b, 0x1d, 0x3b, 0x1f, 0x3b, 0x21, 0x3a,
+ 0x23, 0x3b, 0x25, 0x3b, 0x26, 0x3c, 0x28, 0x3c, 0x29, 0x3c, 0x2a, 0x3b,
+ 0x2b, 0x3b, 0x2c, 0x3b, 0x2d, 0x3b, 0x2e, 0x3b, 0x2e, 0x3b, 0x2f, 0x3b,
+ 0x5d, 0x27, 0x57, 0x2c, 0x54, 0x2f, 0x52, 0x31, 0x4f, 0x32, 0x4e, 0x34,
+ 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x48, 0x39,
+ 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39,
+ 0x46, 0x39, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5b, 0x00, 0x55, 0x00, 0x42, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x8d, 0x00, 0x6f, 0x00, 0x48, 0x00,
+ 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xa7, 0x00, 0x91, 0x01, 0x80, 0x04, 0x75, 0x08, 0x6c, 0x0b, 0x65, 0x0e,
+ 0x61, 0x11, 0x5d, 0x14, 0x59, 0x16, 0x56, 0x19, 0x55, 0x1a, 0x54, 0x1c,
+ 0x53, 0x1e, 0x51, 0x1f, 0x4f, 0x21, 0x4d, 0x22, 0x4c, 0x23, 0x4b, 0x24,
+ 0x4b, 0x25, 0x4b, 0x26, 0x09, 0x45, 0x0d, 0x41, 0x10, 0x3e, 0x14, 0x3d,
+ 0x17, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1e, 0x3b, 0x20, 0x3b, 0x22, 0x3a,
+ 0x23, 0x3a, 0x25, 0x3b, 0x26, 0x3c, 0x28, 0x3c, 0x28, 0x3c, 0x29, 0x3c,
+ 0x2a, 0x3c, 0x2b, 0x3b, 0x2c, 0x3b, 0x2d, 0x3b, 0x5d, 0x26, 0x59, 0x2a,
+ 0x56, 0x2d, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x32, 0x4f, 0x33, 0x4d, 0x35,
+ 0x4b, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x37, 0x4a, 0x38, 0x49, 0x39,
+ 0x48, 0x39, 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58,
+ 0x00, 0x4a, 0x00, 0x38, 0x00, 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xa9, 0x00, 0x96, 0x00,
+ 0x86, 0x02, 0x7a, 0x05, 0x72, 0x08, 0x6b, 0x0b, 0x65, 0x0e, 0x62, 0x10,
+ 0x5f, 0x12, 0x5b, 0x14, 0x58, 0x16, 0x56, 0x18, 0x55, 0x1a, 0x54, 0x1b,
+ 0x53, 0x1d, 0x52, 0x1e, 0x50, 0x1f, 0x4f, 0x20, 0x4d, 0x21, 0x4c, 0x22,
+ 0x09, 0x46, 0x0c, 0x41, 0x0f, 0x3f, 0x12, 0x3d, 0x15, 0x3c, 0x17, 0x3c,
+ 0x1a, 0x3b, 0x1c, 0x3a, 0x1e, 0x3b, 0x1f, 0x3b, 0x21, 0x3a, 0x22, 0x3a,
+ 0x24, 0x3a, 0x25, 0x3a, 0x26, 0x3b, 0x27, 0x3c, 0x28, 0x3c, 0x29, 0x3c,
+ 0x2a, 0x3c, 0x2a, 0x3c, 0x5e, 0x26, 0x5a, 0x29, 0x57, 0x2c, 0x53, 0x2e,
+ 0x53, 0x30, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x33, 0x4e, 0x34, 0x4c, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37, 0x4a, 0x38,
+ 0x48, 0x39, 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40,
+ 0x00, 0x2f, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95, 0x00,
+ 0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xab, 0x00, 0x9a, 0x00, 0x8b, 0x01, 0x7f, 0x03,
+ 0x77, 0x06, 0x71, 0x08, 0x6a, 0x0b, 0x66, 0x0d, 0x63, 0x0f, 0x60, 0x11,
+ 0x5d, 0x13, 0x59, 0x14, 0x57, 0x16, 0x56, 0x18, 0x55, 0x19, 0x54, 0x1b,
+ 0x53, 0x1c, 0x53, 0x1d, 0x51, 0x1e, 0x50, 0x1f, 0x0a, 0x46, 0x0c, 0x42,
+ 0x0e, 0x3f, 0x11, 0x3f, 0x13, 0x3c, 0x16, 0x3c, 0x18, 0x3c, 0x1a, 0x3b,
+ 0x1c, 0x3a, 0x1e, 0x3b, 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3a, 0x23, 0x3a,
+ 0x24, 0x3a, 0x25, 0x39, 0x26, 0x3a, 0x27, 0x3c, 0x27, 0x3c, 0x28, 0x3c,
+ 0x5e, 0x26, 0x5a, 0x29, 0x57, 0x2b, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x30,
+ 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x32, 0x4f, 0x34, 0x4d, 0x35, 0x4b, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x38,
+ 0x4a, 0x39, 0x48, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29,
+ 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00,
+ 0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xac, 0x00, 0x9d, 0x00, 0x8f, 0x01, 0x85, 0x02, 0x7b, 0x04, 0x75, 0x06,
+ 0x6f, 0x08, 0x69, 0x0b, 0x66, 0x0d, 0x63, 0x0e, 0x61, 0x10, 0x5e, 0x12,
+ 0x5b, 0x13, 0x58, 0x15, 0x57, 0x16, 0x56, 0x18, 0x55, 0x19, 0x55, 0x1a,
+ 0x54, 0x1b, 0x53, 0x1c, 0x0a, 0x47, 0x0b, 0x42, 0x0e, 0x40, 0x10, 0x3f,
+ 0x12, 0x3d, 0x15, 0x3c, 0x17, 0x3c, 0x18, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a,
+ 0x1d, 0x3b, 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x23, 0x3a,
+ 0x24, 0x3a, 0x25, 0x39, 0x26, 0x3a, 0x27, 0x3b, 0x5e, 0x26, 0x5b, 0x28,
+ 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x33, 0x4e, 0x35, 0x4b, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c,
+ 0x00, 0x55, 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17,
+ 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00,
+ 0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xad, 0x00, 0xa0, 0x00,
+ 0x92, 0x00, 0x89, 0x02, 0x7f, 0x03, 0x78, 0x05, 0x73, 0x07, 0x6e, 0x09,
+ 0x69, 0x0b, 0x66, 0x0c, 0x64, 0x0e, 0x62, 0x0f, 0x60, 0x11, 0x5c, 0x12,
+ 0x59, 0x14, 0x58, 0x15, 0x57, 0x16, 0x56, 0x18, 0x55, 0x18, 0x55, 0x1a,
+ 0x0a, 0x47, 0x0b, 0x43, 0x0d, 0x41, 0x0f, 0x3f, 0x11, 0x3f, 0x13, 0x3c,
+ 0x15, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a, 0x1d, 0x3a,
+ 0x1f, 0x3b, 0x1f, 0x3b, 0x21, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x24, 0x3a,
+ 0x24, 0x3a, 0x24, 0x39, 0x5e, 0x26, 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2b,
+ 0x55, 0x2e, 0x53, 0x2e, 0x53, 0x2f, 0x52, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x32, 0x4e, 0x34, 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f,
+ 0x00, 0x44, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
+ 0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xae, 0x00, 0xa2, 0x00, 0x95, 0x00, 0x8b, 0x01,
+ 0x83, 0x02, 0x7b, 0x04, 0x76, 0x05, 0x73, 0x07, 0x6e, 0x09, 0x69, 0x0a,
+ 0x66, 0x0c, 0x64, 0x0d, 0x62, 0x0f, 0x61, 0x10, 0x5e, 0x11, 0x5b, 0x13,
+ 0x58, 0x14, 0x58, 0x15, 0x56, 0x16, 0x56, 0x18, 0x0a, 0x47, 0x0b, 0x43,
+ 0x0d, 0x42, 0x0f, 0x3f, 0x11, 0x3f, 0x12, 0x3e, 0x14, 0x3c, 0x16, 0x3c,
+ 0x17, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a, 0x1d, 0x39, 0x1f, 0x3b,
+ 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3b, 0x21, 0x3a, 0x22, 0x3a, 0x24, 0x3a,
+ 0x5e, 0x26, 0x5c, 0x27, 0x59, 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x32, 0x4f, 0x33, 0x4d, 0x35, 0x4b, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e,
+ 0x00, 0x33, 0x00, 0x28, 0x00, 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00,
+ 0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x87, 0x02, 0x7f, 0x03,
+ 0x79, 0x04, 0x75, 0x06, 0x71, 0x07, 0x6c, 0x09, 0x68, 0x0a, 0x66, 0x0c,
+ 0x64, 0x0d, 0x63, 0x0e, 0x61, 0x10, 0x5f, 0x11, 0x5c, 0x12, 0x59, 0x13,
+ 0x58, 0x14, 0x58, 0x15, 0x0a, 0x47, 0x0b, 0x43, 0x0d, 0x42, 0x0e, 0x40,
+ 0x10, 0x3e, 0x11, 0x3f, 0x13, 0x3c, 0x15, 0x3b, 0x17, 0x3c, 0x17, 0x3c,
+ 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x3a, 0x1f, 0x3b,
+ 0x1f, 0x3b, 0x21, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x5e, 0x25, 0x5c, 0x27,
+ 0x5a, 0x29, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2f, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x33, 0x4e, 0x34, 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
+ 0x00, 0x59, 0x00, 0x53, 0x00, 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e,
+ 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00,
+ 0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xaf, 0x00, 0xa5, 0x00,
+ 0x9a, 0x00, 0x90, 0x00, 0x8a, 0x01, 0x83, 0x02, 0x7c, 0x03, 0x77, 0x05,
+ 0x74, 0x06, 0x70, 0x07, 0x6c, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x64, 0x0c,
+ 0x63, 0x0e, 0x61, 0x0f, 0x60, 0x11, 0x5d, 0x11, 0x5b, 0x13, 0x59, 0x13,
+ 0x0a, 0x47, 0x0a, 0x44, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3e, 0x11, 0x3f,
+ 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3a, 0x17, 0x3c, 0x17, 0x3c, 0x19, 0x3c,
+ 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x3a, 0x1f, 0x3b, 0x1f, 0x3b,
+ 0x20, 0x3b, 0x21, 0x3b, 0x5e, 0x25, 0x5c, 0x27, 0x5a, 0x29, 0x57, 0x2a,
+ 0x57, 0x2a, 0x56, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x30,
+ 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x32,
+ 0x4f, 0x33, 0x4d, 0x35, 0x4b, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55,
+ 0x00, 0x4e, 0x00, 0x46, 0x00, 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21,
+ 0x00, 0x18, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
+ 0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00,
+ 0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x92, 0x00,
+ 0x8c, 0x01, 0x86, 0x02, 0x7e, 0x02, 0x7a, 0x04, 0x76, 0x05, 0x73, 0x06,
+ 0x70, 0x07, 0x6b, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0e,
+ 0x62, 0x0e, 0x61, 0x10, 0x5e, 0x11, 0x5c, 0x12, 0x0a, 0x47, 0x0a, 0x44,
+ 0x0c, 0x42, 0x0d, 0x41, 0x0f, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x13, 0x3d,
+ 0x15, 0x3c, 0x16, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x1a, 0x3b,
+ 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x39, 0x1f, 0x3b, 0x1f, 0x3b, 0x1f, 0x3b,
+ 0x5f, 0x25, 0x5c, 0x27, 0x5b, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b,
+ 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x33,
+ 0x4e, 0x34, 0x4c, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49,
+ 0x00, 0x41, 0x00, 0x39, 0x00, 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16,
+ 0x00, 0x0e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00,
+ 0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00,
+ 0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xb0, 0x00, 0xa7, 0x00, 0x9f, 0x00, 0x95, 0x00, 0x8e, 0x00, 0x88, 0x01,
+ 0x82, 0x02, 0x7c, 0x03, 0x78, 0x05, 0x75, 0x06, 0x72, 0x07, 0x6f, 0x08,
+ 0x6a, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0d, 0x62, 0x0e,
+ 0x61, 0x0f, 0x60, 0x11, 0x0a, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42,
+ 0x0e, 0x40, 0x10, 0x3d, 0x11, 0x3f, 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3b,
+ 0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b,
+ 0x1c, 0x3a, 0x1d, 0x39, 0x1f, 0x3a, 0x1f, 0x3b, 0x5f, 0x25, 0x5c, 0x27,
+ 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2d, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x32, 0x4f, 0x34,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e,
+ 0x00, 0x5b, 0x00, 0x57, 0x00, 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d,
+ 0x00, 0x35, 0x00, 0x2c, 0x00, 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00,
+ 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00,
+ 0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xb1, 0x00, 0xa7, 0x00,
+ 0xa0, 0x00, 0x97, 0x00, 0x90, 0x00, 0x8a, 0x01, 0x85, 0x02, 0x7e, 0x02,
+ 0x7a, 0x03, 0x77, 0x05, 0x74, 0x06, 0x72, 0x07, 0x6e, 0x08, 0x6a, 0x09,
+ 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0d, 0x63, 0x0e, 0x61, 0x0f,
+ 0x0a, 0x47, 0x0a, 0x45, 0x0b, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x3e,
+ 0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3d, 0x15, 0x3c, 0x15, 0x3a, 0x17, 0x3c,
+ 0x17, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3a,
+ 0x1d, 0x39, 0x1f, 0x39, 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x59, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x17, 0x00, 0x2f,
+ 0x00, 0x4c, 0x00, 0x56, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x5d,
+ 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f,
+ 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x62,
+ 0x00, 0x62, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e,
+ 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x14, 0x01, 0x29,
+ 0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d,
+ 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e,
+ 0x00, 0x5f, 0x00, 0x5f, 0x31, 0x11, 0x03, 0x23, 0x00, 0x46, 0x00, 0x52,
+ 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e,
+ 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xb1, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x99, 0x00,
+ 0x91, 0x00, 0x8c, 0x00, 0x88, 0x01, 0x82, 0x02, 0x7c, 0x03, 0x79, 0x04,
+ 0x76, 0x05, 0x74, 0x06, 0x71, 0x07, 0x6d, 0x08, 0x6a, 0x09, 0x68, 0x0a,
+ 0x66, 0x0b, 0x65, 0x0c, 0x64, 0x0c, 0x63, 0x0e, 0x0a, 0x47, 0x0a, 0x45,
+ 0x0b, 0x42, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3e, 0x11, 0x3f,
+ 0x13, 0x3e, 0x13, 0x3c, 0x15, 0x3c, 0x16, 0x3a, 0x17, 0x3c, 0x17, 0x3c,
+ 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3a, 0x1d, 0x39,
+ 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5a, 0x29, 0x57, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x2f, 0x00, 0x45,
+ 0x00, 0x4f, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c,
+ 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e,
+ 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x48, 0x00, 0x55, 0x00, 0x58, 0x00, 0x57,
+ 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d,
+ 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x16, 0x04, 0x00, 0x27, 0x00, 0x41,
+ 0x00, 0x4d, 0x00, 0x53, 0x00, 0x56, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b,
+ 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e,
+ 0x5f, 0x00, 0x20, 0x00, 0x00, 0x1f, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x51,
+ 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5c,
+ 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xb1, 0x00, 0xa9, 0x00, 0xa2, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x8e, 0x00,
+ 0x89, 0x01, 0x84, 0x02, 0x7e, 0x02, 0x7a, 0x03, 0x78, 0x05, 0x75, 0x05,
+ 0x73, 0x06, 0x71, 0x07, 0x6c, 0x08, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b,
+ 0x65, 0x0c, 0x64, 0x0c, 0x0a, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x42,
+ 0x0e, 0x42, 0x0f, 0x40, 0x10, 0x3d, 0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3d,
+ 0x15, 0x3c, 0x15, 0x3b, 0x17, 0x3a, 0x17, 0x3c, 0x17, 0x3c, 0x19, 0x3c,
+ 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3b, 0x5f, 0x25, 0x5c, 0x27,
+ 0x5c, 0x27, 0x5b, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x30,
+ 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x22, 0x00, 0x36, 0x00, 0x42,
+ 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58,
+ 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5f, 0x00, 0x48,
+ 0x00, 0x1b, 0x00, 0x34, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4f,
+ 0x00, 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a,
+ 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x82, 0x00, 0x57, 0x00, 0x12, 0x01, 0x00, 0x17, 0x00, 0x2f, 0x00, 0x3e,
+ 0x00, 0x47, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x53, 0x00, 0x56, 0x00, 0x57,
+ 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x85, 0x00, 0x5f, 0x00,
+ 0x1f, 0x00, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4a,
+ 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56, 0x00, 0x57, 0x00, 0x59,
+ 0x00, 0x59, 0x00, 0x5a, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xb2, 0x00, 0xa9, 0x00,
+ 0xa3, 0x00, 0x9d, 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8b, 0x01, 0x87, 0x02,
+ 0x81, 0x02, 0x7c, 0x03, 0x79, 0x03, 0x77, 0x05, 0x75, 0x06, 0x72, 0x06,
+ 0x70, 0x07, 0x6c, 0x08, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c,
+ 0x0a, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40,
+ 0x0f, 0x3e, 0x11, 0x3e, 0x11, 0x3f, 0x13, 0x3f, 0x13, 0x3c, 0x15, 0x3c,
+ 0x15, 0x3a, 0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x19, 0x3c,
+ 0x1a, 0x3b, 0x1c, 0x3b, 0x5f, 0x24, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x28,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x50, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x19, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40,
+ 0x00, 0x47, 0x00, 0x4b, 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55,
+ 0x00, 0x56, 0x00, 0x57, 0x00, 0x62, 0x00, 0x55, 0x00, 0x34, 0x00, 0x0b,
+ 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b,
+ 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x78, 0x00,
+ 0x43, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x23, 0x00, 0x31, 0x00, 0x3b,
+ 0x00, 0x42, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53,
+ 0x00, 0x55, 0x00, 0x56, 0x92, 0x00, 0x7c, 0x00, 0x4d, 0x00, 0x1f, 0x00,
+ 0x00, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x45,
+ 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x53, 0x00, 0x55,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x00, 0x9e, 0x00,
+ 0x96, 0x00, 0x90, 0x00, 0x8c, 0x00, 0x88, 0x01, 0x84, 0x02, 0x7e, 0x02,
+ 0x7b, 0x03, 0x78, 0x04, 0x76, 0x05, 0x74, 0x06, 0x72, 0x07, 0x6f, 0x07,
+ 0x6b, 0x09, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x0a, 0x47, 0x0a, 0x46,
+ 0x0b, 0x44, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x3f, 0x10, 0x3d,
+ 0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3c, 0x16, 0x3a,
+ 0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b,
+ 0x5f, 0x24, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, 0x00, 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f,
+ 0x00, 0x44, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52,
+ 0x00, 0x62, 0x00, 0x58, 0x00, 0x40, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x14,
+ 0x00, 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48,
+ 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x87, 0x00, 0x61, 0x00, 0x36, 0x00,
+ 0x10, 0x00, 0x02, 0x0a, 0x00, 0x1a, 0x00, 0x27, 0x00, 0x32, 0x00, 0x3a,
+ 0x00, 0x40, 0x00, 0x44, 0x00, 0x48, 0x00, 0x4b, 0x00, 0x4e, 0x00, 0x50,
+ 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42, 0x00, 0x1f, 0x00, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x41,
+ 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e, 0x28, 0x3c, 0x16, 0x41,
+ 0x11, 0x43, 0x0f, 0x44, 0x0e, 0x45, 0x0d, 0x46, 0x0c, 0x46, 0x0c, 0x46,
+ 0x0b, 0x47, 0x0b, 0x47, 0x0b, 0x47, 0x0b, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x6e, 0x1c, 0x3a, 0x29, 0x27, 0x31, 0x1e, 0x36, 0x19, 0x3a, 0x17, 0x3b,
+ 0x14, 0x3d, 0x13, 0x3f, 0x11, 0x40, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x42,
+ 0x0f, 0x43, 0x0f, 0x43, 0x0e, 0x43, 0x0e, 0x44, 0x0d, 0x44, 0x0d, 0x44,
+ 0x0c, 0x44, 0x0c, 0x44, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x3c, 0x32, 0x22, 0x38,
+ 0x18, 0x3c, 0x14, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x42, 0x0e, 0x43,
+ 0x0e, 0x44, 0x0d, 0x44, 0x0d, 0x44, 0x0c, 0x44, 0x0c, 0x45, 0x0c, 0x45,
+ 0x0c, 0x45, 0x0c, 0x45, 0x0b, 0x45, 0x0b, 0x45, 0x0b, 0x46, 0x0b, 0x46,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x1e, 0x00, 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e,
+ 0x00, 0x42, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x57,
+ 0x00, 0x44, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e,
+ 0x00, 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46,
+ 0x00, 0x49, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x99, 0x00, 0x8f, 0x00, 0x74, 0x00, 0x51, 0x00, 0x2e, 0x00, 0x10, 0x00,
+ 0x04, 0x08, 0x00, 0x13, 0x00, 0x20, 0x00, 0x2a, 0x00, 0x32, 0x00, 0x38,
+ 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x48, 0x9a, 0x00, 0x91, 0x00,
+ 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f, 0x00, 0x09, 0x00, 0x00, 0x08,
+ 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3e,
+ 0x00, 0x42, 0x00, 0x45, 0x30, 0x38, 0x20, 0x3a, 0x18, 0x3d, 0x14, 0x3e,
+ 0x12, 0x40, 0x10, 0x41, 0x0f, 0x42, 0x0e, 0x42, 0x0e, 0x42, 0x0d, 0x43,
+ 0x0d, 0x43, 0x0d, 0x44, 0x0d, 0x44, 0x0c, 0x45, 0x0c, 0x45, 0x0b, 0x45,
+ 0x0b, 0x46, 0x0b, 0x46, 0x0b, 0x46, 0x0b, 0x47, 0x8a, 0x03, 0x59, 0x0f,
+ 0x40, 0x18, 0x32, 0x1f, 0x2a, 0x24, 0x24, 0x28, 0x20, 0x2c, 0x1c, 0x2f,
+ 0x1b, 0x31, 0x18, 0x33, 0x17, 0x34, 0x16, 0x36, 0x15, 0x37, 0x14, 0x38,
+ 0x13, 0x39, 0x12, 0x3a, 0x12, 0x3a, 0x12, 0x3b, 0x11, 0x3c, 0x10, 0x3c,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x4a, 0x25, 0x31, 0x2b, 0x25, 0x30, 0x1e, 0x33,
+ 0x1a, 0x36, 0x17, 0x38, 0x15, 0x39, 0x13, 0x3b, 0x12, 0x3c, 0x11, 0x3d,
+ 0x10, 0x3e, 0x10, 0x3f, 0x0f, 0x3f, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x40,
+ 0x0e, 0x41, 0x0e, 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
+ 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d,
+ 0x00, 0x41, 0x00, 0x44, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38,
+ 0x00, 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24,
+ 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x94, 0x00,
+ 0x7f, 0x00, 0x64, 0x00, 0x46, 0x00, 0x29, 0x00, 0x10, 0x00, 0x06, 0x07,
+ 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00, 0x38,
+ 0x00, 0x3c, 0x00, 0x40, 0x9b, 0x00, 0x95, 0x00, 0x83, 0x00, 0x6a, 0x00,
+ 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x10,
+ 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3c,
+ 0x34, 0x38, 0x25, 0x39, 0x1e, 0x3b, 0x19, 0x3c, 0x16, 0x3d, 0x14, 0x3d,
+ 0x13, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x41, 0x0f, 0x42, 0x0e, 0x42,
+ 0x0e, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x43, 0x0d, 0x43,
+ 0x0d, 0x44, 0x0d, 0x44, 0x97, 0x00, 0x6c, 0x06, 0x52, 0x0d, 0x43, 0x12,
+ 0x38, 0x18, 0x30, 0x1c, 0x2a, 0x20, 0x27, 0x23, 0x23, 0x26, 0x20, 0x28,
+ 0x1e, 0x2a, 0x1c, 0x2c, 0x1b, 0x2e, 0x19, 0x2f, 0x18, 0x31, 0x17, 0x32,
+ 0x16, 0x33, 0x16, 0x34, 0x16, 0x35, 0x15, 0x35, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x50, 0x24, 0x3b, 0x27, 0x2e, 0x2a, 0x26, 0x2d, 0x21, 0x2f, 0x1d, 0x32,
+ 0x1a, 0x33, 0x18, 0x35, 0x16, 0x36, 0x15, 0x38, 0x14, 0x39, 0x13, 0x3a,
+ 0x12, 0x3a, 0x11, 0x3b, 0x11, 0x3c, 0x11, 0x3c, 0x10, 0x3d, 0x10, 0x3e,
+ 0x10, 0x3e, 0x0f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17,
+ 0x00, 0x20, 0x00, 0x28, 0x00, 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d,
+ 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e,
+ 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28,
+ 0x00, 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x87, 0x00, 0x71, 0x00,
+ 0x57, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x10, 0x00, 0x07, 0x06, 0x00, 0x0b,
+ 0x00, 0x15, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37,
+ 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x48, 0x00,
+ 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15,
+ 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31, 0x36, 0x39, 0x2a, 0x39,
+ 0x22, 0x39, 0x1d, 0x3a, 0x1a, 0x3b, 0x17, 0x3d, 0x15, 0x3d, 0x13, 0x3d,
+ 0x13, 0x3e, 0x12, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x41, 0x0f, 0x42,
+ 0x0e, 0x41, 0x0e, 0x42, 0x0e, 0x42, 0x0e, 0x41, 0x0e, 0x42, 0x0d, 0x42,
+ 0x9e, 0x00, 0x79, 0x02, 0x61, 0x07, 0x50, 0x0b, 0x44, 0x10, 0x3b, 0x14,
+ 0x34, 0x18, 0x2f, 0x1b, 0x2b, 0x1e, 0x28, 0x20, 0x25, 0x23, 0x23, 0x25,
+ 0x21, 0x27, 0x1f, 0x28, 0x1d, 0x2a, 0x1c, 0x2b, 0x1b, 0x2c, 0x19, 0x2e,
+ 0x19, 0x2f, 0x19, 0x30, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x54, 0x23, 0x42, 0x25,
+ 0x35, 0x27, 0x2d, 0x29, 0x27, 0x2c, 0x22, 0x2e, 0x1f, 0x2f, 0x1c, 0x31,
+ 0x1a, 0x33, 0x19, 0x34, 0x17, 0x35, 0x16, 0x36, 0x15, 0x37, 0x14, 0x38,
+ 0x13, 0x38, 0x13, 0x39, 0x12, 0x3a, 0x11, 0x3a, 0x11, 0x3b, 0x11, 0x3c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d,
+ 0x00, 0x24, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x35, 0x00, 0x5e, 0x00, 0x5b,
+ 0x00, 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a,
+ 0x00, 0x30, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9d, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00,
+ 0x37, 0x00, 0x22, 0x00, 0x10, 0x00, 0x08, 0x05, 0x02, 0x0a, 0x00, 0x12,
+ 0x00, 0x1a, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2d, 0x9d, 0x00, 0x99, 0x00,
+ 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57, 0x00, 0x43, 0x00, 0x30, 0x00,
+ 0x1f, 0x00, 0x11, 0x00, 0x04, 0x00, 0x00, 0x07, 0x00, 0x10, 0x00, 0x19,
+ 0x00, 0x20, 0x00, 0x26, 0x38, 0x39, 0x2d, 0x39, 0x25, 0x39, 0x20, 0x3a,
+ 0x1d, 0x3b, 0x1a, 0x3b, 0x18, 0x3c, 0x16, 0x3d, 0x14, 0x3d, 0x13, 0x3d,
+ 0x13, 0x3d, 0x12, 0x3e, 0x11, 0x3f, 0x11, 0x40, 0x10, 0x40, 0x0f, 0x41,
+ 0x0f, 0x42, 0x0f, 0x42, 0x0e, 0x42, 0x0e, 0x42, 0xa2, 0x00, 0x84, 0x00,
+ 0x6c, 0x04, 0x5a, 0x07, 0x4e, 0x0b, 0x45, 0x0f, 0x3e, 0x12, 0x38, 0x15,
+ 0x32, 0x18, 0x2f, 0x1a, 0x2c, 0x1d, 0x29, 0x1f, 0x26, 0x21, 0x24, 0x22,
+ 0x22, 0x24, 0x21, 0x26, 0x1f, 0x27, 0x1e, 0x28, 0x1d, 0x2a, 0x1c, 0x2b,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x56, 0x23, 0x47, 0x24, 0x3b, 0x25, 0x32, 0x27,
+ 0x2c, 0x29, 0x27, 0x2b, 0x24, 0x2d, 0x21, 0x2e, 0x1e, 0x30, 0x1c, 0x31,
+ 0x1b, 0x32, 0x19, 0x33, 0x18, 0x34, 0x17, 0x35, 0x16, 0x36, 0x15, 0x37,
+ 0x14, 0x37, 0x14, 0x38, 0x13, 0x38, 0x13, 0x39, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21,
+ 0x00, 0x27, 0x00, 0x2c, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b,
+ 0x00, 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
+ 0x90, 0x00, 0x81, 0x00, 0x6f, 0x00, 0x5b, 0x00, 0x46, 0x00, 0x32, 0x00,
+ 0x20, 0x00, 0x10, 0x00, 0x09, 0x04, 0x03, 0x09, 0x00, 0x0f, 0x00, 0x17,
+ 0x00, 0x1e, 0x00, 0x24, 0x9d, 0x00, 0x9a, 0x00, 0x92, 0x00, 0x84, 0x00,
+ 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x00,
+ 0x12, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1b,
+ 0x39, 0x3a, 0x2f, 0x39, 0x28, 0x39, 0x23, 0x39, 0x20, 0x3a, 0x1c, 0x3b,
+ 0x1a, 0x3a, 0x18, 0x3b, 0x17, 0x3c, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d,
+ 0x13, 0x3d, 0x12, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x11, 0x40, 0x10, 0x40,
+ 0x0f, 0x40, 0x0f, 0x41, 0xa6, 0x00, 0x8b, 0x00, 0x75, 0x02, 0x63, 0x05,
+ 0x57, 0x07, 0x4d, 0x0b, 0x45, 0x0e, 0x3e, 0x11, 0x39, 0x13, 0x35, 0x16,
+ 0x32, 0x18, 0x2e, 0x1a, 0x2c, 0x1c, 0x29, 0x1d, 0x27, 0x1f, 0x26, 0x22,
+ 0x24, 0x22, 0x21, 0x23, 0x21, 0x25, 0x20, 0x26, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x58, 0x23, 0x4a, 0x23, 0x3f, 0x24, 0x36, 0x26, 0x30, 0x27, 0x2b, 0x29,
+ 0x27, 0x2a, 0x24, 0x2c, 0x22, 0x2d, 0x20, 0x2e, 0x1e, 0x30, 0x1c, 0x30,
+ 0x1b, 0x32, 0x1a, 0x32, 0x18, 0x33, 0x18, 0x34, 0x17, 0x34, 0x16, 0x35,
+ 0x16, 0x36, 0x15, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24,
+ 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38,
+ 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09,
+ 0x00, 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x86, 0x00,
+ 0x76, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00,
+ 0x10, 0x00, 0x09, 0x04, 0x04, 0x08, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1a,
+ 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89, 0x00, 0x7b, 0x00, 0x6b, 0x00,
+ 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x13, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x3a, 0x3a, 0x31, 0x3a,
+ 0x2a, 0x39, 0x25, 0x3a, 0x22, 0x39, 0x1e, 0x3b, 0x1c, 0x3b, 0x1a, 0x3a,
+ 0x19, 0x3a, 0x17, 0x3c, 0x16, 0x3c, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d,
+ 0x13, 0x3d, 0x12, 0x3d, 0x11, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x10, 0x40,
+ 0xa8, 0x00, 0x90, 0x00, 0x7c, 0x01, 0x6b, 0x02, 0x5f, 0x05, 0x55, 0x07,
+ 0x4c, 0x0a, 0x45, 0x0d, 0x40, 0x0f, 0x3c, 0x12, 0x37, 0x14, 0x34, 0x16,
+ 0x31, 0x18, 0x2e, 0x19, 0x2b, 0x1b, 0x2a, 0x1d, 0x28, 0x1e, 0x26, 0x20,
+ 0x25, 0x22, 0x23, 0x22, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x59, 0x23, 0x4d, 0x23,
+ 0x43, 0x24, 0x3b, 0x25, 0x34, 0x26, 0x2f, 0x27, 0x2b, 0x29, 0x28, 0x2a,
+ 0x25, 0x2b, 0x23, 0x2d, 0x21, 0x2e, 0x1f, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
+ 0x1b, 0x31, 0x1a, 0x32, 0x19, 0x32, 0x18, 0x33, 0x17, 0x34, 0x16, 0x34,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x0f, 0x00, 0x16, 0x00, 0x1c, 0x00, 0x5e, 0x00, 0x5d,
+ 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28,
+ 0x00, 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f,
+ 0x00, 0x16, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9b, 0x00, 0x95, 0x00, 0x8a, 0x00, 0x7d, 0x00, 0x6d, 0x00,
+ 0x5d, 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1d, 0x00, 0x10, 0x00,
+ 0x0a, 0x04, 0x05, 0x07, 0x00, 0x0b, 0x00, 0x11, 0x9e, 0x00, 0x9c, 0x00,
+ 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73, 0x00, 0x64, 0x00, 0x55, 0x00,
+ 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0a, 0x00,
+ 0x01, 0x00, 0x00, 0x06, 0x3a, 0x3b, 0x32, 0x3a, 0x2c, 0x39, 0x27, 0x3a,
+ 0x23, 0x39, 0x21, 0x39, 0x1e, 0x3b, 0x1c, 0x3c, 0x1a, 0x3a, 0x19, 0x3a,
+ 0x17, 0x3b, 0x17, 0x3c, 0x15, 0x3d, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d,
+ 0x13, 0x3d, 0x13, 0x3d, 0x11, 0x3d, 0x11, 0x3e, 0xaa, 0x00, 0x94, 0x00,
+ 0x82, 0x00, 0x72, 0x01, 0x65, 0x04, 0x5b, 0x05, 0x53, 0x07, 0x4b, 0x0a,
+ 0x45, 0x0c, 0x41, 0x0f, 0x3d, 0x11, 0x39, 0x12, 0x36, 0x15, 0x33, 0x16,
+ 0x30, 0x18, 0x2e, 0x19, 0x2b, 0x1a, 0x2b, 0x1d, 0x29, 0x1d, 0x26, 0x1e,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x5a, 0x23, 0x4f, 0x23, 0x46, 0x24, 0x3e, 0x24,
+ 0x37, 0x25, 0x32, 0x26, 0x2e, 0x27, 0x2b, 0x28, 0x28, 0x2a, 0x25, 0x2b,
+ 0x23, 0x2c, 0x21, 0x2d, 0x20, 0x2e, 0x1e, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
+ 0x1b, 0x31, 0x1a, 0x32, 0x19, 0x32, 0x18, 0x33, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x0e, 0x00, 0x14, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53,
+ 0x00, 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a,
+ 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
+ 0x96, 0x00, 0x8d, 0x00, 0x81, 0x00, 0x74, 0x00, 0x65, 0x00, 0x56, 0x00,
+ 0x46, 0x00, 0x37, 0x00, 0x29, 0x00, 0x1c, 0x00, 0x10, 0x00, 0x0a, 0x03,
+ 0x06, 0x07, 0x01, 0x0a, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8f, 0x00,
+ 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x43, 0x00,
+ 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x03, 0x00,
+ 0x3b, 0x3b, 0x33, 0x3b, 0x2d, 0x39, 0x29, 0x39, 0x25, 0x3a, 0x22, 0x39,
+ 0x20, 0x39, 0x1e, 0x3b, 0x1c, 0x3c, 0x1a, 0x3a, 0x19, 0x3a, 0x18, 0x3a,
+ 0x17, 0x3c, 0x16, 0x3c, 0x15, 0x3d, 0x15, 0x3e, 0x13, 0x3f, 0x13, 0x3d,
+ 0x13, 0x3d, 0x13, 0x3d, 0xaa, 0x00, 0x98, 0x00, 0x87, 0x00, 0x78, 0x01,
+ 0x6b, 0x02, 0x61, 0x04, 0x58, 0x06, 0x51, 0x08, 0x4b, 0x0a, 0x46, 0x0c,
+ 0x42, 0x0e, 0x3e, 0x0f, 0x3a, 0x12, 0x37, 0x12, 0x35, 0x16, 0x32, 0x16,
+ 0x30, 0x18, 0x2e, 0x19, 0x2b, 0x1a, 0x2b, 0x1c, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x5a, 0x23, 0x51, 0x23, 0x48, 0x23, 0x41, 0x24, 0x3a, 0x25, 0x35, 0x25,
+ 0x31, 0x26, 0x2e, 0x27, 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2b, 0x24, 0x2b,
+ 0x22, 0x2d, 0x21, 0x2d, 0x1f, 0x2e, 0x1e, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
+ 0x1b, 0x30, 0x1a, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d,
+ 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46,
+ 0x00, 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x90, 0x00,
+ 0x85, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x42, 0x00,
+ 0x34, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x06, 0x06,
+ 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91, 0x00, 0x88, 0x00, 0x7e, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00,
+ 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x3b, 0x3c, 0x34, 0x3a,
+ 0x2f, 0x3a, 0x2a, 0x39, 0x26, 0x3a, 0x23, 0x3a, 0x21, 0x39, 0x1f, 0x3a,
+ 0x1d, 0x3b, 0x1c, 0x3c, 0x1a, 0x3b, 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3b,
+ 0x17, 0x3c, 0x15, 0x3c, 0x15, 0x3d, 0x15, 0x3f, 0x13, 0x3f, 0x13, 0x3e,
+ 0xac, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7c, 0x00, 0x71, 0x01, 0x67, 0x03,
+ 0x5e, 0x05, 0x57, 0x07, 0x51, 0x08, 0x4b, 0x0a, 0x46, 0x0c, 0x42, 0x0d,
+ 0x3f, 0x0f, 0x3b, 0x11, 0x39, 0x12, 0x35, 0x14, 0x34, 0x16, 0x31, 0x16,
+ 0x30, 0x18, 0x2e, 0x19, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5b, 0x23, 0x52, 0x23,
+ 0x4a, 0x23, 0x43, 0x24, 0x3d, 0x24, 0x38, 0x25, 0x34, 0x26, 0x30, 0x27,
+ 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x24, 0x2b, 0x22, 0x2c,
+ 0x21, 0x2d, 0x20, 0x2d, 0x1f, 0x2e, 0x1d, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x5e,
+ 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39,
+ 0x00, 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3e, 0x00, 0x31, 0x00,
+ 0x25, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x9e, 0x00, 0x9d, 0x00,
+ 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6c, 0x00,
+ 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d, 0x00, 0x33, 0x00, 0x29, 0x00,
+ 0x1f, 0x00, 0x17, 0x00, 0x3b, 0x3c, 0x35, 0x3a, 0x30, 0x3b, 0x2c, 0x39,
+ 0x28, 0x3a, 0x25, 0x3b, 0x22, 0x39, 0x21, 0x39, 0x1f, 0x3a, 0x1d, 0x3b,
+ 0x1c, 0x3c, 0x1a, 0x3b, 0x19, 0x3a, 0x19, 0x3a, 0x17, 0x3a, 0x17, 0x3c,
+ 0x16, 0x3c, 0x15, 0x3c, 0x15, 0x3e, 0x14, 0x3f, 0xad, 0x00, 0x9d, 0x00,
+ 0x8e, 0x00, 0x81, 0x00, 0x76, 0x01, 0x6b, 0x02, 0x63, 0x04, 0x5c, 0x05,
+ 0x56, 0x07, 0x50, 0x08, 0x4b, 0x0a, 0x47, 0x0c, 0x43, 0x0c, 0x40, 0x0f,
+ 0x3c, 0x0f, 0x3a, 0x12, 0x37, 0x12, 0x35, 0x14, 0x33, 0x16, 0x30, 0x16,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x5b, 0x23, 0x53, 0x23, 0x4c, 0x23, 0x45, 0x23,
+ 0x40, 0x24, 0x3b, 0x25, 0x36, 0x25, 0x33, 0x26, 0x30, 0x27, 0x2d, 0x28,
+ 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x25, 0x2b, 0x23, 0x2b, 0x22, 0x2d,
+ 0x20, 0x2d, 0x20, 0x2e, 0x1e, 0x2e, 0x1d, 0x2e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57,
+ 0x00, 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c,
+ 0x00, 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00,
+ 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6b, 0x00,
+ 0x5f, 0x00, 0x53, 0x00, 0x46, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x24, 0x00,
+ 0x19, 0x00, 0x0f, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x95, 0x00,
+ 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x66, 0x00, 0x5b, 0x00,
+ 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1f, 0x00,
+ 0x3c, 0x3d, 0x36, 0x3a, 0x31, 0x3b, 0x2c, 0x3a, 0x29, 0x39, 0x26, 0x3a,
+ 0x24, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3c,
+ 0x1a, 0x3c, 0x19, 0x3a, 0x19, 0x3a, 0x17, 0x3a, 0x17, 0x3b, 0x17, 0x3c,
+ 0x15, 0x3c, 0x15, 0x3c, 0xad, 0x00, 0x9f, 0x00, 0x91, 0x00, 0x85, 0x00,
+ 0x79, 0x00, 0x6f, 0x01, 0x67, 0x02, 0x60, 0x04, 0x59, 0x05, 0x54, 0x07,
+ 0x4f, 0x08, 0x4b, 0x0a, 0x47, 0x0c, 0x43, 0x0c, 0x41, 0x0f, 0x3d, 0x0f,
+ 0x3b, 0x11, 0x38, 0x12, 0x35, 0x12, 0x35, 0x15, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x5b, 0x23, 0x54, 0x23, 0x4e, 0x23, 0x47, 0x23, 0x42, 0x24, 0x3c, 0x24,
+ 0x38, 0x25, 0x35, 0x25, 0x32, 0x26, 0x2f, 0x27, 0x2d, 0x28, 0x2a, 0x28,
+ 0x28, 0x2a, 0x26, 0x2a, 0x25, 0x2b, 0x23, 0x2b, 0x22, 0x2c, 0x21, 0x2d,
+ 0x20, 0x2d, 0x20, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3d, 0x36, 0x3a,
+ 0x32, 0x3b, 0x2d, 0x3b, 0x2b, 0x39, 0x28, 0x3a, 0x25, 0x3a, 0x23, 0x3a,
+ 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c,
+ 0x19, 0x3a, 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3a, 0x17, 0x3c, 0x16, 0x3c,
+ 0xad, 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x74, 0x01,
+ 0x6c, 0x02, 0x65, 0x03, 0x5e, 0x04, 0x58, 0x05, 0x53, 0x07, 0x4f, 0x08,
+ 0x4b, 0x0a, 0x47, 0x0b, 0x44, 0x0c, 0x41, 0x0e, 0x3e, 0x0f, 0x3b, 0x0f,
+ 0x3a, 0x12, 0x37, 0x12, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x55, 0x23,
+ 0x4f, 0x23, 0x49, 0x23, 0x44, 0x24, 0x3f, 0x24, 0x3b, 0x25, 0x37, 0x25,
+ 0x34, 0x26, 0x31, 0x26, 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29,
+ 0x27, 0x2a, 0x25, 0x2b, 0x24, 0x2b, 0x22, 0x2b, 0x22, 0x2d, 0x20, 0x2d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3b, 0x33, 0x3b, 0x2f, 0x3b,
+ 0x2b, 0x39, 0x29, 0x39, 0x26, 0x3a, 0x24, 0x3b, 0x22, 0x3a, 0x21, 0x39,
+ 0x1f, 0x39, 0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b,
+ 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3a, 0x17, 0x3b, 0xae, 0x00, 0xa2, 0x00,
+ 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x77, 0x00, 0x6f, 0x01, 0x67, 0x02,
+ 0x61, 0x04, 0x5c, 0x05, 0x57, 0x05, 0x52, 0x07, 0x4e, 0x08, 0x4b, 0x0a,
+ 0x47, 0x0b, 0x44, 0x0c, 0x41, 0x0d, 0x3f, 0x0f, 0x3c, 0x0f, 0x3b, 0x11,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x56, 0x23, 0x50, 0x23, 0x4a, 0x23,
+ 0x45, 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39, 0x25, 0x35, 0x25, 0x33, 0x26,
+ 0x30, 0x26, 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a,
+ 0x25, 0x2a, 0x24, 0x2b, 0x23, 0x2b, 0x22, 0x2c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x3e, 0x37, 0x3b, 0x33, 0x3a, 0x2f, 0x3b, 0x2c, 0x3a, 0x2a, 0x39,
+ 0x27, 0x3a, 0x25, 0x3a, 0x23, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x39,
+ 0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b, 0x19, 0x3a,
+ 0x19, 0x3a, 0x17, 0x3a, 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00,
+ 0x84, 0x00, 0x7a, 0x00, 0x72, 0x01, 0x6c, 0x02, 0x65, 0x02, 0x5f, 0x04,
+ 0x5a, 0x05, 0x56, 0x05, 0x52, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0b,
+ 0x45, 0x0c, 0x41, 0x0c, 0x40, 0x0f, 0x3d, 0x0f, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x5c, 0x23, 0x56, 0x23, 0x51, 0x23, 0x4c, 0x23, 0x47, 0x23, 0x42, 0x24,
+ 0x3e, 0x24, 0x3b, 0x25, 0x37, 0x25, 0x34, 0x25, 0x32, 0x26, 0x30, 0x26,
+ 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a, 0x25, 0x2a,
+ 0x25, 0x2b, 0x23, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x38, 0x3c,
+ 0x34, 0x3a, 0x30, 0x3b, 0x2d, 0x3b, 0x2a, 0x39, 0x28, 0x39, 0x26, 0x3a,
+ 0x24, 0x3b, 0x22, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x39, 0x1e, 0x3b,
+ 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b, 0x19, 0x3a, 0x19, 0x3a,
+ 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x90, 0x00, 0x87, 0x00, 0x7e, 0x00,
+ 0x76, 0x00, 0x6f, 0x01, 0x68, 0x02, 0x62, 0x04, 0x5e, 0x04, 0x59, 0x05,
+ 0x55, 0x06, 0x51, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x45, 0x0c,
+ 0x41, 0x0c, 0x41, 0x0f, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x57, 0x23,
+ 0x52, 0x23, 0x4d, 0x23, 0x48, 0x23, 0x44, 0x23, 0x40, 0x24, 0x3c, 0x24,
+ 0x39, 0x25, 0x36, 0x25, 0x34, 0x25, 0x31, 0x26, 0x2f, 0x27, 0x2d, 0x27,
+ 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a, 0x25, 0x2a, 0x25, 0x2b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x38, 0x3c, 0x34, 0x3a, 0x31, 0x3b,
+ 0x2e, 0x3c, 0x2b, 0x39, 0x29, 0x39, 0x27, 0x3a, 0x25, 0x3a, 0x24, 0x3b,
+ 0x21, 0x3a, 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b,
+ 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3a, 0xaf, 0x00, 0xa6, 0x00,
+ 0x9b, 0x00, 0x91, 0x00, 0x88, 0x00, 0x80, 0x00, 0x78, 0x00, 0x71, 0x01,
+ 0x6b, 0x02, 0x66, 0x02, 0x61, 0x04, 0x5c, 0x04, 0x58, 0x05, 0x55, 0x07,
+ 0x50, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0c,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4d, 0x23,
+ 0x49, 0x23, 0x45, 0x23, 0x41, 0x24, 0x3d, 0x24, 0x3b, 0x24, 0x38, 0x25,
+ 0x35, 0x25, 0x33, 0x26, 0x31, 0x26, 0x2f, 0x27, 0x2d, 0x27, 0x2c, 0x28,
+ 0x2a, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x3e, 0x38, 0x3d, 0x35, 0x3a, 0x32, 0x3b, 0x2e, 0x3b, 0x2c, 0x3a,
+ 0x2a, 0x39, 0x27, 0x39, 0x26, 0x3a, 0x24, 0x3a, 0x23, 0x3b, 0x21, 0x39,
+ 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c,
+ 0x1a, 0x3c, 0x19, 0x3c, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x93, 0x00,
+ 0x8b, 0x00, 0x83, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x6e, 0x01, 0x69, 0x02,
+ 0x63, 0x03, 0x5f, 0x04, 0x5b, 0x05, 0x56, 0x05, 0x54, 0x07, 0x4f, 0x07,
+ 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x46, 0x0c, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x5d, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4f, 0x23, 0x4a, 0x23, 0x46, 0x23,
+ 0x43, 0x24, 0x3f, 0x24, 0x3c, 0x24, 0x39, 0x25, 0x36, 0x25, 0x34, 0x25,
+ 0x33, 0x26, 0x30, 0x26, 0x2f, 0x27, 0x2d, 0x27, 0x2c, 0x28, 0x2a, 0x28,
+ 0x28, 0x28, 0x28, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x39, 0x3e,
+ 0x35, 0x3a, 0x32, 0x3a, 0x2f, 0x3b, 0x2d, 0x3c, 0x2a, 0x39, 0x28, 0x39,
+ 0x27, 0x3a, 0x24, 0x3a, 0x24, 0x3b, 0x22, 0x3b, 0x21, 0x39, 0x20, 0x39,
+ 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c,
+ 0xb0, 0x00, 0xa7, 0x00, 0x9e, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x86, 0x00,
+ 0x7e, 0x00, 0x77, 0x00, 0x71, 0x01, 0x6b, 0x01, 0x66, 0x02, 0x62, 0x04,
+ 0x5d, 0x04, 0x5a, 0x05, 0x55, 0x05, 0x53, 0x07, 0x4f, 0x07, 0x4e, 0x09,
+ 0x4a, 0x0a, 0x47, 0x0a, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5d, 0x23, 0x58, 0x23,
+ 0x54, 0x23, 0x50, 0x23, 0x4c, 0x23, 0x48, 0x23, 0x44, 0x23, 0x40, 0x24,
+ 0x3d, 0x24, 0x3a, 0x24, 0x38, 0x25, 0x36, 0x25, 0x33, 0x25, 0x32, 0x26,
+ 0x2f, 0x26, 0x2f, 0x27, 0x2c, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x28,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x39, 0x3e, 0x35, 0x3b, 0x32, 0x3a,
+ 0x30, 0x3b, 0x2e, 0x3c, 0x2b, 0x3a, 0x2a, 0x39, 0x27, 0x39, 0x26, 0x3a,
+ 0x24, 0x3a, 0x23, 0x3b, 0x21, 0x3a, 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x39,
+ 0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0xb1, 0x00, 0xa7, 0x00,
+ 0x9f, 0x00, 0x97, 0x00, 0x8f, 0x00, 0x87, 0x00, 0x80, 0x00, 0x79, 0x00,
+ 0x73, 0x00, 0x6e, 0x01, 0x69, 0x02, 0x64, 0x02, 0x60, 0x04, 0x5c, 0x04,
+ 0x59, 0x05, 0x55, 0x05, 0x53, 0x07, 0x4e, 0x07, 0x4e, 0x09, 0x4a, 0x0a,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x5d, 0x23, 0x58, 0x23, 0x54, 0x23, 0x50, 0x23,
+ 0x4c, 0x23, 0x48, 0x23, 0x45, 0x23, 0x42, 0x24, 0x3f, 0x24, 0x3c, 0x24,
+ 0x39, 0x25, 0x37, 0x25, 0x35, 0x25, 0x33, 0x25, 0x31, 0x26, 0x2f, 0x26,
+ 0x2e, 0x27, 0x2c, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x94, 0x00, 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xa9, 0x00,
+ 0xab, 0x00, 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00,
+ 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb1, 0x00,
+ 0xb2, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x21, 0x00, 0x6e, 0x00,
+ 0x8a, 0x00, 0x97, 0x00, 0x9e, 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa8, 0x00,
+ 0xaa, 0x00, 0xaa, 0x00, 0xac, 0x00, 0xad, 0x00, 0xad, 0x00, 0xad, 0x00,
+ 0xae, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00,
+ 0x6c, 0x00, 0x92, 0x00, 0xa1, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xac, 0x00,
+ 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2, 0x00,
+ 0xb2, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00,
+ 0xb3, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x04, 0x70, 0x01,
+ 0x7f, 0x00, 0x88, 0x00, 0x90, 0x00, 0x95, 0x00, 0x99, 0x00, 0x9c, 0x00,
+ 0x9f, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7, 0x00,
+ 0xa7, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x1c, 0x3a, 0x03, 0x59, 0x00, 0x6c, 0x00,
+ 0x79, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00,
+ 0x9b, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00,
+ 0xa5, 0x00, 0xa6, 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x60, 0x0e, 0x79, 0x01,
+ 0x88, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa3, 0x00,
+ 0xa5, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00,
+ 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4e, 0x0f, 0x60, 0x07, 0x6d, 0x03, 0x77, 0x01,
+ 0x7f, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x8f, 0x00, 0x92, 0x00, 0x94, 0x00,
+ 0x97, 0x00, 0x9a, 0x00, 0x9c, 0x00, 0x9e, 0x00, 0xa0, 0x00, 0xa1, 0x00,
+ 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa4, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x0a, 0x29, 0x27, 0x0f, 0x40, 0x06, 0x52, 0x02, 0x61, 0x00, 0x6c, 0x00,
+ 0x75, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x87, 0x00, 0x8b, 0x00, 0x8e, 0x00,
+ 0x91, 0x00, 0x94, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9b, 0x00,
+ 0x9d, 0x00, 0x9e, 0x00, 0x60, 0x14, 0x6f, 0x07, 0x7b, 0x03, 0x84, 0x01,
+ 0x8c, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9d, 0x00, 0x9f, 0x00,
+ 0xa1, 0x00, 0xa2, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa7, 0x00, 0xa7, 0x00,
+ 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x49, 0x17, 0x56, 0x0d, 0x62, 0x07, 0x6b, 0x04, 0x73, 0x02, 0x79, 0x01,
+ 0x7e, 0x01, 0x83, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00,
+ 0x92, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00,
+ 0x9e, 0x00, 0x9f, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x31, 0x1e, 0x18,
+ 0x32, 0x0d, 0x43, 0x07, 0x50, 0x04, 0x5a, 0x02, 0x63, 0x01, 0x6b, 0x00,
+ 0x72, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x85, 0x00, 0x88, 0x00,
+ 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00,
+ 0x60, 0x18, 0x6b, 0x0c, 0x74, 0x06, 0x7d, 0x03, 0x83, 0x02, 0x89, 0x01,
+ 0x8d, 0x00, 0x91, 0x00, 0x95, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00,
+ 0x9e, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xa4, 0x00,
+ 0xa5, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x1d, 0x51, 0x12,
+ 0x5b, 0x0c, 0x63, 0x08, 0x6a, 0x05, 0x70, 0x03, 0x77, 0x02, 0x7b, 0x02,
+ 0x7e, 0x01, 0x82, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8c, 0x00, 0x8e, 0x00,
+ 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x97, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x36, 0x19, 0x1f, 0x2a, 0x12, 0x38, 0x0b,
+ 0x44, 0x07, 0x4e, 0x05, 0x57, 0x02, 0x5f, 0x01, 0x65, 0x01, 0x6b, 0x00,
+ 0x71, 0x00, 0x76, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x84, 0x00,
+ 0x87, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x60, 0x1b, 0x68, 0x0f,
+ 0x70, 0x09, 0x77, 0x05, 0x7d, 0x03, 0x82, 0x02, 0x87, 0x01, 0x8b, 0x00,
+ 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00,
+ 0x9b, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x45, 0x21, 0x4e, 0x16, 0x56, 0x10, 0x5d, 0x0b,
+ 0x65, 0x08, 0x69, 0x06, 0x6f, 0x04, 0x74, 0x03, 0x78, 0x02, 0x7b, 0x02,
+ 0x7e, 0x01, 0x81, 0x01, 0x85, 0x00, 0x88, 0x00, 0x8a, 0x00, 0x8c, 0x00,
+ 0x8e, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x92, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x09, 0x3a, 0x17, 0x24, 0x24, 0x18, 0x30, 0x10, 0x3b, 0x0b, 0x45, 0x07,
+ 0x4d, 0x05, 0x55, 0x04, 0x5b, 0x02, 0x61, 0x01, 0x67, 0x01, 0x6b, 0x00,
+ 0x6f, 0x00, 0x74, 0x00, 0x77, 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x80, 0x00,
+ 0x83, 0x00, 0x86, 0x00, 0x60, 0x1d, 0x67, 0x12, 0x6d, 0x0c, 0x73, 0x08,
+ 0x79, 0x05, 0x7e, 0x03, 0x82, 0x02, 0x86, 0x02, 0x89, 0x01, 0x8c, 0x00,
+ 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0x99, 0x00,
+ 0x9a, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x44, 0x24, 0x4c, 0x1a, 0x53, 0x13, 0x59, 0x0e, 0x5f, 0x0b, 0x65, 0x08,
+ 0x69, 0x06, 0x6d, 0x05, 0x73, 0x04, 0x76, 0x03, 0x79, 0x02, 0x7c, 0x02,
+ 0x7e, 0x01, 0x81, 0x01, 0x84, 0x00, 0x87, 0x00, 0x89, 0x00, 0x8b, 0x00,
+ 0x8c, 0x00, 0x8d, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x3b, 0x14, 0x28,
+ 0x20, 0x1c, 0x2a, 0x14, 0x34, 0x0f, 0x3e, 0x0b, 0x45, 0x07, 0x4c, 0x05,
+ 0x53, 0x04, 0x58, 0x03, 0x5e, 0x02, 0x63, 0x01, 0x67, 0x01, 0x6c, 0x00,
+ 0x6f, 0x00, 0x72, 0x00, 0x76, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7e, 0x00,
+ 0x60, 0x1d, 0x66, 0x14, 0x6b, 0x0e, 0x71, 0x0a, 0x76, 0x07, 0x7a, 0x05,
+ 0x7e, 0x03, 0x81, 0x02, 0x85, 0x02, 0x88, 0x01, 0x8b, 0x01, 0x8d, 0x00,
+ 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x98, 0x00,
+ 0x99, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x27, 0x4a, 0x1d,
+ 0x4f, 0x16, 0x57, 0x11, 0x5b, 0x0e, 0x61, 0x0b, 0x66, 0x08, 0x69, 0x07,
+ 0x6d, 0x05, 0x71, 0x04, 0x75, 0x03, 0x77, 0x02, 0x7a, 0x02, 0x7c, 0x02,
+ 0x7e, 0x01, 0x80, 0x01, 0x83, 0x01, 0x86, 0x00, 0x88, 0x00, 0x89, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x3d, 0x13, 0x2c, 0x1c, 0x20, 0x27, 0x18,
+ 0x2f, 0x12, 0x38, 0x0e, 0x3e, 0x0a, 0x45, 0x07, 0x4b, 0x06, 0x51, 0x05,
+ 0x57, 0x04, 0x5c, 0x02, 0x60, 0x02, 0x65, 0x01, 0x67, 0x01, 0x6c, 0x00,
+ 0x6f, 0x00, 0x71, 0x00, 0x75, 0x00, 0x77, 0x00, 0x60, 0x1e, 0x65, 0x16,
+ 0x6a, 0x10, 0x6f, 0x0c, 0x73, 0x09, 0x77, 0x07, 0x7b, 0x05, 0x7e, 0x03,
+ 0x81, 0x03, 0x84, 0x02, 0x87, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8e, 0x00,
+ 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00,
+ 0x27, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x8f, 0x00, 0x96, 0x00, 0x99, 0x00,
+ 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00,
+ 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x2c, 0x14, 0x57, 0x00,
+ 0x82, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x00,
+ 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00,
+ 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8c, 0x00, 0x63, 0x00, 0x7f, 0x00, 0x89, 0x00, 0x90, 0x00, 0x96, 0x00,
+ 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00,
+ 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x31, 0x11, 0x5f, 0x00,
+ 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00,
+ 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00,
+ 0x9e, 0x00, 0x9e, 0x00, 0x43, 0x29, 0x48, 0x20, 0x4d, 0x19, 0x54, 0x14,
+ 0x58, 0x10, 0x5c, 0x0d, 0x62, 0x0b, 0x66, 0x09, 0x69, 0x07, 0x6c, 0x06,
+ 0x70, 0x05, 0x74, 0x04, 0x76, 0x03, 0x78, 0x02, 0x7a, 0x02, 0x7c, 0x02,
+ 0x7e, 0x02, 0x80, 0x01, 0x82, 0x01, 0x85, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x09, 0x3f, 0x11, 0x2f, 0x1b, 0x23, 0x23, 0x1b, 0x2b, 0x15, 0x32, 0x11,
+ 0x39, 0x0d, 0x40, 0x0a, 0x45, 0x08, 0x4b, 0x07, 0x51, 0x05, 0x56, 0x04,
+ 0x59, 0x03, 0x5e, 0x02, 0x61, 0x02, 0x65, 0x01, 0x68, 0x01, 0x6b, 0x00,
+ 0x6e, 0x00, 0x71, 0x00, 0x60, 0x1f, 0x64, 0x17, 0x69, 0x11, 0x6d, 0x0d,
+ 0x71, 0x0a, 0x75, 0x08, 0x78, 0x06, 0x7b, 0x05, 0x7e, 0x04, 0x81, 0x03,
+ 0x84, 0x02, 0x86, 0x02, 0x88, 0x01, 0x8a, 0x01, 0x8c, 0x01, 0x8e, 0x00,
+ 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x00, 0x00, 0x0d, 0x00,
+ 0x4f, 0x00, 0x73, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x95, 0x00,
+ 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00,
+ 0x9c, 0x00, 0x9d, 0x00, 0x01, 0x29, 0x16, 0x04, 0x57, 0x00, 0x78, 0x00,
+ 0x87, 0x00, 0x8f, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00,
+ 0x9b, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x4d, 0x00,
+ 0x60, 0x00, 0x77, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x92, 0x00, 0x95, 0x00,
+ 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00,
+ 0x9c, 0x00, 0x9d, 0x00, 0x03, 0x23, 0x20, 0x00, 0x5f, 0x00, 0x7c, 0x00,
+ 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a, 0x00,
+ 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00,
+ 0x43, 0x2b, 0x47, 0x22, 0x4c, 0x1b, 0x51, 0x16, 0x56, 0x12, 0x59, 0x0f,
+ 0x5e, 0x0d, 0x63, 0x0b, 0x66, 0x09, 0x69, 0x07, 0x6b, 0x06, 0x6f, 0x05,
+ 0x73, 0x05, 0x75, 0x03, 0x77, 0x03, 0x79, 0x02, 0x7a, 0x02, 0x7c, 0x02,
+ 0x7e, 0x02, 0x7f, 0x01, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x40, 0x11, 0x31,
+ 0x18, 0x26, 0x20, 0x1e, 0x28, 0x18, 0x2f, 0x13, 0x35, 0x0f, 0x3c, 0x0c,
+ 0x41, 0x0a, 0x46, 0x08, 0x4b, 0x07, 0x50, 0x05, 0x54, 0x04, 0x58, 0x04,
+ 0x5c, 0x02, 0x5f, 0x02, 0x62, 0x02, 0x66, 0x01, 0x69, 0x01, 0x6b, 0x00,
+ 0x60, 0x20, 0x64, 0x18, 0x68, 0x13, 0x6b, 0x0f, 0x6f, 0x0c, 0x73, 0x09,
+ 0x76, 0x07, 0x79, 0x06, 0x7c, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02,
+ 0x85, 0x02, 0x88, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8d, 0x01, 0x8e, 0x00,
+ 0x90, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x38, 0x00,
+ 0x5b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00,
+ 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00,
+ 0x00, 0x49, 0x00, 0x27, 0x12, 0x01, 0x43, 0x00, 0x61, 0x00, 0x74, 0x00,
+ 0x7f, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90, 0x00, 0x93, 0x00, 0x95, 0x00,
+ 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x60, 0x00, 0x24, 0x00, 0x48, 0x00,
+ 0x60, 0x00, 0x70, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00,
+ 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00,
+ 0x00, 0x46, 0x00, 0x1f, 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79, 0x00,
+ 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96, 0x00,
+ 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x43, 0x2d, 0x46, 0x24,
+ 0x4b, 0x1e, 0x4f, 0x19, 0x55, 0x14, 0x58, 0x11, 0x5b, 0x0e, 0x5f, 0x0c,
+ 0x64, 0x0a, 0x66, 0x09, 0x68, 0x07, 0x6a, 0x06, 0x6e, 0x06, 0x72, 0x05,
+ 0x74, 0x04, 0x76, 0x03, 0x78, 0x03, 0x79, 0x02, 0x7b, 0x02, 0x7c, 0x02,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x40, 0x10, 0x33, 0x17, 0x28, 0x1e, 0x20,
+ 0x25, 0x1a, 0x2c, 0x16, 0x32, 0x12, 0x37, 0x0f, 0x3d, 0x0c, 0x42, 0x0a,
+ 0x46, 0x08, 0x4b, 0x07, 0x4f, 0x05, 0x53, 0x05, 0x57, 0x04, 0x5a, 0x04,
+ 0x5e, 0x02, 0x61, 0x02, 0x63, 0x01, 0x66, 0x01, 0x60, 0x20, 0x63, 0x19,
+ 0x67, 0x14, 0x6a, 0x10, 0x6e, 0x0d, 0x71, 0x0b, 0x74, 0x09, 0x77, 0x07,
+ 0x7a, 0x06, 0x7c, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02,
+ 0x87, 0x02, 0x88, 0x02, 0x8a, 0x01, 0x8c, 0x01, 0x8d, 0x00, 0x8e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2a, 0x00, 0x48, 0x00,
+ 0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00,
+ 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x54, 0x00, 0x41,
+ 0x00, 0x17, 0x10, 0x00, 0x36, 0x00, 0x51, 0x00, 0x64, 0x00, 0x71, 0x00,
+ 0x7a, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8d, 0x00, 0x90, 0x00,
+ 0x92, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x89, 0x00, 0x77, 0x00, 0x48, 0x00, 0x0f, 0x00, 0x30, 0x00, 0x48, 0x00,
+ 0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00,
+ 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x52, 0x00, 0x3c,
+ 0x00, 0x0d, 0x1f, 0x00, 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76, 0x00,
+ 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91, 0x00,
+ 0x93, 0x00, 0x95, 0x00, 0x42, 0x2e, 0x45, 0x26, 0x4b, 0x1f, 0x4d, 0x1a,
+ 0x52, 0x16, 0x56, 0x13, 0x59, 0x10, 0x5c, 0x0e, 0x61, 0x0c, 0x64, 0x0a,
+ 0x66, 0x09, 0x68, 0x07, 0x6a, 0x07, 0x6d, 0x06, 0x71, 0x05, 0x74, 0x05,
+ 0x75, 0x03, 0x77, 0x03, 0x78, 0x02, 0x7a, 0x02, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x09, 0x41, 0x0f, 0x34, 0x16, 0x2a, 0x1c, 0x23, 0x23, 0x1d, 0x29, 0x18,
+ 0x2e, 0x14, 0x34, 0x11, 0x39, 0x0e, 0x3e, 0x0c, 0x42, 0x0a, 0x47, 0x08,
+ 0x4b, 0x07, 0x4f, 0x05, 0x52, 0x05, 0x56, 0x04, 0x59, 0x04, 0x5c, 0x03,
+ 0x5f, 0x02, 0x62, 0x02, 0x60, 0x20, 0x63, 0x1a, 0x66, 0x15, 0x6a, 0x11,
+ 0x6d, 0x0e, 0x70, 0x0c, 0x73, 0x0a, 0x75, 0x08, 0x78, 0x07, 0x7a, 0x06,
+ 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02, 0x86, 0x02,
+ 0x88, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00,
+ 0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00,
+ 0x86, 0x00, 0x89, 0x00, 0x00, 0x59, 0x00, 0x4d, 0x00, 0x2f, 0x00, 0x0e,
+ 0x10, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x57, 0x00, 0x64, 0x00, 0x6f, 0x00,
+ 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85, 0x00, 0x89, 0x00, 0x8b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x83, 0x00,
+ 0x60, 0x00, 0x30, 0x00, 0x02, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00,
+ 0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00,
+ 0x86, 0x00, 0x89, 0x00, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02,
+ 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74, 0x00,
+ 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00,
+ 0x42, 0x2f, 0x44, 0x27, 0x4a, 0x22, 0x4c, 0x1c, 0x50, 0x18, 0x55, 0x14,
+ 0x57, 0x12, 0x5a, 0x0f, 0x5d, 0x0d, 0x62, 0x0c, 0x64, 0x0a, 0x66, 0x09,
+ 0x68, 0x08, 0x6a, 0x07, 0x6c, 0x06, 0x70, 0x05, 0x73, 0x05, 0x75, 0x04,
+ 0x76, 0x03, 0x78, 0x03, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x42, 0x0f, 0x36,
+ 0x15, 0x2c, 0x1b, 0x25, 0x21, 0x1f, 0x26, 0x1a, 0x2c, 0x16, 0x31, 0x12,
+ 0x36, 0x0f, 0x3a, 0x0d, 0x3f, 0x0c, 0x43, 0x0a, 0x47, 0x08, 0x4b, 0x07,
+ 0x4e, 0x05, 0x52, 0x05, 0x55, 0x04, 0x58, 0x04, 0x5b, 0x04, 0x5d, 0x02,
+ 0x60, 0x21, 0x63, 0x1b, 0x66, 0x16, 0x69, 0x12, 0x6c, 0x0f, 0x6e, 0x0d,
+ 0x71, 0x0b, 0x74, 0x09, 0x76, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7d, 0x05,
+ 0x7f, 0x04, 0x81, 0x03, 0x82, 0x02, 0x84, 0x02, 0x86, 0x02, 0x87, 0x02,
+ 0x89, 0x02, 0x8a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00,
+ 0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00,
+ 0x00, 0x5b, 0x00, 0x53, 0x00, 0x3e, 0x00, 0x23, 0x02, 0x0a, 0x10, 0x00,
+ 0x29, 0x00, 0x3d, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x65, 0x00, 0x6d, 0x00,
+ 0x74, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x70, 0x00, 0x48, 0x00,
+ 0x22, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00,
+ 0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00,
+ 0x00, 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x04, 0x00, 0x1f, 0x00,
+ 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73, 0x00,
+ 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85, 0x00, 0x42, 0x31, 0x44, 0x29,
+ 0x49, 0x23, 0x4c, 0x1e, 0x4e, 0x1a, 0x53, 0x16, 0x56, 0x13, 0x58, 0x11,
+ 0x5a, 0x0f, 0x5f, 0x0d, 0x63, 0x0b, 0x64, 0x0a, 0x66, 0x09, 0x68, 0x08,
+ 0x6a, 0x07, 0x6b, 0x06, 0x6f, 0x06, 0x72, 0x05, 0x74, 0x05, 0x75, 0x03,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x43, 0x0f, 0x37, 0x14, 0x2e, 0x19, 0x27,
+ 0x1f, 0x21, 0x24, 0x1c, 0x29, 0x18, 0x2e, 0x15, 0x33, 0x12, 0x37, 0x0f,
+ 0x3b, 0x0c, 0x40, 0x0c, 0x43, 0x0a, 0x47, 0x08, 0x4b, 0x07, 0x4e, 0x06,
+ 0x51, 0x05, 0x55, 0x05, 0x56, 0x04, 0x5a, 0x04, 0x60, 0x21, 0x63, 0x1b,
+ 0x65, 0x17, 0x68, 0x13, 0x6b, 0x10, 0x6e, 0x0e, 0x70, 0x0c, 0x73, 0x0a,
+ 0x75, 0x09, 0x77, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7d, 0x05, 0x7f, 0x04,
+ 0x81, 0x03, 0x82, 0x03, 0x84, 0x02, 0x86, 0x02, 0x87, 0x02, 0x88, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00,
+ 0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x5c, 0x00, 0x56,
+ 0x00, 0x47, 0x00, 0x31, 0x00, 0x1a, 0x04, 0x08, 0x10, 0x00, 0x25, 0x00,
+ 0x37, 0x00, 0x46, 0x00, 0x52, 0x00, 0x5d, 0x00, 0x65, 0x00, 0x6c, 0x00,
+ 0x72, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00,
+ 0x01, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00,
+ 0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x5c, 0x00, 0x55,
+ 0x00, 0x43, 0x00, 0x2a, 0x00, 0x10, 0x09, 0x00, 0x1f, 0x00, 0x33, 0x00,
+ 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72, 0x00,
+ 0x77, 0x00, 0x7b, 0x00, 0x42, 0x31, 0x44, 0x2a, 0x48, 0x24, 0x4b, 0x1f,
+ 0x4d, 0x1b, 0x51, 0x18, 0x55, 0x15, 0x57, 0x12, 0x59, 0x10, 0x5b, 0x0e,
+ 0x5f, 0x0c, 0x63, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x6a, 0x07,
+ 0x6b, 0x06, 0x6e, 0x06, 0x71, 0x05, 0x73, 0x05, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x0a, 0x43, 0x0e, 0x38, 0x13, 0x2f, 0x18, 0x28, 0x1d, 0x22, 0x22, 0x1d,
+ 0x27, 0x19, 0x2b, 0x16, 0x30, 0x12, 0x35, 0x11, 0x39, 0x0f, 0x3c, 0x0c,
+ 0x41, 0x0b, 0x44, 0x0a, 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x50, 0x05,
+ 0x54, 0x05, 0x55, 0x04, 0x60, 0x21, 0x63, 0x1c, 0x65, 0x17, 0x68, 0x14,
+ 0x6a, 0x11, 0x6c, 0x0e, 0x6f, 0x0c, 0x71, 0x0b, 0x73, 0x09, 0x76, 0x08,
+ 0x78, 0x07, 0x79, 0x06, 0x7c, 0x05, 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03,
+ 0x82, 0x03, 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00,
+ 0x5f, 0x00, 0x66, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4d, 0x00, 0x3b,
+ 0x00, 0x27, 0x00, 0x13, 0x06, 0x07, 0x10, 0x00, 0x22, 0x00, 0x32, 0x00,
+ 0x40, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95, 0x00,
+ 0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00,
+ 0x5f, 0x00, 0x66, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36,
+ 0x00, 0x1f, 0x00, 0x08, 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f, 0x00,
+ 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71, 0x00,
+ 0x42, 0x32, 0x44, 0x2b, 0x47, 0x25, 0x4b, 0x21, 0x4c, 0x1d, 0x4f, 0x19,
+ 0x54, 0x16, 0x56, 0x14, 0x58, 0x11, 0x5a, 0x10, 0x5d, 0x0e, 0x61, 0x0c,
+ 0x63, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x69, 0x07, 0x6b, 0x07,
+ 0x6d, 0x06, 0x71, 0x05, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x43, 0x0e, 0x39,
+ 0x12, 0x31, 0x17, 0x2a, 0x1c, 0x24, 0x21, 0x1f, 0x26, 0x1b, 0x2a, 0x18,
+ 0x2e, 0x16, 0x32, 0x12, 0x35, 0x0f, 0x3a, 0x0f, 0x3d, 0x0c, 0x41, 0x0b,
+ 0x44, 0x0a, 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x4f, 0x05, 0x53, 0x05,
+ 0x60, 0x21, 0x62, 0x1c, 0x65, 0x18, 0x67, 0x15, 0x6a, 0x12, 0x6c, 0x0f,
+ 0x6e, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x74, 0x09, 0x76, 0x07, 0x79, 0x07,
+ 0x7a, 0x06, 0x7c, 0x05, 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x82, 0x03,
+ 0x83, 0x02, 0x85, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00,
+ 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x42, 0x00, 0x32, 0x00, 0x20,
+ 0x00, 0x0e, 0x07, 0x06, 0x10, 0x00, 0x20, 0x00, 0x2f, 0x00, 0x3b, 0x00,
+ 0x46, 0x00, 0x50, 0x00, 0x58, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00,
+ 0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00,
+ 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17,
+ 0x00, 0x03, 0x0f, 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46, 0x00,
+ 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66, 0x00, 0x42, 0x33, 0x43, 0x2c,
+ 0x46, 0x27, 0x4a, 0x22, 0x4c, 0x1e, 0x4d, 0x1b, 0x52, 0x18, 0x55, 0x15,
+ 0x57, 0x13, 0x58, 0x11, 0x5a, 0x0f, 0x5e, 0x0e, 0x62, 0x0c, 0x63, 0x0b,
+ 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x69, 0x07, 0x6b, 0x07, 0x6c, 0x06,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0d, 0x3a, 0x12, 0x32, 0x16, 0x2b,
+ 0x1b, 0x26, 0x1f, 0x22, 0x24, 0x1d, 0x28, 0x19, 0x2b, 0x16, 0x30, 0x14,
+ 0x34, 0x12, 0x37, 0x0f, 0x3b, 0x0e, 0x3e, 0x0c, 0x41, 0x0b, 0x45, 0x0a,
+ 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x4f, 0x05, 0x60, 0x22, 0x62, 0x1d,
+ 0x65, 0x19, 0x66, 0x15, 0x69, 0x13, 0x6b, 0x11, 0x6d, 0x0e, 0x6f, 0x0c,
+ 0x71, 0x0b, 0x73, 0x0a, 0x76, 0x09, 0x77, 0x07, 0x79, 0x07, 0x7a, 0x06,
+ 0x7c, 0x05, 0x7e, 0x05, 0x7f, 0x04, 0x80, 0x03, 0x82, 0x03, 0x83, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x5e, 0x00, 0x5b,
+ 0x00, 0x53, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2a, 0x00, 0x1a, 0x00, 0x0b,
+ 0x08, 0x05, 0x10, 0x00, 0x1e, 0x00, 0x2c, 0x00, 0x37, 0x00, 0x42, 0x00,
+ 0x4b, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00,
+ 0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x5e, 0x00, 0x5b,
+ 0x00, 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00,
+ 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c, 0x00,
+ 0x54, 0x00, 0x5b, 0x00, 0x42, 0x33, 0x43, 0x2d, 0x45, 0x28, 0x49, 0x23,
+ 0x4b, 0x1f, 0x4d, 0x1c, 0x50, 0x19, 0x55, 0x16, 0x56, 0x14, 0x58, 0x12,
+ 0x59, 0x11, 0x5b, 0x0e, 0x5f, 0x0d, 0x62, 0x0c, 0x63, 0x0b, 0x65, 0x0a,
+ 0x66, 0x09, 0x68, 0x09, 0x69, 0x07, 0x6b, 0x07, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x0a, 0x44, 0x0d, 0x3a, 0x12, 0x33, 0x16, 0x2c, 0x19, 0x27, 0x1e, 0x22,
+ 0x21, 0x1e, 0x26, 0x1a, 0x2b, 0x18, 0x2e, 0x16, 0x31, 0x12, 0x35, 0x11,
+ 0x38, 0x0f, 0x3b, 0x0d, 0x3f, 0x0c, 0x41, 0x0a, 0x45, 0x0a, 0x47, 0x09,
+ 0x4a, 0x07, 0x4e, 0x07, 0x60, 0x22, 0x62, 0x1d, 0x64, 0x19, 0x66, 0x16,
+ 0x68, 0x13, 0x6a, 0x11, 0x6c, 0x0f, 0x6e, 0x0d, 0x71, 0x0c, 0x73, 0x0b,
+ 0x74, 0x09, 0x76, 0x08, 0x78, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7c, 0x05,
+ 0x7e, 0x05, 0x7f, 0x04, 0x80, 0x03, 0x82, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00,
+ 0x33, 0x00, 0x3d, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4c,
+ 0x00, 0x40, 0x00, 0x32, 0x00, 0x24, 0x00, 0x15, 0x02, 0x0a, 0x09, 0x04,
+ 0x10, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x34, 0x00, 0x3e, 0x00, 0x46, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
+ 0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00,
+ 0x33, 0x00, 0x3d, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49,
+ 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x04, 0x00, 0x12, 0x00,
+ 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50, 0x00,
+ 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29, 0x49, 0x24, 0x4b, 0x20, 0x4c, 0x1d,
+ 0x4e, 0x1a, 0x53, 0x18, 0x55, 0x15, 0x56, 0x13, 0x58, 0x11, 0x5a, 0x10,
+ 0x5c, 0x0e, 0x60, 0x0d, 0x63, 0x0c, 0x64, 0x0b, 0x65, 0x0a, 0x66, 0x09,
+ 0x68, 0x09, 0x69, 0x07, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0c, 0x3b,
+ 0x11, 0x34, 0x16, 0x2e, 0x19, 0x28, 0x1d, 0x23, 0x21, 0x20, 0x25, 0x1d,
+ 0x29, 0x19, 0x2b, 0x16, 0x30, 0x14, 0x33, 0x12, 0x35, 0x0f, 0x3a, 0x0f,
+ 0x3c, 0x0c, 0x40, 0x0c, 0x41, 0x0a, 0x45, 0x0a, 0x47, 0x09, 0x4a, 0x07,
+ 0x60, 0x22, 0x62, 0x1d, 0x64, 0x1a, 0x66, 0x17, 0x68, 0x14, 0x6a, 0x11,
+ 0x6c, 0x10, 0x6e, 0x0e, 0x70, 0x0c, 0x71, 0x0b, 0x73, 0x0a, 0x75, 0x09,
+ 0x76, 0x07, 0x78, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7c, 0x05, 0x7e, 0x05,
+ 0x7f, 0x04, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00,
+ 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38,
+ 0x00, 0x2c, 0x00, 0x1f, 0x00, 0x12, 0x03, 0x09, 0x09, 0x04, 0x10, 0x00,
+ 0x1c, 0x00, 0x27, 0x00, 0x31, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00,
+ 0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00,
+ 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33,
+ 0x00, 0x24, 0x00, 0x15, 0x00, 0x07, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00,
+ 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x42, 0x34, 0x43, 0x2f,
+ 0x44, 0x29, 0x49, 0x25, 0x4b, 0x21, 0x4c, 0x1e, 0x4d, 0x1b, 0x51, 0x18,
+ 0x55, 0x16, 0x56, 0x14, 0x58, 0x13, 0x59, 0x11, 0x5a, 0x0f, 0x5d, 0x0e,
+ 0x61, 0x0c, 0x63, 0x0c, 0x64, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x09,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0c, 0x3c, 0x10, 0x35, 0x15, 0x2f,
+ 0x19, 0x2a, 0x1c, 0x25, 0x20, 0x22, 0x23, 0x1d, 0x26, 0x1a, 0x2b, 0x18,
+ 0x2e, 0x16, 0x30, 0x12, 0x35, 0x12, 0x37, 0x0f, 0x3b, 0x0f, 0x3d, 0x0c,
+ 0x41, 0x0c, 0x42, 0x0a, 0x46, 0x0a, 0x47, 0x09, 0x60, 0x22, 0x62, 0x1e,
+ 0x64, 0x1a, 0x66, 0x17, 0x68, 0x15, 0x6a, 0x12, 0x6b, 0x11, 0x6d, 0x0e,
+ 0x6e, 0x0d, 0x71, 0x0c, 0x72, 0x0b, 0x74, 0x09, 0x76, 0x09, 0x77, 0x07,
+ 0x79, 0x07, 0x7a, 0x06, 0x7c, 0x06, 0x7c, 0x05, 0x7e, 0x05, 0x7f, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x5e, 0x00, 0x5d,
+ 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x26,
+ 0x00, 0x1a, 0x00, 0x0f, 0x04, 0x08, 0x0a, 0x04, 0x10, 0x00, 0x1b, 0x00,
+ 0x25, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00,
+ 0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x5e, 0x00, 0x5d,
+ 0x00, 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e,
+ 0x00, 0x10, 0x00, 0x03, 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a, 0x00,
+ 0x33, 0x00, 0x3b, 0x00, 0x4f, 0x2a, 0x56, 0x28, 0x59, 0x27, 0x5a, 0x26,
+ 0x5c, 0x26, 0x5c, 0x26, 0x5c, 0x26, 0x5d, 0x26, 0x5d, 0x26, 0x5d, 0x25,
+ 0x5d, 0x25, 0x5d, 0x25, 0x5d, 0x25, 0x5d, 0x25, 0x5e, 0x25, 0x5e, 0x25,
+ 0x5e, 0x24, 0x5e, 0x24, 0x5e, 0x24, 0x5e, 0x24, 0x92, 0x0e, 0x79, 0x14,
+ 0x6f, 0x18, 0x6b, 0x1b, 0x68, 0x1d, 0x67, 0x1d, 0x66, 0x1e, 0x65, 0x1f,
+ 0x64, 0x20, 0x64, 0x20, 0x63, 0x20, 0x63, 0x21, 0x63, 0x21, 0x63, 0x21,
+ 0x63, 0x21, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22,
+ 0x16, 0x23, 0x3c, 0x23, 0x4a, 0x23, 0x50, 0x23, 0x54, 0x23, 0x56, 0x23,
+ 0x58, 0x23, 0x59, 0x23, 0x5a, 0x23, 0x5a, 0x23, 0x5b, 0x23, 0x5b, 0x23,
+ 0x5b, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23,
+ 0x5d, 0x23, 0x5d, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x16, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53,
+ 0x00, 0x4b, 0x00, 0x42, 0x00, 0x38, 0x00, 0x2d, 0x00, 0x22, 0x00, 0x17,
+ 0x00, 0x0c, 0x05, 0x07, 0x0a, 0x03, 0x0f, 0x00, 0x1a, 0x00, 0x24, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
+ 0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00,
+ 0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x16, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52,
+ 0x00, 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c,
+ 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31, 0x00,
+ 0x48, 0x31, 0x4f, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x29, 0x58, 0x29,
+ 0x59, 0x28, 0x59, 0x27, 0x5a, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0x5c, 0x27, 0x5c, 0x27, 0xa1, 0x01, 0x88, 0x07, 0x7b, 0x0c, 0x74, 0x0f,
+ 0x70, 0x12, 0x6d, 0x14, 0x6b, 0x16, 0x6a, 0x17, 0x69, 0x18, 0x68, 0x19,
+ 0x67, 0x1a, 0x66, 0x1b, 0x66, 0x1b, 0x65, 0x1c, 0x65, 0x1c, 0x65, 0x1d,
+ 0x65, 0x1d, 0x64, 0x1d, 0x64, 0x1e, 0x64, 0x1e, 0x0a, 0x32, 0x22, 0x25,
+ 0x31, 0x24, 0x3b, 0x23, 0x42, 0x23, 0x47, 0x23, 0x4a, 0x23, 0x4d, 0x23,
+ 0x4f, 0x23, 0x51, 0x23, 0x52, 0x23, 0x53, 0x23, 0x54, 0x23, 0x55, 0x23,
+ 0x56, 0x23, 0x56, 0x23, 0x57, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45,
+ 0x00, 0x3c, 0x00, 0x32, 0x00, 0x28, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x0b,
+ 0x06, 0x07, 0x0b, 0x03, 0x0f, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00,
+ 0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00,
+ 0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42,
+ 0x00, 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x01, 0x00,
+ 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28, 0x00, 0x45, 0x34, 0x4b, 0x31,
+ 0x4f, 0x2f, 0x52, 0x2d, 0x54, 0x2c, 0x55, 0x2b, 0x57, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x29, 0x58, 0x29, 0x59, 0x28, 0x59, 0x27, 0x5a, 0x27,
+ 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0xa7, 0x00, 0x92, 0x03, 0x84, 0x06, 0x7d, 0x09, 0x77, 0x0c, 0x73, 0x0e,
+ 0x71, 0x10, 0x6f, 0x11, 0x6d, 0x13, 0x6b, 0x14, 0x6a, 0x15, 0x6a, 0x16,
+ 0x69, 0x17, 0x68, 0x17, 0x68, 0x18, 0x67, 0x19, 0x66, 0x19, 0x66, 0x1a,
+ 0x66, 0x1a, 0x66, 0x1a, 0x0a, 0x38, 0x18, 0x2b, 0x25, 0x27, 0x2e, 0x25,
+ 0x35, 0x24, 0x3b, 0x23, 0x3f, 0x23, 0x43, 0x23, 0x46, 0x23, 0x48, 0x23,
+ 0x4a, 0x23, 0x4c, 0x23, 0x4e, 0x23, 0x4f, 0x23, 0x50, 0x23, 0x51, 0x23,
+ 0x52, 0x23, 0x53, 0x23, 0x53, 0x23, 0x54, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e,
+ 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x48, 0x00, 0x40, 0x00, 0x37,
+ 0x00, 0x2d, 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x01, 0x0a, 0x06, 0x06,
+ 0x0b, 0x03, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00,
+ 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00,
+ 0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d,
+ 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31,
+ 0x00, 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x03, 0x00, 0x0d, 0x00,
+ 0x17, 0x00, 0x1f, 0x00, 0x44, 0x36, 0x49, 0x33, 0x4d, 0x31, 0x4f, 0x2f,
+ 0x51, 0x2e, 0x53, 0x2d, 0x53, 0x2c, 0x55, 0x2b, 0x56, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x29, 0x58, 0x29,
+ 0x59, 0x28, 0x5a, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0xaa, 0x00, 0x98, 0x01,
+ 0x8c, 0x03, 0x83, 0x05, 0x7d, 0x08, 0x79, 0x0a, 0x76, 0x0c, 0x73, 0x0d,
+ 0x71, 0x0f, 0x6f, 0x10, 0x6e, 0x11, 0x6d, 0x12, 0x6c, 0x13, 0x6b, 0x14,
+ 0x6a, 0x15, 0x6a, 0x15, 0x69, 0x16, 0x68, 0x17, 0x68, 0x17, 0x68, 0x18,
+ 0x0a, 0x3c, 0x14, 0x30, 0x1e, 0x2a, 0x26, 0x27, 0x2d, 0x25, 0x32, 0x24,
+ 0x36, 0x24, 0x3b, 0x24, 0x3e, 0x23, 0x41, 0x23, 0x43, 0x23, 0x45, 0x23,
+ 0x47, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4d, 0x23, 0x4d, 0x23,
+ 0x4f, 0x23, 0x50, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x31, 0x11, 0x5f, 0x00, 0x85, 0x00, 0x92, 0x00,
+ 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00,
+ 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x11, 0x03, 0x23,
+ 0x00, 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d,
+ 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e,
+ 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x43, 0x38, 0x48, 0x35, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x30, 0x50, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2c, 0x54, 0x2b, 0x56, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x58, 0x29, 0xac, 0x00, 0x9d, 0x00, 0x91, 0x02, 0x89, 0x03,
+ 0x82, 0x05, 0x7e, 0x07, 0x7a, 0x09, 0x77, 0x0a, 0x75, 0x0c, 0x73, 0x0d,
+ 0x71, 0x0e, 0x70, 0x0f, 0x6e, 0x10, 0x6e, 0x11, 0x6c, 0x12, 0x6c, 0x13,
+ 0x6b, 0x13, 0x6a, 0x14, 0x6a, 0x15, 0x6a, 0x15, 0x09, 0x3f, 0x11, 0x33,
+ 0x1a, 0x2d, 0x21, 0x29, 0x27, 0x27, 0x2c, 0x26, 0x30, 0x25, 0x34, 0x24,
+ 0x37, 0x24, 0x3a, 0x24, 0x3d, 0x23, 0x40, 0x23, 0x42, 0x23, 0x44, 0x23,
+ 0x45, 0x23, 0x47, 0x23, 0x48, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x23, 0x20, 0x00, 0x5f, 0x00, 0x7c, 0x00, 0x8a, 0x00, 0x91, 0x00,
+ 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00,
+ 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x20, 0x00, 0x00, 0x1f, 0x00, 0x3c,
+ 0x00, 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b,
+ 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x39, 0x46, 0x36,
+ 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x54, 0x2b, 0x55, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a,
+ 0xae, 0x00, 0xa1, 0x00, 0x96, 0x01, 0x8d, 0x02, 0x87, 0x03, 0x82, 0x05,
+ 0x7e, 0x07, 0x7b, 0x08, 0x78, 0x09, 0x76, 0x0b, 0x74, 0x0c, 0x73, 0x0d,
+ 0x71, 0x0e, 0x70, 0x0e, 0x6f, 0x0f, 0x6e, 0x11, 0x6d, 0x11, 0x6c, 0x11,
+ 0x6c, 0x12, 0x6b, 0x13, 0x09, 0x40, 0x10, 0x36, 0x17, 0x2f, 0x1d, 0x2c,
+ 0x22, 0x29, 0x27, 0x27, 0x2b, 0x26, 0x2f, 0x25, 0x32, 0x25, 0x35, 0x24,
+ 0x38, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3f, 0x23, 0x40, 0x23, 0x42, 0x23,
+ 0x44, 0x23, 0x45, 0x23, 0x46, 0x23, 0x48, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x1f,
+ 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79, 0x00, 0x83, 0x00, 0x8a, 0x00,
+ 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00,
+ 0x99, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x00, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x39,
+ 0x00, 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56,
+ 0x00, 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x45, 0x37, 0x48, 0x35, 0x4a, 0x33,
+ 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x52, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x54, 0x2c, 0x55, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0xaf, 0x00, 0xa3, 0x00,
+ 0x99, 0x00, 0x91, 0x01, 0x8b, 0x02, 0x86, 0x03, 0x81, 0x05, 0x7e, 0x06,
+ 0x7b, 0x07, 0x79, 0x09, 0x77, 0x0a, 0x75, 0x0b, 0x74, 0x0c, 0x73, 0x0c,
+ 0x71, 0x0d, 0x71, 0x0e, 0x6f, 0x0f, 0x6e, 0x10, 0x6e, 0x11, 0x6d, 0x11,
+ 0x09, 0x41, 0x0f, 0x38, 0x15, 0x32, 0x1a, 0x2e, 0x1f, 0x2b, 0x24, 0x29,
+ 0x27, 0x27, 0x2b, 0x26, 0x2e, 0x25, 0x31, 0x25, 0x34, 0x25, 0x36, 0x24,
+ 0x38, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3e, 0x23, 0x40, 0x23, 0x41, 0x23,
+ 0x43, 0x23, 0x44, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x3c, 0x00, 0x0d, 0x1f, 0x00,
+ 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x84, 0x00,
+ 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x7c, 0x00,
+ 0x4d, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36,
+ 0x00, 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52,
+ 0x00, 0x53, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3a, 0x45, 0x38, 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x53, 0x2c, 0x55, 0x2b, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0xb0, 0x00, 0xa5, 0x00, 0x9d, 0x00, 0x95, 0x00,
+ 0x8e, 0x02, 0x89, 0x02, 0x85, 0x03, 0x81, 0x05, 0x7e, 0x06, 0x7c, 0x07,
+ 0x7a, 0x08, 0x78, 0x09, 0x76, 0x0a, 0x75, 0x0b, 0x73, 0x0c, 0x73, 0x0c,
+ 0x71, 0x0d, 0x71, 0x0e, 0x70, 0x0e, 0x6e, 0x0f, 0x09, 0x42, 0x0e, 0x39,
+ 0x13, 0x33, 0x18, 0x2f, 0x1c, 0x2d, 0x21, 0x2a, 0x24, 0x29, 0x28, 0x27,
+ 0x2b, 0x26, 0x2e, 0x26, 0x30, 0x25, 0x33, 0x25, 0x35, 0x25, 0x37, 0x24,
+ 0x39, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x23, 0x40, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02, 0x1f, 0x00, 0x3b, 0x00,
+ 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x80, 0x00,
+ 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42, 0x00,
+ 0x1f, 0x00, 0x04, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34,
+ 0x00, 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39,
+ 0x46, 0x36, 0x49, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x2f, 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2c, 0x54, 0x2b, 0x56, 0x2a,
+ 0xb1, 0x00, 0xa8, 0x00, 0x9f, 0x00, 0x98, 0x00, 0x91, 0x01, 0x8c, 0x02,
+ 0x88, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06, 0x7c, 0x07, 0x7a, 0x07,
+ 0x79, 0x09, 0x77, 0x09, 0x76, 0x0b, 0x74, 0x0b, 0x73, 0x0c, 0x73, 0x0c,
+ 0x71, 0x0d, 0x71, 0x0e, 0x09, 0x43, 0x0e, 0x3b, 0x12, 0x35, 0x16, 0x31,
+ 0x1a, 0x2e, 0x1e, 0x2c, 0x22, 0x2a, 0x25, 0x28, 0x28, 0x27, 0x2a, 0x27,
+ 0x2d, 0x26, 0x30, 0x25, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x37, 0x24,
+ 0x39, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x51,
+ 0x00, 0x39, 0x00, 0x1a, 0x04, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x48, 0x00,
+ 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73, 0x00, 0x79, 0x00, 0x7e, 0x00,
+ 0x82, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f, 0x00,
+ 0x09, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33,
+ 0x00, 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x37, 0x48, 0x35,
+ 0x4a, 0x35, 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0xb1, 0x00, 0xa9, 0x00,
+ 0xa1, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x8f, 0x01, 0x8b, 0x02, 0x87, 0x03,
+ 0x84, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7d, 0x06, 0x7b, 0x07, 0x79, 0x08,
+ 0x78, 0x09, 0x76, 0x0a, 0x76, 0x0b, 0x74, 0x0b, 0x73, 0x0c, 0x72, 0x0c,
+ 0x09, 0x44, 0x0d, 0x3c, 0x11, 0x36, 0x15, 0x33, 0x19, 0x30, 0x1c, 0x2d,
+ 0x20, 0x2b, 0x23, 0x2a, 0x25, 0x28, 0x28, 0x27, 0x2a, 0x27, 0x2d, 0x26,
+ 0x2f, 0x26, 0x31, 0x25, 0x33, 0x25, 0x34, 0x25, 0x36, 0x24, 0x38, 0x24,
+ 0x39, 0x24, 0x3a, 0x24, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x43, 0x00, 0x2a,
+ 0x00, 0x10, 0x09, 0x00, 0x1f, 0x00, 0x33, 0x00, 0x43, 0x00, 0x50, 0x00,
+ 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72, 0x00, 0x77, 0x00, 0x7b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x95, 0x00,
+ 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c, 0x00,
+ 0x00, 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32,
+ 0x00, 0x37, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3c, 0x43, 0x39, 0x46, 0x38, 0x46, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30,
+ 0x50, 0x2e, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0xb2, 0x00, 0xaa, 0x00, 0xa2, 0x00, 0x9c, 0x00,
+ 0x96, 0x00, 0x91, 0x01, 0x8d, 0x02, 0x89, 0x02, 0x86, 0x03, 0x83, 0x04,
+ 0x81, 0x05, 0x7f, 0x06, 0x7d, 0x06, 0x7b, 0x07, 0x79, 0x07, 0x79, 0x09,
+ 0x77, 0x09, 0x76, 0x0a, 0x75, 0x0b, 0x74, 0x0b, 0x0a, 0x44, 0x0d, 0x3d,
+ 0x10, 0x38, 0x14, 0x34, 0x17, 0x31, 0x1b, 0x2e, 0x1e, 0x2d, 0x21, 0x2b,
+ 0x23, 0x2a, 0x26, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2d, 0x26, 0x2e, 0x26,
+ 0x30, 0x25, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x36, 0x24, 0x38, 0x24,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x08,
+ 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x55, 0x00,
+ 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76, 0x00,
+ 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3c, 0x43, 0x39,
+ 0x46, 0x39, 0x46, 0x37, 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b, 0x32,
+ 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f,
+ 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0xb2, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x98, 0x00, 0x93, 0x00,
+ 0x8f, 0x01, 0x8b, 0x02, 0x88, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05,
+ 0x7f, 0x06, 0x7d, 0x06, 0x7c, 0x07, 0x7a, 0x07, 0x79, 0x08, 0x78, 0x09,
+ 0x76, 0x09, 0x76, 0x0a, 0x0a, 0x44, 0x0c, 0x3e, 0x10, 0x39, 0x13, 0x35,
+ 0x16, 0x32, 0x19, 0x30, 0x1c, 0x2e, 0x1f, 0x2c, 0x21, 0x2b, 0x24, 0x2a,
+ 0x26, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x26, 0x2e, 0x26, 0x30, 0x25,
+ 0x31, 0x25, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59,
+ 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17, 0x00, 0x03, 0x0f, 0x00,
+ 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x59, 0x00,
+ 0x60, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57, 0x00,
+ 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x04, 0x00, 0x00, 0x07,
+ 0x00, 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x39, 0x46, 0x39, 0x46, 0x38,
+ 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f, 0x51, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0xb2, 0x00, 0xac, 0x00,
+ 0xa5, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x91, 0x01, 0x8e, 0x01,
+ 0x8a, 0x02, 0x88, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05, 0x7f, 0x05,
+ 0x7d, 0x06, 0x7c, 0x07, 0x7a, 0x07, 0x79, 0x07, 0x78, 0x09, 0x77, 0x09,
+ 0x0a, 0x44, 0x0c, 0x3f, 0x0f, 0x3a, 0x12, 0x36, 0x15, 0x33, 0x18, 0x30,
+ 0x1b, 0x2e, 0x1d, 0x2d, 0x20, 0x2b, 0x22, 0x2a, 0x24, 0x2a, 0x26, 0x28,
+ 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x26, 0x2e, 0x26, 0x2f, 0x26, 0x31, 0x25,
+ 0x33, 0x25, 0x33, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x52, 0x00, 0x45,
+ 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x11, 0x00, 0x1f, 0x00,
+ 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x5b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
+ 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00,
+ 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0c,
+ 0x00, 0x14, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3d, 0x42, 0x3a, 0x45, 0x39, 0x46, 0x39, 0x46, 0x36, 0x49, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0xb3, 0x00, 0xac, 0x00, 0xa7, 0x00, 0xa1, 0x00,
+ 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8c, 0x02, 0x89, 0x02,
+ 0x87, 0x02, 0x85, 0x03, 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7d, 0x06,
+ 0x7c, 0x06, 0x7b, 0x07, 0x79, 0x07, 0x79, 0x08, 0x0a, 0x45, 0x0c, 0x3f,
+ 0x0f, 0x3a, 0x11, 0x37, 0x14, 0x34, 0x17, 0x32, 0x1a, 0x30, 0x1c, 0x2e,
+ 0x1e, 0x2d, 0x21, 0x2b, 0x22, 0x2a, 0x25, 0x2a, 0x26, 0x28, 0x28, 0x28,
+ 0x2a, 0x27, 0x2c, 0x27, 0x2d, 0x26, 0x2f, 0x26, 0x30, 0x25, 0x32, 0x25,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3b, 0x00, 0x2c,
+ 0x00, 0x1b, 0x00, 0x0b, 0x04, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x2b, 0x00,
+ 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89, 0x00,
+ 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d, 0x00,
+ 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3a,
+ 0x44, 0x39, 0x46, 0x39, 0x46, 0x37, 0x48, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0xb3, 0x00, 0xad, 0x00, 0xa7, 0x00, 0xa3, 0x00, 0x9d, 0x00, 0x99, 0x00,
+ 0x95, 0x00, 0x91, 0x01, 0x8e, 0x01, 0x8b, 0x02, 0x88, 0x02, 0x86, 0x02,
+ 0x84, 0x03, 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06,
+ 0x7b, 0x07, 0x7a, 0x07, 0x0a, 0x45, 0x0c, 0x40, 0x0e, 0x3b, 0x11, 0x38,
+ 0x13, 0x35, 0x16, 0x32, 0x18, 0x30, 0x1b, 0x2e, 0x1d, 0x2d, 0x1f, 0x2c,
+ 0x21, 0x2b, 0x23, 0x2a, 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27,
+ 0x2c, 0x27, 0x2d, 0x26, 0x2f, 0x26, 0x2f, 0x25, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c,
+ 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33, 0x00, 0x24, 0x00, 0x15,
+ 0x00, 0x07, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x34, 0x00,
+ 0x3d, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73, 0x00,
+ 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00,
+ 0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x39,
+ 0x46, 0x38, 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x34,
+ 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2f, 0x52, 0x2e, 0xb3, 0x00, 0xae, 0x00,
+ 0xa8, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x93, 0x00,
+ 0x8f, 0x01, 0x8d, 0x02, 0x8a, 0x02, 0x88, 0x02, 0x86, 0x03, 0x84, 0x03,
+ 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06, 0x7c, 0x07,
+ 0x0a, 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x38, 0x13, 0x36, 0x15, 0x33,
+ 0x18, 0x31, 0x1a, 0x30, 0x1c, 0x2e, 0x1e, 0x2d, 0x20, 0x2b, 0x22, 0x2b,
+ 0x23, 0x2a, 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27,
+ 0x2d, 0x26, 0x2f, 0x26, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x57, 0x00, 0x4f,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x03,
+ 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x33, 0x00, 0x3b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
+ 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e, 0x00,
+ 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15, 0x00,
+ 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3d, 0x42, 0x3c, 0x43, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x36,
+ 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4c, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x2f, 0xb3, 0x00, 0xae, 0x00, 0xa9, 0x00, 0xa4, 0x00,
+ 0xa0, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x94, 0x00, 0x91, 0x01, 0x8e, 0x01,
+ 0x8c, 0x02, 0x89, 0x02, 0x87, 0x02, 0x86, 0x03, 0x84, 0x03, 0x82, 0x04,
+ 0x80, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06, 0x0a, 0x45, 0x0b, 0x40,
+ 0x0e, 0x3c, 0x10, 0x39, 0x12, 0x37, 0x14, 0x34, 0x17, 0x32, 0x19, 0x30,
+ 0x1b, 0x2e, 0x1d, 0x2d, 0x1f, 0x2d, 0x20, 0x2b, 0x22, 0x2b, 0x24, 0x2a,
+ 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27, 0x2c, 0x26,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52, 0x00, 0x49, 0x00, 0x3e,
+ 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x0a, 0x00,
+ 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91, 0x00,
+ 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00,
+ 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3c,
+ 0x43, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x37, 0x48, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0xb3, 0x00, 0xae, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa1, 0x00, 0x9d, 0x00,
+ 0x99, 0x00, 0x96, 0x00, 0x93, 0x00, 0x90, 0x01, 0x8d, 0x01, 0x8b, 0x02,
+ 0x89, 0x02, 0x87, 0x02, 0x85, 0x03, 0x83, 0x03, 0x82, 0x04, 0x80, 0x05,
+ 0x7f, 0x05, 0x7e, 0x06, 0x0a, 0x45, 0x0b, 0x41, 0x0e, 0x3d, 0x10, 0x3a,
+ 0x11, 0x37, 0x14, 0x34, 0x16, 0x32, 0x18, 0x31, 0x1a, 0x30, 0x1c, 0x2e,
+ 0x1d, 0x2d, 0x20, 0x2c, 0x21, 0x2b, 0x22, 0x2a, 0x24, 0x2a, 0x25, 0x29,
+ 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
+ 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00, 0x37, 0x00, 0x2c,
+ 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x01, 0x00, 0x0c, 0x00, 0x16, 0x00,
+ 0x1f, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00,
+ 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d, 0x00,
+ 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x39, 0x46, 0x39,
+ 0x46, 0x39, 0x46, 0x39, 0x46, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0xb4, 0x00, 0xaf, 0x00,
+ 0xaa, 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x9a, 0x00, 0x97, 0x00,
+ 0x94, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c, 0x02, 0x8a, 0x02, 0x88, 0x02,
+ 0x86, 0x02, 0x85, 0x03, 0x83, 0x03, 0x82, 0x04, 0x80, 0x05, 0x7f, 0x05,
+ 0x0a, 0x45, 0x0b, 0x41, 0x0d, 0x3e, 0x10, 0x3a, 0x11, 0x38, 0x13, 0x35,
+ 0x16, 0x33, 0x17, 0x32, 0x19, 0x30, 0x1b, 0x2e, 0x1d, 0x2e, 0x1e, 0x2d,
+ 0x20, 0x2b, 0x22, 0x2b, 0x23, 0x2a, 0x25, 0x2a, 0x25, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x2a, 0x27, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55,
+ 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31, 0x00, 0x26, 0x00, 0x1b,
+ 0x00, 0x11, 0x00, 0x06, 0x03, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00,
+ 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00,
+ 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31, 0x00,
+ 0x28, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3a, 0x45, 0x39, 0x46, 0x39, 0x46, 0x39,
+ 0x46, 0x37, 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0xb4, 0x00, 0xaf, 0x00, 0xab, 0x00, 0xa7, 0x00,
+ 0xa3, 0x00, 0x9f, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x95, 0x00, 0x92, 0x00,
+ 0x90, 0x01, 0x8d, 0x01, 0x8b, 0x02, 0x89, 0x02, 0x88, 0x02, 0x86, 0x02,
+ 0x85, 0x03, 0x82, 0x03, 0x82, 0x04, 0x80, 0x05, 0x0a, 0x46, 0x0b, 0x42,
+ 0x0d, 0x3e, 0x0f, 0x3b, 0x11, 0x38, 0x13, 0x36, 0x15, 0x34, 0x16, 0x32,
+ 0x18, 0x30, 0x1a, 0x30, 0x1c, 0x2e, 0x1d, 0x2d, 0x20, 0x2d, 0x20, 0x2b,
+ 0x22, 0x2b, 0x23, 0x2a, 0x25, 0x2a, 0x26, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x32, 0x74, 0x38, 0x57, 0x3a, 0x4f, 0x3c, 0x4b, 0x3c, 0x49, 0x3d, 0x47,
+ 0x3d, 0x46, 0x3d, 0x45, 0x3d, 0x45, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43,
+ 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42,
+ 0x3d, 0x42, 0x3d, 0x42, 0x41, 0x09, 0x1b, 0x31, 0x27, 0x38, 0x2d, 0x3a,
+ 0x31, 0x3b, 0x33, 0x3c, 0x35, 0x3c, 0x36, 0x3d, 0x37, 0x3d, 0x38, 0x3d,
+ 0x38, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
+ 0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x73, 0x00, 0x38, 0x31,
+ 0x3a, 0x38, 0x3c, 0x3a, 0x3c, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3d,
+ 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+ 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x3d, 0x28, 0x38, 0x30,
+ 0x38, 0x34, 0x39, 0x36, 0x39, 0x38, 0x3a, 0x39, 0x3a, 0x39, 0x3b, 0x3a,
+ 0x3b, 0x3b, 0x3c, 0x3b, 0x3c, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3e, 0x3c,
+ 0x3e, 0x3c, 0x3e, 0x3c, 0x3e, 0x3c, 0x3e, 0x3d, 0x3e, 0x3d, 0x3e, 0x3d,
+ 0x00, 0x7e, 0x05, 0x58, 0x0f, 0x4e, 0x17, 0x49, 0x1d, 0x47, 0x21, 0x45,
+ 0x24, 0x44, 0x27, 0x43, 0x29, 0x43, 0x2b, 0x43, 0x2d, 0x43, 0x2e, 0x42,
+ 0x2f, 0x42, 0x31, 0x42, 0x31, 0x42, 0x32, 0x42, 0x33, 0x42, 0x33, 0x42,
+ 0x34, 0x42, 0x34, 0x42, 0x2b, 0x4e, 0x31, 0x47, 0x34, 0x45, 0x36, 0x44,
+ 0x38, 0x43, 0x39, 0x42, 0x39, 0x42, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41,
+ 0x3c, 0x41, 0x3c, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41,
+ 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x4f, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x2f, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x16, 0x3a, 0x20, 0x39, 0x25, 0x39, 0x29,
+ 0x39, 0x2d, 0x39, 0x2f, 0x3a, 0x31, 0x3a, 0x32, 0x3b, 0x33, 0x3a, 0x34,
+ 0x3a, 0x35, 0x3a, 0x36, 0x3a, 0x36, 0x3b, 0x37, 0x3b, 0x37, 0x3c, 0x38,
+ 0x3c, 0x38, 0x3d, 0x38, 0x3e, 0x39, 0x3e, 0x39, 0x00, 0x93, 0x01, 0x70,
+ 0x06, 0x60, 0x0d, 0x56, 0x12, 0x52, 0x16, 0x4e, 0x1a, 0x4c, 0x1d, 0x4a,
+ 0x20, 0x48, 0x22, 0x47, 0x24, 0x46, 0x26, 0x45, 0x27, 0x44, 0x29, 0x44,
+ 0x2a, 0x44, 0x2b, 0x44, 0x2c, 0x43, 0x2d, 0x43, 0x2e, 0x43, 0x2f, 0x43,
+ 0x28, 0x56, 0x2e, 0x4f, 0x31, 0x4b, 0x33, 0x49, 0x35, 0x48, 0x36, 0x46,
+ 0x37, 0x45, 0x38, 0x45, 0x39, 0x44, 0x39, 0x44, 0x39, 0x43, 0x39, 0x43,
+ 0x39, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3c, 0x42, 0x3c, 0x42,
+ 0x3d, 0x42, 0x3d, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x8f, 0x00, 0x73, 0x00, 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x45, 0x00, 0x22, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x43, 0x11, 0x3d, 0x18, 0x3b, 0x1e, 0x3a, 0x22, 0x39, 0x25, 0x39, 0x28,
+ 0x39, 0x2a, 0x39, 0x2c, 0x39, 0x2d, 0x3a, 0x2f, 0x3b, 0x30, 0x3b, 0x31,
+ 0x3b, 0x32, 0x3b, 0x33, 0x3a, 0x33, 0x3a, 0x34, 0x3a, 0x34, 0x3a, 0x35,
+ 0x3a, 0x35, 0x3b, 0x35, 0x00, 0x9d, 0x00, 0x7f, 0x03, 0x6d, 0x07, 0x62,
+ 0x0c, 0x5b, 0x10, 0x56, 0x13, 0x52, 0x16, 0x50, 0x19, 0x4d, 0x1c, 0x4c,
+ 0x1e, 0x4b, 0x1f, 0x4b, 0x22, 0x4a, 0x23, 0x49, 0x24, 0x48, 0x25, 0x47,
+ 0x27, 0x46, 0x28, 0x45, 0x29, 0x44, 0x29, 0x44, 0x27, 0x59, 0x2c, 0x53,
+ 0x2f, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x34, 0x4a, 0x35, 0x48, 0x35, 0x47,
+ 0x36, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x45,
+ 0x39, 0x44, 0x39, 0x44, 0x39, 0x43, 0x39, 0x43, 0x39, 0x42, 0x3a, 0x42,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x84,
+ 0x00, 0x5b, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x59, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x44, 0x0f, 0x3e, 0x14,
+ 0x3c, 0x19, 0x3a, 0x1d, 0x3a, 0x20, 0x39, 0x23, 0x3a, 0x25, 0x3a, 0x27,
+ 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2c, 0x3a, 0x2c, 0x3b, 0x2d, 0x3b, 0x2f,
+ 0x3b, 0x2f, 0x3b, 0x30, 0x3b, 0x31, 0x3b, 0x32, 0x3a, 0x32, 0x3a, 0x33,
+ 0x00, 0xa3, 0x00, 0x88, 0x01, 0x77, 0x04, 0x6b, 0x08, 0x63, 0x0b, 0x5d,
+ 0x0e, 0x59, 0x11, 0x57, 0x14, 0x54, 0x16, 0x51, 0x19, 0x4f, 0x1a, 0x4d,
+ 0x1c, 0x4c, 0x1e, 0x4c, 0x1f, 0x4b, 0x21, 0x4b, 0x22, 0x4a, 0x23, 0x49,
+ 0x24, 0x49, 0x25, 0x49, 0x27, 0x5a, 0x2a, 0x55, 0x2d, 0x52, 0x2f, 0x4f,
+ 0x31, 0x4e, 0x32, 0x4b, 0x33, 0x4a, 0x35, 0x4a, 0x35, 0x49, 0x35, 0x48,
+ 0x35, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46,
+ 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x8d, 0x00, 0x6f, 0x00, 0x48,
+ 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x55, 0x00,
+ 0x42, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x45, 0x0e, 0x40, 0x12, 0x3d, 0x16, 0x3b, 0x1a,
+ 0x3b, 0x1d, 0x3a, 0x20, 0x39, 0x22, 0x39, 0x23, 0x3a, 0x25, 0x3a, 0x26,
+ 0x3a, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2b, 0x3a, 0x2c, 0x3b, 0x2d,
+ 0x3c, 0x2e, 0x3b, 0x2e, 0x3b, 0x2f, 0x3b, 0x30, 0x00, 0xa7, 0x00, 0x90,
+ 0x00, 0x7e, 0x02, 0x73, 0x05, 0x6a, 0x08, 0x65, 0x0b, 0x5f, 0x0d, 0x5b,
+ 0x10, 0x58, 0x12, 0x56, 0x14, 0x55, 0x16, 0x52, 0x18, 0x50, 0x1a, 0x4e,
+ 0x1b, 0x4d, 0x1d, 0x4c, 0x1e, 0x4c, 0x1f, 0x4b, 0x20, 0x4b, 0x21, 0x4b,
+ 0x26, 0x5b, 0x2a, 0x57, 0x2c, 0x54, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4e,
+ 0x31, 0x4c, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x49,
+ 0x35, 0x47, 0x36, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46,
+ 0x39, 0x46, 0x39, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38, 0x00,
+ 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x46, 0x0d, 0x41, 0x11, 0x3d, 0x14, 0x3d, 0x17, 0x3b, 0x1a, 0x3b, 0x1c,
+ 0x3b, 0x1e, 0x39, 0x21, 0x39, 0x22, 0x3a, 0x23, 0x3a, 0x25, 0x3a, 0x26,
+ 0x3a, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2a, 0x39, 0x2b, 0x3b, 0x2c,
+ 0x3c, 0x2d, 0x3c, 0x2e, 0x00, 0xa9, 0x00, 0x95, 0x00, 0x85, 0x01, 0x79,
+ 0x03, 0x70, 0x06, 0x69, 0x08, 0x65, 0x0b, 0x61, 0x0d, 0x5c, 0x0f, 0x59,
+ 0x11, 0x58, 0x13, 0x56, 0x14, 0x55, 0x16, 0x53, 0x18, 0x51, 0x19, 0x4f,
+ 0x1b, 0x4d, 0x1c, 0x4d, 0x1d, 0x4c, 0x1e, 0x4c, 0x26, 0x5c, 0x29, 0x58,
+ 0x2b, 0x55, 0x2d, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4d,
+ 0x32, 0x4b, 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x49,
+ 0x35, 0x48, 0x35, 0x47, 0x36, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95,
+ 0x00, 0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x46, 0x0c, 0x42, 0x0f,
+ 0x3f, 0x13, 0x3d, 0x15, 0x3c, 0x18, 0x3a, 0x1a, 0x3b, 0x1c, 0x3b, 0x1e,
+ 0x39, 0x20, 0x39, 0x21, 0x39, 0x22, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26,
+ 0x3a, 0x27, 0x39, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2a, 0x3a, 0x2b,
+ 0x00, 0xab, 0x00, 0x99, 0x00, 0x8b, 0x01, 0x7e, 0x02, 0x77, 0x04, 0x6f,
+ 0x06, 0x69, 0x08, 0x66, 0x0b, 0x62, 0x0d, 0x5e, 0x0e, 0x5b, 0x10, 0x59,
+ 0x12, 0x57, 0x13, 0x56, 0x15, 0x55, 0x16, 0x54, 0x18, 0x52, 0x19, 0x50,
+ 0x1a, 0x4e, 0x1b, 0x4d, 0x26, 0x5c, 0x28, 0x59, 0x2a, 0x57, 0x2c, 0x53,
+ 0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4c,
+ 0x33, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x35, 0x49, 0x35, 0x48, 0x36, 0x46, 0x37, 0x46, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76,
+ 0x00, 0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00,
+ 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x46, 0x0c, 0x42, 0x0e, 0x40, 0x11, 0x3d, 0x13,
+ 0x3d, 0x16, 0x3b, 0x18, 0x3b, 0x1a, 0x3c, 0x1c, 0x3b, 0x1e, 0x3a, 0x1f,
+ 0x39, 0x21, 0x39, 0x21, 0x3a, 0x23, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26,
+ 0x3a, 0x27, 0x39, 0x27, 0x39, 0x28, 0x39, 0x2a, 0x00, 0xac, 0x00, 0x9c,
+ 0x00, 0x8f, 0x00, 0x83, 0x02, 0x7b, 0x03, 0x74, 0x05, 0x6d, 0x07, 0x69,
+ 0x09, 0x66, 0x0b, 0x63, 0x0c, 0x5f, 0x0e, 0x5c, 0x0f, 0x5a, 0x11, 0x58,
+ 0x12, 0x57, 0x14, 0x56, 0x15, 0x55, 0x16, 0x55, 0x18, 0x53, 0x18, 0x51,
+ 0x26, 0x5d, 0x27, 0x59, 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2f, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b,
+ 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4a, 0x35, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53,
+ 0x00, 0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b, 0x00,
+ 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x47, 0x0b, 0x42, 0x0d, 0x41, 0x10, 0x3e, 0x13, 0x3d, 0x15, 0x3c, 0x17,
+ 0x3a, 0x19, 0x3b, 0x1a, 0x3c, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x20,
+ 0x39, 0x21, 0x3a, 0x22, 0x3b, 0x23, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26,
+ 0x3a, 0x27, 0x39, 0x27, 0x00, 0xad, 0x00, 0x9f, 0x00, 0x92, 0x00, 0x88,
+ 0x01, 0x7e, 0x02, 0x78, 0x04, 0x72, 0x05, 0x6d, 0x07, 0x69, 0x09, 0x66,
+ 0x0a, 0x64, 0x0c, 0x61, 0x0d, 0x5d, 0x0f, 0x5a, 0x10, 0x59, 0x11, 0x58,
+ 0x13, 0x57, 0x14, 0x56, 0x15, 0x55, 0x16, 0x55, 0x26, 0x5d, 0x27, 0x5a,
+ 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x32, 0x4b, 0x33, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a,
+ 0x00, 0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36,
+ 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38, 0x00,
+ 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0b, 0x43, 0x0d,
+ 0x41, 0x0f, 0x3f, 0x12, 0x3d, 0x13, 0x3e, 0x15, 0x3c, 0x17, 0x3a, 0x19,
+ 0x3a, 0x1a, 0x3c, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x1f, 0x39, 0x21,
+ 0x39, 0x21, 0x3b, 0x22, 0x3b, 0x24, 0x3a, 0x24, 0x3a, 0x24, 0x3a, 0x26,
+ 0x00, 0xae, 0x00, 0xa2, 0x00, 0x94, 0x00, 0x8b, 0x00, 0x82, 0x02, 0x7b,
+ 0x03, 0x76, 0x05, 0x71, 0x06, 0x6c, 0x07, 0x69, 0x09, 0x66, 0x0a, 0x64,
+ 0x0c, 0x62, 0x0d, 0x5f, 0x0e, 0x5b, 0x10, 0x5a, 0x10, 0x58, 0x12, 0x58,
+ 0x13, 0x56, 0x14, 0x56, 0x25, 0x5d, 0x27, 0x5b, 0x29, 0x57, 0x2a, 0x57,
+ 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4d, 0x33, 0x4a, 0x34, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88,
+ 0x00, 0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
+ 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28, 0x00,
+ 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0b, 0x43, 0x0d, 0x42, 0x0f, 0x40, 0x11,
+ 0x3d, 0x13, 0x3e, 0x14, 0x3c, 0x16, 0x3b, 0x17, 0x3a, 0x19, 0x3b, 0x1a,
+ 0x3c, 0x1c, 0x3b, 0x1d, 0x3b, 0x1f, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21,
+ 0x3a, 0x21, 0x3b, 0x22, 0x3b, 0x24, 0x3a, 0x24, 0x00, 0xae, 0x00, 0xa3,
+ 0x00, 0x97, 0x00, 0x8e, 0x00, 0x86, 0x01, 0x7e, 0x02, 0x79, 0x03, 0x75,
+ 0x05, 0x70, 0x06, 0x6b, 0x07, 0x68, 0x09, 0x66, 0x0a, 0x64, 0x0b, 0x63,
+ 0x0c, 0x5f, 0x0e, 0x5d, 0x0f, 0x5a, 0x10, 0x59, 0x11, 0x58, 0x13, 0x58,
+ 0x25, 0x5d, 0x27, 0x5c, 0x29, 0x58, 0x2a, 0x57, 0x2a, 0x56, 0x2d, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x33, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f,
+ 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00,
+ 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a, 0x00,
+ 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x47, 0x0b, 0x44, 0x0d, 0x42, 0x0e, 0x41, 0x10, 0x3e, 0x12, 0x3d, 0x13,
+ 0x3e, 0x15, 0x3c, 0x17, 0x3a, 0x18, 0x3b, 0x19, 0x3b, 0x1a, 0x3c, 0x1c,
+ 0x3b, 0x1c, 0x3b, 0x1e, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21, 0x39, 0x21,
+ 0x3b, 0x22, 0x3b, 0x23, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x90,
+ 0x00, 0x8a, 0x01, 0x81, 0x02, 0x7c, 0x02, 0x77, 0x04, 0x74, 0x05, 0x6f,
+ 0x06, 0x6a, 0x07, 0x68, 0x09, 0x66, 0x0a, 0x64, 0x0b, 0x63, 0x0c, 0x61,
+ 0x0e, 0x5e, 0x0e, 0x5b, 0x10, 0x5a, 0x10, 0x59, 0x25, 0x5d, 0x27, 0x5c,
+ 0x28, 0x59, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4c, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c,
+ 0x00, 0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57,
+ 0x00, 0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46, 0x00,
+ 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x44, 0x0d,
+ 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3d, 0x13, 0x3e, 0x14, 0x3d, 0x15,
+ 0x3c, 0x17, 0x3a, 0x18, 0x3a, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c,
+ 0x3b, 0x1e, 0x39, 0x1f, 0x39, 0x1f, 0x39, 0x21, 0x39, 0x21, 0x3a, 0x21,
+ 0x00, 0xaf, 0x00, 0xa6, 0x00, 0x9c, 0x00, 0x92, 0x00, 0x8c, 0x00, 0x85,
+ 0x01, 0x7e, 0x02, 0x7a, 0x03, 0x76, 0x05, 0x73, 0x06, 0x6e, 0x07, 0x6a,
+ 0x08, 0x68, 0x09, 0x66, 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x62, 0x0d, 0x5f,
+ 0x0e, 0x5c, 0x0f, 0x5a, 0x25, 0x5d, 0x27, 0x5c, 0x27, 0x59, 0x2a, 0x57,
+ 0x2a, 0x57, 0x2a, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x34, 0x4a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90,
+ 0x00, 0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41,
+ 0x00, 0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00,
+ 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39, 0x00,
+ 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42, 0x0f,
+ 0x40, 0x11, 0x3d, 0x12, 0x3d, 0x13, 0x3e, 0x15, 0x3c, 0x16, 0x3b, 0x17,
+ 0x3a, 0x19, 0x3a, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1e,
+ 0x3a, 0x1f, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21, 0x00, 0xb0, 0x00, 0xa7,
+ 0x00, 0x9e, 0x00, 0x94, 0x00, 0x8e, 0x00, 0x88, 0x01, 0x81, 0x02, 0x7c,
+ 0x02, 0x78, 0x03, 0x75, 0x05, 0x72, 0x06, 0x6d, 0x07, 0x6a, 0x08, 0x68,
+ 0x09, 0x66, 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x62, 0x0d, 0x60, 0x0e, 0x5d,
+ 0x25, 0x5d, 0x27, 0x5c, 0x27, 0x5a, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
+ 0x2c, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4e, 0x31, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e,
+ 0x00, 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f,
+ 0x00, 0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57, 0x00,
+ 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c, 0x00,
+ 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x10, 0x3e, 0x11,
+ 0x3d, 0x13, 0x3e, 0x14, 0x3d, 0x15, 0x3c, 0x17, 0x3a, 0x17, 0x3a, 0x19,
+ 0x3b, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f,
+ 0x39, 0x1f, 0x39, 0x1f, 0x00, 0xb0, 0x00, 0xa7, 0x00, 0xa0, 0x00, 0x96,
+ 0x00, 0x90, 0x00, 0x8a, 0x00, 0x84, 0x01, 0x7e, 0x02, 0x7a, 0x03, 0x77,
+ 0x04, 0x74, 0x05, 0x71, 0x06, 0x6c, 0x07, 0x6a, 0x08, 0x68, 0x09, 0x66,
+ 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x63, 0x0c, 0x61, 0x25, 0x5e, 0x27, 0x5c,
+ 0x27, 0x5c, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2d, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x00, 0x27, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x8f, 0x00, 0x96, 0x00, 0x99,
+ 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e,
+ 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x8c, 0x00, 0x63,
+ 0x00, 0x7f, 0x00, 0x89, 0x00, 0x90, 0x00, 0x96, 0x00, 0x9b, 0x00, 0x9c,
+ 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e,
+ 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x2c, 0x00, 0x57, 0x00, 0x82, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99,
+ 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e,
+ 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x11, 0x31, 0x00, 0x5f,
+ 0x00, 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c,
+ 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e,
+ 0x00, 0x9e, 0x00, 0x9e, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x45, 0x0b,
+ 0x42, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3d, 0x12, 0x3d, 0x13,
+ 0x3e, 0x15, 0x3c, 0x15, 0x3c, 0x17, 0x3a, 0x17, 0x3a, 0x19, 0x3b, 0x19,
+ 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x1f,
+ 0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x98, 0x00, 0x91, 0x00, 0x8c,
+ 0x00, 0x87, 0x01, 0x80, 0x02, 0x7c, 0x02, 0x79, 0x03, 0x76, 0x05, 0x74,
+ 0x05, 0x70, 0x06, 0x6b, 0x07, 0x6a, 0x08, 0x68, 0x09, 0x66, 0x0a, 0x65,
+ 0x0b, 0x64, 0x0c, 0x63, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x58,
+ 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x0d,
+ 0x00, 0x4f, 0x00, 0x73, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x95,
+ 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c,
+ 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x63, 0x00, 0x4d, 0x00, 0x60, 0x00, 0x77,
+ 0x00, 0x83, 0x00, 0x8c, 0x00, 0x92, 0x00, 0x95, 0x00, 0x98, 0x00, 0x99,
+ 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x01, 0x04, 0x16,
+ 0x00, 0x57, 0x00, 0x78, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x94, 0x00, 0x96,
+ 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c,
+ 0x00, 0x9d, 0x00, 0x9d, 0x23, 0x03, 0x00, 0x20, 0x00, 0x5f, 0x00, 0x7c,
+ 0x00, 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a,
+ 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x41, 0x0e,
+ 0x42, 0x0f, 0x40, 0x11, 0x3d, 0x11, 0x3d, 0x13, 0x3f, 0x13, 0x3d, 0x15,
+ 0x3c, 0x16, 0x3b, 0x17, 0x3a, 0x18, 0x3a, 0x19, 0x3b, 0x19, 0x3c, 0x1a,
+ 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3b, 0x1e, 0x00, 0xb1, 0x00, 0xa9,
+ 0x00, 0xa2, 0x00, 0x9a, 0x00, 0x93, 0x00, 0x8d, 0x00, 0x89, 0x01, 0x83,
+ 0x02, 0x7e, 0x02, 0x7a, 0x03, 0x78, 0x03, 0x75, 0x05, 0x73, 0x06, 0x6f,
+ 0x06, 0x6b, 0x07, 0x69, 0x08, 0x68, 0x09, 0x66, 0x0a, 0x66, 0x0b, 0x64,
+ 0x24, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x59, 0x2a, 0x57, 0x2a, 0x57,
+ 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x38,
+ 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e,
+ 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99,
+ 0x00, 0x7f, 0x00, 0x60, 0x00, 0x24, 0x00, 0x48, 0x00, 0x60, 0x00, 0x70,
+ 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x93,
+ 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x27, 0x00, 0x01, 0x12, 0x00, 0x43,
+ 0x00, 0x61, 0x00, 0x74, 0x00, 0x7f, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90,
+ 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99,
+ 0x46, 0x00, 0x1f, 0x00, 0x00, 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79,
+ 0x00, 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96,
+ 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x41, 0x0e, 0x42, 0x0f, 0x40, 0x10,
+ 0x3e, 0x11, 0x3d, 0x13, 0x3d, 0x13, 0x3f, 0x15, 0x3c, 0x15, 0x3c, 0x17,
+ 0x3a, 0x17, 0x3a, 0x18, 0x3b, 0x19, 0x3b, 0x19, 0x3c, 0x1a, 0x3c, 0x1c,
+ 0x3b, 0x1c, 0x3b, 0x1c, 0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa3, 0x00, 0x9c,
+ 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8b, 0x00, 0x86, 0x01, 0x80, 0x02, 0x7c,
+ 0x02, 0x79, 0x03, 0x77, 0x04, 0x75, 0x05, 0x72, 0x06, 0x6e, 0x07, 0x6b,
+ 0x07, 0x69, 0x09, 0x68, 0x09, 0x66, 0x0a, 0x66, 0x24, 0x5e, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5a, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
+ 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2a, 0x00, 0x48,
+ 0x00, 0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88,
+ 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x89, 0x00, 0x77,
+ 0x00, 0x48, 0x00, 0x0f, 0x00, 0x30, 0x00, 0x48, 0x00, 0x5d, 0x00, 0x6c,
+ 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e,
+ 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x41, 0x00, 0x17, 0x00, 0x00, 0x10, 0x00, 0x36, 0x00, 0x51,
+ 0x00, 0x64, 0x00, 0x71, 0x00, 0x7a, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a,
+ 0x00, 0x8d, 0x00, 0x90, 0x00, 0x92, 0x00, 0x93, 0x52, 0x00, 0x3c, 0x00,
+ 0x0d, 0x00, 0x00, 0x1f, 0x00, 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76,
+ 0x00, 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91,
+ 0x00, 0x93, 0x00, 0x95, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x46, 0x0b,
+ 0x44, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x40, 0x11, 0x3d, 0x11,
+ 0x3d, 0x13, 0x3f, 0x13, 0x3e, 0x15, 0x3c, 0x15, 0x3c, 0x17, 0x3a, 0x17,
+ 0x3a, 0x18, 0x3b, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c,
+ 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x95, 0x00, 0x90,
+ 0x00, 0x8c, 0x00, 0x88, 0x01, 0x82, 0x02, 0x7e, 0x02, 0x7b, 0x02, 0x78,
+ 0x03, 0x76, 0x05, 0x74, 0x05, 0x71, 0x06, 0x6d, 0x07, 0x6b, 0x07, 0x69,
+ 0x09, 0x68, 0x09, 0x66, 0x24, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5b,
+ 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x50,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f,
+ 0x00, 0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83,
+ 0x00, 0x86, 0x00, 0x89, 0x00, 0x90, 0x00, 0x83, 0x00, 0x60, 0x00, 0x30,
+ 0x00, 0x02, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x5e, 0x00, 0x69,
+ 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x86, 0x00, 0x89,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x4d, 0x00,
+ 0x2f, 0x00, 0x0e, 0x00, 0x00, 0x10, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x57,
+ 0x00, 0x64, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85,
+ 0x00, 0x89, 0x00, 0x8b, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02, 0x00,
+ 0x00, 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74,
+ 0x00, 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d,
+ 0x1b, 0x85, 0x05, 0x96, 0x01, 0x9e, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xa9,
+ 0x00, 0xab, 0x00, 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf,
+ 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2,
+ 0x00, 0xb2, 0x00, 0xb2, 0x1c, 0x6e, 0x03, 0x8a, 0x00, 0x97, 0x00, 0x9e,
+ 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xac,
+ 0x00, 0xad, 0x00, 0xad, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf,
+ 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x0e, 0x92, 0x01, 0xa1, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xac, 0x00, 0xae,
+ 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb2,
+ 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3,
+ 0x00, 0xb4, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53,
+ 0x00, 0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e,
+ 0x00, 0x96, 0x00, 0x8c, 0x00, 0x70, 0x00, 0x48, 0x00, 0x22, 0x00, 0x01,
+ 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00, 0x5e, 0x00, 0x68,
+ 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x3e, 0x00, 0x23, 0x00,
+ 0x0a, 0x02, 0x00, 0x10, 0x00, 0x29, 0x00, 0x3d, 0x00, 0x4e, 0x00, 0x5b,
+ 0x00, 0x65, 0x00, 0x6d, 0x00, 0x74, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82,
+ 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x00, 0x00, 0x04, 0x00, 0x1f,
+ 0x00, 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73,
+ 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85, 0x27, 0x60, 0x0f, 0x73,
+ 0x07, 0x81, 0x03, 0x8a, 0x01, 0x91, 0x00, 0x95, 0x00, 0x99, 0x00, 0x9d,
+ 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
+ 0x00, 0xa7, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa,
+ 0x29, 0x3a, 0x0f, 0x59, 0x06, 0x6c, 0x02, 0x79, 0x00, 0x84, 0x00, 0x8b,
+ 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9f,
+ 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa6,
+ 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x14, 0x79, 0x07, 0x88,
+ 0x03, 0x92, 0x01, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa5,
+ 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00, 0xac,
+ 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55,
+ 0x00, 0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x9b, 0x00, 0x92,
+ 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x18,
+ 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00, 0x66,
+ 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x56, 0x00, 0x47, 0x00, 0x31, 0x00, 0x1a, 0x00, 0x08, 0x04,
+ 0x00, 0x10, 0x00, 0x25, 0x00, 0x37, 0x00, 0x46, 0x00, 0x52, 0x00, 0x5d,
+ 0x00, 0x65, 0x00, 0x6c, 0x00, 0x72, 0x00, 0x77, 0x5c, 0x00, 0x55, 0x00,
+ 0x43, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x33,
+ 0x00, 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72,
+ 0x00, 0x77, 0x00, 0x7b, 0x2d, 0x54, 0x17, 0x63, 0x0d, 0x6f, 0x07, 0x78,
+ 0x04, 0x80, 0x02, 0x86, 0x01, 0x8b, 0x01, 0x8f, 0x00, 0x92, 0x00, 0x95,
+ 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1,
+ 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa4, 0x31, 0x27, 0x18, 0x40,
+ 0x0d, 0x52, 0x07, 0x61, 0x04, 0x6c, 0x02, 0x75, 0x01, 0x7c, 0x00, 0x82,
+ 0x00, 0x87, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x97,
+ 0x00, 0x98, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x18, 0x6f, 0x0c, 0x7b, 0x06, 0x84, 0x03, 0x8c,
+ 0x02, 0x91, 0x01, 0x96, 0x00, 0x99, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa1,
+ 0x00, 0xa2, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xa8,
+ 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57,
+ 0x00, 0x5f, 0x00, 0x66, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x84, 0x00, 0x6c,
+ 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x26,
+ 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00, 0x5f, 0x00, 0x66,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00,
+ 0x4d, 0x00, 0x3b, 0x00, 0x27, 0x00, 0x13, 0x00, 0x07, 0x06, 0x00, 0x10,
+ 0x00, 0x22, 0x00, 0x32, 0x00, 0x40, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5e,
+ 0x00, 0x65, 0x00, 0x6b, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36, 0x00,
+ 0x1f, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f,
+ 0x00, 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71,
+ 0x30, 0x4e, 0x1d, 0x5a, 0x12, 0x64, 0x0c, 0x6d, 0x08, 0x75, 0x05, 0x7a,
+ 0x03, 0x7f, 0x02, 0x85, 0x02, 0x89, 0x01, 0x8b, 0x00, 0x8e, 0x00, 0x90,
+ 0x00, 0x92, 0x00, 0x94, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9c,
+ 0x00, 0x9e, 0x00, 0x9f, 0x36, 0x1e, 0x1f, 0x32, 0x12, 0x43, 0x0b, 0x50,
+ 0x07, 0x5a, 0x05, 0x63, 0x02, 0x6b, 0x01, 0x72, 0x01, 0x78, 0x00, 0x7c,
+ 0x00, 0x81, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90,
+ 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x1b, 0x6b, 0x0f, 0x74, 0x09, 0x7d, 0x05, 0x83, 0x03, 0x89, 0x02, 0x8d,
+ 0x01, 0x91, 0x00, 0x95, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00, 0x9e,
+ 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5,
+ 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
+ 0x00, 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58,
+ 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5e, 0x00, 0x45,
+ 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x22, 0x00, 0x30,
+ 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x42, 0x00,
+ 0x32, 0x00, 0x20, 0x00, 0x0e, 0x00, 0x06, 0x07, 0x00, 0x10, 0x00, 0x20,
+ 0x00, 0x2f, 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x58, 0x00, 0x5f,
+ 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17, 0x00,
+ 0x03, 0x00, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46,
+ 0x00, 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66, 0x33, 0x4b, 0x21, 0x54,
+ 0x16, 0x5d, 0x10, 0x65, 0x0b, 0x6c, 0x08, 0x72, 0x06, 0x77, 0x04, 0x7b,
+ 0x03, 0x7f, 0x02, 0x83, 0x02, 0x87, 0x01, 0x8a, 0x01, 0x8c, 0x00, 0x8e,
+ 0x00, 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x98,
+ 0x3a, 0x19, 0x24, 0x2a, 0x18, 0x38, 0x10, 0x44, 0x0b, 0x4e, 0x07, 0x57,
+ 0x05, 0x5f, 0x04, 0x65, 0x02, 0x6b, 0x01, 0x71, 0x01, 0x76, 0x00, 0x79,
+ 0x00, 0x7e, 0x00, 0x80, 0x00, 0x84, 0x00, 0x87, 0x00, 0x88, 0x00, 0x8b,
+ 0x00, 0x8d, 0x00, 0x8f, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x1d, 0x68, 0x12, 0x70,
+ 0x0c, 0x77, 0x08, 0x7d, 0x05, 0x82, 0x03, 0x87, 0x02, 0x8b, 0x02, 0x8e,
+ 0x01, 0x91, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9b,
+ 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x9d, 0x00, 0x99,
+ 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00, 0x3c, 0x00, 0x26,
+ 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x37,
+ 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2a, 0x00,
+ 0x1a, 0x00, 0x0b, 0x00, 0x05, 0x08, 0x00, 0x10, 0x00, 0x1e, 0x00, 0x2c,
+ 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x5e, 0x00, 0x5b, 0x00,
+ 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c,
+ 0x00, 0x54, 0x00, 0x5b, 0x34, 0x49, 0x25, 0x51, 0x1a, 0x58, 0x13, 0x60,
+ 0x0e, 0x65, 0x0b, 0x6b, 0x08, 0x71, 0x06, 0x75, 0x05, 0x78, 0x04, 0x7b,
+ 0x03, 0x7f, 0x02, 0x83, 0x02, 0x86, 0x01, 0x88, 0x01, 0x8a, 0x00, 0x8c,
+ 0x00, 0x8d, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x92, 0x3b, 0x17, 0x28, 0x24,
+ 0x1c, 0x30, 0x14, 0x3b, 0x0f, 0x45, 0x0b, 0x4d, 0x07, 0x55, 0x05, 0x5b,
+ 0x04, 0x61, 0x03, 0x67, 0x02, 0x6b, 0x01, 0x6f, 0x01, 0x74, 0x00, 0x77,
+ 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x83, 0x00, 0x86, 0x00, 0x87,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x1d, 0x67, 0x14, 0x6d, 0x0e, 0x73, 0x0a, 0x79,
+ 0x07, 0x7e, 0x05, 0x82, 0x03, 0x86, 0x02, 0x89, 0x02, 0x8c, 0x01, 0x8f,
+ 0x01, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a,
+ 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28,
+ 0x00, 0x33, 0x00, 0x3d, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x91, 0x00, 0x83,
+ 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00, 0x22, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x33, 0x00, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00,
+ 0x56, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x32, 0x00, 0x24, 0x00, 0x15, 0x00,
+ 0x0a, 0x02, 0x04, 0x09, 0x00, 0x10, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x34,
+ 0x00, 0x3e, 0x00, 0x46, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49, 0x00,
+ 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x00, 0x00, 0x04, 0x00, 0x12,
+ 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50,
+ 0x36, 0x47, 0x27, 0x4e, 0x1d, 0x54, 0x16, 0x5b, 0x11, 0x61, 0x0e, 0x65,
+ 0x0b, 0x6a, 0x08, 0x6f, 0x07, 0x73, 0x05, 0x76, 0x05, 0x79, 0x03, 0x7c,
+ 0x02, 0x7e, 0x02, 0x82, 0x02, 0x85, 0x01, 0x88, 0x01, 0x89, 0x01, 0x8b,
+ 0x00, 0x8c, 0x00, 0x8d, 0x3d, 0x14, 0x2c, 0x20, 0x20, 0x2a, 0x18, 0x34,
+ 0x12, 0x3e, 0x0e, 0x45, 0x0a, 0x4c, 0x07, 0x53, 0x06, 0x58, 0x05, 0x5e,
+ 0x04, 0x63, 0x02, 0x67, 0x02, 0x6c, 0x01, 0x6f, 0x01, 0x72, 0x00, 0x76,
+ 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x80, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x1e, 0x66, 0x16, 0x6b, 0x10, 0x71, 0x0c, 0x76, 0x09, 0x7a, 0x07, 0x7e,
+ 0x05, 0x81, 0x03, 0x85, 0x03, 0x88, 0x02, 0x8b, 0x02, 0x8d, 0x01, 0x8f,
+ 0x01, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x98, 0x00, 0x99,
+ 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f,
+ 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00, 0x79, 0x00, 0x68,
+ 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00,
+ 0x44, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x09, 0x03,
+ 0x04, 0x09, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x27, 0x00, 0x31, 0x00, 0x3a,
+ 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33, 0x00,
+ 0x24, 0x00, 0x15, 0x00, 0x07, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f,
+ 0x00, 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46, 0x37, 0x46, 0x29, 0x4c,
+ 0x20, 0x52, 0x19, 0x57, 0x14, 0x5d, 0x10, 0x62, 0x0d, 0x66, 0x0b, 0x69,
+ 0x09, 0x6e, 0x07, 0x73, 0x06, 0x75, 0x05, 0x77, 0x04, 0x7a, 0x03, 0x7c,
+ 0x02, 0x7e, 0x02, 0x82, 0x02, 0x84, 0x02, 0x87, 0x01, 0x88, 0x01, 0x89,
+ 0x3f, 0x13, 0x2f, 0x1c, 0x23, 0x27, 0x1b, 0x2f, 0x15, 0x38, 0x10, 0x3e,
+ 0x0d, 0x45, 0x0a, 0x4b, 0x08, 0x51, 0x07, 0x57, 0x05, 0x5c, 0x04, 0x60,
+ 0x03, 0x65, 0x02, 0x67, 0x02, 0x6c, 0x01, 0x6f, 0x01, 0x71, 0x00, 0x75,
+ 0x00, 0x77, 0x00, 0x79, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x1f, 0x65, 0x17, 0x6a,
+ 0x11, 0x6f, 0x0d, 0x73, 0x0a, 0x77, 0x08, 0x7b, 0x06, 0x7e, 0x05, 0x81,
+ 0x04, 0x84, 0x03, 0x87, 0x02, 0x89, 0x02, 0x8b, 0x01, 0x8e, 0x01, 0x8f,
+ 0x01, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x9e, 0x00, 0x9c,
+ 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00, 0x5f, 0x00, 0x4e,
+ 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c,
+ 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00,
+ 0x32, 0x00, 0x26, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x08, 0x04, 0x04, 0x0a,
+ 0x00, 0x10, 0x00, 0x1b, 0x00, 0x25, 0x00, 0x2f, 0x5e, 0x00, 0x5d, 0x00,
+ 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e, 0x00,
+ 0x10, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a,
+ 0x00, 0x33, 0x00, 0x3b, 0x38, 0x45, 0x2b, 0x4a, 0x22, 0x50, 0x1c, 0x55,
+ 0x16, 0x59, 0x12, 0x5f, 0x0f, 0x63, 0x0d, 0x66, 0x0b, 0x69, 0x09, 0x6e,
+ 0x07, 0x71, 0x06, 0x74, 0x05, 0x76, 0x05, 0x78, 0x03, 0x7a, 0x03, 0x7c,
+ 0x02, 0x7e, 0x02, 0x81, 0x02, 0x84, 0x02, 0x86, 0x40, 0x11, 0x31, 0x1b,
+ 0x26, 0x23, 0x1e, 0x2b, 0x18, 0x33, 0x13, 0x39, 0x0f, 0x40, 0x0c, 0x45,
+ 0x0a, 0x4b, 0x08, 0x51, 0x07, 0x56, 0x05, 0x59, 0x04, 0x5e, 0x04, 0x61,
+ 0x02, 0x65, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6e, 0x01, 0x71, 0x00, 0x73,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x20, 0x64, 0x18, 0x69, 0x13, 0x6d, 0x0f, 0x71,
+ 0x0c, 0x75, 0x09, 0x78, 0x07, 0x7b, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84,
+ 0x03, 0x86, 0x02, 0x88, 0x02, 0x8a, 0x02, 0x8c, 0x01, 0x8e, 0x01, 0x8f,
+ 0x01, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x16, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8e,
+ 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00, 0x47, 0x00, 0x37,
+ 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x16,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
+ 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00, 0x38, 0x00, 0x2d, 0x00,
+ 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x07, 0x05, 0x03, 0x0a, 0x00, 0x0f,
+ 0x00, 0x1a, 0x00, 0x24, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52, 0x00,
+ 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31,
+ 0x38, 0x45, 0x2d, 0x49, 0x24, 0x4e, 0x1e, 0x53, 0x19, 0x56, 0x14, 0x5b,
+ 0x11, 0x60, 0x0e, 0x63, 0x0c, 0x66, 0x0a, 0x69, 0x09, 0x6c, 0x07, 0x70,
+ 0x06, 0x73, 0x06, 0x75, 0x05, 0x77, 0x04, 0x79, 0x03, 0x7a, 0x03, 0x7c,
+ 0x02, 0x7e, 0x02, 0x80, 0x40, 0x11, 0x32, 0x18, 0x28, 0x20, 0x20, 0x28,
+ 0x1a, 0x2f, 0x16, 0x35, 0x12, 0x3c, 0x0f, 0x41, 0x0c, 0x46, 0x0a, 0x4b,
+ 0x08, 0x50, 0x07, 0x54, 0x05, 0x58, 0x05, 0x5c, 0x04, 0x5f, 0x04, 0x62,
+ 0x02, 0x66, 0x02, 0x69, 0x01, 0x6b, 0x01, 0x6e, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x20, 0x64, 0x19, 0x68, 0x14, 0x6b, 0x10, 0x6f, 0x0d, 0x73, 0x0b, 0x76,
+ 0x09, 0x79, 0x07, 0x7c, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85,
+ 0x02, 0x88, 0x02, 0x89, 0x02, 0x8b, 0x02, 0x8d, 0x01, 0x8e, 0x01, 0x90,
+ 0x00, 0x91, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00, 0x86, 0x00, 0x7a,
+ 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00, 0x33, 0x00, 0x25,
+ 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00,
+ 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x28, 0x00, 0x1e, 0x00,
+ 0x14, 0x00, 0x0b, 0x00, 0x07, 0x06, 0x03, 0x0b, 0x00, 0x0f, 0x00, 0x19,
+ 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00,
+ 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x01,
+ 0x00, 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28, 0x39, 0x44, 0x2e, 0x49,
+ 0x26, 0x4c, 0x1f, 0x52, 0x1a, 0x55, 0x16, 0x58, 0x13, 0x5d, 0x10, 0x61,
+ 0x0e, 0x64, 0x0c, 0x66, 0x0a, 0x68, 0x09, 0x6c, 0x07, 0x70, 0x07, 0x72,
+ 0x06, 0x74, 0x05, 0x76, 0x05, 0x78, 0x03, 0x79, 0x03, 0x7b, 0x02, 0x7c,
+ 0x41, 0x10, 0x34, 0x17, 0x2a, 0x1e, 0x23, 0x25, 0x1d, 0x2c, 0x18, 0x32,
+ 0x14, 0x37, 0x10, 0x3d, 0x0e, 0x42, 0x0c, 0x46, 0x0a, 0x4b, 0x08, 0x4f,
+ 0x07, 0x53, 0x05, 0x57, 0x05, 0x5a, 0x04, 0x5e, 0x04, 0x61, 0x03, 0x63,
+ 0x02, 0x66, 0x02, 0x69, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x20, 0x63, 0x1a, 0x67,
+ 0x15, 0x6a, 0x11, 0x6e, 0x0e, 0x71, 0x0c, 0x74, 0x0a, 0x77, 0x08, 0x7a,
+ 0x07, 0x7c, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85, 0x02, 0x87,
+ 0x02, 0x88, 0x02, 0x8a, 0x02, 0x8c, 0x01, 0x8d, 0x01, 0x8e, 0x01, 0x90,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d,
+ 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x66,
+ 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00, 0x22, 0x00, 0x16,
+ 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x48, 0x00,
+ 0x40, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x00,
+ 0x0a, 0x01, 0x06, 0x06, 0x03, 0x0b, 0x00, 0x0f, 0x5f, 0x00, 0x5d, 0x00,
+ 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31, 0x00,
+ 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0d,
+ 0x00, 0x17, 0x00, 0x1f, 0x39, 0x43, 0x2f, 0x48, 0x27, 0x4b, 0x22, 0x4f,
+ 0x1c, 0x54, 0x18, 0x56, 0x14, 0x59, 0x12, 0x5e, 0x0f, 0x62, 0x0d, 0x64,
+ 0x0c, 0x66, 0x0a, 0x68, 0x09, 0x6b, 0x08, 0x6f, 0x07, 0x72, 0x06, 0x74,
+ 0x05, 0x75, 0x05, 0x77, 0x04, 0x78, 0x03, 0x7a, 0x42, 0x0f, 0x36, 0x16,
+ 0x2c, 0x1c, 0x25, 0x23, 0x1f, 0x29, 0x1a, 0x2e, 0x16, 0x34, 0x12, 0x39,
+ 0x0f, 0x3e, 0x0d, 0x42, 0x0c, 0x47, 0x0a, 0x4b, 0x08, 0x4f, 0x07, 0x52,
+ 0x05, 0x56, 0x05, 0x59, 0x04, 0x5c, 0x04, 0x5f, 0x04, 0x62, 0x02, 0x64,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1b, 0x66, 0x16, 0x6a, 0x12, 0x6d,
+ 0x0f, 0x70, 0x0d, 0x73, 0x0b, 0x75, 0x09, 0x78, 0x07, 0x7a, 0x06, 0x7d,
+ 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85, 0x02, 0x86, 0x02, 0x88,
+ 0x02, 0x89, 0x02, 0x8b, 0x02, 0x8c, 0x01, 0x8d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3a, 0x43, 0x31, 0x48, 0x29, 0x4a, 0x23, 0x4d, 0x1e, 0x53, 0x1a, 0x55,
+ 0x16, 0x57, 0x13, 0x5b, 0x11, 0x60, 0x0f, 0x62, 0x0d, 0x64, 0x0b, 0x66,
+ 0x0a, 0x68, 0x09, 0x6a, 0x08, 0x6e, 0x07, 0x71, 0x06, 0x73, 0x06, 0x75,
+ 0x05, 0x76, 0x05, 0x78, 0x43, 0x0f, 0x37, 0x15, 0x2e, 0x1b, 0x27, 0x21,
+ 0x21, 0x26, 0x1c, 0x2c, 0x18, 0x31, 0x15, 0x36, 0x12, 0x3a, 0x0f, 0x3f,
+ 0x0c, 0x43, 0x0c, 0x47, 0x0a, 0x4b, 0x08, 0x4e, 0x07, 0x52, 0x06, 0x55,
+ 0x05, 0x58, 0x05, 0x5b, 0x04, 0x5d, 0x04, 0x60, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x21, 0x63, 0x1b, 0x66, 0x17, 0x69, 0x13, 0x6c, 0x10, 0x6e, 0x0e, 0x71,
+ 0x0c, 0x74, 0x0a, 0x76, 0x09, 0x79, 0x07, 0x7b, 0x06, 0x7d, 0x06, 0x7f,
+ 0x05, 0x81, 0x04, 0x82, 0x03, 0x84, 0x03, 0x86, 0x02, 0x87, 0x02, 0x89,
+ 0x02, 0x8a, 0x02, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x42, 0x31, 0x47,
+ 0x2a, 0x49, 0x24, 0x4c, 0x1f, 0x51, 0x1b, 0x54, 0x18, 0x56, 0x15, 0x58,
+ 0x12, 0x5c, 0x10, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0b, 0x66, 0x0a, 0x68,
+ 0x09, 0x6a, 0x08, 0x6d, 0x07, 0x71, 0x06, 0x72, 0x06, 0x74, 0x05, 0x75,
+ 0x43, 0x0f, 0x38, 0x14, 0x2f, 0x19, 0x28, 0x1f, 0x22, 0x24, 0x1d, 0x29,
+ 0x19, 0x2e, 0x16, 0x33, 0x12, 0x37, 0x11, 0x3b, 0x0f, 0x40, 0x0c, 0x43,
+ 0x0b, 0x47, 0x0a, 0x4b, 0x09, 0x4e, 0x07, 0x51, 0x07, 0x55, 0x05, 0x56,
+ 0x05, 0x5a, 0x04, 0x5c, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1c, 0x65,
+ 0x17, 0x68, 0x14, 0x6b, 0x11, 0x6e, 0x0e, 0x70, 0x0c, 0x73, 0x0b, 0x75,
+ 0x09, 0x77, 0x08, 0x79, 0x07, 0x7b, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81,
+ 0x04, 0x82, 0x03, 0x84, 0x03, 0x86, 0x02, 0x87, 0x02, 0x88, 0x02, 0x89,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0x42, 0x32, 0x46, 0x2b, 0x49, 0x25, 0x4b,
+ 0x21, 0x4f, 0x1d, 0x53, 0x19, 0x55, 0x16, 0x57, 0x14, 0x59, 0x11, 0x5e,
+ 0x10, 0x61, 0x0e, 0x63, 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x6a,
+ 0x08, 0x6c, 0x07, 0x70, 0x07, 0x72, 0x06, 0x73, 0x43, 0x0e, 0x39, 0x13,
+ 0x31, 0x18, 0x2a, 0x1d, 0x24, 0x22, 0x1f, 0x27, 0x1b, 0x2b, 0x18, 0x30,
+ 0x16, 0x35, 0x12, 0x39, 0x0f, 0x3c, 0x0f, 0x41, 0x0c, 0x44, 0x0b, 0x47,
+ 0x0a, 0x4a, 0x09, 0x4e, 0x07, 0x50, 0x07, 0x54, 0x05, 0x55, 0x05, 0x59,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1c, 0x65, 0x18, 0x68, 0x15, 0x6a,
+ 0x12, 0x6c, 0x0f, 0x6f, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x76, 0x09, 0x78,
+ 0x07, 0x79, 0x07, 0x7c, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81, 0x04, 0x82,
+ 0x03, 0x84, 0x03, 0x85, 0x02, 0x86, 0x02, 0x88, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x42, 0x33, 0x45, 0x2c, 0x49, 0x27, 0x4b, 0x22, 0x4d, 0x1e, 0x52,
+ 0x1b, 0x54, 0x18, 0x56, 0x15, 0x58, 0x13, 0x5b, 0x10, 0x5f, 0x0f, 0x61,
+ 0x0e, 0x63, 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x08, 0x6c,
+ 0x07, 0x6f, 0x07, 0x72, 0x44, 0x0e, 0x3a, 0x12, 0x32, 0x17, 0x2b, 0x1c,
+ 0x26, 0x21, 0x21, 0x26, 0x1d, 0x2a, 0x19, 0x2e, 0x16, 0x32, 0x14, 0x35,
+ 0x12, 0x3a, 0x0f, 0x3d, 0x0e, 0x41, 0x0c, 0x44, 0x0b, 0x47, 0x0a, 0x4a,
+ 0x09, 0x4e, 0x07, 0x4f, 0x07, 0x53, 0x05, 0x55, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x22, 0x62, 0x1d, 0x65, 0x19, 0x67, 0x15, 0x6a, 0x13, 0x6c, 0x10, 0x6e,
+ 0x0e, 0x71, 0x0c, 0x73, 0x0b, 0x74, 0x0a, 0x76, 0x09, 0x79, 0x07, 0x7a,
+ 0x07, 0x7c, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81, 0x04, 0x82, 0x03, 0x83,
+ 0x03, 0x85, 0x02, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x33, 0x44,
+ 0x2d, 0x48, 0x28, 0x4a, 0x23, 0x4c, 0x1f, 0x50, 0x1c, 0x53, 0x19, 0x55,
+ 0x16, 0x57, 0x14, 0x58, 0x12, 0x5c, 0x10, 0x60, 0x0e, 0x62, 0x0d, 0x63,
+ 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x09, 0x6b, 0x07, 0x6e,
+ 0x44, 0x0d, 0x3a, 0x12, 0x33, 0x16, 0x2c, 0x1b, 0x27, 0x1f, 0x21, 0x24,
+ 0x1e, 0x28, 0x1a, 0x2b, 0x18, 0x30, 0x16, 0x34, 0x12, 0x37, 0x11, 0x3b,
+ 0x0f, 0x3e, 0x0d, 0x41, 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e,
+ 0x07, 0x4f, 0x07, 0x53, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1d, 0x65,
+ 0x19, 0x66, 0x16, 0x69, 0x13, 0x6b, 0x10, 0x6d, 0x0f, 0x6f, 0x0d, 0x71,
+ 0x0c, 0x73, 0x0b, 0x76, 0x09, 0x77, 0x08, 0x79, 0x07, 0x7a, 0x06, 0x7c,
+ 0x06, 0x7e, 0x05, 0x7f, 0x05, 0x80, 0x04, 0x82, 0x03, 0x83, 0x03, 0x85,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x34, 0x44, 0x2e, 0x48, 0x29, 0x49,
+ 0x24, 0x4b, 0x20, 0x4f, 0x1d, 0x53, 0x1a, 0x55, 0x18, 0x56, 0x15, 0x58,
+ 0x13, 0x59, 0x11, 0x5d, 0x10, 0x61, 0x0e, 0x62, 0x0d, 0x63, 0x0c, 0x65,
+ 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x09, 0x6b, 0x44, 0x0d, 0x3b, 0x12,
+ 0x34, 0x16, 0x2e, 0x19, 0x28, 0x1e, 0x23, 0x22, 0x20, 0x26, 0x1d, 0x2b,
+ 0x19, 0x2e, 0x16, 0x31, 0x14, 0x35, 0x12, 0x38, 0x0f, 0x3b, 0x0f, 0x3f,
+ 0x0c, 0x41, 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e, 0x07, 0x4e,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1d, 0x64, 0x1a, 0x66, 0x17, 0x68,
+ 0x14, 0x6a, 0x11, 0x6c, 0x10, 0x6e, 0x0e, 0x71, 0x0c, 0x73, 0x0b, 0x74,
+ 0x0a, 0x76, 0x09, 0x78, 0x07, 0x79, 0x07, 0x7b, 0x06, 0x7c, 0x06, 0x7e,
+ 0x05, 0x7f, 0x05, 0x80, 0x04, 0x82, 0x03, 0x82, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x42, 0x34, 0x43, 0x2f, 0x48, 0x29, 0x49, 0x25, 0x4b, 0x21, 0x4d,
+ 0x1e, 0x51, 0x1b, 0x54, 0x18, 0x55, 0x16, 0x56, 0x14, 0x58, 0x13, 0x5b,
+ 0x10, 0x5e, 0x0f, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0c, 0x66, 0x0b, 0x66,
+ 0x0a, 0x68, 0x09, 0x69, 0x44, 0x0c, 0x3c, 0x11, 0x35, 0x16, 0x2f, 0x19,
+ 0x2a, 0x1d, 0x25, 0x22, 0x21, 0x25, 0x1d, 0x29, 0x1a, 0x2b, 0x18, 0x30,
+ 0x16, 0x33, 0x12, 0x35, 0x12, 0x3a, 0x0f, 0x3c, 0x0f, 0x40, 0x0c, 0x41,
+ 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x22, 0x62, 0x1e, 0x64, 0x1a, 0x66, 0x17, 0x68, 0x15, 0x6a, 0x12, 0x6c,
+ 0x10, 0x6e, 0x0e, 0x70, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x75, 0x09, 0x76,
+ 0x09, 0x78, 0x07, 0x79, 0x07, 0x7b, 0x06, 0x7c, 0x06, 0x7e, 0x05, 0x7f,
+ 0x05, 0x80, 0x04, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x35, 0x43,
+ 0x2f, 0x47, 0x2b, 0x49, 0x26, 0x4b, 0x22, 0x4c, 0x1f, 0x4f, 0x1c, 0x53,
+ 0x1a, 0x55, 0x18, 0x56, 0x15, 0x58, 0x13, 0x59, 0x12, 0x5c, 0x10, 0x60,
+ 0x0f, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0c, 0x66, 0x0b, 0x66, 0x0a, 0x68,
+ 0x44, 0x0c, 0x3c, 0x10, 0x35, 0x15, 0x30, 0x19, 0x2b, 0x1c, 0x26, 0x20,
+ 0x21, 0x23, 0x1e, 0x26, 0x1c, 0x2b, 0x19, 0x2e, 0x16, 0x30, 0x15, 0x35,
+ 0x12, 0x37, 0x11, 0x3b, 0x0f, 0x3d, 0x0f, 0x41, 0x0c, 0x42, 0x0c, 0x46,
+ 0x0a, 0x47, 0x0a, 0x4a, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1e, 0x64,
+ 0x1a, 0x66, 0x18, 0x68, 0x15, 0x6a, 0x13, 0x6b, 0x10, 0x6d, 0x0f, 0x6e,
+ 0x0e, 0x71, 0x0c, 0x72, 0x0b, 0x74, 0x0a, 0x76, 0x09, 0x77, 0x08, 0x79,
+ 0x07, 0x7a, 0x07, 0x7c, 0x06, 0x7c, 0x06, 0x7e, 0x05, 0x7f, 0x05, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x09, 0x43, 0x09, 0x44, 0x09, 0x45, 0x09,
+ 0x45, 0x09, 0x46, 0x09, 0x46, 0x09, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0x22, 0x1c, 0x0a, 0x29, 0x0a, 0x31, 0x09, 0x36, 0x09, 0x3a, 0x09,
+ 0x3b, 0x09, 0x3d, 0x09, 0x3f, 0x09, 0x40, 0x09, 0x40, 0x09, 0x41, 0x09,
+ 0x42, 0x09, 0x43, 0x09, 0x43, 0x0a, 0x43, 0x0a, 0x44, 0x0a, 0x44, 0x0a,
+ 0x44, 0x0a, 0x44, 0x0a, 0x23, 0x16, 0x32, 0x0a, 0x38, 0x0a, 0x3c, 0x0a,
+ 0x3f, 0x09, 0x40, 0x09, 0x41, 0x09, 0x42, 0x09, 0x43, 0x09, 0x44, 0x09,
+ 0x44, 0x0a, 0x44, 0x0a, 0x44, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a,
+ 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x46, 0x0a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x16, 0x3e, 0x11, 0x3f, 0x0f, 0x40, 0x0d, 0x41, 0x0d, 0x41, 0x0c,
+ 0x42, 0x0c, 0x43, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x44, 0x0a,
+ 0x44, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x46, 0x0a, 0x46, 0x0a,
+ 0x46, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x6e, 0x03, 0x3a,
+ 0x0f, 0x27, 0x18, 0x1e, 0x1f, 0x19, 0x24, 0x17, 0x28, 0x14, 0x2c, 0x13,
+ 0x2f, 0x11, 0x31, 0x11, 0x32, 0x10, 0x34, 0x0f, 0x36, 0x0f, 0x37, 0x0f,
+ 0x38, 0x0e, 0x39, 0x0e, 0x3a, 0x0d, 0x3a, 0x0d, 0x3b, 0x0c, 0x3c, 0x0c,
+ 0x23, 0x3c, 0x25, 0x22, 0x2b, 0x18, 0x30, 0x14, 0x33, 0x11, 0x36, 0x10,
+ 0x38, 0x0f, 0x39, 0x0e, 0x3b, 0x0e, 0x3c, 0x0d, 0x3d, 0x0d, 0x3e, 0x0c,
+ 0x3f, 0x0c, 0x3f, 0x0c, 0x40, 0x0c, 0x40, 0x0c, 0x40, 0x0b, 0x41, 0x0b,
+ 0x41, 0x0b, 0x42, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x1f, 0x3c, 0x18,
+ 0x3c, 0x14, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x0f, 0x3f, 0x0e, 0x40, 0x0e,
+ 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0c, 0x42, 0x0c,
+ 0x42, 0x0b, 0x42, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x44, 0x0b, 0x44, 0x0b,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x8a, 0x00, 0x59, 0x06, 0x40, 0x0d, 0x32,
+ 0x12, 0x2a, 0x18, 0x24, 0x1c, 0x20, 0x20, 0x1c, 0x23, 0x1b, 0x26, 0x18,
+ 0x28, 0x17, 0x2a, 0x16, 0x2c, 0x15, 0x2e, 0x14, 0x2f, 0x13, 0x31, 0x12,
+ 0x32, 0x12, 0x33, 0x12, 0x34, 0x11, 0x35, 0x10, 0x23, 0x4a, 0x24, 0x31,
+ 0x27, 0x25, 0x2a, 0x1e, 0x2d, 0x1a, 0x2f, 0x17, 0x32, 0x15, 0x33, 0x13,
+ 0x35, 0x12, 0x36, 0x11, 0x38, 0x10, 0x39, 0x10, 0x3a, 0x0f, 0x3a, 0x0f,
+ 0x3b, 0x0e, 0x3c, 0x0e, 0x3c, 0x0e, 0x3d, 0x0e, 0x3e, 0x0d, 0x3e, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x25, 0x3c, 0x1d, 0x3c, 0x19, 0x3c, 0x16,
+ 0x3d, 0x14, 0x3d, 0x12, 0x3f, 0x11, 0x3f, 0x10, 0x3f, 0x0f, 0x3f, 0x0f,
+ 0x40, 0x0e, 0x41, 0x0e, 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d,
+ 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0c, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0x97, 0x00, 0x6c, 0x02, 0x52, 0x07, 0x43, 0x0b, 0x38, 0x10, 0x30,
+ 0x14, 0x2a, 0x18, 0x27, 0x1b, 0x23, 0x1e, 0x20, 0x20, 0x1e, 0x23, 0x1c,
+ 0x25, 0x1b, 0x27, 0x19, 0x28, 0x18, 0x2a, 0x17, 0x2b, 0x16, 0x2c, 0x16,
+ 0x2e, 0x16, 0x2f, 0x15, 0x23, 0x50, 0x23, 0x3b, 0x25, 0x2e, 0x27, 0x26,
+ 0x29, 0x21, 0x2c, 0x1d, 0x2e, 0x1a, 0x2f, 0x18, 0x31, 0x16, 0x33, 0x15,
+ 0x34, 0x14, 0x35, 0x13, 0x36, 0x12, 0x37, 0x11, 0x38, 0x11, 0x38, 0x11,
+ 0x39, 0x10, 0x3a, 0x10, 0x3a, 0x10, 0x3b, 0x0f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x29, 0x3c, 0x22, 0x3b, 0x1d, 0x3b, 0x19, 0x3c, 0x17, 0x3c, 0x15,
+ 0x3c, 0x13, 0x3d, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x10, 0x3e, 0x0f,
+ 0x3f, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x41, 0x0e, 0x42, 0x0e, 0x42, 0x0d,
+ 0x42, 0x0d, 0x42, 0x0d, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x9e, 0x00, 0x79,
+ 0x00, 0x61, 0x04, 0x50, 0x07, 0x44, 0x0b, 0x3b, 0x0f, 0x34, 0x12, 0x2f,
+ 0x15, 0x2b, 0x18, 0x28, 0x1a, 0x25, 0x1d, 0x23, 0x1f, 0x21, 0x21, 0x1f,
+ 0x22, 0x1d, 0x24, 0x1c, 0x26, 0x1b, 0x27, 0x19, 0x28, 0x19, 0x2a, 0x19,
+ 0x23, 0x54, 0x23, 0x42, 0x24, 0x35, 0x25, 0x2d, 0x27, 0x27, 0x29, 0x22,
+ 0x2b, 0x1f, 0x2d, 0x1c, 0x2e, 0x1a, 0x30, 0x19, 0x31, 0x17, 0x32, 0x16,
+ 0x33, 0x15, 0x34, 0x14, 0x35, 0x13, 0x36, 0x13, 0x37, 0x12, 0x37, 0x11,
+ 0x38, 0x11, 0x38, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2c, 0x3c, 0x25,
+ 0x3b, 0x20, 0x3b, 0x1d, 0x3b, 0x1a, 0x3c, 0x17, 0x3c, 0x16, 0x3c, 0x14,
+ 0x3c, 0x13, 0x3e, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x11, 0x3d, 0x10,
+ 0x3e, 0x0f, 0x3f, 0x0f, 0x40, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x41, 0x0e,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xa2, 0x00, 0x84, 0x00, 0x6c, 0x02, 0x5a,
+ 0x05, 0x4e, 0x07, 0x45, 0x0b, 0x3e, 0x0e, 0x38, 0x10, 0x33, 0x13, 0x2f,
+ 0x16, 0x2c, 0x18, 0x29, 0x1a, 0x26, 0x1c, 0x24, 0x1d, 0x22, 0x1f, 0x21,
+ 0x21, 0x1f, 0x21, 0x1e, 0x23, 0x1d, 0x25, 0x1c, 0x23, 0x56, 0x23, 0x47,
+ 0x23, 0x3b, 0x24, 0x32, 0x26, 0x2c, 0x27, 0x27, 0x29, 0x24, 0x2a, 0x21,
+ 0x2c, 0x1e, 0x2d, 0x1c, 0x2e, 0x1b, 0x30, 0x19, 0x30, 0x18, 0x32, 0x17,
+ 0x32, 0x16, 0x33, 0x15, 0x34, 0x14, 0x34, 0x14, 0x35, 0x13, 0x36, 0x13,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2e, 0x3c, 0x27, 0x3b, 0x23, 0x3b, 0x1f,
+ 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x18, 0x3c, 0x17, 0x3b, 0x15, 0x3c, 0x14,
+ 0x3c, 0x13, 0x3e, 0x13, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11,
+ 0x3d, 0x10, 0x3e, 0x0f, 0x3f, 0x0f, 0x40, 0x0f, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0xa6, 0x00, 0x8b, 0x00, 0x75, 0x01, 0x63, 0x02, 0x57, 0x05, 0x4d,
+ 0x07, 0x45, 0x0a, 0x3e, 0x0d, 0x39, 0x0f, 0x35, 0x12, 0x32, 0x14, 0x2e,
+ 0x16, 0x2c, 0x18, 0x29, 0x19, 0x27, 0x1b, 0x26, 0x1d, 0x24, 0x1e, 0x22,
+ 0x20, 0x22, 0x21, 0x20, 0x23, 0x58, 0x23, 0x4a, 0x23, 0x3f, 0x24, 0x36,
+ 0x25, 0x30, 0x26, 0x2b, 0x27, 0x27, 0x29, 0x24, 0x2a, 0x22, 0x2b, 0x20,
+ 0x2d, 0x1e, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x18, 0x31, 0x18,
+ 0x32, 0x17, 0x32, 0x16, 0x33, 0x16, 0x34, 0x15, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x30, 0x3c, 0x2a, 0x3c, 0x25, 0x3a, 0x21, 0x3b, 0x1e, 0x3a, 0x1c,
+ 0x3b, 0x1a, 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x16, 0x3b, 0x15, 0x3c, 0x14,
+ 0x3d, 0x13, 0x3e, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11,
+ 0x3d, 0x10, 0x3e, 0x0f, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xa8, 0x00, 0x90,
+ 0x00, 0x7c, 0x00, 0x6b, 0x01, 0x5f, 0x04, 0x55, 0x05, 0x4c, 0x07, 0x45,
+ 0x0a, 0x40, 0x0c, 0x3c, 0x0f, 0x37, 0x10, 0x34, 0x12, 0x31, 0x15, 0x2e,
+ 0x16, 0x2b, 0x18, 0x2a, 0x19, 0x28, 0x1a, 0x26, 0x1d, 0x25, 0x1d, 0x23,
+ 0x23, 0x59, 0x23, 0x4d, 0x23, 0x43, 0x24, 0x3b, 0x24, 0x34, 0x25, 0x2f,
+ 0x26, 0x2b, 0x27, 0x28, 0x28, 0x25, 0x2a, 0x23, 0x2b, 0x21, 0x2c, 0x1f,
+ 0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x19, 0x31, 0x18,
+ 0x32, 0x17, 0x32, 0x16, 0x17, 0x00, 0x2f, 0x00, 0x4c, 0x00, 0x56, 0x00,
+ 0x59, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00,
+ 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00,
+ 0x14, 0x2c, 0x29, 0x01, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5b, 0x00,
+ 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00,
+ 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x62, 0x00,
+ 0x62, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00,
+ 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00,
+ 0x11, 0x31, 0x23, 0x03, 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00,
+ 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00,
+ 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x3e, 0x32, 0x3d, 0x2c,
+ 0x3c, 0x26, 0x3b, 0x23, 0x3b, 0x20, 0x3b, 0x1e, 0x3a, 0x1c, 0x3b, 0x1a,
+ 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x14,
+ 0x3d, 0x13, 0x3e, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaa, 0x00, 0x94, 0x00, 0x82, 0x00, 0x72,
+ 0x01, 0x65, 0x02, 0x5b, 0x04, 0x53, 0x06, 0x4b, 0x08, 0x45, 0x0a, 0x41,
+ 0x0c, 0x3d, 0x0e, 0x39, 0x0f, 0x36, 0x12, 0x33, 0x12, 0x30, 0x16, 0x2e,
+ 0x16, 0x2b, 0x18, 0x2b, 0x19, 0x29, 0x1a, 0x26, 0x23, 0x5a, 0x23, 0x4f,
+ 0x23, 0x46, 0x23, 0x3e, 0x24, 0x37, 0x25, 0x32, 0x25, 0x2e, 0x26, 0x2b,
+ 0x27, 0x28, 0x28, 0x25, 0x2a, 0x23, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x1e,
+ 0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x19, 0x30, 0x18,
+ 0x00, 0x00, 0x07, 0x00, 0x2f, 0x00, 0x45, 0x00, 0x4f, 0x00, 0x55, 0x00,
+ 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00,
+ 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x57, 0x04, 0x16,
+ 0x27, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x53, 0x00, 0x56, 0x00, 0x59, 0x00,
+ 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00,
+ 0x5d, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x3b, 0x00, 0x48, 0x00, 0x55, 0x00, 0x58, 0x00, 0x57, 0x00,
+ 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00,
+ 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x5f, 0x00, 0x20,
+ 0x1f, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00,
+ 0x59, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00,
+ 0x5d, 0x00, 0x5d, 0x00, 0x3e, 0x33, 0x3d, 0x2d, 0x3c, 0x28, 0x3b, 0x25,
+ 0x3a, 0x22, 0x3b, 0x1f, 0x3b, 0x1e, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19,
+ 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x16, 0x3b, 0x15, 0x3c, 0x15, 0x3c, 0x13,
+ 0x3d, 0x13, 0x3f, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0xaa, 0x00, 0x98, 0x00, 0x87, 0x00, 0x78, 0x00, 0x6b, 0x01, 0x61,
+ 0x03, 0x58, 0x05, 0x51, 0x07, 0x4b, 0x08, 0x46, 0x0a, 0x42, 0x0c, 0x3e,
+ 0x0d, 0x3a, 0x0f, 0x37, 0x11, 0x35, 0x12, 0x32, 0x14, 0x30, 0x16, 0x2e,
+ 0x16, 0x2b, 0x18, 0x2b, 0x23, 0x5a, 0x23, 0x51, 0x23, 0x48, 0x23, 0x41,
+ 0x24, 0x3a, 0x24, 0x35, 0x25, 0x31, 0x26, 0x2e, 0x27, 0x2a, 0x27, 0x28,
+ 0x28, 0x26, 0x2a, 0x24, 0x2a, 0x22, 0x2b, 0x21, 0x2c, 0x1f, 0x2d, 0x1e,
+ 0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x22, 0x00, 0x36, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x4f, 0x00,
+ 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
+ 0x5b, 0x00, 0x5b, 0x00, 0x00, 0x82, 0x00, 0x57, 0x01, 0x12, 0x17, 0x00,
+ 0x2f, 0x00, 0x3e, 0x00, 0x47, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x53, 0x00,
+ 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x48, 0x00,
+ 0x1b, 0x00, 0x34, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4f, 0x00,
+ 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
+ 0x5b, 0x00, 0x5b, 0x00, 0x00, 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x0d, 0x00,
+ 0x28, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00,
+ 0x54, 0x00, 0x56, 0x00, 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00,
+ 0x3e, 0x34, 0x3d, 0x2f, 0x3b, 0x2a, 0x3c, 0x26, 0x3a, 0x23, 0x3b, 0x21,
+ 0x3b, 0x1f, 0x3b, 0x1d, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x17,
+ 0x3c, 0x17, 0x3b, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x15, 0x3c, 0x13,
+ 0x3e, 0x13, 0x3f, 0x13, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xac, 0x00, 0x9b,
+ 0x00, 0x8b, 0x00, 0x7c, 0x00, 0x71, 0x01, 0x67, 0x02, 0x5e, 0x04, 0x57,
+ 0x05, 0x51, 0x07, 0x4b, 0x08, 0x46, 0x0a, 0x42, 0x0c, 0x3f, 0x0c, 0x3b,
+ 0x0f, 0x39, 0x0f, 0x35, 0x12, 0x34, 0x12, 0x31, 0x14, 0x30, 0x16, 0x2e,
+ 0x23, 0x5b, 0x23, 0x52, 0x23, 0x4a, 0x23, 0x43, 0x23, 0x3d, 0x24, 0x38,
+ 0x25, 0x34, 0x25, 0x30, 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26,
+ 0x2a, 0x24, 0x2a, 0x22, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x1f, 0x2d, 0x1d,
+ 0x2e, 0x1d, 0x2e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x19, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b, 0x00,
+ 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
+ 0x00, 0x91, 0x00, 0x78, 0x00, 0x43, 0x00, 0x10, 0x0e, 0x00, 0x23, 0x00,
+ 0x31, 0x00, 0x3b, 0x00, 0x42, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4f, 0x00,
+ 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x55, 0x00, 0x34, 0x00, 0x0b, 0x00,
+ 0x1f, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b, 0x00,
+ 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
+ 0x00, 0x92, 0x00, 0x7c, 0x00, 0x4d, 0x00, 0x1f, 0x02, 0x00, 0x1a, 0x00,
+ 0x2a, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00,
+ 0x4f, 0x00, 0x52, 0x00, 0x53, 0x00, 0x55, 0x00, 0x3e, 0x35, 0x3e, 0x30,
+ 0x3b, 0x2c, 0x3c, 0x28, 0x3b, 0x25, 0x3a, 0x22, 0x3b, 0x20, 0x3b, 0x1f,
+ 0x3a, 0x1d, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17,
+ 0x3c, 0x17, 0x3a, 0x16, 0x3b, 0x15, 0x3c, 0x15, 0x3c, 0x14, 0x3c, 0x13,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xad, 0x00, 0x9d, 0x00, 0x8e, 0x00, 0x81,
+ 0x00, 0x76, 0x00, 0x6b, 0x01, 0x63, 0x02, 0x5c, 0x04, 0x56, 0x05, 0x50,
+ 0x07, 0x4b, 0x08, 0x47, 0x0a, 0x43, 0x0c, 0x40, 0x0c, 0x3c, 0x0f, 0x3a,
+ 0x0f, 0x37, 0x11, 0x35, 0x12, 0x33, 0x12, 0x30, 0x23, 0x5b, 0x23, 0x53,
+ 0x23, 0x4c, 0x23, 0x45, 0x23, 0x40, 0x24, 0x3b, 0x24, 0x36, 0x25, 0x33,
+ 0x25, 0x30, 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26, 0x2a, 0x25,
+ 0x2a, 0x23, 0x2b, 0x22, 0x2b, 0x20, 0x2c, 0x20, 0x2d, 0x1e, 0x2d, 0x1d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
+ 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48, 0x00,
+ 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x96, 0x00, 0x87,
+ 0x00, 0x61, 0x00, 0x36, 0x00, 0x10, 0x0a, 0x02, 0x1a, 0x00, 0x27, 0x00,
+ 0x32, 0x00, 0x3a, 0x00, 0x40, 0x00, 0x44, 0x00, 0x48, 0x00, 0x4b, 0x00,
+ 0x4e, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x62, 0x00, 0x58, 0x00, 0x40, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x14, 0x00,
+ 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48, 0x00,
+ 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x97, 0x00, 0x8a,
+ 0x00, 0x68, 0x00, 0x42, 0x00, 0x1f, 0x00, 0x04, 0x10, 0x00, 0x1f, 0x00,
+ 0x2b, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00,
+ 0x4b, 0x00, 0x4e, 0x00, 0x3e, 0x36, 0x3e, 0x31, 0x3b, 0x2c, 0x3c, 0x29,
+ 0x3c, 0x26, 0x3a, 0x24, 0x3a, 0x21, 0x3b, 0x20, 0x3b, 0x1f, 0x39, 0x1d,
+ 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x17,
+ 0x3a, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x15, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0xad, 0x00, 0x9f, 0x00, 0x91, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6f,
+ 0x01, 0x67, 0x02, 0x60, 0x03, 0x59, 0x04, 0x54, 0x05, 0x4f, 0x07, 0x4b,
+ 0x08, 0x47, 0x0a, 0x43, 0x0b, 0x41, 0x0c, 0x3d, 0x0e, 0x3b, 0x0f, 0x38,
+ 0x0f, 0x35, 0x12, 0x35, 0x23, 0x5b, 0x23, 0x54, 0x23, 0x4e, 0x23, 0x47,
+ 0x23, 0x42, 0x24, 0x3c, 0x24, 0x38, 0x25, 0x35, 0x25, 0x32, 0x26, 0x2f,
+ 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26, 0x29, 0x25, 0x2a, 0x23,
+ 0x2b, 0x22, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e, 0x00,
+ 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46, 0x00,
+ 0x49, 0x00, 0x4c, 0x00, 0x00, 0x99, 0x00, 0x8f, 0x00, 0x74, 0x00, 0x51,
+ 0x00, 0x2e, 0x00, 0x10, 0x08, 0x04, 0x13, 0x00, 0x20, 0x00, 0x2a, 0x00,
+ 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x48, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x57, 0x00,
+ 0x44, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e, 0x00,
+ 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46, 0x00,
+ 0x49, 0x00, 0x4c, 0x00, 0x00, 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a,
+ 0x00, 0x3b, 0x00, 0x1f, 0x00, 0x09, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00,
+ 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00,
+ 0x3e, 0x36, 0x3e, 0x31, 0x3b, 0x2d, 0x3b, 0x2a, 0x3c, 0x27, 0x3a, 0x25,
+ 0x3a, 0x23, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1c, 0x3b, 0x1c,
+ 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x17,
+ 0x3a, 0x16, 0x3b, 0x15, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xad, 0x00, 0xa0,
+ 0x00, 0x94, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x74, 0x00, 0x6c, 0x01, 0x65,
+ 0x02, 0x5e, 0x04, 0x58, 0x05, 0x53, 0x05, 0x4f, 0x07, 0x4b, 0x08, 0x47,
+ 0x0a, 0x44, 0x0b, 0x41, 0x0c, 0x3e, 0x0d, 0x3b, 0x0f, 0x3a, 0x0f, 0x37,
+ 0x23, 0x5c, 0x23, 0x55, 0x23, 0x4f, 0x23, 0x49, 0x23, 0x44, 0x23, 0x3f,
+ 0x24, 0x3b, 0x24, 0x37, 0x25, 0x34, 0x25, 0x31, 0x26, 0x2e, 0x26, 0x2c,
+ 0x27, 0x2a, 0x28, 0x28, 0x28, 0x27, 0x29, 0x25, 0x2a, 0x24, 0x2a, 0x22,
+ 0x2b, 0x22, 0x2b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00,
+ 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44, 0x00,
+ 0x00, 0x9b, 0x00, 0x94, 0x00, 0x7f, 0x00, 0x64, 0x00, 0x46, 0x00, 0x29,
+ 0x00, 0x10, 0x07, 0x06, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00,
+ 0x32, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38, 0x00,
+ 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00,
+ 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44, 0x00,
+ 0x00, 0x9b, 0x00, 0x95, 0x00, 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36,
+ 0x00, 0x1f, 0x00, 0x0c, 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00,
+ 0x2c, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3c, 0x00, 0x3e, 0x37, 0x3e, 0x32,
+ 0x3c, 0x2f, 0x3b, 0x2b, 0x3c, 0x28, 0x3b, 0x26, 0x3a, 0x24, 0x3a, 0x22,
+ 0x3b, 0x21, 0x3b, 0x1f, 0x3a, 0x1e, 0x39, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a,
+ 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x17, 0x3a, 0x17,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x97, 0x00, 0x8b,
+ 0x00, 0x80, 0x00, 0x77, 0x00, 0x6f, 0x01, 0x67, 0x02, 0x61, 0x02, 0x5c,
+ 0x04, 0x57, 0x05, 0x52, 0x05, 0x4e, 0x07, 0x4b, 0x09, 0x47, 0x0a, 0x44,
+ 0x0b, 0x41, 0x0c, 0x3f, 0x0c, 0x3c, 0x0f, 0x3b, 0x23, 0x5c, 0x23, 0x56,
+ 0x23, 0x50, 0x23, 0x4a, 0x23, 0x45, 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39,
+ 0x25, 0x35, 0x25, 0x33, 0x25, 0x30, 0x26, 0x2e, 0x26, 0x2c, 0x27, 0x2a,
+ 0x28, 0x28, 0x28, 0x27, 0x29, 0x25, 0x2a, 0x24, 0x2a, 0x23, 0x2b, 0x22,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28, 0x00,
+ 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x9c, 0x00, 0x96,
+ 0x00, 0x87, 0x00, 0x71, 0x00, 0x57, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x10,
+ 0x06, 0x07, 0x0b, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x2d, 0x00,
+ 0x32, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28, 0x00,
+ 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x9c, 0x00, 0x97,
+ 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f,
+ 0x00, 0x0f, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00,
+ 0x2c, 0x00, 0x31, 0x00, 0x3e, 0x37, 0x3e, 0x33, 0x3c, 0x2f, 0x3b, 0x2c,
+ 0x3c, 0x29, 0x3c, 0x27, 0x39, 0x25, 0x3a, 0x23, 0x3b, 0x21, 0x3b, 0x20,
+ 0x3b, 0x1f, 0x3a, 0x1e, 0x39, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19,
+ 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17, 0x3b, 0x17, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x84, 0x00, 0x7a,
+ 0x00, 0x72, 0x00, 0x6c, 0x01, 0x65, 0x02, 0x5f, 0x04, 0x5a, 0x04, 0x56,
+ 0x05, 0x52, 0x06, 0x4e, 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x41,
+ 0x0c, 0x40, 0x0c, 0x3d, 0x23, 0x5c, 0x23, 0x56, 0x23, 0x51, 0x23, 0x4c,
+ 0x23, 0x47, 0x23, 0x42, 0x23, 0x3e, 0x24, 0x3b, 0x24, 0x37, 0x25, 0x34,
+ 0x25, 0x32, 0x25, 0x30, 0x26, 0x2e, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28,
+ 0x28, 0x27, 0x29, 0x25, 0x2a, 0x25, 0x2a, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a, 0x00,
+ 0x30, 0x00, 0x35, 0x00, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x7a,
+ 0x00, 0x64, 0x00, 0x4e, 0x00, 0x37, 0x00, 0x22, 0x00, 0x10, 0x05, 0x08,
+ 0x0a, 0x02, 0x12, 0x00, 0x1a, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00,
+ 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a, 0x00,
+ 0x30, 0x00, 0x35, 0x00, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e,
+ 0x00, 0x6b, 0x00, 0x57, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11,
+ 0x00, 0x04, 0x07, 0x00, 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00,
+ 0x3e, 0x38, 0x3e, 0x33, 0x3d, 0x30, 0x3b, 0x2d, 0x3c, 0x2a, 0x3c, 0x27,
+ 0x3a, 0x26, 0x3a, 0x24, 0x3a, 0x22, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f,
+ 0x39, 0x1e, 0x3a, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19,
+ 0x3c, 0x18, 0x3c, 0x17, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaf, 0x00, 0xa5,
+ 0x00, 0x99, 0x00, 0x90, 0x00, 0x87, 0x00, 0x7e, 0x00, 0x76, 0x00, 0x6f,
+ 0x01, 0x68, 0x02, 0x62, 0x02, 0x5e, 0x04, 0x59, 0x04, 0x55, 0x05, 0x51,
+ 0x07, 0x4e, 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x41, 0x0c, 0x41,
+ 0x23, 0x5c, 0x23, 0x57, 0x23, 0x52, 0x23, 0x4d, 0x23, 0x48, 0x23, 0x44,
+ 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39, 0x24, 0x36, 0x25, 0x34, 0x25, 0x31,
+ 0x26, 0x2f, 0x26, 0x2d, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x27,
+ 0x28, 0x25, 0x2a, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c, 0x00,
+ 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x90, 0x00, 0x81, 0x00, 0x6f, 0x00, 0x5b,
+ 0x00, 0x46, 0x00, 0x32, 0x00, 0x20, 0x00, 0x10, 0x04, 0x09, 0x09, 0x03,
+ 0x0f, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b, 0x00,
+ 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c, 0x00,
+ 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62,
+ 0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06,
+ 0x03, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x3e, 0x38, 0x3e, 0x34,
+ 0x3e, 0x31, 0x3b, 0x2e, 0x3b, 0x2b, 0x3c, 0x29, 0x3c, 0x27, 0x39, 0x25,
+ 0x3a, 0x24, 0x3a, 0x21, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1d,
+ 0x3a, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x19,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaf, 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x91,
+ 0x00, 0x88, 0x00, 0x80, 0x00, 0x78, 0x00, 0x71, 0x00, 0x6b, 0x01, 0x66,
+ 0x02, 0x61, 0x03, 0x5c, 0x04, 0x58, 0x05, 0x55, 0x05, 0x50, 0x07, 0x4e,
+ 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x42, 0x23, 0x5c, 0x23, 0x58,
+ 0x23, 0x53, 0x23, 0x4d, 0x23, 0x49, 0x23, 0x45, 0x23, 0x41, 0x24, 0x3d,
+ 0x24, 0x3b, 0x24, 0x38, 0x25, 0x35, 0x25, 0x33, 0x25, 0x31, 0x26, 0x2f,
+ 0x26, 0x2d, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x26,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x9d, 0x00, 0x9b,
+ 0x00, 0x93, 0x00, 0x86, 0x00, 0x76, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40,
+ 0x00, 0x2f, 0x00, 0x1e, 0x00, 0x10, 0x04, 0x09, 0x08, 0x04, 0x0c, 0x00,
+ 0x14, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38, 0x00,
+ 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x9e, 0x00, 0x9b,
+ 0x00, 0x94, 0x00, 0x89, 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b,
+ 0x00, 0x3b, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00,
+ 0x09, 0x00, 0x11, 0x00, 0x3e, 0x38, 0x3e, 0x35, 0x3e, 0x32, 0x3b, 0x2e,
+ 0x3b, 0x2c, 0x3c, 0x2a, 0x3c, 0x27, 0x3a, 0x26, 0x3a, 0x24, 0x3a, 0x23,
+ 0x3b, 0x21, 0x3b, 0x20, 0x3b, 0x1f, 0x3a, 0x1f, 0x39, 0x1d, 0x3a, 0x1c,
+ 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x83,
+ 0x00, 0x7c, 0x00, 0x75, 0x00, 0x6e, 0x01, 0x69, 0x01, 0x63, 0x02, 0x5f,
+ 0x04, 0x5b, 0x04, 0x56, 0x05, 0x54, 0x05, 0x4f, 0x07, 0x4e, 0x07, 0x4a,
+ 0x09, 0x47, 0x0a, 0x46, 0x23, 0x5d, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4f,
+ 0x23, 0x4a, 0x23, 0x46, 0x23, 0x43, 0x23, 0x3f, 0x24, 0x3c, 0x24, 0x39,
+ 0x24, 0x36, 0x25, 0x34, 0x25, 0x32, 0x25, 0x30, 0x26, 0x2f, 0x26, 0x2d,
+ 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
+ 0x16, 0x00, 0x1c, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x95, 0x00, 0x8a,
+ 0x00, 0x7d, 0x00, 0x6d, 0x00, 0x5d, 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x2c,
+ 0x00, 0x1d, 0x00, 0x10, 0x04, 0x0a, 0x07, 0x05, 0x0b, 0x00, 0x11, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
+ 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28, 0x00,
+ 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
+ 0x16, 0x00, 0x1c, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c,
+ 0x00, 0x80, 0x00, 0x73, 0x00, 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38,
+ 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00,
+ 0x3e, 0x39, 0x3e, 0x35, 0x3e, 0x32, 0x3b, 0x2f, 0x3b, 0x2d, 0x3c, 0x2a,
+ 0x3c, 0x28, 0x3b, 0x27, 0x39, 0x24, 0x3a, 0x24, 0x3a, 0x22, 0x3b, 0x21,
+ 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1f, 0x39, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c,
+ 0x3b, 0x1a, 0x3c, 0x19, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xb0, 0x00, 0xa7,
+ 0x00, 0x9e, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x86, 0x00, 0x7e, 0x00, 0x77,
+ 0x00, 0x71, 0x00, 0x6b, 0x01, 0x66, 0x02, 0x62, 0x02, 0x5d, 0x04, 0x5a,
+ 0x04, 0x55, 0x05, 0x53, 0x05, 0x4f, 0x07, 0x4e, 0x07, 0x4a, 0x09, 0x47,
+ 0x23, 0x5d, 0x23, 0x58, 0x23, 0x54, 0x23, 0x50, 0x23, 0x4c, 0x23, 0x48,
+ 0x23, 0x44, 0x23, 0x40, 0x24, 0x3d, 0x24, 0x3a, 0x24, 0x38, 0x25, 0x36,
+ 0x25, 0x33, 0x25, 0x32, 0x25, 0x2f, 0x26, 0x2f, 0x26, 0x2c, 0x27, 0x2c,
+ 0x27, 0x2a, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14, 0x00,
+ 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x81, 0x00, 0x74,
+ 0x00, 0x65, 0x00, 0x56, 0x00, 0x46, 0x00, 0x37, 0x00, 0x29, 0x00, 0x1c,
+ 0x00, 0x10, 0x03, 0x0a, 0x07, 0x06, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00,
+ 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a, 0x00,
+ 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14, 0x00,
+ 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79,
+ 0x00, 0x6b, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a,
+ 0x00, 0x1f, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x03, 0x32, 0x59, 0x2a, 0x5b,
+ 0x28, 0x5c, 0x27, 0x5d, 0x27, 0x5d, 0x26, 0x5e, 0x26, 0x5e, 0x26, 0x5e,
+ 0x26, 0x5e, 0x26, 0x5e, 0x25, 0x5e, 0x25, 0x5e, 0x25, 0x5f, 0x25, 0x5f,
+ 0x25, 0x5f, 0x25, 0x5f, 0x25, 0x5f, 0x24, 0x5f, 0x24, 0x5f, 0x24, 0x60,
+ 0x32, 0x3c, 0x25, 0x4a, 0x24, 0x50, 0x23, 0x54, 0x23, 0x56, 0x23, 0x58,
+ 0x23, 0x59, 0x23, 0x5a, 0x23, 0x5a, 0x23, 0x5b, 0x23, 0x5b, 0x23, 0x5b,
+ 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5d,
+ 0x23, 0x5d, 0x23, 0x5d, 0x00, 0x6c, 0x0e, 0x60, 0x14, 0x60, 0x18, 0x60,
+ 0x1b, 0x60, 0x1d, 0x60, 0x1d, 0x60, 0x1e, 0x60, 0x1f, 0x60, 0x20, 0x60,
+ 0x20, 0x60, 0x20, 0x60, 0x21, 0x60, 0x21, 0x60, 0x21, 0x60, 0x21, 0x60,
+ 0x22, 0x60, 0x22, 0x60, 0x22, 0x60, 0x22, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x9e, 0x00, 0x9c,
+ 0x00, 0x97, 0x00, 0x90, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x5e,
+ 0x00, 0x50, 0x00, 0x42, 0x00, 0x34, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x0f,
+ 0x03, 0x0b, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46, 0x00,
+ 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x9e, 0x00, 0x9d,
+ 0x00, 0x98, 0x00, 0x91, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65,
+ 0x00, 0x59, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f,
+ 0x00, 0x16, 0x00, 0x0d, 0x38, 0x4f, 0x31, 0x53, 0x2e, 0x56, 0x2c, 0x57,
+ 0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5a, 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x38, 0x22, 0x2b, 0x31,
+ 0x27, 0x3b, 0x25, 0x42, 0x24, 0x47, 0x23, 0x4a, 0x23, 0x4d, 0x23, 0x4f,
+ 0x23, 0x51, 0x23, 0x52, 0x23, 0x53, 0x23, 0x54, 0x23, 0x55, 0x23, 0x56,
+ 0x23, 0x56, 0x23, 0x57, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58,
+ 0x00, 0x92, 0x01, 0x79, 0x07, 0x6f, 0x0c, 0x6b, 0x0f, 0x68, 0x12, 0x67,
+ 0x14, 0x66, 0x16, 0x65, 0x17, 0x64, 0x18, 0x64, 0x19, 0x63, 0x1a, 0x63,
+ 0x1b, 0x63, 0x1b, 0x63, 0x1c, 0x63, 0x1c, 0x62, 0x1d, 0x62, 0x1d, 0x62,
+ 0x1d, 0x62, 0x1e, 0x62, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x92,
+ 0x00, 0x89, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x58, 0x00, 0x4b,
+ 0x00, 0x3e, 0x00, 0x31, 0x00, 0x25, 0x00, 0x1a, 0x00, 0x0f, 0x03, 0x0b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00,
+ 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39, 0x00,
+ 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93,
+ 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54,
+ 0x00, 0x49, 0x00, 0x3d, 0x00, 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17,
+ 0x3a, 0x4b, 0x34, 0x4f, 0x31, 0x52, 0x2f, 0x54, 0x2d, 0x56, 0x2c, 0x57,
+ 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5a,
+ 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x3c, 0x18, 0x30, 0x25, 0x2a, 0x2e, 0x27, 0x35,
+ 0x25, 0x3b, 0x24, 0x3f, 0x24, 0x43, 0x24, 0x46, 0x23, 0x48, 0x23, 0x4a,
+ 0x23, 0x4c, 0x23, 0x4e, 0x23, 0x4f, 0x23, 0x50, 0x23, 0x51, 0x23, 0x52,
+ 0x23, 0x53, 0x23, 0x53, 0x23, 0x54, 0x23, 0x54, 0x00, 0xa1, 0x00, 0x88,
+ 0x03, 0x7b, 0x06, 0x74, 0x09, 0x70, 0x0c, 0x6d, 0x0e, 0x6b, 0x10, 0x6a,
+ 0x11, 0x69, 0x13, 0x68, 0x14, 0x67, 0x15, 0x66, 0x16, 0x66, 0x17, 0x65,
+ 0x17, 0x65, 0x18, 0x65, 0x19, 0x65, 0x19, 0x64, 0x1a, 0x64, 0x1a, 0x64,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82,
+ 0x00, 0x77, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x53, 0x00, 0x46, 0x00, 0x3a,
+ 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57, 0x00,
+ 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c, 0x00,
+ 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85,
+ 0x00, 0x7b, 0x00, 0x71, 0x00, 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46,
+ 0x00, 0x3b, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1f, 0x3b, 0x48, 0x36, 0x4c,
+ 0x33, 0x4f, 0x31, 0x52, 0x2f, 0x53, 0x2e, 0x53, 0x2d, 0x55, 0x2c, 0x57,
+ 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58,
+ 0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5b, 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c,
+ 0x3f, 0x14, 0x33, 0x1e, 0x2d, 0x26, 0x29, 0x2d, 0x27, 0x32, 0x26, 0x36,
+ 0x25, 0x3b, 0x24, 0x3e, 0x24, 0x41, 0x24, 0x43, 0x23, 0x45, 0x23, 0x47,
+ 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4d, 0x23, 0x4d, 0x23, 0x4f,
+ 0x23, 0x50, 0x23, 0x50, 0x00, 0xa7, 0x00, 0x92, 0x01, 0x84, 0x03, 0x7d,
+ 0x05, 0x77, 0x08, 0x73, 0x0a, 0x71, 0x0c, 0x6f, 0x0d, 0x6d, 0x0f, 0x6b,
+ 0x10, 0x6a, 0x11, 0x6a, 0x12, 0x69, 0x13, 0x68, 0x14, 0x68, 0x15, 0x67,
+ 0x15, 0x66, 0x16, 0x66, 0x17, 0x66, 0x17, 0x66, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x31, 0x23, 0x03,
+ 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d, 0x00,
+ 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00,
+ 0x5e, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x31, 0x00, 0x5f, 0x00, 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a,
+ 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e,
+ 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x38, 0x4b, 0x35, 0x4e, 0x32, 0x4f,
+ 0x31, 0x51, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55, 0x2c, 0x56,
+ 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
+ 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x2a, 0x59, 0x40, 0x11, 0x36, 0x1a,
+ 0x2f, 0x21, 0x2c, 0x27, 0x29, 0x2c, 0x27, 0x30, 0x26, 0x34, 0x25, 0x37,
+ 0x25, 0x3a, 0x24, 0x3d, 0x24, 0x40, 0x24, 0x42, 0x24, 0x44, 0x23, 0x45,
+ 0x23, 0x47, 0x23, 0x48, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4c,
+ 0x00, 0xaa, 0x00, 0x98, 0x00, 0x8c, 0x02, 0x83, 0x03, 0x7d, 0x05, 0x79,
+ 0x07, 0x76, 0x09, 0x73, 0x0a, 0x71, 0x0c, 0x6f, 0x0d, 0x6e, 0x0e, 0x6d,
+ 0x0f, 0x6c, 0x10, 0x6b, 0x11, 0x6a, 0x12, 0x6a, 0x13, 0x69, 0x13, 0x68,
+ 0x14, 0x68, 0x15, 0x68, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x20, 0x1f, 0x00, 0x3c, 0x00,
+ 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00,
+ 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x00, 0x20,
+ 0x00, 0x5f, 0x00, 0x7c, 0x00, 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97,
+ 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d,
+ 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x46, 0x39, 0x4a, 0x36, 0x4b, 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x50,
+ 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2d, 0x56,
+ 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
+ 0x2a, 0x57, 0x2a, 0x57, 0x41, 0x10, 0x38, 0x17, 0x32, 0x1d, 0x2e, 0x22,
+ 0x2b, 0x27, 0x29, 0x2b, 0x27, 0x2f, 0x26, 0x32, 0x25, 0x35, 0x25, 0x38,
+ 0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3f, 0x24, 0x40, 0x24, 0x42, 0x23, 0x44,
+ 0x23, 0x45, 0x23, 0x46, 0x23, 0x48, 0x23, 0x48, 0x00, 0xac, 0x00, 0x9d,
+ 0x00, 0x91, 0x01, 0x89, 0x02, 0x82, 0x03, 0x7e, 0x05, 0x7a, 0x07, 0x77,
+ 0x08, 0x75, 0x09, 0x73, 0x0b, 0x71, 0x0c, 0x70, 0x0d, 0x6e, 0x0e, 0x6e,
+ 0x0e, 0x6c, 0x0f, 0x6c, 0x10, 0x6b, 0x10, 0x6a, 0x11, 0x6a, 0x12, 0x6a,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x0d, 0x00, 0x28, 0x00, 0x39, 0x00,
+ 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56, 0x00,
+ 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x1f, 0x00, 0x00, 0x1f, 0x00, 0x4d,
+ 0x00, 0x68, 0x00, 0x79, 0x00, 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92,
+ 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x39, 0x48,
+ 0x37, 0x4a, 0x35, 0x4c, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2d, 0x56,
+ 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
+ 0x42, 0x0f, 0x39, 0x15, 0x33, 0x1a, 0x2f, 0x1f, 0x2d, 0x24, 0x2a, 0x27,
+ 0x29, 0x2b, 0x27, 0x2e, 0x26, 0x31, 0x26, 0x34, 0x25, 0x36, 0x25, 0x38,
+ 0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3e, 0x24, 0x40, 0x24, 0x41, 0x24, 0x43,
+ 0x23, 0x44, 0x23, 0x45, 0x00, 0xae, 0x00, 0xa1, 0x00, 0x96, 0x00, 0x8d,
+ 0x01, 0x87, 0x02, 0x82, 0x03, 0x7e, 0x05, 0x7b, 0x06, 0x78, 0x07, 0x76,
+ 0x09, 0x74, 0x0a, 0x73, 0x0b, 0x71, 0x0c, 0x70, 0x0c, 0x6f, 0x0d, 0x6e,
+ 0x0e, 0x6d, 0x0f, 0x6c, 0x10, 0x6c, 0x10, 0x6b, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x7c,
+ 0x00, 0x4d, 0x00, 0x1f, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36, 0x00,
+ 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52, 0x00,
+ 0x53, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x52, 0x00, 0x3c, 0x00, 0x0d, 0x00, 0x00, 0x1f, 0x00, 0x42, 0x00, 0x5a,
+ 0x00, 0x6a, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c,
+ 0x00, 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x3a, 0x47, 0x38, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x52, 0x2f, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x55,
+ 0x2c, 0x57, 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x43, 0x0e, 0x3b, 0x13,
+ 0x35, 0x18, 0x31, 0x1c, 0x2e, 0x21, 0x2c, 0x24, 0x2a, 0x28, 0x28, 0x2b,
+ 0x27, 0x2e, 0x27, 0x30, 0x26, 0x33, 0x25, 0x35, 0x25, 0x37, 0x25, 0x39,
+ 0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x24, 0x40, 0x24, 0x42,
+ 0x00, 0xaf, 0x00, 0xa3, 0x00, 0x99, 0x00, 0x91, 0x00, 0x8b, 0x02, 0x86,
+ 0x02, 0x81, 0x03, 0x7e, 0x05, 0x7b, 0x06, 0x79, 0x07, 0x77, 0x08, 0x75,
+ 0x09, 0x74, 0x0a, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x0c, 0x6f, 0x0d, 0x6e,
+ 0x0e, 0x6e, 0x0e, 0x6d, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42,
+ 0x00, 0x1f, 0x00, 0x04, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34, 0x00,
+ 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x4a, 0x00,
+ 0x28, 0x00, 0x02, 0x00, 0x00, 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f,
+ 0x00, 0x6b, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88,
+ 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x44, 0x3b, 0x46, 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4b, 0x34, 0x4e,
+ 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55,
+ 0x2c, 0x56, 0x2b, 0x57, 0x44, 0x0e, 0x3c, 0x12, 0x36, 0x16, 0x33, 0x1a,
+ 0x30, 0x1e, 0x2d, 0x22, 0x2b, 0x25, 0x2a, 0x28, 0x28, 0x2a, 0x27, 0x2d,
+ 0x27, 0x30, 0x26, 0x32, 0x26, 0x34, 0x25, 0x35, 0x25, 0x37, 0x25, 0x39,
+ 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x00, 0xb0, 0x00, 0xa5,
+ 0x00, 0x9d, 0x00, 0x95, 0x00, 0x8e, 0x01, 0x89, 0x02, 0x85, 0x03, 0x81,
+ 0x04, 0x7e, 0x05, 0x7c, 0x06, 0x7a, 0x07, 0x78, 0x07, 0x76, 0x09, 0x75,
+ 0x09, 0x73, 0x0b, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x0c, 0x70, 0x0d, 0x6e,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f,
+ 0x00, 0x09, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33, 0x00,
+ 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x00,
+ 0x00, 0x04, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62,
+ 0x00, 0x6b, 0x00, 0x73, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3b, 0x46,
+ 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x34, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55,
+ 0x44, 0x0d, 0x3d, 0x11, 0x38, 0x15, 0x34, 0x19, 0x31, 0x1c, 0x2e, 0x20,
+ 0x2d, 0x23, 0x2b, 0x25, 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2d, 0x27, 0x2f,
+ 0x26, 0x31, 0x26, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x38, 0x25, 0x39,
+ 0x24, 0x3a, 0x24, 0x3c, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9f, 0x00, 0x98,
+ 0x00, 0x91, 0x00, 0x8c, 0x01, 0x88, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7e,
+ 0x05, 0x7c, 0x06, 0x7a, 0x06, 0x79, 0x07, 0x77, 0x08, 0x76, 0x09, 0x74,
+ 0x0a, 0x73, 0x0b, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x95,
+ 0x00, 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c,
+ 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00,
+ 0x37, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x55, 0x00, 0x43, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x09,
+ 0x00, 0x1f, 0x00, 0x33, 0x00, 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64,
+ 0x00, 0x6b, 0x00, 0x72, 0x00, 0x77, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x44, 0x0d, 0x3e, 0x10,
+ 0x39, 0x14, 0x35, 0x17, 0x32, 0x1b, 0x30, 0x1e, 0x2e, 0x21, 0x2c, 0x23,
+ 0x2b, 0x26, 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2d, 0x27, 0x2e, 0x26, 0x30,
+ 0x26, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x36, 0x25, 0x38, 0x25, 0x39,
+ 0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa1, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x8f,
+ 0x01, 0x8b, 0x02, 0x87, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d,
+ 0x06, 0x7b, 0x06, 0x79, 0x07, 0x78, 0x07, 0x76, 0x09, 0x76, 0x09, 0x74,
+ 0x0a, 0x73, 0x0b, 0x72, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76,
+ 0x00, 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
+ 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00,
+ 0x4a, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x00, 0x1f,
+ 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65,
+ 0x00, 0x6c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x42, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4b, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x52, 0x2f, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x44, 0x0c, 0x3f, 0x10, 0x3a, 0x13, 0x36, 0x16,
+ 0x33, 0x19, 0x30, 0x1c, 0x2e, 0x1f, 0x2d, 0x21, 0x2b, 0x24, 0x2a, 0x26,
+ 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2e, 0x26, 0x30, 0x26, 0x31,
+ 0x26, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x37, 0x00, 0xb2, 0x00, 0xaa,
+ 0x00, 0xa2, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x91, 0x00, 0x8d, 0x01, 0x89,
+ 0x02, 0x86, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x06, 0x7b,
+ 0x06, 0x79, 0x07, 0x79, 0x07, 0x77, 0x08, 0x76, 0x09, 0x75, 0x09, 0x74,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57,
+ 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x04, 0x07, 0x00,
+ 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00,
+ 0x2b, 0x00, 0x17, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2e,
+ 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x46,
+ 0x39, 0x46, 0x39, 0x47, 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b,
+ 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x45, 0x0c, 0x3f, 0x0f, 0x3a, 0x12, 0x37, 0x15, 0x34, 0x18, 0x32, 0x1b,
+ 0x30, 0x1d, 0x2e, 0x20, 0x2d, 0x22, 0x2b, 0x24, 0x2a, 0x26, 0x2a, 0x28,
+ 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2e, 0x27, 0x2f, 0x26, 0x31, 0x26, 0x32,
+ 0x25, 0x33, 0x25, 0x35, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9e,
+ 0x00, 0x98, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8b, 0x01, 0x88, 0x02, 0x85,
+ 0x02, 0x83, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7a,
+ 0x07, 0x79, 0x07, 0x78, 0x07, 0x76, 0x09, 0x76, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a,
+ 0x00, 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f,
+ 0x00, 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06, 0x03, 0x00, 0x0c, 0x00,
+ 0x14, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5b, 0x00, 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38,
+ 0x00, 0x43, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x45, 0x3a, 0x46, 0x39, 0x46,
+ 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x33, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x51,
+ 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x45, 0x0c, 0x40, 0x0f,
+ 0x3b, 0x11, 0x38, 0x14, 0x35, 0x17, 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1e,
+ 0x2d, 0x21, 0x2c, 0x22, 0x2b, 0x25, 0x2a, 0x26, 0x29, 0x28, 0x28, 0x2a,
+ 0x28, 0x2c, 0x27, 0x2d, 0x27, 0x2f, 0x26, 0x30, 0x26, 0x32, 0x25, 0x33,
+ 0x00, 0xb2, 0x00, 0xac, 0x00, 0xa5, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96,
+ 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8a, 0x02, 0x88, 0x02, 0x85, 0x02, 0x83,
+ 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7a, 0x06, 0x79,
+ 0x07, 0x78, 0x07, 0x77, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89,
+ 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d,
+ 0x00, 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00,
+ 0x54, 0x00, 0x49, 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x00,
+ 0x00, 0x04, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40,
+ 0x00, 0x49, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x42, 0x3d, 0x44, 0x3a, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x38, 0x13,
+ 0x36, 0x16, 0x33, 0x18, 0x31, 0x1b, 0x30, 0x1d, 0x2e, 0x1f, 0x2d, 0x21,
+ 0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c,
+ 0x27, 0x2d, 0x27, 0x2f, 0x26, 0x2f, 0x26, 0x31, 0x00, 0xb3, 0x00, 0xac,
+ 0x00, 0xa7, 0x00, 0xa1, 0x00, 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f,
+ 0x01, 0x8c, 0x01, 0x89, 0x02, 0x87, 0x02, 0x85, 0x02, 0x82, 0x03, 0x81,
+ 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7b, 0x06, 0x79, 0x07, 0x79,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73,
+ 0x00, 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f,
+ 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00,
+ 0x41, 0x00, 0x33, 0x00, 0x24, 0x00, 0x15, 0x00, 0x07, 0x00, 0x00, 0x06,
+ 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x44,
+ 0x3b, 0x46, 0x39, 0x46, 0x39, 0x47, 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4b, 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52, 0x2f, 0x53,
+ 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x39, 0x13, 0x37, 0x15, 0x34, 0x18,
+ 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1e, 0x2d, 0x20, 0x2d, 0x22, 0x2b, 0x23,
+ 0x2b, 0x25, 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2d,
+ 0x27, 0x2f, 0x26, 0x2f, 0x00, 0xb3, 0x00, 0xad, 0x00, 0xa7, 0x00, 0xa3,
+ 0x00, 0x9d, 0x00, 0x99, 0x00, 0x95, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8b,
+ 0x02, 0x88, 0x02, 0x86, 0x02, 0x84, 0x03, 0x82, 0x03, 0x81, 0x04, 0x7f,
+ 0x05, 0x7e, 0x05, 0x7c, 0x06, 0x7b, 0x06, 0x7a, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c,
+ 0x00, 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e,
+ 0x00, 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15,
+ 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5d, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00,
+ 0x2c, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x14,
+ 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x33, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46,
+ 0x39, 0x46, 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4c, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x52, 0x45, 0x0b, 0x41, 0x0e,
+ 0x3d, 0x10, 0x3a, 0x12, 0x37, 0x14, 0x34, 0x17, 0x32, 0x19, 0x31, 0x1b,
+ 0x30, 0x1d, 0x2e, 0x1f, 0x2d, 0x20, 0x2c, 0x22, 0x2b, 0x24, 0x2a, 0x25,
+ 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2c, 0x27, 0x2e,
+ 0x00, 0xb3, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a,
+ 0x00, 0x96, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8d, 0x01, 0x8a, 0x02, 0x88,
+ 0x02, 0x86, 0x02, 0x84, 0x03, 0x82, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7e,
+ 0x05, 0x7c, 0x06, 0x7c, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91,
+ 0x00, 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c,
+ 0x00, 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
+ 0x59, 0x00, 0x52, 0x00, 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00,
+ 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f,
+ 0x00, 0x29, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x42, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x47,
+ 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d,
+ 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x45, 0x0b, 0x41, 0x0e, 0x3e, 0x10, 0x3a, 0x11,
+ 0x38, 0x14, 0x35, 0x16, 0x33, 0x18, 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1d,
+ 0x2e, 0x20, 0x2d, 0x21, 0x2b, 0x22, 0x2b, 0x24, 0x2a, 0x25, 0x2a, 0x27,
+ 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2c, 0x00, 0xb3, 0x00, 0xae,
+ 0x00, 0xa9, 0x00, 0xa4, 0x00, 0xa0, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x94,
+ 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c, 0x01, 0x89, 0x02, 0x87, 0x02, 0x86,
+ 0x02, 0x84, 0x03, 0x82, 0x03, 0x80, 0x04, 0x7f, 0x05, 0x7e, 0x05, 0x7c,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82,
+ 0x00, 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d,
+ 0x00, 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00,
+ 0x4b, 0x00, 0x42, 0x00, 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00,
+ 0x09, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x42,
+ 0x3d, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x4a, 0x36, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b, 0x34, 0x4e, 0x32, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x46, 0x0b, 0x42, 0x0d, 0x3e, 0x10, 0x3b, 0x11, 0x38, 0x13, 0x36, 0x16,
+ 0x34, 0x17, 0x32, 0x19, 0x30, 0x1b, 0x30, 0x1d, 0x2e, 0x1e, 0x2d, 0x20,
+ 0x2d, 0x22, 0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x25, 0x2a, 0x28, 0x28, 0x28,
+ 0x28, 0x2a, 0x28, 0x2c, 0x00, 0xb3, 0x00, 0xae, 0x00, 0xaa, 0x00, 0xa5,
+ 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x96, 0x00, 0x93, 0x00, 0x90,
+ 0x00, 0x8d, 0x01, 0x8b, 0x02, 0x89, 0x02, 0x87, 0x02, 0x85, 0x02, 0x83,
+ 0x03, 0x82, 0x03, 0x80, 0x04, 0x7f, 0x05, 0x7e, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d,
+ 0x00, 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71,
+ 0x00, 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31,
+ 0x00, 0x28, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00,
+ 0x3c, 0x00, 0x31, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x00,
+ 0x00, 0x03, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x45, 0x3a, 0x46,
+ 0x39, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x34, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x46, 0x0b, 0x42, 0x0d,
+ 0x3e, 0x0f, 0x3c, 0x11, 0x39, 0x13, 0x37, 0x15, 0x34, 0x16, 0x33, 0x18,
+ 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1d, 0x2e, 0x20, 0x2d, 0x20, 0x2c, 0x22,
+ 0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x26, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x2a,
+ 0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9e,
+ 0x00, 0x9a, 0x00, 0x97, 0x00, 0x94, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c,
+ 0x01, 0x8a, 0x02, 0x88, 0x02, 0x86, 0x02, 0x85, 0x02, 0x83, 0x03, 0x82,
+ 0x03, 0x80, 0x04, 0x7f, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xb2, 0x00, 0x6f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0xa2, 0x00,
+ 0x4f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x7f, 0x00, 0x3c, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c,
+ 0x00, 0x16, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xd6, 0x00, 0xc6, 0x00, 0x9c, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12,
+ 0x00, 0x0c, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd, 0x00,
+ 0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00,
+ 0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e,
+ 0x00, 0x1b, 0x00, 0x17, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00,
+ 0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19,
+ 0x00, 0x15, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00,
+ 0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12,
+ 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00,
+ 0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d,
+ 0x00, 0x09, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00,
+ 0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b,
+ 0x00, 0x19, 0x00, 0x16, 0x00, 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08,
+ 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00,
+ 0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00,
+ 0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17,
+ 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00,
+ 0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00,
+ 0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13,
+ 0x00, 0x10, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00,
+ 0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d,
+ 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e,
+ 0x00, 0x0c, 0x00, 0x09, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
+ 0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00,
+ 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1c,
+ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x24,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4c, 0x04, 0x11, 0x09, 0x01, 0x11, 0x00, 0x17,
+ 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x61, 0x01, 0x23, 0x03, 0x03, 0x09, 0x00, 0x13, 0x00, 0x18, 0x00, 0x1a,
+ 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e,
+ 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x1c,
+ 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x21,
+ 0x00, 0x27, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x21, 0x00, 0x1d, 0x00, 0x1e,
+ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x87, 0x00, 0x39, 0x01, 0x0f, 0x07, 0x02, 0x0c, 0x00, 0x12, 0x00, 0x17,
+ 0x00, 0x19, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d,
+ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x9f, 0x00, 0x5f, 0x00,
+ 0x1f, 0x00, 0x04, 0x01, 0x00, 0x0a, 0x00, 0x11, 0x00, 0x15, 0x00, 0x18,
+ 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d,
+ 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a,
+ 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e,
+ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x34, 0x00, 0x27, 0x00, 0x0f, 0x00, 0x1a,
+ 0x00, 0x1c, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c,
+ 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x87, 0x00,
+ 0x32, 0x00, 0x19, 0x05, 0x0b, 0x09, 0x03, 0x0b, 0x00, 0x0e, 0x00, 0x12,
+ 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1b,
+ 0x00, 0x1c, 0x00, 0x1c, 0xc5, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x32, 0x00,
+ 0x16, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x12,
+ 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19,
+ 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d,
+ 0x00, 0x32, 0x00, 0x2b, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x0e,
+ 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b,
+ 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xcd, 0x00, 0xaf, 0x00, 0x6e, 0x00, 0x31, 0x00,
+ 0x1e, 0x04, 0x12, 0x07, 0x0a, 0x09, 0x04, 0x0a, 0x00, 0x0b, 0x00, 0x0f,
+ 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19,
+ 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x25, 0x00,
+ 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d,
+ 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
+ 0x00, 0x0c, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18,
+ 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x2c, 0x00, 0x28,
+ 0x00, 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f,
+ 0x00, 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a,
+ 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xd4, 0x00, 0xc1, 0x00, 0x93, 0x00, 0x5f, 0x00, 0x30, 0x00, 0x22, 0x03,
+ 0x17, 0x06, 0x0f, 0x07, 0x0a, 0x09, 0x05, 0x0a, 0x02, 0x0b, 0x00, 0x0c,
+ 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x15, 0xd7, 0x00, 0xc9, 0x00,
+ 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44, 0x00, 0x2f, 0x00, 0x1f, 0x00,
+ 0x14, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x09,
+ 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a,
+ 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17,
+ 0x00, 0x18, 0x00, 0x19, 0x00, 0x24, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0e,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10,
+ 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0xcb, 0x00,
+ 0xaa, 0x00, 0x7f, 0x00, 0x55, 0x00, 0x30, 0x00, 0x24, 0x02, 0x1b, 0x05,
+ 0x14, 0x06, 0x0e, 0x08, 0x09, 0x09, 0x06, 0x0a, 0x03, 0x0b, 0x00, 0x0b,
+ 0x00, 0x0d, 0x00, 0x0f, 0xda, 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x99, 0x00,
+ 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36, 0x00, 0x28, 0x00, 0x1c, 0x00,
+ 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c,
+ 0x00, 0x0e, 0x00, 0x11, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16,
+ 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11,
+ 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xb8, 0x00, 0x96, 0x00,
+ 0x71, 0x00, 0x4e, 0x00, 0x30, 0x00, 0x26, 0x02, 0x1e, 0x04, 0x17, 0x06,
+ 0x12, 0x07, 0x0d, 0x08, 0x09, 0x09, 0x06, 0x0a, 0x04, 0x0a, 0x01, 0x0b,
+ 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa, 0x00, 0x8f, 0x00, 0x76, 0x00,
+ 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x1b, 0x00,
+ 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d,
+ 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x1e,
+ 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11,
+ 0x00, 0x13, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdb, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0xa6, 0x00, 0x87, 0x00, 0x67, 0x00,
+ 0x4a, 0x00, 0x30, 0x00, 0x27, 0x02, 0x20, 0x03, 0x1a, 0x05, 0x14, 0x06,
+ 0x10, 0x07, 0x0c, 0x08, 0x09, 0x09, 0x07, 0x0a, 0xdc, 0x00, 0xd7, 0x00,
+ 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88, 0x00, 0x72, 0x00, 0x5f, 0x00,
+ 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00,
+ 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e,
+ 0x00, 0x10, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17,
+ 0x00, 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00,
+ 0xc8, 0x00, 0xb2, 0x00, 0x97, 0x00, 0x7b, 0x00, 0x60, 0x00, 0x46, 0x00,
+ 0x30, 0x00, 0x28, 0x01, 0x21, 0x03, 0x1c, 0x04, 0x17, 0x06, 0x13, 0x07,
+ 0x0f, 0x08, 0x0c, 0x08, 0xdd, 0x00, 0xd9, 0x00, 0xce, 0x00, 0xbe, 0x00,
+ 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x50, 0x00,
+ 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e,
+ 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10,
+ 0x00, 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06,
+ 0x00, 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xba, 0x00,
+ 0xa4, 0x00, 0x8b, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x44, 0x00, 0x2f, 0x00,
+ 0x29, 0x01, 0x23, 0x03, 0x1e, 0x04, 0x19, 0x05, 0x15, 0x06, 0x11, 0x07,
+ 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4, 0x00, 0xb4, 0x00, 0xa2, 0x00,
+ 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x52, 0x00, 0x46, 0x00,
+ 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x05, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x1e,
+ 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a,
+ 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08,
+ 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xd9, 0x00, 0xd0, 0x00, 0xc0, 0x00, 0xad, 0x00, 0x98, 0x00,
+ 0x81, 0x00, 0x6b, 0x00, 0x56, 0x00, 0x42, 0x00, 0x2f, 0x00, 0x29, 0x01,
+ 0x24, 0x02, 0x1f, 0x04, 0x1b, 0x05, 0x17, 0x06, 0xdd, 0x00, 0xdb, 0x00,
+ 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab, 0x00, 0x9b, 0x00, 0x8a, 0x00,
+ 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3f, 0x00,
+ 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
+ 0x00, 0x07, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b,
+ 0x00, 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00,
+ 0xd2, 0x00, 0xc5, 0x00, 0xb5, 0x00, 0xa2, 0x00, 0x8e, 0x00, 0x79, 0x00,
+ 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x2a, 0x01, 0x25, 0x02,
+ 0x20, 0x03, 0x1c, 0x04, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00,
+ 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95, 0x00, 0x86, 0x00, 0x78, 0x00,
+ 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a, 0x00, 0x41, 0x00, 0x39, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16,
+ 0x00, 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00,
+ 0xbb, 0x00, 0xaa, 0x00, 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x60, 0x00,
+ 0x4f, 0x00, 0x3e, 0x00, 0x2f, 0x00, 0x2a, 0x01, 0x26, 0x02, 0x21, 0x03,
+ 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf, 0x00, 0xc4, 0x00, 0xb8, 0x00,
+ 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83, 0x00, 0x76, 0x00, 0x6a, 0x00,
+ 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11,
+ 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb1, 0x00,
+ 0xa0, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c, 0x00,
+ 0x3d, 0x00, 0x2f, 0x00, 0x2b, 0x01, 0x26, 0x02, 0xde, 0x00, 0xdc, 0x00,
+ 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd, 0x00, 0xb1, 0x00, 0xa5, 0x00,
+ 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5f, 0x00,
+ 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c,
+ 0x00, 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d,
+ 0x00, 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
+ 0xd7, 0x00, 0xce, 0x00, 0xc3, 0x00, 0xb6, 0x00, 0xa8, 0x00, 0x98, 0x00,
+ 0x88, 0x00, 0x78, 0x00, 0x68, 0x00, 0x59, 0x00, 0x4a, 0x00, 0x3c, 0x00,
+ 0x2f, 0x00, 0x2b, 0x01, 0xde, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd3, 0x00,
+ 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab, 0x00, 0xa0, 0x00, 0x94, 0x00,
+ 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19,
+ 0x00, 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09,
+ 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd0, 0x00,
+ 0xc7, 0x00, 0xbb, 0x00, 0xae, 0x00, 0xa0, 0x00, 0x91, 0x00, 0x82, 0x00,
+ 0x73, 0x00, 0x64, 0x00, 0x56, 0x00, 0x48, 0x00, 0x3b, 0x00, 0x2f, 0x00,
+ 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4, 0x00, 0xcd, 0x00, 0xc5, 0x00,
+ 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x90, 0x00, 0x85, 0x00,
+ 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x6f, 0x00,
+ 0xb2, 0x00, 0xc8, 0x00, 0xd2, 0x00, 0xd6, 0x00, 0xd9, 0x00, 0xda, 0x00,
+ 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xde, 0x00, 0x4c, 0x04, 0x87, 0x00, 0xbc, 0x00, 0xcd, 0x00,
+ 0xd4, 0x00, 0xd8, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x76, 0x00,
+ 0x9b, 0x00, 0xac, 0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xda, 0x00,
+ 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xde, 0x00, 0x61, 0x01, 0x9f, 0x00, 0xc5, 0x00, 0xd2, 0x00,
+ 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x6f, 0x00, 0xa2, 0x00,
+ 0xb9, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00,
+ 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00,
+ 0x11, 0x09, 0x39, 0x01, 0x87, 0x00, 0xaf, 0x00, 0xc1, 0x00, 0xcb, 0x00,
+ 0xd1, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00,
+ 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x5b, 0x00, 0x75, 0x00, 0x96, 0x00,
+ 0xab, 0x00, 0xc0, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00,
+ 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00,
+ 0x23, 0x03, 0x5f, 0x00, 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0, 0x00,
+ 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00,
+ 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x9c, 0x00,
+ 0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00,
+ 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x01, 0x11, 0x0f, 0x07,
+ 0x32, 0x00, 0x6e, 0x00, 0x93, 0x00, 0xaa, 0x00, 0xb8, 0x00, 0xc1, 0x00,
+ 0xc8, 0x00, 0xcc, 0x00, 0xd0, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd6, 0x00,
+ 0xd7, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x00, 0x75, 0x00, 0x2b, 0x00, 0x5b, 0x00, 0x7f, 0x00, 0x9b, 0x00,
+ 0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00,
+ 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x03, 0x09, 0x1f, 0x00,
+ 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9, 0x00,
+ 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00,
+ 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00,
+ 0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00,
+ 0xca, 0x00, 0xcd, 0x00, 0x00, 0x17, 0x02, 0x0c, 0x19, 0x05, 0x31, 0x00,
+ 0x5f, 0x00, 0x7f, 0x00, 0x96, 0x00, 0xa6, 0x00, 0xb2, 0x00, 0xba, 0x00,
+ 0xc0, 0x00, 0xc5, 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xd0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x96, 0x00,
+ 0x5b, 0x00, 0x13, 0x00, 0x41, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00,
+ 0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00,
+ 0xca, 0x00, 0xcd, 0x00, 0x00, 0x13, 0x04, 0x01, 0x32, 0x00, 0x5f, 0x00,
+ 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4, 0x00,
+ 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00,
+ 0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00,
+ 0x00, 0x1b, 0x00, 0x12, 0x0b, 0x09, 0x1e, 0x04, 0x30, 0x00, 0x55, 0x00,
+ 0x71, 0x00, 0x87, 0x00, 0x97, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb5, 0x00,
+ 0xbb, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xab, 0x00, 0x7f, 0x00, 0x41, 0x00,
+ 0x03, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00,
+ 0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00,
+ 0x00, 0x18, 0x00, 0x0a, 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a, 0x00,
+ 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0, 0x00,
+ 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00,
+ 0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x1c, 0x00, 0x17,
+ 0x03, 0x0b, 0x12, 0x07, 0x22, 0x03, 0x30, 0x00, 0x4e, 0x00, 0x67, 0x00,
+ 0x7b, 0x00, 0x8b, 0x00, 0x98, 0x00, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00,
+ 0xb6, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x00, 0xc0, 0x00, 0x9b, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x02, 0x00,
+ 0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00,
+ 0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x1a, 0x00, 0x11,
+ 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88, 0x00,
+ 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00,
+ 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00,
+ 0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00,
+ 0x99, 0x00, 0xa0, 0x00, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x0e, 0x0a, 0x09,
+ 0x17, 0x06, 0x24, 0x02, 0x30, 0x00, 0x4a, 0x00, 0x60, 0x00, 0x72, 0x00,
+ 0x81, 0x00, 0x8e, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa8, 0x00, 0xae, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd, 0x00,
+ 0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x01, 0x00, 0x21, 0x00,
+ 0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00,
+ 0x99, 0x00, 0xa0, 0x00, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x14, 0x00,
+ 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90, 0x00,
+ 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x36, 0x00,
+ 0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00,
+ 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x04, 0x0a, 0x0f, 0x07, 0x1b, 0x05,
+ 0x26, 0x02, 0x30, 0x00, 0x46, 0x00, 0x5a, 0x00, 0x6b, 0x00, 0x79, 0x00,
+ 0x85, 0x00, 0x8f, 0x00, 0x98, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00,
+ 0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x36, 0x00,
+ 0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00,
+ 0x00, 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x09, 0x00, 0x1f, 0x00, 0x36, 0x00,
+ 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95, 0x00,
+ 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00,
+ 0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x1e, 0x00, 0x1c,
+ 0x00, 0x15, 0x00, 0x0b, 0x0a, 0x09, 0x14, 0x06, 0x1e, 0x04, 0x27, 0x02,
+ 0x30, 0x00, 0x44, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x7e, 0x00,
+ 0x88, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00,
+ 0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00,
+ 0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x1d, 0x00, 0x1a,
+ 0x00, 0x0f, 0x00, 0x00, 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e, 0x00,
+ 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98, 0x00,
+ 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00,
+ 0x5c, 0x00, 0x68, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x0f,
+ 0x05, 0x0a, 0x0e, 0x08, 0x17, 0x06, 0x20, 0x03, 0x28, 0x01, 0x2f, 0x00,
+ 0x42, 0x00, 0x52, 0x00, 0x60, 0x00, 0x6d, 0x00, 0x78, 0x00, 0x82, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00,
+ 0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00,
+ 0x5c, 0x00, 0x68, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05,
+ 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f, 0x00,
+ 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00,
+ 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x02, 0x0b, 0x09, 0x09,
+ 0x12, 0x07, 0x1a, 0x05, 0x21, 0x03, 0x29, 0x01, 0x2f, 0x00, 0x40, 0x00,
+ 0x4f, 0x00, 0x5c, 0x00, 0x68, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00,
+ 0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00,
+ 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00,
+ 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x04, 0x00, 0x13, 0x00,
+ 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b, 0x00,
+ 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x1f, 0x00, 0x1d,
+ 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x06, 0x0a, 0x0d, 0x08, 0x14, 0x06,
+ 0x1c, 0x04, 0x23, 0x03, 0x29, 0x01, 0x2f, 0x00, 0x3e, 0x00, 0x4c, 0x00,
+ 0x59, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00,
+ 0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x1e, 0x00, 0x1c,
+ 0x00, 0x16, 0x00, 0x0d, 0x00, 0x01, 0x0c, 0x00, 0x1b, 0x00, 0x29, 0x00,
+ 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74, 0x00,
+ 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x16,
+ 0x00, 0x0f, 0x03, 0x0b, 0x09, 0x09, 0x10, 0x07, 0x17, 0x06, 0x1e, 0x04,
+ 0x24, 0x02, 0x2a, 0x01, 0x2f, 0x00, 0x3d, 0x00, 0x4a, 0x00, 0x56, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00,
+ 0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00,
+ 0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x11, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10,
+ 0x00, 0x05, 0x06, 0x00, 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c, 0x00,
+ 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00, 0x11, 0x00, 0x0b,
+ 0x06, 0x0a, 0x0c, 0x08, 0x13, 0x07, 0x19, 0x05, 0x1f, 0x04, 0x25, 0x02,
+ 0x2a, 0x01, 0x2f, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00,
+ 0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00,
+ 0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x01, 0x00,
+ 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a, 0x00,
+ 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x1f, 0x00, 0x1e,
+ 0x00, 0x1c, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x04, 0x0a, 0x09, 0x09,
+ 0x0f, 0x08, 0x15, 0x06, 0x1b, 0x05, 0x20, 0x03, 0x26, 0x02, 0x2b, 0x01,
+ 0x2f, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00,
+ 0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x1f, 0x00, 0x1d,
+ 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x08, 0x00, 0x13, 0x00,
+ 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56, 0x00,
+ 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19,
+ 0x00, 0x15, 0x00, 0x0f, 0x01, 0x0b, 0x07, 0x0a, 0x0c, 0x08, 0x11, 0x07,
+ 0x17, 0x06, 0x1c, 0x04, 0x21, 0x03, 0x26, 0x02, 0x2b, 0x01, 0x2f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
+ 0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00,
+ 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15,
+ 0x00, 0x0e, 0x00, 0x05, 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23, 0x00,
+ 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x01, 0x9f, 0x00, 0xc5, 0x00, 0xd2, 0x00, 0xd7, 0x00, 0xda, 0x00,
+ 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00,
+ 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x61, 0x01, 0x23, 0x03, 0x03, 0x09, 0x00, 0x13,
+ 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e,
+ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x5f, 0x00,
+ 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xd7, 0x00,
+ 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x00, 0x04, 0x01, 0x00, 0x0a, 0x00, 0x11,
+ 0x00, 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c,
+ 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x09, 0x1f, 0x00, 0x5f, 0x00, 0x8d, 0x00,
+ 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9, 0x00, 0xce, 0x00, 0xd1, 0x00,
+ 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x9f, 0x00,
+ 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0a,
+ 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19,
+ 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x13, 0x04, 0x01, 0x32, 0x00, 0x5f, 0x00, 0x81, 0x00, 0x99, 0x00,
+ 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4, 0x00, 0xc9, 0x00, 0xcc, 0x00,
+ 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f, 0x00,
+ 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0a,
+ 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9f, 0x00,
+ 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc4, 0x00, 0xc8, 0x00,
+ 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44, 0x00,
+ 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x01,
+ 0x00, 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x11, 0x06, 0x00, 0x25, 0x00,
+ 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88, 0x00, 0x96, 0x00, 0xa2, 0x00,
+ 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc1, 0x00, 0xc5, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd0, 0x00,
+ 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36, 0x00,
+ 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01, 0x00,
+ 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x14, 0x00, 0x2f, 0x00, 0x49, 0x00,
+ 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90, 0x00, 0x9b, 0x00, 0xa4, 0x00,
+ 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa, 0x00,
+ 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f, 0x00,
+ 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x18,
+ 0x00, 0x0a, 0x09, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x4c, 0x00, 0x5f, 0x00,
+ 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95, 0x00, 0x9e, 0x00, 0xa5, 0x00,
+ 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88, 0x00,
+ 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00,
+ 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x00,
+ 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x6e, 0x00,
+ 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa6, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xd9, 0x00,
+ 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70, 0x00,
+ 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26, 0x00,
+ 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05, 0x0b, 0x00, 0x1c, 0x00,
+ 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x78, 0x00,
+ 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4, 0x00,
+ 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f, 0x00,
+ 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c,
+ 0x00, 0x14, 0x00, 0x09, 0x04, 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00,
+ 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x76, 0x00, 0x80, 0x00,
+ 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab, 0x00,
+ 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53, 0x00,
+ 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0d,
+ 0x00, 0x01, 0x0c, 0x00, 0x1b, 0x00, 0x29, 0x00, 0x38, 0x00, 0x46, 0x00,
+ 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74, 0x00, 0x7d, 0x00, 0x85, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
+ 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95, 0x00,
+ 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a, 0x00,
+ 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10, 0x00, 0x05, 0x06, 0x00,
+ 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x54, 0x00,
+ 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf, 0x00,
+ 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83, 0x00,
+ 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d,
+ 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x01, 0x00, 0x0d, 0x00, 0x19, 0x00,
+ 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00,
+ 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd, 0x00,
+ 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74, 0x00,
+ 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14,
+ 0x00, 0x0c, 0x00, 0x02, 0x08, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00,
+ 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x68, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00,
+ 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab, 0x00,
+ 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69, 0x00,
+ 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x05,
+ 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23, 0x00, 0x2e, 0x00, 0x39, 0x00,
+ 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4, 0x00,
+ 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b, 0x00,
+ 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xb2, 0x00, 0x6f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0xa2,
+ 0x00, 0x4f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x7f, 0x00, 0x3c,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1a, 0x00,
+ 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd6, 0x00, 0xc6, 0x00, 0x9c, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0e, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd,
+ 0x00, 0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97,
+ 0x00, 0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60,
+ 0x00, 0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00,
+ 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7,
+ 0x00, 0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36,
+ 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10, 0x00,
+ 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8,
+ 0x00, 0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a, 0x00,
+ 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91,
+ 0x00, 0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00,
+ 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda,
+ 0x00, 0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d,
+ 0x00, 0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00,
+ 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7,
+ 0x00, 0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e,
+ 0x00, 0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11, 0x00,
+ 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab,
+ 0x00, 0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34,
+ 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00,
+ 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00,
+ 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc,
+ 0x00, 0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e,
+ 0x00, 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00,
+ 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09, 0x00,
+ 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x6f,
+ 0x00, 0xb2, 0x00, 0xc8, 0x00, 0xd2, 0x00, 0xd6, 0x00, 0xd9, 0x00, 0xda,
+ 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xde, 0x00, 0xa6, 0x00, 0x76, 0x00, 0x9b, 0x00, 0xac,
+ 0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc,
+ 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x4c, 0x00, 0x87,
+ 0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd4, 0x00, 0xd8, 0x00, 0xda, 0x00, 0xdb,
+ 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde,
+ 0x00, 0xde, 0x00, 0xde, 0x01, 0x61, 0x00, 0x9f, 0x00, 0xc5, 0x00, 0xd2,
+ 0x00, 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x6f, 0x00, 0xa2,
+ 0x00, 0xb9, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7,
+ 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc,
+ 0x00, 0x76, 0x00, 0x5b, 0x00, 0x75, 0x00, 0x96, 0x00, 0xab, 0x00, 0xc0,
+ 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9,
+ 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x11, 0x01, 0x39, 0x00, 0x87, 0x00, 0xaf,
+ 0x00, 0xc1, 0x00, 0xcb, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8,
+ 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc,
+ 0x03, 0x23, 0x00, 0x5f, 0x00, 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0,
+ 0x00, 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc,
+ 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x9c,
+ 0x00, 0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf,
+ 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x9b, 0x00, 0x75,
+ 0x00, 0x2b, 0x00, 0x5b, 0x00, 0x7f, 0x00, 0x9b, 0x00, 0xae, 0x00, 0xb9,
+ 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3,
+ 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x01, 0x07, 0x0f, 0x00, 0x32, 0x00, 0x6e, 0x00, 0x93, 0x00, 0xaa,
+ 0x00, 0xb8, 0x00, 0xc1, 0x00, 0xc8, 0x00, 0xcc, 0x00, 0xd0, 0x00, 0xd2,
+ 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x09, 0x03, 0x00, 0x1f,
+ 0x00, 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9,
+ 0x00, 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8,
+ 0x00, 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97,
+ 0x00, 0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7,
+ 0x00, 0xca, 0x00, 0xcd, 0x00, 0xac, 0x00, 0x96, 0x00, 0x5b, 0x00, 0x13,
+ 0x00, 0x41, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00, 0xa5, 0x00, 0xb0,
+ 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00, 0xca, 0x00, 0xcd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x0c, 0x02,
+ 0x05, 0x19, 0x00, 0x31, 0x00, 0x5f, 0x00, 0x7f, 0x00, 0x96, 0x00, 0xa6,
+ 0x00, 0xb2, 0x00, 0xba, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc9, 0x00, 0xcc,
+ 0x00, 0xce, 0x00, 0xd0, 0x13, 0x00, 0x01, 0x04, 0x00, 0x32, 0x00, 0x5f,
+ 0x00, 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4,
+ 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93,
+ 0x00, 0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0,
+ 0x00, 0xbc, 0x00, 0xab, 0x00, 0x7f, 0x00, 0x41, 0x00, 0x03, 0x00, 0x2f,
+ 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00, 0xa0, 0x00, 0xa9,
+ 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x09, 0x0b, 0x04, 0x1e,
+ 0x00, 0x30, 0x00, 0x55, 0x00, 0x71, 0x00, 0x87, 0x00, 0x97, 0x00, 0xa4,
+ 0x00, 0xad, 0x00, 0xb5, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc7,
+ 0x18, 0x00, 0x0a, 0x00, 0x00, 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a,
+ 0x00, 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0,
+ 0x00, 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91,
+ 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xcd, 0x00, 0xc0,
+ 0x00, 0x9b, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x02, 0x00, 0x27, 0x00, 0x47,
+ 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00, 0x9c, 0x00, 0xa4,
+ 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x17, 0x00, 0x0b, 0x03, 0x07, 0x12, 0x03, 0x22, 0x00, 0x30,
+ 0x00, 0x4e, 0x00, 0x67, 0x00, 0x7b, 0x00, 0x8b, 0x00, 0x98, 0x00, 0xa2,
+ 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6, 0x00, 0xbb, 0x1a, 0x00, 0x11, 0x00,
+ 0x00, 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88,
+ 0x00, 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd,
+ 0x00, 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21,
+ 0x00, 0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90,
+ 0x00, 0x99, 0x00, 0xa0, 0x00, 0xd9, 0x00, 0xcd, 0x00, 0xae, 0x00, 0x82,
+ 0x00, 0x54, 0x00, 0x27, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x55,
+ 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00, 0x99, 0x00, 0xa0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x19, 0x00,
+ 0x0e, 0x00, 0x09, 0x0a, 0x06, 0x17, 0x02, 0x24, 0x00, 0x30, 0x00, 0x4a,
+ 0x00, 0x60, 0x00, 0x72, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x98, 0x00, 0xa0,
+ 0x00, 0xa8, 0x00, 0xae, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x00, 0x00, 0x14,
+ 0x00, 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90,
+ 0x00, 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x36,
+ 0x00, 0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e,
+ 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00, 0x6f, 0x00, 0x47,
+ 0x00, 0x21, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x36, 0x00, 0x4b, 0x00, 0x5d,
+ 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x0a, 0x04,
+ 0x07, 0x0f, 0x05, 0x1b, 0x02, 0x26, 0x00, 0x30, 0x00, 0x46, 0x00, 0x5a,
+ 0x00, 0x6b, 0x00, 0x79, 0x00, 0x85, 0x00, 0x8f, 0x00, 0x98, 0x00, 0xa0,
+ 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x36,
+ 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95,
+ 0x00, 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44,
+ 0x00, 0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0xdb, 0x00, 0xd4,
+ 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00, 0x3d, 0x00, 0x1d,
+ 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00, 0x55, 0x00, 0x64,
+ 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x0b, 0x00, 0x09, 0x0a, 0x06, 0x14,
+ 0x04, 0x1e, 0x02, 0x27, 0x00, 0x30, 0x00, 0x44, 0x00, 0x56, 0x00, 0x65,
+ 0x00, 0x72, 0x00, 0x7e, 0x00, 0x88, 0x00, 0x91, 0x1d, 0x00, 0x1a, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e,
+ 0x00, 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98,
+ 0x00, 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e,
+ 0x00, 0x5c, 0x00, 0x68, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc7, 0x00, 0xb0,
+ 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00, 0x19, 0x00, 0x00,
+ 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00, 0x5c, 0x00, 0x68,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00,
+ 0x17, 0x00, 0x0f, 0x00, 0x0a, 0x05, 0x08, 0x0e, 0x06, 0x17, 0x03, 0x20,
+ 0x01, 0x28, 0x00, 0x2f, 0x00, 0x42, 0x00, 0x52, 0x00, 0x60, 0x00, 0x6d,
+ 0x00, 0x78, 0x00, 0x82, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05, 0x00,
+ 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f,
+ 0x00, 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55,
+ 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00, 0xa0, 0x00, 0x84,
+ 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00, 0x00, 0x00, 0x15,
+ 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00,
+ 0x0b, 0x02, 0x09, 0x09, 0x07, 0x12, 0x05, 0x1a, 0x03, 0x21, 0x01, 0x29,
+ 0x00, 0x2f, 0x00, 0x40, 0x00, 0x4f, 0x00, 0x5c, 0x00, 0x68, 0x00, 0x73,
+ 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x04, 0x00, 0x13,
+ 0x00, 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b,
+ 0x00, 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0xdd, 0x00, 0xd9,
+ 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00, 0x78, 0x00, 0x5d,
+ 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x24,
+ 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x0a, 0x06,
+ 0x08, 0x0d, 0x06, 0x14, 0x04, 0x1c, 0x03, 0x23, 0x01, 0x29, 0x00, 0x2f,
+ 0x00, 0x3e, 0x00, 0x4c, 0x00, 0x59, 0x00, 0x64, 0x1e, 0x00, 0x1c, 0x00,
+ 0x16, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x29,
+ 0x00, 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74,
+ 0x00, 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x22, 0x00, 0x30, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc3,
+ 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00, 0x55, 0x00, 0x3e,
+ 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x30,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1b, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x09, 0x09, 0x07, 0x10,
+ 0x06, 0x17, 0x04, 0x1e, 0x02, 0x24, 0x01, 0x2a, 0x00, 0x2f, 0x00, 0x3d,
+ 0x00, 0x4a, 0x00, 0x56, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10, 0x00,
+ 0x05, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c,
+ 0x00, 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00, 0xb7, 0x00, 0xa4,
+ 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00, 0x39, 0x00, 0x24,
+ 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00,
+ 0x11, 0x00, 0x0b, 0x00, 0x0a, 0x06, 0x08, 0x0c, 0x07, 0x13, 0x05, 0x19,
+ 0x04, 0x1f, 0x02, 0x25, 0x01, 0x2a, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x48,
+ 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x01,
+ 0x00, 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a,
+ 0x00, 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xdd, 0x00, 0xdb,
+ 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00, 0x99, 0x00, 0x85,
+ 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00,
+ 0x0a, 0x04, 0x09, 0x09, 0x08, 0x0f, 0x06, 0x15, 0x05, 0x1b, 0x03, 0x20,
+ 0x02, 0x26, 0x01, 0x2b, 0x00, 0x2f, 0x00, 0x3b, 0x1f, 0x00, 0x1d, 0x00,
+ 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x08, 0x00, 0x13,
+ 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56,
+ 0x00, 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcd,
+ 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00, 0x7b, 0x00, 0x68,
+ 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0b, 0x01, 0x0a, 0x07,
+ 0x08, 0x0c, 0x07, 0x11, 0x06, 0x17, 0x04, 0x1c, 0x03, 0x21, 0x02, 0x26,
+ 0x01, 0x2b, 0x00, 0x2f, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00,
+ 0x0e, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23,
+ 0x00, 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x1e, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x04, 0x4c, 0x09, 0x11,
+ 0x11, 0x01, 0x17, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00,
+ 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x24, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x01, 0x61, 0x03, 0x23,
+ 0x09, 0x03, 0x13, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00,
+ 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x0f, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00,
+ 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x87, 0x01, 0x39, 0x07, 0x0f, 0x0c, 0x02,
+ 0x12, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00,
+ 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x21, 0x00,
+ 0x27, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x21, 0x00, 0x1d, 0x00, 0x1e, 0x00,
+ 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x01, 0x04,
+ 0x0a, 0x00, 0x11, 0x00, 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00,
+ 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00,
+ 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00,
+ 0x00, 0xbc, 0x00, 0x87, 0x00, 0x32, 0x05, 0x19, 0x09, 0x0b, 0x0b, 0x03,
+ 0x0e, 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00,
+ 0x1b, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x27, 0x00, 0x0f, 0x00, 0x1a, 0x00,
+ 0x1c, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00,
+ 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00,
+ 0x00, 0xc5, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06,
+ 0x03, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00,
+ 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x00,
+ 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00,
+ 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0xcd, 0x00, 0xaf,
+ 0x00, 0x6e, 0x00, 0x31, 0x04, 0x1e, 0x07, 0x12, 0x09, 0x0a, 0x0a, 0x04,
+ 0x0b, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00,
+ 0x18, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0x00, 0x2b, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x0e, 0x00,
+ 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00,
+ 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0xd2, 0x00, 0xbc,
+ 0x00, 0x8d, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09,
+ 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00,
+ 0x14, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f, 0x00,
+ 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00,
+ 0x1a, 0x00, 0x1b, 0x00, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0x93, 0x00, 0x5f,
+ 0x00, 0x30, 0x03, 0x22, 0x06, 0x17, 0x07, 0x0f, 0x09, 0x0a, 0x0a, 0x05,
+ 0x0b, 0x02, 0x0c, 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x15, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x28, 0x00,
+ 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f, 0x00,
+ 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00,
+ 0x1a, 0x00, 0x1b, 0x00, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81,
+ 0x00, 0x5f, 0x00, 0x44, 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b,
+ 0x00, 0x04, 0x01, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00,
+ 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00,
+ 0x00, 0xd8, 0x00, 0xcb, 0x00, 0xaa, 0x00, 0x7f, 0x00, 0x55, 0x00, 0x30,
+ 0x02, 0x24, 0x05, 0x1b, 0x06, 0x14, 0x08, 0x0e, 0x09, 0x09, 0x0a, 0x06,
+ 0x0b, 0x03, 0x0b, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0e, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00,
+ 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00,
+ 0x00, 0xda, 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f,
+ 0x00, 0x49, 0x00, 0x36, 0x00, 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c,
+ 0x00, 0x06, 0x00, 0x01, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11, 0x00,
+ 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0xda, 0x00, 0xd1,
+ 0x00, 0xb8, 0x00, 0x96, 0x00, 0x71, 0x00, 0x4e, 0x00, 0x30, 0x02, 0x26,
+ 0x04, 0x1e, 0x06, 0x17, 0x07, 0x12, 0x08, 0x0d, 0x09, 0x09, 0x0a, 0x06,
+ 0x0a, 0x04, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11, 0x00,
+ 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0xdb, 0x00, 0xd5,
+ 0x00, 0xc3, 0x00, 0xaa, 0x00, 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c,
+ 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d,
+ 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11, 0x00,
+ 0x13, 0x00, 0x14, 0x00, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0xa6,
+ 0x00, 0x87, 0x00, 0x67, 0x00, 0x4a, 0x00, 0x30, 0x02, 0x27, 0x03, 0x20,
+ 0x05, 0x1a, 0x06, 0x14, 0x07, 0x10, 0x08, 0x0c, 0x09, 0x09, 0x0a, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11, 0x00,
+ 0x13, 0x00, 0x14, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6,
+ 0x00, 0x9f, 0x00, 0x88, 0x00, 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40,
+ 0x00, 0x34, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11, 0x00,
+ 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc8, 0x00, 0xb2, 0x00, 0x97, 0x00, 0x7b,
+ 0x00, 0x60, 0x00, 0x46, 0x00, 0x30, 0x01, 0x28, 0x03, 0x21, 0x04, 0x1c,
+ 0x06, 0x17, 0x07, 0x13, 0x08, 0x0f, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00,
+ 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11, 0x00,
+ 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96,
+ 0x00, 0x82, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38,
+ 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00,
+ 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0xdc, 0x00, 0xd8,
+ 0x00, 0xcc, 0x00, 0xba, 0x00, 0xa4, 0x00, 0x8b, 0x00, 0x72, 0x00, 0x5a,
+ 0x00, 0x44, 0x00, 0x2f, 0x01, 0x29, 0x03, 0x23, 0x04, 0x1e, 0x05, 0x19,
+ 0x06, 0x15, 0x07, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10, 0x00,
+ 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00,
+ 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0xdd, 0x00, 0xda,
+ 0x00, 0xd1, 0x00, 0xc4, 0x00, 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e,
+ 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32,
+ 0x00, 0x2a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08, 0x00,
+ 0x0a, 0x00, 0x0c, 0x00, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd0, 0x00, 0xc0,
+ 0x00, 0xad, 0x00, 0x98, 0x00, 0x81, 0x00, 0x6b, 0x00, 0x56, 0x00, 0x42,
+ 0x00, 0x2f, 0x01, 0x29, 0x02, 0x24, 0x04, 0x1f, 0x05, 0x1b, 0x06, 0x17,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a, 0x00,
+ 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08, 0x00,
+ 0x0a, 0x00, 0x0c, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9,
+ 0x00, 0xbb, 0x00, 0xab, 0x00, 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c,
+ 0x00, 0x5f, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00,
+ 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xc5, 0x00, 0xb5, 0x00, 0xa2,
+ 0x00, 0x8e, 0x00, 0x79, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f,
+ 0x01, 0x2a, 0x02, 0x25, 0x03, 0x20, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00,
+ 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00,
+ 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2,
+ 0x00, 0xa4, 0x00, 0x95, 0x00, 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f,
+ 0x00, 0x54, 0x00, 0x4a, 0x00, 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0xdd, 0x00, 0xdb,
+ 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xaa, 0x00, 0x98, 0x00, 0x85,
+ 0x00, 0x72, 0x00, 0x60, 0x00, 0x4f, 0x00, 0x3e, 0x00, 0x2f, 0x01, 0x2a,
+ 0x02, 0x26, 0x03, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00,
+ 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0xde, 0x00, 0xdc,
+ 0x00, 0xd7, 0x00, 0xcf, 0x00, 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e,
+ 0x00, 0x90, 0x00, 0x83, 0x00, 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55,
+ 0x00, 0x4c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x04, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc,
+ 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d,
+ 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x3d, 0x00, 0x2f, 0x01, 0x2b, 0x02, 0x26,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11, 0x00,
+ 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x04, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1,
+ 0x00, 0xc8, 0x00, 0xbd, 0x00, 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c,
+ 0x00, 0x80, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xce, 0x00, 0xc3, 0x00, 0xb6,
+ 0x00, 0xa8, 0x00, 0x98, 0x00, 0x88, 0x00, 0x78, 0x00, 0x68, 0x00, 0x59,
+ 0x00, 0x4a, 0x00, 0x3c, 0x00, 0x2f, 0x01, 0x2b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00,
+ 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00,
+ 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0xde, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1,
+ 0x00, 0xb7, 0x00, 0xab, 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d,
+ 0x00, 0x73, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc,
+ 0x00, 0xd8, 0x00, 0xd0, 0x00, 0xc7, 0x00, 0xbb, 0x00, 0xae, 0x00, 0xa0,
+ 0x00, 0x91, 0x00, 0x82, 0x00, 0x73, 0x00, 0x64, 0x00, 0x56, 0x00, 0x48,
+ 0x00, 0x3b, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00,
+ 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09, 0x00,
+ 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd,
+ 0x00, 0xda, 0x00, 0xd4, 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1,
+ 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71,
+ 0x00, 0x68, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x61, 0x03, 0x23, 0x09, 0x03, 0x13, 0x00,
+ 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00,
+ 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x9f,
+ 0x00, 0xc5, 0x00, 0xd2, 0x00, 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde,
+ 0x00, 0xde, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x01, 0x04, 0x0a, 0x00, 0x11, 0x00,
+ 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00,
+ 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, 0x5f, 0x00, 0x9f, 0x00, 0xbc,
+ 0x00, 0xc9, 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda,
+ 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x9f,
+ 0x00, 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06, 0x03, 0x00, 0x0a, 0x00,
+ 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00,
+ 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x03, 0x00, 0x1f, 0x00, 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8,
+ 0x00, 0xc3, 0x00, 0xc9, 0x00, 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6,
+ 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f,
+ 0x00, 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x05, 0x00,
+ 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x04,
+ 0x00, 0x32, 0x00, 0x5f, 0x00, 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6,
+ 0x00, 0xbe, 0x00, 0xc4, 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1,
+ 0x00, 0xd3, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44,
+ 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x04, 0x01, 0x00,
+ 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x16, 0x00, 0x3d,
+ 0x00, 0x5f, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4,
+ 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd0,
+ 0x00, 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36,
+ 0x00, 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01,
+ 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x11, 0x00, 0x00, 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f,
+ 0x00, 0x76, 0x00, 0x88, 0x00, 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2,
+ 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa,
+ 0x00, 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f,
+ 0x00, 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x15, 0x00,
+ 0x03, 0x00, 0x00, 0x14, 0x00, 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72,
+ 0x00, 0x82, 0x00, 0x90, 0x00, 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1,
+ 0x00, 0xb7, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88,
+ 0x00, 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29,
+ 0x00, 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x09,
+ 0x00, 0x1f, 0x00, 0x36, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e,
+ 0x00, 0x8a, 0x00, 0x95, 0x00, 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xd9,
+ 0x00, 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70,
+ 0x00, 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26,
+ 0x00, 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1d, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x28,
+ 0x00, 0x3c, 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86,
+ 0x00, 0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4,
+ 0x00, 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f,
+ 0x00, 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00,
+ 0x12, 0x00, 0x05, 0x00, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40,
+ 0x00, 0x50, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c,
+ 0x00, 0x94, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab,
+ 0x00, 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53,
+ 0x00, 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x00,
+ 0x00, 0x04, 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52,
+ 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc,
+ 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95,
+ 0x00, 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a,
+ 0x00, 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x0c,
+ 0x00, 0x1b, 0x00, 0x29, 0x00, 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f,
+ 0x00, 0x6a, 0x00, 0x74, 0x00, 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf,
+ 0x00, 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83,
+ 0x00, 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1d, 0x00,
+ 0x18, 0x00, 0x10, 0x00, 0x05, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x21,
+ 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69,
+ 0x00, 0x73, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd,
+ 0x00, 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74,
+ 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00,
+ 0x09, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32,
+ 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd,
+ 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab,
+ 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69,
+ 0x00, 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x00,
+ 0x00, 0x08, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41,
+ 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4,
+ 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b,
+ 0x00, 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1a, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x0e,
+ 0x00, 0x18, 0x00, 0x23, 0x00, 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d,
+ 0x00, 0x56, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+/* clang-format on */
+
+#define SEARCHTEX_WIDTH 64
+#define SEARCHTEX_HEIGHT 16
+#define SEARCHTEX_PITCH SEARCHTEX_WIDTH
+#define SEARCHTEX_SIZE (SEARCHTEX_HEIGHT * SEARCHTEX_PITCH)
+
+/* Don't re-wrap large data definitions. */
+/* clang-format off */
+
+/**
+ * Stored in R8 format. Load it in the following format:
+ * - DX10: DXGI_FORMAT_R8_UNORM
+ */
+static const unsigned char searchTexBytes[] = {
+ 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00,
+ 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe,
+ 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00,
+ 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe,
+ 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f,
+ 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f,
+ 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+};
+
+/* clang-format off */
+
+#endif /* __SMAA_TEXTURES_H__ */
diff --git a/source/blender/draw/modes/draw_mode_engines.h b/source/blender/draw/modes/draw_mode_engines.h
deleted file mode 100644
index 0d3d5cf7c59..00000000000
--- a/source/blender/draw/modes/draw_mode_engines.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#ifndef __DRAW_MODE_ENGINES_H__
-#define __DRAW_MODE_ENGINES_H__
-
-extern DrawEngineType draw_engine_object_type;
-extern DrawEngineType draw_engine_edit_armature_type;
-extern DrawEngineType draw_engine_edit_curve_type;
-extern DrawEngineType draw_engine_edit_lattice_type;
-extern DrawEngineType draw_engine_edit_mesh_type;
-extern DrawEngineType draw_engine_edit_metaball_type;
-extern DrawEngineType draw_engine_edit_text_type;
-extern DrawEngineType draw_engine_motion_path_type;
-extern DrawEngineType draw_engine_paint_texture_type;
-extern DrawEngineType draw_engine_paint_vertex_type;
-extern DrawEngineType draw_engine_particle_type;
-extern DrawEngineType draw_engine_pose_type;
-extern DrawEngineType draw_engine_sculpt_type;
-extern DrawEngineType draw_engine_overlay_type;
-extern DrawEngineType draw_engine_gpencil_type;
-
-#endif /* __DRAW_MODE_ENGINES_H__ */
diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c
deleted file mode 100644
index 20195b7d9f9..00000000000
--- a/source/blender/draw/modes/edit_armature_mode.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
-#include "DNA_armature_types.h"
-#include "DNA_view3d_types.h"
-
-#include "ED_view3d.h"
-
-#include "draw_common.h"
-#include "draw_mode_engines.h"
-
-/* *********** LISTS *********** */
-typedef struct EDIT_ARMATURE_PassList {
- struct DRWPass *bone_solid[2];
- struct DRWPass *bone_transp[2];
- struct DRWPass *bone_wire[2];
- struct DRWPass *bone_outline[2];
- struct DRWPass *bone_envelope[2];
- struct DRWPass *bone_axes;
- struct DRWPass *relationship[2];
-} EDIT_ARMATURE_PassList;
-
-typedef struct EDIT_ARMATURE_StorageList {
- struct EDIT_ARMATURE_PrivateData *g_data;
-} EDIT_ARMATURE_StorageList;
-
-typedef struct EDIT_ARMATURE_Data {
- void *engine_type;
- DRWViewportEmptyList *fbl;
- DRWViewportEmptyList *txl;
- EDIT_ARMATURE_PassList *psl;
- EDIT_ARMATURE_StorageList *stl;
-} EDIT_ARMATURE_Data;
-
-/* *********** STATIC *********** */
-
-typedef struct EDIT_ARMATURE_PrivateData {
- bool transparent_bones;
-} EDIT_ARMATURE_PrivateData; /* Transient data */
-
-/* *********** FUNCTIONS *********** */
-
-static void EDIT_ARMATURE_cache_init(void *vedata)
-{
- EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
- EDIT_ARMATURE_StorageList *stl = ((EDIT_ARMATURE_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
- }
- stl->g_data->transparent_bones = (draw_ctx->v3d->shading.type == OB_WIRE);
-
- for (int i = 0; i < 2; i++) {
- /* Solid bones */
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
- psl->bone_solid[i] = DRW_pass_create("Bone Solid Pass", state | DRW_STATE_WRITE_DEPTH);
- psl->bone_transp[i] = DRW_pass_create("Bone Transp Pass", state | DRW_STATE_BLEND_ALPHA);
-
- /* Bones Outline */
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->bone_outline[i] = DRW_pass_create("Bone Outline Pass", state);
-
- /* Wire bones */
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_BLEND_ALPHA;
- psl->bone_wire[i] = DRW_pass_create("Bone Wire Pass", state);
-
- /* distance outline around envelope bones */
- state = DRW_STATE_BLEND_ADD | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_CULL_FRONT;
- psl->bone_envelope[i] = DRW_pass_create("Bone Envelope Outline Pass", state);
-
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_BLEND_ALPHA;
- psl->relationship[i] = DRW_pass_create("Bone Relationship Pass", state);
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WIRE_SMOOTH | DRW_STATE_BLEND_ALPHA;
- psl->bone_axes = DRW_pass_create("Bone Axes Pass", state);
- }
-}
-
-static void EDIT_ARMATURE_cache_populate(void *vedata, Object *ob)
-{
- bArmature *arm = ob->data;
-
- if (ob->type == OB_ARMATURE) {
- if (arm->edbo) {
- EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
- EDIT_ARMATURE_StorageList *stl = ((EDIT_ARMATURE_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- int ghost = (ob->dtx & OB_DRAWXRAY) ? 1 : 0;
- bool transp = (stl->g_data->transparent_bones || (ob->dt <= OB_WIRE)) ||
- XRAY_FLAG_ENABLED(draw_ctx->v3d);
-
- DRWArmaturePasses passes = {
- .bone_solid = (transp) ? psl->bone_transp[ghost] : psl->bone_solid[ghost],
- .bone_outline = psl->bone_outline[ghost],
- .bone_wire = psl->bone_wire[ghost],
- .bone_envelope = psl->bone_envelope[ghost],
- .bone_axes = psl->bone_axes,
- .relationship_lines = psl->relationship[ghost],
- .custom_shapes = NULL, /* Not needed in edit mode. */
- };
- DRW_shgroup_armature_edit(ob, passes, transp);
- }
- }
-}
-
-static void EDIT_ARMATURE_draw_scene(void *vedata)
-{
- EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- if (DRW_state_is_select()) {
- DRW_draw_pass(psl->bone_outline[0]);
- DRW_draw_pass(psl->bone_solid[0]);
- DRW_draw_pass(psl->bone_wire[0]);
- DRW_draw_pass(psl->bone_outline[1]);
- DRW_draw_pass(psl->bone_solid[1]);
- DRW_draw_pass(psl->bone_wire[1]);
- return;
- }
-
- DRW_draw_pass(psl->bone_envelope[0]);
-
- /* For performance reason, avoid blending on MS target. */
- DRW_draw_pass(psl->bone_transp[0]);
-
- MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
-
- DRW_draw_pass(psl->bone_solid[0]);
- DRW_draw_pass(psl->bone_outline[0]);
- DRW_draw_pass(psl->bone_wire[0]);
- DRW_draw_pass(psl->relationship[0]);
-
- MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
-
- if (!DRW_pass_is_empty(psl->bone_envelope[1]) || !DRW_pass_is_empty(psl->bone_solid[1]) ||
- !DRW_pass_is_empty(psl->bone_transp[1]) || !DRW_pass_is_empty(psl->bone_outline[1]) ||
- !DRW_pass_is_empty(psl->bone_wire[1]) || !DRW_pass_is_empty(psl->relationship[1])) {
- if (DRW_state_is_fbo()) {
- GPU_framebuffer_bind(dfbl->default_fb);
- GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
- }
-
- DRW_draw_pass(psl->bone_envelope[1]);
- DRW_draw_pass(psl->bone_solid[1]);
- DRW_draw_pass(psl->bone_transp[1]);
- DRW_draw_pass(psl->bone_outline[1]);
- DRW_draw_pass(psl->bone_wire[1]);
- DRW_draw_pass(psl->relationship[1]);
- }
-
- /* Draw axes with linesmooth and outside of multisample buffer. */
- DRW_draw_pass(psl->bone_axes);
-}
-
-static const DrawEngineDataSize EDIT_ARMATURE_data_size = DRW_VIEWPORT_DATA_SIZE(
- EDIT_ARMATURE_Data);
-
-DrawEngineType draw_engine_edit_armature_type = {
- NULL,
- NULL,
- N_("EditArmatureMode"),
- &EDIT_ARMATURE_data_size,
- NULL,
- NULL,
- &EDIT_ARMATURE_cache_init,
- &EDIT_ARMATURE_cache_populate,
- NULL,
- NULL,
- &EDIT_ARMATURE_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c
deleted file mode 100644
index afaaba0712f..00000000000
--- a/source/blender/draw/modes/edit_curve_mode.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
-#include "DNA_curve_types.h"
-#include "DNA_view3d_types.h"
-
-#include "BKE_object.h"
-
-/* If builtin shaders are needed */
-#include "GPU_shader.h"
-
-#include "draw_common.h"
-#include "draw_mode_engines.h"
-
-/* If needed, contains all global/Theme colors
- * Add needed theme colors / values to DRW_globals_update() and update UBO
- * Not needed for constant color. */
-
-extern char datatoc_common_globals_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_edit_curve_overlay_loosevert_vert_glsl[];
-extern char datatoc_edit_curve_overlay_normals_vert_glsl[];
-extern char datatoc_edit_curve_overlay_handle_vert_glsl[];
-extern char datatoc_edit_curve_overlay_handle_geom_glsl[];
-
-extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
-extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
-extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
-
-/* *********** LISTS *********** */
-/* All lists are per viewport specific datas.
- * They are all free when viewport changes engines
- * or is free itself. Use EDIT_CURVE_engine_init() to
- * initialize most of them and EDIT_CURVE_cache_init()
- * for EDIT_CURVE_PassList */
-
-typedef struct EDIT_CURVE_PassList {
- struct DRWPass *wire_pass;
- struct DRWPass *wire_pass_xray;
- struct DRWPass *overlay_edge_pass;
- struct DRWPass *overlay_vert_pass;
-} EDIT_CURVE_PassList;
-
-typedef struct EDIT_CURVE_StorageList {
- struct CustomStruct *block;
- struct EDIT_CURVE_PrivateData *g_data;
-} EDIT_CURVE_StorageList;
-
-typedef struct EDIT_CURVE_Data {
- void *engine_type; /* Required */
- DRWViewportEmptyList *fbl;
- DRWViewportEmptyList *txl;
- EDIT_CURVE_PassList *psl;
- EDIT_CURVE_StorageList *stl;
-} EDIT_CURVE_Data;
-
-/* *********** STATIC *********** */
-
-typedef struct EDIT_CURVE_Shaders {
- GPUShader *wire_sh;
- GPUShader *wire_normals_sh;
- GPUShader *overlay_edge_sh; /* handles and nurbs control cage */
- GPUShader *overlay_vert_sh;
-} EDIT_CURVE_Shaders;
-
-static struct {
- EDIT_CURVE_Shaders sh_data[GPU_SHADER_CFG_LEN];
-} e_data = {{{NULL}}}; /* Engine data */
-
-typedef struct EDIT_CURVE_PrivateData {
- /* resulting curve as 'wire' for curves (and optionally normals) */
- DRWShadingGroup *wire_shgrp;
- DRWShadingGroup *wire_shgrp_xray;
- DRWShadingGroup *wire_normals_shgrp;
- DRWShadingGroup *wire_normals_shgrp_xray;
-
- DRWShadingGroup *overlay_edge_shgrp;
- DRWShadingGroup *overlay_vert_shgrp;
-
- int show_handles;
-} EDIT_CURVE_PrivateData; /* Transient data */
-
-/* *********** FUNCTIONS *********** */
-
-/* Init Textures, Framebuffers, Storage and Shaders.
- * It is called for every frames.
- * (Optional) */
-static void EDIT_CURVE_engine_init(void *UNUSED(vedata))
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- EDIT_CURVE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
-
- if (!sh_data->wire_sh) {
- sh_data->wire_sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_UNIFORM_COLOR,
- draw_ctx->sh_cfg);
- }
-
- if (!sh_data->wire_normals_sh) {
- sh_data->wire_normals_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_edit_curve_overlay_normals_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define IN_PLACE_INSTANCES\n", NULL},
- });
- }
-
- if (!sh_data->overlay_edge_sh) {
- sh_data->overlay_edge_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_edit_curve_overlay_handle_vert_glsl,
- NULL},
- .geom = (const char *[]){sh_cfg_data->lib,
- datatoc_common_globals_lib_glsl,
- datatoc_edit_curve_overlay_handle_geom_glsl,
- NULL},
- .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- if (!sh_data->overlay_vert_sh) {
- sh_data->overlay_vert_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_edit_curve_overlay_loosevert_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-}
-
-static void EDIT_CURVE_wire_shgrp_create(EDIT_CURVE_Shaders *sh_data,
- const View3D *v3d,
- const RegionView3D *rv3d,
- DRWPass *pass,
- DRWShadingGroup **wire_shgrp,
- DRWShadingGroup **wire_normals_shgrp)
-{
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->wire_sh, pass);
- DRW_shgroup_uniform_vec4(grp, "color", G_draw.block.colorWireEdit, 1);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- *wire_shgrp = grp;
-
- grp = DRW_shgroup_create(sh_data->wire_normals_sh, pass);
- DRW_shgroup_uniform_vec4(grp, "color", G_draw.block.colorWireEdit, 1);
- DRW_shgroup_uniform_float_copy(grp, "normalSize", v3d->overlay.normals_length);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- *wire_normals_shgrp = grp;
-}
-
-/* Here init all passes and shading groups
- * Assume that all Passes are NULL */
-static void EDIT_CURVE_cache_init(void *vedata)
-{
- EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
- EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- const RegionView3D *rv3d = draw_ctx->rv3d;
- EDIT_CURVE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
- }
-
- stl->g_data->show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
-
- {
- DRWShadingGroup *grp;
-
- /* Center-Line (wire) */
- psl->wire_pass = DRW_pass_create(
- "Curve Wire", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
- EDIT_CURVE_wire_shgrp_create(sh_data,
- v3d,
- rv3d,
- psl->wire_pass,
- &stl->g_data->wire_shgrp,
- &stl->g_data->wire_normals_shgrp);
-
- psl->wire_pass_xray = DRW_pass_create(
- "Curve Wire Xray", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
- EDIT_CURVE_wire_shgrp_create(sh_data,
- v3d,
- rv3d,
- psl->wire_pass_xray,
- &stl->g_data->wire_shgrp_xray,
- &stl->g_data->wire_normals_shgrp_xray);
-
- psl->overlay_edge_pass = DRW_pass_create("Curve Handle Overlay",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
-
- grp = DRW_shgroup_create(sh_data->overlay_edge_sh, psl->overlay_edge_pass);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_bool(grp, "showCurveHandles", &stl->g_data->show_handles, 1);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- stl->g_data->overlay_edge_shgrp = grp;
-
- psl->overlay_vert_pass = DRW_pass_create("Curve Vert Overlay", DRW_STATE_WRITE_COLOR);
-
- grp = DRW_shgroup_create(sh_data->overlay_vert_sh, psl->overlay_vert_pass);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- stl->g_data->overlay_vert_shgrp = grp;
- }
-}
-
-/* Add geometry to shadingGroups. Execute for each objects */
-static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
-{
- EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- if (ob->type == OB_CURVE) {
- if (BKE_object_is_in_editmode(ob)) {
- Curve *cu = ob->data;
- /* Get geometry cache */
- struct GPUBatch *geom;
-
- DRWShadingGroup *wire_shgrp, *wire_normals_shgrp;
-
- if (ob->dtx & OB_DRAWXRAY) {
- wire_shgrp = stl->g_data->wire_shgrp_xray;
- wire_normals_shgrp = stl->g_data->wire_normals_shgrp_xray;
- }
- else {
- wire_shgrp = stl->g_data->wire_shgrp;
- wire_normals_shgrp = stl->g_data->wire_normals_shgrp;
- }
-
- geom = DRW_cache_curve_edge_wire_get(ob);
- if (geom) {
- DRW_shgroup_call_no_cull(wire_shgrp, geom, ob);
- }
-
- if ((cu->flag & CU_3D) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0) {
- geom = DRW_cache_curve_edge_normal_get(ob);
- DRW_shgroup_call_instances(wire_normals_shgrp, ob, geom, 2);
- }
-
- geom = DRW_cache_curve_edge_overlay_get(ob);
- if (geom) {
- DRW_shgroup_call_no_cull(stl->g_data->overlay_edge_shgrp, geom, ob);
- }
-
- geom = DRW_cache_curve_vert_overlay_get(ob, stl->g_data->show_handles);
- if (geom) {
- DRW_shgroup_call_no_cull(stl->g_data->overlay_vert_shgrp, geom, ob);
- }
- }
- }
-
- if (ob->type == OB_SURF) {
- if (BKE_object_is_in_editmode(ob)) {
- struct GPUBatch *geom = DRW_cache_curve_edge_overlay_get(ob);
- if (geom) {
- DRW_shgroup_call_no_cull(stl->g_data->overlay_edge_shgrp, geom, ob);
- }
-
- geom = DRW_cache_curve_vert_overlay_get(ob, false);
- if (geom) {
- DRW_shgroup_call_no_cull(stl->g_data->overlay_vert_shgrp, geom, ob);
- }
- }
- }
-}
-
-/* Draw time ! Control rendering pipeline from here */
-static void EDIT_CURVE_draw_scene(void *vedata)
-{
- EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
-
- /* Default framebuffer and texture */
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- if (!DRW_pass_is_empty(psl->wire_pass)) {
- MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
-
- DRW_draw_pass(psl->wire_pass);
-
- MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
- }
-
- /* Unfortunately this pass cannot be AA'd without
- * MULTISAMPLE_SYNC_DISABLE_NO_DEPTH. While it's
- * quite unlikely to happen to multi-edit curves
- * with a mix of xray enabled/disabled we still
- * support this case. */
- if (!DRW_pass_is_empty(psl->wire_pass_xray)) {
- MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
-
- DRW_draw_pass(psl->wire_pass_xray);
-
- MULTISAMPLE_SYNC_DISABLE_NO_DEPTH(dfbl, dtxl);
- }
-
- /* These passes don't write to depth and are AA'ed using other tricks. */
- DRW_draw_pass(psl->overlay_edge_pass);
- DRW_draw_pass(psl->overlay_vert_pass);
-}
-
-/* Cleanup when destroying the engine.
- * This is not per viewport ! only when quitting blender.
- * Mostly used for freeing shaders */
-static void EDIT_CURVE_engine_free(void)
-{
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- EDIT_CURVE_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- /* Don't free builtins. */
- sh_data->wire_sh = NULL;
- GPUShader **sh_data_as_array = (GPUShader **)sh_data;
- for (int i = 0; i < (sizeof(EDIT_CURVE_Shaders) / sizeof(GPUShader *)); i++) {
- DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
- }
- }
-}
-
-static const DrawEngineDataSize EDIT_CURVE_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_CURVE_Data);
-
-DrawEngineType draw_engine_edit_curve_type = {
- NULL,
- NULL,
- N_("EditCurveMode"),
- &EDIT_CURVE_data_size,
- &EDIT_CURVE_engine_init,
- &EDIT_CURVE_engine_free,
- &EDIT_CURVE_cache_init,
- &EDIT_CURVE_cache_populate,
- NULL,
- NULL, /* draw_background but not needed by mode engines */
- &EDIT_CURVE_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/edit_lattice_mode.c b/source/blender/draw/modes/edit_lattice_mode.c
deleted file mode 100644
index 0fb8f555819..00000000000
--- a/source/blender/draw/modes/edit_lattice_mode.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
-#include "BKE_object.h"
-
-/* If builtin shaders are needed */
-#include "GPU_shader.h"
-
-#include "draw_common.h"
-#include "draw_mode_engines.h"
-
-extern char datatoc_common_globals_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-extern char datatoc_edit_lattice_overlay_loosevert_vert_glsl[];
-extern char datatoc_edit_lattice_overlay_frag_glsl[];
-
-/* *********** LISTS *********** */
-/* All lists are per viewport specific datas.
- * They are all free when viewport changes engines
- * or is free itself. Use EDIT_LATTICE_engine_init() to
- * initialize most of them and EDIT_LATTICE_cache_init()
- * for EDIT_LATTICE_PassList */
-
-typedef struct EDIT_LATTICE_PassList {
- /* Declare all passes here and init them in
- * EDIT_LATTICE_cache_init().
- * Only contains (DRWPass *) */
- struct DRWPass *wire_pass;
- struct DRWPass *vert_pass;
-} EDIT_LATTICE_PassList;
-
-typedef struct EDIT_LATTICE_FramebufferList {
- /* Contains all framebuffer objects needed by this engine.
- * Only contains (GPUFrameBuffer *) */
- struct GPUFrameBuffer *fb;
-} EDIT_LATTICE_FramebufferList;
-
-typedef struct EDIT_LATTICE_TextureList {
- /* Contains all framebuffer textures / utility textures
- * needed by this engine. Only viewport specific textures
- * (not per object). Only contains (GPUTexture *) */
- struct GPUTexture *texture;
-} EDIT_LATTICE_TextureList;
-
-typedef struct EDIT_LATTICE_StorageList {
- /* Contains any other memory block that the engine needs.
- * Only directly MEM_(m/c)allocN'ed blocks because they are
- * free with MEM_freeN() when viewport is freed.
- * (not per object) */
- struct CustomStruct *block;
- struct EDIT_LATTICE_PrivateData *g_data;
-} EDIT_LATTICE_StorageList;
-
-typedef struct EDIT_LATTICE_Data {
- /* Struct returned by DRW_viewport_engine_data_ensure.
- * If you don't use one of these, just make it a (void *) */
- // void *fbl;
- void *engine_type; /* Required */
- EDIT_LATTICE_FramebufferList *fbl;
- EDIT_LATTICE_TextureList *txl;
- EDIT_LATTICE_PassList *psl;
- EDIT_LATTICE_StorageList *stl;
-} EDIT_LATTICE_Data;
-
-typedef struct EDIT_LATTICE_Shaders {
- GPUShader *wire;
- GPUShader *overlay_vert;
-} EDIT_LATTICE_Shaders;
-
-/* *********** STATIC *********** */
-
-static struct {
- /* Custom shaders :
- * Add sources to source/blender/draw/modes/shaders
- * init in EDIT_LATTICE_engine_init();
- * free in EDIT_LATTICE_engine_free(); */
-
- EDIT_LATTICE_Shaders sh_data[GPU_SHADER_CFG_LEN];
-
-} e_data = {{{NULL}}}; /* Engine data */
-
-typedef struct EDIT_LATTICE_PrivateData {
- /* This keeps the references of the shading groups for
- * easy access in EDIT_LATTICE_cache_populate() */
- DRWShadingGroup *wire_shgrp;
- DRWShadingGroup *vert_shgrp;
-} EDIT_LATTICE_PrivateData; /* Transient data */
-
-/* *********** FUNCTIONS *********** */
-
-/* Init Textures, Framebuffers, Storage and Shaders.
- * It is called for every frames.
- * (Optional) */
-static void EDIT_LATTICE_engine_init(void *vedata)
-{
- EDIT_LATTICE_TextureList *txl = ((EDIT_LATTICE_Data *)vedata)->txl;
- EDIT_LATTICE_FramebufferList *fbl = ((EDIT_LATTICE_Data *)vedata)->fbl;
- EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
-
- UNUSED_VARS(txl, fbl, stl);
-
- /* Init Framebuffers like this: order is attachment order (for color texs) */
- /*
- * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
- * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
- */
-
- /* DRW_framebuffer_init takes care of checking if
- * the framebuffer is valid and has the right size*/
- /*
- * float *viewport_size = DRW_viewport_size_get();
- * DRW_framebuffer_init(&fbl->occlude_wire_fb,
- * (int)viewport_size[0], (int)viewport_size[1],
- * tex, 2);
- */
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- EDIT_LATTICE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
-
- if (!sh_data->wire) {
- sh_data->wire = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_SMOOTH_COLOR,
- draw_ctx->sh_cfg);
- }
-
- if (!sh_data->overlay_vert) {
- sh_data->overlay_vert = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_edit_lattice_overlay_loosevert_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_common_globals_lib_glsl,
- datatoc_edit_lattice_overlay_frag_glsl,
- NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-}
-
-/* Here init all passes and shading groups
- * Assume that all Passes are NULL */
-static void EDIT_LATTICE_cache_init(void *vedata)
-{
- EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
- EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
- EDIT_LATTICE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->wire_pass = DRW_pass_create("Lattice Wire", state);
- stl->g_data->wire_shgrp = DRW_shgroup_create(sh_data->wire, psl->wire_pass);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(stl->g_data->wire_shgrp, DRW_STATE_CLIP_PLANES);
- }
-
- state = DRW_STATE_WRITE_COLOR;
- psl->vert_pass = DRW_pass_create("Lattice Verts", state);
- stl->g_data->vert_shgrp = DRW_shgroup_create(sh_data->overlay_vert, psl->vert_pass);
- DRW_shgroup_uniform_block(stl->g_data->vert_shgrp, "globalsBlock", G_draw.block_ubo);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(stl->g_data->vert_shgrp, DRW_STATE_CLIP_PLANES);
- }
- }
-}
-
-/* Add geometry to shadingGroups. Execute for each objects */
-static void EDIT_LATTICE_cache_populate(void *vedata, Object *ob)
-{
- EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
- EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- UNUSED_VARS(psl);
-
- if (ob->type == OB_LATTICE) {
- if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) {
- /* Get geometry cache */
- struct GPUBatch *geom;
-
- geom = DRW_cache_lattice_wire_get(ob, true);
- DRW_shgroup_call(stl->g_data->wire_shgrp, geom, ob);
-
- geom = DRW_cache_lattice_vert_overlay_get(ob);
- DRW_shgroup_call(stl->g_data->vert_shgrp, geom, ob);
- }
- }
-}
-
-/* Optional: Post-cache_populate callback */
-static void EDIT_LATTICE_cache_finish(void *vedata)
-{
- EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
- EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
-
- /* Do something here! dependent on the objects gathered */
- UNUSED_VARS(psl, stl);
-}
-
-/* Draw time ! Control rendering pipeline from here */
-static void EDIT_LATTICE_draw_scene(void *vedata)
-{
- EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
- EDIT_LATTICE_FramebufferList *fbl = ((EDIT_LATTICE_Data *)vedata)->fbl;
-
- /* Default framebuffer and texture */
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- UNUSED_VARS(fbl);
-
- MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
-
- /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
- /*
- * DRW_framebuffer_texture_detach(dtxl->depth);
- * DRW_framebuffer_bind(fbl->custom_fb);
- * DRW_draw_pass(psl->pass);
- * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
- * DRW_framebuffer_bind(dfbl->default_fb);
- */
-
- /* ... or just render passes on default framebuffer. */
- DRW_draw_pass(psl->wire_pass);
- DRW_draw_pass(psl->vert_pass);
-
- MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
-
- /* If you changed framebuffer, double check you rebind
- * the default one with its textures attached before finishing */
-}
-
-/* Cleanup when destroying the engine.
- * This is not per viewport ! only when quitting blender.
- * Mostly used for freeing shaders */
-static void EDIT_LATTICE_engine_free(void)
-{
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- EDIT_LATTICE_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- /* Don't free builtins. */
- sh_data->wire = NULL;
- GPUShader **sh_data_as_array = (GPUShader **)sh_data;
- for (int i = 0; i < (sizeof(EDIT_LATTICE_Shaders) / sizeof(GPUShader *)); i++) {
- DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
- }
- }
-}
-
-static const DrawEngineDataSize EDIT_LATTICE_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_LATTICE_Data);
-
-DrawEngineType draw_engine_edit_lattice_type = {
- NULL,
- NULL,
- N_("EditLatticeMode"),
- &EDIT_LATTICE_data_size,
- &EDIT_LATTICE_engine_init,
- &EDIT_LATTICE_engine_free,
- &EDIT_LATTICE_cache_init,
- &EDIT_LATTICE_cache_populate,
- &EDIT_LATTICE_cache_finish,
- NULL, /* draw_background but not needed by mode engines */
- &EDIT_LATTICE_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
deleted file mode 100644
index 9957dbae3fb..00000000000
--- a/source/blender/draw/modes/edit_mesh_mode.c
+++ /dev/null
@@ -1,903 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_view3d_types.h"
-
-#include "draw_common.h"
-
-#include "draw_cache_impl.h"
-#include "draw_mode_engines.h"
-
-#include "edit_mesh_mode_intern.h" /* own include */
-
-#include "BKE_editmesh.h"
-#include "BKE_object.h"
-
-#include "BLI_dynstr.h"
-#include "BLI_string_utils.h"
-
-#include "ED_view3d.h"
-
-extern char datatoc_paint_weight_vert_glsl[];
-extern char datatoc_paint_weight_frag_glsl[];
-
-extern char datatoc_edit_mesh_overlay_common_lib_glsl[];
-extern char datatoc_edit_mesh_overlay_frag_glsl[];
-extern char datatoc_edit_mesh_overlay_vert_glsl[];
-extern char datatoc_edit_mesh_overlay_geom_glsl[];
-extern char datatoc_edit_mesh_overlay_mix_frag_glsl[];
-extern char datatoc_edit_mesh_overlay_facefill_vert_glsl[];
-extern char datatoc_edit_mesh_overlay_facefill_frag_glsl[];
-extern char datatoc_edit_mesh_overlay_mesh_analysis_frag_glsl[];
-extern char datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl[];
-extern char datatoc_edit_normals_vert_glsl[];
-extern char datatoc_edit_normals_geom_glsl[];
-extern char datatoc_edit_mesh_skin_root_vert_glsl[];
-extern char datatoc_common_globals_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
-extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
-extern char datatoc_gpu_shader_flat_color_frag_glsl[];
-extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
-
-/* *********** LISTS *********** */
-
-typedef struct EDIT_MESH_ComponentPassList {
- struct DRWPass *faces;
- struct DRWPass *faces_cage;
- struct DRWPass *edges;
- struct DRWPass *verts;
-} EDIT_MESH_ComponentPassList;
-
-typedef struct EDIT_MESH_PassList {
- struct DRWPass *weight_faces;
- struct DRWPass *depth_hidden_wire;
- struct DRWPass *depth_hidden_wire_in_front;
-
- EDIT_MESH_ComponentPassList edit_passes;
- EDIT_MESH_ComponentPassList edit_passes_in_front;
-
- struct DRWPass *mix_occlude;
- struct DRWPass *facefill_occlude;
- struct DRWPass *facefill_occlude_cage;
- struct DRWPass *mesh_analysis_pass;
- struct DRWPass *normals;
-} EDIT_MESH_PassList;
-
-typedef struct EDIT_MESH_FramebufferList {
- struct GPUFrameBuffer *occlude_wire_fb;
-} EDIT_MESH_FramebufferList;
-
-typedef struct EDIT_MESH_StorageList {
- struct EDIT_MESH_PrivateData *g_data;
-} EDIT_MESH_StorageList;
-
-typedef struct EDIT_MESH_Data {
- void *engine_type;
- EDIT_MESH_FramebufferList *fbl;
- DRWViewportEmptyList *txl;
- EDIT_MESH_PassList *psl;
- EDIT_MESH_StorageList *stl;
-} EDIT_MESH_Data;
-
-/** Can only contain shaders (freed as array). */
-typedef struct EDIT_MESH_Shaders {
- /* weight */
- GPUShader *weight_face;
-
- /* Geometry */
- GPUShader *overlay_vert;
- GPUShader *overlay_edge;
- GPUShader *overlay_edge_flat;
- GPUShader *overlay_face;
- GPUShader *overlay_facedot;
- GPUShader *overlay_skin_root;
-
- GPUShader *overlay_mix;
- GPUShader *overlay_facefill;
- GPUShader *normals_face;
- GPUShader *normals_loop;
- GPUShader *normals;
- GPUShader *depth;
-
- /* Mesh analysis shader */
- GPUShader *mesh_analysis;
-} EDIT_MESH_Shaders;
-
-/* *********** STATIC *********** */
-static struct {
- EDIT_MESH_Shaders sh_data[GPU_SHADER_CFG_LEN];
-
- /* temp buffer texture */
- struct GPUTexture *occlude_wire_depth_tx;
- struct GPUTexture *occlude_wire_color_tx;
-} e_data = {{{NULL}}}; /* Engine data */
-
-typedef struct EDIT_MESH_ComponentShadingGroupList {
- DRWShadingGroup *verts;
- DRWShadingGroup *edges;
- DRWShadingGroup *faces;
- DRWShadingGroup *faces_cage;
- DRWShadingGroup *facedots;
- DRWShadingGroup *skin_roots;
-} EDIT_MESH_ComponentShadingGroupList;
-
-typedef struct EDIT_MESH_PrivateData {
- /* weight */
- DRWShadingGroup *fweights_shgrp;
- DRWShadingGroup *depth_shgrp_hidden_wire;
- DRWShadingGroup *depth_shgrp_hidden_wire_in_front;
-
- DRWShadingGroup *fnormals_shgrp;
- DRWShadingGroup *vnormals_shgrp;
- DRWShadingGroup *lnormals_shgrp;
-
- EDIT_MESH_ComponentShadingGroupList edit_shgrps;
- EDIT_MESH_ComponentShadingGroupList edit_in_front_shgrps;
-
- DRWShadingGroup *facefill_occluded_shgrp;
- DRWShadingGroup *facefill_occluded_cage_shgrp;
- DRWShadingGroup *mesh_analysis_shgrp;
-
- DRWView *view_faces;
- DRWView *view_faces_cage;
- DRWView *view_edges;
- DRWView *view_verts;
-
- int data_mask[4];
- int ghost_ob;
- int edit_ob;
- bool do_zbufclip;
- bool do_faces;
- bool do_edges;
-} EDIT_MESH_PrivateData; /* Transient data */
-
-/* *********** FUNCTIONS *********** */
-
-static void EDIT_MESH_engine_init(void *vedata)
-{
- EDIT_MESH_FramebufferList *fbl = ((EDIT_MESH_Data *)vedata)->fbl;
- EDIT_MESH_StorageList *stl = ((EDIT_MESH_Data *)vedata)->stl;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- EDIT_MESH_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
-
- e_data.occlude_wire_depth_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_edit_mesh_type);
- e_data.occlude_wire_color_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA8, &draw_engine_edit_mesh_type);
-
- GPU_framebuffer_ensure_config(&fbl->occlude_wire_fb,
- {GPU_ATTACHMENT_TEXTURE(e_data.occlude_wire_depth_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.occlude_wire_color_tx)});
-
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
-
- if (!sh_data->weight_face) {
- sh_data->weight_face = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_paint_weight_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_common_globals_lib_glsl,
- datatoc_paint_weight_frag_glsl,
- NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
-
- char *lib = BLI_string_joinN(sh_cfg_data->lib,
- datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_edit_mesh_overlay_common_lib_glsl);
- /* Use geometry shader to draw edge wire-frame. This ensure us
- * the same result across platforms and more flexibility.
- * But we pay the cost of running a geometry shader.
- * In the future we might consider using only the vertex shader
- * and loading data manually with buffer textures. */
- const bool use_geom_shader = true;
- const char *geom_sh_code[] = {lib, datatoc_edit_mesh_overlay_geom_glsl, NULL};
- if (!use_geom_shader) {
- geom_sh_code[0] = NULL;
- }
- const char *use_geom_def = use_geom_shader ? "#define USE_GEOM_SHADER\n" : "";
- const char *use_smooth_def = (U.gpu_flag & USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE) ?
- "" :
- "#define USE_SMOOTH_WIRE\n";
- sh_data->overlay_face = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define FACE\n", NULL},
- });
- sh_data->overlay_edge = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_vert_glsl, NULL},
- .frag = (const char *[]){lib, datatoc_edit_mesh_overlay_frag_glsl, NULL},
- .defs = (const char
- *[]){sh_cfg_data->def, use_geom_def, use_smooth_def, "#define EDGE\n", NULL},
- .geom = (use_geom_shader) ? geom_sh_code : NULL,
- });
- sh_data->overlay_edge_flat = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_vert_glsl, NULL},
- .frag = (const char *[]){lib, datatoc_edit_mesh_overlay_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def,
- use_geom_def,
- use_smooth_def,
- "#define EDGE\n",
- "#define FLAT\n",
- NULL},
- .geom = (use_geom_shader) ? geom_sh_code : NULL,
- });
- sh_data->overlay_vert = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define VERT\n", NULL},
- });
- sh_data->overlay_facedot = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define FACEDOT\n", NULL},
- });
- sh_data->overlay_facefill = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_facefill_vert_glsl, NULL},
- .frag = (const char *[]){lib, datatoc_edit_mesh_overlay_facefill_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- sh_data->overlay_skin_root = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_mesh_skin_root_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
-
- MEM_freeN(lib);
-
- sh_data->overlay_mix = DRW_shader_create_fullscreen(datatoc_edit_mesh_overlay_mix_frag_glsl,
- NULL);
-
- lib = BLI_string_joinN(sh_cfg_data->lib, datatoc_common_view_lib_glsl);
-
- sh_data->normals_face = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_normals_vert_glsl, NULL},
- .geom = (const char *[]){lib, datatoc_edit_normals_geom_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define FACE_NORMALS\n", NULL},
- });
-
- sh_data->normals_loop = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_normals_vert_glsl, NULL},
- .geom = (const char *[]){lib, datatoc_edit_normals_geom_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define LOOP_NORMALS\n", NULL},
- });
-
- sh_data->normals = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_normals_vert_glsl, NULL},
- .geom = (const char *[]){lib, datatoc_edit_normals_geom_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
-
- /* Mesh Analysis */
- sh_data->mesh_analysis = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_edit_mesh_overlay_mesh_analysis_frag_glsl, NULL},
- });
-
- MEM_freeN(lib);
-
- sh_data->depth = DRW_shader_create_3d_depth_only(draw_ctx->sh_cfg);
- }
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- }
-
- {
- /* Create view with depth offset */
- stl->g_data->view_faces = (DRWView *)DRW_view_default_get();
- stl->g_data->view_faces_cage = DRW_view_create_with_zoffset(draw_ctx->rv3d, 0.5f);
- stl->g_data->view_edges = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.0f);
- stl->g_data->view_verts = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.5f);
- }
-}
-
-static void edit_mesh_create_overlay_passes(float face_alpha,
- int *data_mask,
- bool do_edges,
- DRWState statemod,
- EDIT_MESH_ComponentPassList *passes,
- EDIT_MESH_ComponentShadingGroupList *shgrps)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
- Scene *scene = draw_ctx->scene;
- ToolSettings *tsettings = scene->toolsettings;
- EDIT_MESH_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- const bool select_vert = (tsettings->selectmode & SCE_SELECT_VERTEX) != 0;
- const bool select_face = (tsettings->selectmode & SCE_SELECT_FACE) != 0;
- const bool select_edge = (tsettings->selectmode & SCE_SELECT_EDGE) != 0;
-
- DRWShadingGroup *grp;
-
- GPUShader *vert_sh = sh_data->overlay_vert;
- GPUShader *edge_sh = (select_vert) ? sh_data->overlay_edge : sh_data->overlay_edge_flat;
- GPUShader *face_sh = sh_data->overlay_face;
- GPUShader *facedot_sh = sh_data->overlay_facedot;
- GPUShader *skin_root_sh = sh_data->overlay_skin_root;
-
- /* Faces */
- passes->faces = DRW_pass_create("Edit Mesh Faces", DRW_STATE_WRITE_COLOR | statemod);
- grp = shgrps->faces = DRW_shgroup_create(face_sh, passes->faces);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_float_copy(grp, "faceAlphaMod", face_alpha);
- DRW_shgroup_uniform_ivec4(grp, "dataMask", data_mask, 1);
- DRW_shgroup_uniform_bool_copy(grp, "selectFaces", select_face);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
-
- /* Cage geom needs to be offsetted to avoid Z-fighting. */
- passes->faces_cage = DRW_pass_create("Edit Mesh Faces Cage", DRW_STATE_WRITE_COLOR | statemod);
- grp = shgrps->faces_cage = DRW_shgroup_create(face_sh, passes->faces_cage);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_float_copy(grp, "faceAlphaMod", face_alpha);
- DRW_shgroup_uniform_ivec4(grp, "dataMask", data_mask, 1);
- DRW_shgroup_uniform_bool_copy(grp, "selectFaces", select_face);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
-
- /* Edges */
- /* Change first vertex convention to match blender loop structure. */
- passes->edges = DRW_pass_create(
- "Edit Mesh Edges", DRW_STATE_WRITE_COLOR | DRW_STATE_FIRST_VERTEX_CONVENTION | statemod);
- grp = shgrps->edges = DRW_shgroup_create(edge_sh, passes->edges);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_vec2(grp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_uniform_ivec4(grp, "dataMask", data_mask, 1);
- DRW_shgroup_uniform_bool_copy(grp, "selectEdges", do_edges || select_edge);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
-
- /* Verts */
- DRWState state = (DRW_STATE_WRITE_COLOR | statemod) & ~DRW_STATE_BLEND_ALPHA;
- passes->verts = DRW_pass_create("Edit Mesh Verts", state);
- if (select_vert) {
- grp = shgrps->verts = DRW_shgroup_create(vert_sh, passes->verts);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
-
- grp = shgrps->skin_roots = DRW_shgroup_create(skin_root_sh, passes->verts);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
- }
- if (select_face) {
- grp = shgrps->facedots = DRW_shgroup_create(facedot_sh, passes->verts);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_state_enable(grp, DRW_STATE_WRITE_DEPTH);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- }
-}
-
-static void EDIT_MESH_cache_init(void *vedata)
-{
- EDIT_MESH_PassList *psl = ((EDIT_MESH_Data *)vedata)->psl;
- EDIT_MESH_StorageList *stl = ((EDIT_MESH_Data *)vedata)->stl;
- EDIT_MESH_PrivateData *g_data = stl->g_data;
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- RegionView3D *rv3d = draw_ctx->rv3d;
- Scene *scene = draw_ctx->scene;
- ToolSettings *tsettings = scene->toolsettings;
- EDIT_MESH_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- bool do_occlude_wire = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
-
- g_data->ghost_ob = 0;
- g_data->edit_ob = 0;
- g_data->do_faces = true;
- g_data->do_edges = true;
-
- g_data->do_zbufclip = XRAY_FLAG_ENABLED(v3d);
-
- g_data->data_mask[0] = 0xFF; /* Face Flag */
- g_data->data_mask[1] = 0xFF; /* Edge Flag */
- g_data->data_mask[2] = 0xFF; /* Crease */
- g_data->data_mask[3] = 0xFF; /* BWeight */
-
- if (draw_ctx->object_edit->type == OB_MESH) {
- if (BKE_object_is_in_editmode(draw_ctx->object_edit)) {
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FREESTYLE_FACE) == 0) {
- g_data->data_mask[0] &= ~VFLAG_FACE_FREESTYLE;
- }
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACES) == 0) {
- g_data->data_mask[0] &= ~(VFLAG_FACE_SELECTED & VFLAG_FACE_FREESTYLE);
- g_data->do_faces = false;
- g_data->do_zbufclip = false;
- }
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_SEAMS) == 0) {
- g_data->data_mask[1] &= ~VFLAG_EDGE_SEAM;
- }
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_SHARP) == 0) {
- g_data->data_mask[1] &= ~VFLAG_EDGE_SHARP;
- }
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FREESTYLE_EDGE) == 0) {
- g_data->data_mask[1] &= ~VFLAG_EDGE_FREESTYLE;
- }
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGES) == 0) {
- if ((tsettings->selectmode & SCE_SELECT_EDGE) == 0) {
- if ((v3d->shading.type < OB_SOLID) || (v3d->shading.flag & V3D_SHADING_XRAY)) {
- /* Special case, when drawing wire, draw edges, see: T67637. */
- }
- else {
- g_data->do_edges = false;
- }
- }
- }
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CREASES) == 0) {
- g_data->data_mask[2] = 0x0;
- }
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_BWEIGHTS) == 0) {
- g_data->data_mask[3] = 0x0;
- }
- }
- }
-
- float backwire_opacity = v3d->overlay.backwire_opacity;
- float size_normal = v3d->overlay.normals_length;
- float face_mod = (do_occlude_wire || !g_data->do_faces) ? 0.0f : 1.0f;
-
- {
- psl->weight_faces = DRW_pass_create(
- "Weight Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
-
- g_data->fweights_shgrp = DRW_shgroup_create(sh_data->weight_face, psl->weight_faces);
-
- DRW_shgroup_uniform_float_copy(g_data->fweights_shgrp, "opacity", 1.0);
- DRW_shgroup_uniform_texture(g_data->fweights_shgrp, "colorramp", G_draw.weight_ramp);
- DRW_shgroup_uniform_block(g_data->fweights_shgrp, "globalsBlock", G_draw.block_ubo);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->fweights_shgrp, DRW_STATE_CLIP_PLANES);
- }
- }
-
- {
- /* Complementary Depth Pass */
- psl->depth_hidden_wire = DRW_pass_create("Depth Pass Hidden Wire",
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_CULL_BACK);
- g_data->depth_shgrp_hidden_wire = DRW_shgroup_create(sh_data->depth, psl->depth_hidden_wire);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->depth_shgrp_hidden_wire, DRW_STATE_CLIP_PLANES);
- }
-
- psl->depth_hidden_wire_in_front = DRW_pass_create(
- "Depth Pass Hidden Wire In Front",
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK);
- g_data->depth_shgrp_hidden_wire_in_front = DRW_shgroup_create(sh_data->depth,
- psl->depth_hidden_wire_in_front);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->depth_shgrp_hidden_wire_in_front, DRW_STATE_CLIP_PLANES);
- }
- }
-
- {
- /* Normals */
- psl->normals = DRW_pass_create("Edit Mesh Normals Pass",
- DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR |
- DRW_STATE_DEPTH_LESS_EQUAL);
-
- g_data->fnormals_shgrp = DRW_shgroup_create(sh_data->normals_face, psl->normals);
- DRW_shgroup_uniform_float_copy(g_data->fnormals_shgrp, "normalSize", size_normal);
- DRW_shgroup_uniform_vec4(g_data->fnormals_shgrp, "color", G_draw.block.colorNormal, 1);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->fnormals_shgrp, DRW_STATE_CLIP_PLANES);
- }
-
- g_data->vnormals_shgrp = DRW_shgroup_create(sh_data->normals, psl->normals);
- DRW_shgroup_uniform_float_copy(g_data->vnormals_shgrp, "normalSize", size_normal);
- DRW_shgroup_uniform_vec4(g_data->vnormals_shgrp, "color", G_draw.block.colorVNormal, 1);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->vnormals_shgrp, DRW_STATE_CLIP_PLANES);
- }
-
- g_data->lnormals_shgrp = DRW_shgroup_create(sh_data->normals_loop, psl->normals);
- DRW_shgroup_uniform_float_copy(g_data->lnormals_shgrp, "normalSize", size_normal);
- DRW_shgroup_uniform_vec4(g_data->lnormals_shgrp, "color", G_draw.block.colorLNormal, 1);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->lnormals_shgrp, DRW_STATE_CLIP_PLANES);
- }
- }
-
- {
- /* Mesh Analysis Pass */
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
- psl->mesh_analysis_pass = DRW_pass_create("Mesh Analysis", state);
- g_data->mesh_analysis_shgrp = DRW_shgroup_create(sh_data->mesh_analysis,
- psl->mesh_analysis_pass);
- DRW_shgroup_uniform_texture(g_data->mesh_analysis_shgrp, "weightTex", G_draw.weight_ramp);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->mesh_analysis_shgrp, DRW_STATE_CLIP_PLANES);
- }
- }
- /* For in front option */
- edit_mesh_create_overlay_passes(face_mod,
- g_data->data_mask,
- g_data->do_edges,
- DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA,
- &psl->edit_passes_in_front,
- &g_data->edit_in_front_shgrps);
-
- if (!g_data->do_zbufclip) {
- edit_mesh_create_overlay_passes(face_mod,
- g_data->data_mask,
- g_data->do_edges,
- DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA,
- &psl->edit_passes,
- &g_data->edit_shgrps);
- }
- else {
- /* We render all wires with depth and opaque to a new fbo and blend the result based on depth
- * values */
- edit_mesh_create_overlay_passes(0.0f,
- g_data->data_mask,
- g_data->do_edges,
- DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH,
- &psl->edit_passes,
- &g_data->edit_shgrps);
-
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
- psl->facefill_occlude = DRW_pass_create("Front Face Color", state);
- psl->facefill_occlude_cage = DRW_pass_create("Front Face Cage Color", state);
-
- if (g_data->do_faces) {
- const bool select_face = (tsettings->selectmode & SCE_SELECT_FACE) != 0;
- DRWShadingGroup *shgrp;
-
- /* however we loose the front faces value (because we need the depth of occluded wires and
- * faces are alpha blended ) so we recover them in a new pass. */
- shgrp = g_data->facefill_occluded_shgrp = DRW_shgroup_create(sh_data->overlay_facefill,
- psl->facefill_occlude);
- DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_ivec4(shgrp, "dataMask", g_data->data_mask, 1);
- DRW_shgroup_uniform_bool_copy(shgrp, "selectFaces", select_face);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
-
- shgrp = g_data->facefill_occluded_cage_shgrp = DRW_shgroup_create(
- sh_data->overlay_facefill, psl->facefill_occlude_cage);
- DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_ivec4(shgrp, "dataMask", g_data->data_mask, 1);
- DRW_shgroup_uniform_bool_copy(shgrp, "selectFaces", select_face);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
- }
- else {
- g_data->facefill_occluded_shgrp = NULL;
- }
-
- /* we need a full screen pass to combine the result */
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
-
- psl->mix_occlude = DRW_pass_create("Mix Occluded Wires",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
- DRWShadingGroup *mix_shgrp = DRW_shgroup_create(sh_data->overlay_mix, psl->mix_occlude);
- DRW_shgroup_call(mix_shgrp, quad, NULL);
- DRW_shgroup_uniform_float_copy(mix_shgrp, "alpha", backwire_opacity);
- DRW_shgroup_uniform_texture_ref(mix_shgrp, "wireColor", &e_data.occlude_wire_color_tx);
- DRW_shgroup_uniform_texture_ref(mix_shgrp, "wireDepth", &e_data.occlude_wire_depth_tx);
- DRW_shgroup_uniform_texture_ref(mix_shgrp, "sceneDepth", &dtxl->depth);
- }
-
- bool show_face_dots = XRAY_FLAG_ENABLED(v3d) ||
- (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) != 0;
-
- if (g_data->do_faces == false && g_data->do_edges == false &&
- (tsettings->selectmode & SCE_SELECT_FACE)) {
- /* Force display of face centers in this case because that's
- * the only way to see if a face is selected. */
- show_face_dots = true;
- }
-
- /* HACK: set pointers to NULL even if generated. */
- if (!show_face_dots) {
- g_data->edit_shgrps.facedots = NULL;
- g_data->edit_in_front_shgrps.facedots = NULL;
- }
-}
-
-static void edit_mesh_add_ob_to_pass(Scene *scene,
- Object *ob,
- DRWShadingGroup *skin_roots_shgrp,
- DRWShadingGroup *vert_shgrp,
- DRWShadingGroup *edge_shgrp,
- DRWShadingGroup *face_shgrp,
- DRWShadingGroup *face_cage_shgrp,
- DRWShadingGroup *facedot_shgrp)
-{
- struct GPUBatch *geom_tris, *geom_verts, *geom_edges, *geom_fcenter, *skin_roots;
- ToolSettings *tsettings = scene->toolsettings;
-
- bool has_edit_mesh_cage = false;
- bool has_skin_roots = false;
- /* TODO: Should be its own function. */
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *embm = me->edit_mesh;
- if (embm) {
- has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
- has_skin_roots = CustomData_get_offset(&embm->bm->vdata, CD_MVERT_SKIN) != -1;
- }
-
- face_shgrp = (has_edit_mesh_cage) ? face_cage_shgrp : face_shgrp;
-
- geom_tris = DRW_mesh_batch_cache_get_edit_triangles(ob->data);
- geom_edges = DRW_mesh_batch_cache_get_edit_edges(ob->data);
- DRW_shgroup_call_no_cull(edge_shgrp, geom_edges, ob);
- DRW_shgroup_call_no_cull(face_shgrp, geom_tris, ob);
-
- if ((tsettings->selectmode & SCE_SELECT_VERTEX) != 0) {
- geom_verts = DRW_mesh_batch_cache_get_edit_vertices(ob->data);
- DRW_shgroup_call_no_cull(vert_shgrp, geom_verts, ob);
-
- if (has_skin_roots) {
- DRWShadingGroup *grp = DRW_shgroup_create_sub(skin_roots_shgrp);
- /* We need to upload the matrix. But the ob can be temporary allocated so we cannot
- * use direct reference to ob->obmat. */
- DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[0]", ob->obmat[0]);
- DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[1]", ob->obmat[1]);
- DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[2]", ob->obmat[2]);
- DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[3]", ob->obmat[3]);
-
- skin_roots = DRW_mesh_batch_cache_get_edit_skin_roots(ob->data);
- /* NOTE(fclem) We cannot use ob here since it would offset the instance attribs with
- * base instance offset. */
- DRW_shgroup_call(grp, skin_roots, NULL);
- }
- }
-
- if (facedot_shgrp && (tsettings->selectmode & SCE_SELECT_FACE) != 0) {
- geom_fcenter = DRW_mesh_batch_cache_get_edit_facedots(ob->data);
- DRW_shgroup_call_no_cull(facedot_shgrp, geom_fcenter, ob);
- }
-}
-
-static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
-{
- EDIT_MESH_StorageList *stl = ((EDIT_MESH_Data *)vedata)->stl;
- EDIT_MESH_PrivateData *g_data = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- Scene *scene = draw_ctx->scene;
- struct GPUBatch *geom;
-
- if (ob->type == OB_MESH) {
- if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) {
- bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
- bool do_occlude_wire = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
- bool do_show_weight = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_WEIGHT) != 0;
- bool do_show_mesh_analysis = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_STATVIS) != 0;
- bool fnormals_do = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_NORMALS) != 0;
- bool vnormals_do = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_VERT_NORMALS) != 0;
- bool lnormals_do = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_LOOP_NORMALS) != 0;
-
- if (do_show_weight) {
- geom = DRW_cache_mesh_surface_weights_get(ob);
- DRW_shgroup_call_no_cull(g_data->fweights_shgrp, geom, ob);
- }
- else if (do_show_mesh_analysis && !XRAY_ACTIVE(v3d)) {
- geom = DRW_cache_mesh_surface_mesh_analysis_get(ob);
- if (geom) {
- DRW_shgroup_call_no_cull(g_data->mesh_analysis_shgrp, geom, ob);
- }
- }
-
- if (do_occlude_wire || do_in_front) {
- geom = DRW_cache_mesh_surface_get(ob);
- DRW_shgroup_call_no_cull(do_in_front ? g_data->depth_shgrp_hidden_wire_in_front :
- g_data->depth_shgrp_hidden_wire,
- geom,
- ob);
- }
-
- if (vnormals_do) {
- geom = DRW_mesh_batch_cache_get_edit_vnors(ob->data);
- DRW_shgroup_call_no_cull(g_data->vnormals_shgrp, geom, ob);
- }
- if (lnormals_do) {
- geom = DRW_mesh_batch_cache_get_edit_lnors(ob->data);
- DRW_shgroup_call_no_cull(g_data->lnormals_shgrp, geom, ob);
- }
- if (fnormals_do) {
- geom = DRW_mesh_batch_cache_get_edit_facedots(ob->data);
- DRW_shgroup_call_no_cull(g_data->fnormals_shgrp, geom, ob);
- }
-
- if (g_data->do_zbufclip) {
- edit_mesh_add_ob_to_pass(scene,
- ob,
- g_data->edit_shgrps.skin_roots,
- g_data->edit_shgrps.verts,
- g_data->edit_shgrps.edges,
- g_data->facefill_occluded_shgrp,
- g_data->facefill_occluded_cage_shgrp,
- g_data->edit_shgrps.facedots);
- }
- else if (do_in_front) {
- edit_mesh_add_ob_to_pass(scene,
- ob,
- g_data->edit_in_front_shgrps.skin_roots,
- g_data->edit_in_front_shgrps.verts,
- g_data->edit_in_front_shgrps.edges,
- g_data->edit_in_front_shgrps.faces,
- g_data->edit_in_front_shgrps.faces_cage,
- g_data->edit_in_front_shgrps.facedots);
- }
- else {
- edit_mesh_add_ob_to_pass(scene,
- ob,
- g_data->edit_shgrps.skin_roots,
- g_data->edit_shgrps.verts,
- g_data->edit_shgrps.edges,
- g_data->edit_shgrps.faces,
- g_data->edit_shgrps.faces_cage,
- g_data->edit_shgrps.facedots);
- }
-
- g_data->ghost_ob += (ob->dtx & OB_DRAWXRAY) ? 1 : 0;
- g_data->edit_ob += 1;
-
- /* 3D text overlay */
- if (v3d->overlay.edit_flag &
- (V3D_OVERLAY_EDIT_EDGE_LEN | V3D_OVERLAY_EDIT_FACE_AREA | V3D_OVERLAY_EDIT_FACE_ANG |
- V3D_OVERLAY_EDIT_EDGE_ANG | V3D_OVERLAY_EDIT_INDICES)) {
- if (DRW_state_show_text()) {
- DRW_edit_mesh_mode_text_measure_stats(draw_ctx->ar, v3d, ob, &scene->unit);
- }
- }
- }
- }
-}
-
-static void edit_mesh_draw_components(EDIT_MESH_ComponentPassList *passes,
- EDIT_MESH_PrivateData *g_data)
-{
- DRW_view_set_active(g_data->view_faces);
- DRW_draw_pass(passes->faces);
-
- DRW_view_set_active(g_data->view_faces_cage);
- DRW_draw_pass(passes->faces_cage);
-
- DRW_view_set_active(g_data->view_edges);
- DRW_draw_pass(passes->edges);
-
- DRW_view_set_active(g_data->view_verts);
- DRW_draw_pass(passes->verts);
-
- DRW_view_set_active(NULL);
-}
-
-static void EDIT_MESH_draw_scene(void *vedata)
-{
- EDIT_MESH_PassList *psl = ((EDIT_MESH_Data *)vedata)->psl;
- EDIT_MESH_StorageList *stl = ((EDIT_MESH_Data *)vedata)->stl;
- EDIT_MESH_FramebufferList *fbl = ((EDIT_MESH_Data *)vedata)->fbl;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
-
- DRW_draw_pass(psl->weight_faces);
- DRW_draw_pass(psl->mesh_analysis_pass);
-
- DRW_draw_pass(psl->depth_hidden_wire);
-
- if (stl->g_data->do_zbufclip) {
- float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
- DRW_draw_pass(psl->depth_hidden_wire_in_front);
-
- /* render facefill */
- DRW_view_set_active(stl->g_data->view_faces);
- DRW_draw_pass(psl->facefill_occlude);
-
- DRW_view_set_active(stl->g_data->view_faces_cage);
- DRW_draw_pass(psl->facefill_occlude_cage);
-
- DRW_view_set_active(NULL);
-
- /* Render wires on a separate framebuffer */
- GPU_framebuffer_bind(fbl->occlude_wire_fb);
- GPU_framebuffer_clear_color_depth(fbl->occlude_wire_fb, clearcol, 1.0f);
- DRW_draw_pass(psl->normals);
-
- edit_mesh_draw_components(&psl->edit_passes, stl->g_data);
-
- /* Combine with scene buffer */
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_draw_pass(psl->mix_occlude);
- }
- else {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- DRW_draw_pass(psl->normals);
- edit_mesh_draw_components(&psl->edit_passes, stl->g_data);
-
- if (v3d->shading.type == OB_SOLID && !XRAY_FLAG_ENABLED(v3d) && stl->g_data->ghost_ob == 1 &&
- stl->g_data->edit_ob == 1) {
- /* In the case of single ghost object edit (common case for retopology):
- * we clear the depth buffer so that only the depth of the retopo mesh
- * is occluding the edit cage. */
- GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
- }
-
- DRW_draw_pass(psl->depth_hidden_wire_in_front);
- edit_mesh_draw_components(&psl->edit_passes_in_front, stl->g_data);
- }
-}
-
-static void EDIT_MESH_engine_free(void)
-{
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- EDIT_MESH_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- /* Don't free builtins. */
- sh_data->depth = NULL;
- GPUShader **sh_data_as_array = (GPUShader **)sh_data;
- for (int i = 0; i < (sizeof(EDIT_MESH_Shaders) / sizeof(GPUShader *)); i++) {
- DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
- }
- }
-}
-
-static const DrawEngineDataSize EDIT_MESH_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_MESH_Data);
-
-DrawEngineType draw_engine_edit_mesh_type = {
- NULL,
- NULL,
- N_("EditMeshMode"),
- &EDIT_MESH_data_size,
- &EDIT_MESH_engine_init,
- &EDIT_MESH_engine_free,
- &EDIT_MESH_cache_init,
- &EDIT_MESH_cache_populate,
- NULL,
- NULL,
- &EDIT_MESH_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/edit_mesh_mode_text.c b/source/blender/draw/modes/edit_mesh_mode_text.c
deleted file mode 100644
index 7c7a9a586fa..00000000000
--- a/source/blender/draw/modes/edit_mesh_mode_text.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "BLI_math.h"
-#include "BLI_string.h"
-
-#include "BKE_editmesh.h"
-#include "BKE_global.h"
-#include "BKE_unit.h"
-
-#include "ED_view3d.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_view3d_types.h"
-
-#include "UI_resources.h"
-
-#include "draw_manager_text.h"
-
-#include "edit_mesh_mode_intern.h" /* own include */
-
-/* Copied from drawobject.c */
-void DRW_edit_mesh_mode_text_measure_stats(ARegion *ar,
- View3D *v3d,
- Object *ob,
- const UnitSettings *unit)
-{
- /* Do not use ascii when using non-default unit system, some unit chars are utf8 (micro, square,
- * etc.). See bug #36090.
- */
- struct DRWTextStore *dt = DRW_text_cache_ensure();
- const short txt_flag = DRW_TEXT_CACHE_GLOBALSPACE | (unit->system ? 0 : DRW_TEXT_CACHE_ASCII);
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_mesh;
- float v1[3], v2[3], v3[3], vmid[3], fvec[3];
- char numstr[32]; /* Stores the measurement display text here */
- size_t numstr_len;
- const char *conv_float; /* Use a float conversion matching the grid size */
- uchar col[4] = {0, 0, 0, 255}; /* color of the text to draw */
- float area; /* area of the face */
- float grid = unit->system ? unit->scale_length : v3d->grid;
- const bool do_global = (v3d->flag & V3D_GLOBAL_STATS) != 0;
- const bool do_moving = (G.moving & G_TRANSFORM_EDIT) != 0;
- /* when 2 edge-info options are enabled, space apart */
- const bool do_edge_textpair = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) &&
- (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_ANG);
- const short edge_texpair_sep = (short)(5.0f * U.dpi_fac);
- float clip_planes[4][4];
- /* allow for displaying shape keys and deform mods */
- BMIter iter;
-
- /* make the precision of the display value proportionate to the gridsize */
-
- if (grid <= 0.01f) {
- conv_float = "%.6g";
- }
- else if (grid <= 0.1f) {
- conv_float = "%.5g";
- }
- else if (grid <= 1.0f) {
- conv_float = "%.4g";
- }
- else if (grid <= 10.0f) {
- conv_float = "%.3g";
- }
- else {
- conv_float = "%.2g";
- }
-
- if (v3d->overlay.edit_flag &
- (V3D_OVERLAY_EDIT_EDGE_LEN | V3D_OVERLAY_EDIT_EDGE_ANG | V3D_OVERLAY_EDIT_INDICES)) {
- BoundBox bb;
- const rcti rect = {0, ar->winx, 0, ar->winy};
-
- ED_view3d_clipping_calc(&bb, clip_planes, ar, em->ob, &rect);
- }
-
- if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) {
- BMEdge *eed;
-
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
-
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- /* draw selected edges, or edges next to selected verts while dragging */
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
- (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
- BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)))) {
- float v1_clip[3], v2_clip[3];
-
- copy_v3_v3(v1, eed->v1->co);
- copy_v3_v3(v2, eed->v2->co);
-
- if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
-
- mid_v3_v3v3(vmid, v1_clip, v2_clip);
- mul_m4_v3(ob->obmat, vmid);
-
- if (do_global) {
- mul_mat3_m4_v3(ob->obmat, v1);
- mul_mat3_m4_v3(ob->obmat, v2);
- }
-
- if (unit->system) {
- numstr_len = bUnit_AsString2(numstr,
- sizeof(numstr),
- len_v3v3(v1, v2) * unit->scale_length,
- 3,
- B_UNIT_LENGTH,
- unit,
- false);
- }
- else {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
- }
-
- DRW_text_cache_add(dt,
- vmid,
- numstr,
- numstr_len,
- 0,
- (do_edge_textpair) ? edge_texpair_sep : 0,
- txt_flag,
- col);
- }
- }
- }
- }
-
- if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_ANG) {
- const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
- BMEdge *eed;
-
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col);
-
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- BMLoop *l_a, *l_b;
- if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
- /* Draw selected edges, or edges next to selected verts while dragging. */
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
- (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
- BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
- /* Special case, this is useful to show when verts connected
- * to this edge via a face are being transformed. */
- BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
- BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) ||
- BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
- BM_elem_flag_test(l_b->prev->v, BM_ELEM_SELECT)))) {
- float v1_clip[3], v2_clip[3];
-
- copy_v3_v3(v1, eed->v1->co);
- copy_v3_v3(v2, eed->v2->co);
-
- if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
- float no_a[3], no_b[3];
- float angle;
-
- mid_v3_v3v3(vmid, v1_clip, v2_clip);
- mul_m4_v3(ob->obmat, vmid);
-
- copy_v3_v3(no_a, l_a->f->no);
- copy_v3_v3(no_b, l_b->f->no);
-
- if (do_global) {
- mul_mat3_m4_v3(ob->imat, no_a);
- mul_mat3_m4_v3(ob->imat, no_b);
- normalize_v3(no_a);
- normalize_v3(no_b);
- }
-
- angle = angle_normalized_v3v3(no_a, no_b);
-
- numstr_len = BLI_snprintf_rlen(numstr,
- sizeof(numstr),
- "%.3f%s",
- (is_rad) ? angle : RAD2DEGF(angle),
- (is_rad) ? "r" : "°");
-
- DRW_text_cache_add(dt,
- vmid,
- numstr,
- numstr_len,
- 0,
- (do_edge_textpair) ? -edge_texpair_sep : 0,
- txt_flag,
- col);
- }
- }
- }
- }
- }
-
- if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_AREA) {
- /* would be nice to use BM_face_calc_area, but that is for 2d faces
- * so instead add up tessellation triangle areas */
-
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
-
- int i, n, numtri;
- BMFace *f = NULL;
- BM_ITER_MESH_INDEX (f, &iter, em->bm, BM_FACES_OF_MESH, i) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- n = 0;
- numtri = f->len - 2;
- area = 0;
- zero_v3(vmid);
- BMLoop *(*l)[3] = &em->looptris[poly_to_tri_count(i, BM_elem_index_get(f->l_first))];
- for (int j = 0; j < numtri; j++) {
- copy_v3_v3(v1, l[j][0]->v->co);
- copy_v3_v3(v2, l[j][1]->v->co);
- copy_v3_v3(v3, l[j][2]->v->co);
-
- add_v3_v3(vmid, v1);
- add_v3_v3(vmid, v2);
- add_v3_v3(vmid, v3);
- n += 3;
-
- if (do_global) {
- mul_mat3_m4_v3(ob->obmat, v1);
- mul_mat3_m4_v3(ob->obmat, v2);
- mul_mat3_m4_v3(ob->obmat, v3);
- }
-
- area += area_tri_v3(v1, v2, v3);
- }
-
- mul_v3_fl(vmid, 1.0f / (float)n);
- mul_m4_v3(ob->obmat, vmid);
-
- if (unit->system) {
- numstr_len = bUnit_AsString2(numstr,
- sizeof(numstr),
- (double)(area * unit->scale_length * unit->scale_length),
- 3,
- B_UNIT_AREA,
- unit,
- false);
- }
- else {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area);
- }
-
- DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, 0, txt_flag, col);
- }
- }
- }
-
- if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_ANG) {
- BMFace *efa;
- const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
-
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- const bool is_face_sel = BM_elem_flag_test_bool(efa, BM_ELEM_SELECT);
-
- if (is_face_sel || do_moving) {
- BMIter liter;
- BMLoop *loop;
- bool is_first = true;
-
- BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
- if (is_face_sel || (do_moving && (BM_elem_flag_test(loop->v, BM_ELEM_SELECT) ||
- BM_elem_flag_test(loop->prev->v, BM_ELEM_SELECT) ||
- BM_elem_flag_test(loop->next->v, BM_ELEM_SELECT)))) {
- float v2_local[3];
-
- /* lazy init center calc */
- if (is_first) {
- BM_face_calc_center_bounds(efa, vmid);
- is_first = false;
- }
- copy_v3_v3(v1, loop->prev->v->co);
- copy_v3_v3(v2, loop->v->co);
- copy_v3_v3(v3, loop->next->v->co);
-
- copy_v3_v3(v2_local, v2);
-
- if (do_global) {
- mul_mat3_m4_v3(ob->obmat, v1);
- mul_mat3_m4_v3(ob->obmat, v2);
- mul_mat3_m4_v3(ob->obmat, v3);
- }
-
- float angle = angle_v3v3v3(v1, v2, v3);
-
- numstr_len = BLI_snprintf_rlen(numstr,
- sizeof(numstr),
- "%.3f%s",
- (is_rad) ? angle : RAD2DEGF(angle),
- (is_rad) ? "r" : "°");
- interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
- mul_m4_v3(ob->obmat, fvec);
- DRW_text_cache_add(dt, fvec, numstr, numstr_len, 0, 0, txt_flag, col);
- }
- }
- }
- }
- }
-
- /* This option is for mesh ops and addons debugging; only available in UI if Blender starts with
- * --debug */
- if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_INDICES) {
- int i;
-
- /* For now, reuse an appropriate theme color */
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
-
- if (em->selectmode & SCE_SELECT_VERTEX) {
- BMVert *v;
-
- BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, i) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- float vec[3];
- mul_v3_m4v3(vec, ob->obmat, v->co);
-
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
- DRW_text_cache_add(dt, vec, numstr, numstr_len, 0, 0, txt_flag, col);
- }
- }
- }
-
- if (em->selectmode & SCE_SELECT_EDGE) {
- BMEdge *e;
-
- BM_ITER_MESH_INDEX (e, &iter, em->bm, BM_EDGES_OF_MESH, i) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- float v1_clip[3], v2_clip[3];
-
- copy_v3_v3(v1, e->v1->co);
- copy_v3_v3(v2, e->v2->co);
-
- if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
- mid_v3_v3v3(vmid, v1_clip, v2_clip);
- mul_m4_v3(ob->obmat, vmid);
-
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
- DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, 0, txt_flag, col);
- }
- }
- }
- }
-
- if (em->selectmode & SCE_SELECT_FACE) {
- BMFace *f;
-
- BM_ITER_MESH_INDEX (f, &iter, em->bm, BM_FACES_OF_MESH, i) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- BM_face_calc_center_median(f, v1);
- mul_m4_v3(ob->obmat, v1);
-
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
- DRW_text_cache_add(dt, v1, numstr, numstr_len, 0, 0, txt_flag, col);
- }
- }
- }
- }
-}
diff --git a/source/blender/draw/modes/edit_metaball_mode.c b/source/blender/draw/modes/edit_metaball_mode.c
deleted file mode 100644
index fb7f5ca5ff9..00000000000
--- a/source/blender/draw/modes/edit_metaball_mode.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_render.h"
-
-#include "DNA_meta_types.h"
-
-#include "BKE_object.h"
-
-#include "DEG_depsgraph_query.h"
-
-#include "ED_mball.h"
-
-/* If builtin shaders are needed */
-#include "GPU_shader.h"
-
-#include "draw_common.h"
-#include "draw_mode_engines.h"
-
-/* *********** LISTS *********** */
-/* All lists are per viewport specific datas.
- * They are all free when viewport changes engines
- * or is free itself. Use EDIT_METABALL_engine_init() to
- * initialize most of them and EDIT_METABALL_cache_init()
- * for EDIT_METABALL_PassList */
-
-typedef struct EDIT_METABALL_PassList {
- /* Declare all passes here and init them in
- * EDIT_METABALL_cache_init().
- * Only contains (DRWPass *) */
- struct DRWPass *pass;
-} EDIT_METABALL_PassList;
-
-typedef struct EDIT_METABALL_FramebufferList {
- /* Contains all framebuffer objects needed by this engine.
- * Only contains (GPUFrameBuffer *) */
- struct GPUFrameBuffer *fb;
-} EDIT_METABALL_FramebufferList;
-
-typedef struct EDIT_METABALL_TextureList {
- /* Contains all framebuffer textures / utility textures
- * needed by this engine. Only viewport specific textures
- * (not per object). Only contains (GPUTexture *) */
- struct GPUTexture *texture;
-} EDIT_METABALL_TextureList;
-
-typedef struct EDIT_METABALL_StorageList {
- /* Contains any other memory block that the engine needs.
- * Only directly MEM_(m/c)allocN'ed blocks because they are
- * free with MEM_freeN() when viewport is freed.
- * (not per object) */
- // struct CustomStruct *block;
- struct EDIT_METABALL_PrivateData *g_data;
-} EDIT_METABALL_StorageList;
-
-typedef struct EDIT_METABALL_Data {
- /* Struct returned by DRW_viewport_engine_data_ensure.
- * If you don't use one of these, just make it a (void *) */
- // void *fbl;
- void *engine_type; /* Required */
- EDIT_METABALL_FramebufferList *fbl;
- EDIT_METABALL_TextureList *txl;
- EDIT_METABALL_PassList *psl;
- EDIT_METABALL_StorageList *stl;
-} EDIT_METABALL_Data;
-
-/* *********** STATIC *********** */
-
-typedef struct EDIT_METABALL_PrivateData {
- /* This keeps the references of the shading groups for
- * easy access in EDIT_METABALL_cache_populate() */
- DRWCallBuffer *group;
-} EDIT_METABALL_PrivateData; /* Transient data */
-
-/* *********** FUNCTIONS *********** */
-
-/* Here init all passes and shading groups
- * Assume that all Passes are NULL */
-static void EDIT_METABALL_cache_init(void *vedata)
-{
- EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
- EDIT_METABALL_StorageList *stl = ((EDIT_METABALL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- }
-
- {
- /* Create a pass */
- DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_BLEND_ALPHA);
- psl->pass = DRW_pass_create("My Pass", state);
-
- /* Create a shadingGroup using a function in draw_common.c or custom one */
- stl->g_data->group = buffer_instance_mball_handles(psl->pass, draw_ctx->sh_cfg);
- }
-}
-
-/* Add geometry to shadingGroups. Execute for each objects */
-static void EDIT_METABALL_cache_populate(void *vedata, Object *ob)
-{
- // EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
- EDIT_METABALL_StorageList *stl = ((EDIT_METABALL_Data *)vedata)->stl;
-
- if (ob->type == OB_MBALL) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- DRWCallBuffer *group = stl->g_data->group;
-
- if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) {
- MetaBall *mb = ob->data;
-
- const float *color;
- const float col_radius[3] = {0.63, 0.19, 0.19}; /* 0x3030A0 */
- const float col_radius_select[3] = {0.94, 0.63, 0.63}; /* 0xA0A0F0 */
- const float col_stiffness[3] = {0.19, 0.63, 0.19}; /* 0x30A030 */
- const float col_stiffness_select[3] = {0.63, 0.94, 0.63}; /* 0xA0F0A0 */
-
- const bool is_select = DRW_state_is_select();
-
- float draw_scale_xform[3][4]; /* Matrix of Scale and Translation */
- {
- float scamat[3][3];
- copy_m3_m4(scamat, ob->obmat);
- /* Get the normalized inverse matrix to extract only
- * the scale of Scamat */
- float iscamat[3][3];
- invert_m3_m3(iscamat, scamat);
- normalize_m3(iscamat);
- mul_m3_m3_post(scamat, iscamat);
-
- copy_v3_v3(draw_scale_xform[0], scamat[0]);
- copy_v3_v3(draw_scale_xform[1], scamat[1]);
- copy_v3_v3(draw_scale_xform[2], scamat[2]);
- }
-
- const Object *orig_object = DEG_get_original_object(ob);
- int select_id = orig_object->runtime.select_id;
- for (MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next, select_id += 0x10000) {
- float world_pos[3];
- mul_v3_m4v3(world_pos, ob->obmat, &ml->x);
- draw_scale_xform[0][3] = world_pos[0];
- draw_scale_xform[1][3] = world_pos[1];
- draw_scale_xform[2][3] = world_pos[2];
-
- float draw_stiffness_radius = ml->rad * atanf(ml->s) / (float)M_PI_2;
-
- if ((ml->flag & SELECT) && (ml->flag & MB_SCALE_RAD)) {
- color = col_radius_select;
- }
- else {
- color = col_radius;
- }
-
- if (is_select) {
- DRW_select_load_id(select_id | MBALLSEL_RADIUS);
- }
-
- DRW_buffer_add_entry(group, draw_scale_xform, &ml->rad, color);
-
- if ((ml->flag & SELECT) && !(ml->flag & MB_SCALE_RAD)) {
- color = col_stiffness_select;
- }
- else {
- color = col_stiffness;
- }
-
- if (is_select) {
- DRW_select_load_id(select_id | MBALLSEL_STIFF);
- }
-
- DRW_buffer_add_entry(group, draw_scale_xform, &draw_stiffness_radius, color);
- }
- }
- }
-}
-
-/* Draw time ! Control rendering pipeline from here */
-static void EDIT_METABALL_draw_scene(void *vedata)
-{
- EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
- /* render passes on default framebuffer. */
- DRW_draw_pass(psl->pass);
-}
-
-/* Cleanup when destroying the engine.
- * This is not per viewport ! only when quitting blender.
- * Mostly used for freeing shaders */
-static void EDIT_METABALL_engine_free(void)
-{
- // DRW_SHADER_FREE_SAFE(custom_shader);
-}
-
-static const DrawEngineDataSize EDIT_METABALL_data_size = DRW_VIEWPORT_DATA_SIZE(
- EDIT_METABALL_Data);
-
-DrawEngineType draw_engine_edit_metaball_type = {
- NULL,
- NULL,
- N_("EditMetaballMode"),
- &EDIT_METABALL_data_size,
- NULL,
- &EDIT_METABALL_engine_free,
- &EDIT_METABALL_cache_init,
- &EDIT_METABALL_cache_populate,
- NULL,
- NULL, /* draw_background but not needed by mode engines */
- &EDIT_METABALL_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c
deleted file mode 100644
index 448dc33077e..00000000000
--- a/source/blender/draw/modes/edit_text_mode.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
-#include "DNA_curve_types.h"
-
-#include "BIF_glutil.h"
-
-#include "BKE_font.h"
-
-/* If builtin shaders are needed */
-#include "GPU_shader.h"
-
-#include "draw_common.h"
-#include "draw_mode_engines.h"
-
-/* *********** LISTS *********** */
-/* All lists are per viewport specific datas.
- * They are all free when viewport changes engines
- * or is free itself. Use EDIT_TEXT_engine_init() to
- * initialize most of them and EDIT_TEXT_cache_init()
- * for EDIT_TEXT_PassList */
-
-typedef struct EDIT_TEXT_PassList {
- /* Declare all passes here and init them in
- * EDIT_TEXT_cache_init().
- * Only contains (DRWPass *) */
- struct DRWPass *wire_pass;
- struct DRWPass *overlay_select_pass;
- struct DRWPass *overlay_cursor_pass;
- struct DRWPass *text_box_pass;
-} EDIT_TEXT_PassList;
-
-typedef struct EDIT_TEXT_FramebufferList {
- /* Contains all framebuffer objects needed by this engine.
- * Only contains (GPUFrameBuffer *) */
- struct GPUFrameBuffer *fb;
-} EDIT_TEXT_FramebufferList;
-
-typedef struct EDIT_TEXT_TextureList {
- /* Contains all framebuffer textures / utility textures
- * needed by this engine. Only viewport specific textures
- * (not per object). Only contains (GPUTexture *) */
- struct GPUTexture *texture;
-} EDIT_TEXT_TextureList;
-
-typedef struct EDIT_TEXT_StorageList {
- /* Contains any other memory block that the engine needs.
- * Only directly MEM_(m/c)allocN'ed blocks because they are
- * free with MEM_freeN() when viewport is freed.
- * (not per object) */
- struct CustomStruct *block;
- struct EDIT_TEXT_PrivateData *g_data;
-} EDIT_TEXT_StorageList;
-
-typedef struct EDIT_TEXT_Data {
- /* Struct returned by DRW_viewport_engine_data_ensure.
- * If you don't use one of these, just make it a (void *) */
- // void *fbl;
- void *engine_type; /* Required */
- EDIT_TEXT_FramebufferList *fbl;
- EDIT_TEXT_TextureList *txl;
- EDIT_TEXT_PassList *psl;
- EDIT_TEXT_StorageList *stl;
-} EDIT_TEXT_Data;
-
-/* *********** STATIC *********** */
-
-static struct {
- /* Custom shaders :
- * Add sources to source/blender/draw/modes/shaders
- * init in EDIT_TEXT_engine_init();
- * free in EDIT_TEXT_engine_free(); */
- GPUShader *wire_sh;
- GPUShader *overlay_select_sh;
- GPUShader *overlay_cursor_sh;
-} e_data = {NULL}; /* Engine data */
-
-typedef struct EDIT_TEXT_PrivateData {
- /* resulting curve as 'wire' for fast editmode drawing */
- DRWShadingGroup *wire_shgrp;
- DRWShadingGroup *overlay_select_shgrp;
- DRWShadingGroup *overlay_cursor_shgrp;
- DRWCallBuffer *box_shgrp;
- DRWCallBuffer *box_active_shgrp;
-} EDIT_TEXT_PrivateData; /* Transient data */
-
-/* *********** FUNCTIONS *********** */
-
-/* Init Textures, Framebuffers, Storage and Shaders.
- * It is called for every frames.
- * (Optional) */
-static void EDIT_TEXT_engine_init(void *vedata)
-{
- EDIT_TEXT_TextureList *txl = ((EDIT_TEXT_Data *)vedata)->txl;
- EDIT_TEXT_FramebufferList *fbl = ((EDIT_TEXT_Data *)vedata)->fbl;
- EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
-
- UNUSED_VARS(txl, fbl, stl);
-
- /* Init Framebuffers like this: order is attachment order (for color texs) */
- /*
- * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
- * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
- */
-
- /* DRW_framebuffer_init takes care of checking if
- * the framebuffer is valid and has the right size*/
- /*
- * float *viewport_size = DRW_viewport_size_get();
- * DRW_framebuffer_init(&fbl->occlude_wire_fb,
- * (int)viewport_size[0], (int)viewport_size[1],
- * tex, 2);
- */
-
- if (!e_data.wire_sh) {
- e_data.wire_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
- }
-
- if (!e_data.overlay_select_sh) {
- e_data.overlay_select_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
- }
-
- if (!e_data.overlay_cursor_sh) {
- e_data.overlay_cursor_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
- }
-}
-
-/* Here init all passes and shading groups
- * Assume that all Passes are NULL */
-static void EDIT_TEXT_cache_init(void *vedata)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
- EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- }
-
- {
- /* Text outline (fast drawing!) */
- psl->wire_pass = DRW_pass_create(
- "Font Wire", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
- stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);
-
- /* Show selection & cursor on-top of everything (x-ray). */
-
- psl->overlay_select_pass = DRW_pass_create("Font Select", DRW_STATE_WRITE_COLOR);
- stl->g_data->overlay_select_shgrp = DRW_shgroup_create(e_data.overlay_select_sh,
- psl->overlay_select_pass);
-
- psl->overlay_cursor_pass = DRW_pass_create("Font Cursor", DRW_STATE_WRITE_COLOR);
- stl->g_data->overlay_cursor_shgrp = DRW_shgroup_create(e_data.overlay_cursor_sh,
- psl->overlay_cursor_pass);
-
- psl->text_box_pass = DRW_pass_create("Font Text Boxes", DRW_STATE_WRITE_COLOR);
- stl->g_data->box_shgrp = buffer_dynlines_dashed_uniform_color(
- psl->text_box_pass, G_draw.block.colorWire, draw_ctx->sh_cfg);
- stl->g_data->box_active_shgrp = buffer_dynlines_dashed_uniform_color(
- psl->text_box_pass, G_draw.block.colorActive, draw_ctx->sh_cfg);
- }
-}
-
-/* Use 2D quad corners to create a matrix that set
- * a [-1..1] quad at the right position. */
-static void v2_quad_corners_to_mat4(float corners[4][2], float r_mat[4][4])
-{
- unit_m4(r_mat);
- sub_v2_v2v2(r_mat[0], corners[1], corners[0]);
- sub_v2_v2v2(r_mat[1], corners[3], corners[0]);
- mul_v2_fl(r_mat[0], 0.5f);
- mul_v2_fl(r_mat[1], 0.5f);
- copy_v2_v2(r_mat[3], corners[0]);
- add_v2_v2(r_mat[3], r_mat[0]);
- add_v2_v2(r_mat[3], r_mat[1]);
-}
-
-static void edit_text_cache_populate_select(void *vedata, Object *ob)
-{
- EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
- const Curve *cu = ob->data;
- EditFont *ef = cu->editfont;
- float final_mat[4][4], box[4][2];
- struct GPUBatch *geom = DRW_cache_quad_get();
-
- for (int i = 0; i < ef->selboxes_len; i++) {
- EditFontSelBox *sb = &ef->selboxes[i];
-
- float selboxw;
- if (i + 1 != ef->selboxes_len) {
- if (ef->selboxes[i + 1].y == sb->y) {
- selboxw = ef->selboxes[i + 1].x - sb->x;
- }
- else {
- selboxw = sb->w;
- }
- }
- else {
- selboxw = sb->w;
- }
- /* NOTE: v2_quad_corners_to_mat4 don't need the 3rd corner. */
- if (sb->rot == 0.0f) {
- copy_v2_fl2(box[0], sb->x, sb->y);
- copy_v2_fl2(box[1], sb->x + selboxw, sb->y);
- copy_v2_fl2(box[3], sb->x, sb->y + sb->h);
- }
- else {
- float mat[2][2];
- angle_to_mat2(mat, sb->rot);
- copy_v2_fl2(box[0], sb->x, sb->y);
- mul_v2_v2fl(box[1], mat[0], selboxw);
- add_v2_v2(box[1], &sb->x);
- mul_v2_v2fl(box[3], mat[1], sb->h);
- add_v2_v2(box[3], &sb->x);
- }
- v2_quad_corners_to_mat4(box, final_mat);
- mul_m4_m4m4(final_mat, ob->obmat, final_mat);
-
- DRW_shgroup_call_obmat(stl->g_data->overlay_select_shgrp, geom, final_mat);
- }
-}
-
-static void edit_text_cache_populate_cursor(void *vedata, Object *ob)
-{
- EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
- const Curve *cu = ob->data;
- EditFont *edit_font = cu->editfont;
- float(*cursor)[2] = edit_font->textcurs;
- float mat[4][4];
-
- v2_quad_corners_to_mat4(cursor, mat);
- mul_m4_m4m4(mat, ob->obmat, mat);
-
- struct GPUBatch *geom = DRW_cache_quad_get();
- DRW_shgroup_call_obmat(stl->g_data->overlay_cursor_shgrp, geom, mat);
-}
-
-static void edit_text_cache_populate_boxes(void *vedata, Object *ob)
-{
- EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
- const Curve *cu = ob->data;
-
- DRWCallBuffer *callbufs[] = {
- stl->g_data->box_active_shgrp,
- stl->g_data->box_shgrp,
- };
-
- float vec[3], vec1[3], vec2[3];
- for (int i = 0; i < cu->totbox; i++) {
- TextBox *tb = &cu->tb[i];
-
- if ((tb->w == 0.0f) && (tb->h == 0.0f)) {
- continue;
- }
-
- const bool is_active = i == (cu->actbox - 1);
- DRWCallBuffer *callbuf = callbufs[is_active ? 0 : 1];
-
- vec[0] = cu->xof + tb->x;
- vec[1] = cu->yof + tb->y + cu->fsize_realtime;
- vec[2] = 0.001;
-
- mul_v3_m4v3(vec1, ob->obmat, vec);
- vec[0] += tb->w;
- mul_v3_m4v3(vec2, ob->obmat, vec);
-
- DRW_buffer_add_entry(callbuf, vec1);
- DRW_buffer_add_entry(callbuf, vec2);
-
- vec[1] -= tb->h;
- copy_v3_v3(vec1, vec2);
- mul_v3_m4v3(vec2, ob->obmat, vec);
-
- DRW_buffer_add_entry(callbuf, vec1);
- DRW_buffer_add_entry(callbuf, vec2);
-
- vec[0] -= tb->w;
- copy_v3_v3(vec1, vec2);
- mul_v3_m4v3(vec2, ob->obmat, vec);
-
- DRW_buffer_add_entry(callbuf, vec1);
- DRW_buffer_add_entry(callbuf, vec2);
-
- vec[1] += tb->h;
- copy_v3_v3(vec1, vec2);
- mul_v3_m4v3(vec2, ob->obmat, vec);
-
- DRW_buffer_add_entry(callbuf, vec1);
- DRW_buffer_add_entry(callbuf, vec2);
- }
-}
-
-/* Add geometry to shadingGroups. Execute for each objects */
-static void EDIT_TEXT_cache_populate(void *vedata, Object *ob)
-{
- EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
- EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- UNUSED_VARS(psl, stl);
-
- if (ob->type == OB_FONT) {
- if (ob == draw_ctx->object_edit) {
- const Curve *cu = ob->data;
- /* Get geometry cache */
- struct GPUBatch *geom;
-
- bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f || cu->ext2 != 0.0f;
- if ((cu->flag & CU_FAST) || !has_surface) {
- geom = DRW_cache_text_edge_wire_get(ob);
- if (geom) {
- DRW_shgroup_call(stl->g_data->wire_shgrp, geom, ob);
- }
- }
- else {
- /* object mode draws */
- }
-
- edit_text_cache_populate_select(vedata, ob);
- edit_text_cache_populate_cursor(vedata, ob);
- edit_text_cache_populate_boxes(vedata, ob);
- }
- }
-}
-
-/* Optional: Post-cache_populate callback */
-static void EDIT_TEXT_cache_finish(void *vedata)
-{
- EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
- EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
-
- /* Do something here! dependent on the objects gathered */
- UNUSED_VARS(psl, stl);
-}
-
-/* Draw time ! Control rendering pipeline from here */
-static void EDIT_TEXT_draw_scene(void *vedata)
-{
- EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
- EDIT_TEXT_FramebufferList *fbl = ((EDIT_TEXT_Data *)vedata)->fbl;
-
- /* Default framebuffer and texture */
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- UNUSED_VARS(fbl, dfbl, dtxl);
-
- /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
- /*
- * DRW_framebuffer_texture_detach(dtxl->depth);
- * DRW_framebuffer_bind(fbl->custom_fb);
- * DRW_draw_pass(psl->pass);
- * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
- * DRW_framebuffer_bind(dfbl->default_fb);
- */
-
- DRW_draw_pass(psl->wire_pass);
-
- if (!DRW_pass_is_empty(psl->text_box_pass)) {
- DRW_draw_pass(psl->text_box_pass);
- }
-
- GPU_logic_op_invert_set(true);
- DRW_draw_pass(psl->overlay_select_pass);
- DRW_draw_pass(psl->overlay_cursor_pass);
- GPU_logic_op_invert_set(false);
-
- /* If you changed framebuffer, double check you rebind
- * the default one with its textures attached before finishing */
-}
-
-/* Cleanup when destroying the engine.
- * This is not per viewport ! only when quitting blender.
- * Mostly used for freeing shaders */
-static void EDIT_TEXT_engine_free(void)
-{
- // DRW_SHADER_FREE_SAFE(custom_shader);
-}
-
-static const DrawEngineDataSize EDIT_TEXT_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_TEXT_Data);
-
-DrawEngineType draw_engine_edit_text_type = {
- NULL,
- NULL,
- N_("EditTextMode"),
- &EDIT_TEXT_data_size,
- &EDIT_TEXT_engine_init,
- &EDIT_TEXT_engine_free,
- &EDIT_TEXT_cache_init,
- &EDIT_TEXT_cache_populate,
- &EDIT_TEXT_cache_finish,
- NULL, /* draw_background but not needed by mode engines */
- &EDIT_TEXT_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
deleted file mode 100644
index 80793726afe..00000000000
--- a/source/blender/draw/modes/object_mode.c
+++ /dev/null
@@ -1,3930 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
-#include "DNA_userdef_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_force_types.h"
-#include "DNA_lightprobe_types.h"
-#include "DNA_particle_types.h"
-#include "DNA_rigidbody_types.h"
-#include "DNA_smoke_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_world_types.h"
-
-#include "BKE_anim.h"
-#include "BKE_camera.h"
-#include "BKE_constraint.h"
-#include "BKE_curve.h"
-#include "BKE_editmesh.h"
-#include "BKE_image.h"
-#include "BKE_mball.h"
-#include "BKE_mesh.h"
-#include "BKE_modifier.h"
-#include "BKE_movieclip.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_tracking.h"
-
-#include "BLI_ghash.h"
-
-#include "IMB_imbuf_types.h"
-
-#include "ED_view3d.h"
-
-#include "GPU_batch.h"
-#include "GPU_draw.h"
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "UI_resources.h"
-
-#include "draw_mode_engines.h"
-#include "draw_manager_text.h"
-#include "draw_common.h"
-
-#include "DEG_depsgraph_query.h"
-
-extern char datatoc_object_outline_prepass_vert_glsl[];
-extern char datatoc_object_outline_prepass_geom_glsl[];
-extern char datatoc_object_outline_prepass_frag_glsl[];
-extern char datatoc_object_outline_resolve_frag_glsl[];
-extern char datatoc_object_outline_detect_frag_glsl[];
-extern char datatoc_object_outline_expand_frag_glsl[];
-extern char datatoc_object_grid_frag_glsl[];
-extern char datatoc_object_grid_vert_glsl[];
-extern char datatoc_object_camera_image_frag_glsl[];
-extern char datatoc_object_camera_image_vert_glsl[];
-extern char datatoc_object_empty_image_frag_glsl[];
-extern char datatoc_object_empty_image_vert_glsl[];
-extern char datatoc_object_lightprobe_grid_vert_glsl[];
-extern char datatoc_object_loose_points_frag_glsl[];
-extern char datatoc_object_particle_prim_vert_glsl[];
-extern char datatoc_object_particle_dot_vert_glsl[];
-extern char datatoc_object_particle_dot_frag_glsl[];
-extern char datatoc_common_colormanagement_lib_glsl[];
-extern char datatoc_common_globals_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_common_fxaa_lib_glsl[];
-extern char datatoc_gpu_shader_flat_color_frag_glsl[];
-extern char datatoc_gpu_shader_flat_id_frag_glsl[];
-extern char datatoc_common_fullscreen_vert_glsl[];
-extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
-extern char datatoc_gpu_shader_3D_vert_glsl[];
-
-/* *********** LISTS *********** */
-typedef struct OBJECT_PassList {
- struct DRWPass *non_meshes[2];
- struct DRWPass *image_empties[2];
- struct DRWPass *transp_shapes[2];
- struct DRWPass *ob_center;
- struct DRWPass *outlines;
- struct DRWPass *outlines_search;
- struct DRWPass *outlines_expand;
- struct DRWPass *outlines_bleed;
- struct DRWPass *outlines_resolve;
- struct DRWPass *grid;
- struct DRWPass *bone_solid[2];
- struct DRWPass *bone_outline[2];
- struct DRWPass *bone_wire[2];
- struct DRWPass *bone_envelope[2];
- struct DRWPass *bone_axes[2];
- struct DRWPass *particle;
- struct DRWPass *lightprobes;
- struct DRWPass *camera_images_back_alpha_under;
- struct DRWPass *camera_images_back_alpha_over;
- struct DRWPass *camera_images_front_alpha_over;
-} OBJECT_PassList;
-
-typedef struct OBJECT_FramebufferList {
- struct GPUFrameBuffer *outlines_fb;
- struct GPUFrameBuffer *blur_fb;
- struct GPUFrameBuffer *expand_fb;
- struct GPUFrameBuffer *ghost_fb;
-} OBJECT_FramebufferList;
-
-typedef struct OBJECT_StorageList {
- struct OBJECT_PrivateData *g_data;
-} OBJECT_StorageList;
-
-typedef struct OBJECT_Data {
- void *engine_type;
- OBJECT_FramebufferList *fbl;
- DRWViewportEmptyList *txl;
- OBJECT_PassList *psl;
- OBJECT_StorageList *stl;
-} OBJECT_Data;
-
-typedef struct OBJECT_Shaders {
- /* fullscreen shaders */
- GPUShader *outline_prepass;
- GPUShader *outline_prepass_wire;
- GPUShader *outline_resolve;
- GPUShader *outline_resolve_aa;
- GPUShader *outline_detect;
- GPUShader *outline_detect_wire;
- GPUShader *outline_fade;
- GPUShader *outline_fade_large;
-
- /* regular shaders */
- GPUShader *object_camera_image;
- GPUShader *object_camera_image_cm;
- GPUShader *object_empty_image;
- GPUShader *object_empty_image_wire;
- GPUShader *grid;
- GPUShader *part_dot;
- GPUShader *part_prim;
- GPUShader *part_axis;
- GPUShader *lightprobe_grid;
- GPUShader *loose_points;
-} OBJECT_Shaders;
-
-/* *********** STATIC *********** */
-
-typedef struct OBJECT_ShadingGroupList {
- /* Reference only */
- struct DRWPass *non_meshes;
- struct DRWPass *image_empties;
- struct DRWPass *transp_shapes;
- struct DRWPass *bone_solid;
- struct DRWPass *bone_outline;
- struct DRWPass *bone_wire;
- struct DRWPass *bone_envelope;
- struct DRWPass *bone_axes;
-
- /* Empties */
- DRWEmptiesBufferList empties;
-
- /* Force Field */
- DRWCallBuffer *field_wind;
- DRWCallBuffer *field_force;
- DRWCallBuffer *field_vortex;
- DRWCallBuffer *field_curve_sta;
- DRWCallBuffer *field_curve_end;
- DRWCallBuffer *field_tube_limit;
- DRWCallBuffer *field_cone_limit;
-
- /* Grease Pencil */
- DRWCallBuffer *gpencil_axes;
-
- /* Speaker */
- DRWCallBuffer *speaker;
-
- /* Probe */
- DRWCallBuffer *probe_cube;
- DRWCallBuffer *probe_planar;
- DRWCallBuffer *probe_grid;
-
- /* MetaBalls */
- DRWCallBuffer *mball_handle;
-
- /* Lights */
- DRWCallBuffer *light_center;
- DRWCallBuffer *light_groundpoint;
- DRWCallBuffer *light_groundline;
- DRWCallBuffer *light_circle;
- DRWCallBuffer *light_circle_shadow;
- DRWCallBuffer *light_sunrays;
- DRWCallBuffer *light_distance;
- DRWCallBuffer *light_buflimit;
- DRWCallBuffer *light_buflimit_points;
- DRWCallBuffer *light_area_sphere;
- DRWCallBuffer *light_area_square;
- DRWCallBuffer *light_area_disk;
- DRWCallBuffer *light_hemi;
- DRWCallBuffer *light_spot_cone;
- DRWCallBuffer *light_spot_blend;
- DRWCallBuffer *light_spot_pyramid;
- DRWCallBuffer *light_spot_blend_rect;
- DRWCallBuffer *light_spot_volume;
- DRWCallBuffer *light_spot_volume_rect;
- DRWCallBuffer *light_spot_volume_outside;
- DRWCallBuffer *light_spot_volume_rect_outside;
-
- /* Helpers */
- DRWCallBuffer *relationship_lines;
- DRWCallBuffer *constraint_lines;
- DRWCallBuffer *origin_xform;
-
- /* Camera */
- DRWCallBuffer *camera;
- DRWCallBuffer *camera_frame;
- DRWCallBuffer *camera_tria;
- DRWCallBuffer *camera_focus;
- DRWCallBuffer *camera_clip;
- DRWCallBuffer *camera_clip_points;
- DRWCallBuffer *camera_mist;
- DRWCallBuffer *camera_mist_points;
- DRWCallBuffer *camera_stereo_plane;
- DRWCallBuffer *camera_stereo_plane_wires;
- DRWCallBuffer *camera_stereo_volume;
- DRWCallBuffer *camera_stereo_volume_wires;
- ListBase camera_path;
-
- /* Wire */
- DRWShadingGroup *wire;
- DRWShadingGroup *wire_active;
- DRWShadingGroup *wire_select;
- DRWShadingGroup *wire_transform;
- /* Wire (duplicator) */
- DRWShadingGroup *wire_dupli;
- DRWShadingGroup *wire_dupli_select;
-
- /* Points */
- DRWShadingGroup *points;
- DRWShadingGroup *points_active;
- DRWShadingGroup *points_select;
- DRWShadingGroup *points_transform;
- /* Points (duplicator) */
- DRWShadingGroup *points_dupli;
- DRWShadingGroup *points_dupli_select;
-
- /* Texture Space */
- DRWCallBuffer *texspace;
-} OBJECT_ShadingGroupList;
-
-typedef struct OBJECT_PrivateData {
- OBJECT_ShadingGroupList sgl;
- OBJECT_ShadingGroupList sgl_ghost;
-
- GHash *custom_shapes;
-
- /* Outlines */
- DRWShadingGroup *outlines_active;
- DRWShadingGroup *outlines_select;
- DRWShadingGroup *outlines_select_dupli;
- DRWShadingGroup *outlines_transform;
-
- /* Lightprobes */
- DRWShadingGroup *probe_outlines_transform;
- DRWShadingGroup *probe_outlines_select;
- DRWShadingGroup *probe_outlines_select_dupli;
- DRWShadingGroup *probe_outlines_active;
-
- /* Objects Centers */
- DRWCallBuffer *center_active;
- DRWCallBuffer *center_selected;
- DRWCallBuffer *center_deselected;
- DRWCallBuffer *center_selected_lib;
- DRWCallBuffer *center_deselected_lib;
-
- bool xray_enabled;
- bool xray_enabled_and_not_wire;
-} OBJECT_PrivateData; /* Transient data */
-
-typedef struct OBJECT_DupliData {
- DRWShadingGroup *outline_shgrp;
- GPUBatch *outline_geom;
- DRWShadingGroup *extra_shgrp;
- GPUBatch *extra_geom;
- short base_flag;
-} OBJECT_DupliData;
-
-static struct {
- /* Instance Data format */
- struct GPUVertFormat *empty_image_format;
- struct GPUVertFormat *empty_image_wire_format;
-
- OBJECT_Shaders sh_data[GPU_SHADER_CFG_LEN];
-
- float grid_distance;
- float grid_mesh_size;
- int grid_flag;
- float grid_axes[3];
- int zpos_flag;
- int zneg_flag;
- float zplane_axes[3];
- float inv_viewport_size[2];
- float grid_steps[8];
- bool draw_grid;
- /* Temp buffer textures */
- struct GPUTexture *outlines_depth_tx;
- struct GPUTexture *outlines_id_tx;
- struct GPUTexture *outlines_color_tx;
- struct GPUTexture *outlines_blur_tx;
-
- ListBase smoke_domains;
- ListBase movie_clips;
-} e_data = {NULL}; /* Engine data */
-
-enum {
- SHOW_AXIS_X = (1 << 0),
- SHOW_AXIS_Y = (1 << 1),
- SHOW_AXIS_Z = (1 << 2),
- SHOW_GRID = (1 << 3),
- PLANE_XY = (1 << 4),
- PLANE_XZ = (1 << 5),
- PLANE_YZ = (1 << 6),
- CLIP_ZPOS = (1 << 7),
- CLIP_ZNEG = (1 << 8),
- GRID_BACK = (1 << 9),
-};
-
-/* Prototypes. */
-static void DRW_shgroup_empty_ex(OBJECT_ShadingGroupList *sgl,
- const float mat[4][4],
- const float *draw_size,
- char draw_type,
- const float color[4]);
-
-/* *********** FUNCTIONS *********** */
-
-static void OBJECT_engine_init(void *vedata)
-{
- OBJECT_FramebufferList *fbl = ((OBJECT_Data *)vedata)->fbl;
-
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
-
- if (DRW_state_is_fbo()) {
- e_data.outlines_depth_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_object_type);
- /* XXX TODO GPU_R16UI can overflow, it would cause no harm
- * (only bad colored or missing outlines) but we should
- * use 32bits only if the scene have that many objects */
- e_data.outlines_id_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_R16UI, &draw_engine_object_type);
-
- GPU_framebuffer_ensure_config(&fbl->outlines_fb,
- {GPU_ATTACHMENT_TEXTURE(e_data.outlines_depth_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.outlines_id_tx)});
-
- e_data.outlines_color_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA8, &draw_engine_object_type);
-
- GPU_framebuffer_ensure_config(
- &fbl->expand_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(e_data.outlines_color_tx)});
-
- e_data.outlines_blur_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA8, &draw_engine_object_type);
-
- GPU_framebuffer_ensure_config(
- &fbl->blur_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(e_data.outlines_blur_tx)});
- }
-
- /* Shaders */
- const DRWContextState *draw_ctx = DRW_context_state_get();
- OBJECT_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
-
- if (!sh_data->outline_resolve) {
- /* Outline */
- sh_data->outline_prepass = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_object_outline_prepass_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- sh_data->outline_prepass_wire = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_object_outline_prepass_vert_glsl,
- NULL},
- .geom = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_object_outline_prepass_geom_glsl,
- NULL},
- .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define USE_GEOM\n", NULL},
- });
-
- sh_data->outline_resolve = DRW_shader_create_fullscreen(
- datatoc_object_outline_resolve_frag_glsl, NULL);
-
- sh_data->outline_resolve_aa = DRW_shader_create_with_lib(
- datatoc_common_fullscreen_vert_glsl,
- NULL,
- datatoc_object_outline_resolve_frag_glsl,
- datatoc_common_fxaa_lib_glsl,
- "#define FXAA_ALPHA\n"
- "#define USE_FXAA\n");
-
- sh_data->outline_detect = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
- NULL,
- datatoc_object_outline_detect_frag_glsl,
- datatoc_common_globals_lib_glsl,
- NULL);
-
- sh_data->outline_detect_wire = DRW_shader_create_with_lib(
- datatoc_common_fullscreen_vert_glsl,
- NULL,
- datatoc_object_outline_detect_frag_glsl,
- datatoc_common_globals_lib_glsl,
- "#define WIRE\n");
-
- sh_data->outline_fade = DRW_shader_create_fullscreen(datatoc_object_outline_expand_frag_glsl,
- NULL);
- sh_data->outline_fade_large = DRW_shader_create_fullscreen(
- datatoc_object_outline_expand_frag_glsl, "#define LARGE_OUTLINE\n");
-
- /* Empty images */
- {
- const char *empty_image_defs = (
- "#define DEPTH_UNCHANGED " STRINGIFY(OB_EMPTY_IMAGE_DEPTH_DEFAULT) "\n"
- "#define DEPTH_FRONT " STRINGIFY(OB_EMPTY_IMAGE_DEPTH_FRONT) "\n"
- "#define DEPTH_BACK " STRINGIFY(OB_EMPTY_IMAGE_DEPTH_BACK) "\n");
-
- sh_data->object_empty_image = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_object_empty_image_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
- datatoc_object_empty_image_frag_glsl,
- NULL},
- .defs = (const char *[]){sh_cfg_data->def, empty_image_defs, NULL},
- });
- sh_data->object_empty_image_wire = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_object_empty_image_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_object_empty_image_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define USE_WIRE\n", empty_image_defs, NULL},
- });
-
- sh_data->object_camera_image_cm = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_camera_image_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
- datatoc_object_camera_image_frag_glsl,
- NULL},
- .defs =
- (const char *[]){sh_cfg_data->def, "#define DRW_STATE_DO_COLOR_MANAGEMENT\n", NULL},
- });
- sh_data->object_camera_image = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_camera_image_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
- datatoc_object_camera_image_frag_glsl,
- NULL},
- });
- }
-
- /* Grid */
- sh_data->grid = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_object_grid_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_object_grid_frag_glsl,
- NULL},
- });
-
- /* Particles */
- sh_data->part_prim = DRW_shader_create_with_lib(datatoc_object_particle_prim_vert_glsl,
- NULL,
- datatoc_gpu_shader_flat_color_frag_glsl,
- datatoc_common_view_lib_glsl,
- "#define IN_PLACE_INSTANCES\n");
-
- sh_data->part_axis = DRW_shader_create_with_lib(datatoc_object_particle_prim_vert_glsl,
- NULL,
- datatoc_gpu_shader_flat_color_frag_glsl,
- datatoc_common_view_lib_glsl,
- "#define IN_PLACE_INSTANCES\n"
- "#define USE_AXIS\n");
-
- sh_data->part_dot = DRW_shader_create_with_lib(datatoc_object_particle_dot_vert_glsl,
- NULL,
- datatoc_object_particle_dot_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
-
- /* Lightprobes */
- sh_data->lightprobe_grid = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_common_globals_lib_glsl,
- datatoc_object_lightprobe_grid_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
-
- /* Loose Points */
- sh_data->loose_points = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_gpu_shader_3D_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_object_loose_points_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- {
- /* Grid precompute */
- float viewinv[4][4], wininv[4][4];
- float viewmat[4][4], winmat[4][4];
- View3D *v3d = draw_ctx->v3d;
- Scene *scene = draw_ctx->scene;
- RegionView3D *rv3d = draw_ctx->rv3d;
-
- const bool show_axis_x = (v3d->gridflag & V3D_SHOW_X) != 0;
- const bool show_axis_y = (v3d->gridflag & V3D_SHOW_Y) != 0;
- const bool show_axis_z = (v3d->gridflag & V3D_SHOW_Z) != 0;
- const bool show_floor = (v3d->gridflag & V3D_SHOW_FLOOR) != 0;
- const bool show_ortho_grid = (v3d->gridflag & V3D_SHOW_ORTHO_GRID) != 0;
- e_data.draw_grid = show_axis_x || show_axis_y || show_axis_z || show_floor;
-
- DRW_view_winmat_get(NULL, winmat, false);
- DRW_view_winmat_get(NULL, wininv, true);
- DRW_view_viewmat_get(NULL, viewmat, false);
- DRW_view_viewmat_get(NULL, viewinv, true);
-
- /* if perps */
- if (winmat[3][3] == 0.0f) {
- e_data.grid_flag = (1 << 4); /* XY plane */
- if (show_axis_x) {
- e_data.grid_flag |= SHOW_AXIS_X;
- }
- if (show_axis_y) {
- e_data.grid_flag |= SHOW_AXIS_Y;
- }
- if (show_floor) {
- e_data.grid_flag |= SHOW_GRID;
- }
- }
- else {
- if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) {
- e_data.draw_grid = show_ortho_grid;
- e_data.grid_flag = PLANE_YZ | SHOW_AXIS_Y | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK;
- }
- else if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
- e_data.draw_grid = show_ortho_grid;
- e_data.grid_flag = PLANE_XY | SHOW_AXIS_X | SHOW_AXIS_Y | SHOW_GRID | GRID_BACK;
- }
- else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
- e_data.draw_grid = show_ortho_grid;
- e_data.grid_flag = PLANE_XZ | SHOW_AXIS_X | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK;
- }
- else { /* RV3D_VIEW_USER */
- e_data.grid_flag = PLANE_XY;
- if (show_axis_x) {
- e_data.grid_flag |= SHOW_AXIS_X;
- }
- if (show_axis_y) {
- e_data.grid_flag |= SHOW_AXIS_Y;
- }
- if (show_floor) {
- e_data.grid_flag |= SHOW_GRID;
- }
- }
- }
-
- e_data.grid_axes[0] = (float)((e_data.grid_flag & (PLANE_XZ | PLANE_XY)) != 0);
- e_data.grid_axes[1] = (float)((e_data.grid_flag & (PLANE_YZ | PLANE_XY)) != 0);
- e_data.grid_axes[2] = (float)((e_data.grid_flag & (PLANE_YZ | PLANE_XZ)) != 0);
-
- /* Z axis if needed */
- if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) {
- e_data.zpos_flag = SHOW_AXIS_Z;
-
- float zvec[3], campos[3];
- negate_v3_v3(zvec, viewinv[2]);
- copy_v3_v3(campos, viewinv[3]);
-
- /* z axis : chose the most facing plane */
- if (fabsf(zvec[0]) < fabsf(zvec[1])) {
- e_data.zpos_flag |= PLANE_XZ;
- }
- else {
- e_data.zpos_flag |= PLANE_YZ;
- }
-
- e_data.zneg_flag = e_data.zpos_flag;
-
- /* Persp : If camera is below floor plane, we switch clipping
- * Ortho : If eye vector is looking up, we switch clipping */
- if (((winmat[3][3] == 0.0f) && (campos[2] > 0.0f)) ||
- ((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f))) {
- e_data.zpos_flag |= CLIP_ZPOS;
- e_data.zneg_flag |= CLIP_ZNEG;
- }
- else {
- e_data.zpos_flag |= CLIP_ZNEG;
- e_data.zneg_flag |= CLIP_ZPOS;
- }
-
- e_data.zplane_axes[0] = (float)((e_data.zpos_flag & (PLANE_XZ | PLANE_XY)) != 0);
- e_data.zplane_axes[1] = (float)((e_data.zpos_flag & (PLANE_YZ | PLANE_XY)) != 0);
- e_data.zplane_axes[2] = (float)((e_data.zpos_flag & (PLANE_YZ | PLANE_XZ)) != 0);
- }
- else {
- e_data.zneg_flag = e_data.zpos_flag = CLIP_ZNEG | CLIP_ZPOS;
- }
-
- float dist;
- if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) {
- Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
- dist = ((Camera *)(camera_object->data))->clip_end;
- }
- else {
- dist = v3d->clip_end;
- }
-
- e_data.grid_distance = dist / 2.0f; /* gridDistance */
-
- if (winmat[3][3] == 0.0f) {
- e_data.grid_mesh_size = dist;
- }
- else {
- float viewdist = 1.0f / min_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1]));
- e_data.grid_mesh_size = viewdist * dist;
- }
-
- ED_view3d_grid_steps(scene, v3d, rv3d, e_data.grid_steps);
- }
-
- copy_v2_v2(e_data.inv_viewport_size, DRW_viewport_size_get());
- invert_v2(e_data.inv_viewport_size);
-}
-
-static void OBJECT_engine_free(void)
-{
- MEM_SAFE_FREE(e_data.empty_image_format);
- MEM_SAFE_FREE(e_data.empty_image_wire_format);
-
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- OBJECT_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- GPUShader **sh_data_as_array = (GPUShader **)sh_data;
- for (int i = 0; i < (sizeof(OBJECT_Shaders) / sizeof(GPUShader *)); i++) {
- DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
- }
- }
-}
-
-static DRWShadingGroup *shgroup_outline(DRWPass *pass,
- int outline_id,
- GPUShader *sh,
- eGPUShaderConfig sh_cfg)
-{
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
-
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return grp;
-}
-
-/* currently same as 'shgroup_outline', new function to avoid confustion */
-static DRWShadingGroup *shgroup_wire(DRWPass *pass,
- const float col[4],
- GPUShader *sh,
- eGPUShaderConfig sh_cfg)
-{
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_vec4(grp, "color", col, 1);
-
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return grp;
-}
-
-/* currently same as 'shgroup_outline', new function to avoid confustion */
-static DRWShadingGroup *shgroup_points(DRWPass *pass,
- const float col[4],
- GPUShader *sh,
- eGPUShaderConfig sh_cfg)
-{
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_vec4(grp, "color", col, 1);
- DRW_shgroup_uniform_vec4(grp, "innerColor", G_draw.block.colorEditMeshMiddle, 1);
-
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- return grp;
-}
-
-static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
-{
- if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
- switch (theme_id) {
- case TH_ACTIVE:
- case TH_SELECT:
- return stl->g_data->outlines_select_dupli;
- case TH_TRANSFORM:
- return stl->g_data->outlines_transform;
- default:
- return NULL;
- }
- }
-
- switch (theme_id) {
- case TH_ACTIVE:
- return stl->g_data->outlines_active;
- case TH_SELECT:
- return stl->g_data->outlines_select;
- case TH_TRANSFORM:
- return stl->g_data->outlines_transform;
- default:
- return NULL;
- }
-}
-
-static DRWShadingGroup *shgroup_theme_id_to_probe_outline_or_null(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
-{
- if (UNLIKELY(DRW_state_is_select())) {
- return stl->g_data->probe_outlines_select;
- }
-
- if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
- switch (theme_id) {
- case TH_ACTIVE:
- case TH_SELECT:
- return stl->g_data->probe_outlines_select_dupli;
- case TH_TRANSFORM:
- return stl->g_data->probe_outlines_transform;
- default:
- return NULL;
- }
- }
-
- switch (theme_id) {
- case TH_ACTIVE:
- return stl->g_data->probe_outlines_active;
- case TH_SELECT:
- return stl->g_data->probe_outlines_select;
- case TH_TRANSFORM:
- return stl->g_data->probe_outlines_transform;
- default:
- return NULL;
- }
-}
-
-static int shgroup_theme_id_to_outline_id(int theme_id, const int base_flag)
-{
- if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
- switch (theme_id) {
- case TH_ACTIVE:
- case TH_SELECT:
- return 2;
- case TH_TRANSFORM:
- return 0;
- default:
- return -1;
- }
- }
-
- switch (theme_id) {
- case TH_ACTIVE:
- return 3;
- case TH_SELECT:
- return 1;
- case TH_TRANSFORM:
- return 0;
- default:
- return -1;
- }
-}
-
-static DRWShadingGroup *shgroup_theme_id_to_wire(OBJECT_ShadingGroupList *sgl,
- int theme_id,
- const short base_flag)
-{
- if (UNLIKELY(base_flag & BASE_FROM_SET)) {
- return sgl->wire_dupli;
- }
- else if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
- switch (theme_id) {
- case TH_ACTIVE:
- case TH_SELECT:
- return sgl->wire_dupli_select;
- case TH_TRANSFORM:
- return sgl->wire_transform;
- default:
- return sgl->wire_dupli;
- }
- }
-
- switch (theme_id) {
- case TH_ACTIVE:
- return sgl->wire_active;
- case TH_SELECT:
- return sgl->wire_select;
- case TH_TRANSFORM:
- return sgl->wire_transform;
- default:
- return sgl->wire;
- }
-}
-
-static DRWShadingGroup *shgroup_theme_id_to_point(OBJECT_ShadingGroupList *sgl,
- int theme_id,
- const short base_flag)
-{
- if (UNLIKELY(base_flag & BASE_FROM_SET)) {
- return sgl->points_dupli;
- }
- else if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
- switch (theme_id) {
- case TH_ACTIVE:
- case TH_SELECT:
- return sgl->points_dupli_select;
- case TH_TRANSFORM:
- return sgl->points_transform;
- default:
- return sgl->points_dupli;
- }
- }
-
- switch (theme_id) {
- case TH_ACTIVE:
- return sgl->points_active;
- case TH_SELECT:
- return sgl->points_select;
- case TH_TRANSFORM:
- return sgl->points_transform;
- default:
- return sgl->points;
- }
-}
-
-static void image_calc_aspect(Image *ima, const int size[2], float r_image_aspect[2])
-{
- float ima_x, ima_y;
- if (ima) {
- ima_x = size[0];
- ima_y = size[1];
- }
- else {
- /* if no image, make it a 1x1 empty square, honor scale & offset */
- ima_x = ima_y = 1.0f;
- }
- /* Get the image aspect even if the buffer is invalid */
- float sca_x = 1.0f, sca_y = 1.0f;
- if (ima) {
- if (ima->aspx > ima->aspy) {
- sca_y = ima->aspy / ima->aspx;
- }
- else if (ima->aspx < ima->aspy) {
- sca_x = ima->aspx / ima->aspy;
- }
- }
-
- const float scale_x_inv = ima_x * sca_x;
- const float scale_y_inv = ima_y * sca_y;
- if (scale_x_inv > scale_y_inv) {
- r_image_aspect[0] = 1.0f;
- r_image_aspect[1] = scale_y_inv / scale_x_inv;
- }
- else {
- r_image_aspect[0] = scale_x_inv / scale_y_inv;
- r_image_aspect[1] = 1.0f;
- }
-}
-
-static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data,
- OBJECT_ShadingGroupList *sgl,
- Object *ob,
- const float color[3],
- RegionView3D *rv3d,
- eGPUShaderConfig sh_cfg)
-{
- /* TODO: 'StereoViews', see draw_empty_image. */
-
- if (!BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d)) {
- return;
- }
-
- /* Calling 'BKE_image_get_size' may free the texture. Get the size from 'tex' instead,
- * see: T59347 */
- int size[2] = {0};
-
- const bool use_alpha_blend = (ob->empty_image_flag & OB_EMPTY_IMAGE_USE_ALPHA_BLEND) != 0;
- GPUTexture *tex = NULL;
- Image *ima = ob->data;
-
- if (ima != NULL) {
- tex = GPU_texture_from_blender(ima, ob->iuser, GL_TEXTURE_2D);
- if (tex) {
- size[0] = GPU_texture_orig_width(tex);
- size[1] = GPU_texture_orig_height(tex);
- }
- }
-
- CLAMP_MIN(size[0], 1);
- CLAMP_MIN(size[1], 1);
-
- float image_aspect[2];
- image_calc_aspect(ob->data, size, image_aspect);
-
- char depth_mode;
- if (DRW_state_is_depth()) {
- /* Use the actual depth if we are doing depth tests to determine the distance to the object */
- depth_mode = OB_EMPTY_IMAGE_DEPTH_DEFAULT;
- }
- else {
- depth_mode = ob->empty_image_depth;
- }
-
- {
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->object_empty_image_wire, sgl->non_meshes);
- DRW_shgroup_uniform_vec2_copy(grp, "aspect", image_aspect);
- DRW_shgroup_uniform_int_copy(grp, "depthMode", depth_mode);
- DRW_shgroup_uniform_float(grp, "size", &ob->empty_drawsize, 1);
- DRW_shgroup_uniform_vec2(grp, "offset", ob->ima_ofs, 1);
- DRW_shgroup_uniform_vec3(grp, "color", color, 1);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- DRW_shgroup_call_no_cull(grp, DRW_cache_image_plane_wire_get(), ob);
- }
-
- if (!BKE_object_empty_image_data_is_visible_in_view3d(ob, rv3d)) {
- return;
- }
-
- if (tex && ((ob->color[3] > 0.0f) || !use_alpha_blend)) {
- DRWShadingGroup *grp = DRW_shgroup_create(
- sh_data->object_empty_image, (use_alpha_blend) ? sgl->image_empties : sgl->non_meshes);
- DRW_shgroup_uniform_vec2_copy(grp, "aspect", image_aspect);
- DRW_shgroup_uniform_int_copy(grp, "depthMode", depth_mode);
- DRW_shgroup_uniform_float(grp, "size", &ob->empty_drawsize, 1);
- DRW_shgroup_uniform_vec2(grp, "offset", ob->ima_ofs, 1);
- DRW_shgroup_uniform_texture(grp, "image", tex);
- DRW_shgroup_uniform_bool_copy(
- grp, "imagePremultiplied", (ima->alpha_mode == IMA_ALPHA_PREMUL));
- DRW_shgroup_uniform_vec4(grp, "objectColor", ob->color, 1);
- DRW_shgroup_uniform_bool_copy(grp, "useAlphaTest", !use_alpha_blend);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- DRW_shgroup_call_no_cull(grp, DRW_cache_image_plane_get(), ob);
- }
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Camera Background Images
- * \{ */
-typedef struct CameraEngineData {
- DrawData dd;
- ListBase bg_data;
-} CameraEngineData;
-
-typedef struct CameraEngineBGData {
- CameraBGImage *camera_image;
- GPUTexture *texture;
- float transform_mat[4][4];
- bool premultiplied;
-} CameraEngineBGData;
-
-static void camera_engine_data_free(DrawData *dd)
-{
- CameraEngineData *data = (CameraEngineData *)dd;
- for (LinkData *link = data->bg_data.first; link; link = link->next) {
- CameraEngineBGData *bg_data = (CameraEngineBGData *)link->data;
- MEM_freeN(bg_data);
- }
- BLI_freelistN(&data->bg_data);
-}
-
-static void camera_background_images_stereo_setup(Scene *scene,
- View3D *v3d,
- Image *ima,
- ImageUser *iuser)
-{
- if (BKE_image_is_stereo(ima)) {
- iuser->flag |= IMA_SHOW_STEREO;
-
- if ((scene->r.scemode & R_MULTIVIEW) == 0) {
- iuser->multiview_eye = STEREO_LEFT_ID;
- }
- else if (v3d->stereo3d_camera != STEREO_3D_ID) {
- /* show only left or right camera */
- iuser->multiview_eye = v3d->stereo3d_camera;
- }
-
- BKE_image_multiview_index(ima, iuser);
- }
- else {
- iuser->flag &= ~IMA_SHOW_STEREO;
- }
-}
-static void camera_background_images_add_shgroup(DRWPass *pass,
- CameraEngineBGData *bg_data,
- GPUShader *shader,
- GPUBatch *batch)
-{
- CameraBGImage *camera_image = bg_data->camera_image;
- DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
-
- DRW_shgroup_uniform_float_copy(
- grp, "depth", camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND ? 0.000001f : 0.999999f);
- DRW_shgroup_uniform_float_copy(grp, "alpha", camera_image->alpha);
- DRW_shgroup_uniform_texture(grp, "image", bg_data->texture);
- DRW_shgroup_uniform_bool_copy(grp, "imagePremultiplied", bg_data->premultiplied);
- DRW_shgroup_uniform_float_copy(
- grp, "flipX", (camera_image->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0);
- DRW_shgroup_uniform_float_copy(
- grp, "flipY", (camera_image->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0);
- DRW_shgroup_uniform_mat4(grp, "TransformMat", bg_data->transform_mat);
- DRW_shgroup_call(grp, batch, NULL);
-}
-
-static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data,
- OBJECT_PassList *psl,
- Object *ob,
- RegionView3D *rv3d)
-{
- if (DRW_state_is_select()) {
- return;
- }
-
- if (!BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d)) {
- return;
- }
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- struct ARegion *ar = draw_ctx->ar;
- View3D *v3d = draw_ctx->v3d;
- Scene *scene = draw_ctx->scene;
- Depsgraph *depsgraph = draw_ctx->depsgraph;
- Camera *cam = ob->data;
- const Object *camera_object = DEG_get_evaluated_object(depsgraph, v3d->camera);
- const bool is_active = (ob == camera_object);
- const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB));
-
- if (look_through && (cam->flag & CAM_SHOW_BG_IMAGE)) {
- GPUBatch *batch = DRW_cache_image_plane_get();
-
- /* load camera engine data */
- CameraEngineData *camera_engine_data = (CameraEngineData *)DRW_drawdata_ensure(
- &ob->id,
- &draw_engine_object_type,
- sizeof(CameraEngineData),
- NULL,
- camera_engine_data_free);
- LinkData *list_node = camera_engine_data->bg_data.first;
-
- for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
- if ((bgpic->flag & CAM_BGIMG_FLAG_DISABLED)) {
- continue;
- }
-
- /* retrieve the image we want to show, continue to next when no image could be found */
- ImBuf *ibuf = NULL;
- GPUTexture *tex = NULL;
- float image_aspect_x, image_aspect_y;
- float image_aspect = 1.0;
- int image_width, image_height;
- bool premultiplied = false;
-
- if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
- Image *image = bgpic->ima;
- if (image == NULL) {
- continue;
- }
- premultiplied = (image->alpha_mode == IMA_ALPHA_PREMUL);
- ImageUser *iuser = &bgpic->iuser;
- BKE_image_user_frame_calc(image, iuser, (int)DEG_get_ctime(depsgraph));
- if (image->source == IMA_SRC_SEQUENCE && !(iuser->flag & IMA_USER_FRAME_IN_RANGE)) {
- /* frame is out of range, dont show */
- continue;
- }
- else {
- camera_background_images_stereo_setup(scene, v3d, image, iuser);
- }
- tex = GPU_texture_from_blender(image, iuser, GL_TEXTURE_2D);
- if (tex == NULL) {
- continue;
- }
- ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
- if (ibuf == NULL) {
- continue;
- }
-
- image_aspect_x = bgpic->ima->aspx;
- image_aspect_y = bgpic->ima->aspy;
-
- image_width = ibuf->x;
- image_height = ibuf->y;
- BKE_image_release_ibuf(image, ibuf, NULL);
- image_aspect = (image_width * image_aspect_x) / (image_height * image_aspect_y);
- }
- else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
- MovieClip *clip = NULL;
- if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
- if (scene->camera) {
- clip = BKE_object_movieclip_get(scene, scene->camera, true);
- }
- }
- else {
- clip = bgpic->clip;
- }
-
- if (clip == NULL) {
- continue;
- }
-
- image_aspect_x = clip->aspx;
- image_aspect_y = clip->aspy;
-
- BKE_movieclip_user_set_frame(&bgpic->cuser, (int)DEG_get_ctime(depsgraph));
- tex = GPU_texture_from_movieclip(clip, &bgpic->cuser, GL_TEXTURE_2D);
- if (tex == NULL) {
- continue;
- }
- BLI_addtail(&e_data.movie_clips, BLI_genericNodeN(clip));
- BKE_movieclip_get_size(clip, &bgpic->cuser, &image_width, &image_height);
- image_aspect = (image_width * image_aspect_x) / (image_height * image_aspect_y);
- }
- else {
- continue;
- }
-
- /* ensure link_data is allocated to store matrice */
- CameraEngineBGData *bg_data;
- if (list_node != NULL) {
- bg_data = (CameraEngineBGData *)list_node->data;
- list_node = list_node->next;
- }
- else {
- bg_data = MEM_mallocN(sizeof(CameraEngineBGData), __func__);
- BLI_addtail(&camera_engine_data->bg_data, BLI_genericNodeN(bg_data));
- }
-
- /* calculate the transformation matric for the current bg image */
- float uv2img_space[4][4];
- float img2cam_space[4][4];
- float rot_m4[4][4];
- float scale_m4[4][4];
- float translate_m4[4][4];
- float win_m4_scale[4][4];
- float win_m4_translate[4][4];
-
- unit_m4(uv2img_space);
- unit_m4(img2cam_space);
- unit_m4(win_m4_scale);
- unit_m4(win_m4_translate);
- unit_m4(scale_m4);
- axis_angle_to_mat4_single(rot_m4, 'Z', -bgpic->rotation);
- unit_m4(translate_m4);
-
- const float *size = DRW_viewport_size_get();
- float camera_aspect_x = 1.0;
- float camera_aspect_y = 1.0;
- float camera_offset_x = 0.0;
- float camera_offset_y = 0.0;
- float camera_width = size[0];
- float camera_height = size[1];
- float camera_aspect = camera_width / camera_height;
-
- if (!DRW_state_is_image_render()) {
- rctf render_border;
- ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &render_border, false);
- camera_width = render_border.xmax - render_border.xmin;
- camera_height = render_border.ymax - render_border.ymin;
- camera_aspect = camera_width / camera_height;
- const float camera_aspect_center_x = (render_border.xmax + render_border.xmin) / 2.0;
- const float camera_aspect_center_y = (render_border.ymax + render_border.ymin) / 2.0;
-
- camera_aspect_x = camera_width / size[0];
- camera_aspect_y = camera_height / size[1];
- win_m4_scale[0][0] = camera_aspect_x;
- win_m4_scale[1][1] = camera_aspect_y;
-
- camera_offset_x = (camera_aspect_center_x - (ar->winx / 2.0)) /
- (0.5 * camera_width / camera_aspect_x);
- camera_offset_y = (camera_aspect_center_y - (ar->winy / 2.0)) /
- (0.5 * camera_height / camera_aspect_y);
- win_m4_translate[3][0] = camera_offset_x;
- win_m4_translate[3][1] = camera_offset_y;
- }
-
- /* Convert from uv space to image space -0.5..-.5 */
- uv2img_space[0][0] = image_width;
- uv2img_space[1][1] = image_height;
-
- const float fit_scale = image_aspect / camera_aspect;
- if (camera_aspect < image_aspect) {
- img2cam_space[0][0] = 1.0 / (1.0 / fit_scale) / image_width;
- img2cam_space[1][1] = 1.0 / image_height;
- }
- else {
- img2cam_space[0][0] = 1.0 / image_width;
- img2cam_space[1][1] = 1.0 / fit_scale / image_height;
- }
-
- /* Update scaling based on image and camera framing */
- float scale_x = bgpic->scale;
- float scale_y = bgpic->scale;
-
- float scale_x_offset = image_width;
- float scale_y_offset = image_height;
- if (image_aspect > 1.0f) {
- scale_x_offset /= image_aspect;
- if (camera_aspect > 1.0f) {
- scale_x_offset *= min_ff(image_aspect, camera_aspect);
- scale_y_offset *= min_ff(image_aspect, camera_aspect);
- }
- }
- else {
- scale_y_offset *= image_aspect;
- if (camera_aspect < 1.0f) {
- scale_x_offset /= max_ff(image_aspect, camera_aspect);
- scale_y_offset /= max_ff(image_aspect, camera_aspect);
- }
- }
-
- if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
- if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) {
- /* pass */
- }
- else {
- if (camera_aspect < image_aspect) {
- scale_x /= fit_scale;
- scale_y /= fit_scale;
- }
- else {
- scale_x *= fit_scale;
- scale_y *= fit_scale;
- }
- }
- }
- else {
- /* Stretch image to camera aspect */
- if (camera_aspect < image_aspect) {
- scale_x /= fit_scale;
- }
- else {
- scale_y *= fit_scale;
- }
- }
-
- // scale image to match the desired aspect ratio
- scale_m4[0][0] = scale_x;
- scale_m4[1][1] = scale_y;
-
- /* Translate */
- translate_m4[3][0] = bgpic->offset[0] * 2.0f * scale_x_offset;
- translate_m4[3][1] = bgpic->offset[1] * 2.0f * scale_y_offset;
-
- mul_m4_series(bg_data->transform_mat,
- win_m4_translate,
- win_m4_scale,
- img2cam_space,
- translate_m4,
- rot_m4,
- scale_m4,
- uv2img_space);
-
- /* Keep the references so we can reverse the loop */
- bg_data->camera_image = bgpic;
- bg_data->texture = tex;
- bg_data->premultiplied = premultiplied;
- }
-
- /* Mark the rest bg_data's to be reused in the next drawing call */
- LinkData *last_node = list_node ? list_node->prev : camera_engine_data->bg_data.last;
- while (list_node != NULL) {
- CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data;
- bg_data->texture = NULL;
- bg_data->camera_image = NULL;
- list_node = list_node->next;
- }
-
- GPUShader *shader = DRW_state_do_color_management() ? sh_data->object_camera_image_cm :
- sh_data->object_camera_image;
- /* loop 1: camera images alpha under */
- for (list_node = last_node; list_node; list_node = list_node->prev) {
- CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data;
- CameraBGImage *camera_image = bg_data->camera_image;
- if ((camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND) == 0) {
- camera_background_images_add_shgroup(
- psl->camera_images_back_alpha_under, bg_data, shader, batch);
- }
- }
-
- /* loop 2: camera images alpha over */
- for (list_node = camera_engine_data->bg_data.first; list_node; list_node = list_node->next) {
- CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data;
- CameraBGImage *camera_image = bg_data->camera_image;
- if (camera_image == NULL) {
- break;
- }
- camera_background_images_add_shgroup((camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND) ?
- psl->camera_images_front_alpha_over :
- psl->camera_images_back_alpha_over,
- bg_data,
- shader,
- batch);
- }
- }
-}
-
-static void camera_background_images_free_textures(void)
-{
- for (LinkData *link = e_data.movie_clips.first; link; link = link->next) {
- MovieClip *clip = (MovieClip *)link->data;
- GPU_free_texture_movieclip(clip);
- }
- BLI_freelistN(&e_data.movie_clips);
-}
-/* \} */
-
-static void OBJECT_cache_init(void *vedata)
-{
- const GlobalsUboStorage *gb = &G_draw.block;
- OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl;
- OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- OBJECT_PrivateData *g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- eGPUShaderConfig cfg = draw_ctx->sh_cfg;
- OBJECT_Shaders *sh_data = &e_data.sh_data[cfg];
-
- const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
- const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
- const bool do_large_expand = ((U.pixelsize > 1.0) && (outline_width > 2.0f)) ||
- (outline_width > 4.0f);
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- }
-
- g_data = stl->g_data;
- g_data->xray_enabled = XRAY_ACTIVE(draw_ctx->v3d);
- g_data->xray_enabled_and_not_wire = g_data->xray_enabled &&
- draw_ctx->v3d->shading.type > OB_WIRE;
-
- g_data->custom_shapes = BLI_ghash_ptr_new(__func__);
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->lightprobes = DRW_pass_create("Outlines Probe Pass", state);
-
- GPUShader *sh = sh_data->outline_prepass;
-
- g_data->probe_outlines_transform = shgroup_outline(psl->lightprobes, 0, sh, cfg);
- g_data->probe_outlines_select = shgroup_outline(psl->lightprobes, 1, sh, cfg);
- g_data->probe_outlines_select_dupli = shgroup_outline(psl->lightprobes, 2, sh, cfg);
- g_data->probe_outlines_active = shgroup_outline(psl->lightprobes, 3, sh, cfg);
-
- psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
-
- if (g_data->xray_enabled_and_not_wire) {
- sh = sh_data->outline_prepass_wire;
- }
-
- g_data->outlines_transform = shgroup_outline(psl->outlines, 0, sh, cfg);
- g_data->outlines_select = shgroup_outline(psl->outlines, 1, sh, cfg);
- g_data->outlines_select_dupli = shgroup_outline(psl->outlines, 2, sh, cfg);
- g_data->outlines_active = shgroup_outline(psl->outlines, 3, sh, cfg);
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR;
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
- /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
- float alphaOcclu = (g_data->xray_enabled) ? 1.0f : 0.35f;
-
- psl->outlines_search = DRW_pass_create("Outlines Detect Pass", state);
-
- GPUShader *sh = (g_data->xray_enabled_and_not_wire) ? sh_data->outline_detect_wire :
- sh_data->outline_detect;
- DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->outlines_search);
- DRW_shgroup_uniform_texture_ref(grp, "outlineId", &e_data.outlines_id_tx);
- DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &e_data.outlines_depth_tx);
- DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", alphaOcclu);
- DRW_shgroup_call(grp, quad, NULL);
-
- /* This is the bleed pass if do_outline_expand is false. */
- GPUShader *fade_sh = (do_large_expand) ? sh_data->outline_fade_large : sh_data->outline_fade;
- psl->outlines_expand = DRW_pass_create("Outlines Expand Pass", state);
-
- grp = DRW_shgroup_create(fade_sh, psl->outlines_expand);
- DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_blur_tx);
- DRW_shgroup_uniform_bool_copy(grp, "doExpand", do_outline_expand);
- DRW_shgroup_call(grp, quad, NULL);
-
- psl->outlines_bleed = DRW_pass_create("Outlines Bleed Pass", state);
-
- if (do_outline_expand) {
- grp = DRW_shgroup_create(sh_data->outline_fade, psl->outlines_bleed);
- DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_color_tx);
- DRW_shgroup_uniform_bool_copy(grp, "doExpand", false);
- DRW_shgroup_call(grp, quad, NULL);
- }
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
- psl->outlines_resolve = DRW_pass_create("Outlines Resolve Pass", state);
-
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
- GPUTexture **outline_tx = (do_outline_expand) ? &e_data.outlines_blur_tx :
- &e_data.outlines_color_tx;
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->outline_resolve_aa, psl->outlines_resolve);
- DRW_shgroup_uniform_texture_ref(grp, "outlineBluredColor", outline_tx);
- DRW_shgroup_uniform_vec2(grp, "rcpDimensions", e_data.inv_viewport_size, 1);
- DRW_shgroup_call(grp, quad, NULL);
- }
-
- {
- /* Grid pass */
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
- psl->grid = DRW_pass_create("Infinite Grid Pass", state);
-
- struct GPUBatch *geom = DRW_cache_grid_get();
- float grid_line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f;
-
- /* Create 3 quads to render ordered transparency Z axis */
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->grid, psl->grid);
- DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zneg_flag, 1);
- DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1);
- DRW_shgroup_uniform_vec3(grp, "screenVecs[0]", DRW_viewport_screenvecs_get(), 2);
- DRW_shgroup_uniform_float(grp, "gridDistance", &e_data.grid_distance, 1);
- DRW_shgroup_uniform_float_copy(grp, "lineKernel", grid_line_size);
- DRW_shgroup_uniform_float_copy(grp, "meshSize", e_data.grid_mesh_size);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
- DRW_shgroup_call(grp, geom, NULL);
-
- grp = DRW_shgroup_create(sh_data->grid, psl->grid);
- DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.grid_flag, 1);
- DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.grid_axes, 1);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
- DRW_shgroup_uniform_float(grp, "gridSteps", e_data.grid_steps, ARRAY_SIZE(e_data.grid_steps));
- DRW_shgroup_call(grp, geom, NULL);
-
- grp = DRW_shgroup_create(sh_data->grid, psl->grid);
- DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zpos_flag, 1);
- DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
- DRW_shgroup_call(grp, geom, NULL);
- }
-
- /* Camera background images */
- {
- psl->camera_images_back_alpha_over = DRW_pass_create(
- "Camera Images Back Over",
- DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA_PREMUL);
- psl->camera_images_back_alpha_under = DRW_pass_create(
- "Camera Images Back Under",
- DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL);
- psl->camera_images_front_alpha_over = DRW_pass_create(
- "Camera Images Front Over",
- DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA_PREMUL);
- }
-
- for (int i = 0; i < 2; i++) {
- OBJECT_ShadingGroupList *sgl = (i == 1) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
-
- /* Solid bones */
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- sgl->bone_solid = psl->bone_solid[i] = DRW_pass_create("Bone Solid Pass", state);
- sgl->bone_outline = psl->bone_outline[i] = DRW_pass_create("Bone Outline Pass", state);
-
- /* Wire bones */
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_BLEND_ALPHA;
- sgl->bone_wire = psl->bone_wire[i] = DRW_pass_create("Bone Wire Pass", state);
-
- /* distance outline around envelope bones */
- state = DRW_STATE_BLEND_ADD | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_CULL_FRONT;
- sgl->bone_envelope = psl->bone_envelope[i] = DRW_pass_create("Bone Envelope Outline Pass",
- state);
-
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- sgl->bone_axes = psl->bone_axes[i] = DRW_pass_create("Bone Axes Pass", state);
- }
-
- for (int i = 0; i < 2; i++) {
- OBJECT_ShadingGroupList *sgl = (i == 1) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
-
- /* Non Meshes Pass (Camera, empties, lights ...) */
- struct GPUBatch *geom;
- struct GPUShader *sh;
-
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_BLEND_ALPHA;
- sgl->non_meshes = psl->non_meshes[i] = DRW_pass_create("Non Meshes Pass", state);
-
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
- sgl->image_empties = psl->image_empties[i] = DRW_pass_create("Image Empties", state);
-
- /* Empties */
- empties_callbuffers_create(sgl->non_meshes, &sgl->empties, draw_ctx->sh_cfg);
-
- /* Force Field */
- geom = DRW_cache_field_wind_get();
- sgl->field_wind = buffer_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_field_force_get();
- sgl->field_force = buffer_instance_screen_aligned(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_field_vortex_get();
- sgl->field_vortex = buffer_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_screenspace_circle_get();
- sgl->field_curve_sta = buffer_instance_screen_aligned(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- /* Grease Pencil */
- geom = DRW_cache_gpencil_axes_get();
- sgl->gpencil_axes = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- /* Speaker */
- geom = DRW_cache_speaker_get();
- sgl->speaker = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- /* Probe */
- static float probeSize = 14.0f;
- geom = DRW_cache_lightprobe_cube_get();
- sgl->probe_cube = buffer_instance_screenspace(
- sgl->non_meshes, geom, &probeSize, draw_ctx->sh_cfg);
-
- geom = DRW_cache_lightprobe_grid_get();
- sgl->probe_grid = buffer_instance_screenspace(
- sgl->non_meshes, geom, &probeSize, draw_ctx->sh_cfg);
-
- static float probePlanarSize = 20.0f;
- geom = DRW_cache_lightprobe_planar_get();
- sgl->probe_planar = buffer_instance_screenspace(
- sgl->non_meshes, geom, &probePlanarSize, draw_ctx->sh_cfg);
-
- /* Camera */
- geom = DRW_cache_camera_get();
- sgl->camera = buffer_camera_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_camera_frame_get();
- sgl->camera_frame = buffer_camera_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_camera_tria_get();
- sgl->camera_tria = buffer_camera_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_plain_axes_get();
- sgl->camera_focus = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_single_line_get();
- sgl->camera_clip = buffer_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
- sgl->camera_mist = buffer_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_single_line_endpoints_get();
- sgl->camera_clip_points = buffer_distance_lines_instance(
- sgl->non_meshes, geom, draw_ctx->sh_cfg);
- sgl->camera_mist_points = buffer_distance_lines_instance(
- sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_quad_wires_get();
- sgl->camera_stereo_plane_wires = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_empty_cube_get();
- sgl->camera_stereo_volume_wires = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- BLI_listbase_clear(&sgl->camera_path);
-
- /* Texture Space */
- geom = DRW_cache_empty_cube_get();
- sgl->texspace = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- /* Wires (for loose edges) */
- sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_UNIFORM_COLOR, draw_ctx->sh_cfg);
- sgl->wire = shgroup_wire(sgl->non_meshes, gb->colorWire, sh, draw_ctx->sh_cfg);
- sgl->wire_select = shgroup_wire(sgl->non_meshes, gb->colorSelect, sh, draw_ctx->sh_cfg);
- sgl->wire_transform = shgroup_wire(sgl->non_meshes, gb->colorTransform, sh, draw_ctx->sh_cfg);
- sgl->wire_active = shgroup_wire(sgl->non_meshes, gb->colorActive, sh, draw_ctx->sh_cfg);
- /* Wire (duplicator) */
- sgl->wire_dupli = shgroup_wire(sgl->non_meshes, gb->colorDupli, sh, draw_ctx->sh_cfg);
- sgl->wire_dupli_select = shgroup_wire(
- sgl->non_meshes, gb->colorDupliSelect, sh, draw_ctx->sh_cfg);
-
- /* Points (loose points) */
- sh = sh_data->loose_points;
- sgl->points = shgroup_points(sgl->non_meshes, gb->colorWire, sh, draw_ctx->sh_cfg);
- sgl->points_select = shgroup_points(sgl->non_meshes, gb->colorSelect, sh, draw_ctx->sh_cfg);
- sgl->points_transform = shgroup_points(
- sgl->non_meshes, gb->colorTransform, sh, draw_ctx->sh_cfg);
- sgl->points_active = shgroup_points(sgl->non_meshes, gb->colorActive, sh, draw_ctx->sh_cfg);
- /* Points (duplicator) */
- sgl->points_dupli = shgroup_points(sgl->non_meshes, gb->colorDupli, sh, draw_ctx->sh_cfg);
- sgl->points_dupli_select = shgroup_points(
- sgl->non_meshes, gb->colorDupliSelect, sh, draw_ctx->sh_cfg);
- DRW_shgroup_state_disable(sgl->points, DRW_STATE_BLEND_ALPHA);
- DRW_shgroup_state_disable(sgl->points_select, DRW_STATE_BLEND_ALPHA);
- DRW_shgroup_state_disable(sgl->points_transform, DRW_STATE_BLEND_ALPHA);
- DRW_shgroup_state_disable(sgl->points_active, DRW_STATE_BLEND_ALPHA);
- DRW_shgroup_state_disable(sgl->points_dupli, DRW_STATE_BLEND_ALPHA);
- DRW_shgroup_state_disable(sgl->points_dupli_select, DRW_STATE_BLEND_ALPHA);
-
- /* Metaballs Handles */
- sgl->mball_handle = buffer_instance_mball_handles(sgl->non_meshes, draw_ctx->sh_cfg);
-
- /* Lights */
- /* TODO
- * for now we create multiple times the same VBO with only light center coordinates
- * but ideally we would only create it once */
-
- sh = GPU_shader_get_builtin_shader_with_config(
- GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA, draw_ctx->sh_cfg);
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh, sgl->non_meshes);
- DRW_shgroup_uniform_vec4(grp, "color", gb->colorLightNoAlpha, 1);
- DRW_shgroup_uniform_float(grp, "size", &gb->sizeLightCenter, 1);
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
-
- sgl->light_center = buffer_dynpoints_uniform_color(grp);
-
- geom = DRW_cache_single_line_get();
- sgl->light_buflimit = buffer_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_light_get();
- sgl->light_circle = buffer_instance_screenspace(
- sgl->non_meshes, geom, &gb->sizeLightCircle, draw_ctx->sh_cfg);
- geom = DRW_cache_light_shadows_get();
- sgl->light_circle_shadow = buffer_instance_screenspace(
- sgl->non_meshes, geom, &gb->sizeLightCircleShadow, draw_ctx->sh_cfg);
-
- geom = DRW_cache_light_sunrays_get();
- sgl->light_sunrays = buffer_instance_screenspace(
- sgl->non_meshes, geom, &gb->sizeLightCircle, draw_ctx->sh_cfg);
-
- sgl->light_groundline = buffer_groundlines_uniform_color(
- sgl->non_meshes, gb->colorLight, draw_ctx->sh_cfg);
- sgl->light_groundpoint = buffer_groundpoints_uniform_color(
- sgl->non_meshes, gb->colorLight, draw_ctx->sh_cfg);
-
- geom = DRW_cache_screenspace_circle_get();
- sgl->light_area_sphere = buffer_instance_screen_aligned(
- sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_light_area_square_get();
- sgl->light_area_square = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_light_area_disk_get();
- sgl->light_area_disk = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_light_hemi_get();
- sgl->light_hemi = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_single_line_get();
- sgl->light_distance = buffer_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_single_line_endpoints_get();
- sgl->light_buflimit_points = buffer_distance_lines_instance(
- sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_light_spot_get();
- sgl->light_spot_cone = buffer_spot_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_circle_get();
- sgl->light_spot_blend = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_light_spot_square_get();
- sgl->light_spot_pyramid = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- geom = DRW_cache_square_get();
- sgl->light_spot_blend_rect = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- /* -------- STIPPLES ------- */
-
- /* Relationship Lines */
- sgl->relationship_lines = buffer_dynlines_dashed_uniform_color(
- sgl->non_meshes, gb->colorWire, draw_ctx->sh_cfg);
- sgl->constraint_lines = buffer_dynlines_dashed_uniform_color(
- sgl->non_meshes, gb->colorGridAxisZ, draw_ctx->sh_cfg);
-
- {
- DRWShadingGroup *grp_axes;
- sgl->origin_xform = buffer_instance_color_axes(
- sgl->non_meshes, DRW_cache_bone_arrows_get(), &grp_axes, draw_ctx->sh_cfg);
-
- DRW_shgroup_state_disable(grp_axes, DRW_STATE_DEPTH_LESS_EQUAL);
- DRW_shgroup_state_enable(grp_axes, DRW_STATE_DEPTH_ALWAYS);
- DRW_shgroup_state_enable(grp_axes, DRW_STATE_WIRE_SMOOTH);
- }
-
- /* Force Field Curve Guide End (here because of stipple) */
- /* TODO port to shader stipple */
- geom = DRW_cache_screenspace_circle_get();
- sgl->field_curve_end = buffer_instance_screen_aligned(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- /* Force Field Limits */
- /* TODO port to shader stipple */
- geom = DRW_cache_field_tube_limit_get();
- sgl->field_tube_limit = buffer_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- /* TODO port to shader stipple */
- geom = DRW_cache_field_cone_limit_get();
- sgl->field_cone_limit = buffer_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg);
-
- /* Transparent Shapes */
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_CULL_FRONT;
- sgl->transp_shapes = psl->transp_shapes[i] = DRW_pass_create("Transparent Shapes", state);
-
- sh = GPU_shader_get_builtin_shader_with_config(
- GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, draw_ctx->sh_cfg);
-
- DRWShadingGroup *grp_transp = DRW_shgroup_create(sh, sgl->transp_shapes);
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp_transp, DRW_STATE_CLIP_PLANES);
- }
-
- DRWShadingGroup *grp_cull_back = DRW_shgroup_create_sub(grp_transp);
- DRW_shgroup_state_disable(grp_cull_back, DRW_STATE_CULL_FRONT);
- DRW_shgroup_state_enable(grp_cull_back, DRW_STATE_CULL_BACK);
-
- DRWShadingGroup *grp_cull_none = DRW_shgroup_create_sub(grp_transp);
- DRW_shgroup_state_disable(grp_cull_none, DRW_STATE_CULL_FRONT);
-
- /* Spot cones */
- geom = DRW_cache_light_spot_volume_get();
- sgl->light_spot_volume = buffer_instance_alpha(grp_transp, geom);
-
- geom = DRW_cache_light_spot_square_volume_get();
- sgl->light_spot_volume_rect = buffer_instance_alpha(grp_transp, geom);
-
- geom = DRW_cache_light_spot_volume_get();
- sgl->light_spot_volume_outside = buffer_instance_alpha(grp_cull_back, geom);
-
- geom = DRW_cache_light_spot_square_volume_get();
- sgl->light_spot_volume_rect_outside = buffer_instance_alpha(grp_cull_back, geom);
-
- /* Camera stereo volumes */
- geom = DRW_cache_cube_get();
- sgl->camera_stereo_volume = buffer_instance_alpha(grp_transp, geom);
-
- geom = DRW_cache_quad_get();
- sgl->camera_stereo_plane = buffer_instance_alpha(grp_cull_none, geom);
- }
-
- {
- /* Object Center pass grouped by State */
- DRWShadingGroup *grp;
- static float outlineWidth, size;
-
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
- psl->ob_center = DRW_pass_create("Obj Center Pass", state);
-
- outlineWidth = 1.0f * U.pixelsize;
- size = UI_GetThemeValuef(TH_OBCENTER_DIA) * U.pixelsize + outlineWidth;
-
- GPUShader *sh = GPU_shader_get_builtin_shader_with_config(
- GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA, draw_ctx->sh_cfg);
-
- /* Active */
- grp = DRW_shgroup_create(sh, psl->ob_center);
- DRW_shgroup_uniform_float(grp, "size", &size, 1);
- DRW_shgroup_uniform_float(grp, "outlineWidth", &outlineWidth, 1);
- DRW_shgroup_uniform_vec4(grp, "color", gb->colorActive, 1);
- DRW_shgroup_uniform_vec4(grp, "outlineColor", gb->colorOutline, 1);
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- /* TODO find better name. */
- stl->g_data->center_active = buffer_dynpoints_uniform_color(grp);
-
- /* Select */
- grp = DRW_shgroup_create_sub(grp);
- DRW_shgroup_uniform_vec4(grp, "color", gb->colorSelect, 1);
- stl->g_data->center_selected = buffer_dynpoints_uniform_color(grp);
-
- /* Deselect */
- grp = DRW_shgroup_create_sub(grp);
- DRW_shgroup_uniform_vec4(grp, "color", gb->colorDeselect, 1);
- stl->g_data->center_deselected = buffer_dynpoints_uniform_color(grp);
-
- /* Select (library) */
- grp = DRW_shgroup_create_sub(grp);
- DRW_shgroup_uniform_vec4(grp, "color", gb->colorLibrarySelect, 1);
- stl->g_data->center_selected_lib = buffer_dynpoints_uniform_color(grp);
-
- /* Deselect (library) */
- grp = DRW_shgroup_create_sub(grp);
- DRW_shgroup_uniform_vec4(grp, "color", gb->colorLibrary, 1);
- stl->g_data->center_deselected_lib = buffer_dynpoints_uniform_color(grp);
- }
-
- {
- /* Particle Pass */
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_BLEND_ALPHA;
- psl->particle = DRW_pass_create("Particle Pass", state);
- }
-}
-
-static void DRW_shgroup_mball_handles(OBJECT_ShadingGroupList *sgl,
- Object *ob,
- ViewLayer *view_layer)
-{
- MetaBall *mb = ob->data;
-
- float *color;
- DRW_object_wire_theme_get(ob, view_layer, &color);
-
- float draw_scale_xform[3][4]; /* Matrix of Scale and Translation */
- {
- float scamat[3][3];
- copy_m3_m4(scamat, ob->obmat);
- /* Get the normalized inverse matrix to extract only
- * the scale of Scamat */
- float iscamat[3][3];
- invert_m3_m3(iscamat, scamat);
- normalize_m3(iscamat);
- mul_m3_m3_post(scamat, iscamat);
-
- copy_v3_v3(draw_scale_xform[0], scamat[0]);
- copy_v3_v3(draw_scale_xform[1], scamat[1]);
- copy_v3_v3(draw_scale_xform[2], scamat[2]);
- }
-
- for (MetaElem *ml = mb->elems.first; ml != NULL; ml = ml->next) {
- /* draw radius */
- float world_pos[3];
- mul_v3_m4v3(world_pos, ob->obmat, &ml->x);
- draw_scale_xform[0][3] = world_pos[0];
- draw_scale_xform[1][3] = world_pos[1];
- draw_scale_xform[2][3] = world_pos[2];
-
- DRW_buffer_add_entry(sgl->mball_handle, draw_scale_xform, &ml->rad, color);
- }
-}
-
-static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
-{
- Light *la = ob->data;
- float *color;
- int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
- static float zero = 0.0f;
-
- typedef struct LightEngineData {
- DrawData dd;
- float shape_mat[4][4];
- float spot_blend_mat[4][4];
- } LightEngineData;
-
- LightEngineData *light_engine_data = (LightEngineData *)DRW_drawdata_ensure(
- &ob->id, &draw_engine_object_type, sizeof(LightEngineData), NULL, NULL);
-
- float(*shapemat)[4] = light_engine_data->shape_mat;
- float(*spotblendmat)[4] = light_engine_data->spot_blend_mat;
-
- if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
- /* Don't draw the center if it's selected or active */
- if (theme_id == TH_LIGHT) {
- DRW_buffer_add_entry(sgl->light_center, ob->obmat[3]);
- }
- }
-
- /* First circle */
- DRW_buffer_add_entry(sgl->light_circle, ob->obmat[3], color);
-
- /* draw dashed outer circle for shadow */
- DRW_buffer_add_entry(sgl->light_circle_shadow, ob->obmat[3], color);
-
- /* Distance */
- if (ELEM(la->type, LA_SUN, LA_AREA)) {
- DRW_buffer_add_entry(sgl->light_distance, color, &zero, &la->dist, ob->obmat);
- }
-
- copy_m4_m4(shapemat, ob->obmat);
-
- if (la->type == LA_SUN) {
- DRW_buffer_add_entry(sgl->light_sunrays, ob->obmat[3], color);
- }
- else if (la->type == LA_SPOT) {
- float size[3], sizemat[4][4];
- static float one = 1.0f;
- float cone_inside[4] = {0.0f, 0.0f, 0.0f, 0.5f};
- float cone_outside[4] = {1.0f, 1.0f, 1.0f, 0.3f};
- float blend = 1.0f - pow2f(la->spotblend);
- size[0] = size[1] = sinf(la->spotsize * 0.5f) * la->dist;
- size[2] = cosf(la->spotsize * 0.5f) * la->dist;
-
- size_to_mat4(sizemat, size);
- mul_m4_m4m4(shapemat, ob->obmat, sizemat);
-
- size[0] = size[1] = blend;
- size[2] = 1.0f;
- size_to_mat4(sizemat, size);
- translate_m4(sizemat, 0.0f, 0.0f, -1.0f);
- rotate_m4(sizemat, 'X', (float)(M_PI / 2));
- mul_m4_m4m4(spotblendmat, shapemat, sizemat);
-
- if (la->mode & LA_SQUARE) {
- DRW_buffer_add_entry(sgl->light_spot_pyramid, color, &one, shapemat);
-
- /* hide line if it is zero size or overlaps with outer border,
- * previously it adjusted to always to show it but that seems
- * confusing because it doesn't show the actual blend size */
- if (blend != 0.0f && blend != 1.0f) {
- DRW_buffer_add_entry(sgl->light_spot_blend_rect, color, &one, spotblendmat);
- }
-
- if (la->mode & LA_SHOW_CONE) {
- if (!DRW_state_is_select()) {
- DRW_buffer_add_entry(sgl->light_spot_volume_rect, cone_inside, &one, shapemat);
- DRW_buffer_add_entry(sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat);
- }
- }
- }
- else {
- DRW_buffer_add_entry(sgl->light_spot_cone, color, shapemat);
-
- /* hide line if it is zero size or overlaps with outer border,
- * previously it adjusted to always to show it but that seems
- * confusing because it doesn't show the actual blend size */
- if (blend != 0.0f && blend != 1.0f) {
- DRW_buffer_add_entry(sgl->light_spot_blend, color, &one, spotblendmat);
- }
-
- if (la->mode & LA_SHOW_CONE) {
- if (!DRW_state_is_select()) {
- DRW_buffer_add_entry(sgl->light_spot_volume, cone_inside, &one, shapemat);
- DRW_buffer_add_entry(sgl->light_spot_volume_outside, cone_outside, &one, shapemat);
- }
- }
- }
-
- DRW_buffer_add_entry(sgl->light_buflimit, color, &la->clipsta, &la->clipend, ob->obmat);
- DRW_buffer_add_entry(sgl->light_buflimit_points, color, &la->clipsta, &la->clipend, ob->obmat);
- }
- else if (la->type == LA_AREA) {
- float size[3] = {1.0f, 1.0f, 1.0f}, sizemat[4][4];
-
- if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) {
- size[1] = la->area_sizey / la->area_size;
- size_to_mat4(sizemat, size);
- mul_m4_m4m4(shapemat, shapemat, sizemat);
- }
-
- if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) {
- DRW_buffer_add_entry(sgl->light_area_disk, color, &la->area_size, shapemat);
- }
- else {
- DRW_buffer_add_entry(sgl->light_area_square, color, &la->area_size, shapemat);
- }
- }
-
- if (ELEM(la->type, LA_LOCAL, LA_SPOT)) {
- /* We only want position not scale. */
- shapemat[0][0] = shapemat[1][1] = shapemat[2][2] = 1.0f;
- shapemat[0][1] = shapemat[0][2] = 0.0f;
- shapemat[1][0] = shapemat[1][2] = 0.0f;
- shapemat[2][0] = shapemat[2][1] = 0.0f;
- DRW_buffer_add_entry(sgl->light_area_sphere, color, &la->area_size, shapemat);
- }
-
- /* Line and point going to the ground */
- DRW_buffer_add_entry(sgl->light_groundline, ob->obmat[3]);
- DRW_buffer_add_entry(sgl->light_groundpoint, ob->obmat[3]);
-}
-
-static GPUBatch *batch_camera_path_get(ListBase *camera_paths,
- const MovieTrackingReconstruction *reconstruction)
-{
- GPUBatch *geom;
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, reconstruction->camnr);
-
- MovieReconstructedCamera *camera = reconstruction->cameras;
- for (int a = 0; a < reconstruction->camnr; a++, camera++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, a, camera->mat[3]);
- }
-
- geom = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
-
- /* Store the batch to do cleanup after drawing. */
- BLI_addtail(camera_paths, BLI_genericNodeN(geom));
- return geom;
-}
-
-static void batch_camera_path_free(ListBase *camera_paths)
-{
- LinkData *link;
- while ((link = BLI_pophead(camera_paths))) {
- GPUBatch *camera_path = link->data;
- GPU_batch_discard(camera_path);
- MEM_freeN(link);
- }
-}
-
-/**
- * Draw the stereo 3d support elements (cameras, plane, volume).
- * They are only visible when not looking through the camera:
- */
-static void camera_view3d_stereoscopy_display_extra(OBJECT_ShadingGroupList *sgl,
- Scene *scene,
- ViewLayer *view_layer,
- View3D *v3d,
- Object *ob,
- Camera *cam,
- const float vec[4][3],
- float drawsize,
- const float scale[3])
-{
- const bool is_select = DRW_state_is_select();
- static float drw_tria_dummy[2][2][2] = {{{0}}};
- const float fac = (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER) ? 2.0f : 1.0f;
- float origin[2][3] = {{0}};
- const char *viewnames[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
-
- const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) &&
- (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
- const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) &&
- (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
- const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME);
-
- float *color;
- DRW_object_wire_theme_get(ob, view_layer, &color);
-
- for (int eye = 0; eye < 2; eye++) {
- float obmat[4][4];
- ob = BKE_camera_multiview_render(scene, ob, viewnames[eye]);
-
- BKE_camera_multiview_model_matrix_scaled(&scene->r, ob, viewnames[eye], obmat);
-
- copy_v2_v2(cam->runtime.drw_corners[eye][0], vec[0]);
- copy_v2_v2(cam->runtime.drw_corners[eye][1], vec[1]);
- copy_v2_v2(cam->runtime.drw_corners[eye][2], vec[2]);
- copy_v2_v2(cam->runtime.drw_corners[eye][3], vec[3]);
-
- cam->runtime.drw_depth[eye] = vec[0][2];
-
- if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
- const float shift_x = ((BKE_camera_multiview_shift_x(&scene->r, ob, viewnames[eye]) -
- cam->shiftx) *
- (drawsize * scale[0] * fac)) *
- (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER ? 1.0f : 2.0f);
-
- for (int i = 0; i < 4; i++) {
- cam->runtime.drw_corners[eye][i][0] += shift_x;
- }
- }
-
- /* Dummy triangle, draw on top of existent lines so it is invisible. */
- copy_v2_v2(drw_tria_dummy[eye][0], cam->runtime.drw_corners[eye][0]);
- copy_v2_v2(drw_tria_dummy[eye][1], cam->runtime.drw_corners[eye][0]);
-
- if (is_stereo3d_cameras) {
- DRW_buffer_add_entry(sgl->camera_frame,
- color,
- cam->runtime.drw_corners[eye],
- &cam->runtime.drw_depth[eye],
- cam->runtime.drw_tria,
- obmat);
-
- DRW_buffer_add_entry(sgl->camera,
- color,
- cam->runtime.drw_corners[eye],
- &cam->runtime.drw_depth[eye],
- drw_tria_dummy[eye],
- obmat);
- }
-
- /* Connecting line. */
- mul_m4_v3(obmat, origin[eye]);
- }
-
- /* Draw connecting lines. */
- if (is_stereo3d_cameras) {
- DRW_buffer_add_entry(sgl->relationship_lines, origin[0]);
- DRW_buffer_add_entry(sgl->relationship_lines, origin[1]);
- }
-
- /* Draw convergence plane. */
- if (is_stereo3d_plane && !is_select) {
- float convergence_plane[4][2];
- const float offset = cam->stereo.convergence_distance / cam->runtime.drw_depth[0];
-
- for (int i = 0; i < 4; i++) {
- mid_v2_v2v2(
- convergence_plane[i], cam->runtime.drw_corners[0][i], cam->runtime.drw_corners[1][i]);
- mul_v2_fl(convergence_plane[i], offset);
- }
-
- /* We are using a -1,1 quad for this shading group, so we need to
- * scale and transform it to match the convergence plane border. */
- static float one = 1.0f;
- float plane_mat[4][4], scale_mat[4][4];
- float scale_factor[3] = {1.0f, 1.0f, 1.0f};
- const float color_plane[2][4] = {
- {0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha},
- {0.0f, 0.0f, 0.0f, 1.0f},
- };
-
- const float height = convergence_plane[1][1] - convergence_plane[0][1];
- const float width = convergence_plane[2][0] - convergence_plane[0][0];
-
- scale_factor[0] = width * 0.5f;
- scale_factor[1] = height * 0.5f;
-
- copy_m4_m4(plane_mat, cam->runtime.drw_normalmat);
- translate_m4(plane_mat, 0.0f, 0.0f, -cam->stereo.convergence_distance);
- size_to_mat4(scale_mat, scale_factor);
- mul_m4_m4_post(plane_mat, scale_mat);
- translate_m4(plane_mat, 2.0f * cam->shiftx, (width / height) * 2.0f * cam->shifty, 0.0f);
-
- if (v3d->stereo3d_convergence_alpha > 0.0f) {
- DRW_buffer_add_entry(sgl->camera_stereo_plane, color_plane[0], &one, plane_mat);
- }
- DRW_buffer_add_entry(sgl->camera_stereo_plane_wires, color_plane[1], &one, plane_mat);
- }
-
- /* Draw convergence volume. */
- if (is_stereo3d_volume && !is_select) {
- static float one = 1.0f;
- const float color_volume[3][4] = {
- {0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha},
- {1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha},
- {0.0f, 0.0f, 0.0f, 1.0f},
- };
-
- for (int eye = 0; eye < 2; eye++) {
- float winmat[4][4], viewinv[4][4], viewmat[4][4], persmat[4][4], persinv[4][4];
- ob = BKE_camera_multiview_render(scene, ob, viewnames[eye]);
-
- BKE_camera_multiview_window_matrix(&scene->r, ob, viewnames[eye], winmat);
- BKE_camera_multiview_model_matrix(&scene->r, ob, viewnames[eye], viewinv);
-
- invert_m4_m4(viewmat, viewinv);
- mul_m4_m4m4(persmat, winmat, viewmat);
- invert_m4_m4(persinv, persmat);
-
- if (v3d->stereo3d_volume_alpha > 0.0f) {
- DRW_buffer_add_entry(sgl->camera_stereo_volume, color_volume[eye], &one, persinv);
- }
- DRW_buffer_add_entry(sgl->camera_stereo_volume_wires, color_volume[2], &one, persinv);
- }
- }
-}
-
-static void camera_view3d_reconstruction(OBJECT_ShadingGroupList *sgl,
- Scene *scene,
- View3D *v3d,
- Object *camera_object,
- Object *ob,
- const float color[4],
- const bool is_select)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Camera *cam = ob->data;
- const Object *orig_camera_object = DEG_get_original_object(camera_object);
-
- if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0) {
- return;
- }
-
- MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
- if (clip == NULL) {
- return;
- }
-
- BLI_assert(BLI_listbase_is_empty(&sgl->camera_path));
- const bool is_solid_bundle = (v3d->bundle_drawtype == OB_EMPTY_SPHERE) &&
- ((v3d->shading.type != OB_SOLID) || !XRAY_FLAG_ENABLED(v3d));
-
- MovieTracking *tracking = &clip->tracking;
- /* Index must start in 1, to mimic BKE_tracking_track_get_indexed. */
- int track_index = 1;
-
- uchar text_color_selected[4], text_color_unselected[4];
- float bundle_color_unselected[4], bundle_color_solid[4];
-
- UI_GetThemeColor4ubv(TH_SELECT, text_color_selected);
- UI_GetThemeColor4ubv(TH_TEXT, text_color_unselected);
- UI_GetThemeColor4fv(TH_WIRE, bundle_color_unselected);
- UI_GetThemeColor4fv(TH_BUNDLE_SOLID, bundle_color_solid);
-
- float camera_mat[4][4];
- BKE_tracking_get_camera_object_matrix(scene, ob, camera_mat);
-
- float bundle_scale_mat[4][4];
- if (is_solid_bundle) {
- scale_m4_fl(bundle_scale_mat, v3d->bundle_size);
- }
-
- for (MovieTrackingObject *tracking_object = tracking->objects.first; tracking_object != NULL;
- tracking_object = tracking_object->next) {
- float tracking_object_mat[4][4];
-
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- copy_m4_m4(tracking_object_mat, camera_mat);
- }
- else {
- const int framenr = BKE_movieclip_remap_scene_to_clip_frame(
- clip, DEG_get_ctime(draw_ctx->depsgraph));
- float object_mat[4][4];
- BKE_tracking_camera_get_reconstructed_interpolate(
- tracking, tracking_object, framenr, object_mat);
-
- invert_m4(object_mat);
- mul_m4_m4m4(tracking_object_mat, cam->runtime.drw_normalmat, object_mat);
- }
-
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
- for (MovieTrackingTrack *track = tracksbase->first; track; track = track->next) {
-
- if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
- continue;
- }
-
- bool is_selected = TRACK_SELECTED(track);
-
- float bundle_mat[4][4];
- copy_m4_m4(bundle_mat, tracking_object_mat);
- translate_m4(bundle_mat, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
-
- const float *bundle_color;
- if (track->flag & TRACK_CUSTOMCOLOR) {
- bundle_color = track->color;
- }
- else if (is_solid_bundle) {
- bundle_color = bundle_color_solid;
- }
- else if (is_selected) {
- bundle_color = color;
- }
- else {
- bundle_color = bundle_color_unselected;
- }
-
- if (is_select) {
- DRW_select_load_id(orig_camera_object->runtime.select_id | (track_index << 16));
- track_index++;
- }
-
- if (is_solid_bundle) {
-
- if (is_selected) {
- DRW_shgroup_empty_ex(sgl, bundle_mat, &v3d->bundle_size, v3d->bundle_drawtype, color);
- }
-
- const float bundle_color_v4[4] = {
- bundle_color[0],
- bundle_color[1],
- bundle_color[2],
- 1.0f,
- };
-
- mul_m4_m4m4(bundle_mat, bundle_mat, bundle_scale_mat);
- DRW_buffer_add_entry(sgl->empties.sphere_solid, bundle_mat, bundle_color_v4);
- }
- else {
- DRW_shgroup_empty_ex(
- sgl, bundle_mat, &v3d->bundle_size, v3d->bundle_drawtype, bundle_color);
- }
-
- if ((v3d->flag2 & V3D_SHOW_BUNDLENAME) && !is_select) {
- struct DRWTextStore *dt = DRW_text_cache_ensure();
-
- DRW_text_cache_add(dt,
- bundle_mat[3],
- track->name,
- strlen(track->name),
- 10,
- 0,
- DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
- is_selected ? text_color_selected : text_color_unselected);
- }
- }
-
- if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA) &&
- !is_select) {
- MovieTrackingReconstruction *reconstruction;
- reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
-
- if (reconstruction->camnr) {
- static float camera_path_color[4];
- UI_GetThemeColor4fv(TH_CAMERA_PATH, camera_path_color);
-
- GPUBatch *geom = batch_camera_path_get(&sgl->camera_path, reconstruction);
- GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
- DRWShadingGroup *shading_group = DRW_shgroup_create(shader, sgl->non_meshes);
- DRW_shgroup_uniform_vec4(shading_group, "color", camera_path_color, 1);
- DRW_shgroup_call_obmat(shading_group, geom, camera_mat);
- }
- }
- }
-}
-
-static void DRW_shgroup_camera(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- Scene *scene = draw_ctx->scene;
- RegionView3D *rv3d = draw_ctx->rv3d;
-
- Camera *cam = ob->data;
- Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
- const bool is_select = DRW_state_is_select();
- const bool is_active = (ob == camera_object);
- const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB));
-
- const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
- const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
- const bool is_stereo3d_display_extra = is_active && is_multiview && (!look_through) &&
- ((v3d->stereo3d_flag) != 0);
- const bool is_stereo3d_cameras = (ob == scene->camera) && is_multiview && is_stereo3d_view &&
- (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS);
- const bool is_selection_camera_stereo = is_select && look_through && is_multiview &&
- is_stereo3d_view;
-
- float *color;
- DRW_object_wire_theme_get(ob, view_layer, &color);
-
- float vec[4][3], asp[2], shift[2], scale[3], drawsize;
-
- /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here. */
- if (is_selection_camera_stereo) {
- scale[0] = 1.0f;
- scale[1] = 1.0f;
- scale[2] = 1.0f;
- }
- else {
- scale[0] = 1.0f / len_v3(ob->obmat[0]);
- scale[1] = 1.0f / len_v3(ob->obmat[1]);
- scale[2] = 1.0f / len_v3(ob->obmat[2]);
- }
-
- BKE_camera_view_frame_ex(
- scene, cam, cam->drawsize, look_through, scale, asp, shift, &drawsize, vec);
-
- /* Frame coords */
- copy_v2_v2(cam->runtime.drw_corners[0][0], vec[0]);
- copy_v2_v2(cam->runtime.drw_corners[0][1], vec[1]);
- copy_v2_v2(cam->runtime.drw_corners[0][2], vec[2]);
- copy_v2_v2(cam->runtime.drw_corners[0][3], vec[3]);
-
- /* depth */
- cam->runtime.drw_depth[0] = vec[0][2];
-
- /* tria */
- cam->runtime.drw_tria[0][0] = shift[0] + ((0.7f * drawsize) * scale[0]);
- cam->runtime.drw_tria[0][1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
- cam->runtime.drw_tria[1][0] = shift[0];
- cam->runtime.drw_tria[1][1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
-
- if (look_through) {
- if (!DRW_state_is_image_render()) {
- /* Only draw the frame. */
- float mat[4][4];
- if (is_multiview) {
- const bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
- const char *view_name = is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME;
- BKE_camera_multiview_model_matrix(&scene->r, ob, view_name, mat);
- const float shiftx = BKE_camera_multiview_shift_x(&scene->r, ob, view_name);
- const float delta_shiftx = shiftx - cam->shiftx;
- const float width = cam->runtime.drw_corners[0][2][0] - cam->runtime.drw_corners[0][0][0];
- for (int i = 0; i < 4; i++) {
- cam->runtime.drw_corners[0][i][0] -= delta_shiftx * width;
- }
- }
- else {
- copy_m4_m4(mat, ob->obmat);
- }
-
- DRW_buffer_add_entry(sgl->camera_frame,
- color,
- cam->runtime.drw_corners[0],
- &cam->runtime.drw_depth[0],
- cam->runtime.drw_tria,
- mat);
- }
- }
- else {
- if (!is_stereo3d_cameras) {
- DRW_buffer_add_entry(sgl->camera,
- color,
- cam->runtime.drw_corners[0],
- &cam->runtime.drw_depth[0],
- cam->runtime.drw_tria,
- ob->obmat);
- }
-
- /* Active cam */
- if (is_active) {
- DRW_buffer_add_entry(sgl->camera_tria,
- color,
- cam->runtime.drw_corners[0],
- &cam->runtime.drw_depth[0],
- cam->runtime.drw_tria,
- ob->obmat);
- }
- }
-
- /* draw the rest in normalize object space */
- normalize_m4_m4(cam->runtime.drw_normalmat, ob->obmat);
-
- if (cam->flag & CAM_SHOWLIMITS) {
- static float col[4] = {0.5f, 0.5f, 0.25f, 1.0f}, col_hi[4] = {1.0f, 1.0f, 0.5f, 1.0f};
- float sizemat[4][4], size[3] = {1.0f, 1.0f, 0.0f};
- float focusdist = BKE_camera_object_dof_distance(ob);
-
- copy_m4_m4(cam->runtime.drw_focusmat, cam->runtime.drw_normalmat);
- translate_m4(cam->runtime.drw_focusmat, 0.0f, 0.0f, -focusdist);
- size_to_mat4(sizemat, size);
- mul_m4_m4m4(cam->runtime.drw_focusmat, cam->runtime.drw_focusmat, sizemat);
-
- DRW_buffer_add_entry(
- sgl->camera_focus, (is_active ? col_hi : col), &cam->drawsize, cam->runtime.drw_focusmat);
-
- DRW_buffer_add_entry(
- sgl->camera_clip, color, &cam->clip_start, &cam->clip_end, cam->runtime.drw_normalmat);
- DRW_buffer_add_entry(sgl->camera_clip_points,
- (is_active ? col_hi : col),
- &cam->clip_start,
- &cam->clip_end,
- cam->runtime.drw_normalmat);
- }
-
- if (cam->flag & CAM_SHOWMIST) {
- World *world = scene->world;
-
- if (world) {
- static float col[4] = {0.5f, 0.5f, 0.5f, 1.0f}, col_hi[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- world->mistend = world->miststa + world->mistdist;
- DRW_buffer_add_entry(
- sgl->camera_mist, color, &world->miststa, &world->mistend, cam->runtime.drw_normalmat);
- DRW_buffer_add_entry(sgl->camera_mist_points,
- (is_active ? col_hi : col),
- &world->miststa,
- &world->mistend,
- cam->runtime.drw_normalmat);
- }
- }
-
- /* Stereo cameras, volumes, plane drawing. */
- if (is_stereo3d_display_extra) {
- camera_view3d_stereoscopy_display_extra(
- sgl, scene, view_layer, v3d, ob, cam, vec, drawsize, scale);
- }
-
- /* Motion Tracking. */
- camera_view3d_reconstruction(sgl, scene, v3d, camera_object, ob, color, is_select);
-}
-
-static void DRW_shgroup_empty_ex(OBJECT_ShadingGroupList *sgl,
- const float mat[4][4],
- const float *draw_size,
- char draw_type,
- const float color[4])
-{
- DRWEmptiesBufferList *buffers = &sgl->empties;
- switch (draw_type) {
- case OB_PLAINAXES:
- DRW_buffer_add_entry(buffers->plain_axes, color, draw_size, mat);
- break;
- case OB_SINGLE_ARROW:
- DRW_buffer_add_entry(buffers->single_arrow, color, draw_size, mat);
- DRW_buffer_add_entry(buffers->single_arrow_line, color, draw_size, mat);
- break;
- case OB_CUBE:
- DRW_buffer_add_entry(buffers->cube, color, draw_size, mat);
- break;
- case OB_CIRCLE:
- DRW_buffer_add_entry(buffers->circle, color, draw_size, mat);
- break;
- case OB_EMPTY_SPHERE:
- DRW_buffer_add_entry(buffers->sphere, color, draw_size, mat);
- break;
- case OB_EMPTY_CONE:
- DRW_buffer_add_entry(buffers->cone, color, draw_size, mat);
- break;
- case OB_ARROWS:
- DRW_buffer_add_entry(buffers->empty_axes, color, draw_size, mat);
- break;
- case OB_EMPTY_IMAGE:
- BLI_assert(!"Should never happen, use DRW_shgroup_empty instead.");
- break;
- }
-}
-
-static void DRW_shgroup_empty(OBJECT_Shaders *sh_data,
- OBJECT_ShadingGroupList *sgl,
- Object *ob,
- ViewLayer *view_layer,
- RegionView3D *rv3d,
- eGPUShaderConfig sh_cfg)
-{
- float *color;
- DRW_object_wire_theme_get(ob, view_layer, &color);
-
- switch (ob->empty_drawtype) {
- case OB_PLAINAXES:
- case OB_SINGLE_ARROW:
- case OB_CUBE:
- case OB_CIRCLE:
- case OB_EMPTY_SPHERE:
- case OB_EMPTY_CONE:
- case OB_ARROWS:
- DRW_shgroup_empty_ex(sgl, ob->obmat, &ob->empty_drawsize, ob->empty_drawtype, color);
- break;
- case OB_EMPTY_IMAGE:
- DRW_shgroup_empty_image(sh_data, sgl, ob, color, rv3d, sh_cfg);
- break;
- }
-}
-
-static void DRW_shgroup_forcefield(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
-{
- int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- float *color = DRW_color_background_blend_get(theme_id);
- PartDeflect *pd = ob->pd;
- Curve *cu = (ob->type == OB_CURVE) ? ob->data : NULL;
-
- /* TODO Move this to depsgraph */
- float tmp[3];
- copy_v3_fl(pd->drawvec1, ob->empty_drawsize);
-
- switch (pd->forcefield) {
- case PFIELD_WIND:
- pd->drawvec1[2] = pd->f_strength;
- break;
- case PFIELD_VORTEX:
- if (pd->f_strength < 0.0f) {
- pd->drawvec1[1] = -pd->drawvec1[1];
- }
- break;
- case PFIELD_GUIDE:
- if (cu && (cu->flag & CU_PATH) && ob->runtime.curve_cache->path &&
- ob->runtime.curve_cache->path->data) {
- where_on_path(ob, 0.0f, pd->drawvec1, tmp, NULL, NULL, NULL);
- where_on_path(ob, 1.0f, pd->drawvec2, tmp, NULL, NULL, NULL);
- }
- break;
- }
-
- if (pd->falloff == PFIELD_FALL_TUBE) {
- pd->drawvec_falloff_max[0] = pd->drawvec_falloff_max[1] = (pd->flag & PFIELD_USEMAXR) ?
- pd->maxrad :
- 1.0f;
- pd->drawvec_falloff_max[2] = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
-
- pd->drawvec_falloff_min[0] = pd->drawvec_falloff_min[1] = (pd->flag & PFIELD_USEMINR) ?
- pd->minrad :
- 1.0f;
- pd->drawvec_falloff_min[2] = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
- }
- else if (pd->falloff == PFIELD_FALL_CONE) {
- float radius, distance;
-
- radius = DEG2RADF((pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f);
- distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
- pd->drawvec_falloff_max[0] = pd->drawvec_falloff_max[1] = distance * sinf(radius);
- pd->drawvec_falloff_max[2] = distance * cosf(radius);
-
- radius = DEG2RADF((pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f);
- distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
-
- pd->drawvec_falloff_min[0] = pd->drawvec_falloff_min[1] = distance * sinf(radius);
- pd->drawvec_falloff_min[2] = distance * cosf(radius);
- }
- /* End of things that should go to depthgraph */
-
- switch (pd->forcefield) {
- case PFIELD_WIND:
- DRW_buffer_add_entry(sgl->field_wind, color, &pd->drawvec1, ob->obmat);
- break;
- case PFIELD_FORCE:
- DRW_buffer_add_entry(sgl->field_force, color, &pd->drawvec1, ob->obmat);
- break;
- case PFIELD_VORTEX:
- DRW_buffer_add_entry(sgl->field_vortex, color, &pd->drawvec1, ob->obmat);
- break;
- case PFIELD_GUIDE:
- if (cu && (cu->flag & CU_PATH) && ob->runtime.curve_cache->path &&
- ob->runtime.curve_cache->path->data) {
- DRW_buffer_add_entry(sgl->field_curve_sta, color, &pd->f_strength, ob->obmat);
- DRW_buffer_add_entry(sgl->field_curve_end, color, &pd->f_strength, ob->obmat);
- }
- break;
- }
-
- if (pd->falloff == PFIELD_FALL_SPHERE) {
- /* as last, guide curve alters it */
- if ((pd->flag & PFIELD_USEMAX) != 0) {
- DRW_buffer_add_entry(sgl->field_curve_end, color, &pd->maxdist, ob->obmat);
- }
-
- if ((pd->flag & PFIELD_USEMIN) != 0) {
- DRW_buffer_add_entry(sgl->field_curve_end, color, &pd->mindist, ob->obmat);
- }
- }
- else if (pd->falloff == PFIELD_FALL_TUBE) {
- if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
- DRW_buffer_add_entry(sgl->field_tube_limit, color, &pd->drawvec_falloff_max, ob->obmat);
- }
-
- if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
- DRW_buffer_add_entry(sgl->field_tube_limit, color, &pd->drawvec_falloff_min, ob->obmat);
- }
- }
- else if (pd->falloff == PFIELD_FALL_CONE) {
- if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
- DRW_buffer_add_entry(sgl->field_cone_limit, color, &pd->drawvec_falloff_max, ob->obmat);
- }
-
- if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
- DRW_buffer_add_entry(sgl->field_cone_limit, color, &pd->drawvec_falloff_min, ob->obmat);
- }
- }
-}
-
-static void DRW_shgroup_volume_extra(OBJECT_ShadingGroupList *sgl,
- Object *ob,
- ViewLayer *view_layer,
- Scene *scene,
- ModifierData *md)
-{
- SmokeModifierData *smd = (SmokeModifierData *)md;
- SmokeDomainSettings *sds = smd->domain;
- float *color;
- float one = 1.0f;
-
- if (sds == NULL) {
- return;
- }
-
- DRW_object_wire_theme_get(ob, view_layer, &color);
-
- /* Small cube showing voxel size. */
- float min[3];
- madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min);
- float voxel_cubemat[4][4] = {{0.0f}};
- /* scale small cube to voxel size */
- voxel_cubemat[0][0] = 1.0f / (float)sds->base_res[0];
- voxel_cubemat[1][1] = 1.0f / (float)sds->base_res[1];
- voxel_cubemat[2][2] = 1.0f / (float)sds->base_res[2];
- voxel_cubemat[3][0] = voxel_cubemat[3][1] = voxel_cubemat[3][2] = -1.0f;
- voxel_cubemat[3][3] = 1.0f;
- /* translate small cube to corner */
- voxel_cubemat[3][0] = min[0];
- voxel_cubemat[3][1] = min[1];
- voxel_cubemat[3][2] = min[2];
- voxel_cubemat[3][3] = 1.0f;
- /* move small cube into the domain (otherwise its centered on vertex of domain object) */
- translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f);
- mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat);
-
- DRW_buffer_add_entry(sgl->empties.cube, color, &one, voxel_cubemat);
-
- /* Don't show smoke before simulation starts, this could be made an option in the future. */
- if (!sds->draw_velocity || !sds->fluid || CFRA < sds->point_cache[0]->startframe) {
- return;
- }
-
- const bool use_needle = (sds->vector_draw_type == VECTOR_DRAW_NEEDLE);
- int line_count = (use_needle) ? 6 : 1;
- int slice_axis = -1;
- line_count *= sds->res[0] * sds->res[1] * sds->res[2];
-
- if (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
- sds->axis_slice_method == AXIS_SLICE_SINGLE) {
- float viewinv[4][4];
- DRW_view_viewmat_get(NULL, viewinv, true);
-
- const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) :
- sds->slice_axis - 1;
- slice_axis = axis;
- line_count /= sds->res[axis];
- }
-
- GPU_create_smoke_velocity(smd);
-
- DRWShadingGroup *grp = DRW_shgroup_create(volume_velocity_shader_get(use_needle),
- sgl->non_meshes);
- DRW_shgroup_uniform_texture(grp, "velocityX", sds->tex_velocity_x);
- DRW_shgroup_uniform_texture(grp, "velocityY", sds->tex_velocity_y);
- DRW_shgroup_uniform_texture(grp, "velocityZ", sds->tex_velocity_z);
- DRW_shgroup_uniform_float_copy(grp, "displaySize", sds->vector_scale);
- DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
- DRW_shgroup_uniform_vec3_copy(grp, "cellSize", sds->cell_size);
- DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", sds->p0);
- DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", sds->res_min);
- DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis);
- DRW_shgroup_call_procedural_lines(grp, ob, line_count);
-
- BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd));
-}
-
-static void volumes_free_smoke_textures(void)
-{
- /* Free Smoke Textures after rendering */
- /* XXX This is a waste of processing and GPU bandwidth if nothing
- * is updated. But the problem is since Textures are stored in the
- * modifier we don't want them to take precious VRAM if the
- * modifier is not used for display. We should share them for
- * all viewport in a redraw at least. */
- for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) {
- SmokeModifierData *smd = (SmokeModifierData *)link->data;
- GPU_free_smoke_velocity(smd);
- }
- BLI_freelistN(&e_data.smoke_domains);
-}
-
-static void DRW_shgroup_speaker(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
-{
- float *color;
- static float one = 1.0f;
- DRW_object_wire_theme_get(ob, view_layer, &color);
-
- DRW_buffer_add_entry(sgl->speaker, color, &one, ob->obmat);
-}
-
-static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
- OBJECT_StorageList *stl,
- OBJECT_PassList *psl,
- Object *ob,
- ViewLayer *view_layer,
- const eGPUShaderConfig sh_cfg)
-{
- float *color;
- static float one = 1.0f;
- LightProbe *prb = (LightProbe *)ob->data;
- bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0);
- int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
-
- OBJECT_ShadingGroupList *sgl = (ob->dtx & OB_DRAWXRAY) ? &stl->g_data->sgl_ghost :
- &stl->g_data->sgl;
-
- if (DRW_state_is_select() || do_outlines) {
- if (prb->type == LIGHTPROBE_TYPE_GRID) {
- float corner[3];
- float increment[3][3];
- /* Update transforms */
- float cell_dim[3], half_cell_dim[3];
- cell_dim[0] = 2.0f / (float)(prb->grid_resolution_x);
- cell_dim[1] = 2.0f / (float)(prb->grid_resolution_y);
- cell_dim[2] = 2.0f / (float)(prb->grid_resolution_z);
-
- mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
-
- /* First cell. */
- copy_v3_fl(corner, -1.0f);
- add_v3_v3(corner, half_cell_dim);
- mul_m4_v3(ob->obmat, corner);
-
- /* Opposite neighbor cell. */
- copy_v3_fl3(increment[0], cell_dim[0], 0.0f, 0.0f);
- copy_v3_fl3(increment[1], 0.0f, cell_dim[1], 0.0f);
- copy_v3_fl3(increment[2], 0.0f, 0.0f, cell_dim[2]);
-
- for (int i = 0; i < 3; i++) {
- add_v3_v3(increment[i], half_cell_dim);
- add_v3_fl(increment[i], -1.0f);
- mul_m4_v3(ob->obmat, increment[i]);
- sub_v3_v3(increment[i], corner);
- }
-
- int outline_id = shgroup_theme_id_to_outline_id(theme_id, ob->base_flag);
- uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->lightprobe_grid, psl->lightprobes);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
- DRW_shgroup_uniform_vec3_copy(grp, "corner", corner);
- DRW_shgroup_uniform_vec3_copy(grp, "increment_x", increment[0]);
- DRW_shgroup_uniform_vec3_copy(grp, "increment_y", increment[1]);
- DRW_shgroup_uniform_vec3_copy(grp, "increment_z", increment[2]);
- DRW_shgroup_uniform_ivec3_copy(grp, "grid_resolution", &prb->grid_resolution_x);
- if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
- }
- DRW_shgroup_call_procedural_points(grp, NULL, cell_count);
- }
- else if (prb->type == LIGHTPROBE_TYPE_PLANAR && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
- DRWShadingGroup *grp = shgroup_theme_id_to_probe_outline_or_null(
- stl, theme_id, ob->base_flag);
- DRW_shgroup_call_no_cull(grp, DRW_cache_quad_get(), ob);
- }
- }
-
- switch (prb->type) {
- case LIGHTPROBE_TYPE_PLANAR:
- DRW_buffer_add_entry(sgl->probe_planar, ob->obmat[3], color);
- break;
- case LIGHTPROBE_TYPE_GRID:
- DRW_buffer_add_entry(sgl->probe_grid, ob->obmat[3], color);
- break;
- case LIGHTPROBE_TYPE_CUBE:
- default:
- DRW_buffer_add_entry(sgl->probe_cube, ob->obmat[3], color);
- break;
- }
-
- if (prb->type == LIGHTPROBE_TYPE_PLANAR) {
- float mat[4][4];
- copy_m4_m4(mat, ob->obmat);
- normalize_m4(mat);
-
- DRW_buffer_add_entry(sgl->empties.single_arrow, color, &ob->empty_drawsize, mat);
- DRW_buffer_add_entry(sgl->empties.single_arrow_line, color, &ob->empty_drawsize, mat);
-
- copy_m4_m4(mat, ob->obmat);
- zero_v3(mat[2]);
-
- DRW_buffer_add_entry(sgl->empties.cube, color, &one, mat);
- }
-
- if ((prb->flag & LIGHTPROBE_FLAG_SHOW_INFLUENCE) != 0) {
-
- prb->distfalloff = (1.0f - prb->falloff) * prb->distinf;
- prb->distgridinf = prb->distinf;
-
- if (prb->type == LIGHTPROBE_TYPE_GRID) {
- prb->distfalloff += 1.0f;
- prb->distgridinf += 1.0f;
- }
-
- if (prb->type == LIGHTPROBE_TYPE_GRID || prb->attenuation_type == LIGHTPROBE_SHAPE_BOX) {
- DRW_buffer_add_entry(sgl->empties.cube, color, &prb->distgridinf, ob->obmat);
- DRW_buffer_add_entry(sgl->empties.cube, color, &prb->distfalloff, ob->obmat);
- }
- else if (prb->type == LIGHTPROBE_TYPE_PLANAR) {
- float rangemat[4][4];
- copy_m4_m4(rangemat, ob->obmat);
- normalize_v3(rangemat[2]);
- mul_v3_fl(rangemat[2], prb->distinf);
-
- DRW_buffer_add_entry(sgl->empties.cube, color, &one, rangemat);
-
- copy_m4_m4(rangemat, ob->obmat);
- normalize_v3(rangemat[2]);
- mul_v3_fl(rangemat[2], prb->distfalloff);
-
- DRW_buffer_add_entry(sgl->empties.cube, color, &one, rangemat);
- }
- else {
- DRW_buffer_add_entry(sgl->empties.sphere, color, &prb->distgridinf, ob->obmat);
- DRW_buffer_add_entry(sgl->empties.sphere, color, &prb->distfalloff, ob->obmat);
- }
- }
-
- if ((prb->flag & LIGHTPROBE_FLAG_SHOW_PARALLAX) != 0) {
- if (prb->type != LIGHTPROBE_TYPE_PLANAR) {
- float(*obmat)[4], *dist;
-
- if ((prb->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) {
- dist = &prb->distpar;
- /* TODO object parallax */
- obmat = ob->obmat;
- }
- else {
- dist = &prb->distinf;
- obmat = ob->obmat;
- }
-
- if (prb->parallax_type == LIGHTPROBE_SHAPE_BOX) {
- DRW_buffer_add_entry(sgl->empties.cube, color, dist, obmat);
- }
- else {
- DRW_buffer_add_entry(sgl->empties.sphere, color, dist, obmat);
- }
- }
- }
-
- if ((prb->flag & LIGHTPROBE_FLAG_SHOW_CLIP_DIST) != 0) {
- if (prb->type != LIGHTPROBE_TYPE_PLANAR) {
- static const float cubefacemat[6][4][4] = {
- {{0.0, 0.0, -1.0, 0.0},
- {0.0, -1.0, 0.0, 0.0},
- {-1.0, 0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0, 1.0}},
- {{0.0, 0.0, 1.0, 0.0},
- {0.0, -1.0, 0.0, 0.0},
- {1.0, 0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0, 1.0}},
- {{1.0, 0.0, 0.0, 0.0},
- {0.0, 0.0, -1.0, 0.0},
- {0.0, 1.0, 0.0, 0.0},
- {0.0, 0.0, 0.0, 1.0}},
- {{1.0, 0.0, 0.0, 0.0},
- {0.0, 0.0, 1.0, 0.0},
- {0.0, -1.0, 0.0, 0.0},
- {0.0, 0.0, 0.0, 1.0}},
- {{1.0, 0.0, 0.0, 0.0},
- {0.0, -1.0, 0.0, 0.0},
- {0.0, 0.0, -1.0, 0.0},
- {0.0, 0.0, 0.0, 1.0}},
- {{-1.0, 0.0, 0.0, 0.0},
- {0.0, -1.0, 0.0, 0.0},
- {0.0, 0.0, 1.0, 0.0},
- {0.0, 0.0, 0.0, 1.0}},
- };
-
- for (int i = 0; i < 6; i++) {
- float clipmat[4][4];
- normalize_m4_m4(clipmat, ob->obmat);
- mul_m4_m4m4(clipmat, clipmat, cubefacemat[i]);
-
- DRW_buffer_add_entry(sgl->light_buflimit, color, &prb->clipsta, &prb->clipend, clipmat);
- DRW_buffer_add_entry(
- sgl->light_buflimit_points, color, &prb->clipsta, &prb->clipend, clipmat);
- }
- }
- }
-
- /* Line and point going to the ground */
- if (prb->type == LIGHTPROBE_TYPE_CUBE) {
- DRW_buffer_add_entry(sgl->light_groundline, ob->obmat[3]);
- DRW_buffer_add_entry(sgl->light_groundpoint, ob->obmat[3]);
- }
-}
-
-static void DRW_shgroup_relationship_lines(OBJECT_ShadingGroupList *sgl,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
-{
- if (ob->parent && (DRW_object_visibility_in_active_context(ob->parent) & OB_VISIBLE_SELF)) {
- DRW_buffer_add_entry(sgl->relationship_lines, ob->runtime.parent_display_origin);
- DRW_buffer_add_entry(sgl->relationship_lines, ob->obmat[3]);
- }
-
- if (ob->rigidbody_constraint) {
- Object *rbc_ob1 = ob->rigidbody_constraint->ob1;
- Object *rbc_ob2 = ob->rigidbody_constraint->ob2;
- if (rbc_ob1 && (DRW_object_visibility_in_active_context(rbc_ob1) & OB_VISIBLE_SELF)) {
- DRW_buffer_add_entry(sgl->relationship_lines, rbc_ob1->obmat[3]);
- DRW_buffer_add_entry(sgl->relationship_lines, ob->obmat[3]);
- }
- if (rbc_ob2 && (DRW_object_visibility_in_active_context(rbc_ob2) & OB_VISIBLE_SELF)) {
- DRW_buffer_add_entry(sgl->relationship_lines, rbc_ob2->obmat[3]);
- DRW_buffer_add_entry(sgl->relationship_lines, ob->obmat[3]);
- }
- }
-
- /* Drawing the constraint lines */
- if (!BLI_listbase_is_empty(&ob->constraints)) {
- bConstraint *curcon;
- bConstraintOb *cob;
- ListBase *list = &ob->constraints;
-
- cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
-
- for (curcon = list->first; curcon; curcon = curcon->next) {
- if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) {
- /* special case for object solver and follow track constraints because they don't fill
- * constraint targets properly (design limitation -- scene is needed for their target
- * but it can't be accessed from get_targets callback) */
-
- Object *camob = NULL;
-
- if (curcon->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = (bFollowTrackConstraint *)curcon->data;
-
- camob = data->camera ? data->camera : scene->camera;
- }
- else if (curcon->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = (bObjectSolverConstraint *)curcon->data;
-
- camob = data->camera ? data->camera : scene->camera;
- }
-
- if (camob) {
- DRW_buffer_add_entry(sgl->constraint_lines, camob->obmat[3]);
- DRW_buffer_add_entry(sgl->constraint_lines, ob->obmat[3]);
- }
- }
- else {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
-
- if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) {
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- cti->get_constraint_targets(curcon, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- /* calculate target's matrix */
- if (cti->get_target_matrix) {
- cti->get_target_matrix(depsgraph, curcon, cob, ct, DEG_get_ctime(depsgraph));
- }
- else {
- unit_m4(ct->matrix);
- }
-
- DRW_buffer_add_entry(sgl->constraint_lines, ct->matrix[3]);
- DRW_buffer_add_entry(sgl->constraint_lines, ob->obmat[3]);
- }
-
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(curcon, &targets, 1);
- }
- }
- }
- }
-
- BKE_constraints_clear_evalob(cob);
- }
-}
-
-static void DRW_shgroup_object_center(OBJECT_StorageList *stl,
- Object *ob,
- ViewLayer *view_layer,
- View3D *v3d)
-{
- if (v3d->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_ORIGINS) {
- return;
- }
- const bool is_library = ob->id.us > 1 || ID_IS_LINKED(ob);
- DRWCallBuffer *buf;
-
- if (ob == OBACT(view_layer)) {
- buf = stl->g_data->center_active;
- }
- else if (ob->base_flag & BASE_SELECTED) {
- if (is_library) {
- buf = stl->g_data->center_selected_lib;
- }
- else {
- buf = stl->g_data->center_selected;
- }
- }
- else if (v3d->flag & V3D_DRAW_CENTERS) {
- if (is_library) {
- buf = stl->g_data->center_deselected_lib;
- }
- else {
- buf = stl->g_data->center_deselected;
- }
- }
- else {
- return;
- }
-
- DRW_buffer_add_entry(buf, ob->obmat[3]);
-}
-
-static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id)
-{
- if (ob->data == NULL) {
- return;
- }
-
- ID *ob_data = ob->data;
- float *texcoloc = NULL;
- float *texcosize = NULL;
-
- switch (GS(ob_data->name)) {
- case ID_ME:
- BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
- break;
- case ID_CU: {
- Curve *cu = (Curve *)ob_data;
- BKE_curve_texspace_ensure(cu);
- texcoloc = cu->loc;
- texcosize = cu->size;
- break;
- }
- case ID_MB: {
- MetaBall *mb = (MetaBall *)ob_data;
- texcoloc = mb->loc;
- texcosize = mb->size;
- break;
- }
- default:
- BLI_assert(0);
- }
-
- float tmp[4][4] = {{0.0f}}, one = 1.0f;
- tmp[0][0] = texcosize[0];
- tmp[1][1] = texcosize[1];
- tmp[2][2] = texcosize[2];
- tmp[3][0] = texcoloc[0];
- tmp[3][1] = texcoloc[1];
- tmp[3][2] = texcoloc[2];
- tmp[3][3] = 1.0f;
-
- mul_m4_m4m4(tmp, ob->obmat, tmp);
-
- float color[4];
- UI_GetThemeColor4fv(theme_id, color);
-
- DRW_buffer_add_entry(sgl->texspace, color, &one, tmp);
-}
-
-static void DRW_shgroup_bounds(
- OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id, char boundtype, bool around_origin)
-{
- float color[4], center[3], size[3], tmp[4][4], final_mat[4][4], one = 1.0f;
- BoundBox bb_local;
-
- if (ob->type == OB_MBALL && !BKE_mball_is_basis(ob)) {
- return;
- }
-
- BoundBox *bb = BKE_object_boundbox_get(ob);
-
- if (!ELEM(ob->type,
- OB_MESH,
- OB_CURVE,
- OB_SURF,
- OB_FONT,
- OB_MBALL,
- OB_ARMATURE,
- OB_LATTICE,
- OB_GPENCIL)) {
- const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
- bb = &bb_local;
- BKE_boundbox_init_from_minmax(bb, min, max);
- }
-
- UI_GetThemeColor4fv(theme_id, color);
- BKE_boundbox_calc_size_aabb(bb, size);
-
- if (around_origin) {
- zero_v3(center);
- }
- else {
- BKE_boundbox_calc_center_aabb(bb, center);
- }
-
- switch (boundtype) {
- case OB_BOUND_BOX:
- size_to_mat4(tmp, size);
- copy_v3_v3(tmp[3], center);
- mul_m4_m4m4(tmp, ob->obmat, tmp);
- DRW_buffer_add_entry(sgl->empties.cube, color, &one, tmp);
- break;
- case OB_BOUND_SPHERE:
- size[0] = max_fff(size[0], size[1], size[2]);
- size[1] = size[2] = size[0];
- size_to_mat4(tmp, size);
- copy_v3_v3(tmp[3], center);
- mul_m4_m4m4(tmp, ob->obmat, tmp);
- DRW_buffer_add_entry(sgl->empties.sphere, color, &one, tmp);
- break;
- case OB_BOUND_CYLINDER:
- size[0] = max_ff(size[0], size[1]);
- size[1] = size[0];
- size_to_mat4(tmp, size);
- copy_v3_v3(tmp[3], center);
- mul_m4_m4m4(tmp, ob->obmat, tmp);
- DRW_buffer_add_entry(sgl->empties.cylinder, color, &one, tmp);
- break;
- case OB_BOUND_CONE:
- size[0] = max_ff(size[0], size[1]);
- size[1] = size[0];
- size_to_mat4(tmp, size);
- copy_v3_v3(tmp[3], center);
- /* Cone batch has base at 0 and is pointing towards +Y. */
- swap_v3_v3(tmp[1], tmp[2]);
- tmp[3][2] -= size[2];
- mul_m4_m4m4(tmp, ob->obmat, tmp);
- DRW_buffer_add_entry(sgl->empties.cone, color, &one, tmp);
- break;
- case OB_BOUND_CAPSULE:
- size[0] = max_ff(size[0], size[1]);
- size[1] = size[0];
- scale_m4_fl(tmp, size[0]);
- copy_v2_v2(tmp[3], center);
- tmp[3][2] = center[2] + max_ff(0.0f, size[2] - size[0]);
- mul_m4_m4m4(final_mat, ob->obmat, tmp);
- DRW_buffer_add_entry(sgl->empties.capsule_cap, color, &one, final_mat);
- negate_v3(tmp[2]);
- tmp[3][2] = center[2] - max_ff(0.0f, size[2] - size[0]);
- mul_m4_m4m4(final_mat, ob->obmat, tmp);
- DRW_buffer_add_entry(sgl->empties.capsule_cap, color, &one, final_mat);
- tmp[2][2] = max_ff(0.0f, size[2] * 2.0f - size[0] * 2.0f);
- mul_m4_m4m4(final_mat, ob->obmat, tmp);
- DRW_buffer_add_entry(sgl->empties.capsule_body, color, &one, final_mat);
- break;
- }
-}
-
-static void DRW_shgroup_collision(OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id)
-{
- switch (ob->rigidbody_object->shape) {
- case RB_SHAPE_BOX:
- DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_BOX, true);
- break;
- case RB_SHAPE_SPHERE:
- DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_SPHERE, true);
- break;
- case RB_SHAPE_CONE:
- DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_CONE, true);
- break;
- case RB_SHAPE_CYLINDER:
- DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_CYLINDER, true);
- break;
- case RB_SHAPE_CAPSULE:
- DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_CAPSULE, true);
- break;
- }
-}
-
-static void OBJECT_cache_populate_particles(OBJECT_Shaders *sh_data,
- Object *ob,
- OBJECT_PassList *psl)
-{
- for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
- continue;
- }
-
- ParticleSettings *part = psys->part;
- int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
-
- if (part->type == PART_HAIR) {
- /* Hairs should have been rendered by the render engine.*/
- continue;
- }
-
- if (!ELEM(draw_as, PART_DRAW_NOT, PART_DRAW_OB, PART_DRAW_GR)) {
- struct GPUBatch *geom = DRW_cache_particles_get_dots(ob, psys);
- DRWShadingGroup *shgrp = NULL;
- struct GPUBatch *shape = NULL;
- static float def_prim_col[3] = {0.5f, 0.5f, 0.5f};
- static float def_sec_col[3] = {1.0f, 1.0f, 1.0f};
-
- Material *ma = give_current_material(ob, part->omat);
-
- switch (draw_as) {
- default:
- case PART_DRAW_DOT:
- shgrp = DRW_shgroup_create(sh_data->part_dot, psl->particle);
- DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
- DRW_shgroup_uniform_vec3(shgrp, "outlineColor", ma ? &ma->specr : def_sec_col, 1);
- DRW_shgroup_uniform_float(shgrp, "pixel_size", DRW_viewport_pixelsize_get(), 1);
- DRW_shgroup_uniform_float(shgrp, "size", &part->draw_size, 1);
- DRW_shgroup_uniform_texture(shgrp, "ramp", G_draw.ramp);
- DRW_shgroup_call(shgrp, geom, NULL);
- break;
- case PART_DRAW_CROSS:
- shgrp = DRW_shgroup_create(sh_data->part_prim, psl->particle);
- DRW_shgroup_uniform_texture(shgrp, "ramp", G_draw.ramp);
- DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
- DRW_shgroup_uniform_float(shgrp, "draw_size", &part->draw_size, 1);
- DRW_shgroup_uniform_bool_copy(shgrp, "screen_space", false);
- shape = DRW_cache_particles_get_prim(PART_DRAW_CROSS);
- DRW_shgroup_call_instances_with_attribs(shgrp, NULL, shape, geom);
- break;
- case PART_DRAW_CIRC:
- shape = DRW_cache_particles_get_prim(PART_DRAW_CIRC);
- shgrp = DRW_shgroup_create(sh_data->part_prim, psl->particle);
- DRW_shgroup_uniform_texture(shgrp, "ramp", G_draw.ramp);
- DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
- DRW_shgroup_uniform_float(shgrp, "draw_size", &part->draw_size, 1);
- DRW_shgroup_uniform_bool_copy(shgrp, "screen_space", true);
- DRW_shgroup_call_instances_with_attribs(shgrp, NULL, shape, geom);
- break;
- case PART_DRAW_AXIS:
- shape = DRW_cache_particles_get_prim(PART_DRAW_AXIS);
- shgrp = DRW_shgroup_create(sh_data->part_axis, psl->particle);
- DRW_shgroup_uniform_float(shgrp, "draw_size", &part->draw_size, 1);
- DRW_shgroup_uniform_bool_copy(shgrp, "screen_space", false);
- DRW_shgroup_call_instances_with_attribs(shgrp, NULL, shape, geom);
- break;
- }
- }
- }
-}
-
-static void OBJECT_gpencil_color_names(Object *ob, struct DRWTextStore *dt, uchar color[4])
-{
- if (ob->mode != OB_MODE_EDIT_GPENCIL) {
- return;
- }
-
- bGPdata *gpd = (bGPdata *)ob->data;
- if (gpd == NULL) {
- return;
- }
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->flag & GP_LAYER_HIDE) {
- continue;
- }
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- continue;
- }
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- Material *ma = give_current_material(ob, gps->mat_nr + 1);
- if (ma == NULL) {
- continue;
- }
-
- MaterialGPencilStyle *gp_style = ma->gp_style;
- /* skip stroke if it doesn't have any valid data */
- if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
- continue;
- }
- /* check if the color is visible */
- if (gp_style->flag & GP_STYLE_COLOR_HIDE) {
- continue;
- }
-
- /* only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- float fpt[3];
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- if (pt->flag & GP_SPOINT_SELECT) {
- mul_v3_m4v3(fpt, ob->obmat, &pt->x);
- DRW_text_cache_add(dt,
- fpt,
- ma->id.name + 2,
- strlen(ma->id.name + 2),
- 10,
- 0,
- DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
- color);
- break;
- }
- }
- }
- }
- }
-}
-
-BLI_INLINE OBJECT_DupliData *OBJECT_duplidata_get(Object *ob, void *vedata, bool *init)
-{
- OBJECT_DupliData **dupli_data = (OBJECT_DupliData **)DRW_duplidata_get(vedata);
- *init = false;
- if (!ELEM(ob->type, OB_MESH, OB_SURF, OB_LATTICE, OB_CURVE, OB_FONT)) {
- return NULL;
- }
-
- if (dupli_data) {
- if (*dupli_data == NULL) {
- *dupli_data = MEM_callocN(sizeof(OBJECT_DupliData), "OBJECT_DupliData");
- *init = true;
- }
- else if ((*dupli_data)->base_flag != ob->base_flag) {
- /* Select state might have change, reinit. */
- *init = true;
- }
- return *dupli_data;
- }
- return NULL;
-}
-
-static void OBJECT_cache_populate(void *vedata, Object *ob)
-{
- OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl;
- OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
- OBJECT_ShadingGroupList *sgl = (ob->dtx & OB_DRAWXRAY) ? &stl->g_data->sgl_ghost :
- &stl->g_data->sgl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const bool is_edit_mode = (ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob);
- ViewLayer *view_layer = draw_ctx->view_layer;
- Scene *scene = draw_ctx->scene;
- View3D *v3d = draw_ctx->v3d;
- RegionView3D *rv3d = draw_ctx->rv3d;
- ModifierData *md = NULL;
- int theme_id = TH_UNDEFINED;
- const int ob_visibility = DRW_object_visibility_in_active_context(ob);
- OBJECT_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- /* Handle particles first in case the emitter itself shouldn't be rendered. */
- if (ob_visibility & OB_VISIBLE_PARTICLES) {
- OBJECT_cache_populate_particles(sh_data, ob, psl);
- }
-
- if ((ob_visibility & OB_VISIBLE_SELF) == 0) {
- return;
- }
-
- const bool do_outlines = ((draw_ctx->v3d->flag & V3D_SELECT_OUTLINE) &&
- ((ob->base_flag & BASE_SELECTED) != 0) &&
- ((DRW_object_is_renderable(ob) && (ob->dt > OB_WIRE)) ||
- (ob->dt == OB_WIRE)));
- const bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0);
- const bool hide_object_extra =
- ((v3d->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_XTRAS) != 0 &&
- /* Show if this is the camera we're looking through since it's useful for selecting. */
- (((rv3d->persp == RV3D_CAMOB) && ((ID *)v3d->camera == ob->id.orig_id)) == 0));
-
- /* Fast path for duplis. */
- bool init_duplidata;
- OBJECT_DupliData *dupli_data = OBJECT_duplidata_get(ob, vedata, &init_duplidata);
-
- if (do_outlines) {
- if (!BKE_object_is_in_editmode(ob) &&
- !((ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT))) {
- struct GPUBatch *geom;
- DRWShadingGroup *shgroup = NULL;
-
- /* This fixes only the biggest case which is a plane in ortho view. */
- int flat_axis = 0;
- bool is_flat_object_viewed_from_side = ((rv3d->persp == RV3D_ORTHO) &&
- DRW_object_is_flat(ob, &flat_axis) &&
- DRW_object_axis_orthogonal_to_view(ob, flat_axis));
-
- if (dupli_data && !init_duplidata) {
- geom = dupli_data->outline_geom;
- shgroup = dupli_data->outline_shgrp;
- /* TODO: Remove. Only here to increment outline id counter. */
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- shgroup = shgroup_theme_id_to_outline_or_null(stl, theme_id, ob->base_flag);
- }
- else {
- if (stl->g_data->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) {
- geom = DRW_cache_object_edge_detection_get(ob, NULL);
- }
- else {
- geom = DRW_cache_object_surface_get(ob);
- }
-
- if (geom) {
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- shgroup = shgroup_theme_id_to_outline_or_null(stl, theme_id, ob->base_flag);
- }
- }
-
- if (shgroup && geom) {
- DRW_shgroup_call(shgroup, geom, ob);
- }
-
- if (init_duplidata) {
- dupli_data->outline_shgrp = shgroup;
- dupli_data->outline_geom = geom;
- }
- }
- }
-
- if (dupli_data && !init_duplidata) {
- if (dupli_data->extra_shgrp && dupli_data->extra_geom) {
- DRW_shgroup_call(dupli_data->extra_shgrp, dupli_data->extra_geom, ob);
- }
- }
- else {
- struct GPUBatch *geom = NULL;
- DRWShadingGroup *shgroup = NULL;
- switch (ob->type) {
- case OB_MESH: {
- if (hide_object_extra) {
- break;
- }
- Mesh *me = ob->data;
- if (!is_edit_mode && me->totedge == 0) {
- geom = DRW_cache_mesh_all_verts_get(ob);
- if (geom) {
- if (theme_id == TH_UNDEFINED) {
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- }
- shgroup = shgroup_theme_id_to_point(sgl, theme_id, ob->base_flag);
- DRW_shgroup_call(shgroup, geom, ob);
- }
- }
- else {
- bool has_edit_mesh_cage = false;
- /* TODO: Should be its own function. */
- if (is_edit_mode) {
- BMEditMesh *embm = me->edit_mesh;
- has_edit_mesh_cage = embm->mesh_eval_cage &&
- (embm->mesh_eval_cage != embm->mesh_eval_final);
- }
- if ((!is_edit_mode && me->totedge > 0) || has_edit_mesh_cage) {
- geom = DRW_cache_mesh_loose_edges_get(ob);
- if (geom) {
- if (theme_id == TH_UNDEFINED) {
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- }
- shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
- DRW_shgroup_call(shgroup, geom, ob);
- }
- }
- }
- break;
- }
- case OB_SURF: {
- if (hide_object_extra) {
- break;
- }
- geom = DRW_cache_surf_edge_wire_get(ob);
- if (geom == NULL) {
- break;
- }
- if (theme_id == TH_UNDEFINED) {
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- }
- shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
- DRW_shgroup_call(shgroup, geom, ob);
- break;
- }
- case OB_LATTICE: {
- if (!is_edit_mode) {
- if (hide_object_extra) {
- break;
- }
- geom = DRW_cache_lattice_wire_get(ob, false);
- if (geom == NULL) {
- break;
- }
- if (theme_id == TH_UNDEFINED) {
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- }
- shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
- DRW_shgroup_call(shgroup, geom, ob);
- }
- break;
- }
- case OB_CURVE: {
- if (!is_edit_mode) {
- if (hide_object_extra) {
- break;
- }
- geom = DRW_cache_curve_edge_wire_get(ob);
- if (geom == NULL) {
- break;
- }
- if (theme_id == TH_UNDEFINED) {
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- }
- shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
- DRW_shgroup_call(shgroup, geom, ob);
- }
- break;
- }
- case OB_MBALL: {
- if (!is_edit_mode) {
- DRW_shgroup_mball_handles(sgl, ob, view_layer);
- }
- break;
- }
- case OB_LAMP:
- if (hide_object_extra) {
- break;
- }
- DRW_shgroup_light(sgl, ob, view_layer);
- break;
- case OB_CAMERA:
- if (hide_object_extra) {
- break;
- }
- DRW_shgroup_camera(sgl, ob, view_layer);
- DRW_shgroup_camera_background_images(sh_data, psl, ob, rv3d);
- break;
- case OB_EMPTY:
- if (hide_object_extra) {
- break;
- }
- if ((ob->base_flag & BASE_FROM_DUPLI) && (ob->transflag & OB_DUPLICOLLECTION) &&
- ob->instance_collection) {
- break;
- }
- DRW_shgroup_empty(sh_data, sgl, ob, view_layer, rv3d, draw_ctx->sh_cfg);
- break;
- case OB_SPEAKER:
- if (hide_object_extra) {
- break;
- }
- DRW_shgroup_speaker(sgl, ob, view_layer);
- break;
- case OB_LIGHTPROBE:
- if (hide_object_extra) {
- break;
- }
- DRW_shgroup_lightprobe(sh_data, stl, psl, ob, view_layer, draw_ctx->sh_cfg);
- break;
- case OB_ARMATURE: {
- if ((v3d->flag2 & V3D_HIDE_OVERLAYS) || (v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES) ||
- ((ob->dt < OB_WIRE) && !DRW_state_is_select())) {
- break;
- }
- bArmature *arm = ob->data;
- if (arm->edbo == NULL) {
- if (DRW_state_is_select() || !DRW_pose_mode_armature(ob, draw_ctx->obact)) {
- bool is_wire = (v3d->shading.type == OB_WIRE) || (ob->dt <= OB_WIRE) ||
- XRAY_FLAG_ENABLED(v3d);
- DRWArmaturePasses passes = {
- .bone_solid = (is_wire) ? NULL : sgl->bone_solid,
- .bone_outline = sgl->bone_outline,
- .bone_wire = sgl->bone_wire,
- .bone_envelope = sgl->bone_envelope,
- .bone_axes = sgl->bone_axes,
- .relationship_lines = NULL, /* Don't draw relationship lines */
- .custom_shapes = stl->g_data->custom_shapes,
- };
- DRW_shgroup_armature_object(ob, view_layer, passes, is_wire);
- }
- }
- break;
- }
- case OB_FONT: {
- if (hide_object_extra) {
- break;
- }
- Curve *cu = (Curve *)ob->data;
- bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f ||
- cu->ext2 != 0.0f;
- if (!has_surface) {
- geom = DRW_cache_text_edge_wire_get(ob);
- if (geom) {
- if (theme_id == TH_UNDEFINED) {
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- }
- shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
- DRW_shgroup_call(shgroup, geom, ob);
- }
- }
- break;
- }
- default:
- break;
- }
-
- if (init_duplidata) {
- dupli_data->extra_shgrp = shgroup;
- dupli_data->extra_geom = geom;
- dupli_data->base_flag = ob->base_flag;
- }
- }
-
- if (ob->pd && ob->pd->forcefield) {
- DRW_shgroup_forcefield(sgl, ob, view_layer);
- }
-
- if ((ob->dt == OB_BOUNDBOX) &&
- !ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_EMPTY, OB_SPEAKER, OB_LIGHTPROBE)) {
- if (theme_id == TH_UNDEFINED) {
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- }
- DRW_shgroup_bounds(sgl, ob, theme_id, ob->boundtype, false);
- }
-
- /* Helpers for when we're transforming origins. */
- if (draw_ctx->object_mode == OB_MODE_OBJECT) {
- if (scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) {
- if (ob->base_flag & BASE_SELECTED) {
- if (!DRW_state_is_select()) {
- const float color[4] = {0.75, 0.75, 0.75, 0.5};
- float axes_size = 1.0f;
- DRW_buffer_add_entry(sgl->origin_xform, color, &axes_size, ob->obmat);
- }
- }
- }
- }
-
- /* don't show object extras in set's */
- if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
- if ((draw_ctx->object_mode & (OB_MODE_ALL_PAINT | OB_MODE_ALL_PAINT_GPENCIL)) == 0) {
- DRW_shgroup_object_center(stl, ob, view_layer, v3d);
- }
-
- if (show_relations && !DRW_state_is_select()) {
- DRW_shgroup_relationship_lines(sgl, draw_ctx->depsgraph, scene, ob);
- }
-
- const bool draw_extra = ob->dtx & (OB_DRAWNAME | OB_TEXSPACE | OB_DRAWBOUNDOX);
- if (draw_extra && (theme_id == TH_UNDEFINED)) {
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- }
-
- if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) {
- struct DRWTextStore *dt = DRW_text_cache_ensure();
-
- uchar color[4];
- UI_GetThemeColor4ubv(theme_id, color);
-
- DRW_text_cache_add(dt,
- ob->obmat[3],
- ob->id.name + 2,
- strlen(ob->id.name + 2),
- 10,
- 0,
- DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
- color);
-
- /* draw grease pencil stroke names */
- if (ob->type == OB_GPENCIL) {
- OBJECT_gpencil_color_names(ob, dt, color);
- }
- }
-
- if ((ob->dtx & OB_TEXSPACE) && ELEM(ob->type, OB_MESH, OB_CURVE, OB_MBALL)) {
- DRW_shgroup_texture_space(sgl, ob, theme_id);
- }
-
- /* Don't draw bounding box again if draw type is bound box. */
- if ((ob->dtx & OB_DRAWBOUNDOX) && (ob->dt != OB_BOUNDBOX) &&
- !ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_EMPTY, OB_SPEAKER, OB_LIGHTPROBE)) {
- DRW_shgroup_bounds(sgl, ob, theme_id, ob->boundtype, false);
- }
-
- if (ob->dtx & OB_AXIS) {
- float *color, axes_size = 1.0f;
- DRW_object_wire_theme_get(ob, view_layer, &color);
-
- DRW_buffer_add_entry(sgl->empties.empty_axes, color, &axes_size, ob->obmat);
- }
-
- if (ob->rigidbody_object) {
- DRW_shgroup_collision(sgl, ob, theme_id);
- }
-
- if ((md = modifiers_findByType(ob, eModifierType_Smoke)) &&
- (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- (((SmokeModifierData *)md)->domain != NULL)) {
- DRW_shgroup_volume_extra(sgl, ob, view_layer, scene, md);
- }
- }
-}
-
-static void OBJECT_cache_finish(void *vedata)
-{
- OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
-
- DRW_pass_sort_shgroup_z(stl->g_data->sgl.image_empties);
- DRW_pass_sort_shgroup_z(stl->g_data->sgl_ghost.image_empties);
-
- if (stl->g_data->custom_shapes) {
- /* TODO(fclem): Do not free it for each frame but reuse it. Avoiding alloc cost. */
- BLI_ghash_free(stl->g_data->custom_shapes, NULL, NULL);
- }
-}
-
-static void OBJECT_draw_scene(void *vedata)
-{
- OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl;
- OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
- OBJECT_FramebufferList *fbl = ((OBJECT_Data *)vedata)->fbl;
- OBJECT_PrivateData *g_data = stl->g_data;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- int do_outlines = !DRW_pass_is_empty(psl->outlines) || !DRW_pass_is_empty(psl->lightprobes);
-
- float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
- DRW_draw_pass(psl->camera_images_back_alpha_under);
- DRW_draw_pass(psl->camera_images_back_alpha_over);
-
- /* Don't draw Transparent passes in MSAA buffer. */
- // DRW_draw_pass(psl->bone_envelope); /* Never drawn in Object mode currently. */
- DRW_draw_pass(g_data->sgl.transp_shapes);
-
- MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
-
- DRW_draw_pass(g_data->sgl.bone_solid);
- DRW_draw_pass(g_data->sgl.bone_wire);
- DRW_draw_pass(g_data->sgl.bone_outline);
- DRW_draw_pass(g_data->sgl.non_meshes);
- DRW_draw_pass(psl->particle);
- DRW_draw_pass(g_data->sgl.bone_axes);
-
- MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
-
- DRW_draw_pass(g_data->sgl.image_empties);
-
- if (DRW_state_is_fbo() && do_outlines) {
- DRW_stats_group_start("Outlines");
-
- /* Render filled polygon on a separate framebuffer */
- GPU_framebuffer_bind(fbl->outlines_fb);
- GPU_framebuffer_clear_color_depth(fbl->outlines_fb, clearcol, 1.0f);
- DRW_draw_pass(psl->outlines);
- DRW_draw_pass(psl->lightprobes);
-
- /* Search outline pixels */
- GPU_framebuffer_bind(fbl->blur_fb);
- DRW_draw_pass(psl->outlines_search);
-
- /* Expand outline to form a 3px wide line */
- GPU_framebuffer_bind(fbl->expand_fb);
- DRW_draw_pass(psl->outlines_expand);
-
- /* Bleed color so the AA can do it's stuff */
- GPU_framebuffer_bind(fbl->blur_fb);
- DRW_draw_pass(psl->outlines_bleed);
-
- /* restore main framebuffer */
- GPU_framebuffer_bind(dfbl->default_fb);
- DRW_stats_group_end();
- }
- else if (DRW_state_is_select()) {
- /* Render probes spheres/planes so we can select them. */
- DRW_draw_pass(psl->lightprobes);
- }
-
- if (DRW_state_is_fbo()) {
- if (e_data.draw_grid) {
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_draw_pass(psl->grid);
- }
-
- /* Combine with scene buffer last */
- if (do_outlines) {
- DRW_draw_pass(psl->outlines_resolve);
- }
- }
- volumes_free_smoke_textures();
- batch_camera_path_free(&stl->g_data->sgl.camera_path);
-
- if (!DRW_pass_is_empty(stl->g_data->sgl_ghost.bone_solid) ||
- !DRW_pass_is_empty(stl->g_data->sgl_ghost.bone_wire) ||
- !DRW_pass_is_empty(stl->g_data->sgl_ghost.bone_outline) ||
- !DRW_pass_is_empty(stl->g_data->sgl_ghost.non_meshes) ||
- !DRW_pass_is_empty(stl->g_data->sgl_ghost.image_empties) ||
- !DRW_pass_is_empty(stl->g_data->sgl_ghost.bone_axes)) {
- if (DRW_state_is_fbo()) {
- /* meh, late init to not request a depth buffer we won't use. */
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
-
- GPUTexture *ghost_depth_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_object_type);
- GPU_framebuffer_ensure_config(&fbl->ghost_fb,
- {
- GPU_ATTACHMENT_TEXTURE(ghost_depth_tx),
- GPU_ATTACHMENT_TEXTURE(dtxl->color),
- });
-
- GPU_framebuffer_bind(fbl->ghost_fb);
- GPU_framebuffer_clear_depth(fbl->ghost_fb, 1.0f);
- }
- else if (DRW_state_is_select()) {
- /* XXX `GPU_depth_range` is not a perfect solution
- * since very distant geometries can still be occluded.
- * Also the depth test precision of these geometries is impaired.
- * However solves the selection for the vast majority of cases. */
- GPU_depth_range(0.0f, 0.01f);
- }
-
- DRW_draw_pass(stl->g_data->sgl_ghost.transp_shapes);
- DRW_draw_pass(stl->g_data->sgl_ghost.bone_solid);
- DRW_draw_pass(stl->g_data->sgl_ghost.bone_wire);
- DRW_draw_pass(stl->g_data->sgl_ghost.bone_outline);
- DRW_draw_pass(stl->g_data->sgl_ghost.non_meshes);
- DRW_draw_pass(stl->g_data->sgl_ghost.image_empties);
- DRW_draw_pass(stl->g_data->sgl_ghost.bone_axes);
-
- if (DRW_state_is_select()) {
- GPU_depth_range(0.0f, 1.0f);
- }
- }
-
- batch_camera_path_free(&stl->g_data->sgl_ghost.camera_path);
-
- DRW_draw_pass(psl->camera_images_front_alpha_over);
- camera_background_images_free_textures();
-
- DRW_draw_pass(psl->ob_center);
-}
-
-static const DrawEngineDataSize OBJECT_data_size = DRW_VIEWPORT_DATA_SIZE(OBJECT_Data);
-
-DrawEngineType draw_engine_object_type = {
- NULL,
- NULL,
- N_("ObjectMode"),
- &OBJECT_data_size,
- &OBJECT_engine_init,
- &OBJECT_engine_free,
- &OBJECT_cache_init,
- &OBJECT_cache_populate,
- &OBJECT_cache_finish,
- NULL,
- &OBJECT_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c
deleted file mode 100644
index 9106e89663d..00000000000
--- a/source/blender/draw/modes/overlay_mode.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "DNA_mesh_types.h"
-#include "DNA_view3d_types.h"
-
-#include "BKE_editmesh.h"
-#include "BKE_global.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-
-#include "BLI_hash.h"
-
-#include "GPU_shader.h"
-#include "DRW_render.h"
-
-#include "ED_view3d.h"
-
-#include "draw_mode_engines.h"
-
-#ifdef __APPLE__
-# define USE_GEOM_SHADER_WORKAROUND 1
-#else
-# define USE_GEOM_SHADER_WORKAROUND 0
-#endif
-
-/* Structures */
-
-typedef struct OVERLAY_DupliData {
- DRWShadingGroup *shgrp;
- struct GPUBatch *geom;
- short base_flag;
-} OVERLAY_DupliData;
-
-typedef struct OVERLAY_StorageList {
- struct OVERLAY_PrivateData *g_data;
-} OVERLAY_StorageList;
-
-typedef struct OVERLAY_PassList {
- struct DRWPass *face_orientation_pass;
- struct DRWPass *face_wireframe_pass;
- struct DRWPass *face_wireframe_only_pass;
- struct DRWPass *face_wireframe_xray_pass;
-} OVERLAY_PassList;
-
-typedef struct OVERLAY_Data {
- void *engine_type;
- DRWViewportEmptyList *fbl;
- DRWViewportEmptyList *txl;
- OVERLAY_PassList *psl;
- OVERLAY_StorageList *stl;
-} OVERLAY_Data;
-
-typedef struct OVERLAY_PrivateData {
- DRWShadingGroup *face_orientation_shgrp;
- DRWShadingGroup *face_wires_shgrp;
- DRWShadingGroup *face_wires_xray_shgrp;
- DRWView *view_wires;
- View3DOverlay overlay;
- float wire_step_param;
- bool clear_stencil;
- bool show_overlays;
-} OVERLAY_PrivateData; /* Transient data */
-
-typedef struct OVERLAY_Shaders {
- /* Face orientation shader */
- struct GPUShader *face_orientation;
- /* Wireframe shader */
- struct GPUShader *select_wireframe;
- struct GPUShader *face_wireframe;
-} OVERLAY_Shaders;
-
-/* *********** STATIC *********** */
-static struct {
- OVERLAY_Shaders sh_data[GPU_SHADER_CFG_LEN];
-} e_data = {{{NULL}}};
-
-/* Shaders */
-extern char datatoc_overlay_face_orientation_frag_glsl[];
-extern char datatoc_overlay_face_orientation_vert_glsl[];
-
-extern char datatoc_overlay_face_wireframe_vert_glsl[];
-extern char datatoc_overlay_face_wireframe_geom_glsl[];
-extern char datatoc_overlay_face_wireframe_frag_glsl[];
-extern char datatoc_gpu_shader_depth_only_frag_glsl[];
-
-extern char datatoc_common_view_lib_glsl[];
-
-/* Functions */
-static void overlay_engine_init(void *vedata)
-{
- OVERLAY_Data *data = vedata;
- OVERLAY_StorageList *stl = data->stl;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
- }
-
- stl->g_data->clear_stencil = (draw_ctx->v3d->shading.type > OB_SOLID);
-
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
-
- if (!sh_data->face_orientation) {
- /* Face orientation */
- sh_data->face_orientation = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_overlay_face_orientation_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_overlay_face_orientation_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- if (!sh_data->face_wireframe) {
- sh_data->select_wireframe = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_overlay_face_wireframe_vert_glsl,
- NULL},
- .geom = (const char *[]){sh_cfg_data->lib, datatoc_overlay_face_wireframe_geom_glsl, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_depth_only_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define SELECT_EDGES\n", NULL},
- });
-#if USE_GEOM_SHADER_WORKAROUND
- /* Apple drivers does not support wide wires. Use geometry shader as a workaround. */
- sh_data->face_wireframe = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_overlay_face_wireframe_vert_glsl,
- NULL},
- .geom = (const char *[]){sh_cfg_data->lib, datatoc_overlay_face_wireframe_geom_glsl, NULL},
- .frag = (const char *[]){datatoc_overlay_face_wireframe_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define USE_GEOM\n", NULL},
- });
-#else
- sh_data->face_wireframe = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_overlay_face_wireframe_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_overlay_face_wireframe_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
-#endif
- }
-
- stl->g_data->view_wires = DRW_view_create_with_zoffset(draw_ctx->rv3d, 0.5f);
-}
-
-static void geometry_shader_uniforms(DRWShadingGroup *shgrp)
-{
- DRW_shgroup_uniform_float_copy(shgrp, "wireSize", U.pixelsize * 0.5f);
- DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_vec2(shgrp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1);
-}
-
-static void overlay_cache_init(void *vedata)
-{
- OVERLAY_Data *data = vedata;
- OVERLAY_PassList *psl = data->psl;
- OVERLAY_StorageList *stl = data->stl;
- OVERLAY_PrivateData *g_data = stl->g_data;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
- View3D *v3d = draw_ctx->v3d;
- OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- if (v3d) {
- g_data->overlay = v3d->overlay;
- g_data->show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
- }
- else {
- memset(&g_data->overlay, 0, sizeof(g_data->overlay));
- g_data->show_overlays = false;
- }
-
- if (g_data->show_overlays == false) {
- g_data->overlay.flag = 0;
- }
-
- if (v3d->shading.type == OB_WIRE) {
- g_data->overlay.flag |= V3D_OVERLAY_WIREFRAMES;
- }
-
- {
- /* Face Orientation Pass */
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
- psl->face_orientation_pass = DRW_pass_create("Face Orientation", state);
- g_data->face_orientation_shgrp = DRW_shgroup_create(sh_data->face_orientation,
- psl->face_orientation_pass);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->face_orientation_shgrp, DRW_STATE_CLIP_PLANES);
- }
- }
-
- {
- /* Wireframe */
- const bool use_select = (DRW_state_is_select() || DRW_state_is_depth());
- GPUShader *face_wires_sh = use_select ? sh_data->select_wireframe : sh_data->face_wireframe;
-
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_STENCIL_EQUAL | DRW_STATE_FIRST_VERTEX_CONVENTION;
- psl->face_wireframe_pass = DRW_pass_create("Wires", state);
- g_data->face_wires_shgrp = DRW_shgroup_create(face_wires_sh, psl->face_wireframe_pass);
-
- DRWState state_xray = DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_STENCIL |
- DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_STENCIL_NEQUAL |
- DRW_STATE_FIRST_VERTEX_CONVENTION;
- psl->face_wireframe_xray_pass = DRW_pass_create("Wires Only Xray", state_xray);
- g_data->face_wires_xray_shgrp = DRW_shgroup_create(face_wires_sh,
- psl->face_wireframe_xray_pass);
-
- if (use_select || USE_GEOM_SHADER_WORKAROUND) {
- geometry_shader_uniforms(g_data->face_wires_shgrp);
- geometry_shader_uniforms(g_data->face_wires_xray_shgrp);
- }
- g_data->wire_step_param = stl->g_data->overlay.wireframe_threshold - 254.0f / 255.0f;
- }
-}
-
-static void overlay_wire_color_get(const View3D *v3d,
- const Object *ob,
- const bool use_coloring,
- float **rim_col,
- float **wire_col)
-{
-#ifndef NDEBUG
- *rim_col = NULL;
- *wire_col = NULL;
-#endif
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- if (UNLIKELY(ob->base_flag & BASE_FROM_SET)) {
- *rim_col = G_draw.block.colorDupli;
- *wire_col = G_draw.block.colorDupli;
- }
- else if (UNLIKELY(ob->base_flag & BASE_FROM_DUPLI)) {
- if (ob->base_flag & BASE_SELECTED) {
- if (G.moving & G_TRANSFORM_OBJ) {
- *rim_col = G_draw.block.colorTransform;
- }
- else {
- *rim_col = G_draw.block.colorDupliSelect;
- }
- }
- else {
- *rim_col = G_draw.block.colorDupli;
- }
- *wire_col = G_draw.block.colorDupli;
- }
- else if ((ob->base_flag & BASE_SELECTED) && use_coloring) {
- if (G.moving & G_TRANSFORM_OBJ) {
- *rim_col = G_draw.block.colorTransform;
- }
- else if (ob == draw_ctx->obact) {
- *rim_col = G_draw.block.colorActive;
- }
- else {
- *rim_col = G_draw.block.colorSelect;
- }
- *wire_col = G_draw.block.colorWire;
- }
- else {
- *rim_col = G_draw.block.colorWire;
- *wire_col = G_draw.block.colorBackground;
- }
-
- if (v3d->shading.type == OB_WIRE) {
- if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) {
- /* Theses stays valid until next call. So we need to copy them when using them as uniform. */
- static float wire_col_val[3], rim_col_val[3];
- *wire_col = wire_col_val;
- *rim_col = rim_col_val;
-
- if (v3d->shading.wire_color_type == V3D_SHADING_OBJECT_COLOR) {
- linearrgb_to_srgb_v3_v3(*wire_col, ob->color);
- mul_v3_fl(*wire_col, 0.5f);
- copy_v3_v3(*rim_col, *wire_col);
- }
- else {
- uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
- if (ob->id.lib) {
- hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
- }
-
- float hue = BLI_hash_int_01(hash);
- float hsv[3] = {hue, 0.75f, 0.8f};
- hsv_to_rgb_v(hsv, *wire_col);
- copy_v3_v3(*rim_col, *wire_col);
- }
-
- if ((ob->base_flag & BASE_SELECTED) && use_coloring) {
- /* "Normalize" color. */
- add_v3_fl(*wire_col, 1e-4f);
- float brightness = max_fff((*wire_col)[0], (*wire_col)[1], (*wire_col)[2]);
- mul_v3_fl(*wire_col, (0.5f / brightness));
- add_v3_fl(*rim_col, 0.75f);
- }
- else {
- mul_v3_fl(*rim_col, 0.5f);
- add_v3_fl(*wire_col, 0.5f);
- }
- }
- }
- BLI_assert(*rim_col && *wire_col);
-}
-
-static void overlay_cache_populate(void *vedata, Object *ob)
-{
- OVERLAY_Data *data = vedata;
- OVERLAY_StorageList *stl = data->stl;
- OVERLAY_PrivateData *pd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- if ((ob->dt < OB_WIRE) || (!DRW_object_is_renderable(ob) && (ob->dt != OB_WIRE))) {
- return;
- }
-
- if (DRW_object_is_renderable(ob) && pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION) {
- struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
- if (geom) {
- DRW_shgroup_call(pd->face_orientation_shgrp, geom, ob);
- }
- }
-
- if ((pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) || (v3d->shading.type == OB_WIRE) ||
- (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE)) {
-
- /* Fast path for duplis. */
- OVERLAY_DupliData **dupli_data = (OVERLAY_DupliData **)DRW_duplidata_get(vedata);
- if (dupli_data) {
- if (*dupli_data == NULL) {
- *dupli_data = MEM_callocN(sizeof(OVERLAY_DupliData), "OVERLAY_DupliData");
- }
- else {
- if ((*dupli_data)->shgrp && (*dupli_data)->geom) {
- if ((*dupli_data)->base_flag == ob->base_flag) {
- DRW_shgroup_call((*dupli_data)->shgrp, (*dupli_data)->geom, ob);
- }
- else {
- /* Continue and create a new Shgroup. */
- }
- }
- else {
- return;
- }
- }
- }
-
- const bool is_edit_mode = BKE_object_is_in_editmode(ob);
- bool has_edit_mesh_cage = false;
- if (ob->type == OB_MESH) {
- /* TODO: Should be its own function. */
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *embm = me->edit_mesh;
- if (embm) {
- has_edit_mesh_cage = embm->mesh_eval_cage &&
- (embm->mesh_eval_cage != embm->mesh_eval_final);
- }
- }
-
- /* Don't do that in edit Mesh mode, unless there is a modifier preview. */
- if ((!pd->show_overlays) ||
- (((ob != draw_ctx->object_edit) && !is_edit_mode) || has_edit_mesh_cage) ||
- ob->type != OB_MESH) {
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES);
- const bool is_wire = (ob->dt < OB_SOLID);
- const bool is_xray = (ob->dtx & OB_DRAWXRAY);
- const bool use_coloring = (pd->show_overlays && !is_edit_mode && !use_sculpt_pbvh &&
- !has_edit_mesh_cage);
- DRWShadingGroup *shgrp = NULL;
-
- struct GPUBatch *geom;
- geom = DRW_cache_object_face_wireframe_get(ob);
-
- if (geom || use_sculpt_pbvh) {
- if (is_wire && is_xray) {
- shgrp = DRW_shgroup_create_sub(pd->face_wires_xray_shgrp);
- }
- else {
- shgrp = DRW_shgroup_create_sub(pd->face_wires_shgrp);
- }
-
- if (draw_ctx->rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
-
- float wire_step_param = 10.0f;
- if (!use_sculpt_pbvh) {
- wire_step_param = (all_wires) ? 1.0f : pd->wire_step_param;
- }
- DRW_shgroup_uniform_float_copy(shgrp, "wireStepParam", wire_step_param);
-
- if (!(DRW_state_is_select() || DRW_state_is_depth())) {
- float *rim_col, *wire_col;
- overlay_wire_color_get(v3d, ob, use_coloring, &rim_col, &wire_col);
- DRW_shgroup_uniform_vec3_copy(shgrp, "wireColor", wire_col);
- DRW_shgroup_uniform_vec3_copy(shgrp, "rimColor", rim_col);
- DRW_shgroup_stencil_mask(shgrp,
- (is_xray && (is_wire || !pd->clear_stencil)) ? 0x00 : 0xFF);
- }
-
- if (use_sculpt_pbvh) {
- DRW_shgroup_call_sculpt(shgrp, ob, true, false, false);
- }
- else {
- DRW_shgroup_call(shgrp, geom, ob);
- }
- }
-
- if (dupli_data) {
- (*dupli_data)->shgrp = shgrp;
- (*dupli_data)->geom = geom;
- (*dupli_data)->base_flag = ob->base_flag;
- }
- }
- }
-}
-
-static void overlay_draw_scene(void *vedata)
-{
- OVERLAY_Data *data = vedata;
- OVERLAY_PassList *psl = data->psl;
- OVERLAY_StorageList *stl = data->stl;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- if (DRW_state_is_fbo()) {
- GPU_framebuffer_bind(dfbl->default_fb);
-
- /* In material/rendered mode, Stencil has not be rendered correctly.
- * Clear it to avoid problems.*/
- if (stl->g_data->clear_stencil) {
- GPU_framebuffer_clear_stencil(dfbl->default_fb, 0xFF);
- }
- }
- DRW_draw_pass(psl->face_orientation_pass);
-
- /* Do a depth prepass to lower the depth where the xray wire objects can pass through */
- DRW_draw_pass(psl->face_wireframe_xray_pass);
-
- /* This is replaced by the next code block */
- // MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
-
- if (dfbl->multisample_fb != NULL && DRW_state_is_fbo()) {
- DRW_stats_query_start("Multisample Blit");
- GPU_framebuffer_bind(dfbl->multisample_fb);
- GPU_framebuffer_clear_color(dfbl->multisample_fb, (const float[4]){0.0f});
- /* Special blit: we need the original depth and stencil
- * in the Multisample buffer. */
- GPU_framebuffer_blit(
- dfbl->default_fb, 0, dfbl->multisample_fb, 0, GPU_DEPTH_BIT | GPU_STENCIL_BIT);
- DRW_stats_query_end();
-
- /* Redo the prepass so we ge nice AA lines. */
- DRW_draw_pass(psl->face_wireframe_xray_pass);
- }
-
- DRW_view_set_active(stl->g_data->view_wires);
-
- DRW_pass_state_remove(psl->face_wireframe_xray_pass,
- DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_STENCIL_NEQUAL);
- DRW_pass_state_add(psl->face_wireframe_xray_pass,
- DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_STENCIL_ALWAYS);
- DRW_draw_pass(psl->face_wireframe_xray_pass);
-
- DRW_draw_pass(psl->face_wireframe_pass);
-
- DRW_view_set_active(NULL);
-
- /* TODO(fclem): find a way to unify the multisample pass together
- * (non meshes + armature + wireframe) */
- MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
-}
-
-static void overlay_engine_free(void)
-{
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- GPUShader **sh_data_as_array = (GPUShader **)sh_data;
- for (int i = 0; i < (sizeof(OVERLAY_Shaders) / sizeof(GPUShader *)); i++) {
- DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
- }
- }
-}
-
-static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data);
-
-DrawEngineType draw_engine_overlay_type = {
- NULL,
- NULL,
- N_("OverlayEngine"),
- &overlay_data_size,
- &overlay_engine_init,
- &overlay_engine_free,
- &overlay_cache_init,
- &overlay_cache_populate,
- NULL,
- NULL,
- &overlay_draw_scene,
- NULL,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c
deleted file mode 100644
index 7c164a74f2f..00000000000
--- a/source/blender/draw/modes/paint_texture_mode.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
-#include "BIF_gl.h"
-
-#include "BKE_node.h"
-
-#include "BLI_string_utils.h"
-
-/* If builtin shaders are needed */
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-
-#include "draw_common.h"
-#include "draw_mode_engines.h"
-
-#include "DNA_mesh_types.h"
-
-#include "DEG_depsgraph_query.h"
-
-extern char datatoc_common_colormanagement_lib_glsl[];
-extern char datatoc_common_globals_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_paint_texture_vert_glsl[];
-extern char datatoc_paint_texture_frag_glsl[];
-extern char datatoc_paint_wire_vert_glsl[];
-extern char datatoc_paint_wire_frag_glsl[];
-extern char datatoc_paint_face_vert_glsl[];
-extern char datatoc_paint_face_selection_vert_glsl[];
-
-extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
-
-/* *********** LISTS *********** */
-/* All lists are per viewport specific datas.
- * They are all free when viewport changes engines
- * or is free itself. Use PAINT_TEXTURE_engine_init() to
- * initialize most of them and PAINT_TEXTURE_cache_init()
- * for PAINT_TEXTURE_PassList */
-
-typedef struct PAINT_TEXTURE_PassList {
- /* Declare all passes here and init them in
- * PAINT_TEXTURE_cache_init().
- * Only contains (DRWPass *) */
- struct DRWPass *stencil_mask_overlay;
-
- struct DRWPass *wire_select_overlay;
- struct DRWPass *face_select_overlay;
-} PAINT_TEXTURE_PassList;
-
-typedef struct PAINT_TEXTURE_FramebufferList {
- /* Contains all framebuffer objects needed by this engine.
- * Only contains (GPUFrameBuffer *) */
- struct GPUFrameBuffer *fb;
-} PAINT_TEXTURE_FramebufferList;
-
-typedef struct PAINT_TEXTURE_TextureList {
- /* Contains all framebuffer textures / utility textures
- * needed by this engine. Only viewport specific textures
- * (not per object). Only contains (GPUTexture *) */
- struct GPUTexture *texture;
-} PAINT_TEXTURE_TextureList;
-
-typedef struct PAINT_TEXTURE_StorageList {
- /* Contains any other memory block that the engine needs.
- * Only directly MEM_(m/c)allocN'ed blocks because they are
- * free with MEM_freeN() when viewport is freed.
- * (not per object) */
- struct CustomStruct *block;
- struct PAINT_TEXTURE_PrivateData *g_data;
-} PAINT_TEXTURE_StorageList;
-
-typedef struct PAINT_TEXTURE_Data {
- /* Struct returned by DRW_viewport_engine_data_ensure.
- * If you don't use one of these, just make it a (void *) */
- // void *fbl;
- void *engine_type; /* Required */
- PAINT_TEXTURE_FramebufferList *fbl;
- PAINT_TEXTURE_TextureList *txl;
- PAINT_TEXTURE_PassList *psl;
- PAINT_TEXTURE_StorageList *stl;
-} PAINT_TEXTURE_Data;
-
-typedef struct PAINT_TEXTURE_Shaders {
- /* Custom shaders :
- * Add sources to source/blender/draw/modes/shaders
- * init in PAINT_TEXTURE_engine_init();
- * free in PAINT_TEXTURE_engine_free(); */
- struct GPUShader *stencil_mask_overlay;
-
- struct GPUShader *wire_select_overlay;
- struct GPUShader *face_select_overlay;
-} PAINT_TEXTURE_Shaders;
-
-/* *********** STATIC *********** */
-
-static struct {
- PAINT_TEXTURE_Shaders sh_data[GPU_SHADER_CFG_LEN];
-} e_data = {{{NULL}}}; /* Engine data */
-
-typedef struct PAINT_TEXTURE_PrivateData {
- /* This keeps the references of the shading groups for
- * easy access in PAINT_TEXTURE_cache_populate() */
- DRWShadingGroup *shgroup_stencil_mask;
-
- /* face-mask */
- DRWShadingGroup *lwire_select_shgrp;
- DRWShadingGroup *face_select_shgrp;
-
- DRWView *view_wires;
-} PAINT_TEXTURE_PrivateData; /* Transient data */
-
-/* *********** FUNCTIONS *********** */
-
-/* Init Textures, Framebuffers, Storage and Shaders.
- * It is called for every frames. */
-static void PAINT_TEXTURE_engine_init(void *vedata)
-{
- PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- if (!sh_data->stencil_mask_overlay) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
- sh_data->stencil_mask_overlay = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_paint_texture_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
- datatoc_paint_texture_frag_glsl,
- NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
-
- sh_data->wire_select_overlay = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_paint_wire_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_paint_wire_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define USE_SELECT\n", NULL},
- });
-
- sh_data->face_select_overlay = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_paint_face_selection_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_gpu_shader_uniform_color_frag_glsl,
- NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- }
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- stl->g_data->shgroup_stencil_mask = NULL;
- }
-
- stl->g_data->view_wires = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.0f);
-}
-
-static DRWShadingGroup *create_texture_paint_stencil_mask_shading_group(
- PAINT_TEXTURE_PassList *psl, const DRWContextState *draw_ctx)
-{
- PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- Scene *scene = draw_ctx->scene;
- const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- DRWShadingGroup *grp = DRW_shgroup_create(sh_data->stencil_mask_overlay,
- psl->stencil_mask_overlay);
- DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
-
- const bool masking_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) > 0;
- GPUTexture *stencil = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "maskingImage", stencil);
- DRW_shgroup_uniform_bool_copy(
- grp, "maskingImagePremultiplied", (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL));
- DRW_shgroup_uniform_vec3(grp, "maskingColor", imapaint->stencil_col, 1);
- DRW_shgroup_uniform_bool_copy(grp, "maskingInvertStencil", masking_inverted);
- return grp;
-}
-
-static bool PAINT_TEXTURE_stencil_mask_enabled(const ImagePaintSettings *imapaint)
-{
- return imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL && imapaint->stencil != NULL;
-}
-
-/* Here init all passes and shading groups
- * Assume that all Passes are NULL */
-static void PAINT_TEXTURE_cache_init(void *vedata)
-{
- PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
- PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- /* Stencil Mask */
- if (PAINT_TEXTURE_stencil_mask_enabled(imapaint)) {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
- psl->stencil_mask_overlay = DRW_pass_create("Stencil Mask Pass", state);
- stl->g_data->shgroup_stencil_mask = create_texture_paint_stencil_mask_shading_group(psl,
- draw_ctx);
- }
-
- /* Face Mask */
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- DRWPass *pass = DRW_pass_create("Wire Mask Pass", state);
- DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->wire_select_overlay, pass);
-
- DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo);
-
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
- psl->wire_select_overlay = pass;
- stl->g_data->lwire_select_shgrp = shgrp;
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_BLEND_ALPHA;
- DRWPass *pass = DRW_pass_create("Face Mask Pass", state);
- DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->face_select_overlay, pass);
- static const float col[4] = {1.0f, 1.0f, 1.0f, 0.2f};
- DRW_shgroup_uniform_vec4(shgrp, "color", col, 1);
-
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
- psl->face_select_overlay = pass;
- stl->g_data->face_select_shgrp = shgrp;
- }
-}
-
-/* Add geometry to shadingGroups. Execute for each objects */
-static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob)
-{
- PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
- PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- UNUSED_VARS(psl, stl);
-
- if ((ob->type == OB_MESH) && (draw_ctx->obact == ob)) {
- /* Get geometry cache */
- const Mesh *me_orig = DEG_get_original_object(ob)->data;
- Scene *scene = draw_ctx->scene;
- const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool masking_enabled = imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL &&
- imapaint->stencil != NULL;
-
- if (masking_enabled) {
- if (stl->g_data->shgroup_stencil_mask) {
- struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
- DRW_shgroup_call(stl->g_data->shgroup_stencil_mask, geom, ob);
- }
- }
-
- /* Face Mask */
- if (use_face_sel) {
- struct GPUBatch *geom;
- geom = DRW_cache_mesh_surface_edges_get(ob);
- DRW_shgroup_call(stl->g_data->lwire_select_shgrp, geom, ob);
-
- geom = DRW_cache_mesh_surface_get(ob);
- DRW_shgroup_call(stl->g_data->face_select_shgrp, geom, ob);
- }
- }
-}
-
-/* Draw time ! Control rendering pipeline from here */
-static void PAINT_TEXTURE_draw_scene(void *vedata)
-{
- PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
- PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
-
- if (psl->stencil_mask_overlay) {
- DRW_draw_pass(psl->stencil_mask_overlay);
- }
-
- DRW_draw_pass(psl->face_select_overlay);
-
- DRW_view_set_active(stl->g_data->view_wires);
- DRW_draw_pass(psl->wire_select_overlay);
-
- DRW_view_set_active(NULL);
-}
-
-/* Cleanup when destroying the engine.
- * This is not per viewport ! only when quitting blender.
- * Mostly used for freeing shaders */
-static void PAINT_TEXTURE_engine_free(void)
-{
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- GPUShader **sh_data_as_array = (GPUShader **)sh_data;
- for (int i = 0; i < (sizeof(PAINT_TEXTURE_Shaders) / sizeof(GPUShader *)); i++) {
- DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
- }
- }
-}
-
-static const DrawEngineDataSize PAINT_TEXTURE_data_size = DRW_VIEWPORT_DATA_SIZE(
- PAINT_TEXTURE_Data);
-
-DrawEngineType draw_engine_paint_texture_type = {
- NULL,
- NULL,
- N_("PaintTextureMode"),
- &PAINT_TEXTURE_data_size,
- &PAINT_TEXTURE_engine_init,
- &PAINT_TEXTURE_engine_free,
- &PAINT_TEXTURE_cache_init,
- &PAINT_TEXTURE_cache_populate,
- NULL,
- NULL, /* draw_background but not needed by mode engines */
- &PAINT_TEXTURE_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/paint_vertex_mode.c b/source/blender/draw/modes/paint_vertex_mode.c
deleted file mode 100644
index 5d14b3ba414..00000000000
--- a/source/blender/draw/modes/paint_vertex_mode.c
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_render.h"
-
-/* If builtin shaders are needed */
-#include "GPU_shader.h"
-
-#include "draw_common.h"
-#include "draw_mode_engines.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_view3d_types.h"
-
-#include "DEG_depsgraph_query.h"
-
-extern char datatoc_paint_face_selection_vert_glsl[];
-extern char datatoc_paint_weight_vert_glsl[];
-extern char datatoc_paint_weight_frag_glsl[];
-extern char datatoc_paint_vertex_vert_glsl[];
-extern char datatoc_paint_vertex_frag_glsl[];
-extern char datatoc_paint_wire_vert_glsl[];
-extern char datatoc_paint_wire_frag_glsl[];
-extern char datatoc_paint_vert_frag_glsl[];
-extern char datatoc_common_globals_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
-
-/* *********** LISTS *********** */
-
-enum {
- VERTEX_MODE = 0,
- WEIGHT_MODE = 1,
-};
-#define MODE_LEN (WEIGHT_MODE + 1)
-
-typedef struct PAINT_VERTEX_PassList {
- struct {
- struct DRWPass *color_faces;
- } by_mode[MODE_LEN];
- struct DRWPass *wire_overlay;
- struct DRWPass *wire_select_overlay;
- struct DRWPass *face_select_overlay;
- struct DRWPass *vert_select_overlay;
-} PAINT_VERTEX_PassList;
-
-typedef struct PAINT_VERTEX_StorageList {
- struct PAINT_VERTEX_PrivateData *g_data;
-} PAINT_VERTEX_StorageList;
-
-typedef struct PAINT_VERTEX_Data {
- void *engine_type; /* Required */
- DRWViewportEmptyList *fbl;
- DRWViewportEmptyList *txl;
- PAINT_VERTEX_PassList *psl;
- PAINT_VERTEX_StorageList *stl;
-} PAINT_VERTEX_Data;
-
-typedef struct PAINT_VERTEX_Shaders {
- struct {
- struct GPUShader *color_face_mul_blending;
- struct GPUShader *color_face_alpha_blending;
- struct GPUShader *wire_overlay;
- struct GPUShader *wire_select_overlay;
- } by_mode[MODE_LEN];
- struct GPUShader *face_select_overlay;
- struct GPUShader *vert_select_overlay;
-} PAINT_VERTEX_Shaders;
-
-/* *********** STATIC *********** */
-
-static struct {
- PAINT_VERTEX_Shaders sh_data[GPU_SHADER_CFG_LEN];
-} e_data = {{{{{NULL}}}}}; /* Engine data */
-
-typedef struct PAINT_VERTEX_PrivateData {
- struct {
- DRWShadingGroup *color_shgrp;
- DRWShadingGroup *lwire_shgrp;
- DRWShadingGroup *lwire_select_shgrp;
- } by_mode[MODE_LEN];
- DRWShadingGroup *face_select_shgrp;
- DRWShadingGroup *vert_select_shgrp;
- DRWView *view_wires;
-} PAINT_VERTEX_PrivateData; /* Transient data */
-
-/* *********** FUNCTIONS *********** */
-
-static void PAINT_VERTEX_engine_init(void *vedata)
-{
- PAINT_VERTEX_StorageList *stl = ((PAINT_VERTEX_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- PAINT_VERTEX_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
-
- if (!sh_data->face_select_overlay) {
- sh_data->by_mode[VERTEX_MODE].color_face_mul_blending = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_paint_vertex_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_paint_vertex_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
- });
- sh_data->by_mode[VERTEX_MODE].color_face_alpha_blending = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_paint_vertex_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_paint_vertex_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define DRW_STATE_BLEND_ALPHA\n", NULL},
- });
- sh_data->by_mode[WEIGHT_MODE].color_face_mul_blending = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_common_globals_lib_glsl,
- datatoc_paint_weight_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_common_globals_lib_glsl,
- datatoc_paint_weight_frag_glsl,
- NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define DRW_STATE_BLEND_MUL\n", NULL},
- });
- sh_data->by_mode[WEIGHT_MODE].color_face_alpha_blending = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_common_globals_lib_glsl,
- datatoc_paint_weight_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_common_globals_lib_glsl,
- datatoc_paint_weight_frag_glsl,
- NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define DRW_STATE_BLEND_ALPHA\n", NULL},
- });
-
- sh_data->face_select_overlay = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_view_lib_glsl,
- datatoc_paint_face_selection_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define DRW_STATE_BLEND_MUL\n", NULL},
- });
- sh_data->vert_select_overlay = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_paint_wire_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_paint_vert_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define USE_SELECT\n", NULL},
- });
-
- const char *mode_defs[MODE_LEN] = {
- "#define VERTEX_MODE\n",
- "#define WEIGHT_MODE\n",
- };
- for (int i = 0; i < MODE_LEN; i++) {
- sh_data->by_mode[i].wire_overlay = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_paint_wire_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_paint_wire_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, mode_defs[i], NULL},
- });
- sh_data->by_mode[i].wire_select_overlay = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib,
- datatoc_common_globals_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_paint_wire_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_paint_wire_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, mode_defs[i], "#define USE_SELECT\n", NULL},
- });
- }
- }
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- }
-
- stl->g_data->view_wires = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.0f);
-}
-
-static void PAINT_VERTEX_cache_init(void *vedata)
-{
- PAINT_VERTEX_PassList *psl = ((PAINT_VERTEX_Data *)vedata)->psl;
- PAINT_VERTEX_StorageList *stl = ((PAINT_VERTEX_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const View3D *v3d = draw_ctx->v3d;
- const RegionView3D *rv3d = draw_ctx->rv3d;
- PAINT_VERTEX_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- const bool use_alpha_blending = draw_ctx->v3d->shading.type == OB_WIRE;
- DRWState draw_state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL |
- (use_alpha_blending ? DRW_STATE_BLEND_ALPHA : DRW_STATE_BLEND_MUL);
- /* Vertex color pass */
- {
- DRWPass *pass = DRW_pass_create("Vert Color Pass", draw_state);
- GPUShader *shader = use_alpha_blending ?
- sh_data->by_mode[VERTEX_MODE].color_face_alpha_blending :
- sh_data->by_mode[VERTEX_MODE].color_face_mul_blending;
- DRWShadingGroup *shgrp = DRW_shgroup_create(shader, pass);
- DRW_shgroup_uniform_float(shgrp, "opacity", &v3d->overlay.vertex_paint_mode_opacity, 1);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
- psl->by_mode[VERTEX_MODE].color_faces = pass;
- stl->g_data->by_mode[VERTEX_MODE].color_shgrp = shgrp;
- }
-
- /* Weight color pass */
- {
- DRWPass *pass = DRW_pass_create("Weight Pass", draw_state);
- GPUShader *shader = use_alpha_blending ?
- sh_data->by_mode[WEIGHT_MODE].color_face_alpha_blending :
- sh_data->by_mode[WEIGHT_MODE].color_face_mul_blending;
- DRWShadingGroup *shgrp = DRW_shgroup_create(shader, pass);
- DRW_shgroup_uniform_bool_copy(
- shgrp, "drawContours", (v3d->overlay.wpaint_flag & V3D_OVERLAY_WPAINT_CONTOURS) != 0);
- DRW_shgroup_uniform_float(shgrp, "opacity", &v3d->overlay.weight_paint_mode_opacity, 1);
- DRW_shgroup_uniform_texture(shgrp, "colorramp", G_draw.weight_ramp);
- DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
- psl->by_mode[WEIGHT_MODE].color_faces = pass;
- stl->g_data->by_mode[WEIGHT_MODE].color_shgrp = shgrp;
- }
-
- {
- DRWPass *pass = DRW_pass_create("Wire Pass",
- (DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL));
- for (int i = 0; i < MODE_LEN; i++) {
- DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->by_mode[i].wire_overlay, pass);
- DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
- stl->g_data->by_mode[i].lwire_shgrp = shgrp;
- }
- psl->wire_overlay = pass;
- }
-
- {
- DRWPass *pass = DRW_pass_create("Wire Mask Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_LESS_EQUAL);
- for (int i = 0; i < MODE_LEN; i++) {
- DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->by_mode[i].wire_select_overlay, pass);
- DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
- stl->g_data->by_mode[i].lwire_select_shgrp = shgrp;
- }
- psl->wire_select_overlay = pass;
- }
-
- {
- static const float col[4] = {1.0f, 1.0f, 1.0f, 0.2f};
- DRWPass *pass = DRW_pass_create("Face Mask Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA);
- DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->face_select_overlay, pass);
- DRW_shgroup_uniform_vec4(shgrp, "color", col, 1);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
- psl->face_select_overlay = pass;
- stl->g_data->face_select_shgrp = shgrp;
- }
-
- {
- DRWPass *pass = DRW_pass_create("Vert Mask Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_LESS_EQUAL);
- DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->vert_select_overlay, pass);
- DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo);
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
- }
- psl->vert_select_overlay = pass;
- stl->g_data->vert_select_shgrp = shgrp;
- }
-}
-
-static void PAINT_VERTEX_cache_populate(void *vedata, Object *ob)
-{
- PAINT_VERTEX_StorageList *stl = ((PAINT_VERTEX_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const View3D *v3d = draw_ctx->v3d;
-
- if ((ob->type == OB_MESH) && (ob == draw_ctx->obact)) {
- const int draw_mode = (ob->mode == OB_MODE_VERTEX_PAINT) ? VERTEX_MODE : WEIGHT_MODE;
- const Mesh *me = ob->data;
- const Mesh *me_orig = DEG_get_original_object(ob)->data;
- const bool use_wire = (v3d->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0;
- const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
-
- struct GPUBatch *geom = NULL;
- if (draw_mode == VERTEX_MODE) {
- if (me->mloopcol == NULL) {
- return;
- }
- if (v3d->overlay.vertex_paint_mode_opacity != 0.0f) {
- geom = DRW_cache_mesh_surface_vertpaint_get(ob);
- }
- }
- else {
- if (v3d->overlay.weight_paint_mode_opacity != 0.0f) {
- geom = DRW_cache_mesh_surface_weights_get(ob);
- }
- }
- if (geom != NULL) {
- DRW_shgroup_call(stl->g_data->by_mode[draw_mode].color_shgrp, geom, ob);
- }
-
- if (use_face_sel || use_wire) {
- DRWShadingGroup *shgrp = use_face_sel ? stl->g_data->by_mode[draw_mode].lwire_select_shgrp :
- stl->g_data->by_mode[draw_mode].lwire_shgrp;
- geom = DRW_cache_mesh_surface_edges_get(ob);
- DRW_shgroup_call(shgrp, geom, ob);
- }
-
- if (use_face_sel) {
- geom = DRW_cache_mesh_surface_get(ob);
- DRW_shgroup_call(stl->g_data->face_select_shgrp, geom, ob);
- }
-
- if (use_vert_sel) {
- geom = DRW_cache_mesh_all_verts_get(ob);
- DRW_shgroup_call(stl->g_data->vert_select_shgrp, geom, ob);
- }
- }
-}
-
-static void PAINT_VERTEX_draw_scene(void *vedata)
-{
- PAINT_VERTEX_PassList *psl = ((PAINT_VERTEX_Data *)vedata)->psl;
- PAINT_VERTEX_StorageList *stl = ((PAINT_VERTEX_Data *)vedata)->stl;
- for (int i = 0; i < MODE_LEN; i++) {
- DRW_draw_pass(psl->by_mode[i].color_faces);
- }
- DRW_draw_pass(psl->face_select_overlay);
-
- DRW_view_set_active(stl->g_data->view_wires);
- DRW_draw_pass(psl->wire_overlay);
- DRW_draw_pass(psl->wire_select_overlay);
- DRW_draw_pass(psl->vert_select_overlay);
-
- DRW_view_set_active(NULL);
-}
-
-static void PAINT_VERTEX_engine_free(void)
-{
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- PAINT_VERTEX_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- GPUShader **sh_data_as_array = (GPUShader **)sh_data;
- for (int i = 0; i < (sizeof(PAINT_VERTEX_Shaders) / sizeof(GPUShader *)); i++) {
- DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
- }
- }
-}
-
-static const DrawEngineDataSize PAINT_VERTEX_data_size = DRW_VIEWPORT_DATA_SIZE(PAINT_VERTEX_Data);
-
-DrawEngineType draw_engine_paint_vertex_type = {
- NULL,
- NULL,
- N_("PaintVertexMode"),
- &PAINT_VERTEX_data_size,
- &PAINT_VERTEX_engine_init,
- &PAINT_VERTEX_engine_free,
- &PAINT_VERTEX_cache_init,
- &PAINT_VERTEX_cache_populate,
- NULL,
- NULL,
- &PAINT_VERTEX_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c
deleted file mode 100644
index fa2c4d9b6a8..00000000000
--- a/source/blender/draw/modes/particle_mode.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_render.h"
-
-#include "DNA_object_types.h"
-#include "DNA_particle_types.h"
-
-#include "BKE_pointcache.h"
-
-#include "BLI_string_utils.h"
-
-#include "GPU_shader.h"
-
-#include "draw_common.h"
-#include "draw_mode_engines.h"
-
-#include "ED_particle.h"
-
-#include "DEG_depsgraph_query.h"
-
-extern char datatoc_particle_strand_vert_glsl[];
-extern char datatoc_particle_strand_frag_glsl[];
-extern char datatoc_common_globals_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-/* *********** LISTS *********** */
-
-typedef struct PARTICLE_PassList {
- struct DRWPass *psys_edit_pass;
-} PARTICLE_PassList;
-
-typedef struct PARTICLE_FramebufferList {
- struct GPUFrameBuffer *fb;
-} PARTICLE_FramebufferList;
-
-typedef struct PARTICLE_TextureList {
- struct GPUTexture *texture;
-} PARTICLE_TextureList;
-
-typedef struct PARTICLE_StorageList {
- struct CustomStruct *block;
- struct PARTICLE_PrivateData *g_data;
-} PARTICLE_StorageList;
-
-typedef struct PARTICLE_Data {
- void *engine_type; /* Required */
- PARTICLE_FramebufferList *fbl;
- PARTICLE_TextureList *txl;
- PARTICLE_PassList *psl;
- PARTICLE_StorageList *stl;
-} PARTICLE_Data;
-
-/* *********** STATIC *********** */
-
-static struct {
- struct GPUShader *strands_shader;
- struct GPUShader *strands_weight_shader;
- struct GPUShader *points_shader;
-} e_data = {NULL}; /* Engine data */
-
-typedef struct PARTICLE_PrivateData {
- DRWShadingGroup *strands_group;
- DRWShadingGroup *inner_points_group;
- DRWShadingGroup *tip_points_group;
-} PARTICLE_PrivateData; /* Transient data */
-
-/* *********** FUNCTIONS *********** */
-
-static void particle_engine_init(void *UNUSED(vedata))
-{
- if (!e_data.strands_shader) {
- char *lib = BLI_string_joinN(datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl);
-
- e_data.strands_shader = DRW_shader_create_with_lib(
- datatoc_particle_strand_vert_glsl, NULL, datatoc_particle_strand_frag_glsl, lib, "");
-
- e_data.strands_weight_shader = DRW_shader_create_with_lib(datatoc_particle_strand_vert_glsl,
- NULL,
- datatoc_particle_strand_frag_glsl,
- lib,
- "#define USE_WEIGHT");
-
- e_data.points_shader = DRW_shader_create_with_lib(datatoc_particle_strand_vert_glsl,
- NULL,
- datatoc_particle_strand_frag_glsl,
- lib,
- "#define USE_POINTS");
- MEM_freeN(lib);
- }
-}
-
-static void particle_cache_init(void *vedata)
-{
- PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
- PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
- const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- }
-
- /* Create a pass */
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->psys_edit_pass = DRW_pass_create("PSys Edit Pass", state);
-
- GPUShader *strand_shader = (use_weight) ? e_data.strands_weight_shader : e_data.strands_shader;
- stl->g_data->strands_group = DRW_shgroup_create(strand_shader, psl->psys_edit_pass);
- stl->g_data->inner_points_group = DRW_shgroup_create(e_data.points_shader, psl->psys_edit_pass);
- stl->g_data->tip_points_group = DRW_shgroup_create(e_data.points_shader, psl->psys_edit_pass);
-
- DRW_shgroup_uniform_block(stl->g_data->strands_group, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_block(stl->g_data->inner_points_group, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_block(stl->g_data->tip_points_group, "globalsBlock", G_draw.block_ubo);
-}
-
-static void particle_edit_cache_populate(void *vedata,
- Object *object,
- ParticleSystem *psys,
- PTCacheEdit *edit)
-{
- PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
- const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
- {
- struct GPUBatch *strands = DRW_cache_particles_get_edit_strands(
- object, psys, edit, use_weight);
- DRW_shgroup_call(stl->g_data->strands_group, strands, NULL);
- }
- if (pset->selectmode == SCE_SELECT_POINT) {
- struct GPUBatch *points = DRW_cache_particles_get_edit_inner_points(object, psys, edit);
- DRW_shgroup_call(stl->g_data->inner_points_group, points, NULL);
- }
- if (ELEM(pset->selectmode, SCE_SELECT_POINT, SCE_SELECT_END)) {
- struct GPUBatch *points = DRW_cache_particles_get_edit_tip_points(object, psys, edit);
- DRW_shgroup_call(stl->g_data->tip_points_group, points, NULL);
- }
-}
-
-static void particle_cache_populate(void *vedata, Object *object)
-{
- if (object->mode != OB_MODE_PARTICLE_EDIT) {
- return;
- }
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
- /* Usually the edit structure is created by Particle Edit Mode Toggle
- * operator, but sometimes it's invoked after tagging hair as outdated
- * (for example, when toggling edit mode). That makes it impossible to
- * create edit structure for until after next dependency graph evaluation.
- *
- * Ideally, the edit structure will be created here already via some
- * dependency graph callback or so, but currently trying to make it nicer
- * only causes bad level calls and breaks design from the past.
- */
- Object *object_orig = DEG_get_original_object(object);
- PTCacheEdit *edit = PE_create_current(draw_ctx->depsgraph, scene_orig, object_orig);
- if (edit == NULL) {
- /* Happens when trying to edit particles in EMITTER mode without
- * having them cached.
- */
- return;
- }
- /* NOTE: We need to pass evaluated particle system, which we need
- * to find first.
- */
- ParticleSystem *psys = object->particlesystem.first;
- ParticleSystem *psys_orig = object_orig->particlesystem.first;
- while (psys_orig != NULL) {
- if (PE_get_current_from_psys(psys_orig) == edit) {
- break;
- }
- psys = psys->next;
- psys_orig = psys_orig->next;
- }
- if (psys == NULL) {
- printf("Error getting evaluated particle system for edit.\n");
- return;
- }
- particle_edit_cache_populate(vedata, object, psys, edit);
-}
-
-/* Optional: Post-cache_populate callback */
-static void particle_cache_finish(void *UNUSED(vedata))
-{
-}
-
-/* Draw time ! Control rendering pipeline from here */
-static void particle_draw_scene(void *vedata)
-{
-
- PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
-
- DRW_draw_pass(psl->psys_edit_pass);
-}
-
-static void particle_engine_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.strands_shader);
- DRW_SHADER_FREE_SAFE(e_data.strands_weight_shader);
- DRW_SHADER_FREE_SAFE(e_data.points_shader);
-}
-
-static const DrawEngineDataSize particle_data_size = DRW_VIEWPORT_DATA_SIZE(PARTICLE_Data);
-
-DrawEngineType draw_engine_particle_type = {
- NULL,
- NULL,
- N_("Particle Mode"),
- &particle_data_size,
- &particle_engine_init,
- &particle_engine_free,
- &particle_cache_init,
- &particle_cache_populate,
- &particle_cache_finish,
- NULL, /* draw_background but not needed by mode engines */
- &particle_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c
deleted file mode 100644
index 91e4e2335de..00000000000
--- a/source/blender/draw/modes/pose_mode.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-#include "BKE_modifier.h"
-
-#include "DNA_modifier_types.h"
-#include "DNA_view3d_types.h"
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
-#include "ED_view3d.h"
-
-/* If builtin shaders are needed */
-#include "GPU_shader.h"
-
-#include "draw_common.h"
-#include "draw_mode_engines.h"
-
-extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
-extern char datatoc_pose_selection_vert_glsl[];
-
-/* *********** LISTS *********** */
-/**
- * All lists are per viewport specific datas.
- * They are all free when viewport changes engines
- * or is free itself. Use #POSE_engine_init() to
- * initialize most of them and #POSE_cache_init()
- * for #POSE_PassList
- */
-
-typedef struct POSE_PassList {
- struct DRWPass *bone_solid[2];
- struct DRWPass *bone_transp[2];
- struct DRWPass *bone_outline[2];
- struct DRWPass *bone_wire[2];
- struct DRWPass *bone_envelope[2];
- struct DRWPass *bone_axes;
- struct DRWPass *relationship[2];
- struct DRWPass *bone_selection;
-} POSE_PassList;
-
-typedef struct POSE_StorageList {
- struct POSE_PrivateData *g_data;
-} POSE_StorageList;
-
-typedef struct POSE_Data {
- void *engine_type;
- DRWViewportEmptyList *fbl;
- DRWViewportEmptyList *txl;
- POSE_PassList *psl;
- POSE_StorageList *stl;
-} POSE_Data;
-
-/* *********** STATIC *********** */
-
-typedef struct POSE_PrivateData {
- DRWShadingGroup *bone_selection_shgrp;
- DRWShadingGroup *bone_selection_invert_shgrp;
- GHash *custom_shapes[2];
- float blend_color[4];
- float blend_color_invert[4];
- bool transparent_bones;
-} POSE_PrivateData; /* Transient data */
-
-static struct {
- struct GPUShader *bone_selection_sh;
-} e_data = {NULL};
-
-/* *********** FUNCTIONS *********** */
-static bool POSE_is_bone_selection_overlay_active(void)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const View3D *v3d = draw_ctx->v3d;
- return v3d && (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT) && draw_ctx->object_pose;
-}
-
-static void POSE_engine_init(void *UNUSED(vedata))
-{
- if (!e_data.bone_selection_sh) {
- e_data.bone_selection_sh = DRW_shader_create_with_lib(
- datatoc_pose_selection_vert_glsl,
- NULL,
- datatoc_gpu_shader_uniform_color_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
- }
-}
-
-static void POSE_engine_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.bone_selection_sh);
-}
-
-/* Here init all passes and shading groups
- * Assume that all Passes are NULL */
-static void POSE_cache_init(void *vedata)
-{
- POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
- POSE_StorageList *stl = ((POSE_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
- }
- POSE_PrivateData *ppd = stl->g_data;
- ppd->transparent_bones = (draw_ctx->v3d->shading.type == OB_WIRE);
-
- for (int i = 0; i < 2; i++) {
- /* Solid bones */
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
- psl->bone_solid[i] = DRW_pass_create("Bone Solid Pass", state | DRW_STATE_WRITE_DEPTH);
- psl->bone_transp[i] = DRW_pass_create("Bone Transp Pass", state | DRW_STATE_BLEND_ALPHA);
-
- /* Bones Outline */
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->bone_outline[i] = DRW_pass_create("Bone Outline Pass", state);
-
- /* Wire bones */
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_BLEND_ALPHA;
- psl->bone_wire[i] = DRW_pass_create("Bone Wire Pass", state);
-
- /* distance outline around envelope bones */
- state = DRW_STATE_BLEND_ADD | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_CULL_FRONT;
- psl->bone_envelope[i] = DRW_pass_create("Bone Envelope Outline Pass", state);
-
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_BLEND_ALPHA;
- psl->relationship[i] = DRW_pass_create("Bone Relationship Pass", state);
-
- ppd->custom_shapes[i] = BLI_ghash_ptr_new(__func__);
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WIRE_SMOOTH | DRW_STATE_BLEND_ALPHA;
- psl->bone_axes = DRW_pass_create("Bone Axes Pass", state);
- }
-
- {
- if (POSE_is_bone_selection_overlay_active()) {
- const float alpha = (draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) ?
- 0.0f :
- v3d->overlay.xray_alpha_bone;
- copy_v4_fl4(ppd->blend_color, 0.0f, 0.0f, 0.0f, alpha);
- copy_v4_fl4(ppd->blend_color_invert, 0.0f, 0.0f, 0.0f, pow(alpha, 4));
- DRWShadingGroup *grp;
- psl->bone_selection = DRW_pass_create(
- "Bone Selection", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA);
- grp = DRW_shgroup_create(e_data.bone_selection_sh, psl->bone_selection);
- DRW_shgroup_uniform_vec4(grp, "color", ppd->blend_color, 1);
- stl->g_data->bone_selection_shgrp = grp;
- grp = DRW_shgroup_create(e_data.bone_selection_sh, psl->bone_selection);
- DRW_shgroup_uniform_vec4(grp, "color", ppd->blend_color_invert, 1);
- stl->g_data->bone_selection_invert_shgrp = grp;
- }
- }
-}
-
-static bool POSE_is_driven_by_active_armature(Object *ob)
-{
- Object *ob_arm = modifiers_isDeformedByArmature(ob);
- if (ob_arm) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- bool is_active = DRW_pose_mode_armature(ob_arm, draw_ctx->obact);
- if (!is_active && ob_arm->proxy_from) {
- is_active = DRW_pose_mode_armature(ob_arm->proxy_from, draw_ctx->obact);
- }
- return is_active;
- }
- else {
- Object *ob_mesh_deform = modifiers_isDeformedByMeshDeform(ob);
- if (ob_mesh_deform) {
- return POSE_is_driven_by_active_armature(ob_mesh_deform);
- }
- }
- return false;
-}
-
-/* Add geometry to shading groups. Execute for each objects */
-static void POSE_cache_populate(void *vedata, Object *ob)
-{
- POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
- POSE_PrivateData *ppd = ((POSE_Data *)vedata)->stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- /* In the future this will allow us to implement face gizmos,
- * and similar functionalities. For now we handle only pose bones. */
-
- if (ob->type == OB_ARMATURE) {
- if ((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) ||
- (draw_ctx->v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES)) {
- return;
- }
- if (DRW_pose_mode_armature(ob, draw_ctx->obact)) {
- int ghost = (ob->dtx & OB_DRAWXRAY) ? 1 : 0;
- bool transp = (ppd->transparent_bones || (ob->dt <= OB_WIRE)) ||
- XRAY_FLAG_ENABLED(draw_ctx->v3d);
-
- DRWArmaturePasses passes = {
- .bone_solid = (transp) ? psl->bone_transp[ghost] : psl->bone_solid[ghost],
- .bone_outline = psl->bone_outline[ghost],
- .bone_wire = psl->bone_wire[ghost],
- .bone_envelope = psl->bone_envelope[ghost],
- .bone_axes = psl->bone_axes,
- .relationship_lines = psl->relationship[ghost],
- .custom_shapes = ppd->custom_shapes[transp],
- };
- DRW_shgroup_armature_pose(ob, passes, transp);
- }
- }
- else if (ob->type == OB_MESH && !DRW_state_is_select() &&
- POSE_is_bone_selection_overlay_active()) {
- struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
- if (geom) {
- if (POSE_is_driven_by_active_armature(ob)) {
- DRW_shgroup_call(ppd->bone_selection_shgrp, geom, ob);
- }
- else {
- DRW_shgroup_call(ppd->bone_selection_invert_shgrp, geom, ob);
- }
- }
- }
-}
-
-static void POSE_cache_finish(void *vedata)
-{
- POSE_PrivateData *ppd = ((POSE_Data *)vedata)->stl->g_data;
-
- /* TODO(fclem): Do not free it for each frame but reuse it. Avoiding alloc cost. */
- for (int i = 0; i < 2; i++) {
- BLI_ghash_free(ppd->custom_shapes[i], NULL, NULL);
- }
-}
-
-/**
- * Return true if armature should be handled by the pose mode engine.
- */
-bool DRW_pose_mode_armature(Object *ob, Object *active_ob)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- /* Pose armature is handled by pose mode engine. */
- if (((ob == active_ob) || (ob->mode & OB_MODE_POSE)) &&
- ((draw_ctx->object_mode & OB_MODE_POSE) != 0)) {
- return true;
- }
-
- /* Armature parent is also handled by pose mode engine. */
- if ((active_ob != NULL) && ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) != 0)) {
- if (ob == draw_ctx->object_pose) {
- return true;
- }
- }
-
- return false;
-}
-
-/* Draw time ! Control rendering pipeline from here */
-static void POSE_draw_scene(void *vedata)
-{
- POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- const bool bone_selection_overlay = POSE_is_bone_selection_overlay_active();
-
- if (DRW_state_is_select()) {
- DRW_draw_pass(psl->bone_outline[0]);
- DRW_draw_pass(psl->bone_solid[0]);
- DRW_draw_pass(psl->bone_wire[0]);
- DRW_draw_pass(psl->bone_outline[1]);
- DRW_draw_pass(psl->bone_solid[1]);
- DRW_draw_pass(psl->bone_wire[1]);
- return;
- }
-
- if (bone_selection_overlay) {
- GPU_framebuffer_bind(dfbl->default_fb);
- DRW_draw_pass(psl->bone_selection);
- GPU_framebuffer_bind(dfbl->depth_only_fb);
- GPU_framebuffer_clear_depth(dfbl->depth_only_fb, 1.0);
- GPU_framebuffer_bind(dfbl->default_fb);
- }
-
- DRW_draw_pass(psl->bone_envelope[0]);
- DRW_draw_pass(psl->bone_transp[0]);
-
- MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
-
- DRW_draw_pass(psl->bone_solid[0]);
- DRW_draw_pass(psl->bone_outline[0]);
- DRW_draw_pass(psl->bone_wire[0]);
- DRW_draw_pass(psl->relationship[0]);
-
- MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
-
- if (!DRW_pass_is_empty(psl->bone_envelope[1]) || !DRW_pass_is_empty(psl->bone_transp[1]) ||
- !DRW_pass_is_empty(psl->bone_solid[1]) || !DRW_pass_is_empty(psl->bone_outline[1]) ||
- !DRW_pass_is_empty(psl->bone_wire[1]) || !DRW_pass_is_empty(psl->relationship[1])) {
- if (DRW_state_is_fbo()) {
- GPU_framebuffer_bind(dfbl->default_fb);
- GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
- }
-
- DRW_draw_pass(psl->bone_envelope[1]);
- DRW_draw_pass(psl->bone_solid[1]);
- DRW_draw_pass(psl->bone_transp[1]);
- DRW_draw_pass(psl->bone_outline[1]);
- DRW_draw_pass(psl->bone_wire[1]);
- DRW_draw_pass(psl->relationship[1]);
- }
-
- /* Draw axes with linesmooth and outside of multisample buffer. */
- DRW_draw_pass(psl->bone_axes);
-}
-
-static const DrawEngineDataSize POSE_data_size = DRW_VIEWPORT_DATA_SIZE(POSE_Data);
-
-DrawEngineType draw_engine_pose_type = {
- NULL,
- NULL,
- N_("PoseMode"),
- &POSE_data_size,
- &POSE_engine_init,
- &POSE_engine_free,
- &POSE_cache_init,
- &POSE_cache_populate,
- &POSE_cache_finish,
- NULL,
- &POSE_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c
deleted file mode 100644
index f32eb3b73ba..00000000000
--- a/source/blender/draw/modes/sculpt_mode.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
-#include "DNA_object_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BKE_pbvh.h"
-#include "BKE_paint.h"
-#include "BKE_subdiv_ccg.h"
-
-/* If builtin shaders are needed */
-#include "GPU_shader.h"
-
-#include "draw_common.h"
-#include "draw_mode_engines.h"
-
-extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_sculpt_mask_vert_glsl[];
-extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
-
-/* *********** LISTS *********** */
-/* All lists are per viewport specific datas.
- * They are all free when viewport changes engines
- * or is free itself. Use SCULPT_engine_init() to
- * initialize most of them and SCULPT_cache_init()
- * for SCULPT_PassList */
-
-typedef struct SCULPT_PassList {
- /* Declare all passes here and init them in
- * SCULPT_cache_init().
- * Only contains (DRWPass *) */
- struct DRWPass *pass;
-} SCULPT_PassList;
-
-typedef struct SCULPT_FramebufferList {
- /* Contains all framebuffer objects needed by this engine.
- * Only contains (GPUFrameBuffer *) */
- struct GPUFrameBuffer *fb;
-} SCULPT_FramebufferList;
-
-typedef struct SCULPT_TextureList {
- /* Contains all framebuffer textures / utility textures
- * needed by this engine. Only viewport specific textures
- * (not per object). Only contains (GPUTexture *) */
- struct GPUTexture *texture;
-} SCULPT_TextureList;
-
-typedef struct SCULPT_StorageList {
- /* Contains any other memory block that the engine needs.
- * Only directly MEM_(m/c)allocN'ed blocks because they are
- * free with MEM_freeN() when viewport is freed.
- * (not per object) */
- struct CustomStruct *block;
- struct SCULPT_PrivateData *g_data;
-} SCULPT_StorageList;
-
-typedef struct SCULPT_Data {
- /* Struct returned by DRW_viewport_engine_data_ensure.
- * If you don't use one of these, just make it a (void *) */
- // void *fbl;
- void *engine_type; /* Required */
- SCULPT_FramebufferList *fbl;
- SCULPT_TextureList *txl;
- SCULPT_PassList *psl;
- SCULPT_StorageList *stl;
-} SCULPT_Data;
-
-/* *********** STATIC *********** */
-
-static struct {
- struct GPUShader *shader_mask;
-} e_data = {NULL}; /* Engine data */
-
-typedef struct SCULPT_PrivateData {
- DRWShadingGroup *mask_overlay_grp;
-} SCULPT_PrivateData; /* Transient data */
-
-/* *********** FUNCTIONS *********** */
-
-/* Init Textures, Framebuffers, Storage and Shaders.
- * It is called for every frames.
- * (Optional) */
-static void SCULPT_engine_init(void *vedata)
-{
- SCULPT_TextureList *txl = ((SCULPT_Data *)vedata)->txl;
- SCULPT_FramebufferList *fbl = ((SCULPT_Data *)vedata)->fbl;
- SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
-
- UNUSED_VARS(txl, fbl, stl);
-
- if (!e_data.shader_mask) {
- e_data.shader_mask = DRW_shader_create_with_lib(datatoc_sculpt_mask_vert_glsl,
- NULL,
- datatoc_gpu_shader_3D_smooth_color_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
- }
-}
-
-/* Here init all passes and shading groups
- * Assume that all Passes are NULL */
-static void SCULPT_cache_init(void *vedata)
-{
- SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
- SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
-
- if (!stl->g_data) {
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- }
-
- {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_MUL;
- psl->pass = DRW_pass_create("Sculpt Pass", state);
-
- DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.shader_mask, psl->pass);
- DRW_shgroup_uniform_float(shgrp, "maskOpacity", &v3d->overlay.sculpt_mode_mask_opacity, 1);
- stl->g_data->mask_overlay_grp = shgrp;
- }
-}
-
-/* Add geometry to shadingGroups. Execute for each objects */
-static void SCULPT_cache_populate(void *vedata, Object *ob)
-{
- SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
- SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
-
- UNUSED_VARS(psl, stl);
-
- if (ob->sculpt) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- if ((ob == draw_ctx->obact) &&
- (BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) ||
- !ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active)) {
- PBVH *pbvh = ob->sculpt->pbvh;
- if (pbvh && pbvh_has_mask(pbvh)) {
- DRW_shgroup_call_sculpt(stl->g_data->mask_overlay_grp, ob, false, true, false);
- }
- }
- }
-}
-
-static void SCULPT_draw_scene(void *vedata)
-{
- SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
-
- DRW_draw_pass(psl->pass);
-}
-
-static void SCULPT_engine_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.shader_mask);
-}
-
-static const DrawEngineDataSize SCULPT_data_size = DRW_VIEWPORT_DATA_SIZE(SCULPT_Data);
-
-DrawEngineType draw_engine_sculpt_type = {
- NULL,
- NULL,
- N_("SculptMode"),
- &SCULPT_data_size,
- &SCULPT_engine_init,
- &SCULPT_engine_free,
- &SCULPT_cache_init,
- &SCULPT_cache_populate,
- NULL,
- NULL, /* draw_background but not needed by mode engines */
- &SCULPT_draw_scene,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/modes/shaders/armature_axes_vert.glsl b/source/blender/draw/modes/shaders/armature_axes_vert.glsl
deleted file mode 100644
index d7ed3e9ab71..00000000000
--- a/source/blender/draw/modes/shaders/armature_axes_vert.glsl
+++ /dev/null
@@ -1,35 +0,0 @@
-
-uniform mat4 ViewProjectionMatrix;
-uniform vec3 screenVecs[3];
-
-/* ---- Instantiated Attrs ---- */
-in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */
-in vec2 screenPos;
-in vec3 colorAxis;
-
-/* ---- Per instance Attrs ---- */
-in mat4 InstanceModelMatrix;
-in vec4 color;
-
-flat out vec4 finalColor;
-
-void main()
-{
- vec3 chosen_axis = InstanceModelMatrix[int(axis)].xyz;
- vec3 y_axis = InstanceModelMatrix[1].xyz;
- vec3 bone_loc = InstanceModelMatrix[3].xyz;
- vec3 wpos = bone_loc + y_axis + chosen_axis * fract(axis);
- vec3 spos = screenVecs[0].xyz * screenPos.x + screenVecs[1].xyz * screenPos.y;
- /* Scale uniformly by axis length */
- spos *= length(chosen_axis);
-
- vec4 pos_4d = vec4(wpos + spos, 1.0);
- gl_Position = ViewProjectionMatrix * pos_4d;
-
- finalColor.rgb = mix(colorAxis, color.rgb, color.a);
- finalColor.a = 1.0;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(pos_4d.xyz);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/armature_dof_vert.glsl b/source/blender/draw/modes/shaders/armature_dof_vert.glsl
deleted file mode 100644
index 321614835a1..00000000000
--- a/source/blender/draw/modes/shaders/armature_dof_vert.glsl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-uniform mat4 ViewProjectionMatrix;
-
-/* ---- Instantiated Attrs ---- */
-in vec2 pos;
-
-/* ---- Per instance Attrs ---- */
-/* Assumed to be in world coordinate already. */
-in mat4 InstanceModelMatrix;
-in vec4 color;
-in vec2 amin;
-in vec2 amax;
-
-flat out vec4 finalColor;
-
-vec3 sphere_project(float ax, float az)
-{
- float sine = 1.0 - ax * ax - az * az;
- float q3 = sqrt(max(0.0, sine));
-
- return vec3(-az * q3, 0.5 - sine, ax * q3) * 2.0;
-}
-
-void main()
-{
- vec3 final_pos = sphere_project(pos.x * abs((pos.x > 0.0) ? amax.x : amin.x),
- pos.y * abs((pos.y > 0.0) ? amax.y : amin.y));
- gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(final_pos, 1.0));
- finalColor = color;
-}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl b/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl
deleted file mode 100644
index 61aaf153e83..00000000000
--- a/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl
+++ /dev/null
@@ -1,15 +0,0 @@
-
-flat in vec3 finalStateColor; /* UNUSED */
-flat in vec3 finalBoneColor; /* UNUSED */
-in vec3 normalView;
-
-out vec4 fragColor;
-
-uniform vec4 color = vec4(1.0, 1.0, 1.0, 0.2);
-
-void main()
-{
- float n = normalize(normalView).z;
- n = 1.0 - clamp(-n, 0.0, 1.0);
- fragColor = color * n;
-}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl
deleted file mode 100644
index 424cc92b930..00000000000
--- a/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl
+++ /dev/null
@@ -1,18 +0,0 @@
-
-uniform float alpha = 0.6;
-
-flat in vec3 finalStateColor;
-flat in vec3 finalBoneColor;
-in vec3 normalView;
-
-out vec4 fragColor;
-
-void main()
-{
- /* Smooth lighting factor. */
- const float s = 0.2; /* [0.0-0.5] range */
- float n = normalize(normalView).z;
- float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0);
- fragColor.rgb = mix(finalStateColor, finalBoneColor, fac);
- fragColor.a = alpha;
-}
diff --git a/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl
deleted file mode 100644
index e674b802f65..00000000000
--- a/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl
+++ /dev/null
@@ -1,19 +0,0 @@
-
-flat in int vertFlag;
-
-out vec4 FragColor;
-
-void main()
-{
- /* TODO: vertex size */
-
- if ((vertFlag & VERT_SELECTED) != 0) {
- FragColor = colorVertexSelect;
- }
- else if ((vertFlag & VERT_ACTIVE) != 0) {
- FragColor = colorEditMeshActive;
- }
- else {
- FragColor = colorVertex;
- }
-}
diff --git a/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl
deleted file mode 100644
index bc1975bac81..00000000000
--- a/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Draw Lattice Vertices */
-
-uniform vec2 viewportSize;
-
-in vec3 pos;
-in int data;
-
-/* these are the same for all vertices
- * and does not need interpolation */
-flat out int vertFlag;
-flat out int clipCase;
-
-/* See fragment shader */
-noperspective out vec4 eData1;
-flat out vec4 eData2;
-
-/* project to screen space */
-vec2 proj(vec4 pos)
-{
- return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
-}
-
-void main()
-{
- GPU_INTEL_VERTEX_SHADER_WORKAROUND
-
- clipCase = 0;
-
- vec3 world_pos = point_object_to_world(pos);
- vec4 pPos = point_world_to_ndc(world_pos);
-
- /* only vertex position 0 is used */
- eData1 = eData2 = vec4(1e10);
- eData2.zw = proj(pPos);
-
- vertFlag = data;
-
- gl_PointSize = sizeVertex * 2.0;
- gl_Position = pPos;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl
deleted file mode 100644
index 9a53038a252..00000000000
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl
+++ /dev/null
@@ -1,7 +0,0 @@
-
-in vec2 pos;
-
-void main()
-{
- gl_Position = vec4(pos, 1.0, 1.0);
-}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl
deleted file mode 100644
index a3fcfd880d3..00000000000
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl
+++ /dev/null
@@ -1,22 +0,0 @@
-
-out vec4 FragColor;
-
-uniform sampler2D wireColor;
-uniform sampler2D wireDepth;
-uniform sampler2D sceneDepth;
-uniform float alpha;
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
- float wire_depth = texelFetch(wireDepth, uv, 0).r;
- float scene_depth = texelFetch(sceneDepth, uv, 0).r;
- vec4 wire_color = texelFetch(wireColor, uv, 0).rgba;
-
- FragColor = wire_color;
-
- /* Modulate alpha if occluded */
- if (wire_depth > scene_depth) {
- FragColor.a *= alpha;
- }
-}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl
deleted file mode 100644
index 5187571b27b..00000000000
--- a/source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Need dedicated obmat since we use instancing attribs
- * (we cannot let have baseinstance mess them). */
-uniform vec4 editModelMat[4];
-uniform vec3 screen_vecs[2];
-
-/* ---- Instantiated Attrs ---- */
-in vec2 pos;
-
-/* ---- Per instance Attrs ---- */
-in float size;
-in vec3 local_pos;
-
-flat out vec4 finalColor;
-
-void main()
-{
- mat4 obmat = mat4(editModelMat[0], editModelMat[1], editModelMat[2], editModelMat[3]);
- /* Could be optimized... but it is only for a handful of verts so not a priority. */
- mat3 imat = inverse(mat3(obmat));
- vec3 right = normalize(imat * vec3(screen_vecs[0]));
- vec3 up = normalize(imat * vec3(screen_vecs[1]));
- vec3 screen_pos = (right * pos.x + up * pos.y) * size;
- vec4 pos_4d = obmat * vec4(local_pos + screen_pos, 1.0);
- gl_Position = ViewProjectionMatrix * pos_4d;
- finalColor = colorSkinRoot;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(pos_4d.xyz);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/edit_normals_geom.glsl b/source/blender/draw/modes/shaders/edit_normals_geom.glsl
deleted file mode 100644
index 5f43c13478d..00000000000
--- a/source/blender/draw/modes/shaders/edit_normals_geom.glsl
+++ /dev/null
@@ -1,18 +0,0 @@
-
-layout(points) in;
-layout(line_strip, max_vertices = 2) out;
-
-flat in vec4 v1[1];
-flat in vec4 v2[1];
-
-void main()
-{
- for (int v = 0; v < 2; v++) {
- gl_Position = (v == 0) ? v1[0] : v2[0];
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance);
-#endif
- EmitVertex();
- }
- EndPrimitive();
-}
diff --git a/source/blender/draw/modes/shaders/edit_normals_vert.glsl b/source/blender/draw/modes/shaders/edit_normals_vert.glsl
deleted file mode 100644
index 384d13923f6..00000000000
--- a/source/blender/draw/modes/shaders/edit_normals_vert.glsl
+++ /dev/null
@@ -1,36 +0,0 @@
-
-uniform float normalSize;
-
-in vec3 pos;
-
-#ifdef LOOP_NORMALS
-in vec3 lnor;
-# define nor lnor
-
-#elif defined(FACE_NORMALS)
-in vec4 norAndFlag;
-# define nor norAndFlag.xyz
-#else
-
-in vec3 vnor;
-# define nor vnor
-#endif
-
-flat out vec4 v1;
-flat out vec4 v2;
-
-void main()
-{
- GPU_INTEL_VERTEX_SHADER_WORKAROUND
-
- vec3 n = normalize(normal_object_to_world(nor));
-
- vec3 world_pos = point_object_to_world(pos);
-
- v1 = point_world_to_ndc(world_pos);
- v2 = point_world_to_ndc(world_pos + n * normalSize);
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/object_camera_image_frag.glsl b/source/blender/draw/modes/shaders/object_camera_image_frag.glsl
deleted file mode 100644
index 7804ebdb8c9..00000000000
--- a/source/blender/draw/modes/shaders/object_camera_image_frag.glsl
+++ /dev/null
@@ -1,25 +0,0 @@
-in vec2 texCoord_interp;
-out vec4 fragColor;
-
-uniform sampler2D image;
-uniform float alpha;
-uniform bool imagePremultiplied;
-
-void main()
-{
-#ifdef DRW_STATE_DO_COLOR_MANAGEMENT
- /* render engine has already applied the view transform. We sample the
- * camera images as srgb*/
- vec4 color = texture_read_as_srgb(image, imagePremultiplied, texCoord_interp);
-
-#else
- /* Render engine renders in linearrgb. We sample the camera images as
- * linearrgb */
- vec4 color = texture_read_as_linearrgb(image, imagePremultiplied, texCoord_interp);
-#endif
-
- color.a *= alpha;
- color.rgb *= color.a;
-
- fragColor = color;
-}
diff --git a/source/blender/draw/modes/shaders/object_camera_image_vert.glsl b/source/blender/draw/modes/shaders/object_camera_image_vert.glsl
deleted file mode 100644
index 61b88c013aa..00000000000
--- a/source/blender/draw/modes/shaders/object_camera_image_vert.glsl
+++ /dev/null
@@ -1,18 +0,0 @@
-uniform mat4 TransformMat;
-uniform float flipX;
-uniform float flipY;
-uniform float depth;
-
-in vec2 texCoord;
-in vec2 pos;
-
-out vec2 texCoord_interp;
-
-void main()
-{
- vec4 position = TransformMat * vec4((pos - 0.5) * 2.0, 1.0, 1.0);
- gl_Position = vec4(position.xy, depth, 1.0);
-
- vec2 uv_mul = vec2(flipX, flipY);
- texCoord_interp = texCoord * uv_mul;
-}
diff --git a/source/blender/draw/modes/shaders/object_color_axes_vert.glsl b/source/blender/draw/modes/shaders/object_color_axes_vert.glsl
deleted file mode 100644
index 239dec30c42..00000000000
--- a/source/blender/draw/modes/shaders/object_color_axes_vert.glsl
+++ /dev/null
@@ -1,35 +0,0 @@
-
-uniform mat4 ViewProjectionMatrix;
-uniform vec3 screenVecs[3];
-
-/* ---- Instantiated Attrs ---- */
-in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */
-in vec2 screenPos;
-in vec3 colorAxis;
-
-/* ---- Per instance Attrs ---- */
-in mat4 InstanceModelMatrix;
-in vec4 color;
-
-flat out vec4 finalColor;
-
-void main()
-{
- float draw_size = 4.0;
- vec3 chosen_axis = InstanceModelMatrix[int(axis)].xyz;
- vec3 loc = InstanceModelMatrix[3].xyz;
- vec3 wpos = loc + chosen_axis * fract(axis) * draw_size;
- vec3 spos = screenVecs[0].xyz * screenPos.x + screenVecs[1].xyz * screenPos.y;
- /* Scale uniformly by axis length */
- spos *= length(chosen_axis) * draw_size;
-
- vec4 pos_4d = vec4(wpos + spos, 1.0);
- gl_Position = ViewProjectionMatrix * pos_4d;
-
- finalColor.rgb = mix(colorAxis, color.rgb, color.a);
- finalColor.a = 1.0;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(pos_4d.xyz);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl b/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl
deleted file mode 100644
index 43c8e313fc3..00000000000
--- a/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl
+++ /dev/null
@@ -1,35 +0,0 @@
-
-uniform mat4 ViewProjectionMatrix;
-
-uniform vec3 screenVecs[3];
-
-/* ---- Instantiated Attrs ---- */
-in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */
-in vec2 screenPos;
-
-/* ---- Per instance Attrs ---- */
-in vec3 color;
-in float size;
-in mat4 InstanceModelMatrix;
-
-flat out vec4 finalColor;
-
-void main()
-{
- float draw_size = 4.0 * size;
- vec3 chosen_axis = InstanceModelMatrix[int(axis)].xyz;
- vec3 loc = InstanceModelMatrix[3].xyz;
- vec3 wpos = loc + chosen_axis * fract(axis) * draw_size;
- vec3 spos = screenVecs[0].xyz * screenPos.x + screenVecs[1].xyz * screenPos.y;
- /* Scale uniformly by axis length */
- spos *= length(chosen_axis) * draw_size;
-
- vec4 pos_4d = vec4(wpos + spos, 1.0);
- gl_Position = ViewProjectionMatrix * pos_4d;
-
- finalColor = vec4(color, 1.0);
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(pos_4d.xyz);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
deleted file mode 100644
index e33aa6cdcc1..00000000000
--- a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
+++ /dev/null
@@ -1,53 +0,0 @@
-
-flat in vec4 finalColor;
-
-#ifndef USE_WIRE
-in vec2 texCoord_interp;
-#endif
-
-out vec4 fragColor;
-
-#ifndef USE_WIRE
-uniform sampler2D image;
-uniform bool imagePremultiplied;
-#endif
-
-uniform int depthMode;
-uniform bool useAlphaTest;
-
-void main()
-{
-#ifdef USE_WIRE
- fragColor = finalColor;
-#else
- vec4 tex_col = texture_read_as_srgb(image, imagePremultiplied, texCoord_interp);
- fragColor = finalColor * tex_col;
-
- if (useAlphaTest) {
- /* Arbitrary discard anything below 5% opacity.
- * Note that this could be exposed to the User. */
- if (tex_col.a < 0.05) {
- discard;
- }
- else {
- fragColor.a = 1.0;
- }
- }
-#endif
-
- if (depthMode == DEPTH_BACK) {
- gl_FragDepth = 0.999999;
-#ifdef USE_WIRE
- gl_FragDepth -= 1e-5;
-#endif
- }
- else if (depthMode == DEPTH_FRONT) {
- gl_FragDepth = 0.000001;
-#ifdef USE_WIRE
- gl_FragDepth -= 1e-5;
-#endif
- }
- else if (depthMode == DEPTH_UNCHANGED) {
- gl_FragDepth = gl_FragCoord.z;
- }
-}
diff --git a/source/blender/draw/modes/shaders/object_empty_image_vert.glsl b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl
deleted file mode 100644
index 36e86290be7..00000000000
--- a/source/blender/draw/modes/shaders/object_empty_image_vert.glsl
+++ /dev/null
@@ -1,36 +0,0 @@
-
-uniform vec2 aspect;
-uniform float size;
-uniform vec2 offset;
-#ifdef USE_WIRE
-uniform vec3 color;
-#else
-uniform vec4 objectColor;
-#endif
-
-in vec2 texCoord;
-in vec2 pos;
-
-flat out vec4 finalColor;
-
-#ifndef USE_WIRE
-out vec2 texCoord_interp;
-#endif
-
-void main()
-{
- vec3 pos = vec3((pos + offset) * (size * aspect), 0.0);
- vec3 world_pos = point_object_to_world(pos);
- gl_Position = point_world_to_ndc(world_pos);
-#ifdef USE_WIRE
- gl_Position.z -= 1e-5;
- finalColor = vec4(color, 1.0);
-#else
- texCoord_interp = texCoord;
- finalColor = objectColor;
-#endif
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
deleted file mode 100644
index 144024a7d5d..00000000000
--- a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
+++ /dev/null
@@ -1,31 +0,0 @@
-
-uniform ivec3 grid_resolution;
-uniform vec3 corner;
-uniform vec3 increment_x;
-uniform vec3 increment_y;
-uniform vec3 increment_z;
-
-flat out int objectId;
-
-void main()
-{
- vec3 ls_cell_location;
- /* Keep in sync with update_irradiance_probe */
- ls_cell_location.z = float(gl_VertexID % grid_resolution.z);
- ls_cell_location.y = float((gl_VertexID / grid_resolution.z) % grid_resolution.y);
- ls_cell_location.x = float(gl_VertexID / (grid_resolution.z * grid_resolution.y));
-
- vec3 ws_cell_location = corner +
- (increment_x * ls_cell_location.x + increment_y * ls_cell_location.y +
- increment_z * ls_cell_location.z);
-
- gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0);
- gl_PointSize = 2.0f;
-
- /* ID 0 is nothing (background) */
- objectId = resource_handle + 1;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(ws_cell_location);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl b/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl
deleted file mode 100644
index 9414309570b..00000000000
--- a/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl
+++ /dev/null
@@ -1,36 +0,0 @@
-
-/* This shader takes a 2D shape, puts it in 3D Object space such that is stays aligned with view,
- * and scales the shape according to per-instance attributes
- * Note that if the stiffness is zero, it assumes the scale is directly multiplied by the radius */
-
-uniform mat4 ViewProjectionMatrix;
-uniform vec3 screen_vecs[2];
-
-/* ---- Instantiated Attrs ---- */
-in vec2 pos;
-
-/* ---- Per instance Attrs ---- */
-in mat3x4 ScaleTranslationMatrix;
-in float radius;
-in vec3 color;
-
-flat out vec4 finalColor;
-
-void main()
-{
- mat3 Scamat = mat3(ScaleTranslationMatrix);
- vec4 world_pos = vec4(ScaleTranslationMatrix[0][3],
- ScaleTranslationMatrix[1][3],
- ScaleTranslationMatrix[2][3],
- 1.0);
-
- vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y;
- world_pos.xyz += Scamat * (screen_pos * radius);
-
- gl_Position = ViewProjectionMatrix * world_pos;
- finalColor = vec4(color, 1.0);
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos.xyz);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
deleted file mode 100644
index 7b86d477a39..00000000000
--- a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
+++ /dev/null
@@ -1,87 +0,0 @@
-
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform usampler2D outlineId;
-uniform sampler2D outlineDepth;
-uniform sampler2D sceneDepth;
-
-uniform float alphaOcclu;
-uniform vec2 viewportSize;
-
-void main()
-{
- ivec2 texel = ivec2(gl_FragCoord.xy);
-
-#ifdef GPU_ARB_texture_gather
- vec2 texel_size = 1.0 / vec2(textureSize(outlineId, 0).xy);
- vec2 uv = ceil(gl_FragCoord.xy) * texel_size;
-
- /* Samples order is CW starting from top left. */
- uvec4 tmp1 = textureGather(outlineId, uv - texel_size);
- uvec4 tmp2 = textureGather(outlineId, uv);
-
- uint ref_id = tmp1.y;
- uvec4 id = uvec4(tmp1.xz, tmp2.xz);
-#else
- uvec4 id;
- uint ref_id = texelFetch(outlineId, texel, 0).r;
- id.x = texelFetchOffset(outlineId, texel, 0, ivec2(-1, 0)).r;
- id.y = texelFetchOffset(outlineId, texel, 0, ivec2(0, -1)).r;
- id.z = texelFetchOffset(outlineId, texel, 0, ivec2(0, 1)).r;
- id.w = texelFetchOffset(outlineId, texel, 0, ivec2(1, 0)).r;
-#endif
-
-#ifdef WIRE
- /* We want only 2px outlines. */
- /* TODO optimize, don't sample if we don't need to. */
- id.xy = uvec2(ref_id);
-#endif
-
- bool outline = any(notEqual(id, uvec4(ref_id)));
-
- ivec2 depth_texel = texel;
- /* If texel is an outline but has no valid id ...
- * replace id and depth texel by a valid one.
- * This keeps the outline thickness consistent everywhere. */
- if (ref_id == 0u && outline) {
- depth_texel = (id.x != 0u) ? texel + ivec2(-1, 0) : depth_texel;
- depth_texel = (id.y != 0u) ? texel + ivec2(0, -1) : depth_texel;
- depth_texel = (id.z != 0u) ? texel + ivec2(0, 1) : depth_texel;
- depth_texel = (id.w != 0u) ? texel + ivec2(1, 0) : depth_texel;
-
- ref_id = (id.x != 0u) ? id.x : ref_id;
- ref_id = (id.y != 0u) ? id.y : ref_id;
- ref_id = (id.z != 0u) ? id.z : ref_id;
- ref_id = (id.w != 0u) ? id.w : ref_id;
- }
-
- float ref_depth = texelFetch(outlineDepth, depth_texel, 0).r;
- float scene_depth = texelFetch(sceneDepth, depth_texel, 0).r;
-
- /* Avoid bad cases of zfighting for occlusion only. */
- const float epsilon = 3.0 / 8388608.0;
- bool occluded = (ref_depth > scene_depth + epsilon);
-
- /* WATCH: Keep in sync with outlineId of the prepass. */
- uint color_id = ref_id >> 14u;
- if (ref_id == 0u) {
- FragColor = vec4(0.0);
- }
- else if (color_id == 1u) {
- FragColor = colorSelect;
- }
- else if (color_id == 2u) {
- FragColor = colorDupliSelect;
- }
- else if (color_id == 3u) {
- FragColor = colorActive;
- }
- else {
- FragColor = colorTransform;
- }
-
- FragColor.a *= (occluded) ? alphaOcclu : 1.0;
- FragColor.a = (outline) ? FragColor.a : 0.0;
-}
diff --git a/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl b/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl
deleted file mode 100644
index cb9fe0e7c36..00000000000
--- a/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl
+++ /dev/null
@@ -1,51 +0,0 @@
-
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform sampler2D outlineColor;
-
-uniform float alpha;
-uniform bool doExpand;
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
- FragColor = texelFetch(outlineColor, uv, 0).rgba;
-
- vec4 color[4];
- color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2(1, 0)).rgba;
- color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, 1)).rgba;
- color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-1, 0)).rgba;
- color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, -1)).rgba;
-
- vec4 values = vec4(color[0].a, color[1].a, color[2].a, color[3].a);
-
- vec4 tests = step(vec4(1e-6), values); /* (color.a != 0.0) */
- bvec4 btests = equal(tests, vec4(1.0));
-
- if (FragColor.a != 0.0) {
- return;
- }
-
-#ifdef LARGE_OUTLINE
- if (!any(btests)) {
- color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2(2, 0)).rgba;
- color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, 2)).rgba;
- color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-2, 0)).rgba;
- color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, -2)).rgba;
-
- values = vec4(color[0].a, color[1].a, color[2].a, color[3].a);
-
- tests = step(vec4(1e-6), values); /* (color.a != 0.0) */
- btests = equal(tests, vec4(1.0));
- }
-#endif
-
- FragColor = (btests.x) ? color[0] : FragColor;
- FragColor = (btests.y) ? color[1] : FragColor;
- FragColor = (btests.z) ? color[2] : FragColor;
- FragColor = (btests.w) ? color[3] : FragColor;
-
- FragColor.a *= (!doExpand) ? 0.0 : 1.0;
-}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
deleted file mode 100644
index 5d6c4881b5b..00000000000
--- a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
+++ /dev/null
@@ -1,18 +0,0 @@
-
-/* Should be 2 bits only [0..3]. */
-uniform int outlineId;
-
-flat in int objectId;
-
-/* using uint because 16bit uint can contain more ids than int. */
-out uint outId;
-
-/* Replace top 2 bits (of the 16bit output) by outlineId.
- * This leaves 16K different IDs to create outlines between objects.
- * SHIFT = (32 - (16 - 2)) */
-#define SHIFT 18u
-
-void main()
-{
- outId = (uint(outlineId) << 14u) | ((uint(objectId) << SHIFT) >> SHIFT);
-}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
deleted file mode 100644
index 7740f9a4af2..00000000000
--- a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
+++ /dev/null
@@ -1,29 +0,0 @@
-
-in vec3 pos;
-
-#ifdef USE_GEOM
-out vec3 vPos;
-out int objectId_g;
-# define objectId objectId_g
-#else
-
-flat out int objectId;
-#endif
-
-void main()
-{
- vec3 world_pos = point_object_to_world(pos);
-#ifdef USE_GEOM
- vPos = point_world_to_view(world_pos);
-#endif
- gl_Position = point_world_to_ndc(world_pos);
- /* Small bias to always be on top of the geom. */
- gl_Position.z -= 1e-3;
-
- /* ID 0 is nothing (background) */
- objectId = resource_handle + 1;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl b/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl
deleted file mode 100644
index ba5d073a9c2..00000000000
--- a/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl
+++ /dev/null
@@ -1,21 +0,0 @@
-
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform sampler2D outlineBluredColor;
-uniform vec2 rcpDimensions;
-
-void main()
-{
-#ifdef USE_FXAA
- float aa_alpha =
- FxaaPixelShader(uvcoordsvar.st, outlineBluredColor, rcpDimensions, 1.0, 0.166, 0.0833).r;
-#endif
-
- FragColor = texture(outlineBluredColor, uvcoordsvar.st).rgba;
-
-#ifdef USE_FXAA
- FragColor.a = aa_alpha;
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl b/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl
deleted file mode 100644
index d15580056b0..00000000000
--- a/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl
+++ /dev/null
@@ -1,53 +0,0 @@
-
-uniform vec3 color;
-uniform vec3 outlineColor;
-uniform sampler1D ramp;
-
-in vec4 radii;
-flat in float finalVal;
-
-out vec4 fragColor;
-
-void main()
-{
- float dist = length(gl_PointCoord - vec2(0.5));
-
- // transparent outside of point
- // --- 0 ---
- // smooth transition
- // --- 1 ---
- // pure outline color
- // --- 2 ---
- // smooth transition
- // --- 3 ---
- // pure point color
- // ...
- // dist = 0 at center of point
-
- float midStroke = 0.5 * (radii[1] + radii[2]);
-
- if (dist > midStroke) {
- if (finalVal < 0.0) {
- fragColor.rgb = outlineColor;
- }
- else {
- fragColor.rgb = texture(ramp, finalVal).rgb;
- }
-
- fragColor.a = mix(1.0, 0.0, smoothstep(radii[1], radii[0], dist));
- }
- else {
- if (finalVal < 0.0) {
- fragColor.rgb = mix(color, outlineColor, smoothstep(radii[3], radii[2], dist));
- }
- else {
- fragColor.rgb = texture(ramp, finalVal).rgb;
- }
-
- fragColor.a = 1.0;
- }
-
- if (fragColor.a == 0.0) {
- discard;
- }
-}
diff --git a/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl b/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl
deleted file mode 100644
index f98ae9a9515..00000000000
--- a/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl
+++ /dev/null
@@ -1,36 +0,0 @@
-
-uniform float pixel_size;
-uniform float size;
-
-in vec3 pos;
-in float val;
-
-out vec4 radii;
-flat out float finalVal;
-
-void main()
-{
- vec3 world_pos = point_object_to_world(pos);
-
- float view_z = dot(ViewMatrixInverse[2].xyz, world_pos - ViewMatrixInverse[3].xyz);
-
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
- float psize = (is_persp) ? (size / (-view_z * pixel_size)) : (size / pixel_size);
- gl_Position = point_world_to_ndc(world_pos);
-
- gl_PointSize = psize;
-
- // calculate concentric radii in pixels
- float radius = 0.5 * psize;
-
- // start at the outside and progress toward the center
- radii[0] = radius;
- radii[1] = radius - 1.0;
- radii[2] = radius - 1.0;
- radii[3] = radius - 2.0;
-
- // convert to PointCoord units
- radii /= psize;
-
- finalVal = val;
-}
diff --git a/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl b/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl
deleted file mode 100644
index 46aceb245f4..00000000000
--- a/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl
+++ /dev/null
@@ -1,60 +0,0 @@
-
-uniform bool screen_space;
-uniform float draw_size;
-uniform vec3 color;
-uniform sampler1D ramp;
-
-/* ---- Instantiated Attrs ---- */
-in vec3 inst_pos;
-in int axis;
-
-/* ---- Per instance Attrs ---- */
-in vec3 pos;
-in vec4 rot;
-in float val;
-
-flat out vec4 finalColor;
-
-vec3 rotate(vec3 vec, vec4 quat)
-{
- /* The quaternion representation here stores the w component in the first index */
- return vec + 2.0 * cross(quat.yzw, cross(quat.yzw, vec) + quat.x * vec);
-}
-
-void main()
-{
- if (screen_space) {
- gl_Position = ViewMatrix * (ModelMatrix * vec4(pos, 1.0));
- gl_Position.xyz += inst_pos * draw_size;
- gl_Position = ProjectionMatrix * gl_Position;
- }
- else {
- float size = draw_size;
-
- if (axis > -1) {
- size *= 2;
- }
-
- vec3 pos_rot = pos + rotate(inst_pos * size, rot);
- gl_Position = point_object_to_ndc(pos_rot);
- }
-
-#ifdef USE_AXIS
- if (axis == 0) {
- finalColor = vec4(1.0, 0.0, 0.0, 1.0);
- }
- else if (axis == 1) {
- finalColor = vec4(0.0, 1.0, 0.0, 1.0);
- }
- else {
- finalColor = vec4(0.0, 0.0, 1.0, 1.0);
- }
-#else
- if (val < 0.0) {
- finalColor = vec4(color, 1.0);
- }
- else {
- finalColor = vec4(texture(ramp, val).rgb, 1.0);
- }
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl
deleted file mode 100644
index 1ed35b4a421..00000000000
--- a/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl
+++ /dev/null
@@ -1,9 +0,0 @@
-uniform vec3 color_towards = vec3(0.0, 0.0, 1.0);
-uniform vec3 color_outwards = vec3(1.0, 0.0, 0.0);
-
-out vec4 fragColor;
-
-void main()
-{
- fragColor = vec4(gl_FrontFacing ? color_towards : color_outwards, 0.7);
-}
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl
deleted file mode 100644
index 9414d25e71e..00000000000
--- a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl
+++ /dev/null
@@ -1,23 +0,0 @@
-
-uniform vec3 wireColor;
-uniform vec3 rimColor;
-
-flat in float edgeSharpness;
-in float facing;
-
-out vec4 fragColor;
-
-void main()
-{
- if (edgeSharpness < 0.0) {
- discard;
- }
-
- float facing_clamped = clamp(abs(facing), 0.0, 1.0);
-
- vec3 final_front_col = mix(rimColor, wireColor, 0.4);
- vec3 final_rim_col = mix(rimColor, wireColor, 0.1);
-
- fragColor.rgb = mix(final_rim_col, final_front_col, facing_clamped);
- fragColor.a = 1.0f;
-}
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl
deleted file mode 100644
index 6ae52d43a48..00000000000
--- a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl
+++ /dev/null
@@ -1,60 +0,0 @@
-
-/* This shader is only used for edge selection and OSX workaround for large wires. */
-
-uniform float wireSize;
-uniform vec2 viewportSize;
-uniform vec2 viewportSizeInv;
-
-layout(lines) in;
-layout(triangle_strip, max_vertices = 4) out;
-
-in float facing_g[];
-in float edgeSharpness_g[];
-
-#ifndef SELECT_EDGES
-out float facing;
-flat out float edgeSharpness;
-#endif
-
-void do_vertex(const int i, float coord, vec2 offset)
-{
-#ifndef SELECT_EDGES
- edgeSharpness = edgeSharpness_g[i];
- facing = facing_g[i];
-#endif
- gl_Position = gl_in[i].gl_Position;
- /* Multiply offset by 2 because gl_Position range is [-1..1]. */
- gl_Position.xy += offset * 2.0 * gl_Position.w;
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[i].gl_ClipDistance);
-#endif
- EmitVertex();
-}
-
-void main()
-{
- vec2 ss_pos[2];
- ss_pos[0] = gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w;
- ss_pos[1] = gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w;
-
- vec2 line = ss_pos[0] - ss_pos[1];
- line = abs(line) * viewportSize;
-
- float half_size = wireSize;
-
- vec3 edge_ofs = half_size * viewportSizeInv.xyy * vec3(1.0, 1.0, 0.0);
-
- bool horizontal = line.x > line.y;
- edge_ofs = (horizontal) ? edge_ofs.zyz : edge_ofs.xzz;
-
- if (edgeSharpness_g[0] < 0.0) {
- return;
- }
-
- do_vertex(0, half_size, edge_ofs.xy);
- do_vertex(0, -half_size, -edge_ofs.xy);
- do_vertex(1, half_size, edge_ofs.xy);
- do_vertex(1, -half_size, -edge_ofs.xy);
-
- EndPrimitive();
-}
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl
deleted file mode 100644
index 722f62d9b6d..00000000000
--- a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl
+++ /dev/null
@@ -1,42 +0,0 @@
-
-uniform float wireStepParam;
-
-in vec3 pos;
-in vec3 nor;
-in float wd; /* wiredata */
-
-float get_edge_sharpness(float wd)
-{
-#ifndef USE_SCULPT
- return ((wd == 0.0) ? -1.5 : wd) + wireStepParam;
-#else
- return 1.0;
-#endif
-}
-
-/* Geometry shader version */
-#if defined(SELECT_EDGES) || defined(USE_GEOM)
-out float facing_g;
-out float edgeSharpness_g;
-
-#else /* USE_GEOM */
-out float facing;
-flat out float edgeSharpness;
-# define facing_g facing
-# define edgeSharpness_g edgeSharpness
-
-#endif /* SELECT_EDGES */
-
-void main()
-{
- vec3 wpos = point_object_to_world(pos);
- gl_Position = point_world_to_ndc(wpos);
-
- vec3 wnor = normalize(normal_object_to_world(nor));
- facing_g = dot(wnor, ViewMatrixInverse[2].xyz);
- edgeSharpness_g = get_edge_sharpness(wd);
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(wpos);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/paint_face_vert.glsl b/source/blender/draw/modes/shaders/paint_face_vert.glsl
deleted file mode 100644
index af362f24a85..00000000000
--- a/source/blender/draw/modes/shaders/paint_face_vert.glsl
+++ /dev/null
@@ -1,11 +0,0 @@
-in vec3 pos;
-
-void main()
-{
- vec3 world_pos = point_object_to_world(pos);
- gl_Position = point_world_to_ndc(world_pos);
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/paint_texture_frag.glsl b/source/blender/draw/modes/shaders/paint_texture_frag.glsl
deleted file mode 100644
index edd7c2af001..00000000000
--- a/source/blender/draw/modes/shaders/paint_texture_frag.glsl
+++ /dev/null
@@ -1,25 +0,0 @@
-in vec2 masking_uv_interp;
-
-out vec4 fragColor;
-
-uniform float alpha = 1.0;
-
-uniform sampler2D maskingImage;
-uniform bool maskingImagePremultiplied;
-uniform vec3 maskingColor;
-uniform bool maskingInvertStencil;
-
-void main()
-{
-
- vec4 mask = vec4(
- texture_read_as_srgb(maskingImage, maskingImagePremultiplied, masking_uv_interp).rgb, 1.0);
- if (maskingInvertStencil) {
- mask.rgb = 1.0 - mask.rgb;
- }
- float mask_step = smoothstep(0, 3.0, mask.r + mask.g + mask.b);
- mask.rgb *= maskingColor;
- mask.a = mask_step * alpha;
-
- fragColor = mask;
-}
diff --git a/source/blender/draw/modes/shaders/paint_vert_frag.glsl b/source/blender/draw/modes/shaders/paint_vert_frag.glsl
deleted file mode 100644
index 3303dfa6173..00000000000
--- a/source/blender/draw/modes/shaders/paint_vert_frag.glsl
+++ /dev/null
@@ -1,17 +0,0 @@
-
-flat in vec4 finalColor;
-out vec4 fragColor;
-
-void main()
-{
- vec2 centered = gl_PointCoord - vec2(0.5);
- float dist_squared = dot(centered, centered);
- const float rad_squared = 0.25;
-
- // round point with jaggy edges
- if (dist_squared > rad_squared) {
- discard;
- }
-
- fragColor = finalColor;
-}
diff --git a/source/blender/draw/modes/shaders/paint_wire_frag.glsl b/source/blender/draw/modes/shaders/paint_wire_frag.glsl
deleted file mode 100644
index 6c214534812..00000000000
--- a/source/blender/draw/modes/shaders/paint_wire_frag.glsl
+++ /dev/null
@@ -1,8 +0,0 @@
-
-flat in vec4 finalColor;
-out vec4 fragColor;
-
-void main()
-{
- fragColor = finalColor;
-}
diff --git a/source/blender/draw/modes/shaders/particle_strand_frag.glsl b/source/blender/draw/modes/shaders/particle_strand_frag.glsl
deleted file mode 100644
index 49d843b7e0e..00000000000
--- a/source/blender/draw/modes/shaders/particle_strand_frag.glsl
+++ /dev/null
@@ -1,22 +0,0 @@
-
-in vec4 finalColor;
-#ifdef USE_POINTS
-in vec2 radii;
-#endif
-
-out vec4 fragColor;
-
-void main()
-{
- fragColor = finalColor;
-
-#ifdef USE_POINTS
- float dist = length(gl_PointCoord - vec2(0.5));
-
- fragColor.a = mix(finalColor.a, 0.0, smoothstep(radii[1], radii[0], dist));
-
- if (fragColor.a == 0.0) {
- discard;
- }
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/particle_strand_vert.glsl b/source/blender/draw/modes/shaders/particle_strand_vert.glsl
deleted file mode 100644
index 45fadb4ed5e..00000000000
--- a/source/blender/draw/modes/shaders/particle_strand_vert.glsl
+++ /dev/null
@@ -1,71 +0,0 @@
-
-in vec3 pos;
-in float color;
-
-out vec4 finalColor;
-#ifdef USE_POINTS
-out vec2 radii;
-#endif
-
-vec3 weight_to_rgb(float weight)
-{
- vec3 r_rgb;
- float blend = ((weight / 2.0) + 0.5);
-
- if (weight <= 0.25) { /* blue->cyan */
- r_rgb[0] = 0.0;
- r_rgb[1] = blend * weight * 4.0;
- r_rgb[2] = blend;
- }
- else if (weight <= 0.50) { /* cyan->green */
- r_rgb[0] = 0.0;
- r_rgb[1] = blend;
- r_rgb[2] = blend * (1.0 - ((weight - 0.25) * 4.0));
- }
- else if (weight <= 0.75) { /* green->yellow */
- r_rgb[0] = blend * ((weight - 0.50) * 4.0);
- r_rgb[1] = blend;
- r_rgb[2] = 0.0;
- }
- else if (weight <= 1.0) { /* yellow->red */
- r_rgb[0] = blend;
- r_rgb[1] = blend * (1.0 - ((weight - 0.75) * 4.0));
- r_rgb[2] = 0.0;
- }
- else {
- /* exceptional value, unclamped or nan,
- * avoid uninitialized memory use */
- r_rgb[0] = 1.0;
- r_rgb[1] = 0.0;
- r_rgb[2] = 1.0;
- }
-
- return r_rgb;
-}
-
-void main()
-{
- vec3 world_pos = point_object_to_world(pos);
- gl_Position = point_world_to_ndc(world_pos);
-
-#ifdef USE_WEIGHT
- finalColor = vec4(weight_to_rgb(color), 1.0);
-#else
- finalColor = mix(colorWire, colorEdgeSelect, color);
-#endif
-
-#ifdef USE_POINTS
- float size = sizeVertex * 2.0;
- gl_PointSize = size;
-
- /* calculate concentric radii in pixels */
- float radius = sizeVertex;
-
- /* start at the outside and progress toward the center */
- radii[0] = radius;
- radii[1] = radius - 1.0;
-
- /* convert to PointCoord units */
- radii /= size;
-#endif
-}
diff --git a/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl b/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl
deleted file mode 100644
index 7b026836690..00000000000
--- a/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-uniform float maskOpacity;
-
-in vec3 pos;
-in float msk;
-
-out vec4 finalColor;
-
-void main()
-{
- vec3 world_pos = point_object_to_world(pos);
- gl_Position = point_world_to_ndc(world_pos);
-
- float mask = 1.0 - (msk * maskOpacity);
- finalColor = vec4(mask, mask, mask, 1.0);
-}
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 8951677b32f..2ec1634fa38 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -4222,7 +4222,8 @@ void ANIM_channel_draw(
* - Slider should start before the toggles (if they're visible)
* to keep a clean line down the side.
*/
- if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) {
+ if ((draw_sliders) &&
+ ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY, ANIMTYPE_GPLAYER)) {
/* adjust offset */
offset += SLIDER_WIDTH;
}
@@ -4992,7 +4993,8 @@ void ANIM_channel_draw_widgets(const bContext *C,
* - Slider should start before the toggles (if they're visible)
* to keep a clean line down the side.
*/
- if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) {
+ if ((draw_sliders) &&
+ ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY, ANIMTYPE_GPLAYER)) {
/* adjust offset */
/* TODO: make slider width dynamic,
* so that they can be easier to use when the view is wide enough. */
@@ -5053,8 +5055,81 @@ void ANIM_channel_draw_widgets(const bContext *C,
rna_path = BKE_keyblock_curval_rnapath_get(key, kb);
free_path = 1;
}
+ /* Special for Grease Pencil Layer. */
+ else if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPdata *gpd = (bGPdata *)ale->id;
+ if ((gpd != NULL) && ((gpd->flag & GP_DATA_ANNOTATIONS) == 0)) {
+ /* Add some offset to make it more pleasing to the eye. */
+ offset += SLIDER_WIDTH / 2.1f;
+
+ char *gp_rna_path = NULL;
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ const short width = SLIDER_WIDTH / 5;
+
+ /* Create the RNA pointers. */
+ RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr);
+ RNA_id_pointer_create(ale->id, &id_ptr);
+ int icon;
+
+ /* Layer opacity. */
+ UI_block_emboss_set(block, UI_EMBOSS);
+ prop = RNA_struct_find_property(&ptr, "opacity");
+ gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop);
+ if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) {
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ array_index,
+ "",
+ ICON_NONE,
+ offset,
+ ymid,
+ width * 3,
+ channel_height);
+ }
+ MEM_freeN(gp_rna_path);
+
+ /* Mask Layer. */
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ prop = RNA_struct_find_property(&ptr, "mask_layer");
+ gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop);
+ if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) {
+ icon = (gpl->flag & GP_LAYER_USE_MASK) ? ICON_MOD_MASK : ICON_LAYER_ACTIVE;
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ array_index,
+ "",
+ icon,
+ offset + (width * 3),
+ ymid,
+ width,
+ channel_height);
+ }
+ MEM_freeN(gp_rna_path);
+
+ /* Layer onion skinning switch. */
+ prop = RNA_struct_find_property(&ptr, "use_onion_skinning");
+ gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop);
+ if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) {
+ icon = (gpl->onion_flag & GP_LAYER_ONIONSKIN) ? ICON_ONIONSKIN_ON :
+ ICON_ONIONSKIN_OFF;
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ array_index,
+ "",
+ icon,
+ offset + (width * 4),
+ ymid,
+ width,
+ channel_height);
+ }
+ MEM_freeN(gp_rna_path);
+ }
+ }
- /* only if RNA-Path found */
+ /* Only if RNA-Path found. */
if (rna_path) {
/* get RNA pointer, and resolve the path */
RNA_id_pointer_create(ale->id, &id_ptr);
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 0fc137295d0..e90289de963 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -898,6 +898,23 @@ static AnimChanRearrangeFp rearrange_get_mode_func(eRearrangeAnimChan_Mode mode)
}
}
+/* get rearranging function, given 'rearrange' mode (grease pencil is inverted) */
+static AnimChanRearrangeFp rearrange_gpencil_get_mode_func(eRearrangeAnimChan_Mode mode)
+{
+ switch (mode) {
+ case REARRANGE_ANIMCHAN_TOP:
+ return rearrange_island_bottom;
+ case REARRANGE_ANIMCHAN_UP:
+ return rearrange_island_down;
+ case REARRANGE_ANIMCHAN_DOWN:
+ return rearrange_island_up;
+ case REARRANGE_ANIMCHAN_BOTTOM:
+ return rearrange_island_top;
+ default:
+ return NULL;
+ }
+}
+
/* Rearrange Islands Generics ------------------------------------- */
/* add channel into list of islands */
@@ -1331,7 +1348,7 @@ static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode
int filter;
/* get rearranging function */
- AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+ AnimChanRearrangeFp rearrange_func = rearrange_gpencil_get_mode_func(mode);
if (rearrange_func == NULL) {
return;
@@ -1360,10 +1377,15 @@ static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode
/* free visible layers data */
BLI_freelistN(&anim_data_visible);
+
+ /* Tag to recalc geometry */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
/* free GPD channel data */
ANIM_animdata_freelist(&anim_data);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
/* ------------------- */
@@ -3115,6 +3137,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* update other layer status */
BKE_gpencil_layer_setactive(gpd, gpl);
BKE_gpencil_layer_autolock_set(gpd, false);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
}
/* Grease Pencil updates */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index f73c8a5b71a..4c81df8b71d 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -56,6 +56,7 @@
#include "DNA_meta_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
+#include "DNA_object_force_types.h"
#include "DNA_particle_types.h"
#include "DNA_space_types.h"
#include "DNA_sequence_types.h"
@@ -2433,8 +2434,9 @@ static size_t animdata_filter_ds_particles(
ListBase tmp_data = {NULL, NULL};
size_t tmp_items = 0;
- /* if no material returned, skip - so that we don't get weird blank entries... */
- if (ELEM(NULL, psys->part, psys->part->adt)) {
+ /* Note that when psys->part->adt is NULL the textures can still be
+ * animated. */
+ if (psys->part == NULL) {
continue;
}
@@ -2732,6 +2734,12 @@ static size_t animdata_filter_dopesheet_ob(
tmp_items += animdata_filter_ds_obanim(ac, &tmp_data, ads, ob, filter_mode);
}
+ /* particle deflector textures */
+ if (ob->pd != NULL && ob->pd->tex != NULL && !(ads->filterflag & ADS_FILTER_NOTEX)) {
+ tmp_items += animdata_filter_ds_texture(
+ ac, &tmp_data, ads, ob->pd->tex, &ob->id, filter_mode);
+ }
+
/* shape-key */
if ((key && key->adt) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
tmp_items += animdata_filter_ds_keyanim(ac, &tmp_data, ads, ob, key, filter_mode);
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 36583ecf060..e0d72ab5198 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -228,6 +228,47 @@ void ED_markers_get_minmax(ListBase *markers, short sel, float *first, float *la
*last = max;
}
+/**
+ * Function used in operator polls, checks whether the markers region is currently drawn in the
+ * editor in which the operator is called.
+ */
+static bool ED_operator_markers_region_active(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ switch (sa->spacetype) {
+ case SPACE_ACTION: {
+ SpaceAction *saction = sa->spacedata.first;
+ if (saction->flag & SACTION_SHOW_MARKERS) {
+ return true;
+ }
+ break;
+ }
+ case SPACE_GRAPH: {
+ SpaceGraph *sipo = sa->spacedata.first;
+ if (sipo->mode != SIPO_MODE_DRIVERS && sipo->flag & SIPO_SHOW_MARKERS) {
+ return true;
+ }
+ break;
+ }
+ case SPACE_NLA: {
+ SpaceNla *snla = sa->spacedata.first;
+ if (snla->flag & SNLA_SHOW_MARKERS) {
+ return true;
+ }
+ break;
+ }
+ case SPACE_SEQ: {
+ SpaceSeq *seq = sa->spacedata.first;
+ if (seq->flag & SEQ_SHOW_MARKERS) {
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
static bool region_position_is_over_marker(View2D *v2d, ListBase *markers, float region_x)
{
if (markers == NULL || BLI_listbase_is_empty(markers)) {
@@ -409,7 +450,7 @@ static void draw_marker_name(const uiFontStyle *fstyle,
UI_fontstyle_draw_simple(fstyle, name_x, text_y, name, text_color);
}
-static void draw_marker_line(const float color[4], float x, float ymin, float ymax)
+static void draw_marker_line(const float color[4], int xpos, int ymin, int ymax)
{
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -426,8 +467,8 @@ static void draw_marker_line(const float color[4], float x, float ymin, float ym
immUniform1f("dash_factor", 0.5f);
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, x, ymin);
- immVertex2f(pos, x, ymax);
+ immVertex2f(pos, xpos, ymin);
+ immVertex2f(pos, xpos, ymax);
immEnd();
immUnbindProgram();
@@ -449,26 +490,6 @@ static int marker_get_icon_id(TimeMarker *marker, int flag)
}
}
-static void draw_marker_line_if_necessary(TimeMarker *marker, int flag, int xpos, int height)
-{
-#ifdef DURIAN_CAMERA_SWITCH
- if ((marker->camera) || (flag & DRAW_MARKERS_LINES))
-#else
- if (flag & DRAW_MARKERS_LINES)
-#endif
- {
- float color[4];
- if (marker->flag & SELECT) {
- copy_v4_fl4(color, 1.0f, 1.0f, 1.0f, 0.38f);
- }
- else {
- copy_v4_fl4(color, 0.0f, 0.0f, 0.0f, 0.38f);
- }
-
- draw_marker_line(color, xpos, UI_DPI_FAC * 20, height);
- }
-}
-
static void draw_marker(
const uiFontStyle *fstyle, TimeMarker *marker, int cfra, int xpos, int flag, int region_height)
{
@@ -476,7 +497,15 @@ static void draw_marker(
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- draw_marker_line_if_necessary(marker, flag, xpos, region_height);
+ float color[4];
+ if (marker->flag & SELECT) {
+ copy_v4_fl4(color, 1.0f, 1.0f, 1.0f, 0.38f);
+ }
+ else {
+ copy_v4_fl4(color, 0.0f, 0.0f, 0.0f, 0.38f);
+ }
+
+ draw_marker_line(color, xpos, UI_DPI_FAC * 20, region_height);
int icon_id = marker_get_icon_id(marker, flag);
UI_icon_draw(xpos - 0.55f * UI_DPI_ICON_SIZE, UI_DPI_FAC * 18, icon_id);
@@ -599,8 +628,7 @@ static bool ed_markers_poll_selected_markers(bContext *C)
{
ListBase *markers = ED_context_get_markers(C);
- /* first things first: markers can only exist in timeline views */
- if (ED_operator_animview_active(C) == 0) {
+ if (!ED_operator_markers_region_active(C)) {
return 0;
}
@@ -613,12 +641,7 @@ static bool ed_markers_poll_selected_no_locked_markers(bContext *C)
ListBase *markers = ED_context_get_markers(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- if (ts->lock_markers) {
- return 0;
- }
-
- /* first things first: markers can only exist in timeline views */
- if (ED_operator_animview_active(C) == 0) {
+ if (ts->lock_markers || !ED_operator_markers_region_active(C)) {
return 0;
}
@@ -632,12 +655,7 @@ static bool ed_markers_poll_markers_exist(bContext *C)
ListBase *markers = ED_context_get_markers(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- if (ts->lock_markers) {
- return 0;
- }
-
- /* first things first: markers can only exist in timeline views */
- if (ED_operator_animview_active(C) == 0) {
+ if (ts->lock_markers || !ED_operator_markers_region_active(C)) {
return 0;
}
@@ -692,7 +710,7 @@ static void MARKER_OT_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = ed_marker_add_exec;
- ot->poll = ED_operator_animview_active;
+ ot->poll = ED_operator_markers_region_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -983,13 +1001,7 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *even
mm->evtx = event->x;
fac = ((float)(event->x - mm->firstx) * dx);
- apply_keyb_grid(event->shift,
- event->ctrl,
- &fac,
- 0.0,
- 1.0,
- 0.1,
- 0 /*was: U.flag & USER_AUTOGRABGRID*/);
+ apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
RNA_int_set(op->ptr, "frames", (int)fac);
ed_marker_move_apply(C, op);
@@ -1661,7 +1673,7 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot)
/* api callbacks */
ot->exec = ed_marker_camera_bind_exec;
- ot->poll = ED_operator_animview_active;
+ ot->poll = ED_operator_markers_region_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index ffae402989c..ed5cb65c42e 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -328,34 +328,135 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
/* ---------------- */
+/* Check if the keyframe interpolation type is supported */
+static bool prepare_for_decimate(FCurve *fcu, int i)
+{
+ switch (fcu->bezt[i].ipo) {
+ case BEZT_IPO_BEZ:
+ /* We do not need to do anything here as the keyframe already has the required setting.
+ */
+ return true;
+ case BEZT_IPO_LIN:
+ /* Convert to a linear bezt curve to be able to use the decimation algorithm. */
+ fcu->bezt[i].ipo = BEZT_IPO_BEZ;
+ fcu->bezt[i].h1 = HD_FREE;
+ fcu->bezt[i].h2 = HD_FREE;
+
+ if (i != 0) {
+ float h1[3];
+ sub_v3_v3v3(h1, fcu->bezt[i - 1].vec[1], fcu->bezt[i].vec[1]);
+ mul_v3_fl(h1, 1.0f / 3.0f);
+ add_v3_v3(h1, fcu->bezt[i].vec[1]);
+ copy_v3_v3(fcu->bezt[i].vec[0], h1);
+ }
+
+ if (i + 1 != fcu->totvert) {
+ float h2[3];
+ sub_v3_v3v3(h2, fcu->bezt[i + 1].vec[1], fcu->bezt[i].vec[1]);
+ mul_v3_fl(h2, 1.0f / 3.0f);
+ add_v3_v3(h2, fcu->bezt[i].vec[1]);
+ copy_v3_v3(fcu->bezt[i].vec[2], h2);
+ }
+ return true;
+ default:
+ /* These are unsupported. */
+ return false;
+ }
+}
+
+/* Decimate the given curve segment. */
+static void decimate_fcurve_segment(FCurve *fcu,
+ int bezt_segment_start_idx,
+ int bezt_segment_len,
+ float remove_ratio,
+ float error_sq_max)
+{
+ int selected_len = bezt_segment_len;
+
+ /* Make sure that we can remove the start/end point of the segment if they
+ * are not the start/end point of the curve. BKE_curve_decimate_bezt_array
+ * has a check that prevents removal of the first and last index in the
+ * passed array. */
+ if (bezt_segment_len + bezt_segment_start_idx != fcu->totvert &&
+ prepare_for_decimate(fcu, bezt_segment_len + bezt_segment_start_idx)) {
+ bezt_segment_len++;
+ }
+ if (bezt_segment_start_idx != 0 && prepare_for_decimate(fcu, bezt_segment_start_idx - 1)) {
+ bezt_segment_start_idx--;
+ bezt_segment_len++;
+ }
+
+ const int target_fcurve_verts = ceil(bezt_segment_len - selected_len * remove_ratio);
+
+ BKE_curve_decimate_bezt_array(&fcu->bezt[bezt_segment_start_idx],
+ bezt_segment_len,
+ 12, /* The actual resolution displayed in the viewport is dynamic
+ so we just pick a value that preserves the curve shape. */
+ false,
+ SELECT,
+ BEZT_FLAG_TEMP_TAG,
+ error_sq_max,
+ target_fcurve_verts);
+}
+
/**
* F-Curve 'decimate' function that removes a certain ratio of curve
* points that will affect the curves overall shape the least.
+ * If you want to remove based on a error margin, set remove_ratio to 1 and
+ * simply specify the desired error_sq_max. Otherwise, set the error margin to
+ * FLT_MAX.
*/
-void decimate_fcurve(bAnimListElem *ale, float remove_ratio)
+bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
{
FCurve *fcu = (FCurve *)ale->key_data;
/* Check if the curve actually has any points */
if (fcu == NULL || fcu->bezt == NULL || fcu->totvert == 0) {
- return;
+ return true;
}
- const int target_fcurve_verts = max_ii(2, fcu->totvert - fcu->totvert * remove_ratio);
-
BezTriple *old_bezts = fcu->bezt;
- if (target_fcurve_verts != fcu->totvert) {
- /* We don't want to limit the decimation to a certain error margin */
- const float error_sq_max = FLT_MAX;
- BKE_curve_decimate_bezt_array(fcu->bezt,
- fcu->totvert,
- 12, /* 12 is the resolution of graph editor curves */
- false,
- SELECT,
- BEZT_FLAG_TEMP_TAG,
- error_sq_max,
- target_fcurve_verts);
+ /* Only decimate the individual selected curve segments. */
+ int bezt_segment_start_idx = 0;
+ int bezt_segment_len = 0;
+
+ bool selected;
+ bool can_decimate_all_selected = true;
+ bool in_segment = false;
+
+ for (int i = 0; i < fcu->totvert; i++) {
+ selected = fcu->bezt[i].f2 & SELECT;
+ /* Make sure that the temp flag is unset as we use it to determine what to remove. */
+ fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
+
+ if (selected && !prepare_for_decimate(fcu, i)) {
+ /* This keyframe is not supported, treat them as if they were unselected. */
+ selected = false;
+ can_decimate_all_selected = false;
+ }
+
+ if (selected) {
+ if (!in_segment) {
+ bezt_segment_start_idx = i;
+ in_segment = true;
+ }
+ bezt_segment_len++;
+ }
+ else if (in_segment) {
+ /* If the curve point is not selected then we have reached the end of the selected curve
+ * segment. */
+ decimate_fcurve_segment(
+ fcu, bezt_segment_start_idx, bezt_segment_len, remove_ratio, error_sq_max);
+ in_segment = false;
+ bezt_segment_len = 0;
+ }
+ }
+
+ /* Did the segment run to the end of the curve? */
+ if (in_segment) {
+ decimate_fcurve_segment(
+ fcu, bezt_segment_start_idx, bezt_segment_len, remove_ratio, error_sq_max);
}
uint old_totvert = fcu->totvert;
@@ -372,6 +473,8 @@ void decimate_fcurve(bAnimListElem *ale, float remove_ratio)
if (old_bezts) {
MEM_freeN(old_bezts);
}
+
+ return can_decimate_all_selected;
}
/* ---------------- */
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 8a53883492e..7a14de2b240 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -51,6 +51,8 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "DEG_depsgraph.h"
+
#include "armature_intern.h"
/* *************** Adding stuff in editmode *************** */
@@ -214,6 +216,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
return OPERATOR_FINISHED;
}
@@ -609,6 +612,7 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
ED_armature_edit_validate_active(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_SELECT);
}
MEM_freeN(objects);
@@ -838,6 +842,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
ED_armature_edit_validate_active(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
}
MEM_freeN(objects);
@@ -1053,6 +1058,7 @@ static int armature_extrude_exec(bContext *C, wmOperator *op)
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_SELECT);
}
MEM_freeN(objects);
@@ -1126,6 +1132,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
return OPERATOR_FINISHED;
}
@@ -1215,6 +1222,7 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 64857dd1874..4ca0cd117b6 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -57,6 +57,8 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "DEG_depsgraph.h"
+
#include "armature_intern.h"
/* ************************** Object Tools Exports ******************************* */
@@ -443,6 +445,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
if (changed) {
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
}
@@ -512,6 +515,7 @@ static int armature_roll_clear_exec(bContext *C, wmOperator *op)
if (changed) {
/* Note, notifier might evolve. */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
}
MEM_freeN(objects);
@@ -844,6 +848,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
/* updates */
ED_armature_edit_refresh_layer_used(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
/* free points */
BLI_freelistN(&points);
@@ -1038,6 +1043,7 @@ static int armature_merge_exec(bContext *C, wmOperator *op)
ED_armature_edit_sync_selection(arm->edbo);
ED_armature_edit_refresh_layer_used(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
}
MEM_freeN(objects);
@@ -1182,6 +1188,7 @@ static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
MEM_freeN(objects);
@@ -1327,6 +1334,7 @@ static int armature_align_bones_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
return OPERATOR_FINISHED;
}
@@ -1370,6 +1378,7 @@ static int armature_split_exec(bContext *C, wmOperator *UNUSED(op))
}
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
MEM_freeN(objects);
@@ -1447,6 +1456,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
ED_armature_edit_refresh_layer_used(arm);
BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
}
MEM_freeN(objects);
@@ -1621,6 +1631,7 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
ED_armature_edit_sync_selection(arm->edbo);
ED_armature_edit_refresh_layer_used(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
}
MEM_freeN(objects);
@@ -1684,6 +1695,7 @@ static int armature_hide_exec(bContext *C, wmOperator *op)
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
MEM_freeN(objects);
return OPERATOR_FINISHED;
@@ -1736,6 +1748,7 @@ static int armature_reveal_exec(bContext *C, wmOperator *op)
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
}
MEM_freeN(objects);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index b3588404cf2..c2c7d7e5ee7 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -550,7 +550,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
* sel: remove selected bones from the armature, otherwise the unselected bones are removed
* (ob is not in editmode)
*/
-static void separate_armature_bones(Main *bmain, Object *ob, short sel)
+static void separate_armature_bones(Main *bmain, Object *ob, const bool is_select)
{
bArmature *arm = (bArmature *)ob->data;
bPoseChannel *pchan, *pchann;
@@ -565,12 +565,10 @@ static void separate_armature_bones(Main *bmain, Object *ob, short sel)
curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
/* check if bone needs to be removed */
- if ((sel && (curbone->flag & BONE_SELECTED)) || (!sel && !(curbone->flag & BONE_SELECTED))) {
- EditBone *ebo;
- bPoseChannel *pchn;
+ if (is_select == (EBONE_VISIBLE(arm, curbone) && (curbone->flag & BONE_SELECTED))) {
/* clear the bone->parent var of any bone that had this as its parent */
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
if (ebo->parent == curbone) {
ebo->parent = NULL;
/* this is needed to prevent random crashes with in ED_armature_from_edit */
@@ -580,7 +578,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, short sel)
}
/* clear the pchan->parent var of any pchan that had this as its parent */
- for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
+ for (bPoseChannel *pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
if (pchn->parent == pchan) {
pchn->parent = NULL;
}
@@ -603,6 +601,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, short sel)
}
/* exit editmode (recalculates pchans too) */
+ ED_armature_edit_deselect_all(ob);
ED_armature_from_edit(bmain, ob->data);
ED_armature_edit_free(ob->data);
}
@@ -622,17 +621,34 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
view_layer, CTX_wm_view3d(C), &bases_len);
- CTX_DATA_BEGIN (C, Base *, base, visible_bases) {
- ED_object_base_select(base, BA_DESELECT);
- }
- CTX_DATA_END;
-
for (uint base_index = 0; base_index < bases_len; base_index++) {
- Base *base_iter = bases[base_index];
- Object *obedit = base_iter->object;
-
- Object *oldob, *newob;
- Base *oldbase, *newbase;
+ Base *base_old = bases[base_index];
+ Object *ob_old = base_old->object;
+
+ {
+ bArmature *arm_old = ob_old->data;
+ bool has_selected_bone = false;
+ bool has_selected_any = false;
+ for (EditBone *ebone = arm_old->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm_old, ebone)) {
+ if (ebone->flag & BONE_SELECTED) {
+ has_selected_bone = true;
+ break;
+ }
+ else if (ebone->flag & (BONE_TIPSEL | BONE_ROOTSEL)) {
+ has_selected_any = true;
+ }
+ }
+ if (has_selected_bone == false) {
+ if (has_selected_any) {
+ /* Without this, we may leave head/tail selected
+ * which isn't expected after separating. */
+ ED_armature_edit_deselect_all(ob_old);
+ }
+ continue;
+ }
+ }
+ }
/* We are going to do this as follows (unlike every other instance of separate):
* 1. Exit editmode +posemode for active armature/base. Take note of what this is.
@@ -643,53 +659,43 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
* 5. Make original armature active and enter editmode
*/
- /* 1) only edit-base selected */
- ED_object_base_select(base_iter, BA_SELECT);
-
/* 1) store starting settings and exit editmode */
- oldob = obedit;
- oldbase = base_iter;
- oldob->mode &= ~OB_MODE_POSE;
- // oldbase->flag &= ~OB_POSEMODE;
+ ob_old->mode &= ~OB_MODE_POSE;
- ED_armature_from_edit(bmain, obedit->data);
- ED_armature_edit_free(obedit->data);
+ ED_armature_from_edit(bmain, ob_old->data);
+ ED_armature_edit_free(ob_old->data);
/* 2) duplicate base */
/* only duplicate linked armature */
- newbase = ED_object_add_duplicate(bmain, scene, view_layer, oldbase, USER_DUP_ARM);
+ Base *base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, USER_DUP_ARM);
+ Object *ob_new = base_new->object;
DEG_relations_tag_update(bmain);
- newob = newbase->object;
- newbase->flag &= ~BASE_SELECTED;
-
/* 3) remove bones that shouldn't still be around on both armatures */
- separate_armature_bones(bmain, oldob, 1);
- separate_armature_bones(bmain, newob, 0);
+ separate_armature_bones(bmain, ob_old, true);
+ separate_armature_bones(bmain, ob_new, false);
/* 4) fix links before depsgraph flushes */ // err... or after?
- separated_armature_fix_links(bmain, oldob, newob);
+ separated_armature_fix_links(bmain, ob_old, ob_new);
- DEG_id_tag_update(&oldob->id, ID_RECALC_GEOMETRY); /* this is the original one */
- DEG_id_tag_update(&newob->id, ID_RECALC_GEOMETRY); /* this is the separated one */
+ DEG_id_tag_update(&ob_old->id, ID_RECALC_GEOMETRY); /* this is the original one */
+ DEG_id_tag_update(&ob_new->id, ID_RECALC_GEOMETRY); /* this is the separated one */
/* 5) restore original conditions */
- obedit = oldob;
-
- ED_armature_to_edit(obedit->data);
+ ED_armature_to_edit(ob_old->data);
- ED_armature_edit_refresh_layer_used(obedit->data);
- BKE_armature_refresh_layer_used(newob->data);
+ ED_armature_edit_refresh_layer_used(ob_old->data);
+ BKE_armature_refresh_layer_used(ob_new->data);
/* parents tips remain selected when connected children are removed. */
- ED_armature_edit_deselect_all(obedit);
+ ED_armature_edit_deselect_all(ob_old);
ok = true;
/* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob_old);
}
MEM_freeN(bases);
@@ -879,6 +885,7 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_SELECT);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index c37f9ce126b..0f288c0d8b8 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -363,6 +363,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
return OPERATOR_FINISHED;
}
@@ -792,6 +793,7 @@ bool ED_armature_edit_select_pick(
}
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
return true;
}
@@ -1037,6 +1039,10 @@ static int armature_de_select_all_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
+ /* Tagging only one object to refresh drawing. */
+ Object *obedit = CTX_data_edit_object(C);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+
return OPERATOR_FINISHED;
}
@@ -1154,6 +1160,7 @@ static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = objects[ob_index];
armature_select_more_less(ob, true);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
MEM_freeN(objects);
@@ -1186,6 +1193,7 @@ static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = objects[ob_index];
armature_select_more_less(ob, false);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
MEM_freeN(objects);
@@ -1274,6 +1282,7 @@ static void select_similar_length(bContext *C, const float thresh)
if (changed) {
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
}
MEM_freeN(objects);
@@ -1323,6 +1332,8 @@ static void select_similar_direction(bContext *C, const float thresh)
if (changed) {
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
}
MEM_freeN(objects);
@@ -1352,6 +1363,7 @@ static void select_similar_layer(bContext *C)
if (changed) {
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
}
MEM_freeN(objects);
@@ -1393,6 +1405,7 @@ static void select_similar_prefix(bContext *C)
if (changed) {
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
}
MEM_freeN(objects);
@@ -1434,6 +1447,7 @@ static void select_similar_suffix(bContext *C)
if (changed) {
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
}
MEM_freeN(objects);
@@ -1461,6 +1475,7 @@ static void select_similar_data_pchan(bContext *C, const size_t bytes_size, cons
}
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_COPY_ON_WRITE);
}
static void is_ancestor(EditBone *bone, EditBone *ancestor)
@@ -1495,6 +1510,7 @@ static void select_similar_children(bContext *C)
}
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_COPY_ON_WRITE);
}
static void select_similar_children_immediate(bContext *C)
@@ -1510,6 +1526,7 @@ static void select_similar_children_immediate(bContext *C)
}
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_COPY_ON_WRITE);
}
static void select_similar_siblings(bContext *C)
@@ -1529,6 +1546,7 @@ static void select_similar_siblings(bContext *C)
}
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_COPY_ON_WRITE);
}
static int armature_select_similar_exec(bContext *C, wmOperator *op)
@@ -1682,6 +1700,7 @@ static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
return OPERATOR_FINISHED;
}
@@ -1769,6 +1788,7 @@ static int armature_select_mirror_exec(bContext *C, wmOperator *op)
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
MEM_freeN(objects);
@@ -1897,6 +1917,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
ED_outliner_select_sync_from_edit_bone_tag(C);
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_COPY_ON_WRITE);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 2b18fc15f63..451148ed936 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -232,11 +232,22 @@ EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[],
void ED_armature_ebone_to_mat3(EditBone *ebone, float mat[3][3])
{
- float delta[3];
+ float delta[3], roll;
/* Find the current bone matrix */
sub_v3_v3v3(delta, ebone->tail, ebone->head);
- vec_roll_to_mat3(delta, ebone->roll, mat);
+ roll = ebone->roll;
+ if (!normalize_v3(delta)) {
+ /* Use the orientation of the parent bone if any. */
+ const EditBone *ebone_parent = ebone->parent;
+ if (ebone_parent) {
+ sub_v3_v3v3(delta, ebone_parent->tail, ebone_parent->head);
+ normalize_v3(delta);
+ roll = ebone_parent->roll;
+ }
+ }
+
+ vec_roll_to_mat3_normalized(delta, roll, mat);
}
void ED_armature_ebone_to_mat4(EditBone *ebone, float mat[4][4])
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 55c9b661074..d366978ba2b 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -463,7 +463,7 @@ static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
- /* loop over all selected pchans
+ /* Loop over all selected pchan's.
*
* TODO, loop over children before parents if multiple bones
* at once are to be predictable*/
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index af2d92533c3..e7803fdaafb 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -908,7 +908,7 @@ static bool curve_is_animated(Curve *cu)
static void fcurve_path_rename(AnimData *adt,
const char *orig_rna_path,
- char *rna_path,
+ const char *rna_path,
ListBase *orig_curves,
ListBase *curves)
{
@@ -922,11 +922,15 @@ static void fcurve_path_rename(AnimData *adt,
nfcu = copy_fcurve(fcu);
spath = nfcu->rna_path;
nfcu->rna_path = BLI_sprintfN("%s%s", rna_path, suffix);
+
+ /* copy_fcurve() sets nfcu->grp to NULL. To maintain the groups, we need to keep the pointer.
+ * As a result, the group's 'channels' pointers will be wrong, which is fixed by calling
+ * `action_groups_reconstruct(action)` later, after all fcurves have been renamed. */
+ nfcu->grp = fcu->grp;
BLI_addtail(curves, nfcu);
if (fcu->grp) {
action_groups_remove_channel(adt->action, fcu);
- action_groups_add_channel(adt->action, fcu->grp, nfcu);
}
else if ((adt->action) && (&adt->action->curves == orig_curves)) {
BLI_remlink(&adt->action->curves, fcu);
@@ -1077,6 +1081,9 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
}
*orig_curves = curves;
+ if (adt != NULL) {
+ BKE_action_groups_reconstruct(adt->action);
+ }
}
/* return 0 if animation data wasn't changed, 1 otherwise */
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 92957c51c08..c9206e8df4a 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -1320,20 +1320,36 @@ static int change_spacing_exec(bContext *C, wmOperator *op)
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
int kern, delta = RNA_int_get(op->ptr, "delta");
+ int selstart, selend;
+ bool changed = false;
- kern = ef->textbufinfo[ef->pos - 1].kern;
- kern += delta;
- CLAMP(kern, -20, 20);
-
- if (ef->textbufinfo[ef->pos - 1].kern == kern) {
- return OPERATOR_CANCELLED;
+ const bool has_select = BKE_vfont_select_get(obedit, &selstart, &selend);
+ if (has_select) {
+ selstart -= 1;
+ }
+ else {
+ selstart = selend = ef->pos - 1;
}
+ selstart = max_ii(0, selstart);
- ef->textbufinfo[ef->pos - 1].kern = kern;
+ for (int i = selstart; i <= selend; i++) {
+ kern = ef->textbufinfo[i].kern + delta;
+ CLAMP(kern, -20, 20);
- text_update_edited(C, obedit, FO_EDIT);
+ if (ef->textbufinfo[i].kern != kern) {
+ ef->textbufinfo[i].kern = kern;
+ changed = true;
+ }
+ }
- return OPERATOR_FINISHED;
+ if (changed) {
+ text_update_edited(C, obedit, FO_EDIT);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void FONT_OT_change_spacing(wmOperatorType *ot)
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 680fe3a00e5..62bac643347 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -385,9 +385,8 @@ set(ICON_NAMES
mod_mask
mod_cloth
mod_explode
- mod_fluidsim
mod_multires
- mod_smoke
+ mod_fluid
mod_solidify
mod_screw
mod_vertex_weight
@@ -529,10 +528,6 @@ set(ICON_NAMES
axis_side
axis_front
axis_top
- ndof_dom
- ndof_turn
- ndof_fly
- ndof_trans
layer_used
layer_active
sortalpha
@@ -653,6 +648,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.inflate
brush.sculpt.layer
brush.sculpt.mask
+ brush.sculpt.multiplane_scrape
brush.sculpt.nudge
brush.sculpt.pinch
brush.sculpt.pose
@@ -662,6 +658,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.smooth
brush.sculpt.snake_hook
brush.sculpt.thumb
+ brush.sculpt.topology
brush.uv_sculpt.grab
brush.uv_sculpt.pinch
brush.uv_sculpt.relax
diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt
index 4fbe901c1ca..68a204c04a7 100644
--- a/source/blender/editors/gizmo_library/CMakeLists.txt
+++ b/source/blender/editors/gizmo_library/CMakeLists.txt
@@ -45,7 +45,6 @@ set(SRC
geometry/geom_arrow_gizmo.c
geometry/geom_cube_gizmo.c
geometry/geom_dial_gizmo.c
- gizmo_types/arrow2d_gizmo.c
gizmo_types/arrow3d_gizmo.c
gizmo_types/blank3d_gizmo.c
gizmo_types/button2d_gizmo.c
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
deleted file mode 100644
index 24571f67fdb..00000000000
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2016 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup edgizmolib
- *
- * \name 2D Arrow Gizmo
- *
- * \brief Simple arrow gizmo which is dragged into a certain direction.
- */
-
-#include "BLI_math.h"
-
-#include "DNA_windowmanager_types.h"
-
-#include "BKE_context.h"
-
-#include "GPU_immediate.h"
-#include "GPU_matrix.h"
-#include "GPU_state.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_types.h"
-
-#include "ED_screen.h"
-#include "ED_gizmo_library.h"
-
-/* own includes */
-#include "WM_api.h"
-
-#include "../gizmo_library_intern.h"
-
-static void arrow2d_draw_geom(wmGizmo *gz, const float matrix[4][4], const float color[4])
-{
- const float size = 0.11f;
- const float size_breadth = size / 2.0f;
- const float size_length = size * 1.7f;
- /* Subtract the length so the arrow fits in the hotspot. */
- const float arrow_length = RNA_float_get(gz->ptr, "length") - size_length;
- const float arrow_angle = RNA_float_get(gz->ptr, "angle");
-
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- GPU_matrix_push();
- GPU_matrix_mul(matrix);
- GPU_matrix_rotate_2d(RAD2DEGF(arrow_angle));
-
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- immUniformColor4fv(color);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, 0.0f, 0.0f);
- immVertex2f(pos, 0.0f, arrow_length);
- immEnd();
-
- immBegin(GPU_PRIM_TRIS, 3);
- immVertex2f(pos, size_breadth, arrow_length);
- immVertex2f(pos, -size_breadth, arrow_length);
- immVertex2f(pos, 0.0f, arrow_length + size_length);
- immEnd();
-
- immUnbindProgram();
-
- GPU_matrix_pop();
-}
-
-static void gizmo_arrow2d_draw(const bContext *UNUSED(C), wmGizmo *gz)
-{
- float color[4];
-
- float matrix_final[4][4];
-
- gizmo_color_get(gz, gz->state & WM_GIZMO_STATE_HIGHLIGHT, color);
-
- GPU_line_width(gz->line_width);
-
- WM_gizmo_calc_matrix_final(gz, matrix_final);
-
- GPU_blend(true);
- arrow2d_draw_geom(gz, matrix_final, color);
- GPU_blend(false);
-
- if (gz->interaction_data) {
- GizmoInteraction *inter = gz->interaction_data;
-
- GPU_blend(true);
- arrow2d_draw_geom(gz, inter->init_matrix_final, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f});
- GPU_blend(false);
- }
-}
-
-static void gizmo_arrow2d_setup(wmGizmo *gz)
-{
- gz->flag |= WM_GIZMO_DRAW_MODAL;
-}
-
-static int gizmo_arrow2d_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *UNUSED(event))
-{
- GizmoInteraction *inter = MEM_callocN(sizeof(GizmoInteraction), __func__);
-
- copy_m4_m4(inter->init_matrix_basis, gz->matrix_basis);
- WM_gizmo_calc_matrix_final(gz, inter->init_matrix_final);
-
- gz->interaction_data = inter;
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int gizmo_arrow2d_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
-{
- const float mval_fl[2] = {UNPACK2(mval)};
- const float arrow_length = RNA_float_get(gz->ptr, "length");
- const float arrow_angle = RNA_float_get(gz->ptr, "angle");
- const float line_len = arrow_length * gz->scale_final;
- float mval_local[2];
-
- copy_v2_v2(mval_local, mval_fl);
- sub_v2_v2(mval_local, gz->matrix_basis[3]);
-
- float line[2][2];
- line[0][0] = line[0][1] = line[1][0] = 0.0f;
- line[1][1] = line_len;
-
- /* rotate only if needed */
- if (arrow_angle != 0.0f) {
- float rot_point[2];
- copy_v2_v2(rot_point, line[1]);
- rotate_v2_v2fl(line[1], rot_point, arrow_angle);
- }
-
- /* arrow line intersection check */
- float isect_1[2], isect_2[2];
- const int isect = isect_line_sphere_v2(
- line[0], line[1], mval_local, GIZMO_HOTSPOT + gz->line_width * 0.5f, isect_1, isect_2);
-
- if (isect > 0) {
- float line_ext[2][2]; /* extended line for segment check including hotspot */
- copy_v2_v2(line_ext[0], line[0]);
- line_ext[1][0] = line[1][0] + GIZMO_HOTSPOT * ((line[1][0] - line[0][0]) / line_len);
- line_ext[1][1] = line[1][1] + GIZMO_HOTSPOT * ((line[1][1] - line[0][1]) / line_len);
-
- const float lambda_1 = line_point_factor_v2(isect_1, line_ext[0], line_ext[1]);
- if (isect == 1) {
- if (IN_RANGE_INCL(lambda_1, 0.0f, 1.0f)) {
- return 0;
- }
- }
- else {
- BLI_assert(isect == 2);
- const float lambda_2 = line_point_factor_v2(isect_2, line_ext[0], line_ext[1]);
- if (IN_RANGE_INCL(lambda_1, 0.0f, 1.0f) && IN_RANGE_INCL(lambda_2, 0.0f, 1.0f)) {
- return 0;
- }
- }
- }
-
- return -1;
-}
-
-/* -------------------------------------------------------------------- */
-/** \name 2D Arrow Gizmo API
- *
- * \{ */
-
-static void GIZMO_GT_arrow_2d(wmGizmoType *gzt)
-{
- /* identifiers */
- gzt->idname = "GIZMO_GT_arrow_2d";
-
- /* api callbacks */
- gzt->draw = gizmo_arrow2d_draw;
- gzt->setup = gizmo_arrow2d_setup;
- gzt->invoke = gizmo_arrow2d_invoke;
- gzt->test_select = gizmo_arrow2d_test_select;
-
- gzt->struct_size = sizeof(wmGizmo);
-
- /* rna */
- RNA_def_float(gzt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX);
- RNA_def_float_rotation(gzt->srna,
- "angle",
- 0,
- NULL,
- DEG2RADF(-360.0f),
- DEG2RADF(360.0f),
- "Roll",
- "",
- DEG2RADF(-360.0f),
- DEG2RADF(360.0f));
-}
-
-void ED_gizmotypes_arrow_2d(void)
-{
- WM_gizmotype_append(GIZMO_GT_arrow_2d);
-}
-
-/** \} */
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 6a28c626a81..22d4a8f2676 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -22,17 +22,18 @@
*
* \name Arrow Gizmo
*
- * 3D Gizmo
+ * 2D/3D Gizmo
*
* \brief Simple arrow gizmo which is dragged into a certain direction.
* The arrow head can have varying shapes, e.g. cone, box, etc.
*
* - `matrix[0]` is derived from Y and Z.
* - `matrix[1]` is 'up' for gizmo types that have an up.
- * - `matrix[2]` is the arrow direction (for all arrowes).
+ * - `matrix[2]` is the arrow direction (for all arrows).
*/
#include "BLI_math.h"
+#include "BLI_utildefines.h"
#include "DNA_view3d_types.h"
@@ -56,6 +57,8 @@
#include "ED_screen.h"
#include "ED_gizmo_library.h"
+#include "UI_interface.h"
+
/* own includes */
#include "../gizmo_geometry.h"
#include "../gizmo_library_intern.h"
@@ -214,6 +217,37 @@ static void gizmo_arrow_draw(const bContext *UNUSED(C), wmGizmo *gz)
}
/**
+ * Selection for 2D views.
+ */
+static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
+{
+ /* 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");
+
+ float matrix_final[4][4];
+ WM_gizmo_calc_matrix_final(gz, matrix_final);
+
+ /* Arrow in pixel space. */
+ float arrow_start[2] = {matrix_final[3][0], matrix_final[3][1]};
+ float arrow_end[2];
+ {
+ float co[3] = {0, 0, arrow_length};
+ mul_m4_v3(matrix_final, co);
+ copy_v2_v2(arrow_end, co);
+ }
+
+ const float mval_fl[2] = {UNPACK2(mval)};
+ const float arrow_stem_threshold_px = 5 * UI_DPI_FAC;
+ const float arrow_head_threshold_px = 10 * UI_DPI_FAC;
+ if (dist_squared_to_line_v2(mval_fl, arrow_start, arrow_end) < SQUARE(arrow_stem_threshold_px) ||
+ len_squared_v2v2(mval_fl, arrow_end) < SQUARE(arrow_head_threshold_px)) {
+ return 0;
+ }
+ return -1;
+}
+
+/**
* Calculate arrow offset independent from prop min value,
* meaning the range will not be offset by min value first.
*/
@@ -427,6 +461,7 @@ static void GIZMO_GT_arrow_3d(wmGizmoType *gzt)
/* api callbacks */
gzt->draw = gizmo_arrow_draw;
gzt->draw_select = gizmo_arrow_draw_select;
+ gzt->test_select = gizmo_arrow_test_select;
gzt->matrix_basis_get = gizmo_arrow_matrix_basis_get;
gzt->modal = gizmo_arrow_modal;
gzt->setup = gizmo_arrow_setup;
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 125adfb1ffb..ef3014eabc2 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -71,29 +71,45 @@ typedef struct ButtonGizmo2D {
/* -------------------------------------------------------------------- */
-static void button2d_geom_draw_backdrop(const wmGizmo *gz, const float color[4], const bool select)
+static void button2d_geom_draw_backdrop(const wmGizmo *gz,
+ const float color[4],
+ const float fill_alpha,
+ const bool select)
{
GPU_line_width(gz->line_width);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
-
- immUniformColor4fv(color);
-
/* TODO, other draw styles */
- if (color[3] == 1.0 && select == false) {
+ if (color[3] == 1.0 && fill_alpha == 1.0 && select == false) {
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
GPU_polygon_smooth(0);
imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
GPU_polygon_smooth(1);
+ immUnbindProgram();
}
else {
- imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
- }
+ /* Draw fill. */
+ if ((fill_alpha != 0.0f) || (select == true)) {
+ float fill_color[4] = {UNPACK3(color), fill_alpha * color[3]};
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(fill_color);
+ imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
+ immUnbindProgram();
+ }
- immUnbindProgram();
+ /* Draw outline. */
+ if ((fill_alpha != 1.0f) && (select == false)) {
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
+ GPU_line_width(gz->line_width);
+ imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
+ immUnbindProgram();
+ }
+ }
UNUSED_VARS(select);
}
@@ -167,14 +183,15 @@ static void button2d_draw_intern(const bContext *C,
if (select) {
BLI_assert(is_3d);
- button2d_geom_draw_backdrop(gz, color, select);
+ button2d_geom_draw_backdrop(gz, color, 1.0, select);
}
else {
GPU_blend(true);
if (draw_options & ED_GIZMO_BUTTON_SHOW_BACKDROP) {
- button2d_geom_draw_backdrop(gz, color, select);
+ const float fill_alpha = RNA_float_get(gz->ptr, "backdrop_fill_alpha");
+ button2d_geom_draw_backdrop(gz, color, fill_alpha, select);
}
if (button->shape_batch[0] != NULL) {
@@ -269,7 +286,7 @@ static int gizmo_button2d_test_select(bContext *C, wmGizmo *gz, const int mval[2
else {
copy_v2_v2(point_local, (float[2]){UNPACK2(mval)});
sub_v2_v2(point_local, gz->matrix_basis[3]);
- mul_v2_fl(point_local, 1.0f / (gz->scale_basis * UI_DPI_FAC));
+ mul_v2_fl(point_local, 1.0f / gz->scale_final);
}
/* The 'gz->scale_final' is already applied when projecting. */
if (len_squared_v2(point_local) < 1.0f) {
@@ -336,6 +353,16 @@ static void GIZMO_GT_button_2d(wmGizmoType *gzt)
/* Currently only used for cursor display. */
RNA_def_boolean(gzt->srna, "show_drag", true, "Show Drag", "");
+
+ RNA_def_float(gzt->srna,
+ "backdrop_fill_alpha",
+ 1.0f,
+ 0.0f,
+ 1.0,
+ "When below 1.0, draw the interior with a reduced alpha compared to the outline",
+ "",
+ 0.0f,
+ 1.0f);
}
void ED_gizmotypes_button_2d(void)
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
index ef4fd23b64d..2e4284d357a 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -56,7 +56,6 @@
/* own includes */
#include "../gizmo_library_intern.h"
-#define GIZMO_RESIZER_SIZE 10.0f
#define GIZMO_MARGIN_OFFSET_SCALE 1.5f
static bool gizmo_calc_rect_view_scale(const wmGizmo *gz, const float dims[2], float scale[2])
@@ -92,12 +91,7 @@ static bool gizmo_calc_rect_view_scale(const wmGizmo *gz, const float dims[2], f
static bool gizmo_calc_rect_view_margin(const wmGizmo *gz, const float dims[2], float margin[2])
{
float handle_size;
- if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- handle_size = 0.15f;
- }
- else {
- handle_size = GIZMO_RESIZER_SIZE;
- }
+ handle_size = 0.15f;
handle_size *= gz->scale_final;
float scale_xy[2];
if (!gizmo_calc_rect_view_scale(gz, dims, scale_xy)) {
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
index 723be3cfe6b..05b58903e04 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -91,13 +91,7 @@ static void gizmo_calc_rect_view_scale(const wmGizmo *gz, const float dims[3], f
static void gizmo_calc_rect_view_margin(const wmGizmo *gz, const float dims[3], float margin[3])
{
- float handle_size;
- if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- handle_size = 0.15f;
- }
- else {
- handle_size = GIZMO_RESIZER_SIZE;
- }
+ const float handle_size = 0.15f;
// XXX, the scale isn't taking offset into account, we need to calculate scale per handle!
// handle_size *= gz->scale_final;
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 80795b825b0..06e5f36637b 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -51,6 +51,7 @@
#include "BKE_context.h"
#include "BKE_brush.h"
#include "BKE_global.h"
+#include "BKE_material.h"
#include "BKE_paint.h"
#include "BKE_gpencil.h"
#include "BKE_image.h"
@@ -427,7 +428,9 @@ static void gp_draw_stroke_fill(bGPdata *gpd,
const float color[4])
{
BLI_assert(gps->totpoints >= 3);
- Material *ma = gpd->mat[gps->mat_nr];
+ const bool use_mat = (gpd->mat != NULL);
+
+ Material *ma = (use_mat) ? gpd->mat[gps->mat_nr] : BKE_material_gpencil_default_get();
MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
/* Calculate triangles cache for filling area (must be done only after changes) */
@@ -869,6 +872,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
short sthickness;
float ink[4];
const bool is_unique = (tgpw->gps != NULL);
+ const bool use_mat = (tgpw->gpd->mat != NULL);
GPU_program_point_size(true);
@@ -880,7 +884,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
continue;
}
/* check if the color is visible */
- Material *ma = tgpw->gpd->mat[gps->mat_nr];
+ Material *ma = (use_mat) ? tgpw->gpd->mat[gps->mat_nr] : BKE_material_gpencil_default_get();
MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
@@ -1159,6 +1163,9 @@ void ED_gp_draw_interpolation(const bContext *C, tGPDinterpolate *tgpi, const in
copy_v4_v4(tgpw.tintcolor, color);
tgpw.onion = true;
tgpw.custonion = true;
+ if (obact->totcol == 0) {
+ tgpw.gpd->mat = NULL;
+ }
gp_draw_strokes(&tgpw);
}
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 67ffc6adc9f..1331cc92d96 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -1797,6 +1797,11 @@ static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *op)
}
CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ /* Verify the strokes has something to change. */
+ if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
+ continue;
+ }
+
for (int i = 0; i < gps->totpoints; i++) {
dvert = &gps->dvert[i];
MDeformWeight *dw = defvert_find_index(dvert, def_nr);
@@ -1864,7 +1869,8 @@ static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op)
MDeformVert *dverta, *dvertb;
CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
- if (gps->dvert == NULL) {
+ /* Verify the strokes has something to change. */
+ if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
continue;
}
@@ -1959,6 +1965,11 @@ static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op)
}
CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ /* Verify the strokes has something to change. */
+ if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
+ continue;
+ }
+
/* look for max value */
float maxvalue = 0.0f;
for (int i = 0; i < gps->totpoints; i++) {
@@ -2027,10 +2038,11 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
}
CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
- /* verify the strokes has something to change */
- if (gps->totpoints == 0) {
+ /* Verify the strokes has something to change. */
+ if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
continue;
}
+
/* look for tot value */
float *tot_values = MEM_callocN(gps->totpoints * sizeof(float), __func__);
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 3ab11f8f3f7..a87db4543e4 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -770,6 +770,11 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* deselect original stroke, or else the originals get moved too
* (when using the copy + move macro)
*/
+ bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
gps->flag &= ~GP_STROKE_SELECT;
}
}
@@ -1610,6 +1615,8 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_blank_frame_add(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Insert Blank Frame";
ot->idname = "GPENCIL_OT_blank_frame_add";
@@ -1621,13 +1628,15 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot)
ot->exec = gp_blank_frame_add_exec;
ot->poll = gp_add_poll;
- /* properties */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna,
- "all_layers",
- false,
- "All Layers",
- "Create blank frame in all layers, not only active");
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna,
+ "all_layers",
+ false,
+ "All Layers",
+ "Create blank frame in all layers, not only active");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ******************* Delete Active Frame ************************ */
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 3c4d43b5f53..ec26006eb06 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -1052,8 +1052,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
/* free weights of removed points */
- if (gps_from->dvert != NULL) {
- BKE_defvert_array_free_elems(gps_from->dvert + gps_to->totpoints,
+ if (new_stroke->dvert != NULL) {
+ BKE_defvert_array_free_elems(new_stroke->dvert + gps_to->totpoints,
gps_from->totpoints - gps_to->totpoints);
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 91af444c28a..300d7d9e925 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -105,6 +105,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(
/* XXX: Should we reduce reliance on context.gpencil_data for these cases? */
case SPACE_PROPERTIES: /* properties */
case SPACE_INFO: /* header info (needed after workspaces merge) */
+ case SPACE_ACTION: /* Dopesheet header. */
{
if (ob && (ob->type == OB_GPENCIL)) {
/* GP Object */
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 48d256476e0..98e1e99116f 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -159,7 +159,7 @@ typedef struct FSMenuEntry {
char name[256]; /* FILE_MAXFILE */
short save;
short valid;
- short pad[2];
+ int icon;
} FSMenuEntry;
typedef enum FSMenuCategory {
@@ -197,4 +197,7 @@ void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path);
char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry);
void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name);
+int ED_fsmenu_entry_get_icon(struct FSMenuEntry *fsentry);
+void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, const int icon);
+
#endif /* __ED_FILESELECT_H__ */
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 4d8da1acb4b..e09f101af73 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -26,7 +26,6 @@
#define __ED_GIZMO_LIBRARY_H__
/* initialize gizmos */
-void ED_gizmotypes_arrow_2d(void);
void ED_gizmotypes_arrow_3d(void);
void ED_gizmotypes_button_2d(void);
void ED_gizmotypes_cage_2d(void);
@@ -92,11 +91,6 @@ void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, const float min, const fl
void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, const float range_fac);
/* -------------------------------------------------------------------- */
-/* 2D Arrow Gizmo */
-
-/* none */
-
-/* -------------------------------------------------------------------- */
/* Cage Gizmo */
enum {
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 69742af9f50..e6d8684a8b2 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -50,7 +50,7 @@ bool ED_space_image_color_sample(struct SpaceImage *sima,
struct ARegion *ar,
int mval[2],
float r_col[3]);
-struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock);
+struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile);
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock);
bool ED_space_image_has_buffer(struct SpaceImage *sima);
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index 8181cebfe3c..c347d75fa66 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -309,7 +309,7 @@ void clean_fcurve(struct bAnimContext *ac,
struct bAnimListElem *ale,
float thresh,
bool cleardefault);
-void decimate_fcurve(struct bAnimListElem *ale, float remove_ratio);
+bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max);
void smooth_fcurve(struct FCurve *fcu);
void sample_fcurve(struct FCurve *fcu);
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 5afb645d9e7..8ffae0f2b66 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -25,7 +25,6 @@
#define __ED_MBALL_H__
struct Base;
-struct MetaBall;
struct Object;
struct UndoType;
struct bContext;
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index fc7b0d8be8f..246dba57bb5 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -83,6 +83,7 @@ void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
void EDBM_mesh_free(struct BMEditMesh *em);
+void EDBM_mesh_load_ex(struct Main *bmain, struct Object *ob, bool free_data);
void EDBM_mesh_load(struct Main *bmain, struct Object *ob);
/* flushes based on the current select mode. if in vertex select mode,
@@ -108,7 +109,9 @@ void EDBM_update_generic(struct BMEditMesh *em,
const bool is_destructive);
struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
- const bool selected,
+ const struct Scene *scene,
+ const bool face_selected,
+ const bool uv_selected,
const bool use_winding,
const bool do_islands);
void BM_uv_element_map_free(struct UvElementMap *vmap);
@@ -141,9 +144,9 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
/* editmesh_automerge.c */
void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist);
void EDBM_automerge_and_split(struct Object *ob,
- bool split_edges,
- bool split_faces,
- bool update,
+ const bool split_edges,
+ const bool split_faces,
+ const bool update,
const char hflag,
const float dist);
@@ -236,6 +239,14 @@ void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); /* rename
bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len);
bool EDBM_mesh_deselect_all_multi(struct bContext *C);
+bool EDBM_selectmode_disable_multi_ex(struct Scene *scene,
+ struct Base **bases,
+ const uint bases_len,
+ const short selectmode_disable,
+ const short selectmode_fallback);
+bool EDBM_selectmode_disable_multi(struct bContext *C,
+ const short selectmode_disable,
+ const short selectmode_fallback);
/* editmesh_preselect_edgering.c */
struct EditMesh_PreSelEdgeRing;
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index a5f56689c95..d27eeb270ac 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -421,6 +421,16 @@ void ED_object_data_xform_by_mat4(struct XFormObjectData *xod, const float mat[4
void ED_object_data_xform_restore(struct XFormObjectData *xod);
void ED_object_data_xform_tag_update(struct XFormObjectData *xod);
+/* Container helper API. */
+struct XFormObjectData_Container;
+struct XFormObjectData_Container *ED_object_data_xform_container_create(void);
+void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xds);
+void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
+ struct Main *bmain,
+ struct Depsgraph *depsgraph);
+void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container *xds,
+ struct Object *ob);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index fec4beea809..e15e4c45c4a 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -36,15 +36,25 @@ void ED_keymap_paint(struct wmKeyConfig *keyconf);
/* paint_image.c */
void ED_imapaint_clear_partial_redraw(void);
-void ED_imapaint_dirty_region(
- struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old);
-void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
+void ED_imapaint_dirty_region(struct Image *ima,
+ struct ImBuf *ibuf,
+ int tile_number,
+ int x,
+ int y,
+ int w,
+ int h,
+ bool find_old);
+void ED_imapaint_bucket_fill(struct bContext *C,
+ float color[3],
+ struct wmOperator *op,
+ const int mouse[2]);
/* image_undo.c */
void ED_image_undo_push_begin(const char *name, int paint_mode);
void ED_image_undo_push_begin_with_image(const char *name,
struct Image *image,
- struct ImBuf *ibuf);
+ struct ImBuf *ibuf,
+ int tile_number);
void ED_image_undo_push_end(void);
void ED_image_undo_restore(struct UndoStep *us);
@@ -54,6 +64,7 @@ void ED_image_undosys_type(struct UndoType *ut);
void *ED_image_paint_tile_find(struct ListBase *undo_tiles,
struct Image *ima,
struct ImBuf *ibuf,
+ int tile_number,
int x_tile,
int y_tile,
unsigned short **r_mask,
@@ -62,6 +73,7 @@ void *ED_image_paint_tile_push(struct ListBase *undo_tiles,
struct Image *ima,
struct ImBuf *ibuf,
struct ImBuf **tmpibuf,
+ int tile_number,
int x_tile,
int y_tile,
unsigned short **r_mask,
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 4ca7c8f96ad..6a801fc9928 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -120,7 +120,7 @@ void ED_region_info_draw_multiline(ARegion *ar,
void ED_region_image_metadata_draw(
int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy);
void ED_region_image_metadata_panel_draw(struct ImBuf *ibuf, struct uiLayout *layout);
-void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy);
+void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy, float x0, float y0);
float ED_region_blend_alpha(struct ARegion *ar);
void ED_region_visible_rect_calc(struct ARegion *ar, struct rcti *rect);
const rcti *ED_region_visible_rect(ARegion *ar);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 0771f39f905..29bac9df93a 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -27,8 +27,6 @@
/* ******************* Registration Function ********************** */
struct Object;
-struct SnapObjectContext;
-struct SnapObjectParams;
struct bContext;
struct wmKeyConfig;
struct wmOperatorType;
@@ -107,7 +105,6 @@ bool calculateTransformCenter(struct bContext *C,
struct Object;
struct Scene;
-struct TransInfo;
struct wmGizmoGroup;
struct wmGizmoGroupType;
@@ -168,10 +165,28 @@ void VIEW3D_GGT_xform_shear(struct wmGizmoGroupType *gzgt);
/* *** transform_gizmo_extrude_3d.c *** */
void VIEW3D_GGT_xform_extrude(struct wmGizmoGroupType *gzgt);
-bool ED_widgetgroup_gizmo2d_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
-void ED_widgetgroup_gizmo2d_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_draw_prepare(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+/* Transform: Axis/Cage */
+bool ED_widgetgroup_gizmo2d_xform_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
+void ED_widgetgroup_gizmo2d_xform_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_xform_setup_no_cage(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_xform_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_xform_draw_prepare(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup);
+
+/* Resize: Axis */
+bool ED_widgetgroup_gizmo2d_resize_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
+void ED_widgetgroup_gizmo2d_resize_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_resize_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_resize_draw_prepare(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup);
+
+/* Rotate: Axis */
+bool ED_widgetgroup_gizmo2d_rotate_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
+void ED_widgetgroup_gizmo2d_rotate_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_rotate_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_rotate_draw_prepare(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup);
#define SNAP_INCREMENTAL_ANGLE DEG2RAD(5.0)
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 1856ad8454b..1f50770eef6 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -45,18 +45,22 @@ struct wmKeyConfig;
void ED_operatortypes_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
-bool ED_uvedit_minmax(
- struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]);
-bool ED_uvedit_center(Scene *scene, Image *ima, struct Object *obedit, float cent[2], char mode);
+bool ED_uvedit_minmax(const struct Scene *scene,
+ struct Image *ima,
+ struct Object *obedit,
+ float min[2],
+ float max[2]);
+bool ED_uvedit_center(
+ const struct Scene *scene, Image *ima, struct Object *obedit, float cent[2], char mode);
void ED_uvedit_select_all(struct BMesh *bm);
-bool ED_uvedit_minmax_multi(struct Scene *scene,
+bool ED_uvedit_minmax_multi(const struct Scene *scene,
struct Image *ima,
struct Object **objects_edit,
uint objects_len,
float r_min[2],
float r_max[2]);
-bool ED_uvedit_center_multi(Scene *scene,
+bool ED_uvedit_center_multi(const struct Scene *scene,
Image *ima,
struct Object **objects_edit,
uint objects_len,
@@ -92,70 +96,76 @@ bool uvedit_uv_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
const int cd_loop_uv_offset);
-bool uvedit_face_visible_nolocal(struct Scene *scene, struct BMFace *efa);
-bool uvedit_face_visible_test(struct Scene *scene,
+bool uvedit_face_visible_nolocal(const struct Scene *scene, struct BMFace *efa);
+bool uvedit_face_visible_test(const struct Scene *scene,
struct Object *obedit,
struct Image *ima,
struct BMFace *efa);
-bool uvedit_face_select_test(struct Scene *scene, struct BMFace *efa, const int cd_loop_uv_offset);
-bool uvedit_edge_select_test(struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset);
-bool uvedit_uv_select_test(struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset);
+bool uvedit_face_select_test(const struct Scene *scene,
+ struct BMFace *efa,
+ const int cd_loop_uv_offset);
+bool uvedit_edge_select_test(const struct Scene *scene,
+ struct BMLoop *l,
+ const int cd_loop_uv_offset);
+bool uvedit_uv_select_test(const struct Scene *scene,
+ struct BMLoop *l,
+ const int cd_loop_uv_offset);
/* uv face */
-bool uvedit_face_select_set(struct Scene *scene,
+bool uvedit_face_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
const bool select,
const bool do_history,
const int cd_loop_uv_offset);
-bool uvedit_face_select_enable(struct Scene *scene,
+bool uvedit_face_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
const bool do_history,
const int cd_loop_uv_offset);
-bool uvedit_face_select_disable(struct Scene *scene,
+bool uvedit_face_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
const int cd_loop_uv_offset);
/* uv edge */
void uvedit_edge_select_set(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const bool select,
const bool do_history,
const int cd_loop_uv_offset);
void uvedit_edge_select_enable(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const bool do_history,
const int cd_loop_uv_offset);
void uvedit_edge_select_disable(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const int cd_loop_uv_offset);
/* uv vert */
void uvedit_uv_select_set(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const bool select,
const bool do_history,
const int cd_loop_uv_offset);
void uvedit_uv_select_enable(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const bool do_history,
const int cd_loop_uv_offset);
void uvedit_uv_select_disable(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const int cd_loop_uv_offset);
-bool ED_uvedit_nearest_uv(struct Scene *scene,
+bool ED_uvedit_nearest_uv(const struct Scene *scene,
struct Object *obedit,
struct Image *ima,
const float co[2],
float *dist_sq,
float r_uv[2]);
-bool ED_uvedit_nearest_uv_multi(struct Scene *scene,
+bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
struct Image *ima,
struct Object **objects,
const uint objects_len,
@@ -164,20 +174,20 @@ bool ED_uvedit_nearest_uv_multi(struct Scene *scene,
float r_uv[2]);
void ED_uvedit_get_aspect(
- struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy);
+ const struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy);
/* uvedit_unwrap_ops.c */
void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit);
void ED_uvedit_live_unwrap_re_solve(void);
void ED_uvedit_live_unwrap_end(short cancel);
-void ED_uvedit_live_unwrap(struct Scene *scene, struct Object **objects, int objects_len);
-void ED_uvedit_add_simple_uvs(struct Main *bmain, struct Scene *scene, struct Object *ob);
+void ED_uvedit_live_unwrap(const struct Scene *scene, struct Object **objects, int objects_len);
+void ED_uvedit_add_simple_uvs(struct Main *bmain, const struct Scene *scene, struct Object *ob);
/* uvedit_draw.c */
void ED_image_draw_cursor(struct ARegion *ar, const float cursor[2]);
void ED_uvedit_draw_main(struct SpaceImage *sima,
- struct Scene *scene,
+ const struct Scene *scene,
struct ViewLayer *view_layer,
struct Object *obedit,
struct Object *obact,
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 7a31c92a29c..19db3b49778 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -610,7 +610,6 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph,
int sizey,
unsigned int flag,
int alpha_mode,
- int samples,
const char *viewname,
struct GPUOffScreen *ofs,
char err_out[256]);
@@ -624,7 +623,6 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Depsgraph *depsgraph,
unsigned int flag,
unsigned int draw_flags,
int alpha_mode,
- int samples,
const char *viewname,
struct GPUOffScreen *ofs,
char err_out[256]);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index c15f299bca8..44c734e264a 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -560,7 +560,7 @@ DEF_ICON_MODIFIER(MOD_CLOTH)
DEF_ICON_MODIFIER(MOD_EXPLODE)
DEF_ICON_MODIFIER(MOD_FLUIDSIM)
DEF_ICON_MODIFIER(MOD_MULTIRES)
-DEF_ICON_MODIFIER(MOD_SMOKE)
+DEF_ICON_MODIFIER(MOD_FLUID)
DEF_ICON_MODIFIER(MOD_SOLIDIFY)
DEF_ICON_MODIFIER(MOD_SCREW)
DEF_ICON_MODIFIER(MOD_VERTEX_WEIGHT)
@@ -739,10 +739,10 @@ DEF_ICON_BLANK(251)
DEF_ICON(AXIS_SIDE)
DEF_ICON(AXIS_FRONT)
DEF_ICON(AXIS_TOP)
-DEF_ICON(NDOF_DOM)
-DEF_ICON(NDOF_TURN)
-DEF_ICON(NDOF_FLY)
-DEF_ICON(NDOF_TRANS)
+DEF_ICON_BLANK(252)
+DEF_ICON_BLANK(252a)
+DEF_ICON_BLANK(252b)
+DEF_ICON_BLANK(252c)
DEF_ICON(LAYER_USED)
DEF_ICON(LAYER_ACTIVE)
/* available */
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 738a91c085d..bd8eed4e4aa 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -99,6 +99,8 @@ typedef enum ThemeColorID {
TH_EDGE_FACESEL,
TH_FACE,
TH_FACE_SELECT,
+ TH_FACE_BACK,
+ TH_FACE_FRONT,
TH_NORMAL,
TH_VNORMAL,
TH_LNORMAL,
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 0dbf3c710d6..e34f40d057d 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -220,6 +220,7 @@ bool UI_view2d_view_to_region_rcti_clip(struct View2D *v2d,
struct View2D *UI_view2d_fromcontext(const struct bContext *C);
struct View2D *UI_view2d_fromcontext_rwin(const struct bContext *C);
+void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_y);
void UI_view2d_scale_get(struct View2D *v2d, float *r_x, float *r_y);
float UI_view2d_scale_get_x(const struct View2D *v2d);
float UI_view2d_scale_get_y(const struct View2D *v2d);
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 499842a570b..31cbd2a3831 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -2019,7 +2019,7 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, const uiWidgetColors *wcol, cons
rctf line_range;
/* First curve point. */
- if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
+ if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
line_range.xmin = rect->xmin;
line_range.ymin = rect->ymin + zoomy * (cmp[0].y - offsy);
}
@@ -2028,7 +2028,7 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, const uiWidgetColors *wcol, cons
line_range.ymin = rect->ymin + zoomy * (cmp[0].y - offsy + cuma->ext_in[1]);
}
/* Last curve point. */
- if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
+ if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
line_range.xmax = rect->xmax;
line_range.ymax = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy);
}
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 0cf357c508b..2b5cf2ed6b9 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -39,7 +39,7 @@
#include "RNA_access.h"
-#include "BIF_gl.h"
+#include "GPU_glew.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 11106dd403f..05d5f03a363 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -294,6 +294,7 @@ typedef struct uiHandleButtonMulti {
typedef struct uiHandleButtonData {
wmWindowManager *wm;
wmWindow *window;
+ ScrArea *area;
ARegion *region;
bool interactive;
@@ -7721,7 +7722,8 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but)
if (!wm->drags.first) {
bool is_label = UI_but_has_tooltip_label(but);
double delay = is_label ? UI_TOOLTIP_DELAY_LABEL : UI_TOOLTIP_DELAY;
- WM_tooltip_timer_init_ex(C, data->window, data->region, ui_but_tooltip_init, delay);
+ WM_tooltip_timer_init_ex(
+ C, data->window, data->area, data->region, ui_but_tooltip_init, delay);
if (is_label) {
bScreen *sc = WM_window_get_active_screen(data->window);
if (sc->tool_tip) {
@@ -7927,6 +7929,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
data = MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData");
data->wm = CTX_wm_manager(C);
data->window = CTX_wm_window(C);
+ data->area = CTX_wm_area(C);
BLI_assert(ar != NULL);
data->region = ar;
@@ -8009,7 +8012,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
/* Show a label for this button. */
bScreen *sc = WM_window_get_active_screen(data->window);
if ((PIL_check_seconds_timer() - WM_tooltip_time_closed()) < 0.1) {
- WM_tooltip_immediate_init(C, CTX_wm_window(C), ar, ui_but_tooltip_init);
+ WM_tooltip_immediate_init(C, CTX_wm_window(C), data->area, ar, ui_but_tooltip_init);
if (sc->tool_tip) {
sc->tool_tip->pass = 1;
}
@@ -9498,7 +9501,8 @@ static int ui_handle_menu_event(bContext *C,
* To support we would need UI_RETURN_OUT_PARENT to be handled by
* top-level buttons, not just menus. Note that this isn't very important
* since it's easy to manually close these menus by clicking on them. */
- menu->menuretval = (level > 0) ? UI_RETURN_OUT_PARENT : UI_RETURN_OUT;
+ menu->menuretval = (level > 0 && is_parent_inside) ? UI_RETURN_OUT_PARENT :
+ UI_RETURN_OUT;
}
}
retval = WM_UI_HANDLER_BREAK;
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index ab5fdfd69e0..5f25316cf25 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -2153,6 +2153,9 @@ int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, const bool big
else if (RNA_struct_is_a(ptr->type, &RNA_TextureSlot)) {
id = RNA_pointer_get(ptr, "texture").data;
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_FileBrowserFSMenuEntry)) {
+ return RNA_int_get(ptr, "icon");
+ }
else if (RNA_struct_is_a(ptr->type, &RNA_DynamicPaintSurface)) {
DynamicPaintSurface *surface = ptr->data;
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 8af82864b03..cc677f8f7cb 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -707,6 +707,25 @@ static void UI_OT_override_remove_button(wmOperatorType *ot)
/** \name Copy To Selected Operator
* \{ */
+#define NOT_NULL(assignment) ((assignment) != NULL)
+#define NOT_RNA_NULL(assignment) ((assignment).data != NULL)
+
+static void ui_context_selected_bones_via_pose(bContext *C, ListBase *r_lb)
+{
+ ListBase lb;
+ lb = CTX_data_collection_get(C, "selected_pose_bones");
+
+ if (!BLI_listbase_is_empty(&lb)) {
+ CollectionPointerLink *link;
+ for (link = lb.first; link; link = link->next) {
+ bPoseChannel *pchan = link->ptr.data;
+ RNA_pointer_create(link->ptr.owner_id, &RNA_Bone, pchan->bone, &link->ptr);
+ }
+ }
+
+ *r_lb = lb;
+}
+
bool UI_context_copy_to_selected_list(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -717,6 +736,52 @@ bool UI_context_copy_to_selected_list(bContext *C,
*r_use_path_from_id = false;
*r_path = NULL;
+ /* PropertyGroup objects don't have a reference to the struct that actually owns
+ * them, so it is normally necessary to do a brute force search to find it. This
+ * handles the search for non-ID owners by using the 'active' reference as a hint
+ * to preserve efficiency. Only properties defined through RNA are handled, as
+ * custom properties cannot be assumed to be valid for all instances.
+ *
+ * Properties owned by the ID are handled by the 'if (ptr->owner_id)' case below.
+ */
+ if (!RNA_property_is_idprop(prop) && RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) {
+ PointerRNA owner_ptr;
+ char *idpath = NULL;
+
+ /* First, check the active PoseBone and PoseBone->Bone. */
+ if (NOT_RNA_NULL(
+ owner_ptr = CTX_data_pointer_get_type(C, "active_pose_bone", &RNA_PoseBone))) {
+ if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) {
+ *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
+ }
+ else {
+ bPoseChannel *pchan = owner_ptr.data;
+ RNA_pointer_create(owner_ptr.owner_id, &RNA_Bone, pchan->bone, &owner_ptr);
+
+ if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) {
+ ui_context_selected_bones_via_pose(C, r_lb);
+ }
+ }
+ }
+
+ if (idpath == NULL) {
+ /* Check the active EditBone if in edit mode. */
+ if (NOT_RNA_NULL(
+ owner_ptr = CTX_data_pointer_get_type_silent(C, "active_bone", &RNA_EditBone)) &&
+ NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
+ }
+
+ /* Add other simple cases here (Node, NodeSocket, Sequence, ViewLayer etc). */
+ }
+
+ if (idpath) {
+ *r_path = BLI_sprintfN("%s.%s", idpath, RNA_property_identifier(prop));
+ MEM_freeN(idpath);
+ return true;
+ }
+ }
+
if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) {
*r_lb = CTX_data_collection_get(C, "selected_editable_bones");
}
@@ -724,18 +789,7 @@ bool UI_context_copy_to_selected_list(bContext *C,
*r_lb = CTX_data_collection_get(C, "selected_pose_bones");
}
else if (RNA_struct_is_a(ptr->type, &RNA_Bone)) {
- ListBase lb;
- lb = CTX_data_collection_get(C, "selected_pose_bones");
-
- if (!BLI_listbase_is_empty(&lb)) {
- CollectionPointerLink *link;
- for (link = lb.first; link; link = link->next) {
- bPoseChannel *pchan = link->ptr.data;
- RNA_pointer_create(link->ptr.owner_id, &RNA_Bone, pchan->bone, &link->ptr);
- }
- }
-
- *r_lb = lb;
+ ui_context_selected_bones_via_pose(C, r_lb);
}
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
*r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
@@ -1654,7 +1708,7 @@ void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
}
-static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
uiBut *but = NULL;
@@ -1697,7 +1751,7 @@ static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
srgb_to_linearrgb_v3_v3(color, color);
}
- ED_imapaint_bucket_fill(C, color, op);
+ ED_imapaint_bucket_fill(C, color, op, event->mval);
}
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c
index 54bdbe0ec6e..fa471441cc9 100644
--- a/source/blender/editors/interface/interface_region_hud.c
+++ b/source/blender/editors/interface/interface_region_hud.c
@@ -265,6 +265,14 @@ static ARegion *hud_region_add(ScrArea *sa)
ar->overlap = true;
ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
+ if (ar_win) {
+ float x, y;
+
+ UI_view2d_scroller_size_get(&ar_win->v2d, &x, &y);
+ ar->runtime.offset_x = x;
+ ar->runtime.offset_y = y;
+ }
+
return ar;
}
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index 8cea80bac7f..f4407d59d7f 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -371,6 +371,28 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
RNA_string_get(but->opptr, "name", tool_id);
BLI_assert(tool_id[0] != '\0');
+ /* When false, we're in a different space type to the tool being set.
+ * Needed for setting the fallback tool from the properties space.
+ *
+ * If we drop the hard coded 3D-view in properties hack, we can remove this check. */
+ bool has_valid_context = true;
+ const char *has_valid_context_error = IFACE_("Unsupported context");
+ {
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa == NULL) {
+ has_valid_context = false;
+ }
+ else {
+ PropertyRNA *prop = RNA_struct_find_property(but->opptr, "space_type");
+ if (RNA_property_is_set(but->opptr, prop)) {
+ const int space_type_prop = RNA_property_enum_get(but->opptr, prop);
+ if (space_type_prop != sa->spacetype) {
+ has_valid_context = false;
+ }
+ }
+ }
+ }
+
/* We have a tool, now extract the info. */
uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
@@ -391,7 +413,11 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
tool_id);
char *expr_result = NULL;
bool is_error = false;
- if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) {
+
+ if (has_valid_context == false) {
+ expr_result = BLI_strdup(has_valid_context_error);
+ }
+ else if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) {
if (STREQ(expr_result, "")) {
MEM_freeN(expr_result);
expr_result = NULL;
@@ -444,7 +470,11 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
char *expr_result = NULL;
bool is_error = false;
- if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) {
+
+ if (has_valid_context == false) {
+ expr_result = BLI_strdup(has_valid_context_error);
+ }
+ else if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) {
if (STREQ(expr_result, ".")) {
MEM_freeN(expr_result);
expr_result = NULL;
@@ -473,7 +503,10 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
}
/* Shortcut. */
- if (is_label == false && ((but->block->flag & UI_BLOCK_SHOW_SHORTCUT_ALWAYS) == 0)) {
+ const bool show_shortcut = is_label == false &&
+ ((but->block->flag & UI_BLOCK_SHOW_SHORTCUT_ALWAYS) == 0);
+
+ if (show_shortcut) {
/* There are different kinds of shortcuts:
*
* - Direct access to the tool (as if the toolbar button is pressed).
@@ -541,7 +574,11 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
"'as_pointer', lambda: 0)()");
intptr_t expr_result = 0;
- if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) {
+
+ if (has_valid_context == false) {
+ shortcut = BLI_strdup(has_valid_context_error);
+ }
+ else if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) {
if (expr_result != 0) {
wmKeyMap *keymap = (wmKeyMap *)expr_result;
for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
@@ -576,6 +613,80 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
}
}
+ if (show_shortcut) {
+ /* Shortcut for Cycling
+ *
+ * As a second option, we may have a shortcut to cycle this tool group.
+ *
+ * Since some keymaps may use this for the primary means of binding keys,
+ * it's useful to show these too.
+ * Without this there is no way to know how to use a key to set the tool.
+ *
+ * This is a little involved since the shortcut may be bound to another tool in this group,
+ * instead of the current tool on display. */
+
+ char *expr_result = NULL;
+ size_t expr_result_len;
+
+ {
+ const char *expr_imports[] = {"bpy", "bl_ui", NULL};
+ char expr[256];
+ SNPRINTF(expr,
+ "'\\x00'.join("
+ "item.idname for item in bl_ui.space_toolsystem_common.item_group_from_id("
+ "bpy.context, "
+ "bpy.context.space_data.type, '%s', coerce=True) "
+ "if item is not None)",
+ tool_id);
+
+ if (has_valid_context == false) {
+ /* pass */
+ }
+ else if (BPY_execute_string_as_string_and_size(
+ C, expr_imports, expr, true, &expr_result, &expr_result_len)) {
+ /* pass. */
+ }
+ }
+
+ if (expr_result != NULL) {
+ PointerRNA op_props;
+ WM_operator_properties_create_ptr(&op_props, but->optype);
+ RNA_boolean_set(&op_props, "cycle", true);
+
+ char shortcut[128] = "";
+
+ const char *item_end = expr_result + expr_result_len;
+ const char *item_step = expr_result;
+
+ while (item_step < item_end) {
+ RNA_string_set(&op_props, "name", item_step);
+ if (WM_key_event_operator_string(C,
+ but->optype->idname,
+ WM_OP_INVOKE_REGION_WIN,
+ op_props.data,
+ true,
+ shortcut,
+ ARRAY_SIZE(shortcut))) {
+ break;
+ }
+ item_step += strlen(item_step) + 1;
+ }
+
+ WM_operator_properties_free(&op_props);
+ MEM_freeN(expr_result);
+
+ if (shortcut[0] != '\0') {
+ uiTooltipField *field = text_field_add(data,
+ &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = BLI_sprintfN(TIP_("Shortcut Cycle: %s"), shortcut);
+ }
+ }
+ }
+
/* Keymap */
/* This is too handy not to expose somehow, let's be sneaky for now. */
@@ -592,7 +703,11 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
tool_id);
intptr_t expr_result = 0;
- if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) {
+
+ if (has_valid_context == false) {
+ /* pass */
+ }
+ else if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) {
if (expr_result != 0) {
{
uiTooltipField *field = text_field_add(data,
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 956fd4514af..0880da91005 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -1819,11 +1819,13 @@ static int modifier_can_delete(ModifierData *md)
{
/* fluid particle modifier can't be deleted here */
if (md->type == eModifierType_ParticleSystem) {
- if (((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID) {
+ short particle_type = ((ParticleSystemModifierData *)md)->psys->part->type;
+ if (particle_type == PART_FLUID || particle_type == PART_FLUID_FLIP ||
+ particle_type == PART_FLUID_FOAM || particle_type == PART_FLUID_SPRAY ||
+ particle_type == PART_FLUID_BUBBLE || particle_type == PART_FLUID_TRACER) {
return 0;
}
}
-
return 1;
}
@@ -1836,7 +1838,7 @@ static int modifier_is_simulation(ModifierData *md)
eModifierType_Cloth,
eModifierType_Collision,
eModifierType_Fluidsim,
- eModifierType_Smoke,
+ eModifierType_Fluid,
eModifierType_Softbody,
eModifierType_Surface,
eModifierType_DynamicPaint)) {
@@ -2069,7 +2071,7 @@ static uiLayout *draw_modifier(uiLayout *layout,
eModifierType_Softbody,
eModifierType_ParticleSystem,
eModifierType_Cloth,
- eModifierType_Smoke)) {
+ eModifierType_Fluid)) {
uiItemO(row,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"),
ICON_NONE,
@@ -3992,11 +3994,11 @@ static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
BKE_curvemapping_changed(cumap, false);
break;
case UICURVE_FUNC_EXTEND_HOZ: /* extend horiz */
- cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
+ cumap->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
BKE_curvemapping_changed(cumap, false);
break;
case UICURVE_FUNC_EXTEND_EXP: /* extend extrapolate */
- cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
+ cumap->flag |= CUMA_EXTEND_EXTRAPOLATE;
BKE_curvemapping_changed(cumap, false);
break;
}
@@ -5011,7 +5013,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
0.0,
- TIP_("Set the point's handle type to sharp."));
+ TIP_("Set the point's handle type to sharp"));
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
@@ -5029,7 +5031,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
0.0,
- TIP_("Set the point's handle type to sharp."));
+ TIP_("Set the point's handle type to smooth"));
UI_but_funcN_set(bt, CurveProfile_buttons_setcurved, MEM_dupallocN(cb), profile);
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index f2027d491fb..d313310bfa1 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1609,7 +1609,7 @@ static void widget_draw_icon(
else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW))) {
UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme);
}
- else if (!UI_but_is_tool(but)) {
+ else if (!((but->icon != ICON_NONE) && UI_but_is_tool(but))) {
if (has_theme) {
alpha *= 0.8f;
}
@@ -2459,7 +2459,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
}
/* Icons on the left with optional text label on the right */
else if (but->flag & UI_HAS_ICON || show_menu_icon) {
- const bool is_tool = UI_but_is_tool(but);
+ const bool is_tool = ((but->icon != ICON_NONE) & UI_but_is_tool(but));
/* XXX add way to draw icons at a different size!
* Use small icons for popup. */
@@ -3495,6 +3495,50 @@ static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int round
widget_numbut_draw(wcol, rect, state, roundboxalign, false);
}
+static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+{
+ uiWidgetBase wtb;
+ float rad;
+
+ widget_init(&wtb);
+
+ rad = wcol->roundness * U.widget_unit;
+ round_box_edges(&wtb, roundboxalign, rect, rad);
+
+ /* decoration */
+ shape_preset_trias_from_rect_menu(&wtb.tria1, rect);
+ /* copy size and center to 2nd tria */
+ wtb.tria2 = wtb.tria1;
+
+ widgetbase_draw(&wtb, wcol);
+
+ /* text space, arrows are about 0.6 height of button */
+ rect->xmax -= (6 * BLI_rcti_size_y(rect)) / 10;
+}
+
+/**
+ * Draw menu buttons still with triangles when field is not embossed
+ */
+static void widget_menubut_embossn(uiBut *UNUSED(but),
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign))
+{
+ uiWidgetBase wtb;
+
+ widget_init(&wtb);
+ wtb.draw_inner = false;
+ wtb.draw_outline = false;
+
+ /* decoration */
+ shape_preset_trias_from_rect_menu(&wtb.tria1, rect);
+ /* copy size and center to 2nd tria */
+ wtb.tria2 = wtb.tria1;
+
+ widgetbase_draw(&wtb, wcol);
+}
+
/**
* Draw number buttons still with triangles when field is not embossed
*/
@@ -3931,6 +3975,10 @@ static void widget_icon_has_anim(
* triangles when field is not embossed */
widget_numbut_embossn(but, wcol, rect, state, roundboxalign);
}
+ else if (but->type == UI_BTYPE_MENU) {
+ /* Draw menu buttons still with down arrow. */
+ widget_menubut_embossn(but, wcol, rect, state, roundboxalign);
+ }
}
static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
@@ -3950,27 +3998,6 @@ static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roun
widgetbase_draw(&wtb, wcol);
}
-static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
-{
- uiWidgetBase wtb;
- float rad;
-
- widget_init(&wtb);
-
- rad = wcol->roundness * U.widget_unit;
- round_box_edges(&wtb, roundboxalign, rect, rad);
-
- /* decoration */
- shape_preset_trias_from_rect_menu(&wtb.tria1, rect);
- /* copy size and center to 2nd tria */
- wtb.tria2 = wtb.tria1;
-
- widgetbase_draw(&wtb, wcol);
-
- /* text space, arrows are about 0.6 height of button */
- rect->xmax -= (6 * BLI_rcti_size_y(rect)) / 10;
-}
-
static void widget_menuiconbut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
@@ -4626,7 +4653,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
case UI_BTYPE_BUT:
#ifdef USE_UI_TOOLBAR_HACK
- if (UI_but_is_tool(but)) {
+ if ((but->icon != ICON_NONE) && UI_but_is_tool(but)) {
wt = widget_type(UI_WTYPE_TOOLBAR_ITEM);
}
else {
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 99833e9200d..f8b4d85a212 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -401,6 +401,12 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_FACE_SELECT:
cp = ts->face_select;
break;
+ case TH_FACE_BACK:
+ cp = ts->face_back;
+ break;
+ case TH_FACE_FRONT:
+ cp = ts->face_front;
+ break;
case TH_FACE_DOT:
cp = ts->face_dot;
break;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index b1a060089ee..a3f84e7bdd0 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -174,12 +174,9 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr
* - if they overlap, they must not occupy the corners (which are reserved for other widgets)
*/
if (scroll) {
- const int scroll_width = (v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) ?
- V2D_SCROLL_HANDLE_WIDTH :
- V2D_SCROLL_WIDTH;
- const int scroll_height = (v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) ?
- V2D_SCROLL_HANDLE_HEIGHT :
- V2D_SCROLL_HEIGHT;
+ float scroll_width, scroll_height;
+
+ UI_view2d_scroller_size_get(v2d, &scroll_width, &scroll_height);
/* vertical scroller */
if (scroll & V2D_SCROLL_LEFT) {
@@ -1939,6 +1936,31 @@ View2D *UI_view2d_fromcontext_rwin(const bContext *C)
return &(region->v2d);
}
+/* Get scrollbar sizes of the current 2D view. The size will be zero if the view has its scrollbars
+ * disabled. */
+void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
+{
+ int scroll = view2d_scroll_mapped(v2d->scroll);
+
+ if (r_x) {
+ if (scroll & V2D_SCROLL_VERTICAL) {
+ *r_x = (scroll & V2D_SCROLL_VERTICAL_HANDLES) ? V2D_SCROLL_HANDLE_WIDTH : V2D_SCROLL_WIDTH;
+ }
+ else {
+ *r_x = 0;
+ }
+ }
+ if (r_y) {
+ if (scroll & V2D_SCROLL_HORIZONTAL) {
+ *r_y = (scroll & V2D_SCROLL_HORIZONTAL_HANDLES) ? V2D_SCROLL_HANDLE_HEIGHT :
+ V2D_SCROLL_HEIGHT;
+ }
+ else {
+ *r_y = 0;
+ }
+ }
+}
+
/**
* Calculate the scale per-axis of the drawing-area
*
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 5a35b251d0c..5afe348158f 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../../depsgraph
../../makesdna
../../makesrna
+ ../../usd
../../windowmanager
../../../../intern/guardedalloc
)
@@ -39,11 +40,13 @@ set(SRC
io_cache.c
io_collada.c
io_ops.c
+ io_usd.c
io_alembic.h
io_cache.h
io_collada.h
io_ops.h
+ io_usd.h
)
set(LIB
@@ -69,6 +72,13 @@ if(WITH_ALEMBIC)
endif()
endif()
+if(WITH_USD)
+ list(APPEND LIB
+ bf_usd
+ )
+ add_definitions(-DWITH_USD)
+endif()
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 573dfcde88a..7582ef3f41d 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -127,7 +127,7 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
.apply_subdiv = RNA_boolean_get(op->ptr, "apply_subdiv"),
.curves_as_mesh = RNA_boolean_get(op->ptr, "curves_as_mesh"),
.flatten_hierarchy = RNA_boolean_get(op->ptr, "flatten"),
- .visible_layers_only = RNA_boolean_get(op->ptr, "visible_layers_only"),
+ .visible_objects_only = RNA_boolean_get(op->ptr, "visible_objects_only"),
.renderable_only = RNA_boolean_get(op->ptr, "renderable_only"),
.face_sets = RNA_boolean_get(op->ptr, "face_sets"),
.use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"),
@@ -209,7 +209,7 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(row, imfptr, "renderable_only", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "visible_layers_only", 0, NULL, ICON_NONE);
+ uiItemR(row, imfptr, "visible_objects_only", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "flatten", 0, NULL, ICON_NONE);
@@ -392,10 +392,10 @@ void WM_OT_alembic_export(wmOperatorType *ot)
"Export only objects marked renderable in the outliner");
RNA_def_boolean(ot->srna,
- "visible_layers_only",
+ "visible_objects_only",
0,
- "Visible Layers Only",
- "Export only objects in visible layers");
+ "Visible Objects Only",
+ "Export only objects that are visible");
RNA_def_boolean(ot->srna,
"flatten",
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index e04fe4a20c0..acb511a414d 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -33,6 +33,10 @@
# include "io_alembic.h"
#endif
+#ifdef WITH_USD
+# include "io_usd.h"
+#endif
+
#include "io_cache.h"
void ED_operatortypes_io(void)
@@ -46,6 +50,9 @@ void ED_operatortypes_io(void)
WM_operatortype_append(WM_OT_alembic_import);
WM_operatortype_append(WM_OT_alembic_export);
#endif
+#ifdef WITH_USD
+ WM_operatortype_append(WM_OT_usd_export);
+#endif
WM_operatortype_append(CACHEFILE_OT_open);
WM_operatortype_append(CACHEFILE_OT_reload);
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
new file mode 100644
index 00000000000..2818b134509
--- /dev/null
+++ b/source/blender/editors/io/io_usd.c
@@ -0,0 +1,240 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#ifdef WITH_USD
+# include "DNA_space_types.h"
+
+# include "BKE_context.h"
+# include "BKE_main.h"
+# include "BKE_report.h"
+
+# include "BLI_path_util.h"
+# include "BLI_string.h"
+# include "BLI_utildefines.h"
+
+# include "MEM_guardedalloc.h"
+
+# include "RNA_access.h"
+# include "RNA_define.h"
+
+# include "UI_interface.h"
+# include "UI_resources.h"
+
+# include "WM_api.h"
+# include "WM_types.h"
+
+# include "DEG_depsgraph.h"
+
+# include "io_usd.h"
+# include "usd.h"
+
+const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = {
+ {DAG_EVAL_RENDER,
+ "RENDER",
+ 0,
+ "Render",
+ "Use Render settings for object visibility, modifier settings, etc"},
+ {DAG_EVAL_VIEWPORT,
+ "VIEWPORT",
+ 0,
+ "Viewport",
+ "Use Viewport settings for object visibility, modifier settings, etc"},
+ {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 };
+typedef struct eUSDOperatorOptions {
+ bool as_background_job;
+} eUSDOperatorOptions;
+
+static int wm_usd_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ eUSDOperatorOptions *options = MEM_callocN(sizeof(eUSDOperatorOptions), "eUSDOperatorOptions");
+ options->as_background_job = true;
+ op->customdata = options;
+
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+ const char *main_blendfile_path = BKE_main_blendfile_path(bmain);
+
+ if (main_blendfile_path[0] == '\0') {
+ BLI_strncpy(filepath, "untitled", sizeof(filepath));
+ }
+ else {
+ BLI_strncpy(filepath, main_blendfile_path, sizeof(filepath));
+ }
+
+ BLI_path_extension_replace(filepath, sizeof(filepath), ".usdc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_usd_export_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ eUSDOperatorOptions *options = (eUSDOperatorOptions *)op->customdata;
+ const bool as_background_job = (options != NULL && options->as_background_job);
+ MEM_SAFE_FREE(op->customdata);
+
+ const bool selected_objects_only = RNA_boolean_get(op->ptr, "selected_objects_only");
+ const bool visible_objects_only = RNA_boolean_get(op->ptr, "visible_objects_only");
+ const bool export_animation = RNA_boolean_get(op->ptr, "export_animation");
+ const bool export_hair = RNA_boolean_get(op->ptr, "export_hair");
+ const bool export_uvmaps = RNA_boolean_get(op->ptr, "export_uvmaps");
+ const bool export_normals = RNA_boolean_get(op->ptr, "export_normals");
+ const bool export_materials = RNA_boolean_get(op->ptr, "export_materials");
+ const bool use_instancing = RNA_boolean_get(op->ptr, "use_instancing");
+ const bool evaluation_mode = RNA_enum_get(op->ptr, "evaluation_mode");
+
+ struct USDExportParams params = {
+ export_animation,
+ export_hair,
+ export_uvmaps,
+ export_normals,
+ export_materials,
+ selected_objects_only,
+ visible_objects_only,
+ use_instancing,
+ evaluation_mode,
+ };
+
+ bool ok = USD_export(C, filename, &params, as_background_job);
+
+ return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+static void wm_usd_export_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ uiLayout *col;
+ struct PointerRNA *ptr = op->ptr;
+
+ uiLayoutSetPropSep(layout, true);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "selected_objects_only", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "visible_objects_only", 0, NULL, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "export_animation", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "export_hair", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "export_uvmaps", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "export_normals", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "export_materials", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_instancing", 0, NULL, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "evaluation_mode", 0, NULL, ICON_NONE);
+}
+
+void WM_OT_usd_export(struct wmOperatorType *ot)
+{
+ ot->name = "Export USD";
+ ot->description = "Export current scene in a USD archive";
+ ot->idname = "WM_OT_usd_export";
+
+ ot->invoke = wm_usd_export_invoke;
+ ot->exec = wm_usd_export_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_usd_export_draw;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_USD,
+ FILE_BLENDER,
+ FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_ALPHA);
+
+ RNA_def_boolean(ot->srna,
+ "selected_objects_only",
+ false,
+ "Only Export Selected Objects",
+ "Only selected objects are exported. Unselected parents of selected objects are "
+ "exported as empty transform");
+
+ RNA_def_boolean(ot->srna,
+ "visible_objects_only",
+ true,
+ "Only Export Visible Objects",
+ "Only visible objects are exported. Invisible parents of visible objects are "
+ "exported as empty transform");
+
+ RNA_def_boolean(ot->srna,
+ "export_animation",
+ false,
+ "Export Animation",
+ "When checked, the render frame range is exported. When false, only the current "
+ "frame is exported");
+ RNA_def_boolean(ot->srna,
+ "export_hair",
+ false,
+ "Export Hair",
+ "When checked, hair is exported as USD curves");
+ RNA_def_boolean(ot->srna,
+ "export_uvmaps",
+ true,
+ "Export UV Maps",
+ "When checked, all UV maps of exported meshes are included in the export");
+ RNA_def_boolean(ot->srna,
+ "export_normals",
+ true,
+ "Export Normals",
+ "When checked, normals of exported meshes are included in the export");
+ RNA_def_boolean(ot->srna,
+ "export_materials",
+ true,
+ "Export Materials",
+ "When checked, the viewport settings of materials are exported as USD preview "
+ "materials, and material assignments are exported as geometry subsets");
+
+ RNA_def_boolean(ot->srna,
+ "use_instancing",
+ false,
+ "Use Instancing (EXPERIMENTAL)",
+ "When true, dupli-objects are written as instances of the original in USD. "
+ "Experimental feature, not working perfectly");
+
+ RNA_def_enum(ot->srna,
+ "evaluation_mode",
+ rna_enum_usd_export_evaluation_mode_items,
+ DAG_EVAL_RENDER,
+ "Evaluation Mode",
+ "Determines visibility of objects and modifier settings");
+}
+
+#endif /* WITH_USD */
diff --git a/source/blender/editors/io/io_usd.h b/source/blender/editors/io/io_usd.h
new file mode 100644
index 00000000000..4738e1c348d
--- /dev/null
+++ b/source/blender/editors/io/io_usd.h
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+#ifndef __IO_USD_H__
+#define __IO_USD_H__
+
+/** \file
+ * \ingroup editor/io
+ */
+
+struct wmOperatorType;
+
+void WM_OT_usd_export(struct wmOperatorType *ot);
+
+#endif /* __IO_USD_H__ */
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index b7f506a8a41..5c9fb866df7 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -36,8 +36,6 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
-#include "BIF_gl.h"
-
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
diff --git a/source/blender/editors/mesh/editmesh_automerge.c b/source/blender/editors/mesh/editmesh_automerge.c
index fb8ee85f9db..55b52e01fc3 100644
--- a/source/blender/editors/mesh/editmesh_automerge.c
+++ b/source/blender/editors/mesh/editmesh_automerge.c
@@ -92,9 +92,9 @@ void EDBM_automerge(Object *obedit, bool update, const char hflag, const float d
* \{ */
void EDBM_automerge_and_split(Object *obedit,
- bool UNUSED(split_edges),
- bool split_faces,
- bool update,
+ const bool UNUSED(split_edges),
+ const bool split_faces,
+ const bool update,
const char hflag,
const float dist)
{
@@ -126,18 +126,54 @@ void EDBM_automerge_and_split(Object *obedit,
ok = BM_mesh_intersect_edges(bm, hflag, dist, ghash_targetmap);
if (ok) {
+ GHashIterator gh_iter;
+ BMVert **v_survivors, **v_iter;
+ uint v_survivors_len = 0;
+ if (split_faces) {
+ BMVert *v_src, *v_dst;
+ GHASH_ITER (gh_iter, ghash_targetmap) {
+ v_src = BLI_ghashIterator_getKey(&gh_iter);
+ v_dst = BLI_ghashIterator_getValue(&gh_iter);
+ BM_elem_flag_disable(v_src, BM_ELEM_TAG);
+ BM_elem_flag_disable(v_dst, BM_ELEM_TAG);
+ }
+
+ int v_survivors_len_max = BLI_ghash_len(ghash_targetmap);
+ GHASH_ITER (gh_iter, ghash_targetmap) {
+ v_src = BLI_ghashIterator_getKey(&gh_iter);
+ v_dst = BLI_ghashIterator_getValue(&gh_iter);
+ if (!BM_elem_flag_test(v_src, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(v_src, BM_ELEM_TAG);
+ }
+ if (BM_elem_flag_test(v_dst, BM_ELEM_TAG)) {
+ v_survivors_len_max--;
+ }
+ }
+
+ v_survivors = MEM_mallocN(sizeof(*v_survivors) * v_survivors_len_max, __func__);
+ v_iter = &v_survivors[0];
+ GHASH_ITER (gh_iter, ghash_targetmap) {
+ v_dst = BLI_ghashIterator_getValue(&gh_iter);
+ if (!BM_elem_flag_test(v_dst, BM_ELEM_TAG)) {
+ *v_iter = v_dst;
+ v_iter++;
+ v_survivors_len++;
+ }
+ }
+ }
+
BMO_op_exec(bm, &weldop);
BMEdge **edgenet = NULL;
int edgenet_alloc_len = 0;
if (split_faces) {
- GHashIterator gh_iter;
- GHASH_ITER (gh_iter, ghash_targetmap) {
- BMVert *v = BLI_ghashIterator_getValue(&gh_iter);
- // BLI_assert(BM_elem_flag_test(v, hflag) || hflag == BM_ELEM_TAG);
+ v_iter = &v_survivors[0];
+ for (int i = v_survivors_len; i--; v_iter++) {
BM_vert_weld_linked_wire_edges_into_linked_faces(
- bm, v, dist, &edgenet, &edgenet_alloc_len);
+ bm, *v_iter, dist, &edgenet, &edgenet_alloc_len);
}
+
+ MEM_freeN(v_survivors);
}
if (edgenet) {
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 1adbbe30286..4c4aa4214b2 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1460,7 +1460,8 @@ static bool point_is_visible(KnifeTool_OpData *kcd,
BMFace *f_hit;
/* If box clipping on, make sure p is not clipped */
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING && ED_view3d_clipping_test(kcd->vc.rv3d, p, true)) {
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) &&
+ ED_view3d_clipping_test(kcd->vc.rv3d, p, true)) {
return false;
}
@@ -1484,7 +1485,7 @@ static bool point_is_visible(KnifeTool_OpData *kcd,
dist = kcd->vc.v3d->clip_end * 2.0f;
}
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
float view_clip[2][3];
/* note: view_clip[0] should never get clipped */
copy_v3_v3(view_clip[0], p_ofs);
@@ -1935,7 +1936,7 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius
dis_sq = len_squared_v2v2(kfv->sco, sco);
if (dis_sq < radius_sq) {
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) {
c++;
}
@@ -2045,7 +2046,7 @@ static KnifeEdge *knife_find_closest_edge(
/* now we have 'lambda' calculated (in screen-space) */
knife_interp_v3_v3v3(kcd, test_cagep, kfe->v1->cageco, kfe->v2->cageco, lambda);
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
/* check we're in the view */
if (ED_view3d_clipping_test(kcd->vc.rv3d, test_cagep, true)) {
continue;
@@ -2152,7 +2153,7 @@ static KnifeVert *knife_find_closest_vert(
dis_sq = len_squared_v2v2(kfv->sco, sco);
if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) {
curv = kfv;
curdis_sq = dis_sq;
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index a709bd010aa..ebd1e62e596 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -22,7 +22,6 @@
*/
#include "DNA_curve_types.h"
-#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
@@ -143,21 +142,7 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
/* select only tagged faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
- if (ob->type == OB_MESH) {
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *embm = me->edit_mesh;
- if (embm) {
- /* not essential, but switch out of vertex mode since the
- * selected regions wont be nicely isolated after flushing.
- * note: call after de-select to avoid selection flushing.
- * note: do this on all participating meshes so this is in sync
- * e.g. for later selection picking, see T68852.*/
- EDBM_selectmode_disable(scene, embm, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
- }
- }
- }
- CTX_DATA_END;
+ EDBM_selectmode_disable_multi(C, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 7955ccc0977..40d57af97aa 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -2653,6 +2653,41 @@ bool EDBM_mesh_deselect_all_multi(struct bContext *C)
return changed_multi;
}
+bool EDBM_selectmode_disable_multi_ex(Scene *scene,
+ struct Base **bases,
+ const uint bases_len,
+ const short selectmode_disable,
+ const short selectmode_fallback)
+{
+ bool changed_multi = false;
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *ob_iter = base_iter->object;
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+
+ EDBM_selectmode_disable(scene, em_iter, selectmode_disable, selectmode_fallback);
+ changed_multi = true;
+ }
+ return changed_multi;
+}
+
+bool EDBM_selectmode_disable_multi(struct bContext *C,
+ const short selectmode_disable,
+ const short selectmode_fallback)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ vc.view_layer, NULL, &bases_len);
+ bool changed_multi = EDBM_selectmode_disable_multi_ex(
+ scene, bases, bases_len, selectmode_disable, selectmode_fallback);
+ MEM_freeN(bases);
+ return changed_multi;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 8df392fb04b..abc0d258e55 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -2357,7 +2357,7 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->prop = RNA_def_float_factor(
- ot->srna, "factor", 0.5f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
+ ot->srna, "factor", 0.0f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
RNA_def_int(
ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100);
@@ -4197,7 +4197,12 @@ static bool mesh_separate_loose(
BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
if (clear_object_data) {
- BM_mesh_bm_to_me(NULL, bm_old, me_old, (&(struct BMeshToMeshParams){0}));
+ BM_mesh_bm_to_me(NULL,
+ bm_old,
+ me_old,
+ (&(struct BMeshToMeshParams){
+ .update_shapekey_indices = true,
+ }));
}
finally:
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 44984251243..d07ba05de20 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -521,6 +521,7 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key)
(&(struct BMeshToMeshParams){
/* Undo code should not be manipulating 'G_MAIN->object' hooks/vertex-parent. */
.calc_object_remap = false,
+ .update_shapekey_indices = false,
.cd_mask_extra = {.vmask = CD_MASK_SHAPE_KEYINDEX},
}));
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 522c2f32d27..67f8db71e54 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -51,6 +51,7 @@
#include "ED_mesh.h"
#include "ED_screen.h"
+#include "ED_uvedit.h"
#include "ED_view3d.h"
#include "mesh_intern.h" /* own include */
@@ -325,7 +326,7 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
* \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
* Most callers should run #DEG_id_tag_update on \a ob->data, see: T46738, T46913
*/
-void EDBM_mesh_load(Main *bmain, Object *ob)
+void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
{
Mesh *me = ob->data;
BMesh *bm = me->edit_mesh->bm;
@@ -341,6 +342,7 @@ void EDBM_mesh_load(Main *bmain, Object *ob)
me,
(&(struct BMeshToMeshParams){
.calc_object_remap = true,
+ .update_shapekey_indices = !free_data,
}));
/* Free derived mesh. usually this would happen through depsgraph but there
@@ -380,6 +382,11 @@ void EDBM_mesh_clear(BMEditMesh *em)
}
}
+void EDBM_mesh_load(Main *bmain, Object *ob)
+{
+ EDBM_mesh_load_ex(bmain, ob, true);
+}
+
/**
* Should only be called on the active editmesh, otherwise call #BKE_editmesh_free
*/
@@ -656,7 +663,9 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v)
/* A specialized vert map used by stitch operator */
UvElementMap *BM_uv_element_map_create(BMesh *bm,
- const bool selected,
+ const Scene *scene,
+ const bool face_selected,
+ const bool uv_selected,
const bool use_winding,
const bool do_islands)
{
@@ -683,8 +692,17 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
/* generate UvElement array */
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- totuv += efa->len;
+ 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++;
+ }
+ }
+ }
}
}
@@ -709,7 +727,7 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
winding[j] = false;
}
- if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
float(*tf_uv)[2] = NULL;
if (use_winding) {
@@ -717,6 +735,10 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
}
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;
+ }
+
buf->l = l;
buf->separate = 0;
buf->island = INVALID_ISLAND;
@@ -826,6 +848,10 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
efa = stack[--stacksize];
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+
UvElement *element, *initelement = element_map->vert[BM_elem_index_get(l->v)];
for (element = initelement; element; element = element->next) {
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 9e9cfe1beed..acecbc47c28 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -305,9 +305,12 @@ static void refresh_images(BakeImages *bake_images)
int i;
for (i = 0; i < bake_images->size; i++) {
Image *ima = bake_images->data[i].image;
- if (ima->ok == IMA_OK_LOADED) {
- GPU_free_image(ima);
- DEG_id_tag_update(&ima->id, 0);
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ if (tile->ok == IMA_OK_LOADED) {
+ GPU_free_image(ima);
+ DEG_id_tag_update(&ima->id, 0);
+ break;
+ }
}
}
}
diff --git a/source/blender/editors/object/object_data_transform.c b/source/blender/editors/object/object_data_transform.c
index 51d8fb8fd72..29b0cb88935 100644
--- a/source/blender/editors/object/object_data_transform.c
+++ b/source/blender/editors/object/object_data_transform.c
@@ -49,10 +49,12 @@
#include "BKE_mesh.h"
#include "BKE_armature.h"
#include "BKE_lattice.h"
+#include "BKE_scene.h"
#include "bmesh.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "WM_types.h"
@@ -575,3 +577,100 @@ void ED_object_data_xform_tag_update(struct XFormObjectData *xod_base)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Data Transform Container
+ *
+ * Use to implement 'Affect Only Origins' feature.
+ *
+ * \{ */
+
+struct XFormObjectData_Container {
+ GHash *obdata_in_obmode_map;
+};
+
+struct XFormObjectData_Extra {
+ Object *ob;
+ float obmat_orig[4][4];
+ struct XFormObjectData *xod;
+};
+
+void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container *xds, Object *ob)
+{
+ if (xds->obdata_in_obmode_map == NULL) {
+ xds->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
+ }
+
+ void **xf_p;
+ if (!BLI_ghash_ensure_p(xds->obdata_in_obmode_map, ob->data, &xf_p)) {
+ struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__);
+ copy_m4_m4(xf->obmat_orig, ob->obmat);
+ xf->ob = ob;
+ /* Result may be NULL, that's OK. */
+ xf->xod = ED_object_data_xform_create(ob->data);
+ *xf_p = xf;
+ }
+}
+
+/**
+ * This may be called multiple times with the same data.
+ * Each time, the original transformations are re-applied, instead of accumulating the changes.
+ */
+void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
+ struct Main *bmain,
+ Depsgraph *depsgraph)
+{
+ if (xds->obdata_in_obmode_map == NULL) {
+ return;
+ }
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, xds->obdata_in_obmode_map) {
+ ID *id = BLI_ghashIterator_getKey(&gh_iter);
+ struct XFormObjectData_Extra *xf = BLI_ghashIterator_getValue(&gh_iter);
+ if (xf->xod == NULL) {
+ continue;
+ }
+
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, xf->ob);
+ float imat[4][4], dmat[4][4];
+ invert_m4_m4(imat, xf->obmat_orig);
+ mul_m4_m4m4(dmat, imat, ob_eval->obmat);
+ invert_m4(dmat);
+
+ ED_object_data_xform_by_mat4(xf->xod, dmat);
+ if (xf->ob->type == OB_ARMATURE) {
+ /* TODO: none of the current flags properly update armatures, needs investigation. */
+ DEG_id_tag_update(id, 0);
+ }
+ else {
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ }
+ }
+}
+
+/** Callback for #GHash free. */
+static void trans_obdata_in_obmode_free_elem(void *xf_p)
+{
+ struct XFormObjectData_Extra *xf = xf_p;
+ if (xf->xod) {
+ ED_object_data_xform_destroy(xf->xod);
+ }
+ MEM_freeN(xf);
+}
+
+struct XFormObjectData_Container *ED_object_data_xform_container_create(void)
+{
+ struct XFormObjectData_Container *xds = MEM_callocN(sizeof(*xds), __func__);
+ xds->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
+ return xds;
+}
+
+void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xds)
+{
+ BLI_ghash_free(xds->obdata_in_obmode_map, NULL, trans_obdata_in_obmode_free_elem);
+ MEM_freeN(xds);
+}
+
+/** \} */
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index be815fb0d10..8012565ba2e 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -445,7 +445,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
return false;
}
- EDBM_mesh_load(bmain, obedit);
+ EDBM_mesh_load_ex(bmain, obedit, freedata);
if (freedata) {
EDBM_mesh_free(me->edit_mesh);
@@ -513,6 +513,9 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
ED_mball_editmball_free(obedit);
}
}
+ else {
+ return false;
+ }
char *needs_flush_ptr = BKE_object_data_editmode_flush_ptr_get(obedit->data);
if (needs_flush_ptr) {
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 41205bc8778..352ba744d92 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -129,7 +129,7 @@ void OBJECT_OT_hook_assign(struct wmOperatorType *ot);
void OBJECT_OT_hook_reset(struct wmOperatorType *ot);
void OBJECT_OT_hook_recenter(struct wmOperatorType *ot);
-/* object_group.c */
+/* object_collection.c */
void COLLECTION_OT_create(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove_all(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove(struct wmOperatorType *ot);
@@ -172,7 +172,7 @@ void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot);
void OBJECT_OT_laplaciandeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_surfacedeform_bind(struct wmOperatorType *ot);
-/* grease pencil modifiers */
+/* object_gpencil_modifiers.c */
void OBJECT_OT_gpencil_modifier_add(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_remove(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_move_up(struct wmOperatorType *ot);
@@ -180,7 +180,7 @@ void OBJECT_OT_gpencil_modifier_move_down(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_apply(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot);
-/* shader fx */
+/* object_shader_fx.c */
void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot);
void OBJECT_OT_shaderfx_remove(struct wmOperatorType *ot);
void OBJECT_OT_shaderfx_move_up(struct wmOperatorType *ot);
@@ -265,7 +265,7 @@ void OBJECT_OT_shape_key_retime(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_mirror(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_move(struct wmOperatorType *ot);
-/* object_group.c */
+/* object_collection.c */
void OBJECT_OT_collection_add(struct wmOperatorType *ot);
void OBJECT_OT_collection_link(struct wmOperatorType *ot);
void OBJECT_OT_collection_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_random.c b/source/blender/editors/object/object_random.c
index a130e3f3766..43aaecb887b 100644
--- a/source/blender/editors/object/object_random.c
+++ b/source/blender/editors/object/object_random.c
@@ -159,7 +159,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot)
/* props */
ot->prop = RNA_def_float_distance(
- ot->srna, "offset", 0.1f, -FLT_MAX, FLT_MAX, "Amount", "Distance to offset", -10.0f, 10.0f);
+ ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Amount", "Distance to offset", -10.0f, 10.0f);
RNA_def_float_factor(ot->srna,
"uniform",
0.0f,
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 826d1db2538..45b9c6306ac 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -72,6 +72,7 @@
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_gpencil.h"
+#include "ED_object.h"
#include "MEM_guardedalloc.h"
@@ -292,6 +293,8 @@ static int object_clear_transform_generic_exec(bContext *C,
void (*clear_func)(Object *, const bool),
const char default_ksName[])
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
KeyingSet *ks;
const bool clear_delta = RNA_boolean_get(op->ptr, "clear_delta");
@@ -304,6 +307,16 @@ static int object_clear_transform_generic_exec(bContext *C,
return OPERATOR_CANCELLED;
}
+ /* Support transforming the object data. */
+ const bool use_transform_data_origin = (scene->toolsettings->transform_flag &
+ SCE_XFORM_DATA_ORIGIN);
+ struct XFormObjectData_Container *xds = NULL;
+
+ if (use_transform_data_origin) {
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ xds = ED_object_data_xform_container_create();
+ }
+
/* get KeyingSet to use */
ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
@@ -311,18 +324,29 @@ static int object_clear_transform_generic_exec(bContext *C,
* (so that object-transform clearing won't be applied at same time as bone-clearing)
*/
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
- /* run provided clearing function */
- clear_func(ob, clear_delta);
-
- ED_autokeyframe_object(C, scene, ob, ks);
+ if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ continue;
+ }
- /* tag for updates */
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ if (use_transform_data_origin) {
+ ED_object_data_xform_container_item_ensure(xds, ob);
}
+
+ /* run provided clearing function */
+ clear_func(ob, clear_delta);
+
+ ED_autokeyframe_object(C, scene, ob, ks);
+
+ /* tag for updates */
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
}
CTX_DATA_END;
+ if (use_transform_data_origin) {
+ ED_object_data_xform_container_update_all(xds, bmain, depsgraph);
+ ED_object_data_xform_container_destroy(xds);
+ }
+
/* this is needed so children are also updated */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt
index 021c17a94c2..0998280c381 100644
--- a/source/blender/editors/physics/CMakeLists.txt
+++ b/source/blender/editors/physics/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
+ ../../../../intern/mantaflow/extern
)
set(INC_SYS
@@ -56,19 +57,10 @@ set(LIB
)
if(WITH_MOD_FLUID)
- list(APPEND INC
- ../../../../intern/elbeem/extern
- )
- list(APPEND LIB
- bf_intern_elbeem
- )
- add_definitions(-DWITH_MOD_FLUID)
-endif()
-
-if(WITH_MOD_SMOKE)
list(APPEND LIB
- bf_intern_smoke
+ bf_intern_mantaflow
)
+ add_definitions(-DWITH_FLUID)
endif()
if(WITH_INTERNATIONAL)
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index f16a372cb3c..9d3388bd220 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -5324,6 +5324,7 @@ static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op))
psys_reset(psys, PSYS_RESET_DEPSGRAPH);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
}
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index aee79523c87..e85b025e28e 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -262,6 +262,11 @@ static void particle_undosys_step_decode(struct bContext *C,
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit) {
undoptcache_to_editcache(&us->data, edit);
+ ParticleEditSettings *pset = &scene->toolsettings->particle;
+ if ((pset->flag & PE_DRAW_PART) != 0) {
+ psys_free_path_cache(NULL, edit);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ }
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
else {
diff --git a/source/blender/editors/physics/particle_edit_utildefines.h b/source/blender/editors/physics/particle_edit_utildefines.h
index da27420505f..dc858687341 100644
--- a/source/blender/editors/physics/particle_edit_utildefines.h
+++ b/source/blender/editors/physics/particle_edit_utildefines.h
@@ -21,8 +21,8 @@
* \ingroup edphys
*/
-#ifndef __PARTICLE_EDIT_UTILDEFNIES_H__
-#define __PARTICLE_EDIT_UTILDEFNIES_H__
+#ifndef __PARTICLE_EDIT_UTILDEFINES_H__
+#define __PARTICLE_EDIT_UTILDEFINES_H__
#define KEY_K \
PTCacheEditKey *key; \
@@ -59,4 +59,4 @@
#define KEY_WCO ((key->flag & PEK_USE_WCO) ? key->world_co : key->co)
-#endif /* __PARTICLE_EDIT_UTILDEFNIES_H__ */
+#endif /* __PARTICLE_EDIT_UTILDEFINES_H__ */
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index cfb3a400f47..4df74434c6a 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -1065,7 +1065,7 @@ static void remove_particle_systems_from_object(Object *ob_to)
if (ELEM(md->type,
eModifierType_ParticleSystem,
eModifierType_DynamicPaint,
- eModifierType_Smoke)) {
+ eModifierType_Fluid)) {
BLI_remlink(&ob_to->modifiers, md);
modifier_free(md);
}
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 44858e36fab..5414c2a44a2 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup edphys
+ * \ingroup edphys
*/
#include <math.h>
@@ -31,1219 +31,808 @@
/* types */
#include "DNA_action_types.h"
#include "DNA_object_types.h"
-#include "DNA_object_fluidsim_types.h"
+#include "BLI_blenlib.h"
+#include "BLI_path_util.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_fluidsim.h"
+#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_fluid.h"
+#include "BKE_global.h"
#include "DEG_depsgraph.h"
#include "ED_screen.h"
-#include "ED_object.h"
+#include "PIL_time.h"
#include "WM_types.h"
#include "WM_api.h"
#include "physics_intern.h" // own include
+#include "manta_fluid_API.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_fluid_types.h"
+#include "DNA_mesh_types.h"
+
+#define FLUID_JOB_BAKE_ALL "FLUID_OT_bake_all"
+#define FLUID_JOB_BAKE_DATA "FLUID_OT_bake_data"
+#define FLUID_JOB_BAKE_NOISE "FLUID_OT_bake_noise"
+#define FLUID_JOB_BAKE_MESH "FLUID_OT_bake_mesh"
+#define FLUID_JOB_BAKE_PARTICLES "FLUID_OT_bake_particles"
+#define FLUID_JOB_BAKE_GUIDES "FLUID_OT_bake_guides"
+#define FLUID_JOB_FREE_ALL "FLUID_OT_free_all"
+#define FLUID_JOB_FREE_DATA "FLUID_OT_free_data"
+#define FLUID_JOB_FREE_NOISE "FLUID_OT_free_noise"
+#define FLUID_JOB_FREE_MESH "FLUID_OT_free_mesh"
+#define FLUID_JOB_FREE_PARTICLES "FLUID_OT_free_particles"
+#define FLUID_JOB_FREE_GUIDES "FLUID_OT_free_guides"
+#define FLUID_JOB_BAKE_PAUSE "FLUID_OT_pause_bake"
+
+typedef struct FluidJob {
+ /* from wmJob */
+ void *owner;
+ short *stop, *do_update;
+ float *progress;
+ const char *type;
+ const char *name;
-/* enable/disable overall compilation */
-#ifdef WITH_MOD_FLUID
-
-# include "LBM_fluidsim.h"
-
-# include "BLI_blenlib.h"
-# include "BLI_path_util.h"
-# include "BLI_math.h"
+ struct Main *bmain;
+ Scene *scene;
+ Depsgraph *depsgraph;
+ Object *ob;
-# include "BKE_global.h"
-# include "BKE_main.h"
+ FluidModifierData *mmd;
-# include "WM_api.h"
+ int success;
+ double start;
-# include "DNA_scene_types.h"
-# include "DNA_mesh_types.h"
+ int *pause_frame;
+} FluidJob;
-static float get_fluid_viscosity(FluidsimSettings *settings)
+static inline bool fluid_is_bake_all(FluidJob *job)
{
- return (1.0f / powf(10.0f, settings->viscosityExponent)) * settings->viscosityValue;
+ return (STREQ(job->type, FLUID_JOB_BAKE_ALL));
}
-
-static float get_fluid_rate(FluidsimSettings *settings)
+static inline bool fluid_is_bake_data(FluidJob *job)
{
- float rate = 1.0f; /* default rate if not animated... */
-
- rate = settings->animRate;
-
- if (rate < 0.0f) {
- rate = 0.0f;
- }
-
- return rate;
+ return (STREQ(job->type, FLUID_JOB_BAKE_DATA));
}
-
-static void get_fluid_gravity(float *gravity, Scene *scene, FluidsimSettings *fss)
+static inline bool fluid_is_bake_noise(FluidJob *job)
{
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- }
- else {
- copy_v3_v3(gravity, fss->grav);
- }
+ return (STREQ(job->type, FLUID_JOB_BAKE_NOISE));
}
-
-static float get_fluid_size_m(Scene *scene, Object *domainob, FluidsimSettings *fss)
+static inline bool fluid_is_bake_mesh(FluidJob *job)
{
- if (!scene->unit.system) {
- return fss->realsize;
- }
- else {
- float dim[3];
- float longest_axis;
-
- BKE_object_dimensions_get(domainob, dim);
- longest_axis = max_fff(dim[0], dim[1], dim[2]);
-
- return longest_axis * scene->unit.scale_length;
- }
+ return (STREQ(job->type, FLUID_JOB_BAKE_MESH));
}
-
-static bool fluid_is_animated_mesh(FluidsimSettings *fss)
+static inline bool fluid_is_bake_particle(FluidJob *job)
{
- return ((fss->type == OB_FLUIDSIM_CONTROL) || fss->domainNovecgen);
+ return (STREQ(job->type, FLUID_JOB_BAKE_PARTICLES));
}
-
-/* ********************** fluid sim settings struct functions ********************** */
-
-# if 0
-/* helper function */
-void fluidsimGetGeometryObjFilename(Object *ob, char *dst) //, char *srcname)
+static inline bool fluid_is_bake_guiding(FluidJob *job)
{
- //BLI_snprintf(dst, FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name);
- BLI_snprintf(dst, FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name);
+ return (STREQ(job->type, FLUID_JOB_BAKE_GUIDES));
}
-# endif
-
-/* ********************** fluid sim channel helper functions ********************** */
-
-typedef struct FluidAnimChannels {
- int length;
-
- double aniFrameTime;
-
- float *timeAtFrame;
- float *DomainTime;
- float *DomainGravity;
- float *DomainViscosity;
-} FluidAnimChannels;
-
-typedef struct FluidObject {
- struct FluidObject *next, *prev;
-
- struct Object *object;
-
- float *Translation;
- float *Rotation;
- float *Scale;
- float *Active;
-
- float *InitialVelocity;
-
- float *AttractforceStrength;
- float *AttractforceRadius;
- float *VelocityforceStrength;
- float *VelocityforceRadius;
-
- float *VertexCache;
- int numVerts, numTris;
-} FluidObject;
-
-// no. of entries for the two channel sizes
-# define CHANNEL_FLOAT 1
-# define CHANNEL_VEC 3
-
-// simplify channels before printing
-// for API this is done anyway upon init
-# if 0
-static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char *str, int entries)
+static inline bool fluid_is_free_all(FluidJob *job)
{
- int i, j;
- int channelSize = paramsize;
-
- if (entries == 3) {
- elbeemSimplifyChannelVec3(channel, &channelSize);
- }
- else if (entries == 1) {
- elbeemSimplifyChannelFloat(channel, &channelSize);
- }
- else {
- /* invalid, cant happen? */
- }
-
- fprintf(file, " CHANNEL %s =\n", str);
- for (i = 0; i < channelSize; i++) {
- fprintf(file, " ");
- for (j = 0; j <= entries; j++) { // also print time value
- fprintf(file, " %f ", channel[i * (entries + 1) + j]);
- if (j == entries - 1) {
- fprintf(file, " ");
- }
- }
- fprintf(file, "\n");
- }
-
- fprintf(file, " ;\n");
+ return (STREQ(job->type, FLUID_JOB_FREE_ALL));
}
-# endif
-
-/* Note: fluid anim channel data layout
- * ------------------------------------
- * CHANNEL_FLOAT:
- * frame 1 |frame 2
- * [dataF][time][dataF][time]
- *
- * CHANNEL_VEC:
- * frame 1 |frame 2
- * [dataX][dataY][dataZ][time][dataX][dataY][dataZ][time]
- */
-
-static void init_time(FluidsimSettings *domainSettings, FluidAnimChannels *channels)
+static inline bool fluid_is_free_data(FluidJob *job)
{
- int i;
-
- channels->timeAtFrame = MEM_callocN((channels->length + 1) * sizeof(float),
- "timeAtFrame channel");
-
- channels->timeAtFrame[0] = channels->timeAtFrame[1] =
- domainSettings->animStart; // start at index 1
-
- for (i = 2; i <= channels->length; i++) {
- channels->timeAtFrame[i] = channels->timeAtFrame[i - 1] + (float)channels->aniFrameTime;
- }
+ return (STREQ(job->type, FLUID_JOB_FREE_DATA));
}
-
-/* if this is slow, can replace with faster, less readable code */
-static void set_channel(float *channel, float time, float *value, int i, int size)
+static inline bool fluid_is_free_noise(FluidJob *job)
{
- if (size == CHANNEL_FLOAT) {
- channel[(i * 2) + 0] = value[0];
- channel[(i * 2) + 1] = time;
- }
- else if (size == CHANNEL_VEC) {
- channel[(i * 4) + 0] = value[0];
- channel[(i * 4) + 1] = value[1];
- channel[(i * 4) + 2] = value[2];
- channel[(i * 4) + 3] = time;
- }
+ return (STREQ(job->type, FLUID_JOB_FREE_NOISE));
}
-
-static void set_vertex_channel(Depsgraph *depsgraph,
- float *channel,
- float time,
- struct Scene *scene,
- struct FluidObject *fobj,
- int i)
+static inline bool fluid_is_free_mesh(FluidJob *job)
{
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- float *verts;
- int *tris = NULL, numVerts = 0, numTris = 0;
- int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd);
- int framesize = (3 * fobj->numVerts) + 1;
- int j;
-
- if (channel == NULL) {
- return;
- }
+ return (STREQ(job->type, FLUID_JOB_FREE_MESH));
+}
+static inline bool fluid_is_free_particles(FluidJob *job)
+{
+ return (STREQ(job->type, FLUID_JOB_FREE_PARTICLES));
+}
+static inline bool fluid_is_free_guiding(FluidJob *job)
+{
+ return (STREQ(job->type, FLUID_JOB_FREE_GUIDES));
+}
- initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex);
+static bool fluid_initjob(
+ bContext *C, FluidJob *job, wmOperator *op, char *error_msg, int error_size)
+{
+ FluidModifierData *mmd = NULL;
+ FluidDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
- /* don't allow mesh to change number of verts in anim sequence */
- if (numVerts != fobj->numVerts) {
- MEM_freeN(channel);
- channel = NULL;
- return;
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ if (!mmd) {
+ BLI_strncpy(error_msg, N_("Bake failed: no Fluid modifier found"), error_size);
+ return false;
}
-
- /* fill frame of channel with vertex locations */
- for (j = 0; j < (3 * numVerts); j++) {
- channel[i * framesize + j] = verts[j];
+ mds = mmd->domain;
+ if (!mds) {
+ BLI_strncpy(error_msg, N_("Bake failed: invalid domain"), error_size);
+ return false;
}
- channel[i * framesize + framesize - 1] = time;
- MEM_freeN(verts);
- MEM_freeN(tris);
-}
+ job->bmain = CTX_data_main(C);
+ job->scene = CTX_data_scene(C);
+ job->depsgraph = CTX_data_depsgraph_pointer(C);
+ job->ob = CTX_data_active_object(C);
+ job->mmd = mmd;
+ job->type = op->type->idname;
+ job->name = op->type->name;
-static void free_domain_channels(FluidAnimChannels *channels)
-{
- if (!channels->timeAtFrame) {
- return;
- }
- MEM_freeN(channels->timeAtFrame);
- channels->timeAtFrame = NULL;
- MEM_freeN(channels->DomainGravity);
- channels->DomainGravity = NULL;
- MEM_freeN(channels->DomainViscosity);
- channels->DomainViscosity = NULL;
- MEM_freeN(channels->DomainTime);
- channels->DomainTime = NULL;
+ return true;
}
-static void free_all_fluidobject_channels(ListBase *fobjects)
+static bool fluid_initpaths(FluidJob *job, ReportList *reports)
{
- FluidObject *fobj;
-
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- if (fobj->Translation) {
- MEM_freeN(fobj->Translation);
- fobj->Translation = NULL;
- MEM_freeN(fobj->Rotation);
- fobj->Rotation = NULL;
- MEM_freeN(fobj->Scale);
- fobj->Scale = NULL;
- MEM_freeN(fobj->Active);
- fobj->Active = NULL;
- MEM_freeN(fobj->InitialVelocity);
- fobj->InitialVelocity = NULL;
- }
-
- if (fobj->AttractforceStrength) {
- MEM_freeN(fobj->AttractforceStrength);
- fobj->AttractforceStrength = NULL;
- MEM_freeN(fobj->AttractforceRadius);
- fobj->AttractforceRadius = NULL;
- MEM_freeN(fobj->VelocityforceStrength);
- fobj->VelocityforceStrength = NULL;
- MEM_freeN(fobj->VelocityforceRadius);
- fobj->VelocityforceRadius = NULL;
- }
+ FluidDomainSettings *mds = job->mmd->domain;
+ char temp_dir[FILE_MAX];
+ temp_dir[0] = '\0';
- if (fobj->VertexCache) {
- MEM_freeN(fobj->VertexCache);
- fobj->VertexCache = NULL;
- }
- }
-}
+ const char *relbase = modifier_path_relbase(job->bmain, job->ob);
-static void fluid_init_all_channels(bContext *C,
- Depsgraph *depsgraph,
- Object *UNUSED(fsDomain),
- FluidsimSettings *domainSettings,
- FluidAnimChannels *channels,
- ListBase *fobjects)
-{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base;
- int i;
- int length = channels->length;
- float eval_time;
-
- /* init time values (assuming that time moves at a constant speed; may be overridden later) */
- init_time(domainSettings, channels);
-
- /* allocate domain animation channels */
- channels->DomainGravity = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "channel DomainGravity");
- channels->DomainViscosity = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "channel DomainViscosity");
- channels->DomainTime = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "channel DomainTime");
-
- /* allocate fluid objects */
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
- Object *ob = base->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
-
- if (fluidmd) {
- FluidObject *fobj = MEM_callocN(sizeof(FluidObject), "Fluid Object");
- fobj->object = ob;
-
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- BLI_addtail(fobjects, fobj);
- continue;
- }
-
- fobj->Translation = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject Translation");
- fobj->Rotation = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject Rotation");
- fobj->Scale = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float), "fluidobject Scale");
- fobj->Active = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject Active");
- fobj->InitialVelocity = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject InitialVelocity");
-
- if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) {
- fobj->AttractforceStrength = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject AttractforceStrength");
- fobj->AttractforceRadius = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject AttractforceRadius");
- fobj->VelocityforceStrength = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject VelocityforceStrength");
- fobj->VelocityforceRadius = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject VelocityforceRadius");
- }
-
- if (fluid_is_animated_mesh(fluidmd->fss)) {
- float *verts = NULL;
- int *tris = NULL, modifierIndex = BLI_findindex(&ob->modifiers, (ModifierData *)fluidmd);
-
- initElbeemMesh(depsgraph,
- scene,
- ob,
- &fobj->numVerts,
- &verts,
- &fobj->numTris,
- &tris,
- 0,
- modifierIndex);
- fobj->VertexCache = MEM_callocN(length * ((fobj->numVerts * CHANNEL_VEC) + 1) *
- sizeof(float),
- "fluidobject VertexCache");
-
- MEM_freeN(verts);
- MEM_freeN(tris);
- }
-
- BLI_addtail(fobjects, fobj);
- }
+ /* We do not accept empty paths, they can end in random places silently, see T51176. */
+ if (mds->cache_directory[0] == '\0') {
+ modifier_path_init(
+ mds->cache_directory, sizeof(mds->cache_directory), FLUID_DOMAIN_DIR_DEFAULT);
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Fluid: Empty cache path, reset to default '%s'",
+ mds->cache_directory);
}
- /* now we loop over the frames and fill the allocated channels with data */
- for (i = 0; i < channels->length; i++) {
- FluidObject *fobj;
- float viscosity, gravity[3];
- float timeAtFrame, time;
+ BLI_strncpy(temp_dir, mds->cache_directory, FILE_MAXDIR);
+ BLI_path_abs(temp_dir, relbase);
- eval_time = domainSettings->bakeStart + i;
+ /* Ensure whole path exists */
+ const bool dir_exists = BLI_dir_create_recursive(temp_dir);
- /* Modifying the global scene isn't nice, but we can do it in
- * this part of the process before a threaded job is created */
- scene->r.cfra = (int)eval_time;
- ED_update_for_newframe(CTX_data_main(C), depsgraph);
+ /* We change path to some presumably valid default value, but do not allow bake process to
+ * continue, this gives user chance to set manually another path. */
+ if (!dir_exists) {
+ modifier_path_init(
+ mds->cache_directory, sizeof(mds->cache_directory), FLUID_DOMAIN_DIR_DEFAULT);
- /* now scene data should be current according to animation system, so we fill the channels */
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Fluid: Could not create cache directory '%s', reset to default '%s'",
+ temp_dir,
+ mds->cache_directory);
- /* Domain time */
- /* TODO: have option for not running sim, time mangling,
- * in which case second case comes in handy. */
- if (channels->DomainTime) {
- time = get_fluid_rate(domainSettings) * (float)channels->aniFrameTime;
- timeAtFrame = channels->timeAtFrame[i] + time;
+ BLI_strncpy(temp_dir, mds->cache_directory, FILE_MAXDIR);
+ BLI_path_abs(temp_dir, relbase);
- channels->timeAtFrame[i + 1] = timeAtFrame;
- set_channel(channels->DomainTime, i, &time, i, CHANNEL_FLOAT);
- }
- else {
- timeAtFrame = channels->timeAtFrame[i + 1];
+ /* Ensure whole path exists and is writable. */
+ if (!BLI_dir_create_recursive(temp_dir)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Fluid: Could not use default cache directory '%s', "
+ "please define a valid cache path manually",
+ temp_dir);
}
+ /* Copy final dir back into domain settings */
+ BLI_strncpy(mds->cache_directory, temp_dir, FILE_MAXDIR);
- /* Domain properties - gravity/viscosity */
- get_fluid_gravity(gravity, scene, domainSettings);
- set_channel(channels->DomainGravity, timeAtFrame, gravity, i, CHANNEL_VEC);
- viscosity = get_fluid_viscosity(domainSettings);
- set_channel(channels->DomainViscosity, timeAtFrame, &viscosity, i, CHANNEL_FLOAT);
-
- /* object movement */
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- float active = (float)((fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE) ? 1 : 0);
- float rot_d[3] = {0.f, 0.f, 0.f}, old_rot[3] = {0.f, 0.f, 0.f};
-
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- continue;
- }
-
- /* init euler rotation values and convert to elbeem format */
- /* get the rotation from ob->obmat rather than ob->rot to account for parent animations */
- if (i) {
- copy_v3_v3(old_rot, fobj->Rotation + 4 * (i - 1));
- mul_v3_fl(old_rot, (float)-M_PI / 180.f);
- }
-
- mat4_to_compatible_eulO(rot_d, old_rot, 0, ob->obmat);
- mul_v3_fl(rot_d, -180.0f / (float)M_PI);
-
- set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC);
- set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC);
- set_channel(fobj->Scale, timeAtFrame, ob->scale, i, CHANNEL_VEC);
- set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT);
- set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC);
-
- // printf("Active: %f, Frame: %f\n", active, timeAtFrame);
-
- if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) {
- set_channel(fobj->AttractforceStrength,
- timeAtFrame,
- &fluidmd->fss->attractforceStrength,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->AttractforceRadius,
- timeAtFrame,
- &fluidmd->fss->attractforceRadius,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->VelocityforceStrength,
- timeAtFrame,
- &fluidmd->fss->velocityforceStrength,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->VelocityforceRadius,
- timeAtFrame,
- &fluidmd->fss->velocityforceRadius,
- i,
- CHANNEL_FLOAT);
- }
-
- if (fluid_is_animated_mesh(fluidmd->fss)) {
- set_vertex_channel(depsgraph, fobj->VertexCache, timeAtFrame, scene, fobj, i);
- }
- }
+ return false;
}
+
+ /* Copy final dir back into domain settings */
+ BLI_strncpy(mds->cache_directory, temp_dir, FILE_MAXDIR);
+ return true;
}
-static void export_fluid_objects(Depsgraph *depsgraph,
- ListBase *fobjects,
- Scene *scene,
- int length)
+static void fluid_bake_free(void *customdata)
{
- FluidObject *fobj;
-
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd);
+ FluidJob *job = customdata;
+ MEM_freeN(job);
+}
- float *verts = NULL;
- int *tris = NULL;
- int numVerts = 0, numTris = 0;
- bool deform = fluid_is_animated_mesh(fluidmd->fss);
+static void fluid_bake_sequence(FluidJob *job)
+{
+ FluidDomainSettings *mds = job->mmd->domain;
+ Scene *scene = job->scene;
+ int frame = 1, orig_frame;
+ int frames;
+ int *pause_frame = NULL;
+ bool is_first_frame;
- elbeemMesh fsmesh;
+ frames = mds->cache_frame_end - mds->cache_frame_start + 1;
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- continue;
- }
+ if (frames <= 0) {
+ BLI_strncpy(mds->error, N_("No frames to bake"), sizeof(mds->error));
+ return;
+ }
- elbeemResetMesh(&fsmesh);
+ /* Show progress bar. */
+ if (job->do_update) {
+ *(job->do_update) = true;
+ }
- fsmesh.type = fluidmd->fss->type;
- fsmesh.name = ob->id.name;
+ /* Get current pause frame (pointer) - depending on bake type */
+ pause_frame = job->pause_frame;
- initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 0, modifierIndex);
+ /* Set frame to start point (depending on current pause frame value) */
+ is_first_frame = ((*pause_frame) == 0);
+ frame = is_first_frame ? mds->cache_frame_start : (*pause_frame);
- fsmesh.numVertices = numVerts;
- fsmesh.numTriangles = numTris;
- fsmesh.vertices = verts;
- fsmesh.triangles = tris;
+ /* Save orig frame and update scene frame */
+ orig_frame = CFRA;
+ CFRA = frame;
- fsmesh.channelSizeTranslation = fsmesh.channelSizeRotation = fsmesh.channelSizeScale =
- fsmesh.channelSizeInitialVel = fsmesh.channelSizeActive = length;
+ /* Loop through selected frames */
+ for (; frame <= mds->cache_frame_end; frame++) {
+ const float progress = (frame - mds->cache_frame_start) / (float)frames;
- fsmesh.channelTranslation = fobj->Translation;
- fsmesh.channelRotation = fobj->Rotation;
- fsmesh.channelScale = fobj->Scale;
- fsmesh.channelActive = fobj->Active;
+ /* Keep track of pause frame - needed to init future loop */
+ (*pause_frame) = frame;
- if (ELEM(fsmesh.type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) {
- fsmesh.channelInitialVel = fobj->InitialVelocity;
- fsmesh.localInivelCoords = ((fluidmd->fss->typeFlags & OB_FSINFLOW_LOCALCOORD) ? 1 : 0);
+ /* If user requested stop, quit baking */
+ if (G.is_break) {
+ job->success = 0;
+ return;
}
- if (fluidmd->fss->typeFlags & OB_FSBND_NOSLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- else if (fluidmd->fss->typeFlags & OB_FSBND_PARTSLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP;
+ /* Update progress bar */
+ if (job->do_update) {
+ *(job->do_update) = true;
}
- else if (fluidmd->fss->typeFlags & OB_FSBND_FREESLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP;
+ if (job->progress) {
+ *(job->progress) = progress;
}
- fsmesh.obstaclePartslip = fluidmd->fss->partSlipValue;
- fsmesh.volumeInitType = fluidmd->fss->volumeInitType;
- fsmesh.obstacleImpactFactor = fluidmd->fss->surfaceSmoothing; // misused value
-
- if (fsmesh.type == OB_FLUIDSIM_CONTROL) {
- fsmesh.cpsTimeStart = fluidmd->fss->cpsTimeStart;
- fsmesh.cpsTimeEnd = fluidmd->fss->cpsTimeEnd;
- fsmesh.cpsQuality = fluidmd->fss->cpsQuality;
- fsmesh.obstacleType = (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE);
+ CFRA = frame;
- fsmesh.channelSizeAttractforceRadius = fsmesh.channelSizeVelocityforceStrength =
- fsmesh.channelSizeVelocityforceRadius = fsmesh.channelSizeAttractforceStrength = length;
-
- fsmesh.channelAttractforceStrength = fobj->AttractforceStrength;
- fsmesh.channelAttractforceRadius = fobj->AttractforceRadius;
- fsmesh.channelVelocityforceStrength = fobj->VelocityforceStrength;
- fsmesh.channelVelocityforceRadius = fobj->VelocityforceRadius;
- }
- else {
- fsmesh.channelAttractforceStrength = fsmesh.channelAttractforceRadius =
- fsmesh.channelVelocityforceStrength = fsmesh.channelVelocityforceRadius = NULL;
- }
-
- /* animated meshes */
- if (deform) {
- fsmesh.channelSizeVertices = length;
- fsmesh.channelVertices = fobj->VertexCache;
-
- /* remove channels */
- fsmesh.channelTranslation = fsmesh.channelRotation = fsmesh.channelScale = NULL;
-
- /* Override user settings, only noslip is supported here! */
- if (fsmesh.type != OB_FLUIDSIM_CONTROL) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- }
+ /* Update animation system */
+ ED_update_for_newframe(job->bmain, job->depsgraph);
+ }
- elbeemAddMesh(&fsmesh);
+ /* Restore frame position that we were on before bake */
+ CFRA = orig_frame;
+}
- if (verts) {
- MEM_freeN(verts);
+static void fluid_bake_endjob(void *customdata)
+{
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
+
+ if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_NOISE;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_NOISE;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_NOISE;
+ }
+ if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_MESH;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_MESH;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_MESH;
+ }
+ if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_PARTICLES;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_PARTICLES;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES;
+ }
+ if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_GUIDE;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_GUIDE;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDE;
+ }
+ if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_DATA;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_DATA;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_DATA;
+ }
+ DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(G_MAIN->wm.first, false);
+
+ /* Bake was successful:
+ * Report for ended bake and how long it took */
+ if (job->success) {
+ /* Show bake info */
+ WM_reportf(
+ RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
+ }
+ else {
+ if (mds->error != NULL && mds->error[0] != '\0') {
+ WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
- if (tris) {
- MEM_freeN(tris);
+ else { /* User canceled the bake */
+ WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name);
}
}
}
-static int fluid_validate_scene(ReportList *reports, ViewLayer *view_layer, Object *fsDomain)
+static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
- Base *base;
- Object *newdomain = NULL;
- int channelObjCount = 0;
- int fluidInputCount = 0;
-
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
- Object *ob = base->object;
- FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
-
- /* only find objects with fluid modifiers */
- if (!fluidmdtmp || ob->type != OB_MESH) {
- continue;
- }
-
- if (fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) {
- /* if no initial domain object given, find another potential domain */
- if (!fsDomain) {
- newdomain = ob;
- }
- /* if there's more than one domain, cancel */
- else if (fsDomain && ob != fsDomain) {
- BKE_report(reports, RPT_ERROR, "There should be only one domain object");
- return 0;
- }
- }
-
- /* count number of objects needed for animation channels */
- if (!ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- channelObjCount++;
- }
-
- /* count number of fluid input objects */
- if (ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) {
- fluidInputCount++;
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
+
+ char temp_dir[FILE_MAX];
+
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
+ job->start = PIL_check_seconds_timer();
+ job->success = 1;
+
+ G.is_break = false;
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
+
+ if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_NOISE;
+ job->pause_frame = &mds->cache_frame_pause_noise;
+ }
+ if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_MESH;
+ job->pause_frame = &mds->cache_frame_pause_mesh;
+ }
+ if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
+ BLI_path_join(
+ temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_dir_create_recursive(
+ temp_dir); /* Create 'particles' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_PARTICLES | FLUID_DOMAIN_OUTDATED_PARTICLES);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_PARTICLES;
+ job->pause_frame = &mds->cache_frame_pause_particles;
+ }
+ if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_GUIDE;
+ job->pause_frame = &mds->cache_frame_pause_guide;
+ }
+ if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */
+
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_DATA;
+ job->pause_frame = &mds->cache_frame_pause_data;
+
+ if (mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) {
+ BLI_path_join(
+ temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */
}
}
+ DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
- if (newdomain) {
- fsDomain = newdomain;
- }
+ fluid_bake_sequence(job);
- if (!fsDomain) {
- BKE_report(reports, RPT_ERROR, "No domain object found");
- return 0;
+ if (do_update) {
+ *do_update = true;
}
-
- if (channelObjCount >= 255) {
- BKE_report(reports, RPT_ERROR, "Cannot bake with more than 256 objects");
- return 0;
+ if (stop) {
+ *stop = 0;
}
-
- if (fluidInputCount == 0) {
- BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene");
- return 0;
- }
-
- return 1;
}
-# define FLUID_SUFFIX_CONFIG "fluidsim.cfg"
-# define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp")
-# define FLUID_SUFFIX_SURFACE "fluidsurface"
-
-static bool fluid_init_filepaths(Main *bmain,
- ReportList *reports,
- FluidsimSettings *domainSettings,
- Object *fsDomain,
- char *targetDir,
- char *targetFile)
+static void fluid_free_endjob(void *customdata)
{
- const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
- /* prepare names... */
- const char *relbase = modifier_path_relbase(bmain, fsDomain);
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(G_MAIN->wm.first, false);
- /* We do not accept empty paths, they can end in random places silently, see T51176. */
- if (domainSettings->surfdataPath[0] == '\0') {
- modifier_path_init(domainSettings->surfdataPath,
- sizeof(domainSettings->surfdataPath),
- OB_FLUIDSIM_SURF_DIR_DEFAULT);
- BKE_reportf(reports,
- RPT_WARNING,
- "Fluidsim: empty cache path, reset to default '%s'",
- domainSettings->surfdataPath);
+ /* Free was successful:
+ * Report for ended free job and how long it took */
+ if (job->success) {
+ /* Show free job info */
+ WM_reportf(
+ RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
}
-
- BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, relbase);
-
- /* .tmp: don't overwrite/delete original file */
- BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
-
- /* Ensure whole path exists and is writeable. */
- const bool dir_exists = BLI_dir_create_recursive(targetDir);
- const bool is_writable = BLI_file_is_writable(targetFile);
-
- /* We change path to some presumably valid default value,
- * but do not allow bake process to continue,
- * this gives user chance to set manually another path. */
- if (!dir_exists || !is_writable) {
- modifier_path_init(domainSettings->surfdataPath,
- sizeof(domainSettings->surfdataPath),
- OB_FLUIDSIM_SURF_DIR_DEFAULT);
-
- if (!dir_exists) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: could not create cache directory '%s', reset to default '%s'",
- targetDir,
- domainSettings->surfdataPath);
+ else {
+ if (mds->error != NULL && mds->error[0] != '\0') {
+ WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
- else {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: cache directory '%s' is not writable, reset to default '%s'",
- targetDir,
- domainSettings->surfdataPath);
+ else { /* User canceled the free job */
+ WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name);
}
-
- BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, relbase);
-
- /* .tmp: don't overwrite/delete original file */
- BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
-
- /* Ensure whole path exists and is writeable. */
- if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: could not use default cache directory '%s', "
- "please define a valid cache path manually",
- targetDir);
- }
- return false;
}
-
- return true;
}
-/* ******************************************************************************** */
-/* ********************** write fluidsim config to file ************************* */
-/* ******************************************************************************** */
+static void fluid_free_startjob(void *customdata, short *stop, short *do_update, float *progress)
+{
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
+ Scene *scene = job->scene;
-typedef struct FluidBakeJob {
- /* from wmJob */
- void *owner;
- short *stop, *do_update;
- float *progress;
- int current_frame;
- elbeemSimulationSettings *settings;
-} FluidBakeJob;
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
+ job->start = PIL_check_seconds_timer();
+ job->success = 1;
-static void fluidbake_free(void *customdata)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
- MEM_freeN(fb);
-}
+ G.is_break = false;
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
-/* called by fluidbake, only to check job 'stop' value */
-static int fluidbake_breakjob(void *customdata)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
+ int cache_map = 0;
- if (fb->stop && *(fb->stop)) {
- return 1;
+ if (fluid_is_free_data(job) || fluid_is_free_all(job)) {
+ cache_map |= (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
+ FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES);
+ }
+ if (fluid_is_free_noise(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_NOISE;
+ }
+ if (fluid_is_free_mesh(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_MESH;
+ }
+ if (fluid_is_free_particles(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_PARTICLES;
+ }
+ if (fluid_is_free_guiding(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_GUIDE;
}
+#ifdef WITH_FLUID
+ BKE_fluid_cache_free(mds, job->ob, cache_map);
+#endif
- /* this is not nice yet, need to make the jobs list template better
- * for identifying/acting upon various different jobs */
- /* but for now we'll reuse the render break... */
- return (G.is_break);
-}
+ *do_update = true;
+ *stop = 0;
-/* called by fluidbake, wmJob sends notifier */
-static void fluidbake_updatejob(void *customdata, float progress)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
+ /* Reset scene frame to cache frame start */
+ CFRA = mds->cache_frame_start;
- *(fb->do_update) = true;
- *(fb->progress) = progress;
+ /* Update scene so that viewport shows freed up scene */
+ ED_update_for_newframe(job->bmain, job->depsgraph);
}
-static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
+/***************************** Operators ******************************/
- fb->stop = stop;
- fb->do_update = do_update;
- fb->progress = progress;
+static int fluid_bake_exec(struct bContext *C, struct wmOperator *op)
+{
+ FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
+ char error_msg[256] = "\0";
- G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
+ if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
+ }
+ fluid_bake_free(job);
+ return OPERATOR_CANCELLED;
+ }
+ if (!fluid_initpaths(job, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ fluid_bake_startjob(job, NULL, NULL, NULL);
+ fluid_bake_endjob(job);
+ fluid_bake_free(job);
- elbeemSimulate();
- *do_update = true;
- *stop = 0;
+ return OPERATOR_FINISHED;
}
-static void fluidbake_endjob(void *customdata)
+static int fluid_bake_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const wmEvent *UNUSED(_event))
{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
+ Scene *scene = CTX_data_scene(C);
+ FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
+ char error_msg[256] = "\0";
- if (fb->settings) {
- MEM_freeN(fb->settings);
- fb->settings = NULL;
+ if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
+ }
+ fluid_bake_free(job);
+ return OPERATOR_CANCELLED;
}
-}
-static int runSimulationCallback(void *data, int status, int frame)
-{
- FluidBakeJob *fb = (FluidBakeJob *)data;
- elbeemSimulationSettings *settings = fb->settings;
-
- if (status == FLUIDSIM_CBSTATUS_NEWFRAME) {
- fluidbake_updatejob(fb, frame / (float)settings->noOfFrames);
-# if 0
- printf("elbeem blender cb s%d, f%d, domainid:%d noOfFrames: %d\n",
- status,
- frame,
- settings->domainId,
- settings->noOfFrames); // DEBUG
-# endif
+ if (!fluid_initpaths(job, op->reports)) {
+ return OPERATOR_CANCELLED;
}
- if (fluidbake_breakjob(fb)) {
- return FLUIDSIM_CBRET_ABORT;
- }
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Fluid Bake",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_OBJECT_SIM_FLUID);
+
+ WM_jobs_customdata_set(wm_job, job, fluid_bake_free);
+ WM_jobs_timer(wm_job, 0.01, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
+ WM_jobs_callbacks(wm_job, fluid_bake_startjob, NULL, NULL, fluid_bake_endjob);
+
+ WM_set_locked_interface(CTX_wm_manager(C), true);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ WM_event_add_modal_handler(C, op);
- return FLUIDSIM_CBRET_CONTINUE;
+ return OPERATOR_RUNNING_MODAL;
}
-static void fluidbake_free_data(FluidAnimChannels *channels,
- ListBase *fobjects,
- elbeemSimulationSettings *fsset,
- FluidBakeJob *fb)
+static int fluid_bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- free_domain_channels(channels);
- MEM_freeN(channels);
- channels = NULL;
-
- free_all_fluidobject_channels(fobjects);
- BLI_freelistN(fobjects);
- MEM_freeN(fobjects);
- fobjects = NULL;
-
- if (fsset) {
- MEM_freeN(fsset);
- fsset = NULL;
+ /* no running blender, remove handler and pass through */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}
- if (fb) {
- MEM_freeN(fb);
- fb = NULL;
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
}
+ return OPERATOR_PASS_THROUGH;
}
-/* copied from rna_fluidsim.c: fluidsim_find_lastframe() */
-static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *relbase)
+static int fluid_free_exec(struct bContext *C, struct wmOperator *op)
{
- char targetDir[FILE_MAX], targetFile[FILE_MAX];
- char targetDirVel[FILE_MAX], targetFileVel[FILE_MAX];
- char previewDir[FILE_MAX], previewFile[FILE_MAX];
- int curFrame = 1, exists = 0;
-
- BLI_join_dirfile(
- targetDir, sizeof(targetDir), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
- BLI_join_dirfile(
- targetDirVel, sizeof(targetDirVel), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_VEL_FNAME);
- BLI_join_dirfile(
- previewDir, sizeof(previewDir), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
-
- BLI_path_abs(targetDir, relbase);
- BLI_path_abs(targetDirVel, relbase);
- BLI_path_abs(previewDir, relbase);
-
- do {
- BLI_strncpy(targetFile, targetDir, sizeof(targetFile));
- BLI_strncpy(targetFileVel, targetDirVel, sizeof(targetFileVel));
- BLI_strncpy(previewFile, previewDir, sizeof(previewFile));
-
- BLI_path_frame(targetFile, curFrame, 0);
- BLI_path_frame(targetFileVel, curFrame, 0);
- BLI_path_frame(previewFile, curFrame, 0);
-
- curFrame++;
-
- if ((exists = BLI_exists(targetFile))) {
- BLI_delete(targetFile, false, false);
- BLI_delete(targetFileVel, false, false);
- BLI_delete(previewFile, false, false);
- }
- } while (exists);
+ FluidModifierData *mmd = NULL;
+ FluidDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
- return;
-}
+ /*
+ * Get modifier data
+ */
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ if (!mmd) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
+ return OPERATOR_CANCELLED;
+ }
+ mds = mmd->domain;
+ if (!mds) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
+ return OPERATOR_CANCELLED;
+ }
-static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- int i;
- FluidsimSettings *domainSettings;
-
- char debugStrBuffer[256];
-
- int gridlevels = 0;
- const char *relbase = modifier_path_relbase(bmain, fsDomain);
- const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
- const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
- const char *suffixSurface = FLUID_SUFFIX_SURFACE;
-
- char targetDir[FILE_MAX]; // store & modify output settings
- char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
-
- float domainMat[4][4];
- float invDomMat[4][4];
-
- int noFrames;
- int origFrame = scene->r.cfra;
-
- FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels),
- "fluid domain animation channels");
- ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects");
- FluidsimModifierData *fluidmd = NULL;
- Mesh *mesh = NULL;
-
- FluidBakeJob *fb;
- elbeemSimulationSettings *fsset = MEM_callocN(sizeof(elbeemSimulationSettings),
- "Fluid sim settings");
-
- fb = MEM_callocN(sizeof(FluidBakeJob), "fluid bake job");
-
- if (BLI_getenv(strEnvName)) {
- int dlevel = atoi(BLI_getenv(strEnvName));
- elbeemSetDebugLevel(dlevel);
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",
- strEnvName);
- elbeemDebugOut(debugStrBuffer);
+ /* Cannot free data if other bakes currently working */
+ if (mmd->domain->cache_flag & (FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKING_NOISE |
+ FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKING_PARTICLES)) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: pending bake jobs found");
+ return OPERATOR_CANCELLED;
}
- /* Make sure it corresponds to startFrame setting
- * (old: noFrames = scene->r.efra - scene->r.sfra +1). */
+ FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
+ job->bmain = CTX_data_main(C);
+ job->scene = scene;
+ job->depsgraph = CTX_data_depsgraph_pointer(C);
+ job->ob = ob;
+ job->mmd = mmd;
+ job->type = op->type->idname;
+ job->name = op->type->name;
- noFrames = scene->r.efra - 0;
- if (noFrames <= 0) {
- BKE_report(reports, RPT_ERROR, "No frames to export (check your animation range settings)");
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
+ if (!fluid_initpaths(job, op->reports)) {
+ return OPERATOR_CANCELLED;
}
- /* check scene for sane object/modifier settings */
- if (!fluid_validate_scene(reports, view_layer, fsDomain)) {
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
- }
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Fluid Free",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_OBJECT_SIM_FLUID);
- /* these both have to be valid, otherwise we wouldn't be here */
- fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
- domainSettings = fluidmd->fss;
- mesh = fsDomain->data;
-
- domainSettings->bakeStart = 1;
- domainSettings->bakeEnd = scene->r.efra;
-
- // calculate bounding box
- fluid_get_bb(mesh->mvert,
- mesh->totvert,
- fsDomain->obmat,
- domainSettings->bbStart,
- domainSettings->bbSize);
-
- // reset last valid frame
- domainSettings->lastgoodframe = -1;
-
- /* delete old baked files */
- fluidsim_delete_until_lastframe(domainSettings, relbase);
-
- /* rough check of settings... */
- if (domainSettings->previewresxyz > domainSettings->resolutionxyz) {
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n",
- domainSettings->previewresxyz,
- domainSettings->resolutionxyz);
- elbeemDebugOut(debugStrBuffer);
- domainSettings->previewresxyz = domainSettings->resolutionxyz;
- }
- // set adaptive coarsening according to resolutionxyz
- // this should do as an approximation, with in/outflow
- // doing this more accurate would be overkill
- // perhaps add manual setting?
- if (domainSettings->maxRefine < 0) {
- if (domainSettings->resolutionxyz > 128) {
- gridlevels = 2;
- }
- else if (domainSettings->resolutionxyz > 64) {
- gridlevels = 1;
- }
- else {
- gridlevels = 0;
- }
- }
- else {
- gridlevels = domainSettings->maxRefine;
- }
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::msg: Baking %s, refine: %d\n",
- fsDomain->id.name,
- gridlevels);
- elbeemDebugOut(debugStrBuffer);
-
- /* ******** prepare output file paths ******** */
- if (!fluid_init_filepaths(bmain, reports, domainSettings, fsDomain, targetDir, targetFile)) {
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return false;
- }
+ WM_jobs_customdata_set(wm_job, job, fluid_bake_free);
+ WM_jobs_timer(wm_job, 0.01, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
+ WM_jobs_callbacks(wm_job, fluid_free_startjob, NULL, NULL, fluid_free_endjob);
- /* DG TODO: why using endframe and not "noFrames" here?
- * because "noFrames" is buggy too? (not using sfra) */
- channels->length = scene->r.efra;
- channels->aniFrameTime = (double)((double)domainSettings->animEnd -
- (double)domainSettings->animStart) /
- (double)noFrames;
-
- /* ******** initialize and allocate animation channels ******** */
- fluid_init_all_channels(C, depsgraph, fsDomain, domainSettings, channels, fobjects);
-
- /* reset to original current frame */
- scene->r.cfra = origFrame;
- ED_update_for_newframe(CTX_data_main(C), CTX_data_depsgraph_pointer(C));
-
- /* ******** init domain object's matrix ******** */
- copy_m4_m4(domainMat, fsDomain->obmat);
- if (!invert_m4_m4(invDomMat, domainMat)) {
- BLI_snprintf(
- debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n");
- elbeemDebugOut(debugStrBuffer);
- BKE_report(reports, RPT_ERROR, "Invalid object matrix");
-
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
- }
+ WM_set_locked_interface(CTX_wm_manager(C), true);
- /* ******** start writing / exporting ******** */
- // use .tmp, don't overwrite/delete original file
- BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp);
-
- /* ******** export domain to elbeem ******** */
- elbeemResetSettings(fsset);
- fsset->version = 1;
- fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) :
- domainSettings->threads;
- // setup global settings
- copy_v3_v3(fsset->geoStart, domainSettings->bbStart);
- copy_v3_v3(fsset->geoSize, domainSettings->bbSize);
-
- // simulate with 50^3
- fsset->resolutionxyz = (int)domainSettings->resolutionxyz;
- fsset->previewresxyz = (int)domainSettings->previewresxyz;
-
- fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings);
- fsset->viscosity = get_fluid_viscosity(domainSettings);
- get_fluid_gravity(fsset->gravity, scene, domainSettings);
-
- // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz
- fsset->animStart = domainSettings->animStart;
- fsset->aniFrameTime = channels->aniFrameTime;
- fsset->noOfFrames = noFrames; // is otherwise subtracted in parser
-
- BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface);
-
- // defaults for compressibility and adaptive grids
- fsset->gstar = domainSettings->gstar;
- fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels
- fsset->generateParticles = domainSettings->generateParticles;
- fsset->numTracerParticles = domainSettings->generateTracers;
- fsset->surfaceSmoothing = domainSettings->surfaceSmoothing;
- fsset->surfaceSubdivs = domainSettings->surfaceSubdivs;
- fsset->farFieldSize = domainSettings->farFieldSize;
- BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath));
-
- // domain channels
- fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity =
- channels->length;
- fsset->channelFrameTime = channels->DomainTime;
- fsset->channelViscosity = channels->DomainViscosity;
- fsset->channelGravity = channels->DomainGravity;
-
- fsset->runsimCallback = &runSimulationCallback;
- fsset->runsimUserData = fb;
-
- if (domainSettings->typeFlags & OB_FSBND_NOSLIP) {
- fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- else if (domainSettings->typeFlags & OB_FSBND_PARTSLIP) {
- fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
- }
- else if (domainSettings->typeFlags & OB_FSBND_FREESLIP) {
- fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
- }
- fsset->domainobsPartslip = domainSettings->partSlipValue;
+ /* Free Fluid Geometry */
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+
+ return OPERATOR_FINISHED;
+}
- /* use domainobsType also for surface generation flag (bit: >=64) */
- if (domainSettings->typeFlags & OB_FSSG_NOOBS) {
- fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS;
+static int fluid_pause_exec(struct bContext *C, struct wmOperator *op)
+{
+ FluidModifierData *mmd = NULL;
+ FluidDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
+
+ /*
+ * Get modifier data
+ */
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ if (!mmd) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
+ return OPERATOR_CANCELLED;
}
- else {
- fsset->mFsSurfGenSetting = 0; // "normal" mode
+ mds = mmd->domain;
+ if (!mds) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
+ return OPERATOR_CANCELLED;
}
- fsset->generateVertexVectors = (domainSettings->domainNovecgen == 0);
+ G.is_break = true;
- // init blender domain transform matrix
- {
- int j;
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
- fsset->surfaceTrafo[i * 4 + j] = invDomMat[j][i];
- }
- }
- }
+ return OPERATOR_FINISHED;
+}
- /* ******** init solver with settings ******** */
- elbeemInit();
- elbeemAddDomain(fsset);
+void FLUID_OT_bake_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake All";
+ ot->description = "Bake Entire Fluid Simulation";
+ ot->idname = FLUID_JOB_BAKE_ALL;
- /* ******** export all fluid objects to elbeem ******** */
- export_fluid_objects(depsgraph, fobjects, scene, channels->length);
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
- /* custom data for fluid bake job */
- fb->settings = fsset;
+void FLUID_OT_free_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free All";
+ ot->description = "Free Entire Fluid Simulation";
+ ot->idname = FLUID_JOB_FREE_ALL;
- if (do_job) {
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- scene,
- "Fluid Simulation",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_OBJECT_SIM_FLUID);
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
- /* setup job */
- WM_jobs_customdata_set(wm_job, fb, fluidbake_free);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
- WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob);
+void FLUID_OT_bake_data(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Data";
+ ot->description = "Bake Fluid Data";
+ ot->idname = FLUID_JOB_BAKE_DATA;
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- }
- else {
- short dummy_stop = 0, dummy_do_update = 0;
- float dummy_progress = 0.0f;
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
- /* blocking, use with exec() */
- fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress);
- fluidbake_endjob((void *)fb);
- fluidbake_free((void *)fb);
- }
+void FLUID_OT_free_data(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free Data";
+ ot->description = "Free Fluid Data";
+ ot->idname = FLUID_JOB_FREE_DATA;
+
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
- /* ******** free stored animation data ******** */
- fluidbake_free_data(channels, fobjects, NULL, NULL);
+void FLUID_OT_bake_noise(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Noise";
+ ot->description = "Bake Fluid Noise";
+ ot->idname = FLUID_JOB_BAKE_NOISE;
- // elbeemFree();
- return 1;
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
}
-static void UNUSED_FUNCTION(fluidsimFreeBake)(Object *UNUSED(ob))
+void FLUID_OT_free_noise(wmOperatorType *ot)
{
- /* not implemented yet */
+ /* identifiers */
+ ot->name = "Free Noise";
+ ot->description = "Free Fluid Noise";
+ ot->idname = FLUID_JOB_FREE_NOISE;
+
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-#else /* WITH_MOD_FLUID */
+void FLUID_OT_bake_mesh(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Mesh";
+ ot->description = "Bake Fluid Mesh";
+ ot->idname = FLUID_JOB_BAKE_MESH;
+
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
-/* only compile dummy functions */
-static int fluidsimBake(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
- Object *UNUSED(ob),
- short UNUSED(do_job))
+void FLUID_OT_free_mesh(wmOperatorType *ot)
{
- return 0;
+ /* identifiers */
+ ot->name = "Free Mesh";
+ ot->description = "Free Fluid Mesh";
+ ot->idname = FLUID_JOB_FREE_MESH;
+
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-#endif /* WITH_MOD_FLUID */
+void FLUID_OT_bake_particles(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Particles";
+ ot->description = "Bake Fluid Particles";
+ ot->idname = FLUID_JOB_BAKE_PARTICLES;
-/***************************** Operators ******************************/
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
-static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+void FLUID_OT_free_particles(wmOperatorType *ot)
{
- /* only one bake job at a time */
- if (WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) {
- return OPERATOR_CANCELLED;
- }
+ /* identifiers */
+ ot->name = "Free Particles";
+ ot->description = "Free Fluid Particles";
+ ot->idname = FLUID_JOB_FREE_PARTICLES;
- if (!fluidsimBake(C, op->reports, ED_object_context(C), true)) {
- return OPERATOR_CANCELLED;
- }
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
- return OPERATOR_FINISHED;
+void FLUID_OT_bake_guides(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Guides";
+ ot->description = "Bake Fluid Guiding";
+ ot->idname = FLUID_JOB_BAKE_GUIDES;
+
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
}
-static int fluid_bake_exec(bContext *C, wmOperator *op)
+void FLUID_OT_free_guides(wmOperatorType *ot)
{
- if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), false)) {
- return OPERATOR_CANCELLED;
- }
+ /* identifiers */
+ ot->name = "Free Guides";
+ ot->description = "Free Fluid Guiding";
+ ot->idname = FLUID_JOB_FREE_GUIDES;
- return OPERATOR_FINISHED;
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-void FLUID_OT_bake(wmOperatorType *ot)
+void FLUID_OT_pause_bake(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Fluid Simulation Bake";
- ot->description = "Bake fluid simulation";
- ot->idname = "FLUID_OT_bake";
+ ot->name = "Pause Bake";
+ ot->description = "Pause Bake";
+ ot->idname = FLUID_JOB_BAKE_PAUSE;
/* api callbacks */
- ot->invoke = fluid_bake_invoke;
- ot->exec = fluid_bake_exec;
+ ot->exec = fluid_pause_exec;
ot->poll = ED_operator_object_active_editable;
}
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index fc2f3d21bb6..3af818b3a9d 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -103,7 +103,19 @@ void BOID_OT_state_move_up(struct wmOperatorType *ot);
void BOID_OT_state_move_down(struct wmOperatorType *ot);
/* physics_fluid.c */
-void FLUID_OT_bake(struct wmOperatorType *ot);
+void FLUID_OT_bake_all(struct wmOperatorType *ot);
+void FLUID_OT_free_all(struct wmOperatorType *ot);
+void FLUID_OT_bake_data(struct wmOperatorType *ot);
+void FLUID_OT_free_data(struct wmOperatorType *ot);
+void FLUID_OT_bake_noise(struct wmOperatorType *ot);
+void FLUID_OT_free_noise(struct wmOperatorType *ot);
+void FLUID_OT_bake_mesh(struct wmOperatorType *ot);
+void FLUID_OT_free_mesh(struct wmOperatorType *ot);
+void FLUID_OT_bake_particles(struct wmOperatorType *ot);
+void FLUID_OT_free_particles(struct wmOperatorType *ot);
+void FLUID_OT_bake_guides(struct wmOperatorType *ot);
+void FLUID_OT_free_guides(struct wmOperatorType *ot);
+void FLUID_OT_pause_bake(struct wmOperatorType *ot);
/* dynamicpaint.c */
void DPAINT_OT_bake(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index b1b3927d05e..d1536733b9b 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -126,7 +126,19 @@ static void operatortypes_boids(void)
static void operatortypes_fluid(void)
{
- WM_operatortype_append(FLUID_OT_bake);
+ WM_operatortype_append(FLUID_OT_bake_all);
+ WM_operatortype_append(FLUID_OT_free_all);
+ WM_operatortype_append(FLUID_OT_bake_data);
+ WM_operatortype_append(FLUID_OT_free_data);
+ WM_operatortype_append(FLUID_OT_bake_noise);
+ WM_operatortype_append(FLUID_OT_free_noise);
+ WM_operatortype_append(FLUID_OT_bake_mesh);
+ WM_operatortype_append(FLUID_OT_free_mesh);
+ WM_operatortype_append(FLUID_OT_bake_particles);
+ WM_operatortype_append(FLUID_OT_free_particles);
+ WM_operatortype_append(FLUID_OT_bake_guides);
+ WM_operatortype_append(FLUID_OT_free_guides);
+ WM_operatortype_append(FLUID_OT_pause_bake);
}
/**************************** point cache **********************************/
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 6c62dbcb3a2..7f7748bf52f 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -55,6 +55,10 @@ set(LIB
if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
+else()
+ list(APPEND LIB
+ bf_editor_datafiles
+ )
endif()
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 7106af25a82..5740dacd05f 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -1173,7 +1173,7 @@ static int render_shutter_curve_preset_exec(bContext *C, wmOperator *op)
CurveMap *cm = mblur_shutter_curve->cm;
int preset = RNA_enum_get(op->ptr, "shape");
- cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
+ mblur_shutter_curve->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
mblur_shutter_curve->preset = preset;
BKE_curvemap_reset(
cm, &mblur_shutter_curve->clipr, mblur_shutter_curve->preset, CURVEMAP_SLOPE_POS_NEG);
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index f419d30a17e..3a77e1e1565 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup edrend
+ * \ingroup render
*/
#include <math.h>
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_camera_types.h"
+#include "BLI_bitmap.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_blenlib.h"
@@ -35,13 +36,18 @@
#include "BLI_threads.h"
#include "BLI_task.h"
+#include "DNA_anim_types.h"
+#include "DNA_action_types.h"
+#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
+#include "BKE_animsys.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
@@ -77,7 +83,7 @@
#include "render_intern.h"
/* Define this to get timing information. */
-// #undef DEBUG_TIME
+// #define DEBUG_TIME
#ifdef DEBUG_TIME
# include "PIL_time.h"
@@ -114,7 +120,6 @@ typedef struct OGLRender {
ImageUser iuser;
GPUOffScreen *ofs;
- int ofs_samples;
int sizex, sizey;
int write_still;
@@ -124,6 +129,9 @@ typedef struct OGLRender {
int totvideos;
+ /* For only rendering frames that have a key in animation data. */
+ BLI_bitmap *render_frames;
+
/* quick lookup */
int view_id;
@@ -138,6 +146,8 @@ typedef struct OGLRender {
TaskPool *task_pool;
bool pool_ok;
bool is_animation;
+
+ eImageFormatDepth color_depth;
SpinLock reports_lock;
unsigned int num_scheduled_frames;
ThreadMutex task_mutex;
@@ -284,6 +294,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
const short view_context = (v3d != NULL);
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
float *rectf = NULL;
+ unsigned char *rect = NULL;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
ImBuf *ibuf_result = NULL;
@@ -356,6 +367,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
char err_out[256] = "unknown";
ImBuf *ibuf_view;
const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL;
+ int output_flags = oglrender->color_depth <= R_IMF_CHAN_DEPTH_8 ? IB_rect : IB_rectfloat;
if (view_context) {
ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph,
@@ -365,9 +377,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ar,
sizex,
sizey,
- IB_rectfloat,
+ output_flags,
alpha_mode,
- oglrender->ofs_samples,
viewname,
oglrender->ofs,
err_out);
@@ -385,10 +396,9 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
scene->camera,
oglrender->sizex,
oglrender->sizey,
- IB_rectfloat,
+ output_flags,
V3D_OFSDRAW_SHOW_ANNOTATION,
alpha_mode,
- oglrender->ofs_samples,
viewname,
oglrender->ofs,
err_out);
@@ -397,7 +407,12 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (ibuf_view) {
ibuf_result = ibuf_view;
- rectf = (float *)ibuf_view->rect_float;
+ if (ibuf_view->rect_float) {
+ rectf = ibuf_view->rect_float;
+ }
+ else {
+ rect = (unsigned char *)ibuf_view->rect;
+ }
}
else {
fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
@@ -406,7 +421,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (ibuf_result != NULL) {
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
- BKE_image_stamp_buf(scene, camera, NULL, NULL, rectf, rr->rectx, rr->recty, 4);
+ BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4);
}
RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
IMB_freeImBuf(ibuf_result);
@@ -511,6 +526,71 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
}
}
+static void gather_frames_to_render_for_adt(OGLRender *oglrender,
+ int frame_start,
+ int frame_end,
+ const AnimData *adt)
+{
+ if (adt == NULL || adt->action == NULL) {
+ return;
+ }
+
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
+ if (fcu->driver != NULL || fcu->fpt != NULL) {
+ /* Drivers have values for any point in time, so to get "the keyed frames" they are
+ * useless. Same for baked FCurves, they also have keys for every frame, which is not
+ * useful for rendering the keyed subset of the frames. */
+ continue;
+ }
+
+ bool found = false; /* Not interesting, we just want a starting point for the for-loop.*/
+ int key_index = binarysearch_bezt_index(fcu->bezt, frame_start, fcu->totvert, &found);
+ for (; key_index < fcu->totvert; key_index++) {
+ BezTriple *bezt = &fcu->bezt[key_index];
+ /* The frame range to render uses integer frame numbers, and the frame
+ * step is also an integer, so we always render on the frame. */
+ int frame_nr = round_fl_to_int(bezt->vec[1][0]);
+
+ /* (frame_nr < frame_start) cannot happen because of the binary search above. */
+ BLI_assert(frame_nr >= frame_start);
+ if (frame_nr > frame_end) {
+ break;
+ }
+ BLI_BITMAP_ENABLE(oglrender->render_frames, frame_nr - frame_start);
+ }
+ }
+}
+
+/**
+ * Collect the frame numbers for which selected objects have keys in the animation data.
+ * The frames ares stored in #OGLRender.render_frames.
+ */
+static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
+{
+ Scene *scene = CTX_data_scene(C);
+ int frame_start = PSFRA;
+ int frame_end = PEFRA;
+
+ /* Will be freed in screen_opengl_render_end(). */
+ oglrender->render_frames = BLI_BITMAP_NEW(frame_end - frame_start + 1,
+ "OGLRender::render_frames");
+
+ /* The first frame should always be rendered, otherwise there is nothing to write to file. */
+ BLI_BITMAP_ENABLE(oglrender->render_frames, 0);
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (ob->adt != NULL) {
+ gather_frames_to_render_for_adt(oglrender, frame_start, frame_end, ob->adt);
+ }
+
+ AnimData *adt = BKE_animdata_from_id(ob->data);
+ if (adt != NULL) {
+ gather_frames_to_render_for_adt(oglrender, frame_start, frame_end, adt);
+ }
+ }
+ CTX_DATA_END;
+}
+
static bool screen_opengl_render_init(bContext *C, wmOperator *op)
{
/* new render clears all callbacks */
@@ -526,9 +606,11 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
int sizex, sizey;
bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
+ const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
- const int samples = U.ogl_multisamples;
+ const eImageFormatDepth color_depth = (is_animation) ? scene->r.im_format.depth :
+ R_IMF_CHAN_DEPTH_32;
char err_out[256] = "unknown";
if (G.background) {
@@ -573,7 +655,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* corrects render size with actual size, not every card supports non-power-of-two dimensions */
DRW_opengl_context_enable(); /* Offscreen creation needs to be done in DRW context. */
- ofs = GPU_offscreen_create(sizex, sizey, samples, true, true, err_out);
+ ofs = GPU_offscreen_create(sizex, sizey, 0, true, true, err_out);
DRW_opengl_context_disable();
if (!ofs) {
@@ -596,10 +678,10 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
* output video handles, which does need evaluated scene. */
oglrender->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
oglrender->cfrao = scene->r.cfra;
- oglrender->ofs_samples = samples;
oglrender->write_still = is_write_still && !is_animation;
oglrender->is_animation = is_animation;
+ oglrender->color_depth = color_depth;
oglrender->views_len = BKE_scene_multiview_num_views_get(&scene->r);
@@ -658,6 +740,10 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->movie_ctx_arr = NULL;
if (is_animation) {
+ if (is_render_keyed_only) {
+ gather_frames_to_render(C, oglrender);
+ }
+
TaskScheduler *task_scheduler = BLI_task_scheduler_get();
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
task_scheduler = BLI_task_scheduler_create(1);
@@ -724,6 +810,8 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
printf("Total render time: %f\n", PIL_check_seconds_timer() - oglrender->time_start);
#endif
+ MEM_SAFE_FREE(oglrender->render_frames);
+
if (oglrender->mh) {
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
for (i = 0; i < oglrender->totvideos; i++) {
@@ -988,8 +1076,11 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
}
- /* render into offscreen buffer */
- screen_opengl_render_apply(C, oglrender);
+ if (oglrender->render_frames == NULL ||
+ BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) {
+ /* render into offscreen buffer */
+ screen_opengl_render_apply(C, oglrender);
+ }
/* save to disk */
rr = RE_AcquireResultRead(oglrender->re);
@@ -1117,6 +1208,23 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static char *screen_opengl_render_description(struct bContext *UNUSED(C),
+ struct wmOperatorType *UNUSED(ot),
+ struct PointerRNA *ptr)
+{
+ if (!RNA_boolean_get(ptr, "animation")) {
+ return NULL;
+ }
+
+ if (RNA_boolean_get(ptr, "render_keyed_only")) {
+ return BLI_strdup(
+ "Render the viewport for the animation range of this scene, but only render keyframes of "
+ "selected objects");
+ }
+
+ return BLI_strdup("Render the viewport for the animation range of this scene");
+}
+
void RENDER_OT_opengl(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1127,6 +1235,7 @@ void RENDER_OT_opengl(wmOperatorType *ot)
ot->idname = "RENDER_OT_opengl";
/* api callbacks */
+ ot->get_description = screen_opengl_render_description;
ot->invoke = screen_opengl_render_invoke;
ot->exec = screen_opengl_render_exec; /* blocking */
ot->modal = screen_opengl_render_modal;
@@ -1140,6 +1249,15 @@ void RENDER_OT_opengl(wmOperatorType *ot)
"Animation",
"Render files from the animation range of this scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna,
+ "render_keyed_only",
+ 0,
+ "Render Keyframes Only",
+ "Render only those frames where selected objects have a key in their "
+ "animation data. Only used when rendering animation");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
prop = RNA_def_boolean(
ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 6dc3a1ec1ac..0ed37bbc5af 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -80,10 +80,10 @@
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "GPU_shader.h"
+#include "GPU_glew.h"
#include "RE_pipeline.h"
#include "RE_engine.h"
@@ -1118,10 +1118,16 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
if (idtype == ID_IM) {
Image *ima = (Image *)id;
ImBuf *ibuf = NULL;
- ImageUser iuser = {NULL};
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
- /* ima->ok is zero when Image cannot load */
- if (ima == NULL || ima->ok == 0) {
+ if (ima == NULL) {
+ return;
+ }
+
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ /* tile->ok is zero when Image cannot load */
+ if (tile->ok == 0) {
return;
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index ccee88eb0d6..98bee156090 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1280,11 +1280,12 @@ static void region_rect_recursive(
*/
const int size_min[2] = {UI_UNIT_X, UI_UNIT_Y};
rcti overlap_remainder_margin = *overlap_remainder;
+
BLI_rcti_resize(&overlap_remainder_margin,
max_ii(0, BLI_rcti_size_x(overlap_remainder) - UI_UNIT_X / 2),
max_ii(0, BLI_rcti_size_y(overlap_remainder) - UI_UNIT_Y / 2));
- ar->winrct.xmin = overlap_remainder_margin.xmin;
- ar->winrct.ymin = overlap_remainder_margin.ymin;
+ ar->winrct.xmin = overlap_remainder_margin.xmin + ar->runtime.offset_x;
+ ar->winrct.ymin = overlap_remainder_margin.ymin + ar->runtime.offset_y;
ar->winrct.xmax = ar->winrct.xmin + prefsizex - 1;
ar->winrct.ymax = ar->winrct.ymin + prefsizey - 1;
@@ -1594,6 +1595,8 @@ static void ed_default_handlers(
}
}
if (flag & ED_KEYMAP_TOOL) {
+ WM_event_add_keymap_handler_dynamic(
+ &ar->handlers, WM_event_get_keymap_from_toolsystem_fallback, sa);
WM_event_add_keymap_handler_dynamic(&ar->handlers, WM_event_get_keymap_from_toolsystem, sa);
}
if (flag & ED_KEYMAP_VIEW2D) {
@@ -3211,15 +3214,15 @@ void ED_region_image_metadata_panel_draw(ImBuf *ibuf, uiLayout *layout)
IMB_metadata_foreach(ibuf, metadata_panel_draw_field, &ctx);
}
-void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
+void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy, float x0, float y0)
{
float gridsize, gridstep = 1.0f / 32.0f;
float fac, blendfac;
int x1, y1, x2, y2;
- /* the image is located inside (0, 0), (1, 1) as set by view2d */
- UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x1, &y1);
- UI_view2d_view_to_region(&ar->v2d, 1.0f, 1.0f, &x2, &y2);
+ /* the image is located inside (x0, y0), (x0+1, y0+1) as set by view2d */
+ UI_view2d_view_to_region(&ar->v2d, x0, y0, &x1, &y1);
+ UI_view2d_view_to_region(&ar->v2d, x0 + 1.0f, y0 + 1.0f, &x2, &y2);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index 61fb9d5a3a8..12de1ddb795 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -33,6 +33,7 @@
#include "ED_screen.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
/* -------------------------------------------------------------------- */
/** \name Generic Tool System Region Callbacks
@@ -63,17 +64,27 @@ void ED_region_generic_tools_region_message_subscribe(const struct bContext *UNU
int ED_region_generic_tools_region_snap_size(const ARegion *ar, int size, int axis)
{
if (axis == 0) {
- /* Note, this depends on the icon size: see #ICON_DEFAULT_HEIGHT_TOOLBAR. */
- const float snap_units[] = {2 + 0.8f, 4 + 0.8f};
- const float aspect = BLI_rctf_size_x(&ar->v2d.cur) / (BLI_rcti_size_x(&ar->v2d.mask) + 1);
+ /* Using Y axis avoids slight feedback loop when adjusting X. */
+ const float aspect = BLI_rctf_size_y(&ar->v2d.cur) / (BLI_rcti_size_y(&ar->v2d.mask) + 1);
+ const float icon_size = ICON_DEFAULT_HEIGHT_TOOLBAR / aspect;
+ const float column = 1.25f * icon_size;
+ const float margin = 0.5f * icon_size;
+ const float snap_units[] = {
+ column + margin,
+ (2.0f * column) + margin,
+ (2.7f * column) + margin,
+ };
int best_diff = INT_MAX;
int best_size = size;
- for (uint i = 0; i < ARRAY_SIZE(snap_units); i += 1) {
- const int test_size = (snap_units[i] * U.widget_unit) / (UI_DPI_FAC * aspect);
- const int test_diff = ABS(test_size - size);
- if (test_diff < best_diff) {
- best_size = test_size;
- best_diff = test_diff;
+ /* Only snap if less than last snap unit. */
+ if (size <= snap_units[ARRAY_SIZE(snap_units) - 1]) {
+ for (uint i = 0; i < ARRAY_SIZE(snap_units); i += 1) {
+ const int test_size = snap_units[i];
+ const int test_diff = ABS(test_size - size);
+ if (test_diff < best_diff) {
+ best_size = test_size;
+ best_diff = test_diff;
+ }
}
}
return best_size;
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 5b8fd33a4e9..501c36286d0 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1389,13 +1389,13 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
case USER_TEMP_SPACE_DISPLAY_FULLSCREEN: {
ScrArea *ctx_sa = CTX_wm_area(C);
- if (ctx_sa->full) {
+ if (ctx_sa != NULL && ctx_sa->full) {
sa = ctx_sa;
ED_area_newspace(C, ctx_sa, space_type, true);
sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
((SpaceLink *)sa->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
}
- else if (ctx_sa->spacetype == space_type) {
+ else if (ctx_sa != NULL && ctx_sa->spacetype == space_type) {
sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED);
}
else {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 9975c49dc54..dd09def2df6 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -929,6 +929,8 @@ static void actionzone_exit(wmOperator *op)
MEM_freeN(op->customdata);
}
op->customdata = NULL;
+
+ G.moving &= ~G_TRANSFORM_WM;
}
/* send EVT_ACTIONZONE event */
@@ -986,9 +988,11 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED;
}
else {
+ BLI_assert(ELEM(sad->az->type, AZONE_AREA, AZONE_REGION_SCROLL));
+
/* add modal handler */
+ G.moving |= G_TRANSFORM_WM;
WM_event_add_modal_handler(C, op);
-
return OPERATOR_RUNNING_MODAL;
}
}
@@ -1807,9 +1811,8 @@ static int area_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
- G.moving |= G_TRANSFORM_WM;
-
/* add temp handler */
+ G.moving |= G_TRANSFORM_WM;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2115,6 +2118,8 @@ static void area_split_exit(bContext *C, wmOperator *op)
/* this makes sure aligned edges will result in aligned grabbing */
BKE_screen_remove_double_scrverts(CTX_wm_screen(C));
BKE_screen_remove_double_scredges(CTX_wm_screen(C));
+
+ G.moving &= ~G_TRANSFORM_WM;
}
static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
@@ -2247,6 +2252,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
area_move_set_limits(win, sc, dir, &sd->bigger, &sd->smaller, NULL);
/* add temp handler for edge move or cancel */
+ G.moving |= G_TRANSFORM_WM;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2526,6 +2532,14 @@ static bool is_split_edge(const int alignment, const AZEdge edge)
((alignment == RGN_ALIGN_RIGHT) && (edge == AE_LEFT_TO_TOPRIGHT));
}
+static void region_scale_exit(wmOperator *op)
+{
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+
+ G.moving &= ~G_TRANSFORM_WM;
+}
+
static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
sActionzoneData *sad = event->customdata;
@@ -2579,6 +2593,7 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event
CLAMP(rmd->maxsize, 0, 1000);
/* add temp handler */
+ G.moving |= G_TRANSFORM_WM;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2651,7 +2666,8 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* region sizes now get multiplied */
delta /= UI_DPI_FAC;
- rmd->ar->sizex = rmd->origval + delta;
+ const int size_no_snap = rmd->origval + delta;
+ rmd->ar->sizex = size_no_snap;
if (rmd->ar->type->snap_size) {
short sizex_test = rmd->ar->type->snap_size(rmd->ar, rmd->ar->sizex, 0);
@@ -2661,7 +2677,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
CLAMP(rmd->ar->sizex, 0, rmd->maxsize);
- if (rmd->ar->sizex < UI_UNIT_X) {
+ if (size_no_snap < UI_UNIT_X / aspect) {
rmd->ar->sizex = rmd->origval;
if (!(rmd->ar->flag & RGN_FLAG_HIDDEN)) {
region_scale_toggle_hidden(C, rmd);
@@ -2683,7 +2699,8 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* region sizes now get multiplied */
delta /= UI_DPI_FAC;
- rmd->ar->sizey = rmd->origval + delta;
+ const int size_no_snap = rmd->origval + delta;
+ rmd->ar->sizey = size_no_snap;
if (rmd->ar->type->snap_size) {
short sizey_test = rmd->ar->type->snap_size(rmd->ar, rmd->ar->sizey, 1);
@@ -2696,7 +2713,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* note, 'UI_UNIT_Y/4' means you need to drag the footer and execute region
* almost all the way down for it to become hidden, this is done
* otherwise its too easy to do this by accident */
- if (rmd->ar->sizey < UI_UNIT_Y / 4) {
+ if (size_no_snap < (UI_UNIT_Y / 4) / aspect) {
rmd->ar->sizey = rmd->origval;
if (!(rmd->ar->flag & RGN_FLAG_HIDDEN)) {
region_scale_toggle_hidden(C, rmd);
@@ -2727,8 +2744,8 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_area_tag_redraw(rmd->sa);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
- MEM_freeN(op->customdata);
- op->customdata = NULL;
+
+ region_scale_exit(op);
return OPERATOR_FINISHED;
}
@@ -2743,8 +2760,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void region_scale_cancel(bContext *UNUSED(C), wmOperator *op)
{
- MEM_freeN(op->customdata);
- op->customdata = NULL;
+ region_scale_exit(op);
}
static void SCREEN_OT_region_scale(wmOperatorType *ot)
@@ -4229,19 +4245,6 @@ static void SCREEN_OT_region_context_menu(wmOperatorType *ot)
* Animation Step.
* \{ */
-static int match_area_with_refresh(int spacetype, int refresh)
-{
- switch (spacetype) {
- case SPACE_TIME:
- if (refresh & SPACE_TIME) {
- return 1;
- }
- break;
- }
-
- return 0;
-}
-
static int match_region_with_redraws(int spacetype,
int regiontype,
int redraws,
@@ -4524,10 +4527,6 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
}
}
-
- if (match_area_with_refresh(sa->spacetype, sad->refresh)) {
- ED_area_tag_refresh(sa);
- }
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 78c9980134f..9021666c001 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -648,7 +648,7 @@ static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups,
GPU_matrix_translate_2f(-x, -y);
/* scale based on tablet pressure */
- if (primary && ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
+ if (primary && ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
const float scale = ups->size_pressure_value;
GPU_matrix_translate_2f(x, y);
GPU_matrix_scale_2f(scale, scale);
@@ -778,7 +778,7 @@ static bool paint_draw_cursor_overlay(
}
/* scale based on tablet pressure */
- if (ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
+ if (ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
do_pop = true;
GPU_matrix_push();
GPU_matrix_translate_2fv(center);
@@ -1075,7 +1075,7 @@ static void paint_cursor_on_hit(UnifiedPaintSettings *ups,
unprojected_radius = paint_calc_object_space_radius(vc, location, projected_radius);
/* scale 3D brush radius by pressure */
- if (ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
+ if (ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
unprojected_radius *= ups->size_pressure_value;
}
@@ -1329,7 +1329,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* set various defaults */
const float *outline_col = brush->add_col;
- const float outline_alpha = 0.7f;
+ const float outline_alpha = brush->add_col[3];
float translation[2] = {x, y};
float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
@@ -1362,7 +1362,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
immUniformColor3fvAlpha(outline_col, outline_alpha);
/* draw brush outline */
- if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ if (ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
imm_draw_circle_wire_2d(
pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
/* outer at half alpha */
@@ -1407,8 +1407,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
immUniformColor3fvAlpha(outline_col, outline_alpha);
- if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush) &&
- mode != PAINT_MODE_SCULPT) {
+ if (ups->stroke_active && BKE_brush_use_size_pressure(brush) && mode != PAINT_MODE_SCULPT) {
imm_draw_circle_wire_3d(
pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
/* outer at half alpha */
@@ -1548,16 +1547,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
else {
if (vc.obact->sculpt->cache && !vc.obact->sculpt->cache->first_time) {
- /* Draw cursor location preview when the stroke is active using the data from StrokeCache
- */
- float cursor_location[3];
wmViewport(&ar->winrct);
- copy_v3_v3(cursor_location, ss->cache->true_location);
- if (ss->cache->brush->sculpt_tool == SCULPT_TOOL_GRAB) {
- add_v3_v3(cursor_location, ss->cache->grab_delta);
- }
- cursor_draw_point_with_symmetry(
- pos, ar, cursor_location, sd, vc.obact, ss->cache->radius);
/* Draw cached dynamic mesh preview lines */
if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 9acc189ae95..de09a52258f 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -119,7 +119,8 @@ void imapaint_region_tiles(
*ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
}
-void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
+void ED_imapaint_dirty_region(
+ Image *ima, ImBuf *ibuf, int tile_number, int x, int y, int w, int h, bool find_old)
{
ImBuf *tmpibuf = NULL;
int tilex, tiley, tilew, tileh, tx, ty;
@@ -152,7 +153,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
ED_image_paint_tile_push(
- undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
+ undo_tiles, ima, ibuf, &tmpibuf, tile_number, tx, ty, NULL, NULL, false, find_old);
}
}
@@ -163,7 +164,8 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
}
}
-void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
+void imapaint_image_update(
+ SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
{
if (imapaintpartial.x1 != imapaintpartial.x2 && imapaintpartial.y1 != imapaintpartial.y2) {
IMB_partial_display_buffer_update_delayed(
@@ -180,8 +182,7 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
int h = imapaintpartial.y2 - imapaintpartial.y1;
if (w && h) {
/* Testing with partial update in uv editor too */
- GPU_paint_update_image(
- image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h);
+ GPU_paint_update_image(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h);
}
}
}
@@ -548,7 +549,7 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po
return;
}
- if (BKE_brush_use_alpha_pressure(scene, brush)) {
+ if (BKE_brush_use_alpha_pressure(brush)) {
BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure * alphafac));
}
else {
@@ -623,7 +624,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
else {
srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush));
}
- paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint);
+ paint_2d_bucket_fill(C, color, brush, pop->startmouse, pop->prevmouse, pop->custom_paint);
}
else {
paint_proj_stroke(C,
@@ -1297,7 +1298,10 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
+void ED_imapaint_bucket_fill(struct bContext *C,
+ float color[3],
+ wmOperator *op,
+ const int mouse[2])
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceImage *sima = CTX_wm_space_image(C);
@@ -1307,7 +1311,8 @@ void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
- paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
+ float mouse_init[2] = {mouse[0], mouse[1]};
+ paint_2d_bucket_fill(C, color, NULL, mouse_init, NULL, NULL);
BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 004caae8a00..7f71110b360 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -30,6 +30,7 @@
#include "DNA_space_types.h"
#include "DNA_object_types.h"
+#include "BLI_listbase.h"
#include "BLI_math_color_blend.h"
#include "BLI_stack.h"
#include "BLI_bitmap.h"
@@ -84,22 +85,21 @@ typedef struct BrushPainterCache {
unsigned short *tex_mask_old;
unsigned int tex_mask_old_w;
unsigned int tex_mask_old_h;
+
+ int image_size[2];
} BrushPainterCache;
typedef struct BrushPainter {
Scene *scene;
Brush *brush;
- float lastpaintpos[2]; /* position of last paint op */
- float startpaintpos[2]; /* position of first paint */
-
short firsttouch; /* first paint op */
struct ImagePool *pool; /* image pool */
rctf tex_mapping; /* texture coordinate mapping */
rctf mask_mapping; /* mask texture coordinate mapping */
- BrushPainterCache cache;
+ bool cache_invert;
} BrushPainter;
typedef struct ImagePaintRegion {
@@ -108,6 +108,27 @@ typedef struct ImagePaintRegion {
int width, height;
} ImagePaintRegion;
+typedef enum ImagePaintTileState {
+ PAINT2D_TILE_UNINITIALIZED = 0,
+ PAINT2D_TILE_MISSING,
+ PAINT2D_TILE_READY,
+} ImagePaintTileState;
+
+typedef struct ImagePaintTile {
+ ImageUser iuser;
+ ImBuf *canvas;
+ float radius_fac;
+ int size[2];
+ float uv_origin[2]; /* Stores the position of this tile in UV space. */
+ bool need_redraw;
+ BrushPainterCache cache;
+
+ ImagePaintTileState state;
+
+ float last_paintpos[2]; /* position of last paint op */
+ float start_paintpos[2]; /* position of first paint */
+} ImagePaintTile;
+
typedef struct ImagePaintState {
BrushPainter *painter;
SpaceImage *sima;
@@ -119,10 +140,7 @@ typedef struct ImagePaintState {
Brush *brush;
short tool, blend;
Image *image;
- ImBuf *canvas;
ImBuf *clonecanvas;
- const char *warnpackedfile;
- const char *warnmultifile;
bool do_masking;
@@ -133,7 +151,8 @@ typedef struct ImagePaintState {
int do_facesel;
int symmetry;
- bool need_redraw;
+ ImagePaintTile *tiles;
+ int num_tiles;
BlurKernel *blurkernel;
} ImagePaintState;
@@ -145,63 +164,60 @@ static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush, bool inver
painter->brush = brush;
painter->scene = scene;
painter->firsttouch = 1;
- painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
- painter->cache.invert = invert;
+ painter->cache_invert = invert;
return painter;
}
-static void brush_painter_2d_require_imbuf(BrushPainter *painter,
- bool use_float,
- bool use_color_correction)
+static void brush_painter_2d_require_imbuf(
+ Brush *brush, ImagePaintTile *tile, bool use_float, bool use_color_correction, bool invert)
{
- Brush *brush = painter->brush;
+ BrushPainterCache *cache = &tile->cache;
- if ((painter->cache.use_float != use_float)) {
- if (painter->cache.ibuf) {
- IMB_freeImBuf(painter->cache.ibuf);
+ if ((cache->use_float != use_float)) {
+ if (cache->ibuf) {
+ IMB_freeImBuf(cache->ibuf);
}
- if (painter->cache.curve_mask) {
- MEM_freeN(painter->cache.curve_mask);
+ if (cache->curve_mask) {
+ MEM_freeN(cache->curve_mask);
}
- if (painter->cache.tex_mask) {
- MEM_freeN(painter->cache.tex_mask);
+ if (cache->tex_mask) {
+ MEM_freeN(cache->tex_mask);
}
- if (painter->cache.tex_mask_old) {
- MEM_freeN(painter->cache.tex_mask_old);
+ if (cache->tex_mask_old) {
+ MEM_freeN(cache->tex_mask_old);
}
- painter->cache.ibuf = NULL;
- painter->cache.curve_mask = NULL;
- painter->cache.tex_mask = NULL;
- painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
- }
-
- painter->cache.use_float = use_float;
- painter->cache.use_color_correction = use_float && use_color_correction;
- painter->cache.is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ?
- true :
- false;
- painter->cache.is_maskbrush = (brush->mask_mtex.tex) ? true : false;
+ cache->ibuf = NULL;
+ cache->curve_mask = NULL;
+ cache->tex_mask = NULL;
+ cache->lastdiameter = -1; /* force ibuf create in refresh */
+ cache->invert = invert;
+ }
+
+ cache->use_float = use_float;
+ cache->use_color_correction = use_float && use_color_correction;
+ cache->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true :
+ false;
+ cache->is_maskbrush = (brush->mask_mtex.tex) ? true : false;
}
-static void brush_painter_2d_free(BrushPainter *painter)
+static void brush_painter_cache_2d_free(BrushPainterCache *cache)
{
- if (painter->cache.ibuf) {
- IMB_freeImBuf(painter->cache.ibuf);
+ if (cache->ibuf) {
+ IMB_freeImBuf(cache->ibuf);
}
- if (painter->cache.texibuf) {
- IMB_freeImBuf(painter->cache.texibuf);
+ if (cache->texibuf) {
+ IMB_freeImBuf(cache->texibuf);
}
- if (painter->cache.curve_mask) {
- MEM_freeN(painter->cache.curve_mask);
+ if (cache->curve_mask) {
+ MEM_freeN(cache->curve_mask);
}
- if (painter->cache.tex_mask) {
- MEM_freeN(painter->cache.tex_mask);
+ if (cache->tex_mask) {
+ MEM_freeN(cache->tex_mask);
}
- if (painter->cache.tex_mask_old) {
- MEM_freeN(painter->cache.tex_mask_old);
+ if (cache->tex_mask_old) {
+ MEM_freeN(cache->tex_mask_old);
}
- MEM_freeN(painter);
}
static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
@@ -212,7 +228,7 @@ static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
}
/* create a mask with the mask texture */
-static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int size)
+static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, const int size)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
@@ -240,6 +256,7 @@ static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int si
/* update rectangular section of the brush image */
static void brush_painter_mask_imbuf_update(BrushPainter *painter,
+ ImagePaintTile *tile,
unsigned short *tex_mask_old,
int origx,
int origy,
@@ -247,10 +264,11 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
int h,
int xt,
int yt,
- int diameter)
+ const int diameter)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
+ BrushPainterCache *cache = &tile->cache;
rctf tex_mapping = painter->mask_mapping;
struct ImagePool *pool = painter->pool;
unsigned short res;
@@ -259,8 +277,8 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
int x, y, thread = 0;
- unsigned short *tex_mask = painter->cache.tex_mask;
- unsigned short *tex_mask_cur = painter->cache.tex_mask_old;
+ unsigned short *tex_mask = cache->tex_mask;
+ unsigned short *tex_mask_cur = cache->tex_mask_old;
/* fill pixels */
for (y = origy; y < h; y++) {
@@ -280,8 +298,7 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
/* read from old texture buffer */
if (use_texture_old) {
- res = *(tex_mask_old +
- ((y - origy + yt) * painter->cache.tex_mask_old_w + (x - origx + xt)));
+ res = *(tex_mask_old + ((y - origy + yt) * cache->tex_mask_old_w + (x - origx + xt)));
}
/* write to new texture mask */
@@ -298,10 +315,11 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
* textures that stick to the surface where only part of the pixels are new
*/
static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
+ ImagePaintTile *tile,
const float pos[2],
- int diameter)
+ const int diameter)
{
- BrushPainterCache *cache = &painter->cache;
+ BrushPainterCache *cache = &tile->cache;
unsigned short *tex_mask_old;
int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
@@ -319,15 +337,16 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
if (tex_mask_old) {
ImBuf maskibuf;
ImBuf maskibuf_old;
- maskibuf.x = maskibuf.y = diameter;
+ maskibuf.x = diameter;
+ maskibuf.y = diameter;
maskibuf_old.x = cache->tex_mask_old_w;
maskibuf_old.y = cache->tex_mask_old_h;
srcx = srcy = 0;
w = cache->tex_mask_old_w;
h = cache->tex_mask_old_h;
- destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
- desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
+ destx = (int)floorf(tile->last_paintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
+ desty = (int)floorf(tile->last_paintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
/* hack, use temporary rects so that clipping works */
IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h);
@@ -345,7 +364,8 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
/* blend existing texture in new position */
if ((x1 < x2) && (y1 < y2)) {
- brush_painter_mask_imbuf_update(painter, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);
+ brush_painter_mask_imbuf_update(
+ painter, tile, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);
}
if (tex_mask_old) {
@@ -354,16 +374,17 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
/* sample texture in new areas */
if ((0 < x1) && (0 < diameter)) {
- brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter);
+ brush_painter_mask_imbuf_update(painter, tile, NULL, 0, 0, x1, diameter, 0, 0, diameter);
}
if ((x2 < diameter) && (0 < diameter)) {
- brush_painter_mask_imbuf_update(painter, NULL, x2, 0, diameter, diameter, 0, 0, diameter);
+ brush_painter_mask_imbuf_update(
+ painter, tile, NULL, x2, 0, diameter, diameter, 0, 0, diameter);
}
if ((x1 < x2) && (0 < y1)) {
- brush_painter_mask_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0, diameter);
+ brush_painter_mask_imbuf_update(painter, tile, NULL, x1, 0, x2, y1, 0, 0, diameter);
}
if ((x1 < x2) && (y2 < diameter)) {
- brush_painter_mask_imbuf_update(painter, NULL, x1, y2, x2, diameter, 0, 0, diameter);
+ brush_painter_mask_imbuf_update(painter, tile, NULL, x1, y2, x2, diameter, 0, 0, diameter);
}
/* through with sampling, now update sizes */
@@ -445,13 +466,12 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
}
/* create imbuf with brush color */
-static ImBuf *brush_painter_imbuf_new(BrushPainter *painter,
- int size,
- float pressure,
- float distance)
+static ImBuf *brush_painter_imbuf_new(
+ BrushPainter *painter, ImagePaintTile *tile, const int size, float pressure, float distance)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
+ BrushPainterCache *cache = &tile->cache;
const char *display_device = scene->display_settings.display_device;
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
@@ -459,9 +479,9 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter,
rctf tex_mapping = painter->tex_mapping;
struct ImagePool *pool = painter->pool;
- bool use_color_correction = painter->cache.use_color_correction;
- bool use_float = painter->cache.use_float;
- bool is_texbrush = painter->cache.is_texbrush;
+ bool use_color_correction = cache->use_color_correction;
+ bool use_float = cache->use_float;
+ bool is_texbrush = cache->is_texbrush;
int x, y, thread = 0;
float brush_rgb[3];
@@ -471,14 +491,8 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter,
/* get brush color */
if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
- paint_brush_color_get(scene,
- brush,
- use_color_correction,
- painter->cache.invert,
- distance,
- pressure,
- brush_rgb,
- display);
+ paint_brush_color_get(
+ scene, brush, use_color_correction, cache->invert, distance, pressure, brush_rgb, display);
}
else {
brush_rgb[0] = 1.0f;
@@ -526,11 +540,19 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter,
}
/* update rectangular section of the brush image */
-static void brush_painter_imbuf_update(
- BrushPainter *painter, ImBuf *oldtexibuf, int origx, int origy, int w, int h, int xt, int yt)
+static void brush_painter_imbuf_update(BrushPainter *painter,
+ ImagePaintTile *tile,
+ ImBuf *oldtexibuf,
+ int origx,
+ int origy,
+ int w,
+ int h,
+ int xt,
+ int yt)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
+ BrushPainterCache *cache = &tile->cache;
const char *display_device = scene->display_settings.display_device;
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
@@ -538,21 +560,21 @@ static void brush_painter_imbuf_update(
rctf tex_mapping = painter->tex_mapping;
struct ImagePool *pool = painter->pool;
- bool use_color_correction = painter->cache.use_color_correction;
- bool use_float = painter->cache.use_float;
- bool is_texbrush = painter->cache.is_texbrush;
+ bool use_color_correction = cache->use_color_correction;
+ bool use_float = cache->use_float;
+ bool is_texbrush = cache->is_texbrush;
bool use_texture_old = (oldtexibuf != NULL);
int x, y, thread = 0;
float brush_rgb[3];
- ImBuf *ibuf = painter->cache.ibuf;
- ImBuf *texibuf = painter->cache.texibuf;
+ ImBuf *ibuf = cache->ibuf;
+ ImBuf *texibuf = cache->texibuf;
/* get brush color */
if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
paint_brush_color_get(
- scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, brush_rgb, display);
+ scene, brush, use_color_correction, cache->invert, 0.0, 1.0, brush_rgb, display);
}
else {
brush_rgb[0] = 1.0f;
@@ -641,10 +663,11 @@ static void brush_painter_imbuf_update(
* can be considerably faster for brushes that change size due to pressure or
* textures that stick to the surface where only part of the pixels are new */
static void brush_painter_imbuf_partial_update(BrushPainter *painter,
+ ImagePaintTile *tile,
const float pos[2],
- int diameter)
+ const int diameter)
{
- BrushPainterCache *cache = &painter->cache;
+ BrushPainterCache *cache = &tile->cache;
ImBuf *oldtexibuf, *ibuf;
int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
@@ -663,8 +686,8 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter,
srcx = srcy = 0;
w = oldtexibuf->x;
h = oldtexibuf->y;
- destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
- desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
+ destx = (int)floorf(tile->last_paintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
+ desty = (int)floorf(tile->last_paintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
}
@@ -681,7 +704,7 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter,
/* blend existing texture in new position */
if ((x1 < x2) && (y1 < y2)) {
- brush_painter_imbuf_update(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy);
+ brush_painter_imbuf_update(painter, tile, oldtexibuf, x1, y1, x2, y2, srcx, srcy);
}
if (oldtexibuf) {
@@ -690,29 +713,30 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter,
/* sample texture in new areas */
if ((0 < x1) && (0 < ibuf->y)) {
- brush_painter_imbuf_update(painter, NULL, 0, 0, x1, ibuf->y, 0, 0);
+ brush_painter_imbuf_update(painter, tile, NULL, 0, 0, x1, ibuf->y, 0, 0);
}
if ((x2 < ibuf->x) && (0 < ibuf->y)) {
- brush_painter_imbuf_update(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0);
+ brush_painter_imbuf_update(painter, tile, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0);
}
if ((x1 < x2) && (0 < y1)) {
- brush_painter_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0);
+ brush_painter_imbuf_update(painter, tile, NULL, x1, 0, x2, y1, 0, 0);
}
if ((x1 < x2) && (y2 < ibuf->y)) {
- brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0);
+ brush_painter_imbuf_update(painter, tile, NULL, x1, y2, x2, ibuf->y, 0, 0);
}
}
static void brush_painter_2d_tex_mapping(ImagePaintState *s,
- int diameter,
+ ImBuf *canvas,
+ const int diameter,
const float startpos[2],
const float pos[2],
const float mouse[2],
int mapmode,
rctf *mapping)
{
- float invw = 1.0f / (float)s->canvas->x;
- float invh = 1.0f / (float)s->canvas->y;
+ float invw = 1.0f / (float)canvas->x;
+ float invh = 1.0f / (float)canvas->y;
int xmin, ymin, xmax, ymax;
int ipos[2];
@@ -756,6 +780,7 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s,
static void brush_painter_2d_refresh_cache(ImagePaintState *s,
BrushPainter *painter,
+ ImagePaintTile *tile,
const float pos[2],
const float mouse[2],
float pressure,
@@ -765,7 +790,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
const Scene *scene = painter->scene;
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Brush *brush = painter->brush;
- BrushPainterCache *cache = &painter->cache;
+ BrushPainterCache *cache = &tile->cache;
/* Adding 4 pixels of padding for brush antialiasing */
const int diameter = MAX2(1, size * 2) + 4;
@@ -782,7 +807,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
painter->pool = BKE_image_pool_new();
/* determine how can update based on textures used */
- if (painter->cache.is_texbrush) {
+ if (cache->is_texbrush) {
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
tex_rotation += ups->brush_rotation;
}
@@ -794,15 +819,16 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
brush_painter_2d_tex_mapping(s,
+ tile->canvas,
diameter,
- painter->startpaintpos,
+ tile->start_paintpos,
pos,
mouse,
brush->mtex.brush_map_mode,
&painter->tex_mapping);
}
- if (painter->cache.is_maskbrush) {
+ if (cache->is_maskbrush) {
bool renew_maxmask = false;
bool do_partial_update_mask = false;
/* invalidate case for all mapping modes */
@@ -822,7 +848,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
renew_maxmask = true;
}
- if ((diameter != cache->lastdiameter) || (mask_rotation != cache->last_mask_rotation) ||
+ if (diameter != cache->lastdiameter || (mask_rotation != cache->last_mask_rotation) ||
renew_maxmask) {
if (cache->tex_mask) {
MEM_freeN(cache->tex_mask);
@@ -830,15 +856,16 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
brush_painter_2d_tex_mapping(s,
+ tile->canvas,
diameter,
- painter->startpaintpos,
+ tile->start_paintpos,
pos,
mouse,
brush->mask_mtex.brush_map_mode,
&painter->mask_mapping);
if (do_partial_update_mask) {
- brush_painter_mask_imbuf_partial_update(painter, pos, diameter);
+ brush_painter_mask_imbuf_partial_update(painter, tile, pos, diameter);
}
else {
cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter);
@@ -856,8 +883,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos);
/* detect if we need to recreate image brush buffer */
- if ((diameter != cache->lastdiameter) || (tex_rotation != cache->last_tex_rotation) ||
- do_random || update_color) {
+ if (diameter != cache->lastdiameter || (tex_rotation != cache->last_tex_rotation) || do_random ||
+ update_color) {
if (cache->ibuf) {
IMB_freeImBuf(cache->ibuf);
cache->ibuf = NULL;
@@ -865,11 +892,11 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
if (do_partial_update) {
/* do partial update of texture */
- brush_painter_imbuf_partial_update(painter, pos, diameter);
+ brush_painter_imbuf_partial_update(painter, tile, pos, diameter);
}
else {
/* create brush from scratch */
- cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance);
+ cache->ibuf = brush_painter_imbuf_new(painter, tile, diameter, pressure, distance);
}
cache->lastdiameter = diameter;
@@ -878,11 +905,11 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
else if (do_partial_update) {
/* do only partial update of texture */
- int dx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]);
- int dy = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]);
+ int dx = (int)floorf(tile->last_paintpos[0]) - (int)floorf(pos[0]);
+ int dy = (int)floorf(tile->last_paintpos[1]) - (int)floorf(pos[1]);
if ((dx != 0) || (dy != 0)) {
- brush_painter_imbuf_partial_update(painter, pos, diameter);
+ brush_painter_imbuf_partial_update(painter, tile, pos, diameter);
}
}
@@ -890,6 +917,56 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
painter->pool = NULL;
}
+static bool paint_2d_ensure_tile_canvas(ImagePaintState *s, int i)
+{
+ if (i == 0) {
+ return true;
+ }
+ if (i >= s->num_tiles) {
+ return false;
+ }
+
+ if (s->tiles[i].state == PAINT2D_TILE_READY) {
+ return true;
+ }
+ if (s->tiles[i].state == PAINT2D_TILE_MISSING) {
+ return false;
+ }
+
+ s->tiles[i].cache.lastdiameter = -1;
+
+ s->tiles[i].iuser.ok = true;
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &s->tiles[i].iuser, NULL);
+ if (ibuf != NULL) {
+ if (ibuf->channels != 4) {
+ s->tiles[i].state = PAINT2D_TILE_MISSING;
+ }
+ else if ((s->tiles[0].canvas->rect && !ibuf->rect) ||
+ (s->tiles[0].canvas->rect_float && !ibuf->rect_float)) {
+ s->tiles[i].state = PAINT2D_TILE_MISSING;
+ }
+ else {
+ s->tiles[i].size[0] = ibuf->x;
+ s->tiles[i].size[1] = ibuf->y;
+ s->tiles[i].radius_fac = sqrtf(((float)ibuf->x * (float)ibuf->y) /
+ (s->tiles[0].size[0] * s->tiles[0].size[1]));
+ s->tiles[i].state = PAINT2D_TILE_READY;
+ }
+ }
+ else {
+ s->tiles[i].state = PAINT2D_TILE_MISSING;
+ }
+
+ if (s->tiles[i].state == PAINT2D_TILE_MISSING) {
+ BKE_image_release_ibuf(s->image, ibuf, NULL);
+ return false;
+ }
+
+ s->tiles[i].canvas = ibuf;
+ return true;
+}
+
/* keep these functions in sync */
static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
{
@@ -935,15 +1012,15 @@ static void paint_2d_ibuf_rgb_set(
}
}
-static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short tile)
+static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short paint_tile)
{
- if (tile & PAINT_TILE_X) {
+ if (paint_tile & PAINT_TILE_X) {
*x %= ibuf->x;
if (*x < 0) {
*x += ibuf->x;
}
}
- if (tile & PAINT_TILE_Y) {
+ if (paint_tile & PAINT_TILE_Y) {
*y %= ibuf->y;
if (*y < 0) {
*y += ibuf->y;
@@ -951,12 +1028,13 @@ static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short tile)
}
}
-static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, short tile, float w)
+static float paint_2d_ibuf_add_if(
+ ImBuf *ibuf, int x, int y, float *outrgb, short paint_tile, float w)
{
float inrgb[4];
- if (tile) {
- paint_2d_ibuf_tile_convert(ibuf, &x, &y, tile);
+ if (paint_tile) {
+ paint_2d_ibuf_tile_convert(ibuf, &x, &y, paint_tile);
}
/* need to also do clipping here always since tiled coordinates
* are not always within bounds */
@@ -973,10 +1051,14 @@ static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, shor
return w;
}
-static void paint_2d_lift_soften(
- ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short tile)
+static void paint_2d_lift_soften(ImagePaintState *s,
+ ImagePaintTile *tile,
+ ImBuf *ibuf,
+ ImBuf *ibufb,
+ int *pos,
+ const short paint_tile)
{
- bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
+ bool sharpen = (tile->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
float threshold = s->brush->sharp_threshold;
int x, y, xi, yi, xo, yo, xk, yk;
float count;
@@ -992,7 +1074,7 @@ static void paint_2d_lift_soften(
in_off[1] = pos[1];
out_off[0] = out_off[1] = 0;
- if (!tile) {
+ if (!paint_tile) {
IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0], &out_off[1], &dim[0], &dim[1]);
if ((dim[0] == 0) || (dim[1] == 0)) {
@@ -1010,8 +1092,8 @@ static void paint_2d_lift_soften(
yi = in_off[1] + y;
count = 0.0;
- if (tile) {
- paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
+ if (paint_tile) {
+ paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, paint_tile);
if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0) {
paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
}
@@ -1031,7 +1113,7 @@ static void paint_2d_lift_soften(
xi + xk - kernel->pixel_len,
yi + yk - kernel->pixel_len,
outrgb,
- tile,
+ paint_tile,
kernel->wdata[xk + yk * kernel->side]);
}
}
@@ -1085,7 +1167,7 @@ static void paint_2d_set_region(
static int paint_2d_torus_split_region(ImagePaintRegion region[4],
ImBuf *dbuf,
ImBuf *sbuf,
- short tile)
+ short paint_tile)
{
int destx = region->destx;
int desty = region->desty;
@@ -1096,7 +1178,7 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4],
int origw, origh, w, h, tot = 0;
/* convert destination and source coordinates to be within image */
- if (tile & PAINT_TILE_X) {
+ if (paint_tile & PAINT_TILE_X) {
destx = destx % dbuf->x;
if (destx < 0) {
destx += dbuf->x;
@@ -1106,7 +1188,7 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4],
srcx += sbuf->x;
}
}
- if (tile & PAINT_TILE_Y) {
+ if (paint_tile & PAINT_TILE_Y) {
desty = desty % dbuf->y;
if (desty < 0) {
desty += dbuf->y;
@@ -1126,15 +1208,15 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4],
paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
/* do 3 other rects if needed */
- if ((tile & PAINT_TILE_X) && w < origw) {
+ if ((paint_tile & PAINT_TILE_X) && w < origw) {
paint_2d_set_region(
&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
}
- if ((tile & PAINT_TILE_Y) && h < origh) {
+ if ((paint_tile & PAINT_TILE_Y) && h < origh) {
paint_2d_set_region(
&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
}
- if ((tile & PAINT_TILE_X) && (tile & PAINT_TILE_Y) && (w < origw) && (h < origh)) {
+ if ((paint_tile & PAINT_TILE_X) && (paint_tile & PAINT_TILE_Y) && (w < origw) && (h < origh)) {
paint_2d_set_region(&region[tot++],
(destx + w) % dbuf->x,
(desty + h) % dbuf->y,
@@ -1147,13 +1229,13 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4],
return tot;
}
-static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short tile)
+static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short paint_tile)
{
ImagePaintRegion region[4];
int a, tot;
paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
- tot = paint_2d_torus_split_region(region, ibufb, ibuf, tile);
+ tot = paint_2d_torus_split_region(region, ibufb, ibuf, paint_tile);
for (a = 0; a < tot; a++) {
IMB_rectblend(ibufb,
@@ -1229,9 +1311,8 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[
}
static void paint_2d_do_making_brush(ImagePaintState *s,
+ ImagePaintTile *tile,
ImagePaintRegion *region,
- unsigned short *curveb,
- unsigned short *texmaskb,
ImBuf *frombuf,
float mask_max,
short blend,
@@ -1252,21 +1333,21 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
int origx = region->destx - tx * ED_IMAGE_UNDO_TILE_SIZE;
int origy = region->desty - ty * ED_IMAGE_UNDO_TILE_SIZE;
- if (s->canvas->rect_float) {
+ if (tile->canvas->rect_float) {
tmpbuf.rect_float = ED_image_paint_tile_find(
- undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+ undo_tiles, s->image, tile->canvas, tile->iuser.tile, tx, ty, &mask, false);
}
else {
tmpbuf.rect = ED_image_paint_tile_find(
- undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+ undo_tiles, s->image, tile->canvas, tile->iuser.tile, tx, ty, &mask, false);
}
- IMB_rectblend(s->canvas,
+ IMB_rectblend(tile->canvas,
&tmpbuf,
frombuf,
mask,
- curveb,
- texmaskb,
+ tile->cache.curve_mask,
+ tile->cache.tex_mask,
mask_max,
region->destx,
region->desty,
@@ -1284,9 +1365,8 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
typedef struct Paint2DForeachData {
ImagePaintState *s;
+ ImagePaintTile *tile;
ImagePaintRegion *region;
- unsigned short *curveb;
- unsigned short *texmaskb;
ImBuf *frombuf;
float mask_max;
short blend;
@@ -1300,9 +1380,8 @@ static void paint_2d_op_foreach_do(void *__restrict data_v,
{
Paint2DForeachData *data = (Paint2DForeachData *)data_v;
paint_2d_do_making_brush(data->s,
+ data->tile,
data->region,
- data->curveb,
- data->texmaskb,
data->frombuf,
data->mask_max,
data->blend,
@@ -1313,16 +1392,16 @@ static void paint_2d_op_foreach_do(void *__restrict data_v,
}
static int paint_2d_op(void *state,
- ImBuf *ibufb,
- unsigned short *curveb,
- unsigned short *texmaskb,
+ ImagePaintTile *tile,
const float lastpos[2],
const float pos[2])
{
ImagePaintState *s = ((ImagePaintState *)state);
ImBuf *clonebuf = NULL, *frombuf;
+ ImBuf *canvas = tile->canvas;
+ ImBuf *ibufb = tile->cache.ibuf;
ImagePaintRegion region[4];
- short tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
+ short paint_tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
short blend = s->blend;
const float *offset = s->brush->clone.offset;
float liftpos[2];
@@ -1334,7 +1413,7 @@ static int paint_2d_op(void *state,
/* lift from canvas */
if (s->tool == PAINT_TOOL_SOFTEN) {
- paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile);
+ paint_2d_lift_soften(s, tile, canvas, ibufb, bpos, paint_tile);
blend = IMB_BLEND_INTERPOLATE;
}
else if (s->tool == PAINT_TOOL_SMEAR) {
@@ -1343,12 +1422,12 @@ static int paint_2d_op(void *state,
}
paint_2d_convert_brushco(ibufb, lastpos, blastpos);
- paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile);
+ paint_2d_lift_smear(canvas, ibufb, blastpos, paint_tile);
blend = IMB_BLEND_INTERPOLATE;
}
else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
- liftpos[0] = pos[0] - offset[0] * s->canvas->x;
- liftpos[1] = pos[1] - offset[1] * s->canvas->y;
+ liftpos[0] = pos[0] - offset[0] * canvas->x;
+ liftpos[1] = pos[1] - offset[1] * canvas->y;
paint_2d_convert_brushco(ibufb, liftpos, bliftpos);
clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos);
@@ -1356,9 +1435,9 @@ static int paint_2d_op(void *state,
frombuf = (clonebuf) ? clonebuf : ibufb;
- if (tile) {
+ if (paint_tile) {
paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
- tot = paint_2d_torus_split_region(region, s->canvas, frombuf, tile);
+ tot = paint_2d_torus_split_region(region, canvas, frombuf, paint_tile);
}
else {
paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
@@ -1368,7 +1447,8 @@ static int paint_2d_op(void *state,
/* blend into canvas */
for (a = 0; a < tot; a++) {
ED_imapaint_dirty_region(s->image,
- s->canvas,
+ canvas,
+ tile->iuser.tile,
region[a].destx,
region[a].desty,
region[a].width,
@@ -1379,7 +1459,7 @@ static int paint_2d_op(void *state,
/* masking, find original pixels tiles from undo buffer to composite over */
int tilex, tiley, tilew, tileh;
- imapaint_region_tiles(s->canvas,
+ imapaint_region_tiles(canvas,
region[a].destx,
region[a].desty,
region[a].width,
@@ -1391,14 +1471,13 @@ static int paint_2d_op(void *state,
if (tiley == tileh) {
paint_2d_do_making_brush(
- s, &region[a], curveb, texmaskb, frombuf, mask_max, blend, tilex, tiley, tilew, tileh);
+ s, tile, &region[a], frombuf, mask_max, blend, tilex, tiley, tilew, tileh);
}
else {
Paint2DForeachData data;
data.s = s;
+ data.tile = tile;
data.region = &region[a];
- data.curveb = curveb;
- data.texmaskb = texmaskb;
data.frombuf = frombuf;
data.mask_max = mask_max;
data.blend = blend;
@@ -1412,12 +1491,12 @@ static int paint_2d_op(void *state,
}
else {
/* no masking, composite brush directly onto canvas */
- IMB_rectblend_threaded(s->canvas,
- s->canvas,
+ IMB_rectblend_threaded(canvas,
+ canvas,
frombuf,
NULL,
- curveb,
- texmaskb,
+ tile->cache.curve_mask,
+ tile->cache.tex_mask,
mask_max,
region[a].destx,
region[a].desty,
@@ -1439,47 +1518,25 @@ static int paint_2d_op(void *state,
return 1;
}
-static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
+static int paint_2d_canvas_set(ImagePaintState *s)
{
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-
- /* verify that we can paint and set canvas */
- if (ima == NULL) {
- return 0;
- }
- else if (BKE_image_has_packedfile(ima) && ima->rr) {
- s->warnpackedfile = ima->id.name + 2;
- return 0;
- }
- else if (ibuf && ibuf->channels != 4) {
- s->warnmultifile = ima->id.name + 2;
- return 0;
- }
- else if (!ibuf || !(ibuf->rect || ibuf->rect_float)) {
- return 0;
- }
-
- s->image = ima;
- s->canvas = ibuf;
-
/* set clone canvas */
if (s->tool == PAINT_TOOL_CLONE) {
- ima = s->brush->clone.image;
- ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
+ Image *ima = s->brush->clone.image;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
BKE_image_release_ibuf(ima, ibuf, NULL);
- BKE_image_release_ibuf(s->image, s->canvas, NULL);
return 0;
}
s->clonecanvas = ibuf;
/* temporarily add float rect for cloning */
- if (s->canvas->rect_float && !s->clonecanvas->rect_float) {
+ if (s->tiles[0].canvas->rect_float && !s->clonecanvas->rect_float) {
IMB_float_from_rect(s->clonecanvas);
}
- else if (!s->canvas->rect_float && !s->clonecanvas->rect) {
+ else if (!s->tiles[0].canvas->rect_float && !s->clonecanvas->rect) {
IMB_rect_from_float(s->clonecanvas);
}
}
@@ -1492,7 +1549,9 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
static void paint_2d_canvas_free(ImagePaintState *s)
{
- BKE_image_release_ibuf(s->image, s->canvas, NULL);
+ for (int i = 0; i < s->num_tiles; i++) {
+ BKE_image_release_ibuf(s->image, s->tiles[i].canvas, NULL);
+ }
BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
if (s->blurkernel) {
@@ -1501,71 +1560,108 @@ static void paint_2d_canvas_free(ImagePaintState *s)
}
}
+static void paint_2d_transform_mouse(View2D *v2d, const float in[2], float out[2])
+{
+ UI_view2d_region_to_view(v2d, in[0], in[1], &out[0], &out[1]);
+}
+
+static bool is_inside_tile(const int size[2], const float pos[2], const float brush[2])
+{
+ return (pos[0] >= -brush[0]) && (pos[0] < size[0] + brush[0]) && (pos[1] >= -brush[1]) &&
+ (pos[1] < size[1] + brush[1]);
+}
+
+static void paint_2d_uv_to_coord(ImagePaintTile *tile, const float uv[2], float coord[2])
+{
+ coord[0] = (uv[0] - tile->uv_origin[0]) * tile->size[0];
+ coord[1] = (uv[1] - tile->uv_origin[1]) * tile->size[1];
+}
+
void paint_2d_stroke(void *ps,
const float prev_mval[2],
const float mval[2],
const bool eraser,
float pressure,
float distance,
- float size)
+ float base_size)
{
- float newuv[2], olduv[2];
+ float new_uv[2], old_uv[2];
ImagePaintState *s = ps;
BrushPainter *painter = s->painter;
- ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
- const bool is_data = (ibuf && ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA);
- if (!ibuf) {
- return;
- }
+ const bool is_data = s->tiles[0].canvas->colormanage_flag & IMB_COLORMANAGE_IS_DATA;
s->blend = s->brush->blend;
if (eraser) {
s->blend = IMB_BLEND_ERASE_ALPHA;
}
- UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]);
- UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &olduv[0], &olduv[1]);
-
- newuv[0] *= ibuf->x;
- newuv[1] *= ibuf->y;
-
- olduv[0] *= ibuf->x;
- olduv[1] *= ibuf->y;
+ UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &new_uv[0], &new_uv[1]);
+ UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &old_uv[0], &old_uv[1]);
+ float last_uv[2], start_uv[2];
+ UI_view2d_region_to_view(s->v2d, 0.0f, 0.0f, &start_uv[0], &start_uv[1]);
if (painter->firsttouch) {
- float startuv[2];
-
- UI_view2d_region_to_view(s->v2d, 0, 0, &startuv[0], &startuv[1]);
-
/* paint exactly once on first touch */
- painter->startpaintpos[0] = startuv[0] * ibuf->x;
- painter->startpaintpos[1] = startuv[1] * ibuf->y;
-
- painter->firsttouch = 0;
- copy_v2_v2(painter->lastpaintpos, newuv);
+ copy_v2_v2(last_uv, new_uv);
}
else {
- copy_v2_v2(painter->lastpaintpos, olduv);
+ copy_v2_v2(last_uv, old_uv);
}
- /* OCIO_TODO: float buffers are now always linear, so always use color correction
- * this should probably be changed when texture painting color space is supported
- */
- brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data);
+ float uv_brush_size[2] = {base_size / s->tiles[0].size[0], base_size / s->tiles[0].size[1]};
- brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size);
+ for (int i = 0; i < s->num_tiles; i++) {
+ ImagePaintTile *tile = &s->tiles[i];
+
+ /* First test: Project brush into UV space, clip against tile. */
+ const int uv_size[2] = {1, 1};
+ float local_new_uv[2], local_old_uv[2];
+ sub_v2_v2v2(local_new_uv, new_uv, tile->uv_origin);
+ sub_v2_v2v2(local_old_uv, old_uv, tile->uv_origin);
+ if (!(is_inside_tile(uv_size, local_new_uv, uv_brush_size) ||
+ is_inside_tile(uv_size, local_old_uv, uv_brush_size))) {
+ continue;
+ }
- if (paint_2d_op(s,
- painter->cache.ibuf,
- painter->cache.curve_mask,
- painter->cache.tex_mask,
- olduv,
- newuv)) {
- s->need_redraw = true;
+ /* Lazy tile loading to get size in pixels. */
+ if (!paint_2d_ensure_tile_canvas(s, i)) {
+ continue;
+ }
+
+ float size = base_size * tile->radius_fac;
+
+ float new_coord[2], old_coord[2];
+ paint_2d_uv_to_coord(tile, new_uv, new_coord);
+ paint_2d_uv_to_coord(tile, old_uv, old_coord);
+ if (painter->firsttouch) {
+ paint_2d_uv_to_coord(tile, start_uv, tile->start_paintpos);
+ }
+ paint_2d_uv_to_coord(tile, last_uv, tile->last_paintpos);
+
+ /* Second check in pixel coordinates. */
+ const float pixel_brush_size[] = {size, size};
+ if (!(is_inside_tile(tile->size, new_coord, pixel_brush_size) ||
+ is_inside_tile(tile->size, old_coord, pixel_brush_size))) {
+ continue;
+ }
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &tile->iuser, NULL);
+
+ /* OCIO_TODO: float buffers are now always linear, so always use color correction
+ * this should probably be changed when texture painting color space is supported
+ */
+ brush_painter_2d_require_imbuf(
+ painter->brush, tile, (ibuf->rect_float != NULL), !is_data, painter->cache_invert);
+
+ brush_painter_2d_refresh_cache(s, painter, tile, new_coord, mval, pressure, distance, size);
+
+ if (paint_2d_op(s, tile, old_coord, new_coord)) {
+ tile->need_redraw = true;
+ }
}
- BKE_image_release_ibuf(s->image, ibuf, NULL);
+ painter->firsttouch = 0;
}
void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
@@ -1588,13 +1684,57 @@ void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
s->image = s->sima->image;
s->symmetry = settings->imapaint.paint.symmetry_flags;
- if (!paint_2d_canvas_set(s, s->image)) {
- if (s->warnmultifile) {
- BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
- }
- if (s->warnpackedfile) {
- BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
- }
+ if (s->image == NULL) {
+ MEM_freeN(s);
+ return NULL;
+ }
+ if (BKE_image_has_packedfile(s->image) && s->image->rr != NULL) {
+ BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
+ MEM_freeN(s);
+ return 0;
+ }
+
+ s->num_tiles = BLI_listbase_count(&s->image->tiles);
+ s->tiles = MEM_callocN(sizeof(ImagePaintTile) * s->num_tiles, "ImagePaintTile");
+ for (int i = 0; i < s->num_tiles; i++) {
+ BKE_imageuser_default(&s->tiles[i].iuser);
+ }
+ s->tiles[0].iuser.ok = true;
+
+ zero_v2(s->tiles[0].uv_origin);
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &s->tiles[0].iuser, NULL);
+ if (ibuf == NULL) {
+ MEM_freeN(s->tiles);
+ MEM_freeN(s);
+ return NULL;
+ }
+
+ if (ibuf->channels != 4) {
+ BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
+ MEM_freeN(s->tiles);
+ MEM_freeN(s);
+ return NULL;
+ }
+
+ s->tiles[0].size[0] = ibuf->x;
+ s->tiles[0].size[1] = ibuf->y;
+ s->tiles[0].radius_fac = 1.0f;
+
+ s->tiles[0].canvas = ibuf;
+ s->tiles[0].state = PAINT2D_TILE_READY;
+
+ /* Initialize offsets here, they're needed for the uv space clip test before lazy-loading the
+ * tile properly. */
+ int tile_idx = 0;
+ for (ImageTile *tile = s->image->tiles.first; tile; tile = tile->next, tile_idx++) {
+ s->tiles[tile_idx].iuser.tile = tile->tile_number;
+ s->tiles[tile_idx].uv_origin[0] = ((tile->tile_number - 1001) % 10);
+ s->tiles[tile_idx].uv_origin[1] = ((tile->tile_number - 1001) / 10);
+ }
+
+ if (!paint_2d_canvas_set(s)) {
+ MEM_freeN(s->tiles);
MEM_freeN(s);
return NULL;
@@ -1616,18 +1756,28 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final)
{
ImagePaintState *s = ps;
- if (s->need_redraw) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
+ bool had_redraw = false;
+ for (int i = 0; i < s->num_tiles; i++) {
+ if (s->tiles[i].need_redraw) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &s->tiles[i].iuser, NULL);
- imapaint_image_update(s->sima, s->image, ibuf, false);
- ED_imapaint_clear_partial_redraw();
+ imapaint_image_update(s->sima, s->image, ibuf, &s->tiles[i].iuser, false);
- BKE_image_release_ibuf(s->image, ibuf, NULL);
+ BKE_image_release_ibuf(s->image, ibuf, NULL);
- s->need_redraw = false;
+ s->tiles[i].need_redraw = false;
+ had_redraw = true;
+ }
}
- else if (!final) {
- return;
+
+ if (had_redraw) {
+ ED_imapaint_clear_partial_redraw();
+ if (s->sima == NULL || !s->sima->lock) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ }
+ else {
+ WM_event_add_notifier(C, NC_IMAGE | NA_PAINTING, s->image);
+ }
}
if (final) {
@@ -1639,14 +1789,6 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final)
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
DEG_id_tag_update(&s->image->id, 0);
}
- else {
- if (!s->sima || !s->sima->lock) {
- ED_region_tag_redraw(CTX_wm_region(C));
- }
- else {
- WM_event_add_notifier(C, NC_IMAGE | NA_PAINTING, s->image);
- }
- }
}
void paint_2d_stroke_done(void *ps)
@@ -1654,7 +1796,11 @@ void paint_2d_stroke_done(void *ps)
ImagePaintState *s = ps;
paint_2d_canvas_free(s);
- brush_painter_2d_free(s->painter);
+ for (int i = 0; i < s->num_tiles; i++) {
+ brush_painter_cache_2d_free(&s->tiles[i].cache);
+ }
+ MEM_freeN(s->painter);
+ MEM_freeN(s->tiles);
paint_brush_exit_tex(s->brush);
MEM_freeN(s);
@@ -1713,9 +1859,29 @@ static void paint_2d_fill_add_pixel_float(const int x_px,
}
}
+static ImageUser *paint_2d_get_tile_iuser(ImagePaintState *s, int tile_number)
+{
+ ImageUser *iuser = &s->tiles[0].iuser;
+ for (int i = 0; i < s->num_tiles; i++) {
+ if (s->tiles[i].iuser.tile == tile_number) {
+ if (!paint_2d_ensure_tile_canvas(s, i)) {
+ return NULL;
+ }
+ iuser = &s->tiles[i].iuser;
+ break;
+ }
+ }
+
+ return iuser;
+}
+
/* this function expects linear space color values */
-void paint_2d_bucket_fill(
- const bContext *C, const float color[3], Brush *br, const float mouse_init[2], void *ps)
+void paint_2d_bucket_fill(const bContext *C,
+ const float color[3],
+ Brush *br,
+ const float mouse_init[2],
+ const float mouse_final[2],
+ void *ps)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = sima->image;
@@ -1734,8 +1900,27 @@ void paint_2d_bucket_fill(
return;
}
- ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+ View2D *v2d = s ? s->v2d : &CTX_wm_region(C)->v2d;
+ float uv_origin[2];
+ float image_init[2];
+ paint_2d_transform_mouse(v2d, mouse_init, image_init);
+
+ int tile_number = BKE_image_get_tile_from_pos(ima, image_init, image_init, uv_origin);
+
+ ImageUser local_iuser, *iuser;
+ if (s != NULL) {
+ iuser = paint_2d_get_tile_iuser(s, tile_number);
+ if (iuser == NULL) {
+ return;
+ }
+ }
+ else {
+ iuser = &local_iuser;
+ BKE_imageuser_default(iuser);
+ iuser->tile = tile_number;
+ }
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (!ibuf) {
return;
}
@@ -1753,9 +1938,9 @@ void paint_2d_bucket_fill(
color_f[3] = strength;
}
- if (!mouse_init || !br) {
+ if (!mouse_final || !br) {
/* first case, no image UV, fill the whole image */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+ ED_imapaint_dirty_region(ima, ibuf, tile_number, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
@@ -1783,15 +1968,12 @@ void paint_2d_bucket_fill(
BLI_bitmap *touched;
size_t coordinate;
int width = ibuf->x;
- float image_init[2];
int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
float pixel_color[4];
/* We are comparing to sum of three squared values
* (assumed in range [0,1]), so need to multiply... */
float threshold_sq = br->fill_threshold * br->fill_threshold * 3;
- UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
-
x_px = image_init[0] * ibuf->x;
y_px = image_init[1] * ibuf->y;
@@ -1801,7 +1983,7 @@ void paint_2d_bucket_fill(
}
/* change image invalidation method later */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+ ED_imapaint_dirty_region(ima, ibuf, tile_number, 0, 0, ibuf->x, ibuf->y, false);
stack = BLI_stack_new(sizeof(size_t), __func__);
touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
@@ -1913,7 +2095,7 @@ void paint_2d_bucket_fill(
BLI_stack_free(stack);
}
- imapaint_image_update(sima, ima, ibuf, false);
+ imapaint_image_update(sima, ima, ibuf, iuser, false);
ED_imapaint_clear_partial_redraw();
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -1938,19 +2120,26 @@ void paint_2d_gradient_fill(
bool do_float;
- if (!ima) {
+ if (ima == NULL) {
return;
}
- ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+ float uv_origin[2];
+ int tile_number = BKE_image_get_tile_from_pos(ima, image_init, image_init, uv_origin);
+ ImageUser *iuser = paint_2d_get_tile_iuser(s, tile_number);
+ if (!iuser) {
+ return;
+ }
- if (!ibuf) {
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ if (ibuf == NULL) {
return;
}
- UI_view2d_region_to_view(
- s->v2d, mouse_final[0], mouse_final[1], &image_final[0], &image_final[1]);
- UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
+ paint_2d_transform_mouse(s->v2d, mouse_final, image_final);
+ paint_2d_transform_mouse(s->v2d, mouse_init, image_init);
+ sub_v2_v2(image_init, uv_origin);
+ sub_v2_v2(image_final, uv_origin);
image_final[0] *= ibuf->x;
image_final[1] *= ibuf->y;
@@ -1967,7 +2156,7 @@ void paint_2d_gradient_fill(
do_float = (ibuf->rect_float != NULL);
/* this will be substituted by something else when selection is available */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+ ED_imapaint_dirty_region(ima, ibuf, tile_number, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
@@ -2027,7 +2216,7 @@ void paint_2d_gradient_fill(
}
}
- imapaint_image_update(sima, ima, ibuf, false);
+ imapaint_image_update(sima, ima, ibuf, iuser, false);
ED_imapaint_clear_partial_redraw();
BKE_image_release_ibuf(ima, ibuf, NULL);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index fa4e250871e..d649f5017eb 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -197,6 +197,7 @@ BLI_INLINE unsigned char f_to_char(const float val)
*/
typedef struct ProjPaintImage {
Image *ima;
+ ImageUser iuser;
ImBuf *ibuf;
ImagePaintPartialRedraw *partRedrawRect;
/** Only used to build undo tiles during painting. */
@@ -530,6 +531,18 @@ BLI_INLINE const MPoly *ps_tri_index_to_mpoly(const ProjPaintState *ps, int tri_
/* Finish projection painting structs */
+static int project_paint_face_paint_tile(Image *ima, const float *uv)
+{
+ if (ima == NULL || ima->source != IMA_SRC_TILED) {
+ return 0;
+ }
+
+ /* Currently, faces are assumed to belong to one tile, so checking the first loop is enough. */
+ int tx = (int)uv[0];
+ int ty = (int)uv[1];
+ return 1001 + 10 * ty + tx;
+}
+
static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
@@ -729,9 +742,13 @@ static bool project_paint_PickColor(const ProjPaintState *ps,
ima = project_paint_face_paint_image(ps, tri_index);
/** we must have got the imbuf before getting here. */
- ibuf = BKE_image_get_first_ibuf(ima);
- if (!ibuf) {
- return 0;
+ int tile_number = project_paint_face_paint_tile(ima, lt_tri_uv[0]);
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile_number;
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ if (ibuf == NULL) {
+ return false;
}
if (interp) {
@@ -887,7 +904,7 @@ static bool project_bucket_point_occluded(const ProjPaintState *ps,
const float pixelScreenCo[4])
{
int isect_ret;
- const bool do_clip = ps->rv3d ? (ps->rv3d->rflag & RV3D_CLIPPING) != 0 : 0;
+ const bool do_clip = RV3D_CLIPPING_ENABLED(ps->v3d, ps->rv3d);
/* we could return 0 for 1 face buckets, as long as this function assumes
* that the point its testing is only every originated from an existing face */
@@ -1154,6 +1171,8 @@ static bool check_seam(const ProjPaintState *ps,
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
Image *tpage = project_paint_face_paint_image(ps, tri_index);
Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
+ int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
+ int orig_tile = project_paint_face_paint_tile(orig_tpage, orig_lt_tri_uv[0]);
BLI_assert(i1_fidx != -1);
@@ -1171,7 +1190,8 @@ static bool check_seam(const ProjPaintState *ps,
}
/* first test if they have the same image */
- if ((orig_tpage == tpage) && cmp_uv(orig_lt_tri_uv[orig_i1_fidx], lt_tri_uv[i1_fidx]) &&
+ if ((orig_tpage == tpage) && (orig_tile == tile) &&
+ cmp_uv(orig_lt_tri_uv[orig_i1_fidx], lt_tri_uv[i1_fidx]) &&
cmp_uv(orig_lt_tri_uv[orig_i2_fidx], lt_tri_uv[i2_fidx])) {
/* if faces don't have the same winding in uv space,
* they are on the same side so edge is boundary */
@@ -1817,6 +1837,7 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
pjIma->ima,
pjIma->ibuf,
tinf->tmpibuf,
+ pjIma->iuser.tile,
tx,
ty,
&pjIma->maskRect[tile_index],
@@ -1829,6 +1850,7 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
pjIma->ima,
pjIma->ibuf,
tinf->tmpibuf,
+ pjIma->iuser.tile,
tx,
ty,
NULL,
@@ -3024,7 +3046,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
const bool is_ortho = ps->is_ortho;
const bool is_flip_object = ps->is_flip_object;
const bool do_backfacecull = ps->do_backfacecull;
- const bool do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
+ const bool do_clip = RV3D_CLIPPING_ENABLED(ps->v3d, ps->rv3d);
vCo[0] = ps->mvert_eval[lt_vtri[0]].co;
vCo[1] = ps->mvert_eval[lt_vtri[1]].co;
@@ -3486,6 +3508,7 @@ static void project_bucket_init(const ProjPaintState *ps,
ImBuf *ibuf = NULL;
Image *tpage_last = NULL, *tpage;
ImBuf *tmpibuf = NULL;
+ int tile_last = 0;
if (ps->image_tot == 1) {
/* Simple loop, no context switching */
@@ -3509,17 +3532,25 @@ static void project_bucket_init(const ProjPaintState *ps,
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
tri_index = POINTER_AS_INT(node->link);
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
+
/* Image context switching */
tpage = project_paint_face_paint_image(ps, tri_index);
- if (tpage_last != tpage) {
+ int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
+ if (tpage_last != tpage || tile_last != tile) {
tpage_last = tpage;
+ tile_last = tile;
+ ibuf = NULL;
for (image_index = 0; image_index < ps->image_tot; image_index++) {
- if (ps->projImages[image_index].ima == tpage_last) {
- ibuf = ps->projImages[image_index].ibuf;
+ ProjPaintImage *projIma = &ps->projImages[image_index];
+ if ((projIma->ima == tpage) && (projIma->iuser.tile == tile)) {
+ ibuf = projIma->ibuf;
break;
}
}
+ BLI_assert(ibuf != NULL);
}
/* context switching done */
@@ -4232,22 +4263,36 @@ static bool project_paint_winclip(const ProjPaintState *ps, const ProjPaintFaceC
}
#endif // PROJ_DEBUG_WINCLIP
+typedef struct PrepareImageEntry {
+ struct PrepareImageEntry *next, *prev;
+ Image *ima;
+ int tile;
+} PrepareImageEntry;
+
static void project_paint_build_proj_ima(ProjPaintState *ps,
MemArena *arena,
- LinkNode *image_LinkList)
+ ListBase *used_images)
{
ProjPaintImage *projIma;
- LinkNode *node;
+ PrepareImageEntry *entry;
int i;
/* build an array of images we use */
projIma = ps->projImages = BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
- for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) {
+ for (entry = used_images->first, i = 0; entry; entry = entry->next, i++, projIma++) {
+ memset(&projIma->iuser, 0, sizeof(ImageUser));
+ BKE_imageuser_default(&projIma->iuser);
+ projIma->iuser.tile = entry->tile;
int size;
- projIma->ima = node->link;
+ projIma->ima = entry->ima;
projIma->touch = 0;
- projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
+ projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, &projIma->iuser, NULL);
+ if (projIma->ibuf == NULL) {
+ projIma->iuser.tile = 0;
+ projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, &projIma->iuser, NULL);
+ BLI_assert(projIma->ibuf != NULL);
+ }
size = sizeof(void **) * ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->x) *
ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->y);
projIma->partRedrawRect = BLI_memarena_alloc(
@@ -4270,15 +4315,18 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
const bool is_multi_view)
{
/* Image Vars - keep track of images we have used */
- LinkNodePair image_LinkList = {NULL, NULL};
+ ListBase used_images = {NULL};
Image *tpage_last = NULL, *tpage;
TexPaintSlot *slot_last = NULL;
TexPaintSlot *slot = NULL;
+ int tile_last = -1, tile;
const MLoopTri *lt;
int image_index = -1, tri_index;
int prev_poly = -1;
+ BLI_assert(ps->image_tot == 0);
+
for (tri_index = 0, lt = ps->mlooptri_eval; tri_index < ps->totlooptri_eval; tri_index++, lt++) {
bool is_face_sel;
bool skip_tri = false;
@@ -4321,6 +4369,8 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
ps->poly_to_loop_uv[lt->poly] = mloopuv_base;
+ tile = project_paint_face_paint_tile(tpage, mloopuv_base[lt->tri[0]].uv);
+
#ifndef PROJ_DEBUG_NOSEAMBLEED
project_paint_bleed_add_face_user(ps, arena, lt, tri_index);
#endif
@@ -4382,18 +4432,32 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
}
}
- if (tpage_last != tpage) {
-
- image_index = BLI_linklist_index(image_LinkList.list, tpage);
+ if (tpage_last != tpage || tile_last != tile) {
+ image_index = 0;
+ for (PrepareImageEntry *e = used_images.first; e; e = e->next, image_index++) {
+ if (e->ima == tpage && e->tile == tile) {
+ break;
+ }
+ }
- if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) {
- /* MemArena doesn't have an append func */
- BLI_linklist_append(&image_LinkList, tpage);
- image_index = ps->image_tot;
- ps->image_tot++;
+ if (image_index == ps->image_tot) {
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile;
+ if (BKE_image_has_ibuf(tpage, &iuser)) {
+ PrepareImageEntry *e = MEM_callocN(sizeof(PrepareImageEntry), "PrepareImageEntry");
+ e->ima = tpage;
+ e->tile = tile;
+ BLI_addtail(&used_images, e);
+ ps->image_tot++;
+ }
+ else {
+ image_index = -1;
+ }
}
tpage_last = tpage;
+ tile_last = tile;
}
if (image_index != -1) {
@@ -4406,11 +4470,11 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
/* build an array of images we use*/
if (ps->is_shared_user == false) {
- project_paint_build_proj_ima(ps, arena, image_LinkList.list);
+ project_paint_build_proj_ima(ps, arena, &used_images);
}
/* we have built the array, discard the linked list */
- BLI_linklist_free(image_LinkList.list, NULL);
+ BLI_freelistN(&used_images);
}
/* run once per stroke before projection painting */
@@ -4675,7 +4739,7 @@ static bool project_image_refresh_tagged(ProjPaintState *ps)
pr = &(projIma->partRedrawRect[i]);
if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
set_imapaintpartial(pr);
- imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
+ imapaint_image_update(NULL, projIma->ima, projIma->ibuf, &projIma->iuser, true);
redraw = 1;
}
@@ -6209,7 +6273,6 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
h,
IB_rect,
R_ALPHAPREMUL,
- 0,
NULL,
NULL,
err_out);
@@ -6442,7 +6505,8 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
gen_type,
color,
false,
- is_data);
+ is_data,
+ false); /* TODO(lukas): Add option */
return ima;
}
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 84665728e17..53beb981522 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -186,6 +186,7 @@ bool image_texture_paint_poll(struct bContext *C);
void imapaint_image_update(struct SpaceImage *sima,
struct Image *image,
struct ImBuf *ibuf,
+ struct ImageUser *iuser,
short texpaint);
struct ImagePaintPartialRedraw *get_imapaintpartial(void);
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
@@ -206,6 +207,7 @@ void paint_2d_bucket_fill(const struct bContext *C,
const float color[3],
struct Brush *br,
const float mouse_init[2],
+ const float mouse_final[2],
void *ps);
void paint_2d_gradient_fill(const struct bContext *C,
struct Brush *br,
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index ee359def68c..372ea954630 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -335,8 +335,9 @@ static bool paint_brush_update(bContext *C,
ups->size_pressure_value = stroke->cached_size_pressure;
ups->pixel_radius = BKE_brush_size_get(scene, brush);
+ ups->initial_pixel_radius = BKE_brush_size_get(scene, brush);
- if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, mode)) {
+ if (BKE_brush_use_size_pressure(brush) && paint_supports_dynamic_size(brush, mode)) {
ups->pixel_radius *= stroke->cached_size_pressure;
}
@@ -527,8 +528,8 @@ static void paint_brush_stroke_add_step(bContext *C,
* windows for some tablets, then we just skip first touch .. */
if (tablet && (pressure >= 0.99f) &&
((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
- BKE_brush_use_alpha_pressure(scene, pop->s.brush) ||
- BKE_brush_use_size_pressure(scene, pop->s.brush))) {
+ BKE_brush_use_alpha_pressure(pop->s.brush) ||
+ BKE_brush_use_size_pressure(pop->s.brush))) {
return;
}
@@ -540,8 +541,8 @@ static void paint_brush_stroke_add_step(bContext *C,
* which is the sensitivity of the most sensitive pen tablet available */
if (tablet && (pressure < 0.0002f) &&
((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
- BKE_brush_use_alpha_pressure(scene, pop->s.brush) ||
- BKE_brush_use_size_pressure(scene, pop->s.brush))) {
+ BKE_brush_use_alpha_pressure(pop->s.brush) ||
+ BKE_brush_use_size_pressure(pop->s.brush))) {
return;
}
#endif
@@ -756,7 +757,7 @@ static float paint_space_stroke_spacing_variable(bContext *C,
float dpressure,
float length)
{
- if (BKE_brush_use_size_pressure(scene, stroke->brush)) {
+ if (BKE_brush_use_size_pressure(stroke->brush)) {
/* use pressure to modify size. set spacing so that at 100%, the circles
* are aligned nicely with no overlap. for this the spacing needs to be
* the average of the previous and next size. */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index ac7cf310099..cafdd72c7cd 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -1522,7 +1522,7 @@ static void vwpaint_update_cache_variants(bContext *C, VPaint *vp, Object *ob, P
}
}
- if (BKE_brush_use_size_pressure(scene, brush) &&
+ if (BKE_brush_use_size_pressure(brush) &&
paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT)) {
cache->radius = cache->initial_radius * cache->pressure;
}
@@ -1684,11 +1684,9 @@ static void get_brush_alpha_data(const Scene *scene,
float *r_brush_alpha_pressure)
{
*r_brush_size_pressure = BKE_brush_size_get(scene, brush) *
- (BKE_brush_use_size_pressure(scene, brush) ? ss->cache->pressure :
- 1.0f);
+ (BKE_brush_use_size_pressure(brush) ? ss->cache->pressure : 1.0f);
*r_brush_alpha_value = BKE_brush_alpha_get(scene, brush);
- *r_brush_alpha_pressure = (BKE_brush_use_alpha_pressure(scene, brush) ? ss->cache->pressure :
- 1.0f);
+ *r_brush_alpha_pressure = (BKE_brush_use_alpha_pressure(brush) ? ss->cache->pressure : 1.0f);
}
static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintInfo *wpi)
@@ -2341,7 +2339,9 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, ss->cache->true_location);
+ float loc_world[3];
+ mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location);
+ paint_last_stroke_update(scene, loc_world);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -3316,7 +3316,9 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, ss->cache->true_location);
+ float loc_world[3];
+ mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location);
+ paint_last_stroke_update(scene, loc_world);
ED_region_tag_redraw(vc->ar);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 2e98d463945..10772fa68ba 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -48,6 +48,7 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_image.h"
+#include "BKE_kelvinlet.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -107,6 +108,7 @@ static void sculpt_vertex_random_access_init(SculptSession *ss)
{
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
+ BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
}
}
@@ -1011,6 +1013,7 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar, Object *ob)
void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{
RegionView3D *rv3d = ss->cache ? ss->cache->vc->rv3d : ss->rv3d;
+ View3D *v3d = ss->cache ? ss->cache->vc->v3d : ss->v3d;
test->radius_squared = ss->cache ? ss->cache->radius_squared :
ss->cursor_radius * ss->cursor_radius;
@@ -1031,7 +1034,7 @@ void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
test->mirror_symmetry_pass = ss->cache ? ss->cache->mirror_symmetry_pass : 0;
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
test->clip_rv3d = rv3d;
}
else {
@@ -1723,7 +1726,7 @@ static float brush_strength(const Sculpt *sd,
const float root_alpha = BKE_brush_alpha_get(scene, brush);
float alpha = root_alpha * root_alpha;
float dir = (brush->flag & BRUSH_DIR_IN) ? -1 : 1;
- float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1;
+ float pressure = BKE_brush_use_alpha_pressure(brush) ? cache->pressure : 1;
float pen_flip = cache->pen_flip ? -1 : 1;
float invert = cache->invert ? -1 : 1;
float overlap = ups->overlap_factor;
@@ -1740,8 +1743,9 @@ static float brush_strength(const Sculpt *sd,
switch (brush->sculpt_tool) {
case SCULPT_TOOL_CLAY:
+ final_pressure = pow4f(pressure);
overlap = (1.0f + overlap) / 2.0f;
- return 0.25f * alpha * flip * pressure * overlap * feather;
+ return 0.25f * alpha * flip * final_pressure * overlap * feather;
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_DRAW_SHARP:
case SCULPT_TOOL_LAYER:
@@ -2631,152 +2635,48 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
- SculptDoBrushSmoothGridDataChunk *data_chunk = tls->userdata_chunk;
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
const Brush *brush = data->brush;
const bool smooth_mask = data->smooth_mask;
float bstrength = data->strength;
- CCGElem **griddata, *gddata;
-
- float(*tmpgrid_co)[3] = NULL;
- float tmprow_co[2][3];
- float *tmpgrid_mask = NULL;
- float tmprow_mask[2];
+ PBVHVertexIter vd;
- BLI_bitmap *const *grid_hidden;
- int *grid_indices, totgrid, gridsize;
- int i, x, y;
+ CLAMP(bstrength, 0.0f, 1.0f);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
- CLAMP(bstrength, 0.0f, 1.0f);
-
- BKE_pbvh_node_get_grids(
- ss->pbvh, data->nodes[n], &grid_indices, &totgrid, NULL, &gridsize, &griddata);
- CCGKey key = *BKE_pbvh_get_grid_key(ss->pbvh);
-
- grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
-
- if (smooth_mask) {
- tmpgrid_mask = (void *)(data_chunk + 1);
- }
- else {
- tmpgrid_co = (void *)(data_chunk + 1);
- }
-
- for (i = 0; i < totgrid; i++) {
- int gi = grid_indices[i];
- const BLI_bitmap *gh = grid_hidden[gi];
- gddata = griddata[gi];
-
- if (smooth_mask) {
- memset(tmpgrid_mask, 0, data_chunk->tmpgrid_size);
- }
- else {
- memset(tmpgrid_co, 0, data_chunk->tmpgrid_size);
- }
-
- for (y = 0; y < gridsize - 1; y++) {
- const int v = y * gridsize;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ vd.index,
+ tls->thread_id);
if (smooth_mask) {
- tmprow_mask[0] = (*CCG_elem_offset_mask(&key, gddata, v) +
- *CCG_elem_offset_mask(&key, gddata, v + gridsize));
+ float val = grids_neighbor_average_mask(ss, vd.index) - *vd.mask;
+ val *= fade * bstrength;
+ *vd.mask += val;
+ CLAMP(*vd.mask, 0.0f, 1.0f);
}
else {
- add_v3_v3v3(tmprow_co[0],
- CCG_elem_offset_co(&key, gddata, v),
- CCG_elem_offset_co(&key, gddata, v + gridsize));
- }
-
- for (x = 0; x < gridsize - 1; x++) {
- const int v1 = x + y * gridsize;
- const int v2 = v1 + 1;
- const int v3 = v1 + gridsize;
- const int v4 = v3 + 1;
-
- if (smooth_mask) {
- float tmp;
-
- tmprow_mask[(x + 1) % 2] = (*CCG_elem_offset_mask(&key, gddata, v2) +
- *CCG_elem_offset_mask(&key, gddata, v4));
- tmp = tmprow_mask[(x + 1) % 2] + tmprow_mask[x % 2];
-
- tmpgrid_mask[v1] += tmp;
- tmpgrid_mask[v2] += tmp;
- tmpgrid_mask[v3] += tmp;
- tmpgrid_mask[v4] += tmp;
- }
- else {
- float tmp[3];
-
- add_v3_v3v3(tmprow_co[(x + 1) % 2],
- CCG_elem_offset_co(&key, gddata, v2),
- CCG_elem_offset_co(&key, gddata, v4));
- add_v3_v3v3(tmp, tmprow_co[(x + 1) % 2], tmprow_co[x % 2]);
-
- add_v3_v3(tmpgrid_co[v1], tmp);
- add_v3_v3(tmpgrid_co[v2], tmp);
- add_v3_v3(tmpgrid_co[v3], tmp);
- add_v3_v3(tmpgrid_co[v4], tmp);
- }
- }
- }
-
- /* blend with existing coordinates */
- for (y = 0; y < gridsize; y++) {
- for (x = 0; x < gridsize; x++) {
- float *co;
- const float *fno;
- float *mask;
- const int index = y * gridsize + x;
-
- if (gh) {
- if (BLI_BITMAP_TEST(gh, index)) {
- continue;
- }
- }
-
- co = CCG_elem_offset_co(&key, gddata, index);
- fno = CCG_elem_offset_no(&key, gddata, index);
- mask = CCG_elem_offset_mask(&key, gddata, index);
-
- if (sculpt_brush_test_sq_fn(&test, co)) {
- const float strength_mask = (smooth_mask ? 0.0f : *mask);
- const float fade =
- bstrength *
- tex_strength(
- ss, brush, co, sqrtf(test.dist), NULL, fno, strength_mask, 0, tls->thread_id);
- float f = 1.0f / 16.0f;
-
- if (x == 0 || x == gridsize - 1) {
- f *= 2.0f;
- }
-
- if (y == 0 || y == gridsize - 1) {
- f *= 2.0f;
- }
-
- if (smooth_mask) {
- *mask += ((tmpgrid_mask[index] * f) - *mask) * fade;
- }
- else {
- float *avg = tmpgrid_co[index];
- float val[3];
-
- mul_v3_fl(avg, f);
- sub_v3_v3v3(val, avg, co);
- madd_v3_v3v3fl(val, co, val, fade);
-
- sculpt_clip(sd, ss, co, val);
- }
- }
+ float avg[3], val[3];
+ grids_neighbor_average(ss, avg, vd.index);
+ sub_v3_v3v3(val, avg, vd.co);
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+ sculpt_clip(sd, ss, vd.co, val);
}
}
}
+ BKE_pbvh_vertex_iter_end;
}
static void smooth(Sculpt *sd,
@@ -2821,25 +2721,9 @@ static void smooth(Sculpt *sd,
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
switch (type) {
- case PBVH_GRIDS: {
- int gridsize;
- size_t size;
- SculptDoBrushSmoothGridDataChunk *data_chunk;
-
- BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL, &gridsize, NULL);
- size = (size_t)gridsize;
- size = sizeof(float) * size * size * (smooth_mask ? 1 : 3);
- data_chunk = MEM_mallocN(sizeof(*data_chunk) + size, __func__);
- data_chunk->tmpgrid_size = size;
- size += sizeof(*data_chunk);
-
- settings.userdata_chunk = data_chunk;
- settings.userdata_chunk_size = size;
+ case PBVH_GRIDS:
BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
-
- MEM_freeN(data_chunk);
break;
- }
case PBVH_FACES:
BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
break;
@@ -2847,10 +2731,6 @@ static void smooth(Sculpt *sd,
BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
break;
}
-
- if (ss->multires) {
- multires_stitch_grids(ob);
- }
}
}
@@ -2910,8 +2790,13 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
const float fade = tex_strength(
ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
- (*vd.mask) += fade * bstrength;
- CLAMP(*vd.mask, 0, 1);
+ if (bstrength > 0.0f) {
+ (*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
+ }
+ else {
+ (*vd.mask) += fade * bstrength * (*vd.mask);
+ }
+ CLAMP(*vd.mask, 0.0f, 1.0f);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@@ -3194,7 +3079,12 @@ static void sculpt_relax_vertex(SculptSession *ss,
float plane[4];
float smooth_closest_plane[3];
float vno[3];
- normal_short_to_float_v3(vno, vd->no);
+ if (vd->no) {
+ normal_short_to_float_v3(vno, vd->no);
+ }
+ else {
+ copy_v3_v3(vno, vd->fno);
+ }
plane_from_point_normal_v3(plane, vd->co, vno);
closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos);
sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co);
@@ -3528,98 +3418,6 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BKE_pbvh_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
}
-/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
- * Pixar Technical Memo #17-03 */
-
-typedef struct KelvinletParams {
- float f;
- float a;
- float b;
- float c;
- float radius_scaled;
-} KelvinletParams;
-
-static int sculpt_kelvinlet_get_scale_iteration_count(eBrushElasticDeformType type)
-{
- if (type == BRUSH_ELASTIC_DEFORM_GRAB) {
- return 1;
- }
- if (type == BRUSH_ELASTIC_DEFORM_GRAB_BISCALE) {
- return 2;
- }
- if (type == BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE) {
- return 3;
- }
- return 0;
-}
-
-static void sculpt_kelvinet_integrate(void (*kelvinlet)(float disp[3],
- const float vertex_co[3],
- const float location[3],
- float normal[3],
- KelvinletParams *p),
- float r_disp[3],
- const float vertex_co[3],
- const float location[3],
- float normal[3],
- KelvinletParams *p)
-{
- float k[4][3], k_it[4][3];
- kelvinlet(k[0], vertex_co, location, normal, p);
- copy_v3_v3(k_it[0], k[0]);
- mul_v3_fl(k_it[0], 0.5f);
- add_v3_v3v3(k_it[0], vertex_co, k_it[0]);
- kelvinlet(k[1], k_it[0], location, normal, p);
- copy_v3_v3(k_it[1], k[1]);
- mul_v3_fl(k_it[1], 0.5f);
- add_v3_v3v3(k_it[1], vertex_co, k_it[1]);
- kelvinlet(k[2], k_it[1], location, normal, p);
- copy_v3_v3(k_it[2], k[2]);
- add_v3_v3v3(k_it[2], vertex_co, k_it[2]);
- sub_v3_v3v3(k_it[2], k_it[2], location);
- kelvinlet(k[3], k_it[2], location, normal, p);
- copy_v3_v3(r_disp, k[0]);
- madd_v3_v3fl(r_disp, k[1], 2);
- madd_v3_v3fl(r_disp, k[2], 2);
- add_v3_v3(r_disp, k[3]);
- mul_v3_fl(r_disp, 1.0f / 6.0f);
-}
-
-/* Regularized Kelvinlets: Formula (16) */
-static void sculpt_kelvinlet_scale(float disp[3],
- const float vertex_co[3],
- const float location[3],
- float UNUSED(normal[3]),
- KelvinletParams *p)
-{
- float r_v[3];
- sub_v3_v3v3(r_v, vertex_co, location);
- float r = len_v3(r_v);
- float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled);
- float u = (2.0f * p->b - p->a) * ((1.0f / (r_e * r_e * r_e))) +
- ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e));
- float fade = u * p->c;
- mul_v3_v3fl(disp, r_v, fade * p->f);
-}
-
-/* Regularized Kelvinlets: Formula (15) */
-static void sculpt_kelvinlet_twist(float disp[3],
- const float vertex_co[3],
- const float location[3],
- float normal[3],
- KelvinletParams *p)
-{
- float r_v[3], q_r[3];
- sub_v3_v3v3(r_v, vertex_co, location);
- float r = len_v3(r_v);
- float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled);
- float u = -p->a * ((1.0f / (r_e * r_e * r_e))) +
- ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e));
- float fade = u * p->c;
- cross_v3_v3v3(q_r, normal, r_v);
- mul_v3_v3fl(disp, q_r, fade * p->f);
-}
-
static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -3640,23 +3438,6 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- /* Maybe this can be exposed to the user */
- float radius_e[3] = {1.0f, 2.0f, 2.0f};
- float r_e[3];
- float kvl[3];
- float radius_scaled[3];
-
- radius_scaled[0] = ss->cache->radius * radius_e[0];
- radius_scaled[1] = radius_scaled[0] * radius_e[1];
- radius_scaled[2] = radius_scaled[1] * radius_e[2];
-
- float shear_modulus = 1.0f;
- float poisson_ratio = brush->elastic_deform_volume_preservation;
-
- float a = 1.0f / (4.0f * (float)M_PI * shear_modulus);
- float b = a / (4.0f * (1.0f - poisson_ratio));
- float c = 2 * (3.0f * a - 2.0f * b);
-
float dir;
if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
dir = 1.0f;
@@ -3671,73 +3452,38 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
dir = -dir;
}
}
+
+ KelvinletParams params;
+ float force = len_v3(grab_delta) * dir * bstrength;
+ BKE_kelvinlet_init_params(
+ &params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
sculpt_orig_vert_data_update(&orig_data, &vd);
- float fade, final_disp[3], weights[3];
- float r = len_v3v3(location, orig_data.co);
- KelvinletParams params;
- params.a = a;
- params.b = b;
- params.c = c;
- params.radius_scaled = radius_scaled[0];
-
- int multi_scale_it = sculpt_kelvinlet_get_scale_iteration_count(brush->elastic_deform_type);
- for (int it = 0; it < max_ii(1, multi_scale_it); it++) {
- r_e[it] = sqrtf(r * r + radius_scaled[it] * radius_scaled[it]);
- }
-
- /* Regularized Kelvinlets: Formula (6) */
- for (int s_it = 0; s_it < multi_scale_it; s_it++) {
- kvl[s_it] = ((a - b) / r_e[s_it]) + ((b * r * r) / (r_e[s_it] * r_e[s_it] * r_e[s_it])) +
- ((a * radius_scaled[s_it] * radius_scaled[s_it]) /
- (2.0f * r_e[s_it] * r_e[s_it] * r_e[s_it]));
- }
-
+ float final_disp[3];
switch (brush->elastic_deform_type) {
- /* Regularized Kelvinlets: Multi-scale extrapolation. Formula (11) */
case BRUSH_ELASTIC_DEFORM_GRAB:
- fade = kvl[0] * c;
- mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.f);
+ BKE_kelvinlet_grab(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
break;
case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
- const float u = kvl[0] - kvl[1];
- fade = u * c / ((1.0f / radius_scaled[0]) - (1.0f / radius_scaled[1]));
- mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.0f);
+ BKE_kelvinlet_grab_biscale(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
break;
}
case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
- weights[0] = 1.0f;
- weights[1] = -(
- (radius_scaled[2] * radius_scaled[2] - radius_scaled[0] * radius_scaled[0]) /
- (radius_scaled[2] * radius_scaled[2] - radius_scaled[1] * radius_scaled[1]));
- weights[2] = ((radius_scaled[1] * radius_scaled[1] - radius_scaled[0] * radius_scaled[0]) /
- (radius_scaled[2] * radius_scaled[2] - radius_scaled[1] * radius_scaled[1]));
-
- const float u = weights[0] * kvl[0] + weights[1] * kvl[1] + weights[2] * kvl[2];
- fade = u * c /
- (weights[0] / radius_scaled[0] + weights[1] / radius_scaled[1] +
- weights[2] / radius_scaled[2]);
- mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.0f);
+ BKE_kelvinlet_grab_triscale(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
break;
}
case BRUSH_ELASTIC_DEFORM_SCALE:
- params.f = len_v3(grab_delta) * dir * bstrength;
- sculpt_kelvinet_integrate(sculpt_kelvinlet_scale,
- final_disp,
- orig_data.co,
- location,
- ss->cache->sculpt_normal_symm,
- &params);
+ BKE_kelvinlet_scale(
+ final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
break;
case BRUSH_ELASTIC_DEFORM_TWIST:
- params.f = len_v3(grab_delta) * dir * bstrength;
- sculpt_kelvinet_integrate(sculpt_kelvinlet_twist,
- final_disp,
- orig_data.co,
- location,
- ss->cache->sculpt_normal_symm,
- &params);
+ BKE_kelvinlet_twist(
+ final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
break;
}
@@ -4871,6 +4617,10 @@ static void calc_clay_surface_task_cb(void *__restrict userdata,
test.radius_squared = test_radius * test_radius;
plane_from_point_normal_v3(plane, area_co, area_no);
+ if (is_zero_v4(plane)) {
+ return;
+ }
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4926,7 +4676,6 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
float intr[3];
float val[3];
-
closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
sub_v3_v3v3(val, intr, vd.co);
@@ -4962,6 +4711,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
Brush *brush = BKE_paint_brush(&sd->paint);
const float radius = fabsf(ss->cache->radius);
+ const float initial_radius = fabsf(ss->cache->initial_radius);
bool flip = ss->cache->bstrength < 0.0f;
float offset = get_offset(sd, ss);
@@ -4997,7 +4747,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
d_offset = min_ff(radius, d_offset);
d_offset = d_offset / radius;
d_offset = 1.0f - d_offset;
- displace = fabsf(radius * (0.25f + offset + (d_offset * 0.15f)));
+ displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f)));
if (flip) {
displace = -displace;
}
@@ -6781,8 +6531,10 @@ static void sculpt_update_cache_invariants(
static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, float initial_size)
{
switch (brush->sculpt_tool) {
+ case SCULPT_TOOL_CLAY:
+ return max_ff(initial_size * 0.20f, initial_size * pow3f(cache->pressure));
case SCULPT_TOOL_CLAY_STRIPS:
- return max_ff(initial_size * 0.35f, initial_size * cache->pressure * cache->pressure);
+ return max_ff(initial_size * 0.35f, initial_size * pow2f(cache->pressure));
default:
return initial_size * cache->pressure;
}
@@ -6986,12 +6738,15 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
}
}
- if (BKE_brush_use_size_pressure(scene, brush) &&
+ if (BKE_brush_use_size_pressure(brush) &&
paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT)) {
cache->radius = sculpt_brush_dynamic_size_get(brush, cache, cache->initial_radius);
+ cache->dyntopo_pixel_radius = sculpt_brush_dynamic_size_get(
+ brush, cache, ups->initial_pixel_radius);
}
else {
cache->radius = cache->initial_radius;
+ cache->dyntopo_pixel_radius = ups->initial_pixel_radius;
}
cache->radius_squared = cache->radius * cache->radius;
@@ -7142,6 +6897,7 @@ static float sculpt_raycast_init(ViewContext *vc,
float dist;
Object *ob = vc->obact;
RegionView3D *rv3d = vc->ar->regiondata;
+ View3D *v3d = vc->v3d;
/* TODO: what if the segment is totally clipped? (return == 0) */
ED_view3d_win_to_segment_clipped(
@@ -7156,7 +6912,7 @@ static float sculpt_raycast_init(ViewContext *vc,
if ((rv3d->is_persp == false) &&
/* if the ray is clipped, don't adjust its start/end */
- ((rv3d->rflag & RV3D_CLIPPING) == 0)) {
+ RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
BKE_pbvh_raycast_project_ray_root(ob->sculpt->pbvh, original, ray_start, ray_end, ray_normal);
/* recalculate the normal */
@@ -7251,6 +7007,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
copy_v3_v3(ss->cursor_normal, srd.face_normal);
copy_v3_v3(ss->cursor_location, out->location);
ss->rv3d = vc.rv3d;
+ ss->v3d = vc.v3d;
if (!BKE_brush_use_locked_size(scene, brush)) {
radius = paint_calc_object_space_radius(&vc, out->location, BKE_brush_size_get(scene, brush));
@@ -7402,14 +7159,13 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
{
- SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
/* Restore the mesh before continuing with anchored stroke */
if ((brush->flag & BRUSH_ANCHORED) ||
((brush->sculpt_tool == SCULPT_TOOL_GRAB ||
brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) &&
- BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) ||
+ BKE_brush_use_size_pressure(brush)) ||
(brush->flag & BRUSH_DRAG_DOT)) {
paint_mesh_restore_co(sd, ob);
}
@@ -7456,9 +7212,7 @@ static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
ED_region_tag_redraw(ar);
}
else {
- /* Fast path where we just update the BVH nodes that changed, and redraw
- * only the part of the 3D viewport where changes happened. */
- rcti r;
+ /* Fast path where we just update the BVH nodes that changed. */
if (update_flags & SCULPT_UPDATE_COORDS) {
BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
@@ -7468,21 +7222,7 @@ static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
sculpt_update_object_bounding_box(ob);
}
- if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
- if (ss->cache) {
- ss->cache->current_r = r;
- }
-
- /* previous is not set in the current cache else
- * the partial rect will always grow */
- sculpt_extend_redraw_rect_previous(ob, &r);
-
- r.xmin += ar->winrct.xmin - 2;
- r.xmax += ar->winrct.xmin + 2;
- r.ymin += ar->winrct.ymin - 2;
- r.ymax += ar->winrct.ymin + 2;
- ED_region_tag_redraw_partial(ar, &r, true);
- }
+ ED_region_tag_redraw(ar);
}
}
@@ -7607,7 +7347,7 @@ static void sculpt_stroke_update_step(bContext *C,
}
else {
BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
- (ss->cache->radius / (float)ups->pixel_radius) *
+ (ss->cache->radius / ss->cache->dyntopo_pixel_radius) *
(float)(sd->detail_size * U.pixelsize) / 0.4f);
}
@@ -8710,36 +8450,60 @@ static void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static void sample_detail(bContext *C, int mx, int my)
+typedef enum eSculptSampleDetailModeTypes {
+ SAMPLE_DETAIL_DYNTOPO = 0,
+ SAMPLE_DETAIL_VOXEL = 1,
+} eSculptSampleDetailModeTypes;
+
+static EnumPropertyItem prop_sculpt_sample_detail_mode_types[] = {
+ {SAMPLE_DETAIL_DYNTOPO, "DYNTOPO", 0, "Dyntopo", "Sample dyntopo detail"},
+ {SAMPLE_DETAIL_VOXEL, "VOXEL", 0, "Voxel", "Sample mesh voxel size"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
{
- /* Find 3D view to pick from. */
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
- ARegion *ar = (sa) ? BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my) : NULL;
- if (ar == NULL) {
- return;
- }
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = vc->obact;
+ Mesh *mesh = ob->data;
- /* Set context to 3D view. */
- ScrArea *prev_sa = CTX_wm_area(C);
- ARegion *prev_ar = CTX_wm_region(C);
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
+ SculptSession *ss = ob->sculpt;
+ SculptCursorGeometryInfo sgi;
+ sculpt_vertex_random_access_init(ss);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc, depsgraph);
+ /* Update the active vertex */
+ float mouse[2] = {mx, my};
+ sculpt_cursor_geometry_info_update(C, &sgi, mouse, false);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
- /* Pick sample detail. */
+ /* Average the edge length of the connected edges to the active vertex */
+ int active_vertex = sculpt_active_vertex_get(ss);
+ const float *active_vertex_co = sculpt_active_vertex_co_get(ss);
+ float edge_length = 0.0f;
+ int tot = 0;
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, active_vertex, ni)
+ {
+ edge_length += len_v3v3(active_vertex_co, sculpt_vertex_co_get(ss, ni.index));
+ tot += 1;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ if (tot > 0) {
+ mesh->remesh_voxel_size = edge_length / (float)tot;
+ }
+}
+
+static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *ar, int mx, int my)
+{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = vc.obact;
+ Object *ob = vc->obact;
Brush *brush = BKE_paint_brush(&sd->paint);
sculpt_stroke_modifiers_check(C, ob, brush);
float mouse[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
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, mouse, ray_start, ray_end, ray_normal, false);
SculptDetailRaycastData srd;
srd.hit = 0;
@@ -8754,6 +8518,37 @@ static void sample_detail(bContext *C, int mx, int my)
/* Convert edge length to world space detail resolution. */
sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->obmat));
}
+}
+
+static void sample_detail(bContext *C, int mx, int my, int mode)
+{
+ /* Find 3D view to pick from. */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
+ ARegion *ar = (sa) ? BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my) : NULL;
+ if (ar == NULL) {
+ return;
+ }
+
+ /* Set context to 3D view. */
+ ScrArea *prev_sa = CTX_wm_area(C);
+ ARegion *prev_ar = CTX_wm_region(C);
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+
+ /* Pick sample detail. */
+ switch (mode) {
+ case SAMPLE_DETAIL_DYNTOPO:
+ sample_detail_dyntopo(C, &vc, ar, mx, my);
+ break;
+ case SAMPLE_DETAIL_VOXEL:
+ sample_detail_voxel(C, &vc, mx, my);
+ break;
+ }
/* Restore context. */
CTX_wm_area_set(C, prev_sa);
@@ -8764,7 +8559,8 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
{
int ss_co[2];
RNA_int_get_array(op->ptr, "location", ss_co);
- sample_detail(C, ss_co[0], ss_co[1]);
+ int mode = RNA_enum_get(op->ptr, "mode");
+ sample_detail(C, ss_co[0], ss_co[1], mode);
return OPERATOR_FINISHED;
}
@@ -8783,7 +8579,8 @@ static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wm
if (event->val == KM_PRESS) {
int ss_co[2] = {event->x, event->y};
- sample_detail(C, ss_co[0], ss_co[1]);
+ int mode = RNA_enum_get(op->ptr, "mode");
+ sample_detail(C, ss_co[0], ss_co[1], mode);
RNA_int_set_array(op->ptr, "location", ss_co);
WM_cursor_modal_restore(CTX_wm_window(C));
@@ -8816,7 +8613,7 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
ot->invoke = sculpt_sample_detail_size_invoke;
ot->exec = sculpt_sample_detail_size_exec;
ot->modal = sculpt_sample_detail_size_modal;
- ot->poll = sculpt_and_constant_or_manual_detail_poll;
+ ot->poll = sculpt_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -8830,6 +8627,12 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
"Screen Coordinates of sampling",
0,
SHRT_MAX);
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_sample_detail_mode_types,
+ SAMPLE_DETAIL_DYNTOPO,
+ "Detail Mode",
+ "Target sculpting workflow that is going to use the sampled size");
}
/* Dynamic-topology detail size
@@ -9112,8 +8915,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
}
BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_redraw(node);
- BKE_pbvh_node_mark_normals_update(node);
+ BKE_pbvh_node_mark_update(node);
}
static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
@@ -9161,6 +8963,11 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *
sculpt_flush_stroke_deform(sd, ob, true);
}
+ /* The relax mesh filter needs the updated normals of the modified mesh after each iteration */
+ if (filter_type == MESH_FILTER_RELAX) {
+ BKE_pbvh_update_normals(ss->pbvh, ss->subdiv_ccg);
+ }
+
sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
return OPERATOR_RUNNING_MODAL;
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 0b25ab31ce0..e9ad31d6f25 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -318,6 +318,10 @@ typedef struct StrokeCache {
float true_last_location[3];
float location[3];
float last_location[3];
+
+ /* Original pixel radius with the pressure curve applied for dyntopo detail size */
+ float dyntopo_pixel_radius;
+
bool is_last_valid;
bool pen_flip;
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 8fbaf3396bd..72b02436b92 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -521,18 +521,18 @@ 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, false, true, true);
+ data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, true);
}
else {
- data->elementMap = BM_uv_element_map_create(bm, true, true, true);
+ data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, true);
}
}
else {
if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, false, true, false);
+ data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, false);
}
else {
- data->elementMap = BM_uv_element_map_create(bm, true, true, false);
+ data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, false);
}
}
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 1685852dd02..901efbdf0ff 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -71,7 +71,7 @@ static SpaceLink *action_new(const ScrArea *sa, const Scene *scene)
saction->autosnap = SACTSNAP_FRAME;
saction->mode = SACTCONT_DOPESHEET;
saction->mode_prev = SACTCONT_DOPESHEET;
- saction->flag = SACTION_SHOW_INTERPOLATION | SACTION_SHOW_MARKER_LINES;
+ saction->flag = SACTION_SHOW_INTERPOLATION | SACTION_SHOW_MARKERS;
saction->ads.filterflag |= ADS_FILTER_SUMMARY;
@@ -215,10 +215,10 @@ static void action_main_region_draw(const bContext *C, ARegion *ar)
marker_flag = ((ac.markers && (ac.markers != &ac.scene->markers)) ? DRAW_MARKERS_LOCAL : 0) |
DRAW_MARKERS_MARGIN;
- if (saction->flag & SACTION_SHOW_MARKER_LINES) {
- marker_flag |= DRAW_MARKERS_LINES;
+
+ if (saction->flag & SACTION_SHOW_MARKERS) {
+ ED_markers_draw(C, marker_flag);
}
- ED_markers_draw(C, marker_flag);
/* caches */
if (saction->mode == SACTCONT_TIMELINE) {
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index a017186b407..9056bbb1246 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -129,7 +129,6 @@ void ED_spacetypes_init(void)
ED_gizmotypes_button_2d();
ED_gizmotypes_dial_3d();
ED_gizmotypes_move_3d();
- ED_gizmotypes_arrow_2d();
ED_gizmotypes_arrow_3d();
ED_gizmotypes_preselect_3d();
ED_gizmotypes_primitive_3d();
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 8cb0a3f3c86..ecd2b5a3697 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -770,7 +770,6 @@ const char *buttons_context_dir[] = {
"cloth",
"soft_body",
"fluid",
- "smoke",
"collision",
"brush",
"dynamic_paint",
@@ -1018,24 +1017,14 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
return 1;
}
}
- else if (CTX_data_equals(member, "fluid")) {
- PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
- if (ptr && ptr->data) {
- Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim);
- CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
- return 1;
- }
- }
-
- else if (CTX_data_equals(member, "smoke")) {
+ else if (CTX_data_equals(member, "fluid")) {
PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
- CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid);
+ CTX_data_pointer_set(result, &ob->id, &RNA_FluidModifier, md);
return 1;
}
}
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 74cf28ce5d4..f9899135e2d 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -1947,7 +1947,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
/* if no clip, nothing to do */
if (!clip) {
- ED_region_grid_draw(ar, zoomx, zoomy);
+ ED_region_grid_draw(ar, zoomx, zoomy, 0.0f, 0.0f);
return;
}
@@ -1994,7 +1994,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
draw_movieclip_muted(ar, width, height, zoomx, zoomy);
}
else {
- ED_region_grid_draw(ar, zoomx, zoomy);
+ ED_region_grid_draw(ar, zoomx, zoomy, 0.0f, 0.0f);
}
if (width && height) {
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 4d6b05df609..bf6683ffc33 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -80,8 +80,6 @@ void console_scrollback_prompt_end(struct SpaceConsole *sc, ConsoleLine *cl_dumm
BLI_remlink(&sc->scrollback, cl_dummy);
}
-#define CONSOLE_DRAW_MARGIN 4
-
/* console textview callbacks */
static int console_textview_begin(TextViewContext *tvc)
{
@@ -150,18 +148,18 @@ static int console_textview_line_color(struct TextViewContext *tvc,
const SpaceConsole *sc = (SpaceConsole *)tvc->arg1;
const ConsoleLine *cl = (ConsoleLine *)sc->history.last;
int offl = 0, offc = 0;
- int xy[2] = {CONSOLE_DRAW_MARGIN, CONSOLE_DRAW_MARGIN};
+ int xy[2] = {tvc->draw_rect.xmin, tvc->draw_rect.ymin};
int pen[2];
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
xy[1] += tvc->lheight / 6;
- console_cursor_wrap_offset(sc->prompt, tvc->console_width, &offl, &offc, NULL);
- console_cursor_wrap_offset(cl->line, tvc->console_width, &offl, &offc, cl->line + cl->cursor);
+ console_cursor_wrap_offset(sc->prompt, tvc->columns, &offl, &offc, NULL);
+ console_cursor_wrap_offset(cl->line, tvc->columns, &offl, &offc, cl->line + cl->cursor);
pen[0] = tvc->cwidth * offc;
pen[1] = -2 - tvc->lheight * offl;
- console_cursor_wrap_offset(cl->line + cl->cursor, tvc->console_width, &offl, &offc, NULL);
+ console_cursor_wrap_offset(cl->line + cl->cursor, tvc->columns, &offl, &offc, NULL);
pen[1] += tvc->lheight * offl;
/* cursor */
@@ -169,9 +167,9 @@ static int console_textview_line_color(struct TextViewContext *tvc,
immUniformThemeColor(TH_CONSOLE_CURSOR);
immRectf(pos,
- (xy[0] + pen[0]) - 1,
+ (xy[0] + pen[0]) - U.pixelsize,
(xy[1] + pen[1]),
- (xy[0] + pen[0]) + 1,
+ (xy[0] + pen[0]) + U.pixelsize,
(xy[1] + pen[1] + tvc->lheight));
immUnbindProgram();
@@ -187,13 +185,27 @@ static void console_textview_const_colors(TextViewContext *UNUSED(tvc), unsigned
UI_GetThemeColor4ubv(TH_CONSOLE_SELECT, bg_sel);
}
-static int console_textview_main__internal(
- struct SpaceConsole *sc, ARegion *ar, int draw, int mval[2], void **mouse_pick, int *pos_pick)
+static void console_textview_draw_rect_calc(const ARegion *ar, rcti *draw_rect)
+{
+ const int margin = 4 * UI_DPI_FAC;
+ draw_rect->xmin = margin;
+ draw_rect->xmax = ar->winx - (margin + V2D_SCROLL_WIDTH);
+ draw_rect->ymin = margin;
+ /* No margin at the top (allow text to scroll off the window). */
+ draw_rect->ymax = ar->winy;
+}
+
+static int console_textview_main__internal(struct SpaceConsole *sc,
+ const ARegion *ar,
+ const bool do_draw,
+ const int mval[2],
+ void **r_mval_pick_item,
+ int *r_mval_pick_offset)
{
ConsoleLine cl_dummy = {NULL};
int ret = 0;
- View2D *v2d = &ar->v2d;
+ const View2D *v2d = &ar->v2d;
TextViewContext tvc = {0};
@@ -212,38 +224,38 @@ static int console_textview_main__internal(
tvc.sel_start = sc->sel_start;
tvc.sel_end = sc->sel_end;
tvc.lheight = sc->lheight * UI_DPI_FAC;
- tvc.ymin = v2d->cur.ymin;
- tvc.ymax = v2d->cur.ymax;
- tvc.winx = ar->winx - V2D_SCROLL_WIDTH;
+ tvc.scroll_ymin = v2d->cur.ymin;
+ tvc.scroll_ymax = v2d->cur.ymax;
+
+ console_textview_draw_rect_calc(ar, &tvc.draw_rect);
console_scrollback_prompt_begin(sc, &cl_dummy);
- ret = textview_draw(&tvc, draw, mval, mouse_pick, pos_pick);
+ ret = textview_draw(&tvc, do_draw, mval, r_mval_pick_item, r_mval_pick_offset);
console_scrollback_prompt_end(sc, &cl_dummy);
return ret;
}
-void console_textview_main(struct SpaceConsole *sc, ARegion *ar)
+void console_textview_main(struct SpaceConsole *sc, const ARegion *ar)
{
- int mval[2] = {INT_MAX, INT_MAX};
- console_textview_main__internal(sc, ar, 1, mval, NULL, NULL);
+ const int mval[2] = {INT_MAX, INT_MAX};
+ console_textview_main__internal(sc, ar, true, mval, NULL, NULL);
}
-int console_textview_height(struct SpaceConsole *sc, ARegion *ar)
+int console_textview_height(struct SpaceConsole *sc, const ARegion *ar)
{
- int mval[2] = {INT_MAX, INT_MAX};
- return console_textview_main__internal(sc, ar, 0, mval, NULL, NULL);
+ const int mval[2] = {INT_MAX, INT_MAX};
+ return console_textview_main__internal(sc, ar, false, mval, NULL, NULL);
}
-int console_char_pick(struct SpaceConsole *sc, ARegion *ar, const int mval[2])
+int console_char_pick(struct SpaceConsole *sc, const ARegion *ar, const int mval[2])
{
- int pos_pick = 0;
- void *mouse_pick = NULL;
- int mval_clamp[2];
+ int r_mval_pick_offset = 0;
+ void *mval_pick_item = NULL;
- mval_clamp[0] = CLAMPIS(mval[0], CONSOLE_DRAW_MARGIN, ar->winx - CONSOLE_DRAW_MARGIN);
- mval_clamp[1] = CLAMPIS(mval[1], CONSOLE_DRAW_MARGIN, ar->winy - CONSOLE_DRAW_MARGIN);
+ rcti draw_rect;
+ console_textview_draw_rect_calc(ar, &draw_rect);
- console_textview_main__internal(sc, ar, 0, mval_clamp, &mouse_pick, &pos_pick);
- return pos_pick;
+ console_textview_main__internal(sc, ar, false, mval, &mval_pick_item, &r_mval_pick_offset);
+ return r_mval_pick_offset;
}
diff --git a/source/blender/editors/space_console/console_intern.h b/source/blender/editors/space_console/console_intern.h
index 2a5675b9c3b..def7fbc193b 100644
--- a/source/blender/editors/space_console/console_intern.h
+++ b/source/blender/editors/space_console/console_intern.h
@@ -28,10 +28,10 @@ struct bContext;
struct wmOperatorType;
/* console_draw.c */
-void console_textview_main(struct SpaceConsole *sc, struct ARegion *ar);
+void console_textview_main(struct SpaceConsole *sc, const struct ARegion *ar);
/* needed to calculate the scrollbar */
-int console_textview_height(struct SpaceConsole *sc, struct ARegion *ar);
-int console_char_pick(struct SpaceConsole *sc, struct ARegion *ar, const int mval[2]);
+int console_textview_height(struct SpaceConsole *sc, const struct ARegion *ar);
+int console_char_pick(struct SpaceConsole *sc, const struct ARegion *ar, const int mval[2]);
void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_dummy);
void console_scrollback_prompt_end(struct SpaceConsole *sc, ConsoleLine *cl_dummy);
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index 33f57b9c235..84df11ea39c 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -57,6 +57,10 @@ set(LIB
if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
+else()
+ list(APPEND LIB
+ bf_editor_datafiles
+ )
endif()
if(WITH_IMAGE_OPENEXR)
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index b26769f2118..77e6266b830 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -45,6 +45,8 @@
#include "ED_select_utils.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
+#include "UI_resources.h"
#include "MEM_guardedalloc.h"
@@ -952,7 +954,8 @@ static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
if (params->dir[0] != '\0') {
char name[FILE_MAX];
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, NULL, FS_INSERT_SAVE);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, NULL, ICON_FILE_FOLDER, FS_INSERT_SAVE);
BLI_make_file_string(
"/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
@@ -1572,6 +1575,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
FS_CATEGORY_RECENT,
sfile->params->dir,
NULL,
+ ICON_FILE_FOLDER,
FS_INSERT_SAVE | FS_INSERT_FIRST);
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 1ea7d81f9da..a567aeed826 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1001,6 +1001,9 @@ static int filelist_geticon_ex(const int typeflag,
else if (typeflag & FILE_TYPE_ALEMBIC) {
return ICON_FILE_3D;
}
+ else if (typeflag & FILE_TYPE_USD) {
+ return ICON_FILE_3D;
+ }
else if (typeflag & FILE_TYPE_OBJECT_IO) {
return ICON_FILE_3D;
}
@@ -2130,6 +2133,9 @@ int ED_path_extension_type(const char *path)
else if (BLI_path_extension_check(path, ".abc")) {
return FILE_TYPE_ALEMBIC;
}
+ else if (BLI_path_extension_check_n(path, ".usd", ".usda", ".usdc", NULL)) {
+ return FILE_TYPE_USD;
+ }
else if (BLI_path_extension_check(path, ".zip")) {
return FILE_TYPE_ARCHIVE;
}
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index f8adf9b707a..02fb98aa7d7 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -160,14 +160,11 @@ short ED_fileselect_set_params(SpaceFile *sfile)
BLI_path_abs(params->dir, blendfile_path);
}
+ params->flag = 0;
if (is_directory == true && is_filename == false && is_filepath == false &&
is_files == false) {
params->flag |= FILE_DIRSEL_ONLY;
}
- else {
- params->flag &= ~FILE_DIRSEL_ONLY;
- }
-
if ((prop = RNA_struct_find_property(op->ptr, "check_existing"))) {
params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_CHECK_EXISTING : 0;
}
@@ -218,6 +215,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
if ((prop = RNA_struct_find_property(op->ptr, "filter_alembic"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ALEMBIC : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_usd"))) {
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_USD : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) {
/* Protection against pyscripts not setting proper size limit... */
char *tmp = RNA_property_string_get_alloc(
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 7faa2b883f2..f9506da39a8 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -46,6 +46,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface_icons.h"
+#include "UI_resources.h"
#ifdef __APPLE__
# include <Carbon/Carbon.h>
@@ -162,6 +164,16 @@ void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path)
}
}
+int ED_fsmenu_entry_get_icon(struct FSMenuEntry *fsentry)
+{
+ return (fsentry->icon) ? fsentry->icon : ICON_FILE_FOLDER;
+}
+
+void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, const int icon)
+{
+ fsentry->icon = icon;
+}
+
static void fsmenu_entry_generate_name(struct FSMenuEntry *fsentry, char *name, size_t name_size)
{
int offset = 0;
@@ -258,6 +270,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
FSMenuCategory category,
const char *path,
const char *name,
+ const int icon,
FSMenuInsert flag)
{
FSMenuEntry *fsm_prev;
@@ -328,6 +341,9 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
else {
fsm_iter->name[0] = '\0';
}
+
+ ED_fsmenu_entry_set_icon(fsm_iter, icon);
+
fsmenu_entry_refresh_valid(fsm_iter);
if (fsm_prev) {
@@ -459,7 +475,7 @@ void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
if (BLI_exists(line))
#endif
{
- fsmenu_insert_entry(fsmenu, category, line, name, FS_INSERT_SAVE);
+ fsmenu_insert_entry(fsmenu, category, line, name, ICON_FILE_FOLDER, FS_INSERT_SAVE);
}
}
/* always reset name. */
@@ -504,7 +520,24 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
name = tmps;
}
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, name, FS_INSERT_SORTED);
+ int icon = ICON_DISK_DRIVE;
+ switch (GetDriveType(tmps)) {
+ case DRIVE_REMOVABLE:
+ icon = ICON_EXTERNAL_DRIVE;
+ break;
+ case DRIVE_CDROM:
+ icon = ICON_DISC;
+ break;
+ case DRIVE_FIXED:
+ case DRIVE_RAMDISK:
+ icon = ICON_DISK_DRIVE;
+ break;
+ case DRIVE_REMOTE:
+ icon = ICON_NETWORK_DRIVE;
+ break;
+ }
+
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, name, icon, FS_INSERT_SORTED);
}
}
@@ -512,10 +545,12 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
if (read_bookmarks) {
SHGetSpecialFolderPathW(0, wline, CSIDL_PERSONAL, 0);
BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_DOCUMENTS, FS_INSERT_SORTED);
SHGetSpecialFolderPathW(0, wline, CSIDL_DESKTOPDIRECTORY, 0);
BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_DESKTOP, FS_INSERT_SORTED);
}
}
#else
@@ -546,7 +581,8 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* Add end slash for consistency with other platforms */
BLI_add_slash(defPath);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, defPath, NULL, FS_INSERT_SORTED);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_SYSTEM, defPath, NULL, ICON_DISK_DRIVE, FS_INSERT_SORTED);
}
CFRelease(volEnum);
@@ -586,7 +622,8 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* Exclude "all my files" as it makes no sense in blender fileselector */
/* Exclude "airdrop" if wlan not active as it would show "" ) */
if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_LAST);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_FILE_FOLDER, FS_INSERT_LAST);
}
CFRelease(pathString);
@@ -604,10 +641,12 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
if (read_bookmarks && home) {
BLI_snprintf(line, sizeof(line), "%s/", home);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_HOME, FS_INSERT_SORTED);
BLI_snprintf(line, sizeof(line), "%s/Desktop/", home);
if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_DESKTOP, FS_INSERT_SORTED);
}
}
@@ -641,10 +680,12 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
len = strlen(mnt->mnt_dir);
if (len && mnt->mnt_dir[len - 1] != '/') {
BLI_snprintf(line, sizeof(line), "%s/", mnt->mnt_dir);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, NULL, FS_INSERT_SORTED);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_SYSTEM, line, NULL, ICON_DISK_DRIVE, FS_INSERT_SORTED);
}
else {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, mnt->mnt_dir, NULL, FS_INSERT_SORTED);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_SYSTEM, mnt->mnt_dir, NULL, ICON_DISK_DRIVE, FS_INSERT_SORTED);
}
found = 1;
@@ -674,7 +715,8 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
label = *label_test ? label_test : dirname;
}
BLI_snprintf(line, sizeof(line), "%s%s/", name, dirname);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, label, FS_INSERT_SORTED);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_SYSTEM, line, label, ICON_NETWORK_DRIVE, FS_INSERT_SORTED);
found = 1;
}
}
@@ -685,7 +727,8 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* fallback */
if (!found) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, "/", NULL, FS_INSERT_SORTED);
+ fsmenu_insert_entry(
+ fsmenu, FS_CATEGORY_SYSTEM, "/", NULL, ICON_DISK_DRIVE, FS_INSERT_SORTED);
}
}
}
diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h
index a86a552f9f9..a33783b1905 100644
--- a/source/blender/editors/space_file/fsmenu.h
+++ b/source/blender/editors/space_file/fsmenu.h
@@ -42,6 +42,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
enum FSMenuCategory category,
const char *path,
const char *name,
+ const int icon,
const enum FSMenuInsert flag);
/** Refresh 'valid' status of given menu entry */
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index e7a25f6c659..03df93e4c8a 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -60,6 +60,7 @@
#include "ED_anim_api.h"
#include "ED_keyframing.h"
#include "ED_keyframes_edit.h"
+#include "ED_numinput.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_markers.h"
@@ -1305,7 +1306,7 @@ void GRAPH_OT_clean(wmOperatorType *ot)
/* ******************** Decimate Keyframes Operator ************************* */
-static void decimate_graph_keys(bAnimContext *ac, float remove_ratio)
+static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -1318,7 +1319,10 @@ static void decimate_graph_keys(bAnimContext *ac, float remove_ratio)
/* loop through filtered data and clean curves */
for (ale = anim_data.first; ale; ale = ale->next) {
- decimate_fcurve(ale, remove_ratio);
+ if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) {
+ /* The selection contains unsupported keyframe types! */
+ WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!");
+ }
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -1329,18 +1333,348 @@ static void decimate_graph_keys(bAnimContext *ac, float remove_ratio)
/* ------------------- */
+/* This data type is only used for modal operation. */
+typedef struct tDecimateGraphOp {
+ bAnimContext ac;
+ Scene *scene;
+ ScrArea *sa;
+ ARegion *ar;
+
+ /** A 0-1 value for determining how much we should decimate. */
+ PropertyRNA *percentage_prop;
+
+ /** The original bezt curve data (used for restoring fcurves).*/
+ ListBase bezt_arr_list;
+
+ NumInput num;
+} tDecimateGraphOp;
+
+typedef struct tBeztCopyData {
+ int tot_vert;
+ BezTriple *bezt;
+} tBeztCopyData;
+
+typedef enum tDecimModes {
+ DECIM_RATIO = 1,
+ DECIM_ERROR,
+} tDecimModes;
+
+/* Overwrite the current bezts arrays with the original data. */
+static void decimate_reset_bezts(tDecimateGraphOp *dgo)
+{
+ ListBase anim_data = {NULL, NULL};
+ LinkData *link_bezt;
+ bAnimListElem *ale;
+ int filter;
+
+ bAnimContext *ac = &dgo->ac;
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* Loop through filtered data and reset bezts. */
+ for (ale = anim_data.first, link_bezt = dgo->bezt_arr_list.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ if (fcu->bezt == NULL) {
+ /* This curve is baked, skip it */
+ continue;
+ }
+
+ tBeztCopyData *data = link_bezt->data;
+
+ const int arr_size = sizeof(BezTriple) * data->tot_vert;
+
+ MEM_freeN(fcu->bezt);
+
+ fcu->bezt = MEM_mallocN(arr_size, __func__);
+ fcu->totvert = data->tot_vert;
+
+ memcpy(fcu->bezt, data->bezt, arr_size);
+
+ link_bezt = link_bezt->next;
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void decimate_exit(bContext *C, wmOperator *op)
+{
+ tDecimateGraphOp *dgo = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+
+ /* If data exists, clear its data and exit. */
+ if (dgo == NULL) {
+ return;
+ }
+
+ ScrArea *sa = dgo->sa;
+ LinkData *link;
+
+ for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) {
+ tBeztCopyData *copy = link->data;
+ MEM_freeN(copy->bezt);
+ MEM_freeN(link->data);
+ }
+
+ BLI_freelistN(&dgo->bezt_arr_list);
+ MEM_freeN(dgo);
+
+ /* Return to normal cursor and header status. */
+ WM_cursor_modal_restore(win);
+ ED_area_status_text(sa, NULL);
+
+ /* cleanup */
+ op->customdata = NULL;
+}
+
+/* Draw a percentage indicator in header. */
+static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
+{
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+
+ strcpy(mode_str, TIP_("Decimate Keyframes"));
+
+ if (hasNumInput(&dgo->num)) {
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&dgo->num, str_offs, &dgo->scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs);
+ }
+ else {
+ float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop);
+ BLI_snprintf(
+ status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(percentage * 100.0f));
+ }
+
+ ED_area_status_text(dgo->sa, status_str);
+}
+
+/* Calculate percentage based on position of mouse (we only use x-axis for now.
+ * Since this is more convenient for users to do), and store new percentage value.
+ */
+static void decimate_mouse_update_percentage(tDecimateGraphOp *dgo,
+ wmOperator *op,
+ const wmEvent *event)
+{
+ float percentage = (event->x - dgo->ar->winrct.xmin) / ((float)dgo->ar->winx);
+ RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage);
+}
+
+static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tDecimateGraphOp *dgo;
+
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EW_SCROLL);
+
+ /* Init slide-op data. */
+ dgo = op->customdata = MEM_callocN(sizeof(tDecimateGraphOp), "tDecimateGraphOp");
+
+ /* Get editor data. */
+ if (ANIM_animdata_get_context(C, &dgo->ac) == 0) {
+ decimate_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+
+ dgo->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio");
+
+ dgo->scene = CTX_data_scene(C);
+ dgo->sa = CTX_wm_area(C);
+ dgo->ar = CTX_wm_region(C);
+
+ /* initialise percentage so that it will have the correct value before the first mouse move. */
+ decimate_mouse_update_percentage(dgo, op, event);
+
+ decimate_draw_status_header(op, dgo);
+
+ /* Construct a list with the original bezt arrays so we can restore them during modal operation.
+ */
+ {
+ ListBase anim_data = {NULL, NULL};
+ bAnimContext *ac = &dgo->ac;
+ bAnimListElem *ale;
+
+ int filter;
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* Loop through filtered data and copy the curves. */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ if (fcu->bezt == NULL) {
+ /* This curve is baked, skip it */
+ continue;
+ }
+
+ const int arr_size = sizeof(BezTriple) * fcu->totvert;
+
+ tBeztCopyData *copy = MEM_mallocN(sizeof(tBeztCopyData), "bezts_copy");
+ BezTriple *bezts_copy = MEM_mallocN(arr_size, "bezts_copy_array");
+
+ copy->tot_vert = fcu->totvert;
+ memcpy(bezts_copy, fcu->bezt, arr_size);
+
+ copy->bezt = bezts_copy;
+
+ LinkData *link = NULL;
+
+ link = MEM_callocN(sizeof(LinkData), "Bezt Link");
+ link->data = copy;
+
+ BLI_addtail(&dgo->bezt_arr_list, link);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+ }
+
+ if (dgo->bezt_arr_list.first == NULL) {
+ WM_report(RPT_WARNING,
+ "Fcurve Decimate: Can't decimate baked channels. Unbake them and try again.");
+ decimate_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op)
+{
+ /* Perform decimate updates - in response to some user action
+ * (e.g. pressing a key or moving the mouse). */
+ tDecimateGraphOp *dgo = op->customdata;
+
+ decimate_draw_status_header(op, dgo);
+
+ /* Reset keyframe data (so we get back to the original state). */
+ decimate_reset_bezts(dgo);
+
+ /* apply... */
+ float remove_ratio = RNA_property_float_get(op->ptr, dgo->percentage_prop);
+ /* We don't want to limit the decimation to a certain error margin. */
+ const float error_sq_max = FLT_MAX;
+ decimate_graph_keys(&dgo->ac, remove_ratio, error_sq_max);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ /* This assumes that we are in "DECIM_RATIO" mode. This is because the error margin is very hard
+ * and finicky to control with this modal mouse grab method. Therefore, it is expected that the
+ * error margin mode is not adjusted by the modal operator but instead tweaked via the redo
+ * panel.*/
+ tDecimateGraphOp *dgo = op->customdata;
+
+ const bool has_numinput = hasNumInput(&dgo->num);
+
+ switch (event->type) {
+ case LEFTMOUSE: /* confirm */
+ case RETKEY:
+ case PADENTER: {
+ if (event->val == KM_PRESS) {
+ decimate_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ break;
+ }
+
+ case ESCKEY: /* cancel */
+ case RIGHTMOUSE: {
+ if (event->val == KM_PRESS) {
+ decimate_reset_bezts(dgo);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ decimate_exit(C, op);
+
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+
+ /* Percentage Change... */
+ case MOUSEMOVE: /* calculate new position */
+ {
+ if (has_numinput == false) {
+ /* Update percentage based on position of mouse. */
+ decimate_mouse_update_percentage(dgo, op, event);
+
+ /* Update pose to reflect the new values. */
+ graphkeys_decimate_modal_update(C, op);
+ }
+ break;
+ }
+ default: {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &dgo->num, event)) {
+ float value;
+ float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop);
+
+ /* Grab percentage from numeric input, and store this new value for redo
+ * NOTE: users see ints, while internally we use a 0-1 float.
+ */
+ value = percentage * 100.0f;
+ applyNumInput(&dgo->num, &value);
+
+ percentage = value / 100.0f;
+ RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage);
+
+ /* Update decimate output to reflect the new values. */
+ graphkeys_decimate_modal_update(C, op);
+ break;
+ }
+ else {
+ /* unhandled event - maybe it was some view manip? */
+ /* allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
- float remove_ratio;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
return OPERATOR_CANCELLED;
}
- remove_ratio = RNA_float_get(op->ptr, "remove_ratio");
- decimate_graph_keys(&ac, remove_ratio);
+ tDecimModes mode = RNA_enum_get(op->ptr, "mode");
+ /* We want to be able to work on all available keyframes. */
+ float remove_ratio = 1.0f;
+ /* We don't want to limit the decimation to a certain error margin. */
+ float error_sq_max = FLT_MAX;
+
+ switch (mode) {
+ case DECIM_RATIO:
+ remove_ratio = RNA_float_get(op->ptr, "remove_ratio");
+ break;
+ case DECIM_ERROR:
+ error_sq_max = RNA_float_get(op->ptr, "remove_error_margin");
+ /* The decimate algorithm expects the error to be squared. */
+ error_sq_max *= error_sq_max;
+
+ break;
+ }
+
+ if (remove_ratio == 0.0f || error_sq_max == 0.0f) {
+ /* Nothing to remove. */
+ return OPERATOR_FINISHED;
+ }
+
+ decimate_graph_keys(&ac, remove_ratio, error_sq_max);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1348,6 +1682,55 @@ static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static bool graphkeys_decimate_poll_property(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+
+ if (STRPREFIX(prop_id, "remove")) {
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ if (STREQ(prop_id, "remove_ratio") && mode != DECIM_RATIO) {
+ return false;
+ }
+ else if (STREQ(prop_id, "remove_error_margin") && mode != DECIM_ERROR) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static char *graphkeys_decimate_desc(bContext *UNUSED(C),
+ wmOperatorType *UNUSED(op),
+ PointerRNA *ptr)
+{
+
+ if (RNA_enum_get(ptr, "mode") == DECIM_ERROR) {
+ return BLI_strdup(
+ "Decimate F-Curves by specifying how much it can deviate from the original curve");
+ }
+
+ /* Use default description. */
+ return NULL;
+}
+
+static const EnumPropertyItem decimate_mode_items[] = {
+ {DECIM_RATIO,
+ "RATIO",
+ 0,
+ "Ratio",
+ "Use a percentage to specify how many keyframes you want to remove"},
+ {DECIM_ERROR,
+ "ERROR",
+ 0,
+ "Error Margin",
+ "Use an error margin to specify how much the curve is allowed to deviate from the original "
+ "path"},
+ {0, NULL, 0, NULL, NULL},
+};
+
void GRAPH_OT_decimate(wmOperatorType *ot)
{
/* identifiers */
@@ -1357,6 +1740,10 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
"Decimate F-Curves by removing keyframes that influence the curve shape the least";
/* api callbacks */
+ ot->poll_property = graphkeys_decimate_poll_property;
+ ot->get_description = graphkeys_decimate_desc;
+ ot->invoke = graphkeys_decimate_invoke;
+ ot->modal = graphkeys_decimate_modal;
ot->exec = graphkeys_decimate_exec;
ot->poll = graphop_editable_keyframes_poll;
@@ -1364,15 +1751,31 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_float_percentage(ot->srna,
- "remove_ratio",
- 1.0f / 3.0f,
- 0.0f,
- 1.0f,
- "Remove",
- "The percentage of keyframes to remove",
- 0.0f,
- 1.0f);
+ RNA_def_enum(ot->srna,
+ "mode",
+ decimate_mode_items,
+ DECIM_RATIO,
+ "Mode",
+ "Which mode to use for decimation");
+
+ RNA_def_float_percentage(ot->srna,
+ "remove_ratio",
+ 1.0f / 3.0f,
+ 0.0f,
+ 1.0f,
+ "Remove",
+ "The percentage of keyframes to remove",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "remove_error_margin",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Max Error Margin",
+ "How much the new decimated curve is allowed to deviate from the original",
+ 0.0f,
+ 10.0f);
}
/* ******************** Bake F-Curve Operator *********************** */
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index b8d9d3b791f..7bc907bb3db 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -81,7 +81,7 @@ static SpaceLink *graph_new(const ScrArea *UNUSED(sa), const Scene *scene)
/* settings for making it easier by default to just see what you're interested in tweaking */
sipo->ads->filterflag |= ADS_FILTER_ONLYSEL;
- sipo->flag |= SIPO_SELVHANDLESONLY | SIPO_MARKER_LINES;
+ sipo->flag |= SIPO_SELVHANDLESONLY | SIPO_SHOW_MARKERS;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for graphedit");
@@ -296,10 +296,9 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar)
if (sipo->mode != SIPO_MODE_DRIVERS) {
UI_view2d_view_orthoSpecial(ar, v2d, 1);
int marker_draw_flag = DRAW_MARKERS_MARGIN;
- if (sipo->flag & SIPO_MARKER_LINES) {
- marker_draw_flag |= DRAW_MARKERS_LINES;
+ if (sipo->flag & SIPO_SHOW_MARKERS) {
+ ED_markers_draw(C, marker_draw_flag);
}
- ED_markers_draw(C, marker_draw_flag);
}
/* preview range */
@@ -906,5 +905,8 @@ void ED_spacetype_ipo(void)
graph_buttons_register(art);
+ art = ED_area_type_hud(st->spaceid);
+ BLI_addhead(&st->regiontypes, art);
+
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 2d4ca6dc15a..3f563fe9033 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -37,6 +37,7 @@
#include "PIL_time.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_threads.h"
@@ -531,6 +532,39 @@ static void sima_draw_zbuffloat_pixels(Scene *scene,
MEM_freeN(rectf);
}
+static void draw_udim_label(ARegion *ar, float fx, float fy, const char *label)
+{
+ if (label == NULL || !label[0]) {
+ return;
+ }
+
+ /* find window pixel coordinates of origin */
+ int x, y;
+ UI_view2d_view_to_region(&ar->v2d, fx, fy, &x, &y);
+
+ GPU_blend_set_func_separate(
+ GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ int textwidth = BLF_width(blf_mono_font, label, strlen(label)) + 10;
+ float stepx = BLI_rcti_size_x(&ar->v2d.mask) / BLI_rctf_size_x(&ar->v2d.cur);
+ float opacity;
+ if (textwidth < 0.5f * (stepx - 10)) {
+ opacity = 1.0f;
+ }
+ else if (textwidth < (stepx - 10)) {
+ opacity = 2.0f - 2.0f * (textwidth / (stepx - 10));
+ }
+ else {
+ opacity = 0.0f;
+ }
+ BLF_color4ub(blf_mono_font, 220, 220, 220, 150 * opacity);
+ BLF_position(blf_mono_font, (int)(x + 10), (int)(y + 10), 0);
+ BLF_draw_ascii(blf_mono_font, label, strlen(label));
+
+ GPU_blend(false);
+}
+
static void draw_image_buffer(const bContext *C,
SpaceImage *sima,
ARegion *ar,
@@ -760,6 +794,83 @@ static void draw_image_paint_helpers(
}
}
+static void draw_udim_tile_grid(unsigned int pos_attr,
+ unsigned int color_attr,
+ ARegion *ar,
+ int x,
+ int y,
+ float stepx,
+ float stepy,
+ const float color[3])
+{
+ float x1, y1;
+ UI_view2d_view_to_region_fl(&ar->v2d, x, y, &x1, &y1);
+ int gridpos[5][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ for (int i = 0; i < 4; i++) {
+ immAttr3fv(color_attr, color);
+ immVertex2f(pos_attr, x1 + gridpos[i][0] * stepx, y1 + gridpos[i][1] * stepy);
+ immAttr3fv(color_attr, color);
+ immVertex2f(pos_attr, x1 + gridpos[i + 1][0] * stepx, y1 + gridpos[i + 1][1] * stepy);
+ }
+}
+
+static void draw_udim_tile_grids(ARegion *ar, SpaceImage *sima, Image *ima)
+{
+ int num_tiles;
+ if (ima != NULL) {
+ num_tiles = BLI_listbase_count(&ima->tiles);
+
+ if (ima->source != IMA_SRC_TILED) {
+ return;
+ }
+ }
+ else {
+ num_tiles = sima->tile_grid_shape[0] * sima->tile_grid_shape[1];
+ }
+
+ float stepx = BLI_rcti_size_x(&ar->v2d.mask) / BLI_rctf_size_x(&ar->v2d.cur);
+ float stepy = BLI_rcti_size_y(&ar->v2d.mask) / BLI_rctf_size_y(&ar->v2d.cur);
+
+ GPUVertFormat *format = immVertexFormat();
+ unsigned int pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ unsigned color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GPU_PRIM_LINES, 8 * num_tiles);
+
+ float theme_color[3], selected_color[3];
+ UI_GetThemeColorShade3fv(TH_BACK, 60.0f, theme_color);
+ UI_GetThemeColor3fv(TH_FACE_SELECT, selected_color);
+
+ if (ima != NULL) {
+ ImageTile *cur_tile = BLI_findlink(&ima->tiles, ima->active_tile_index);
+
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ if (tile != cur_tile) {
+ int x = (tile->tile_number - 1001) % 10;
+ int y = (tile->tile_number - 1001) / 10;
+ draw_udim_tile_grid(pos, color, ar, x, y, stepx, stepy, theme_color);
+ }
+ }
+
+ if (cur_tile != NULL) {
+ int cur_x = (cur_tile->tile_number - 1001) % 10;
+ int cur_y = (cur_tile->tile_number - 1001) / 10;
+ draw_udim_tile_grid(pos, color, ar, cur_x, cur_y, stepx, stepy, selected_color);
+ }
+ }
+ else {
+ for (int y = 0; y < sima->tile_grid_shape[1]; y++) {
+ for (int x = 0; x < sima->tile_grid_shape[0]; x++) {
+ draw_udim_tile_grid(pos, color, ar, x, y, stepx, stepy, theme_color);
+ }
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
+}
+
/* draw main image region */
void draw_image_main(const bContext *C, ARegion *ar)
@@ -827,18 +938,43 @@ void draw_image_main(const bContext *C, ARegion *ar)
}
}
- ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
+
+ int main_w = 0;
+ int main_h = 0;
/* draw the image or grid */
if (ibuf == NULL) {
- ED_region_grid_draw(ar, zoomx, zoomy);
+ if (ima != NULL) {
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ int x = (tile->tile_number - 1001) % 10;
+ int y = (tile->tile_number - 1001) / 10;
+ ED_region_grid_draw(ar, zoomx, zoomy, x, y);
+ }
+ }
+ else {
+ for (int y = 0; y < sima->tile_grid_shape[1]; y++) {
+ for (int x = 0; x < sima->tile_grid_shape[0]; x++) {
+ ED_region_grid_draw(ar, zoomx, zoomy, x, y);
+ }
+ }
+ }
}
else {
if (sima->flag & SI_DRAW_TILE) {
draw_image_buffer_repeated(C, sima, ar, scene, ibuf, zoomx, zoomy);
}
else {
+ main_w = ibuf->x;
+ main_h = ibuf->y;
+
draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
+ if (ima->source == IMA_SRC_TILED) {
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ char label[sizeof(tile->label)];
+ BKE_image_get_tile_label(ima, tile, label, sizeof(label));
+ draw_udim_label(ar, 0.0f, 0.0f, label);
+ }
}
if (sima->flag & SI_DRAW_METADATA) {
@@ -854,6 +990,30 @@ void draw_image_main(const bContext *C, ARegion *ar)
ED_space_image_release_buffer(sima, ibuf, lock);
+ if (ima != NULL && ima->source == IMA_SRC_TILED) {
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ if (tile->tile_number == 1001) {
+ continue;
+ }
+
+ ibuf = ED_space_image_acquire_buffer(sima, &lock, tile->tile_number);
+ if (ibuf != NULL) {
+ int x_pos = (tile->tile_number - 1001) % 10;
+ int y_pos = (tile->tile_number - 1001) / 10;
+ char label[sizeof(tile->label)];
+ BKE_image_get_tile_label(ima, tile, label, sizeof(label));
+
+ float tile_zoomx = (zoomx * main_w) / ibuf->x;
+ float tile_zoomy = (zoomy * main_h) / ibuf->y;
+ draw_image_buffer(C, sima, ar, scene, ibuf, x_pos, y_pos, tile_zoomx, tile_zoomy);
+ draw_udim_label(ar, x_pos, y_pos, label);
+ }
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ }
+
+ draw_udim_tile_grids(ar, sima, ima);
+
/* paint helpers */
if (show_paint) {
draw_image_paint_helpers(C, ar, scene, zoomx, zoomy);
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index ec2b1cc7fbe..c1ed049130e 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -136,7 +136,7 @@ void ED_space_image_set_mask(bContext *C, SpaceImage *sima, Mask *mask)
}
}
-ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock)
+ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock, int tile)
{
ImBuf *ibuf;
@@ -148,7 +148,9 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock)
else
#endif
{
+ sima->iuser.tile = tile;
ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, r_lock);
+ sima->iuser.tile = 0;
}
if (ibuf) {
@@ -179,7 +181,7 @@ bool ED_space_image_has_buffer(SpaceImage *sima)
void *lock;
bool has_buffer;
- ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
has_buffer = (ibuf != NULL);
ED_space_image_release_buffer(sima, ibuf, lock);
@@ -192,7 +194,8 @@ void ED_space_image_get_size(SpaceImage *sima, int *width, int *height)
ImBuf *ibuf;
void *lock;
- ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ /* TODO(lukas): Support tiled images with different sizes */
+ ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
if (ibuf && ibuf->x > 0 && ibuf->y > 0) {
*width = ibuf->x;
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index f8ce065d46c..f3ec68db562 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -89,6 +89,10 @@ void IMAGE_OT_read_viewlayers(struct wmOperatorType *ot);
void IMAGE_OT_render_border(struct wmOperatorType *ot);
void IMAGE_OT_clear_render_border(struct wmOperatorType *ot);
+void IMAGE_OT_tile_add(struct wmOperatorType *ot);
+void IMAGE_OT_tile_remove(struct wmOperatorType *ot);
+void IMAGE_OT_tile_fill(struct wmOperatorType *ot);
+
/* image_panels.c */
struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
void image_buttons_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 8d17b703449..061ed978acd 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -35,7 +35,10 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
#include "BLI_ghash.h"
+#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -1264,6 +1267,65 @@ static int image_cmp_frame(const void *a, const void *b)
return 0;
}
+/* Checks whether the given filepath refers to a UDIM texture.
+ * If yes, the range from 1001 to the highest tile is returned, otherwise 0.
+ *
+ * If the result is positive, the filepath will be overwritten with that of
+ * the 1001 tile.
+ * udim_tiles may get filled even if the result ultimately is false! */
+static int image_get_udim(char *filepath, LinkNodePair *udim_tiles)
+{
+ char filename[FILE_MAX], dirname[FILE_MAXDIR];
+ BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
+
+ unsigned short digits;
+ char base_head[FILE_MAX], base_tail[FILE_MAX];
+ int id = BLI_stringdec(filename, base_head, base_tail, &digits);
+
+ if (id < 1001 || id >= IMA_UDIM_MAX) {
+ return 0;
+ }
+
+ bool is_udim = true;
+ bool has_primary = false;
+ int max_udim = 0;
+
+ struct direntry *dir;
+ uint totfile = BLI_filelist_dir_contents(dirname, &dir);
+ for (int i = 0; i < totfile; i++) {
+ if (!(dir[i].type & S_IFREG)) {
+ continue;
+ }
+ char head[FILE_MAX], tail[FILE_MAX];
+ id = BLI_stringdec(dir[i].relname, head, tail, &digits);
+
+ if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
+ !(STREQLEN(base_tail, tail, FILE_MAX))) {
+ continue;
+ }
+
+ if (id < 1001 || id >= IMA_UDIM_MAX) {
+ is_udim = false;
+ break;
+ }
+ if (id == 1001) {
+ has_primary = true;
+ }
+
+ BLI_linklist_append(udim_tiles, POINTER_FROM_INT(id));
+ max_udim = max_ii(max_udim, id);
+ }
+ BLI_filelist_free(dir, totfile);
+
+ if (is_udim && has_primary) {
+ char primary_filename[FILE_MAX];
+ BLI_stringenc(primary_filename, base_head, base_tail, digits, 1001);
+ BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename);
+ return max_udim - 1000;
+ }
+ return 0;
+}
+
/**
* Return the start (offset) and the length of the sequence of
* continuous frames in the list of frames.
@@ -1272,17 +1334,30 @@ static int image_cmp_frame(const void *a, const void *b)
* \param ofs: [out] offset the first frame number in the sequence.
* \return the number of contiguous frames in the sequence
*/
-static int image_sequence_get_len(ListBase *frames, int *ofs)
+static int image_sequence_get_len(ImageFrameRange *frame_range,
+ int *ofs,
+ char *filepath_range,
+ LinkNodePair *udim_tiles)
{
ImageFrame *frame;
- BLI_listbase_sort(frames, image_cmp_frame);
+ BLI_listbase_sort(&frame_range->frames, image_cmp_frame);
+ BLI_strncpy(filepath_range, frame_range->filepath, FILE_MAX);
- frame = frames->first;
- if (frame) {
+ frame = frame_range->frames.first;
+ if (frame != NULL) {
int frame_curr = frame->framenr;
(*ofs) = frame_curr;
- while (frame && (frame->framenr == frame_curr)) {
+
+ if (udim_tiles != NULL) {
+ int len_udim = image_get_udim(filepath_range, udim_tiles);
+ if (len_udim > 0) {
+ *ofs = 1001;
+ return len_udim;
+ }
+ }
+
+ while (frame != NULL && (frame->framenr == frame_curr)) {
frame_curr++;
frame = frame->next;
}
@@ -1298,7 +1373,9 @@ static Image *image_open_single(Main *bmain,
const char *relbase,
bool is_relative_path,
bool use_multiview,
- int frame_seq_len)
+ int frame_seq_len,
+ int frame_seq_ofs,
+ LinkNodePair *udim_tiles)
{
bool exists = false;
Image *ima = NULL;
@@ -1339,7 +1416,15 @@ static Image *image_open_single(Main *bmain,
}
if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) {
- ima->source = IMA_SRC_SEQUENCE;
+ if (udim_tiles && frame_seq_ofs == 1001) {
+ ima->source = IMA_SRC_TILED;
+ for (LinkNode *node = udim_tiles->list; node; node = node->next) {
+ BKE_image_add_tile(ima, POINTER_AS_INT(node->link), NULL);
+ }
+ }
+ else {
+ ima->source = IMA_SRC_SEQUENCE;
+ }
}
}
@@ -1361,6 +1446,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
+ const bool use_udim = RNA_boolean_get(op->ptr, "use_udim_detecting");
if (!op->customdata) {
image_open_init(C, op);
@@ -1378,11 +1464,14 @@ static int image_open_exec(bContext *C, wmOperator *op)
for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range;
frame_range = frame_range->next) {
int frame_range_ofs;
- int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs);
- BLI_freelistN(&frame_range->frames);
+
+ LinkNodePair udim_tiles = {NULL};
+ LinkNodePair *udim_tiles_ptr = use_udim ? (&udim_tiles) : NULL;
char filepath_range[FILE_MAX];
- BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range));
+ int frame_range_seq_len = image_sequence_get_len(
+ frame_range, &frame_range_ofs, filepath_range, udim_tiles_ptr);
+ BLI_freelistN(&frame_range->frames);
if (was_relative) {
BLI_path_rel(filepath_range, BKE_main_blendfile_path(bmain));
@@ -1394,7 +1483,9 @@ static int image_open_exec(bContext *C, wmOperator *op)
BKE_main_blendfile_path(bmain),
is_relative_path,
use_multiview,
- frame_range_seq_len);
+ frame_range_seq_len,
+ frame_range_ofs,
+ udim_tiles_ptr);
/* take the first image */
if ((ima == NULL) && ima_range) {
@@ -1402,13 +1493,41 @@ static int image_open_exec(bContext *C, wmOperator *op)
frame_seq_len = frame_range_seq_len;
frame_ofs = frame_range_ofs;
}
+
+ BLI_linklist_free(udim_tiles.list, NULL);
}
BLI_freelistN(&frame_ranges_all);
}
else {
/* for drag & drop etc. */
- ima = image_open_single(
- bmain, op, filepath, BKE_main_blendfile_path(bmain), is_relative_path, use_multiview, 1);
+
+ LinkNodePair udim_tiles = {NULL};
+ frame_seq_len = 1;
+ char filepath_range[FILE_MAX];
+ BLI_strncpy(filepath_range, filepath, FILE_MAX);
+
+ if (use_udim > 0) {
+ /* Try to find UDIM tiles corresponding to the image */
+ int udim_len = image_get_udim(filepath_range, &udim_tiles);
+
+ /* If we found something, mark the image as tiled. */
+ if (udim_len) {
+ frame_seq_len = udim_len;
+ frame_ofs = 1001;
+ }
+ }
+
+ ima = image_open_single(bmain,
+ op,
+ filepath_range,
+ BKE_main_blendfile_path(bmain),
+ is_relative_path,
+ use_multiview,
+ frame_seq_len,
+ frame_ofs,
+ &udim_tiles);
+
+ BLI_linklist_free(udim_tiles.list, NULL);
}
if (ima == NULL) {
@@ -1458,7 +1577,8 @@ static int image_open_exec(bContext *C, wmOperator *op)
/* initialize because of new image */
if (iuser) {
- iuser->frames = frame_seq_len;
+ /* If the sequence was a tiled image, we only have one frame. */
+ iuser->frames = (ima->source == IMA_SRC_SEQUENCE) ? frame_seq_len : 1;
iuser->sfra = 1;
iuser->framenr = 1;
if (ima->source == IMA_SRC_MOVIE) {
@@ -1604,6 +1724,11 @@ void IMAGE_OT_open(wmOperatorType *ot)
true,
"Detect Sequences",
"Automatically detect animated sequences in selected images (based on file names)");
+ RNA_def_boolean(ot->srna,
+ "use_udim_detecting",
+ true,
+ "Detect UDIMs",
+ "Detect selected UDIM files and load all matching tiles");
}
/** \} */
@@ -1870,6 +1995,12 @@ static int image_save_options_init(Main *bmain,
BLI_path_make_safe(opts->filepath);
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
+
+ /* append UDIM numbering if not present */
+ if (ima->source == IMA_SRC_TILED && (BLI_stringdec(ima->name, NULL, NULL, NULL) != 1001)) {
+ int len = strlen(opts->filepath);
+ STR_CONCAT(opts->filepath, len, ".1001");
+ }
}
/* color management */
@@ -2608,13 +2739,23 @@ static int image_new_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "color", color);
alpha = RNA_boolean_get(op->ptr, "alpha");
stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
+ bool tiled = RNA_boolean_get(op->ptr, "tiled");
if (!alpha) {
color[3] = 1.0f;
}
- ima = BKE_image_add_generated(
- bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d, false);
+ ima = BKE_image_add_generated(bmain,
+ width,
+ height,
+ name,
+ alpha ? 32 : 24,
+ floatbuf,
+ gen_type,
+ color,
+ stereo3d,
+ false,
+ tiled);
if (!ima) {
image_new_free(op);
@@ -2698,6 +2839,9 @@ static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
uiItemL(col[0], "", ICON_NONE);
uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], &ptr, "tiled", 0, NULL, ICON_NONE);
+
#if 0
if (is_multiview) {
uiItemL(col[0], "", ICON_NONE);
@@ -2753,6 +2897,8 @@ void IMAGE_OT_new(wmOperatorType *ot)
prop = RNA_def_boolean(
ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "tiled", 0, "Tiled", "Create a tiled image");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
#undef IMA_DEF_NAME
@@ -2783,7 +2929,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);
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, 0);
if (is_paint) {
ED_imapaint_clear_partial_redraw();
@@ -2927,7 +3073,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);
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, 0);
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
IMB_scaleImBuf(ibuf, size[0], size[1]);
@@ -2977,7 +3123,7 @@ static bool image_pack_test(bContext *C, wmOperator *op)
return 0;
}
- if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
+ if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
return 0;
}
@@ -3045,7 +3191,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
+ if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
return OPERATOR_CANCELLED;
}
@@ -3078,7 +3224,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
return OPERATOR_CANCELLED;
}
- if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
+ if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
return OPERATOR_CANCELLED;
}
@@ -3210,9 +3356,12 @@ static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
{
+ float uv[2];
+ UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &uv[0], &uv[1]);
+ int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
+
void *lock;
- ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
- float fx, fy;
+ ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
bool ret = false;
if (ibuf == NULL) {
@@ -3220,12 +3369,10 @@ bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], flo
return false;
}
- UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fx, &fy);
-
- if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
+ if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
const float *fp;
unsigned char *cp;
- int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
+ int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
CLAMP(y, 0, ibuf->y - 1);
@@ -3326,10 +3473,15 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
{
SpaceImage *sima = CTX_wm_space_image(C);
ARegion *ar = CTX_wm_region(C);
+ Image *image = ED_space_image(sima);
+
+ float uv[2];
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &uv[0], &uv[1]);
+ int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
+
void *lock;
- ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
ImageSampleInfo *info = op->customdata;
- float fx, fy;
Scene *scene = CTX_data_scene(C);
CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
@@ -3339,11 +3491,8 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
return;
}
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
-
- if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
- int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
- Image *image = ED_space_image(sima);
+ if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
+ int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
CLAMP(y, 0, ibuf->y - 1);
@@ -3551,18 +3700,25 @@ static int image_sample_line_exec(bContext *C, wmOperator *op)
SpaceImage *sima = CTX_wm_space_image(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
+ Image *ima = ED_space_image(sima);
int x_start = RNA_int_get(op->ptr, "xstart");
int y_start = RNA_int_get(op->ptr, "ystart");
int x_end = RNA_int_get(op->ptr, "xend");
int y_end = RNA_int_get(op->ptr, "yend");
+ float uv1[2], uv2[2], ofs[2];
+ UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &uv1[0], &uv1[1]);
+ UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &uv2[0], &uv2[1]);
+
+ /* If the image has tiles, shift the positions accordingly. */
+ int tile = BKE_image_get_tile_from_pos(ima, uv1, uv1, ofs);
+ sub_v2_v2(uv2, ofs);
+
void *lock;
- ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
Histogram *hist = &sima->sample_line_hist;
- float x1f, y1f, x2f, y2f;
-
if (ibuf == NULL) {
ED_space_image_release_buffer(sima, ibuf, lock);
return OPERATOR_CANCELLED;
@@ -3573,13 +3729,8 @@ static int image_sample_line_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
- UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
-
- hist->co[0][0] = x1f;
- hist->co[0][1] = y1f;
- hist->co[1][0] = x2f;
- hist->co[1][1] = y2f;
+ copy_v2_v2(hist->co[0], uv1);
+ copy_v2_v2(hist->co[1], uv2);
/* enable line drawing */
hist->flag |= HISTO_FLAG_SAMPLELINE;
@@ -4085,3 +4236,315 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot)
}
/** \} */
+
+/* ********************* Add tile operator ****************** */
+
+static bool do_fill_tile(PointerRNA *ptr, Image *ima, ImageTile *tile)
+{
+ float color[4];
+ RNA_float_get_array(ptr, "color", color);
+ int gen_type = RNA_enum_get(ptr, "generated_type");
+ int width = RNA_int_get(ptr, "width");
+ int height = RNA_int_get(ptr, "height");
+ bool is_float = RNA_boolean_get(ptr, "float");
+ int planes = RNA_boolean_get(ptr, "alpha") ? 32 : 24;
+
+ return BKE_image_fill_tile(ima, tile, width, height, color, gen_type, planes, is_float);
+}
+
+static void draw_fill_tile(PointerRNA *ptr, uiLayout *layout)
+{
+ uiLayout *split, *col[2];
+
+ split = uiLayoutSplit(layout, 0.5f, false);
+ col[0] = uiLayoutColumn(split, false);
+ col[1] = uiLayoutColumn(split, false);
+
+ uiItemL(col[0], IFACE_("Color"), ICON_NONE);
+ uiItemR(col[1], ptr, "color", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Width"), ICON_NONE);
+ uiItemR(col[1], ptr, "width", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Height"), ICON_NONE);
+ uiItemR(col[1], ptr, "height", 0, "", ICON_NONE);
+
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], ptr, "alpha", 0, NULL, ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
+ uiItemR(col[1], ptr, "generated_type", 0, "", ICON_NONE);
+
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], ptr, "float", 0, NULL, ICON_NONE);
+}
+
+static void initialize_fill_tile(PointerRNA *ptr, Image *ima, ImageTile *tile)
+{
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ if (tile != NULL) {
+ iuser.tile = tile->tile_number;
+ }
+
+ /* Acquire ibuf to get the default values.
+ * If the specified tile has no ibuf, try acquiring the main tile instead
+ * (unless the specified tile already was the main tile).*/
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ if (ibuf == NULL && (tile != NULL) && (tile->tile_number != 1001)) {
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ }
+
+ if (ibuf != NULL) {
+ /* Initialize properties from reference tile. */
+ RNA_int_set(ptr, "width", ibuf->x);
+ RNA_int_set(ptr, "height", ibuf->y);
+ RNA_boolean_set(ptr, "float", ibuf->rect_float != NULL);
+ RNA_boolean_set(ptr, "alpha", ibuf->planes > 24);
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+}
+
+static void def_fill_tile(StructOrFunctionRNA *srna)
+{
+ PropertyRNA *prop;
+ static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ prop = RNA_def_float_color(
+ srna, "color", 4, NULL, 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);
+ RNA_def_enum(srna,
+ "generated_type",
+ rna_enum_image_generated_type_items,
+ IMA_GENTYPE_BLANK,
+ "Generated Type",
+ "Fill the image with a grid for UV map testing");
+ prop = RNA_def_int(srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ prop = RNA_def_int(srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+
+ /* Only needed when filling the first tile. */
+ RNA_def_boolean(
+ srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
+ RNA_def_boolean(srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
+}
+
+static bool tile_add_poll(bContext *C)
+{
+ Image *ima = CTX_data_edit_image(C);
+
+ return (ima != NULL && ima->source == IMA_SRC_TILED && BKE_image_has_ibuf(ima, NULL));
+}
+
+static int tile_add_exec(bContext *C, wmOperator *op)
+{
+ Image *ima = CTX_data_edit_image(C);
+
+ int start_tile = RNA_int_get(op->ptr, "number");
+ int end_tile = min_ii(start_tile + RNA_int_get(op->ptr, "count"), IMA_UDIM_MAX);
+ bool fill_tile = RNA_boolean_get(op->ptr, "fill");
+ char *label = RNA_string_get_alloc(op->ptr, "label", NULL, 0);
+
+ bool created_tile = false;
+ for (int tile_number = start_tile; tile_number < end_tile; tile_number++) {
+ ImageTile *tile = BKE_image_add_tile(ima, tile_number, label);
+
+ if (tile != NULL) {
+ ima->active_tile_index = BLI_findindex(&ima->tiles, tile);
+
+ if (fill_tile) {
+ do_fill_tile(op->ptr, ima, tile);
+ }
+
+ created_tile = true;
+ }
+ }
+ MEM_freeN(label);
+
+ if (!created_tile) {
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ return OPERATOR_FINISHED;
+}
+
+static int tile_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Image *ima = CTX_data_edit_image(C);
+
+ /* Find the first gap in tile numbers or the number after the last if
+ * no gap exists. */
+ int next_number = 0;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ next_number = tile->tile_number + 1;
+ if (tile->next == NULL || tile->next->tile_number > next_number) {
+ break;
+ }
+ }
+
+ ImageTile *tile = BLI_findlink(&ima->tiles, ima->active_tile_index);
+ initialize_fill_tile(op->ptr, ima, tile);
+
+ RNA_int_set(op->ptr, "number", next_number);
+ RNA_int_set(op->ptr, "count", 1);
+ RNA_string_set(op->ptr, "label", "");
+
+ return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y);
+}
+
+static void tile_add_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *split, *col[2];
+ uiLayout *layout = op->layout;
+ PointerRNA ptr;
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ split = uiLayoutSplit(layout, 0.5f, false);
+ col[0] = uiLayoutColumn(split, false);
+ col[1] = uiLayoutColumn(split, false);
+
+ uiItemL(col[0], IFACE_("Number"), ICON_NONE);
+ uiItemR(col[1], &ptr, "number", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Count"), ICON_NONE);
+ uiItemR(col[1], &ptr, "count", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Label"), ICON_NONE);
+ uiItemR(col[1], &ptr, "label", 0, "", ICON_NONE);
+
+ uiItemR(layout, &ptr, "fill", 0, NULL, ICON_NONE);
+
+ if (RNA_boolean_get(&ptr, "fill")) {
+ draw_fill_tile(&ptr, layout);
+ }
+}
+
+void IMAGE_OT_tile_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add tile";
+ ot->description = "Adds a tile to the image";
+ ot->idname = "IMAGE_OT_tile_add";
+
+ /* api callbacks */
+ ot->poll = tile_add_poll;
+ ot->exec = tile_add_exec;
+ ot->invoke = tile_add_invoke;
+ ot->ui = tile_add_draw;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int(
+ ot->srna, "number", 1002, 1001, INT_MAX, "Number", "UDIM number of the tile", 1001, 1099);
+ RNA_def_int(ot->srna, "count", 1, 1, INT_MAX, "Count", "How many tiles to add", 1, 1000);
+ RNA_def_string(ot->srna, "label", NULL, 0, "Label", "Optional tile label");
+ RNA_def_boolean(ot->srna, "fill", true, "Fill", "Fill new tile with a generated image");
+ def_fill_tile(ot->srna);
+}
+
+/* ********************* Remove tile operator ****************** */
+
+static bool tile_remove_poll(bContext *C)
+{
+ Image *ima = CTX_data_edit_image(C);
+
+ return (ima != NULL && ima->source == IMA_SRC_TILED && ima->active_tile_index != 0);
+}
+
+static int tile_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Image *ima = CTX_data_edit_image(C);
+
+ ImageTile *tile = BLI_findlink(&ima->tiles, ima->active_tile_index);
+ if (!BKE_image_remove_tile(ima, tile)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Ensure that the active index is valid. */
+ ima->active_tile_index = min_ii(ima->active_tile_index, BLI_listbase_count(&ima->tiles) - 1);
+
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_tile_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove tile";
+ ot->description = "Removes a tile from the image";
+ ot->idname = "IMAGE_OT_tile_remove";
+
+ /* api callbacks */
+ ot->poll = tile_remove_poll;
+ ot->exec = tile_remove_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************* Fill tile operator ****************** */
+
+static bool tile_fill_poll(bContext *C)
+{
+ Image *ima = CTX_data_edit_image(C);
+
+ if (ima != NULL && ima->source == IMA_SRC_TILED) {
+ /* Filling secondary tiles is only allowed if the primary tile exists. */
+ return (ima->active_tile_index == 0) || BKE_image_has_ibuf(ima, NULL);
+ }
+ return false;
+}
+
+static int tile_fill_exec(bContext *C, wmOperator *op)
+{
+ Image *ima = CTX_data_edit_image(C);
+
+ ImageTile *tile = BLI_findlink(&ima->tiles, ima->active_tile_index);
+ if (!do_fill_tile(op->ptr, ima, tile)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static int tile_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ initialize_fill_tile(op->ptr, CTX_data_edit_image(C), NULL);
+
+ return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
+}
+
+static void tile_fill_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ draw_fill_tile(&ptr, op->layout);
+}
+
+void IMAGE_OT_tile_fill(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Fill Tile";
+ ot->description = "Fill the current tile with a generated image";
+ ot->idname = "IMAGE_OT_tile_fill";
+
+ /* api callbacks */
+ ot->poll = tile_fill_poll;
+ ot->exec = tile_fill_exec;
+ ot->invoke = tile_fill_invoke;
+ ot->ui = tile_fill_draw;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ def_fill_tile(ot->srna);
+}
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index b6b32293cee..79aa4d2ed7f 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -107,6 +107,7 @@ typedef struct PaintTile {
struct PaintTile *next, *prev;
Image *image;
ImBuf *ibuf;
+ int tile_number;
union {
float *fp;
uint *uint;
@@ -148,6 +149,7 @@ static void ptile_invalidate_list(ListBase *paint_tiles)
void *ED_image_paint_tile_find(ListBase *paint_tiles,
Image *image,
ImBuf *ibuf,
+ int tile_number,
int x_tile,
int y_tile,
ushort **r_mask,
@@ -155,7 +157,7 @@ void *ED_image_paint_tile_find(ListBase *paint_tiles,
{
for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
if (ptile->x_tile == x_tile && ptile->y_tile == y_tile) {
- if (ptile->image == image && ptile->ibuf == ibuf) {
+ if (ptile->image == image && ptile->ibuf == ibuf && ptile->tile_number == tile_number) {
if (r_mask) {
/* allocate mask if requested. */
if (!ptile->mask) {
@@ -178,6 +180,7 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
Image *image,
ImBuf *ibuf,
ImBuf **tmpibuf,
+ int tile_number,
int x_tile,
int y_tile,
ushort **r_mask,
@@ -191,7 +194,8 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
/* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
if (find_prev) {
- void *data = ED_image_paint_tile_find(paint_tiles, image, ibuf, x_tile, y_tile, r_mask, true);
+ void *data = ED_image_paint_tile_find(
+ paint_tiles, image, ibuf, tile_number, x_tile, y_tile, r_mask, true);
if (data) {
return data;
}
@@ -205,6 +209,7 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
ptile->image = image;
ptile->ibuf = ibuf;
+ ptile->tile_number = tile_number;
ptile->x_tile = x_tile;
ptile->y_tile = y_tile;
@@ -259,7 +264,10 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
Image *image = ptile->image;
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = ptile->tile_number;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, NULL);
const bool has_float = (ibuf->rect_float != NULL);
if (has_float) {
@@ -460,6 +468,8 @@ static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf)
}
}
+ BLI_assert(i == ubuf->tiles_len);
+
IMB_freeImBuf(tmpibuf);
}
@@ -514,13 +524,13 @@ typedef struct UndoImageHandle {
/** Each undo handle refers to a single image which may have multiple buffers. */
UndoRefID_Image image_ref;
+ /** Each tile of a tiled image has its own UndoImageHandle.
+ * The tile number of this IUser is used to distinguish them.
+ */
+ ImageUser iuser;
+
/**
* List of #UndoImageBuf's to support multiple buffers per image.
- *
- * \note To properly support multiple buffers per image
- * we would need to store an #ImageUser for each #UndoImageBuf.
- * since when restoring the image we use:
- * `BKE_image_acquire_ibuf(image, NULL, NULL)`.
*/
ListBase buffers;
@@ -533,7 +543,8 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
/* Tiles only added to second set of tiles. */
Image *image = uh->image_ref.ptr;
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &uh->iuser, NULL);
if (UNLIKELY(ibuf == NULL)) {
CLOG_ERROR(&LOG, "Unable to get buffer for image '%s'", image->id.name + 2);
continue;
@@ -626,40 +637,44 @@ static UndoImageBuf *uhandle_ensure_ubuf(UndoImageHandle *uh, Image *image, ImBu
return ubuf;
}
-static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles, const Image *image)
+static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles,
+ const Image *image,
+ int tile_number)
{
for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
- if (STREQ(image->id.name + 2, uh->image_ref.name + 2)) {
+ if (STREQ(image->id.name + 2, uh->image_ref.name + 2) && uh->iuser.tile == tile_number) {
return uh;
}
}
return NULL;
}
-static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image)
+static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image, int tile_number)
{
for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
- if (image == uh->image_ref.ptr) {
+ if (image == uh->image_ref.ptr && uh->iuser.tile == tile_number) {
return uh;
}
}
return NULL;
}
-static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image)
+static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image, int tile_number)
{
- BLI_assert(uhandle_lookup(undo_handles, image) == NULL);
+ BLI_assert(uhandle_lookup(undo_handles, image, tile_number) == NULL);
UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__);
uh->image_ref.ptr = image;
+ uh->iuser.ok = 1;
+ uh->iuser.tile = tile_number;
BLI_addtail(undo_handles, uh);
return uh;
}
-static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image)
+static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image, int tile_number)
{
- UndoImageHandle *uh = uhandle_lookup(undo_handles, image);
+ UndoImageHandle *uh = uhandle_lookup(undo_handles, image, tile_number);
if (uh == NULL) {
- uh = uhandle_add(undo_handles, image);
+ uh = uhandle_add(undo_handles, image, tile_number);
}
return uh;
}
@@ -693,10 +708,11 @@ typedef struct ImageUndoStep {
*/
static UndoImageBuf *ubuf_lookup_from_reference(ImageUndoStep *us_prev,
const Image *image,
+ int tile_number,
const UndoImageBuf *ubuf)
{
/* Use name lookup because because the pointer is cleared for previous steps. */
- UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image);
+ UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image, tile_number);
if (uh_prev != NULL) {
UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name);
if (ubuf_reference) {
@@ -763,7 +779,7 @@ static bool image_undosys_step_encode(struct bContext *C,
/* Initialize undo tiles from ptiles (if they exist). */
for (PaintTile *ptile = us->paint_tiles.first, *ptile_next; ptile; ptile = ptile_next) {
if (ptile->valid) {
- UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image);
+ UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image, ptile->tile_number);
UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, ptile->image, ptile->ibuf);
UndoImageTile *utile = MEM_callocN(sizeof(*utile), "UndoImageTile");
@@ -783,7 +799,7 @@ static bool image_undosys_step_encode(struct bContext *C,
for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
for (UndoImageBuf *ubuf_pre = uh->buffers.first; ubuf_pre; ubuf_pre = ubuf_pre->next) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, NULL, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, &uh->iuser, NULL);
const bool has_float = ibuf->rect_float;
@@ -797,10 +813,10 @@ static bool image_undosys_step_encode(struct bContext *C,
}
else {
/* Search for the previous buffer. */
- UndoImageBuf *ubuf_reference = (us_reference ?
- ubuf_lookup_from_reference(
- us_reference, uh->image_ref.ptr, ubuf_post) :
- NULL);
+ UndoImageBuf *ubuf_reference =
+ (us_reference ? ubuf_lookup_from_reference(
+ us_reference, uh->image_ref.ptr, uh->iuser.tile, ubuf_post) :
+ NULL);
int i = 0;
for (uint y_tile = 0; y_tile < ubuf_pre->tiles_dims[1]; y_tile += 1) {
@@ -850,6 +866,8 @@ static bool image_undosys_step_encode(struct bContext *C,
i += 1;
}
}
+ BLI_assert(i == ubuf_pre->tiles_len);
+ BLI_assert(i == ubuf_post->tiles_len);
}
BKE_image_release_ibuf(uh->image_ref.ptr, ibuf, NULL);
}
@@ -1026,11 +1044,15 @@ void ED_image_undo_push_begin(const char *name, int paint_mode)
image_undo_push_begin(name, paint_mode);
}
-void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *ibuf)
+void ED_image_undo_push_begin_with_image(const char *name,
+ Image *image,
+ ImBuf *ibuf,
+ int tile_number)
{
ImageUndoStep *us = image_undo_push_begin(name, PAINT_MODE_TEXTURE_2D);
- UndoImageHandle *uh = uhandle_ensure(&us->handles, image);
+ BLI_assert(BKE_image_get_tile(image, tile_number));
+ UndoImageHandle *uh = uhandle_ensure(&us->handles, image, tile_number);
UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, image, ibuf);
BLI_assert(ubuf_pre->post == NULL);
@@ -1038,9 +1060,9 @@ void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *
while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
us_reference = (ImageUndoStep *)us_reference->step.prev;
}
- UndoImageBuf *ubuf_reference = (us_reference ?
- ubuf_lookup_from_reference(us_reference, image, ubuf_pre) :
- NULL);
+ UndoImageBuf *ubuf_reference = (us_reference ? ubuf_lookup_from_reference(
+ us_reference, image, tile_number, ubuf_pre) :
+ NULL);
if (ubuf_reference) {
memcpy(ubuf_pre->tiles, ubuf_reference->tiles, sizeof(*ubuf_pre->tiles) * ubuf_pre->tiles_len);
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index a88ecc91868..2f93be8ae38 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -134,6 +134,9 @@ static SpaceLink *image_new(const ScrArea *UNUSED(area), const Scene *UNUSED(sce
BKE_scopes_new(&simage->scopes);
simage->sample_line_hist.height = 100;
+ simage->tile_grid_shape[0] = 1;
+ simage->tile_grid_shape[1] = 1;
+
/* tool header */
ar = MEM_callocN(sizeof(ARegion), "tool header for image");
@@ -246,6 +249,10 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_read_viewlayers);
WM_operatortype_append(IMAGE_OT_render_border);
WM_operatortype_append(IMAGE_OT_clear_render_border);
+
+ WM_operatortype_append(IMAGE_OT_tile_add);
+ WM_operatortype_append(IMAGE_OT_tile_remove);
+ WM_operatortype_append(IMAGE_OT_tile_fill);
}
static void image_keymap(struct wmKeyConfig *keyconf)
@@ -457,14 +464,71 @@ static void IMAGE_GGT_gizmo2d(wmGizmoGroupType *gzgt)
gzgt->name = "UV Transform Gizmo";
gzgt->idname = "IMAGE_GGT_gizmo2d";
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
+ gzgt->gzmap_params.spaceid = SPACE_IMAGE;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_widgetgroup_gizmo2d_xform_poll;
+ gzgt->setup = ED_widgetgroup_gizmo2d_xform_setup;
+ gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
+ gzgt->refresh = ED_widgetgroup_gizmo2d_xform_refresh;
+ gzgt->draw_prepare = ED_widgetgroup_gizmo2d_xform_draw_prepare;
+}
+
+static void IMAGE_GGT_gizmo2d_translate(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "UV Translate Gizmo";
+ gzgt->idname = "IMAGE_GGT_gizmo2d_translate";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
+ gzgt->gzmap_params.spaceid = SPACE_IMAGE;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_widgetgroup_gizmo2d_xform_poll;
+ gzgt->setup = ED_widgetgroup_gizmo2d_xform_setup_no_cage;
+ gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
+ gzgt->refresh = ED_widgetgroup_gizmo2d_xform_refresh;
+ gzgt->draw_prepare = ED_widgetgroup_gizmo2d_xform_draw_prepare;
+}
+
+static void IMAGE_GGT_gizmo2d_resize(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "UV Transform Gizmo Resize";
+ gzgt->idname = "IMAGE_GGT_gizmo2d_resize";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
+ gzgt->gzmap_params.spaceid = SPACE_IMAGE;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_widgetgroup_gizmo2d_resize_poll;
+ gzgt->setup = ED_widgetgroup_gizmo2d_resize_setup;
+ gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
+ gzgt->refresh = ED_widgetgroup_gizmo2d_resize_refresh;
+ gzgt->draw_prepare = ED_widgetgroup_gizmo2d_resize_draw_prepare;
+}
+
+static void IMAGE_GGT_gizmo2d_rotate(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "UV Transform Gizmo Resize";
+ gzgt->idname = "IMAGE_GGT_gizmo2d_rotate";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
- gzgt->poll = ED_widgetgroup_gizmo2d_poll;
- gzgt->setup = ED_widgetgroup_gizmo2d_setup;
+ gzgt->poll = ED_widgetgroup_gizmo2d_rotate_poll;
+ gzgt->setup = ED_widgetgroup_gizmo2d_rotate_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
- gzgt->refresh = ED_widgetgroup_gizmo2d_refresh;
- gzgt->draw_prepare = ED_widgetgroup_gizmo2d_draw_prepare;
+ gzgt->refresh = ED_widgetgroup_gizmo2d_rotate_refresh;
+ gzgt->draw_prepare = ED_widgetgroup_gizmo2d_rotate_draw_prepare;
}
static void IMAGE_GGT_navigate(wmGizmoGroupType *gzgt)
@@ -478,6 +542,9 @@ static void image_widgets(void)
&(const struct wmGizmoMapType_Params){SPACE_IMAGE, RGN_TYPE_WINDOW});
WM_gizmogrouptype_append(IMAGE_GGT_gizmo2d);
+ WM_gizmogrouptype_append(IMAGE_GGT_gizmo2d_translate);
+ WM_gizmogrouptype_append(IMAGE_GGT_gizmo2d_resize);
+ WM_gizmogrouptype_append(IMAGE_GGT_gizmo2d_rotate);
WM_gizmogrouptype_append_and_link(gzmap_type, IMAGE_GGT_navigate);
}
@@ -783,7 +850,8 @@ static void image_buttons_region_draw(const bContext *C, ARegion *ar)
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
void *lock;
- ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ /* TODO(lukas): Support tiles in scopes? */
+ ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
/* XXX performance regression if name of scopes category changes! */
PanelCategoryStack *category = UI_panel_category_active_find(ar, "Scopes");
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 734515e1f79..64570459532 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -228,17 +228,27 @@ static int report_textview_line_color(struct TextViewContext *tvc,
#undef USE_INFO_NEWLINE
+static void info_textview_draw_rect_calc(const ARegion *ar, rcti *draw_rect)
+{
+ const int margin = 4 * UI_DPI_FAC;
+ draw_rect->xmin = margin;
+ draw_rect->xmax = ar->winx - (V2D_SCROLL_WIDTH + margin);
+ draw_rect->ymin = margin;
+ /* No margin at the top (allow text to scroll off the window). */
+ draw_rect->ymax = ar->winy;
+}
+
static int info_textview_main__internal(struct SpaceInfo *sinfo,
- ARegion *ar,
+ const ARegion *ar,
ReportList *reports,
- int draw,
- int mval[2],
- void **mouse_pick,
- int *pos_pick)
+ const bool do_draw,
+ const int mval[2],
+ void **r_mval_pick_item,
+ int *r_mval_pick_offset)
{
int ret = 0;
- View2D *v2d = &ar->v2d;
+ const View2D *v2d = &ar->v2d;
TextViewContext tvc = {0};
tvc.begin = report_textview_begin;
@@ -256,35 +266,33 @@ static int info_textview_main__internal(struct SpaceInfo *sinfo,
tvc.sel_start = 0;
tvc.sel_end = 0;
tvc.lheight = 14 * UI_DPI_FAC; // sc->lheight;
- tvc.ymin = v2d->cur.ymin;
- tvc.ymax = v2d->cur.ymax;
- tvc.winx = ar->winx - V2D_SCROLL_WIDTH;
+ tvc.scroll_ymin = v2d->cur.ymin;
+ tvc.scroll_ymax = v2d->cur.ymax;
- ret = textview_draw(&tvc, draw, mval, mouse_pick, pos_pick);
+ info_textview_draw_rect_calc(ar, &tvc.draw_rect);
+
+ ret = textview_draw(&tvc, do_draw, mval, r_mval_pick_item, r_mval_pick_offset);
return ret;
}
-void *info_text_pick(struct SpaceInfo *sinfo, ARegion *ar, ReportList *reports, int mouse_y)
+void *info_text_pick(struct SpaceInfo *sinfo, const ARegion *ar, ReportList *reports, int mval_y)
{
- void *mouse_pick = NULL;
- int mval[2];
-
- mval[0] = 0;
- mval[1] = mouse_y;
+ void *mval_pick_item = NULL;
+ const int mval[2] = {0, mval_y};
- info_textview_main__internal(sinfo, ar, reports, 0, mval, &mouse_pick, NULL);
- return (void *)mouse_pick;
+ info_textview_main__internal(sinfo, ar, reports, false, mval, &mval_pick_item, NULL);
+ return (void *)mval_pick_item;
}
-int info_textview_height(struct SpaceInfo *sinfo, ARegion *ar, ReportList *reports)
+int info_textview_height(struct SpaceInfo *sinfo, const ARegion *ar, ReportList *reports)
{
int mval[2] = {INT_MAX, INT_MAX};
- return info_textview_main__internal(sinfo, ar, reports, 0, mval, NULL, NULL);
+ return info_textview_main__internal(sinfo, ar, reports, false, mval, NULL, NULL);
}
-void info_textview_main(struct SpaceInfo *sinfo, ARegion *ar, ReportList *reports)
+void info_textview_main(struct SpaceInfo *sinfo, const ARegion *ar, ReportList *reports)
{
int mval[2] = {INT_MAX, INT_MAX};
- info_textview_main__internal(sinfo, ar, reports, 1, mval, NULL, NULL);
+ info_textview_main__internal(sinfo, ar, reports, true, mval, NULL, NULL);
}
diff --git a/source/blender/editors/space_info/info_intern.h b/source/blender/editors/space_info/info_intern.h
index 7d4d6e5ab90..177b43edf74 100644
--- a/source/blender/editors/space_info/info_intern.h
+++ b/source/blender/editors/space_info/info_intern.h
@@ -46,11 +46,15 @@ void INFO_OT_reports_display_update(struct wmOperatorType *ot);
/* info_draw.c */
void *info_text_pick(struct SpaceInfo *sinfo,
- struct ARegion *ar,
+ const struct ARegion *ar,
ReportList *reports,
int mouse_y);
-int info_textview_height(struct SpaceInfo *sinfo, struct ARegion *ar, struct ReportList *reports);
-void info_textview_main(struct SpaceInfo *sinfo, struct ARegion *ar, struct ReportList *reports);
+int info_textview_height(struct SpaceInfo *sinfo,
+ const struct ARegion *ar,
+ struct ReportList *reports);
+void info_textview_main(struct SpaceInfo *sinfo,
+ const struct ARegion *ar,
+ struct ReportList *reports);
/* info_report.c */
int info_report_mask(struct SpaceInfo *sinfo);
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index b51aec90e4f..225ca72a7d0 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -123,6 +123,10 @@ static bool stats_mesheval(Mesh *me_eval, bool is_selected, SceneStats *stats)
static void stats_object(Object *ob, SceneStats *stats, GSet *objects_gset)
{
+ if ((ob->base_flag & BASE_VISIBLE_VIEWLAYER) == 0) {
+ return;
+ }
+
const bool is_selected = (ob->base_flag & BASE_SELECTED) != 0;
stats->totobj++;
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index 97d5faa9c13..1bc583461a5 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -39,40 +39,40 @@
static void console_font_begin(const int font_id, const int lheight)
{
- /* 0.875 is based on: 16 pixels lines get 14 pixel text */
+ /* 0.875 is based on: 16 pixels lines get 14 pixel text. */
BLF_size(font_id, 0.875 * lheight, 72);
}
-typedef struct ConsoleDrawContext {
+typedef struct TextViewDrawState {
int font_id;
int cwidth;
int lheight;
- /** text vertical offset */
+ /** Text vertical offset per line. */
int lofs;
- /** number of characters that fit into the width of the console (fixed width) */
- int console_width;
- int winx;
- int ymin, ymax;
+ /** Number of characters that fit into the width of the console (fixed width). */
+ int columns;
+ const rcti *draw_rect;
+ int scroll_ymin, scroll_ymax;
int *xy; // [2]
int *sel; // [2]
- /* bottom of view == 0, top of file == combine chars, end of line is lower then start. */
- int *pos_pick;
+ /* Bottom of view == 0, top of file == combine chars, end of line is lower then start. */
+ int *mval_pick_offset;
const int *mval; // [2]
- int draw;
-} ConsoleDrawContext;
+ bool do_draw;
+} TextViewDrawState;
-BLI_INLINE void console_step_sel(ConsoleDrawContext *cdc, const int step)
+BLI_INLINE void console_step_sel(TextViewDrawState *tds, const int step)
{
- cdc->sel[0] += step;
- cdc->sel[1] += step;
+ tds->sel[0] += step;
+ tds->sel[1] += step;
}
static void console_draw_sel(const char *str,
const int sel[2],
const int xy[2],
const int str_len_draw,
- int cwidth,
- int lheight,
+ const int cwidth,
+ const int lheight,
const unsigned char bg_sel[4])
{
if (sel[0] <= str_len_draw && sel[1] >= 0) {
@@ -96,11 +96,14 @@ static void console_draw_sel(const char *str,
}
}
-/* warning: allocated memory for 'offsets' must be freed by caller */
+/**
+ * \warning Allocated memory for 'offsets' must be freed by caller.
+ * \return The length in bytes.
+ */
static int console_wrap_offsets(const char *str, int len, int width, int *lines, int **offsets)
{
- int i, end; /* column */
- int j; /* mem */
+ int i, end; /* Offset as unicode code-point. */
+ int j; /* Offset as bytes. */
*lines = 1;
@@ -121,79 +124,81 @@ static int console_wrap_offsets(const char *str, int len, int width, int *lines,
}
i += columns;
}
- return j; /* return actual length */
+ return j;
}
-/* return 0 if the last line is off the screen
- * should be able to use this for any string type */
-
-static int console_draw_string(ConsoleDrawContext *cdc,
- const char *str,
- int str_len,
- const unsigned char fg[3],
- const unsigned char bg[3],
- const unsigned char bg_sel[4])
+/**
+ * return false if the last line is off the screen
+ * should be able to use this for any string type.
+ */
+static bool console_draw_string(TextViewDrawState *tds,
+ const char *str,
+ int str_len,
+ const unsigned char fg[3],
+ const unsigned char bg[3],
+ const unsigned char bg_sel[4])
{
- int tot_lines; /* total number of lines for wrapping */
- int *offsets; /* offsets of line beginnings for wrapping */
+ int tot_lines; /* Total number of lines for wrapping. */
+ int *offsets; /* Offsets of line beginnings for wrapping. */
int y_next;
- str_len = console_wrap_offsets(str, str_len, cdc->console_width, &tot_lines, &offsets);
- y_next = cdc->xy[1] + cdc->lheight * tot_lines;
+ str_len = console_wrap_offsets(str, str_len, tds->columns, &tot_lines, &offsets);
+ y_next = tds->xy[1] + tds->lheight * tot_lines;
- /* just advance the height */
- if (cdc->draw == 0) {
- if (cdc->pos_pick && cdc->mval[1] != INT_MAX && cdc->xy[1] <= cdc->mval[1]) {
- if (y_next >= cdc->mval[1]) {
+ /* Just advance the height. */
+ if (tds->do_draw == false) {
+ if (tds->mval_pick_offset && tds->mval[1] != INT_MAX && tds->xy[1] <= tds->mval[1]) {
+ if (y_next >= tds->mval[1]) {
int ofs = 0;
- /* wrap */
+ /* Wrap. */
if (tot_lines > 1) {
- int iofs = (int)((float)(y_next - cdc->mval[1]) / cdc->lheight);
+ int iofs = (int)((float)(y_next - tds->mval[1]) / tds->lheight);
ofs += offsets[MIN2(iofs, tot_lines - 1)];
}
- /* last part */
+ /* Last part. */
ofs += BLI_str_utf8_offset_from_column(str + ofs,
- (int)floor((float)cdc->mval[0] / cdc->cwidth));
+ (int)floor((float)tds->mval[0] / tds->cwidth));
CLAMP(ofs, 0, str_len);
- *cdc->pos_pick += str_len - ofs;
+ *tds->mval_pick_offset += str_len - ofs;
}
else {
- *cdc->pos_pick += str_len + 1;
+ *tds->mval_pick_offset += str_len + 1;
}
}
- cdc->xy[1] = y_next;
+ tds->xy[1] = y_next;
MEM_freeN(offsets);
- return 1;
+ return true;
}
- else if (y_next < cdc->ymin) {
- /* have not reached the drawable area so don't break */
- cdc->xy[1] = y_next;
+ else if (y_next < tds->scroll_ymin) {
+ /* Have not reached the drawable area so don't break. */
+ tds->xy[1] = y_next;
- /* adjust selection even if not drawing */
- if (cdc->sel[0] != cdc->sel[1]) {
- console_step_sel(cdc, -(str_len + 1));
+ /* Adjust selection even if not drawing. */
+ if (tds->sel[0] != tds->sel[1]) {
+ console_step_sel(tds, -(str_len + 1));
}
MEM_freeN(offsets);
- return 1;
+ return true;
}
- if (tot_lines > 1) { /* wrap? */
+ /* Check if we need to wrap lines. */
+ if (tot_lines > 1) {
const int initial_offset = offsets[tot_lines - 1];
size_t len = str_len - initial_offset;
const char *s = str + initial_offset;
int i;
int sel_orig[2];
- copy_v2_v2_int(sel_orig, cdc->sel);
+ copy_v2_v2_int(sel_orig, tds->sel);
- /* invert and swap for wrapping */
- cdc->sel[0] = str_len - sel_orig[1];
- cdc->sel[1] = str_len - sel_orig[0];
+ /* Invert and swap for wrapping. */
+ tds->sel[0] = str_len - sel_orig[1];
+ tds->sel[1] = str_len - sel_orig[0];
if (bg) {
GPUVertFormat *format = immVertexFormat();
@@ -201,50 +206,52 @@ static int console_draw_string(ConsoleDrawContext *cdc,
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3ubv(bg);
- immRecti(pos, 0, cdc->xy[1], cdc->winx, (cdc->xy[1] + (cdc->lheight * tot_lines)));
+ immRecti(
+ pos, 0, tds->xy[1], tds->draw_rect->xmax, (tds->xy[1] + (tds->lheight * tot_lines)));
immUnbindProgram();
}
- /* last part needs no clipping */
- BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
- BLF_color3ubv(cdc->font_id, fg);
- BLF_draw_mono(cdc->font_id, s, len, cdc->cwidth);
+ /* Last part needs no clipping. */
+ BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0);
+ BLF_color3ubv(tds->font_id, fg);
+ BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
- if (cdc->sel[0] != cdc->sel[1]) {
- console_step_sel(cdc, -initial_offset);
- /* BLF_color3ub(cdc->font_id, 255, 0, 0); // debug */
- console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel);
+ if (tds->sel[0] != tds->sel[1]) {
+ console_step_sel(tds, -initial_offset);
+ /* BLF_color3ub(tds->font_id, 255, 0, 0); // debug */
+ console_draw_sel(s, tds->sel, tds->xy, len, tds->cwidth, tds->lheight, bg_sel);
}
- cdc->xy[1] += cdc->lheight;
+ tds->xy[1] += tds->lheight;
for (i = tot_lines - 1; i > 0; i--) {
len = offsets[i] - offsets[i - 1];
s = str + offsets[i - 1];
- BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
- BLF_draw_mono(cdc->font_id, s, len, cdc->cwidth);
+ 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 (cdc->sel[0] != cdc->sel[1]) {
- console_step_sel(cdc, len);
- /* BLF_color3ub(cdc->font_id, 0, 255, 0); // debug */
- console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel);
+ if (tds->sel[0] != tds->sel[1]) {
+ console_step_sel(tds, len);
+ /* BLF_color3ub(tds->font_id, 0, 255, 0); // debug */
+ console_draw_sel(s, tds->sel, tds->xy, len, tds->cwidth, tds->lheight, bg_sel);
}
- cdc->xy[1] += cdc->lheight;
+ tds->xy[1] += tds->lheight;
- /* check if were out of view bounds */
- if (cdc->xy[1] > cdc->ymax) {
+ /* Check if were out of view bounds. */
+ if (tds->xy[1] > tds->scroll_ymax) {
MEM_freeN(offsets);
- return 0;
+ return false;
}
}
- copy_v2_v2_int(cdc->sel, sel_orig);
- console_step_sel(cdc, -(str_len + 1));
+ copy_v2_v2_int(tds->sel, sel_orig);
+ console_step_sel(tds, -(str_len + 1));
}
- else { /* simple, no wrap */
+ else {
+ /* Simple, no wrap. */
if (bg) {
GPUVertFormat *format = immVertexFormat();
@@ -252,48 +259,57 @@ static int console_draw_string(ConsoleDrawContext *cdc,
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3ubv(bg);
- immRecti(pos, 0, cdc->xy[1], cdc->winx, cdc->xy[1] + cdc->lheight);
+ immRecti(pos, 0, tds->xy[1], tds->draw_rect->xmax, tds->xy[1] + tds->lheight);
immUnbindProgram();
}
- BLF_color3ubv(cdc->font_id, fg);
- BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
- BLF_draw_mono(cdc->font_id, str, str_len, cdc->cwidth);
+ BLF_color3ubv(tds->font_id, fg);
+ BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0);
+ BLF_draw_mono(tds->font_id, str, str_len, tds->cwidth);
- if (cdc->sel[0] != cdc->sel[1]) {
+ if (tds->sel[0] != tds->sel[1]) {
int isel[2];
- isel[0] = str_len - cdc->sel[1];
- isel[1] = str_len - cdc->sel[0];
+ isel[0] = str_len - tds->sel[1];
+ isel[1] = str_len - tds->sel[0];
- /* BLF_color3ub(cdc->font_id, 255, 255, 0); // debug */
- console_draw_sel(str, isel, cdc->xy, str_len, cdc->cwidth, cdc->lheight, bg_sel);
- console_step_sel(cdc, -(str_len + 1));
+ /* BLF_color3ub(tds->font_id, 255, 255, 0); // debug */
+ console_draw_sel(str, isel, tds->xy, str_len, tds->cwidth, tds->lheight, bg_sel);
+ console_step_sel(tds, -(str_len + 1));
}
- cdc->xy[1] += cdc->lheight;
+ tds->xy[1] += tds->lheight;
- if (cdc->xy[1] > cdc->ymax) {
+ if (tds->xy[1] > tds->scroll_ymax) {
MEM_freeN(offsets);
- return 0;
+ return false;
}
}
MEM_freeN(offsets);
- return 1;
+ return true;
}
-#define CONSOLE_DRAW_MARGIN 4
-
-int textview_draw(
- TextViewContext *tvc, const int draw, int mval[2], void **mouse_pick, int *pos_pick)
+/**
+ * \param r_mval_pick_item: The resulting item clicked on using \a mval_init.
+ * Set from the void pointer which holds the current iterator.
+ * It's type depends on the data being iterated over.
+ * \param r_mval_pick_offset: The offset in bytes of the \a mval_init.
+ * Use for selection.
+ */
+int textview_draw(TextViewContext *tvc,
+ const bool do_draw,
+ const int mval_init[2],
+ void **r_mval_pick_item,
+ int *r_mval_pick_offset)
{
- ConsoleDrawContext cdc = {0};
+ TextViewDrawState tds = {0};
- int x_orig = CONSOLE_DRAW_MARGIN, y_orig = CONSOLE_DRAW_MARGIN + tvc->lheight / 6;
- int xy[2], y_prev;
- int sel[2] = {-1, -1}; /* defaults disabled */
+ int x_orig = tvc->draw_rect.xmin, y_orig = tvc->draw_rect.ymin + tvc->lheight / 6;
+ int xy[2];
+ /* Disable selection by. */
+ int sel[2] = {-1, -1};
unsigned char fg[3], bg[3];
const int font_id = blf_mono_font;
@@ -302,38 +318,45 @@ int textview_draw(
xy[0] = x_orig;
xy[1] = y_orig;
- if (mval[1] != INT_MAX) {
- mval[1] += (tvc->ymin + CONSOLE_DRAW_MARGIN);
- }
-
- if (pos_pick) {
- *pos_pick = 0;
+ /* Offset and clamp the results,
+ * clamping so moving the cursor out of the bounds doesn't wrap onto the other lines. */
+ const int mval[2] = {
+ (mval_init[0] == INT_MAX) ?
+ INT_MAX :
+ CLAMPIS(mval_init[0], tvc->draw_rect.xmin, tvc->draw_rect.xmax) - tvc->draw_rect.xmin,
+ (mval_init[1] == INT_MAX) ?
+ INT_MAX :
+ CLAMPIS(mval_init[1], tvc->draw_rect.ymin, tvc->draw_rect.ymax) + tvc->scroll_ymin,
+ };
+
+ if (r_mval_pick_offset != NULL) {
+ *r_mval_pick_offset = 0;
}
- /* constants for the sequencer context */
- cdc.font_id = font_id;
- cdc.cwidth = (int)BLF_fixed_width(font_id);
- BLI_assert(cdc.cwidth > 0);
- cdc.lheight = tvc->lheight;
- cdc.lofs = -BLF_descender(font_id);
- /* note, scroll bar must be already subtracted () */
- cdc.console_width = (tvc->winx - (CONSOLE_DRAW_MARGIN * 2)) / cdc.cwidth;
- /* avoid divide by zero on small windows */
- if (cdc.console_width < 1) {
- cdc.console_width = 1;
+ /* Constants for the text-view context. */
+ tds.font_id = font_id;
+ tds.cwidth = (int)BLF_fixed_width(font_id);
+ BLI_assert(tds.cwidth > 0);
+ tds.lheight = tvc->lheight;
+ tds.lofs = -BLF_descender(font_id);
+ /* Note, scroll bar must be already subtracted. */
+ tds.columns = (tvc->draw_rect.xmax - tvc->draw_rect.xmin) / tds.cwidth;
+ /* Avoid divide by zero on small windows. */
+ if (tds.columns < 1) {
+ tds.columns = 1;
}
- cdc.winx = tvc->winx - CONSOLE_DRAW_MARGIN;
- cdc.ymin = tvc->ymin;
- cdc.ymax = tvc->ymax;
- cdc.xy = xy;
- cdc.sel = sel;
- cdc.pos_pick = pos_pick;
- cdc.mval = mval;
- cdc.draw = draw;
-
- /* shouldnt be needed */
- tvc->cwidth = cdc.cwidth;
- tvc->console_width = cdc.console_width;
+ tds.draw_rect = &tvc->draw_rect;
+ tds.scroll_ymin = tvc->scroll_ymin;
+ tds.scroll_ymax = tvc->scroll_ymax;
+ tds.xy = xy;
+ tds.sel = sel;
+ tds.mval_pick_offset = r_mval_pick_offset;
+ tds.mval = mval;
+ tds.do_draw = do_draw;
+
+ /* Shouldnt be needed. */
+ tvc->cwidth = tds.cwidth;
+ tvc->columns = tds.columns;
tvc->iter_index = 0;
if (tvc->sel_start != tvc->sel_end) {
@@ -344,7 +367,7 @@ int textview_draw(
if (tvc->begin(tvc)) {
unsigned char bg_sel[4] = {0};
- if (draw && tvc->const_colors) {
+ if (do_draw && tvc->const_colors) {
tvc->const_colors(tvc, bg_sel);
}
@@ -353,28 +376,29 @@ int textview_draw(
int ext_len;
int color_flag = 0;
- y_prev = xy[1];
+ const int y_prev = xy[1];
- if (draw) {
+ if (do_draw) {
color_flag = tvc->line_color(tvc, fg, bg);
}
tvc->line_get(tvc, &ext_line, &ext_len);
- if (!console_draw_string(&cdc,
+ if (!console_draw_string(&tds,
ext_line,
ext_len,
(color_flag & TVC_LINE_FG) ? fg : NULL,
(color_flag & TVC_LINE_BG) ? bg : NULL,
bg_sel)) {
- /* when drawing, if we pass v2d->cur.ymax, then quit */
- if (draw) {
- break; /* past the y limits */
+ /* When drawing, if we pass v2d->cur.ymax, then quit. */
+ if (do_draw) {
+ /* Past the y limits. */
+ break;
}
}
if ((mval[1] != INT_MAX) && (mval[1] >= y_prev && mval[1] <= xy[1])) {
- *mouse_pick = (void *)tvc->iter;
+ *r_mval_pick_item = (void *)tvc->iter;
break;
}
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index aa0e924b461..578236bbd13 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -22,15 +22,20 @@
#define __TEXTVIEW_H__
typedef struct TextViewContext {
+ /** Font size scaled by the interface size. */
int lheight;
+ /** Text selection, when a selection range is in use. */
int sel_start, sel_end;
/* view settings */
- int cwidth; /* shouldnt be needed! */
- int console_width; /* shouldnt be needed! */
+ int cwidth; /* shouldnt be needed! */
+ int columns; /* shouldnt be needed! */
- int winx;
- int ymin, ymax;
+ /** Area to draw: (0, 0, winx, winy) with a margin applied and scroll-bar subtracted. */
+ rcti draw_rect;
+
+ /** Scroll offset in pixels. */
+ int scroll_ymin, scroll_ymax;
/* callbacks */
int (*begin)(struct TextViewContext *tvc);
@@ -46,14 +51,20 @@ typedef struct TextViewContext {
void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]);
void *iter;
int iter_index;
- int iter_char; /* char intex, used for multi-line report display */
- int iter_char_next; /* same as above, next \n */
- int iter_tmp; /* internal iterator use */
+ /** Char index, used for multi-line report display. */
+ int iter_char;
+ /** Same as 'iter_char', next new-line. */
+ int iter_char_next;
+ /** Internal iterator use. */
+ int iter_tmp;
} TextViewContext;
-int textview_draw(
- struct TextViewContext *tvc, const int draw, int mval[2], void **mouse_pick, int *pos_pick);
+int textview_draw(struct TextViewContext *tvc,
+ const bool do_draw,
+ const int mval_init[2],
+ void **r_mval_pick_item,
+ int *r_mval_pick_offset);
#define TVC_LINE_FG (1 << 0)
#define TVC_LINE_BG (1 << 1)
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index f274f3c93ec..5cd2a86adf8 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -71,7 +71,7 @@ static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene)
/* set auto-snapping settings */
snla->autosnap = SACTSNAP_FRAME;
- snla->flag = SNLA_SHOW_MARKER_LINES;
+ snla->flag = SNLA_SHOW_MARKERS;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for nla");
@@ -274,10 +274,9 @@ static void nla_main_region_draw(const bContext *C, ARegion *ar)
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
int marker_draw_flag = DRAW_MARKERS_MARGIN;
- if (snla->flag & SNLA_SHOW_MARKER_LINES) {
- marker_draw_flag |= DRAW_MARKERS_LINES;
+ if (snla->flag & SNLA_SHOW_MARKERS) {
+ ED_markers_draw(C, marker_draw_flag);
}
- ED_markers_draw(C, marker_draw_flag);
/* preview range */
UI_view2d_view_ortho(v2d);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index b60764c410d..35c9082b54c 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -250,9 +250,19 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
}
}
-static void node_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "clamp", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "clamp_type", 0, "", ICON_NONE);
+}
+
+static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE);
+ if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
+ NODE_MAP_RANGE_SMOOTHSTEP,
+ NODE_MAP_RANGE_SMOOTHERSTEP)) {
+ uiItemR(layout, ptr, "clamp", 0, NULL, ICON_NONE);
+ }
}
static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1144,6 +1154,11 @@ static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C),
uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
}
+static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "name", 0, NULL, ICON_NONE);
+}
+
/* only once called */
static void node_shader_set_butfunc(bNodeType *ntype)
{
@@ -1172,8 +1187,11 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_VALTORGB:
ntype->draw_buttons = node_buts_colorramp;
break;
+ case SH_NODE_CLAMP:
+ ntype->draw_buttons = node_shader_buts_clamp;
+ break;
case SH_NODE_MAP_RANGE:
- ntype->draw_buttons = node_buts_map_range;
+ ntype->draw_buttons = node_shader_buts_map_range;
break;
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;
@@ -1297,6 +1315,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_TEX_WHITE_NOISE:
ntype->draw_buttons = node_shader_buts_white_noise;
break;
+ case SH_NODE_OUTPUT_AOV:
+ ntype->draw_buttons = node_shader_buts_output_aov;
+ break;
}
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 8811918b552..9623d89e030 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -2064,7 +2064,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
/* No ID refcounting, this node is virtual,
* detached from any actual Blender data currently. */
bNode *new_node = BKE_node_copy_store_new_pointers(
- NULL, node, LIB_ID_CREATE_NO_USER_REFCOUNT);
+ NULL, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN);
BKE_node_clipboard_add_node(new_node);
}
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 11f18357f7b..2c2989a284d 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -818,6 +818,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
BLI_uniquename(
&gpd->layers, gpl, "GP Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd);
break;
}
@@ -2124,14 +2125,14 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eModifierType_Surface:
data.icon = ICON_MOD_PHYSICS;
break;
- case eModifierType_Fluidsim:
+ case eModifierType_Fluidsim: /* deprecated, old fluid modifier */
data.icon = ICON_MOD_FLUIDSIM;
break;
case eModifierType_Multires:
data.icon = ICON_MOD_MULTIRES;
break;
- case eModifierType_Smoke:
- data.icon = ICON_MOD_SMOKE;
+ case eModifierType_Fluid:
+ data.icon = ICON_MOD_FLUID;
break;
case eModifierType_Solidify:
data.icon = ICON_MOD_SOLIDIFY;
@@ -2171,6 +2172,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eModifierType_Wireframe:
data.icon = ICON_MOD_WIREFRAME;
break;
+ case eModifierType_Weld:
+ data.icon = ICON_AUTOMERGE_OFF; /* XXX, needs own icon */
+ break;
case eModifierType_LaplacianDeform:
data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */
break;
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 34bbf3a2a30..7b59b056264 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -1311,6 +1311,10 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
outliner_show_active(so, ar, te, id);
}
+ /* Also open back from the active_element (only done for the first found occurrence of ID
+ * though). */
+ outliner_show_active(so, ar, active_element, id);
+
/* Center view on first element found */
int size_y = BLI_rcti_size_y(&v2d->mask) + 1;
int ytop = (active_element->ys + (size_y / 2));
@@ -2173,9 +2177,15 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
static bool ed_operator_outliner_id_orphans_active(bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
- if ((sa) && (sa->spacetype == SPACE_OUTLINER)) {
- SpaceOutliner *so = CTX_wm_space_outliner(C);
- return (so->outlinevis == SO_ID_ORPHANS);
+ if (sa != NULL) {
+ if (sa->spacetype == SPACE_TOPBAR) {
+ return true;
+ }
+
+ if (sa->spacetype == SPACE_OUTLINER) {
+ SpaceOutliner *so = CTX_wm_space_outliner(C);
+ return (so->outlinevis == SO_ID_ORPHANS);
+ }
}
return 0;
}
@@ -2242,6 +2252,7 @@ static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEv
static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ ScrArea *sa = CTX_wm_area(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int num_tagged[INDEX_ID_MAX] = {0};
@@ -2268,7 +2279,9 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
* outliner several mouse events can be handled in one cycle without
* handling notifiers/redraw which leads to deleting the same object twice.
* cleanup tree here to prevent such cases. */
- outliner_cleanup_tree(soops);
+ if ((sa != NULL) && (sa->spacetype == SPACE_OUTLINER)) {
+ outliner_cleanup_tree(soops);
+ }
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index c96f2f9956f..51e837db4c2 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -557,6 +557,7 @@ static eOLDrawState tree_element_active_gplayer(bContext *C,
if (set != OL_SETSEL_NONE) {
if (gpl) {
BKE_gpencil_layer_setactive(gpd, gpl);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd);
}
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 476010a693d..234da323de6 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -1559,6 +1559,9 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
EnumPropertyItem *items = NULL;
int totitem = 0;
+ if (C == NULL) {
+ return prop_id_op_types;
+ }
for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != NULL; it++) {
if (!outliner_id_operation_item_poll(C, ptr, prop, it->value)) {
continue;
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 5b2ea9d4793..70cb28fa937 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2067,10 +2067,9 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
int marker_draw_flag = DRAW_MARKERS_MARGIN;
- if (sseq->flag & SEQ_SHOW_MARKER_LINES) {
- marker_draw_flag |= DRAW_MARKERS_LINES;
+ if (sseq->flag & SEQ_SHOW_MARKERS) {
+ ED_markers_draw(C, marker_draw_flag);
}
- ED_markers_draw(C, marker_draw_flag);
UI_view2d_view_ortho(v2d);
/* draw cache on top of markers area */
@@ -2087,8 +2086,10 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
scene->r.cfra + scene->ed->over_ofs;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
-
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
immUniform1f("dash_width", 20.0f * U.pixelsize);
immUniform1f("dash_factor", 0.5f);
immUniformThemeColor(TH_CFRAME);
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index e1cf6d00b90..6e1b9d62f0e 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -93,7 +93,7 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
sseq->chanshown = 0;
sseq->view = SEQ_VIEW_SEQUENCE;
sseq->mainb = SEQ_DRAW_IMG_IMBUF;
- sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKER_LINES;
+ sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for sequencer");
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index ae7c3b001e7..b477e3838bd 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -117,7 +117,7 @@ static SpaceLink *text_duplicate(SpaceLink *sl)
/* clear or remove stuff from old */
- stextn->drawcache = NULL; /* space need it's own cache */
+ stextn->runtime.drawcache = NULL; /* space need it's own cache */
return (SpaceLink *)stextn;
}
@@ -314,8 +314,9 @@ static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
SpaceText *st = sa->spacedata.first;
int wmcursor = WM_CURSOR_TEXT_EDIT;
- if (st->text &&
- BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) {
+ if (st->text && BLI_rcti_isect_pt(&st->runtime.scroll_region_handle,
+ win->eventstate->x - ar->winrct.xmin,
+ st->runtime.scroll_region_handle.ymin)) {
wmcursor = WM_CURSOR_DEFAULT;
}
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index 9b10f9831a5..a560b8af70f 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -83,11 +83,11 @@ int text_do_suggest_select(SpaceText *st, ARegion *ar)
text_update_character_width(st);
- x = TXT_BODY_LEFT(st) + (st->cwidth * (st->text->curc - st->left));
- y = ar->winy - st->lheight_dpi * l - 2;
+ x = TXT_BODY_LEFT(st) + (st->runtime.cwidth_px * (st->text->curc - st->left));
+ y = ar->winy - st->runtime.lheight_px * l - 2;
- w = SUGG_LIST_WIDTH * st->cwidth + U.widget_unit;
- h = SUGG_LIST_SIZE * st->lheight_dpi + 0.4f * U.widget_unit;
+ w = SUGG_LIST_WIDTH * st->runtime.cwidth_px + U.widget_unit;
+ h = SUGG_LIST_SIZE * st->runtime.lheight_px + 0.4f * U.widget_unit;
// XXX getmouseco_areawin(mval);
@@ -101,7 +101,7 @@ int text_do_suggest_select(SpaceText *st, ARegion *ar)
}
/* Work out the target item index in the visible list */
- tgti = (y - mval[1] - 4) / st->lheight_dpi;
+ tgti = (y - mval[1] - 4) / st->runtime.lheight_px;
if (tgti < 0 || tgti > SUGG_LIST_SIZE) {
return 1;
}
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index a8b141eff15..96fa9f87398 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -52,22 +52,22 @@
typedef struct TextDrawContext {
int font_id;
- int cwidth;
- int lheight_dpi;
+ int cwidth_px;
+ int lheight_px;
bool syntax_highlight;
} TextDrawContext;
static void text_draw_context_init(const SpaceText *st, TextDrawContext *tdc)
{
tdc->font_id = blf_mono_font;
- tdc->cwidth = 0;
- tdc->lheight_dpi = st->lheight_dpi;
+ tdc->cwidth_px = 0;
+ tdc->lheight_px = st->runtime.lheight_px;
tdc->syntax_highlight = st->showsyntax && ED_text_is_syntax_highlight_supported(st->text);
}
static void text_font_begin(const TextDrawContext *tdc)
{
- BLF_size(tdc->font_id, tdc->lheight_dpi, 72);
+ BLF_size(tdc->font_id, tdc->lheight_px, 72);
}
static void text_font_end(const TextDrawContext *UNUSED(tdc))
@@ -79,9 +79,9 @@ static int text_font_draw(const TextDrawContext *tdc, int x, int y, const char *
int columns;
BLF_position(tdc->font_id, x, y, 0);
- columns = BLF_draw_mono(tdc->font_id, str, BLF_DRAW_STR_DUMMY_MAX, tdc->cwidth);
+ columns = BLF_draw_mono(tdc->font_id, str, BLF_DRAW_STR_DUMMY_MAX, tdc->cwidth_px);
- return tdc->cwidth * columns;
+ return tdc->cwidth_px * columns;
}
static int text_font_draw_character(const TextDrawContext *tdc, int x, int y, char c)
@@ -89,7 +89,7 @@ static int text_font_draw_character(const TextDrawContext *tdc, int x, int y, ch
BLF_position(tdc->font_id, x, y, 0);
BLF_draw(tdc->font_id, &c, 1);
- return tdc->cwidth;
+ return tdc->cwidth_px;
}
static int text_font_draw_character_utf8(const TextDrawContext *tdc, int x, int y, const char *c)
@@ -98,9 +98,9 @@ static int text_font_draw_character_utf8(const TextDrawContext *tdc, int x, int
const size_t len = BLI_str_utf8_size_safe(c);
BLF_position(tdc->font_id, x, y, 0);
- columns = BLF_draw_mono(tdc->font_id, c, len, tdc->cwidth);
+ columns = BLF_draw_mono(tdc->font_id, c, len, tdc->cwidth_px);
- return tdc->cwidth * columns;
+ return tdc->cwidth_px * columns;
}
#if 0
@@ -193,7 +193,7 @@ int wrap_width(const SpaceText *st, ARegion *ar)
int x, max;
x = TXT_BODY_LEFT(st);
- max = st->cwidth ? (winx - x) / st->cwidth : 0;
+ max = st->runtime.cwidth_px ? (winx - x) / st->runtime.cwidth_px : 0;
return max > 8 ? max : 8;
}
@@ -429,11 +429,11 @@ static int text_draw_wrapped(const SpaceText *st,
int mi, ma, mstart, mend; /* mem */
char fmt_prev = 0xff;
/* don't draw lines below this */
- const int clip_min_y = -(int)(st->lheight_dpi - 1);
+ const int clip_min_y = -(int)(st->runtime.lheight_px - 1);
flatten_string(st, &fs, str);
str = fs.buf;
- max = w / st->cwidth;
+ max = w / st->runtime.cwidth_px;
if (max < 8) {
max = 8;
}
@@ -549,7 +549,7 @@ static void text_draw(const SpaceText *st,
return; /* String is shorter than shift or ends with a padding */
}
- x += tdc->cwidth * padding;
+ x += tdc->cwidth_px * padding;
if (use_syntax) {
int a, str_shift = 0;
@@ -579,7 +579,7 @@ typedef struct DrawCache {
/* this is needed to check cache relevance */
int winx, wordwrap, showlinenrs, tabnumber;
short lheight;
- char cwidth;
+ char cwidth_px;
char text_id[MAX_ID_NAME];
/* for partial lines recalculation */
@@ -595,7 +595,7 @@ static void text_drawcache_init(SpaceText *st)
drawcache->nlines = BLI_listbase_count(&st->text->lines);
drawcache->text_id[0] = '\0';
- st->drawcache = drawcache;
+ st->runtime.drawcache = drawcache;
}
static void text_update_drawcache(SpaceText *st, ARegion *ar)
@@ -604,13 +604,13 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
int full_update = 0, nlines = 0;
Text *txt = st->text;
- if (!st->drawcache) {
+ if (st->runtime.drawcache == NULL) {
text_drawcache_init(st);
}
text_update_character_width(st);
- drawcache = (DrawCache *)st->drawcache;
+ drawcache = st->runtime.drawcache;
nlines = drawcache->nlines;
/* check if full cache update is needed */
@@ -624,9 +624,9 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
/* word-wrapping option was toggled */
full_update |= drawcache->tabnumber != st->tabnumber;
/* word-wrapping option was toggled */
- full_update |= drawcache->lheight != st->lheight_dpi;
+ full_update |= drawcache->lheight != st->runtime.lheight_px;
/* word-wrapping option was toggled */
- full_update |= drawcache->cwidth != st->cwidth;
+ full_update |= drawcache->cwidth_px != st->runtime.cwidth_px;
/* text datablock was changed */
full_update |= !STREQLEN(drawcache->text_id, txt->id.name, MAX_ID_NAME);
@@ -661,7 +661,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
drawcache->total_lines = 0;
if (st->showlinenrs) {
- st->linenrs_tot = integer_digits_i(nlines);
+ st->runtime.line_number_display_digits = integer_digits_i(nlines);
}
while (line) {
@@ -696,7 +696,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
nlines = BLI_listbase_count(&txt->lines);
if (st->showlinenrs) {
- st->linenrs_tot = integer_digits_i(nlines);
+ st->runtime.line_number_display_digits = integer_digits_i(nlines);
}
}
@@ -708,8 +708,8 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
/* store settings */
drawcache->winx = ar->winx;
drawcache->wordwrap = st->wordwrap;
- drawcache->lheight = st->lheight_dpi;
- drawcache->cwidth = st->cwidth;
+ drawcache->lheight = st->runtime.lheight_px;
+ drawcache->cwidth_px = st->runtime.cwidth_px;
drawcache->showlinenrs = st->showlinenrs;
drawcache->tabnumber = st->tabnumber;
@@ -728,8 +728,8 @@ void text_drawcache_tag_update(SpaceText *st, int full)
return;
}
- if (st->drawcache) {
- DrawCache *drawcache = (DrawCache *)st->drawcache;
+ if (st->runtime.drawcache != NULL) {
+ DrawCache *drawcache = st->runtime.drawcache;
Text *txt = st->text;
if (drawcache->update_flag) {
@@ -772,7 +772,7 @@ void text_drawcache_tag_update(SpaceText *st, int full)
void text_free_caches(SpaceText *st)
{
- DrawCache *drawcache = (DrawCache *)st->drawcache;
+ DrawCache *drawcache = st->runtime.drawcache;
if (drawcache) {
if (drawcache->line_height) {
@@ -788,7 +788,7 @@ void text_free_caches(SpaceText *st)
/* cache should be updated in caller */
static int text_get_visible_lines_no(const SpaceText *st, int lineno)
{
- const DrawCache *drawcache = st->drawcache;
+ const DrawCache *drawcache = st->runtime.drawcache;
return drawcache->line_height[lineno];
}
@@ -859,7 +859,7 @@ int text_get_total_lines(SpaceText *st, ARegion *ar)
DrawCache *drawcache;
text_update_drawcache(st, ar);
- drawcache = st->drawcache;
+ drawcache = st->runtime.drawcache;
return drawcache->total_lines;
}
@@ -876,7 +876,7 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back)
pix_bottom_margin = (0.4 * U.widget_unit);
pix_available = ar->winy - pix_top_margin - pix_bottom_margin;
ltexth = text_get_total_lines(st, ar);
- blank_lines = st->viewlines / 2;
+ blank_lines = st->runtime.viewlines / 2;
/* nicer code: use scroll rect for entire bar */
back->xmin = ar->winx - (0.6 * U.widget_unit);
@@ -891,13 +891,13 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back)
/* when re-sizing a view-port with the bar at the bottom to a greater height
* more blank lines will be added */
- if (ltexth + blank_lines < st->top + st->viewlines) {
- blank_lines = st->top + st->viewlines - ltexth;
+ if (ltexth + blank_lines < st->top + st->runtime.viewlines) {
+ blank_lines = st->top + st->runtime.viewlines - ltexth;
}
ltexth += blank_lines;
- barheight = (ltexth > 0) ? (st->viewlines * pix_available) / ltexth : 0;
+ barheight = (ltexth > 0) ? (st->runtime.viewlines * pix_available) / ltexth : 0;
pix_bardiff = 0;
if (barheight < 20) {
pix_bardiff = 20 - barheight; /* take into account the now non-linear sizing of the bar */
@@ -905,16 +905,16 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back)
}
barstart = (ltexth > 0) ? ((pix_available - pix_bardiff) * st->top) / ltexth : 0;
- st->txtbar = *scroll;
- st->txtbar.ymax -= barstart;
- st->txtbar.ymin = st->txtbar.ymax - barheight;
+ st->runtime.scroll_region_handle = *scroll;
+ st->runtime.scroll_region_handle.ymax -= barstart;
+ st->runtime.scroll_region_handle.ymin = st->runtime.scroll_region_handle.ymax - barheight;
- CLAMP(st->txtbar.ymin, pix_bottom_margin, ar->winy - pix_top_margin);
- CLAMP(st->txtbar.ymax, pix_bottom_margin, ar->winy - pix_top_margin);
+ CLAMP(st->runtime.scroll_region_handle.ymin, pix_bottom_margin, ar->winy - pix_top_margin);
+ CLAMP(st->runtime.scroll_region_handle.ymax, pix_bottom_margin, ar->winy - pix_top_margin);
- st->pix_per_line = (pix_available > 0) ? (float)ltexth / pix_available : 0;
- if (st->pix_per_line < 0.1f) {
- st->pix_per_line = 0.1f;
+ st->runtime.scroll_px_per_line = (pix_available > 0) ? (float)ltexth / pix_available : 0;
+ if (st->runtime.scroll_px_per_line < 0.1f) {
+ st->runtime.scroll_px_per_line = 0.1f;
}
curl_off = text_get_span_wrap(st, ar, st->text->lines.first, st->text->curl);
@@ -929,12 +929,13 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back)
/* the scrollbar is non-linear sized */
if (pix_bardiff > 0) {
/* the start of the highlight is in the current viewport */
- if (st->viewlines && lhlstart >= st->top && lhlstart <= st->top + st->viewlines) {
+ if (st->runtime.viewlines && lhlstart >= st->top &&
+ lhlstart <= st->top + st->runtime.viewlines) {
/* speed the progresion of the start of the highlight through the scrollbar */
hlstart = (((pix_available - pix_bardiff) * lhlstart) / ltexth) +
- (pix_bardiff * (lhlstart - st->top) / st->viewlines);
+ (pix_bardiff * (lhlstart - st->top) / st->runtime.viewlines);
}
- else if (lhlstart > st->top + st->viewlines && hlstart < barstart + barheight &&
+ else if (lhlstart > st->top + st->runtime.viewlines && hlstart < barstart + barheight &&
hlstart > barstart) {
/* push hl start down */
hlstart = barstart + barheight;
@@ -949,17 +950,18 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back)
}
/* the end of the highlight is in the current viewport */
- if (st->viewlines && lhlend >= st->top && lhlend <= st->top + st->viewlines) {
+ if (st->runtime.viewlines && lhlend >= st->top &&
+ lhlend <= st->top + st->runtime.viewlines) {
/* speed the progresion of the end of the highlight through the scrollbar */
hlend = (((pix_available - pix_bardiff) * lhlend) / ltexth) +
- (pix_bardiff * (lhlend - st->top) / st->viewlines);
+ (pix_bardiff * (lhlend - st->top) / st->runtime.viewlines);
}
else if (lhlend < st->top && hlend >= barstart - 2 && hlend < barstart + barheight) {
/* push hl end up */
hlend = barstart;
}
- else if (lhlend > st->top + st->viewlines && lhlstart < st->top + st->viewlines &&
- hlend < barstart + barheight) {
+ else if (lhlend > st->top + st->runtime.viewlines &&
+ lhlstart < st->top + st->runtime.viewlines && hlend < barstart + barheight) {
/* fill out end */
hlend = barstart + barheight;
}
@@ -978,12 +980,12 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back)
hlend = hlstart + 2;
}
- st->txtscroll = *scroll;
- st->txtscroll.ymax = ar->winy - pix_top_margin - hlstart;
- st->txtscroll.ymin = ar->winy - pix_top_margin - hlend;
+ st->runtime.scroll_region_select = *scroll;
+ st->runtime.scroll_region_select.ymax = ar->winy - pix_top_margin - hlstart;
+ st->runtime.scroll_region_select.ymin = ar->winy - pix_top_margin - hlend;
- CLAMP(st->txtscroll.ymin, pix_bottom_margin, ar->winy - pix_top_margin);
- CLAMP(st->txtscroll.ymax, pix_bottom_margin, ar->winy - pix_top_margin);
+ CLAMP(st->runtime.scroll_region_select.ymin, pix_bottom_margin, ar->winy - pix_top_margin);
+ CLAMP(st->runtime.scroll_region_select.ymax, pix_bottom_margin, ar->winy - pix_top_margin);
}
static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back)
@@ -1001,18 +1003,21 @@ static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back)
immRecti(pos, back->xmin, back->ymin, back->xmax, back->ymax);
immUnbindProgram();
- UI_draw_widget_scroll(
- &wcol, scroll, &st->txtbar, (st->flags & ST_SCROLL_SELECT) ? UI_SCROLL_PRESSED : 0);
+ UI_draw_widget_scroll(&wcol,
+ scroll,
+ &st->runtime.scroll_region_handle,
+ (st->flags & ST_SCROLL_SELECT) ? UI_SCROLL_PRESSED : 0);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- rad = 0.4f * min_ii(BLI_rcti_size_x(&st->txtscroll), BLI_rcti_size_y(&st->txtscroll));
+ rad = 0.4f * min_ii(BLI_rcti_size_x(&st->runtime.scroll_region_select),
+ BLI_rcti_size_y(&st->runtime.scroll_region_select));
UI_GetThemeColor3fv(TH_HILITE, col);
col[3] = 0.18f;
UI_draw_roundbox_aa(true,
- st->txtscroll.xmin + 1,
- st->txtscroll.ymin,
- st->txtscroll.xmax - 1,
- st->txtscroll.ymax,
+ st->runtime.scroll_region_select.xmin + 1,
+ st->runtime.scroll_region_select.ymin,
+ st->runtime.scroll_region_select.xmax - 1,
+ st->runtime.scroll_region_select.ymax,
rad,
col);
}
@@ -1052,13 +1057,13 @@ static void draw_documentation(const SpaceText *st, ARegion *ar)
return;
}
- x = TXT_BODY_LEFT(st) + (st->cwidth * (st->text->curc - st->left));
+ x = TXT_BODY_LEFT(st) + (st->runtime.cwidth_px * (st->text->curc - st->left));
if (texttool_suggest_first()) {
- x += SUGG_LIST_WIDTH * st->cwidth + 50;
+ x += SUGG_LIST_WIDTH * st->runtime.cwidth_px + 50;
}
- /* top = */ /* UNUSED */ y = ar->winy - st->lheight_dpi * l - 2;
- boxw = DOC_WIDTH * st->cwidth + 20;
+ /* top = */ /* UNUSED */ y = ar->winy - st->runtime.lheight_px * l - 2;
+ boxw = DOC_WIDTH * st->runtime.cwidth_px + 20;
boxh = (DOC_HEIGHT + 1) * TXT_LINE_HEIGHT(st);
/* Draw panel */
@@ -1103,7 +1108,7 @@ static void draw_documentation(const SpaceText *st, ARegion *ar)
else if (*p == '\n') {
buf[i] = '\0';
if (lines >= 0) {
- y -= st->lheight_dpi;
+ y -= st->runtime.lheight_px;
text_draw(st, &tdc, buf, 0, 0, x + 4, y - 3, NULL);
}
i = 0;
@@ -1114,7 +1119,7 @@ static void draw_documentation(const SpaceText *st, ARegion *ar)
if (i == DOC_WIDTH) { /* Reached the width, go to last break and wrap there */
buf[br] = '\0';
if (lines >= 0) {
- y -= st->lheight_dpi;
+ y -= st->runtime.lheight_px;
text_draw(st, &tdc, buf, 0, 0, x + 4, y - 3, NULL);
}
p -= i - br - 1; /* Rewind pointer to last break */
@@ -1162,15 +1167,15 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc
vcurl = txt_get_span(st->text->lines.first, st->text->curl) - st->top + offl;
vcurc = text_get_char_pos(st, st->text->curl->line, st->text->curc) - st->left + offc;
- x = TXT_BODY_LEFT(st) + (vcurc * st->cwidth);
+ x = TXT_BODY_LEFT(st) + (vcurc * st->runtime.cwidth_px);
y = ar->winy - (vcurl + 1) * lheight - 2;
/* offset back so the start of the text lines up with the suggestions,
* not essential but makes suggestions easier to follow */
- x -= st->cwidth *
+ x -= st->runtime.cwidth_px *
(st->text->curc - text_find_identifier_start(st->text->curl->line, st->text->curc));
- boxw = SUGG_LIST_WIDTH * st->cwidth + 20;
+ boxw = SUGG_LIST_WIDTH * st->runtime.cwidth_px + 20;
boxh = SUGG_LIST_SIZE * lheight + 8;
if (x + boxw > ar->winx) {
@@ -1203,7 +1208,7 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc
BLI_strncpy(str, item->name, len + 1);
- w = st->cwidth * text_get_char_pos(st, str, len);
+ w = st->runtime.cwidth_px * text_get_char_pos(st, str, len);
if (item == sel) {
uint posi = GPU_vertformat_attr_add(
@@ -1270,17 +1275,25 @@ static void draw_text_decoration(SpaceText *st, ARegion *ar)
x = TXT_BODY_LEFT(st);
y = ar->winy;
if (st->flags & ST_SCROLL_SELECT) {
- y += st->scroll_ofs_px[1];
+ y += st->runtime.scroll_ofs_px[1];
}
if (vcurl == vsell) {
y -= vcurl * lheight;
if (vcurc < vselc) {
- immRecti(pos, x + vcurc * st->cwidth, y, x + vselc * st->cwidth, y - lheight);
+ immRecti(pos,
+ x + vcurc * st->runtime.cwidth_px,
+ y,
+ x + vselc * st->runtime.cwidth_px,
+ y - lheight);
}
else {
- immRecti(pos, x + vselc * st->cwidth, y, x + vcurc * st->cwidth, y - lheight);
+ immRecti(pos,
+ x + vselc * st->runtime.cwidth_px,
+ y,
+ x + vcurc * st->runtime.cwidth_px,
+ y - lheight);
}
}
else {
@@ -1301,7 +1314,7 @@ static void draw_text_decoration(SpaceText *st, ARegion *ar)
y -= froml * lheight;
- immRecti(pos, x + fromc * st->cwidth - U.pixelsize, y, ar->winx, y - lheight);
+ immRecti(pos, x + fromc * st->runtime.cwidth_px - U.pixelsize, y, ar->winx, y - lheight);
y -= lheight;
for (i = froml + 1; i < tol; i++) {
@@ -1309,8 +1322,8 @@ static void draw_text_decoration(SpaceText *st, ARegion *ar)
y -= lheight;
}
- if (x + toc * st->cwidth > x) {
- immRecti(pos, x - U.pixelsize, y, x + toc * st->cwidth, y - lheight);
+ if (x + toc * st->runtime.cwidth_px > x) {
+ immRecti(pos, x - U.pixelsize, y, x + toc * st->runtime.cwidth_px, y - lheight);
}
y -= lheight;
}
@@ -1347,10 +1360,10 @@ static void draw_text_decoration(SpaceText *st, ARegion *ar)
if (!hidden) {
/* Draw the cursor itself (we draw the sel. cursor as this is the leading edge) */
- x = TXT_BODY_LEFT(st) + (vselc * st->cwidth);
+ x = TXT_BODY_LEFT(st) + (vselc * st->runtime.cwidth_px);
y = ar->winy - vsell * lheight;
if (st->flags & ST_SCROLL_SELECT) {
- y += st->scroll_ofs_px[1];
+ y += st->runtime.scroll_ofs_px[1];
}
immUniformThemeColor(TH_HILITE);
@@ -1359,7 +1372,7 @@ static void draw_text_decoration(SpaceText *st, ARegion *ar)
char ch = text->sell->line[text->selc];
y += TXT_LINE_SPACING(st);
- w = st->cwidth;
+ w = st->runtime.cwidth_px;
if (ch == '\t') {
w *= st->tabnumber - (vselc + st->left) % st->tabnumber;
}
@@ -1502,9 +1515,9 @@ static void draw_brackets(const SpaceText *st, const TextDrawContext *tdc, ARegi
UI_FontThemeColor(tdc->font_id, TH_HILITE);
x = TXT_BODY_LEFT(st);
- y = ar->winy - st->lheight_dpi;
+ y = ar->winy - st->runtime.lheight_px;
if (st->flags & ST_SCROLL_SELECT) {
- y += st->scroll_ofs_px[1];
+ y += st->runtime.scroll_ofs_px[1];
}
/* draw opening bracket */
@@ -1515,8 +1528,10 @@ static void draw_brackets(const SpaceText *st, const TextDrawContext *tdc, ARegi
if (viewc >= 0) {
viewl = txt_get_span(text->lines.first, startl) - st->top + offl;
- text_font_draw_character(tdc, x + viewc * st->cwidth, y - viewl * TXT_LINE_HEIGHT(st), ch);
- text_font_draw_character(tdc, x + viewc * st->cwidth + 1, y - viewl * TXT_LINE_HEIGHT(st), ch);
+ text_font_draw_character(
+ tdc, x + viewc * st->runtime.cwidth_px, y - viewl * TXT_LINE_HEIGHT(st), ch);
+ text_font_draw_character(
+ tdc, x + viewc * st->runtime.cwidth_px + 1, y - viewl * TXT_LINE_HEIGHT(st), ch);
}
/* draw closing bracket */
@@ -1527,8 +1542,10 @@ static void draw_brackets(const SpaceText *st, const TextDrawContext *tdc, ARegi
if (viewc >= 0) {
viewl = txt_get_span(text->lines.first, endl) - st->top + offl;
- text_font_draw_character(tdc, x + viewc * st->cwidth, y - viewl * TXT_LINE_HEIGHT(st), ch);
- text_font_draw_character(tdc, x + viewc * st->cwidth + 1, y - viewl * TXT_LINE_HEIGHT(st), ch);
+ text_font_draw_character(
+ tdc, x + viewc * st->runtime.cwidth_px, y - viewl * TXT_LINE_HEIGHT(st), ch);
+ text_font_draw_character(
+ tdc, x + viewc * st->runtime.cwidth_px + 1, y - viewl * TXT_LINE_HEIGHT(st), ch);
}
}
@@ -1552,12 +1569,14 @@ void draw_text_main(SpaceText *st, ARegion *ar)
}
/* dpi controlled line height and font size */
- st->lheight_dpi = (U.widget_unit * st->lheight) / 20;
+ st->runtime.lheight_px = (U.widget_unit * st->lheight) / 20;
/* don't draw lines below this */
- const int clip_min_y = -(int)(st->lheight_dpi - 1);
+ const int clip_min_y = -(int)(st->runtime.lheight_px - 1);
- st->viewlines = (st->lheight_dpi) ? (int)(ar->winy - clip_min_y) / TXT_LINE_HEIGHT(st) : 0;
+ st->runtime.viewlines = (st->runtime.lheight_px) ?
+ (int)(ar->winy - clip_min_y) / TXT_LINE_HEIGHT(st) :
+ 0;
text_draw_context_init(st, &tdc);
@@ -1603,8 +1622,8 @@ void draw_text_main(SpaceText *st, ARegion *ar)
text_font_begin(&tdc);
- tdc.cwidth = max_ii((int)BLF_fixed_width(tdc.font_id), 1);
- st->cwidth = tdc.cwidth;
+ tdc.cwidth_px = max_ii((int)BLF_fixed_width(tdc.font_id), 1);
+ st->runtime.cwidth_px = tdc.cwidth_px;
/* draw line numbers background */
if (st->showlinenrs) {
@@ -1616,14 +1635,14 @@ void draw_text_main(SpaceText *st, ARegion *ar)
immUnbindProgram();
}
else {
- st->linenrs_tot = 0; /* not used */
+ st->runtime.line_number_display_digits = 0; /* not used */
}
x = TXT_BODY_LEFT(st);
- y = ar->winy - st->lheight_dpi;
- int viewlines = st->viewlines;
+ y = ar->winy - st->runtime.lheight_px;
+ int viewlines = st->runtime.viewlines;
if (st->flags & ST_SCROLL_SELECT) {
- y += st->scroll_ofs_px[1];
+ y += st->runtime.scroll_ofs_px[1];
viewlines += 1;
}
@@ -1649,9 +1668,13 @@ void draw_text_main(SpaceText *st, ARegion *ar)
UI_FontThemeColor(tdc.font_id, TH_LINENUMBERS);
}
- BLI_snprintf(linenr, sizeof(linenr), "%*d", st->linenrs_tot, i + linecount + 1);
+ BLI_snprintf(linenr,
+ sizeof(linenr),
+ "%*d",
+ st->runtime.line_number_display_digits,
+ i + linecount + 1);
/* itoa(i + linecount + 1, linenr, 10); */ /* not ansi-c :/ */
- text_font_draw(&tdc, TXT_NUMCOL_PAD * st->cwidth, y, linenr);
+ text_font_draw(&tdc, TXT_NUMCOL_PAD * st->runtime.cwidth_px, y, linenr);
if (tmp == text->curl) {
UI_FontThemeColor(tdc.font_id, TH_TEXT);
@@ -1665,7 +1688,8 @@ void draw_text_main(SpaceText *st, ARegion *ar)
}
else {
/* draw unwrapped text */
- text_draw(st, &tdc, tmp->line, st->left, ar->winx / st->cwidth, x, y, tmp->format);
+ text_draw(
+ st, &tdc, tmp->line, st->left, ar->winx / st->runtime.cwidth_px, x, y, tmp->format);
y -= TXT_LINE_HEIGHT(st);
}
@@ -1673,7 +1697,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
}
if (st->flags & ST_SHOW_MARGIN) {
- margin_column_x = x + st->cwidth * (st->margin_column - st->left);
+ margin_column_x = x + st->runtime.cwidth_px * (st->margin_column - st->left);
if (margin_column_x >= x) {
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
@@ -1707,8 +1731,8 @@ void text_update_character_width(SpaceText *st)
text_draw_context_init(st, &tdc);
text_font_begin(&tdc);
- st->cwidth = BLF_fixed_width(tdc.font_id);
- st->cwidth = MAX2(st->cwidth, (char)1);
+ st->runtime.cwidth_px = BLF_fixed_width(tdc.font_id);
+ st->runtime.cwidth_px = MAX2(st->runtime.cwidth_px, (char)1);
text_font_end(&tdc);
}
@@ -1735,13 +1759,13 @@ void text_scroll_to_cursor(SpaceText *st, ARegion *ar, const bool center)
}
if (center) {
- if (st->top + st->viewlines <= i || st->top > i) {
- st->top = i - st->viewlines / 2;
+ if (st->top + st->runtime.viewlines <= i || st->top > i) {
+ st->top = i - st->runtime.viewlines / 2;
}
}
else {
- if (st->top + st->viewlines <= i) {
- st->top = i - (st->viewlines - 1);
+ if (st->top + st->runtime.viewlines <= i) {
+ st->top = i - (st->runtime.viewlines - 1);
}
else if (st->top > i) {
st->top = i;
@@ -1752,20 +1776,20 @@ void text_scroll_to_cursor(SpaceText *st, ARegion *ar, const bool center)
st->left = 0;
}
else {
- x = st->cwidth * (text_get_char_pos(st, text->sell->line, text->selc) - st->left);
+ x = st->runtime.cwidth_px * (text_get_char_pos(st, text->sell->line, text->selc) - st->left);
winx -= TXT_BODY_LEFT(st) + TXT_SCROLL_WIDTH;
if (center) {
if (x <= 0 || x > winx) {
- st->left += (x - winx / 2) / st->cwidth;
+ st->left += (x - winx / 2) / st->runtime.cwidth_px;
}
}
else {
if (x <= 0) {
- st->left += ((x + 1) / st->cwidth) - 1;
+ st->left += ((x + 1) / st->runtime.cwidth_px) - 1;
}
else if (x > winx) {
- st->left += ((x - (winx + 1)) / st->cwidth) + 1;
+ st->left += ((x - (winx + 1)) / st->runtime.cwidth_px) + 1;
}
}
}
@@ -1777,8 +1801,8 @@ void text_scroll_to_cursor(SpaceText *st, ARegion *ar, const bool center)
st->left = 0;
}
- st->scroll_ofs_px[0] = 0;
- st->scroll_ofs_px[1] = 0;
+ st->runtime.scroll_ofs_px[0] = 0;
+ st->runtime.scroll_ofs_px[1] = 0;
}
/* takes an area instead of a region, use for listeners */
@@ -1830,9 +1854,10 @@ bool ED_text_region_location_from_cursor(SpaceText *st,
int char_pos = text_get_char_pos(st, line->line, cursor_co[1]);
wrap_offset(st, ar, line, cursor_co[1], &offl, &offc);
- r_pixel_co[0] = (char_pos + offc - st->left) * st->cwidth + linenr_offset;
+ r_pixel_co[0] = (char_pos + offc - st->left) * st->runtime.cwidth_px + linenr_offset;
r_pixel_co[1] = (cursor_co[0] + offl - st->top) * TXT_LINE_HEIGHT(st);
- r_pixel_co[1] = (ar->winy - (r_pixel_co[1] + (TXT_BODY_LPAD * st->cwidth))) - st->lheight_dpi;
+ r_pixel_co[1] = (ar->winy - (r_pixel_co[1] + (TXT_BODY_LPAD * st->runtime.cwidth_px))) -
+ st->runtime.lheight_px;
}
return true;
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 349682bb131..1a36b21952b 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -47,13 +47,14 @@ void text_update_cursor_moved(struct bContext *C);
/* Padding around line numbers in character widths. */
#define TXT_NUMCOL_PAD 1.0f
/* Total width of the optional line numbers column. */
-#define TXT_NUMCOL_WIDTH(st) (st->cwidth * (st->linenrs_tot + (2 * TXT_NUMCOL_PAD)))
+#define TXT_NUMCOL_WIDTH(st) \
+ (st->runtime.cwidth_px * (st->runtime.line_number_display_digits + (2 * TXT_NUMCOL_PAD)))
/* Padding on left of body text in character units. */
#define TXT_BODY_LPAD 1.0f
/* Left position of body text. */
#define TXT_BODY_LEFT(st) \
- (st->showlinenrs ? TXT_NUMCOL_WIDTH(st) : 0) + (TXT_BODY_LPAD * st->cwidth)
+ (st->showlinenrs ? TXT_NUMCOL_WIDTH(st) : 0) + (TXT_BODY_LPAD * st->runtime.cwidth_px)
#define TXT_SCROLL_WIDTH U.widget_unit
#define TXT_SCROLL_SPACE ((int)(0.1f * U.widget_unit))
@@ -61,9 +62,9 @@ void text_update_cursor_moved(struct bContext *C);
/* Space between lines, in relation to letter height. */
#define TXT_LINE_VPAD 0.3f
/* Space between lines. */
-#define TXT_LINE_SPACING(st) ((int)(TXT_LINE_VPAD * st->lheight_dpi))
+#define TXT_LINE_SPACING(st) ((int)(TXT_LINE_VPAD * st->runtime.lheight_px))
/* Total height of each line. */
-#define TXT_LINE_HEIGHT(st) ((int)((1.0f + TXT_LINE_VPAD) * st->lheight_dpi))
+#define TXT_LINE_HEIGHT(st) ((int)((1.0f + TXT_LINE_VPAD) * st->runtime.lheight_px))
#define SUGG_LIST_SIZE 7
#define SUGG_LIST_WIDTH 20
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 842570459be..eea3e4d7958 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -143,7 +143,7 @@ static char *buf_tabs_to_spaces(const char *in_buf, const int tab_size)
BLI_INLINE int text_pixel_x_to_column(SpaceText *st, const int x)
{
/* Add half the char width so mouse cursor selection is in between letters. */
- return (x + (st->cwidth / 2)) / st->cwidth;
+ return (x + (st->runtime.cwidth_px / 2)) / st->runtime.cwidth_px;
}
/** \} */
@@ -270,8 +270,8 @@ static int text_new_exec(bContext *C, wmOperator *UNUSED(op))
st->text = text;
st->left = 0;
st->top = 0;
- st->scroll_ofs_px[0] = 0;
- st->scroll_ofs_px[1] = 0;
+ st->runtime.scroll_ofs_px[0] = 0;
+ st->runtime.scroll_ofs_px[1] = 0;
text_drawcache_tag_update(st, 1);
}
@@ -353,8 +353,8 @@ static int text_open_exec(bContext *C, wmOperator *op)
st->text = text;
st->left = 0;
st->top = 0;
- st->scroll_ofs_px[0] = 0;
- st->scroll_ofs_px[1] = 0;
+ st->runtime.scroll_ofs_px[0] = 0;
+ st->runtime.scroll_ofs_px[1] = 0;
}
text_drawcache_tag_update(st, 1);
@@ -2206,7 +2206,7 @@ static int text_move_cursor(bContext *C, int type, bool select)
case PREV_PAGE:
if (st) {
- cursor_skip(st, ar, st->text, -st->viewlines, select);
+ cursor_skip(st, ar, st->text, -st->runtime.viewlines, select);
}
else {
cursor_skip(NULL, NULL, text, -10, select);
@@ -2215,7 +2215,7 @@ static int text_move_cursor(bContext *C, int type, bool select)
case NEXT_PAGE:
if (st) {
- cursor_skip(st, ar, st->text, st->viewlines, select);
+ cursor_skip(st, ar, st->text, st->runtime.viewlines, select);
}
else {
cursor_skip(NULL, NULL, text, 10, select);
@@ -2497,7 +2497,7 @@ static void txt_screen_clamp(SpaceText *st, ARegion *ar)
else {
int last;
last = text_get_total_lines(st, ar);
- last = last - (st->viewlines / 2);
+ last = last - (st->runtime.viewlines / 2);
if (last > 0 && st->top > last) {
st->top = last;
}
@@ -2544,9 +2544,9 @@ static void text_scroll_state_init(TextScroll *tsc, SpaceText *st, ARegion *ar)
tsc->state.ofs_init[1] = st->top;
tsc->state.ofs_max[0] = INT_MAX;
- tsc->state.ofs_max[1] = text_get_total_lines(st, ar) - (st->viewlines / 2);
+ tsc->state.ofs_max[1] = text_get_total_lines(st, ar) - (st->runtime.viewlines / 2);
- tsc->state.size_px[0] = st->cwidth;
+ tsc->state.size_px[0] = st->runtime.cwidth_px;
tsc->state.size_px[1] = TXT_LINE_HEIGHT(st);
}
@@ -2602,7 +2602,8 @@ static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event)
tsc->ofs_delta_px[1] += tsc->mval_delta[1];
}
else {
- tsc->ofs_delta_px[1] -= (tsc->mval_delta[1] * st->pix_per_line) * tsc->state.size_px[1];
+ tsc->ofs_delta_px[1] -= (tsc->mval_delta[1] * st->runtime.scroll_px_per_line) *
+ tsc->state.size_px[1];
}
for (int i = 0; i < 2; i += 1) {
@@ -2651,12 +2652,12 @@ static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event)
if (scroll_ofs_new[0] != st->left || scroll_ofs_new[1] != st->top ||
/* Horizontal sub-pixel offset currently isn't used. */
/* scroll_ofs_px_new[0] != st->scroll_ofs_px[0] || */
- scroll_ofs_px_new[1] != st->scroll_ofs_px[1]) {
+ scroll_ofs_px_new[1] != st->runtime.scroll_ofs_px[1]) {
st->left = scroll_ofs_new[0];
st->top = scroll_ofs_new[1];
- st->scroll_ofs_px[0] = scroll_ofs_px_new[0];
- st->scroll_ofs_px[1] = scroll_ofs_px_new[1];
+ st->runtime.scroll_ofs_px[0] = scroll_ofs_px_new[0];
+ st->runtime.scroll_ofs_px[1] = scroll_ofs_px_new[1];
ED_area_tag_redraw(CTX_wm_area(C));
}
@@ -2671,12 +2672,12 @@ static void scroll_exit(bContext *C, wmOperator *op)
st->flags &= ~ST_SCROLL_SELECT;
- if (st->scroll_ofs_px[1] > tsc->state.size_px[1] / 2) {
+ if (st->runtime.scroll_ofs_px[1] > tsc->state.size_px[1] / 2) {
st->top += 1;
}
- st->scroll_ofs_px[0] = 0;
- st->scroll_ofs_px[1] = 0;
+ st->runtime.scroll_ofs_px[0] = 0;
+ st->runtime.scroll_ofs_px[1] = 0;
ED_area_tag_redraw(CTX_wm_area(C));
MEM_freeN(op->customdata);
@@ -2700,7 +2701,7 @@ static int text_scroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->val == KM_RELEASE) {
if (ELEM(tsc->zone, SCROLLHANDLE_MIN_OUTSIDE, SCROLLHANDLE_MAX_OUTSIDE)) {
txt_screen_skip(
- st, ar, st->viewlines * (tsc->zone == SCROLLHANDLE_MIN_OUTSIDE ? 1 : -1));
+ st, ar, st->runtime.viewlines * (tsc->zone == SCROLLHANDLE_MIN_OUTSIDE ? 1 : -1));
ED_area_tag_redraw(CTX_wm_area(C));
}
@@ -2744,8 +2745,8 @@ static int text_scroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
tsc->mval_prev[0] = event->x;
tsc->mval_prev[1] = event->y;
/* Sensitivity of scroll set to 4pix per line/char */
- tsc->mval_delta[0] = (event->x - event->prevx) * st->cwidth / 4;
- tsc->mval_delta[1] = (event->y - event->prevy) * st->lheight_dpi / 4;
+ tsc->mval_delta[0] = (event->x - event->prevx) * st->runtime.cwidth_px / 4;
+ tsc->mval_delta[1] = (event->y - event->prevy) * st->runtime.lheight_px / 4;
tsc->is_first = false;
tsc->is_scrollbar = false;
text_scroll_apply(C, op, event);
@@ -2819,13 +2820,15 @@ static int text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *ev
}
/* verify we are in the right zone */
- if (mval[0] > st->txtbar.xmin && mval[0] < st->txtbar.xmax) {
- if (mval[1] >= st->txtbar.ymin && mval[1] <= st->txtbar.ymax) {
+ if (mval[0] > st->runtime.scroll_region_handle.xmin &&
+ mval[0] < st->runtime.scroll_region_handle.xmax) {
+ if (mval[1] >= st->runtime.scroll_region_handle.ymin &&
+ mval[1] <= st->runtime.scroll_region_handle.ymax) {
/* mouse inside scroll handle */
zone = SCROLLHANDLE_BAR;
}
else if (mval[1] > TXT_SCROLL_SPACE && mval[1] < ar->winy - TXT_SCROLL_SPACE) {
- if (mval[1] < st->txtbar.ymin) {
+ if (mval[1] < st->runtime.scroll_region_handle.ymin) {
zone = SCROLLHANDLE_MIN_OUTSIDE;
}
else {
@@ -2850,8 +2853,8 @@ static int text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *ev
/* jump scroll, works in v2d but needs to be added here too :S */
if (event->type == MIDDLEMOUSE) {
- tsc->mval_prev[0] = ar->winrct.xmin + BLI_rcti_cent_x(&st->txtbar);
- tsc->mval_prev[1] = ar->winrct.ymin + BLI_rcti_cent_y(&st->txtbar);
+ tsc->mval_prev[0] = ar->winrct.xmin + BLI_rcti_cent_x(&st->runtime.scroll_region_handle);
+ tsc->mval_prev[1] = ar->winrct.ymin + BLI_rcti_cent_y(&st->runtime.scroll_region_handle);
tsc->is_first = false;
tsc->zone = SCROLLHANDLE_BAR;
@@ -3228,7 +3231,7 @@ static int text_selection_set_invoke(bContext *C, wmOperator *op, const wmEvent
SpaceText *st = CTX_wm_space_text(C);
SetSelection *ssel;
- if (event->mval[0] >= st->txtbar.xmin) {
+ if (event->mval[0] >= st->runtime.scroll_region_handle.xmin) {
return OPERATOR_PASS_THROUGH;
}
@@ -3309,7 +3312,7 @@ static int text_cursor_set_invoke(bContext *C, wmOperator *op, const wmEvent *ev
{
SpaceText *st = CTX_wm_space_text(C);
- if (event->mval[0] >= st->txtbar.xmin) {
+ if (event->mval[0] >= st->runtime.scroll_region_handle.xmin) {
return OPERATOR_PASS_THROUGH;
}
@@ -3358,7 +3361,8 @@ static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), const wm
return OPERATOR_PASS_THROUGH;
}
- if (!(mval[0] > 2 && mval[0] < (TXT_NUMCOL_WIDTH(st) + (TXT_BODY_LPAD * st->cwidth)) &&
+ if (!(mval[0] > 2 &&
+ mval[0] < (TXT_NUMCOL_WIDTH(st) + (TXT_BODY_LPAD * st->runtime.cwidth_px)) &&
mval[1] > 2 && mval[1] < ar->winy - 2)) {
return OPERATOR_PASS_THROUGH;
}
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index a42ab048907..731c8a3028e 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -35,6 +35,9 @@
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -119,9 +122,27 @@ static void userpref_main_region_init(wmWindowManager *wm, ARegion *ar)
ED_region_panels_init(wm, ar);
}
-static void userpref_main_region_draw(const bContext *C, ARegion *ar)
+static void userpref_main_region_layout(const bContext *C, ARegion *ar)
{
- ED_region_panels_ex(C, ar, NULL, U.space_data.section_active, true);
+ char id_lower[64];
+ const char *contexts[2] = {id_lower, NULL};
+
+ /* Avoid duplicating identifiers, use existing RNA enum. */
+ {
+ const EnumPropertyItem *items = rna_enum_preference_section_items;
+ int i = RNA_enum_from_value(items, U.space_data.section_active);
+ /* File is from the future. */
+ if (i == -1) {
+ i = 0;
+ }
+ const char *id = items[i].identifier;
+ BLI_assert(strlen(id) < sizeof(id_lower));
+ STRNCPY(id_lower, id);
+ BLI_str_tolower_ascii(id_lower, strlen(id_lower));
+ }
+
+ ED_region_panels_layout_ex(
+ C, ar, &ar->type->paneltypes, contexts, U.space_data.section_active, true, NULL);
}
static void userpref_operatortypes(void)
@@ -225,7 +246,8 @@ void ED_spacetype_userpref(void)
art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region");
art->regionid = RGN_TYPE_WINDOW;
art->init = userpref_main_region_init;
- art->draw = userpref_main_region_draw;
+ art->layout = userpref_main_region_layout;
+ art->draw = ED_region_panels_draw;
art->listener = userpref_main_region_listener;
art->keymapflag = ED_KEYMAP_UI;
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index 7c75f0ea907..95d7f79f666 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -32,7 +32,7 @@ set(INC
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
- ../../../../intern/smoke/extern
+ ../../../../intern/mantaflow/extern
# dna_type_offsets.h
${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
@@ -61,6 +61,7 @@ set(SRC
view3d_gizmo_preselect.c
view3d_gizmo_preselect_type.c
view3d_gizmo_ruler.c
+ view3d_gizmo_tool_generic.c
view3d_header.c
view3d_iterators.c
view3d_ops.c
@@ -94,8 +95,8 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_FLUID)
+ add_definitions(-DWITH_FLUID)
endif()
blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 5c7263d458d..7db1a6123e8 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -626,6 +626,8 @@ static void view3d_widgets(void)
WM_gizmogrouptype_append(VIEW3D_GGT_xform_extrude);
WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_elem);
WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_edgering);
+ WM_gizmogrouptype_append(VIEW3D_GGT_tool_generic_handle_normal);
+ WM_gizmogrouptype_append(VIEW3D_GGT_tool_generic_handle_free);
WM_gizmogrouptype_append(VIEW3D_GGT_ruler);
WM_gizmotype_append(VIEW3D_GT_ruler_item);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 54d2937baa9..54020553394 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -796,7 +796,7 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, bool a
GPU_clear(GPU_DEPTH_BIT);
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_set(rv3d);
}
/* get surface depth without bias */
@@ -817,7 +817,7 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, bool a
WM_draw_region_viewport_unbind(ar);
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_disable();
}
rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED;
@@ -1121,13 +1121,6 @@ static void draw_rotation_guide(const RegionView3D *rv3d)
immEnd();
immUnbindProgram();
-# if 0
- /* find screen coordinates for rotation center, then draw pretty icon */
- mul_m4_v3(rv3d->persinv, rot_center);
- UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
- /* ^^ just playing around, does not work */
-# endif
-
GPU_blend(false);
glDepthMask(GL_TRUE);
}
@@ -1287,8 +1280,8 @@ static void draw_viewport_name(ARegion *ar, View3D *v3d, int xoffset, int *yoffs
}
/**
- * draw info beside axes in bottom left-corner:
- * framenum, collection, object name, bone name (if available), marker name (if available)
+ * Draw info beside axes in bottom left-corner:
+ * frame-number, collection, object name, bone name (if available), marker name (if available).
*/
static void draw_selected_name(
@@ -1778,7 +1771,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
int sizey,
uint flag,
int alpha_mode,
- int samples,
const char *viewname,
/* output vars */
GPUOffScreen *ofs,
@@ -1807,7 +1799,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
if (own_ofs) {
/* bind */
- ofs = GPU_offscreen_create(sizex, sizey, samples, true, false, err_out);
+ ofs = GPU_offscreen_create(sizex, sizey, 0, true, false, err_out);
if (ofs == NULL) {
DRW_opengl_context_disable();
return NULL;
@@ -1925,7 +1917,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
uint flag,
uint draw_flags,
int alpha_mode,
- int samples,
const char *viewname,
GPUOffScreen *ofs,
char err_out[256])
@@ -1949,9 +1940,11 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
if (drawtype == OB_MATERIAL) {
v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
+ v3d.shading.render_pass = SCE_PASS_COMBINED;
}
else if (drawtype == OB_RENDER) {
v3d.shading.flag = V3D_SHADING_SCENE_WORLD_RENDER | V3D_SHADING_SCENE_LIGHTS_RENDER;
+ v3d.shading.render_pass = SCE_PASS_COMBINED;
}
v3d.flag2 = V3D_HIDE_OVERLAYS;
@@ -2000,7 +1993,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
height,
flag,
alpha_mode,
- samples,
viewname,
ofs,
err_out);
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index 17b575cedae..38cb5ad8651 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -228,7 +228,7 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc)
if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) {
GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
- DRW_draw_depth_object(vc->ar, viewport, obact_eval);
+ DRW_draw_depth_object(vc->ar, vc->v3d, viewport, obact_eval);
}
vc->v3d->flag &= ~V3D_INVALID_BACKBUF;
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 3ad194a5d2b..d40f79cea3f 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -992,8 +992,17 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
* \{ */
#ifdef WITH_INPUT_NDOF
-# define NDOF_HAS_TRANSLATE ((!ED_view3d_offset_lock_check(v3d, rv3d)) && !is_zero_v3(ndof->tvec))
-# define NDOF_HAS_ROTATE (((rv3d->viewlock & RV3D_LOCKED) == 0) && !is_zero_v3(ndof->rvec))
+static bool ndof_has_translate(const wmNDOFMotionData *ndof,
+ const View3D *v3d,
+ const RegionView3D *rv3d)
+{
+ return !is_zero_v3(ndof->tvec) && (!ED_view3d_offset_lock_check(v3d, rv3d));
+}
+
+static bool ndof_has_rotate(const wmNDOFMotionData *ndof, const RegionView3D *rv3d)
+{
+ return !is_zero_v3(ndof->rvec) && ((rv3d->viewlock & RV3D_LOCKED) == 0);
+}
/**
* \param depth_pt: A point to calculate the depth (in perspective mode)
@@ -1189,8 +1198,8 @@ void view3d_ndof_fly(const wmNDOFMotionData *ndof,
bool *r_has_translate,
bool *r_has_rotate)
{
- bool has_translate = NDOF_HAS_TRANSLATE;
- bool has_rotate = NDOF_HAS_ROTATE;
+ bool has_translate = ndof_has_translate(ndof, v3d, rv3d);
+ bool has_rotate = ndof_has_rotate(ndof, rv3d);
float view_inv[4];
invert_qt_qt_normalized(view_inv, rv3d->viewquat);
@@ -1338,9 +1347,10 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false);
if (ndof->progress != P_FINISHING) {
- const bool has_rotation = NDOF_HAS_ROTATE;
+ const bool has_rotation = ndof_has_rotate(ndof, rv3d);
/* if we can't rotate, fallback to translate (locked axis views) */
- const bool has_translate = NDOF_HAS_TRANSLATE && (rv3d->viewlock & RV3D_LOCKED);
+ const bool has_translate = ndof_has_translate(ndof, v3d, rv3d) &&
+ (rv3d->viewlock & RV3D_LOCKED);
const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp;
if (has_translate || has_zoom) {
@@ -1423,7 +1433,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
}
else if ((rv3d->persp == RV3D_ORTHO) && RV3D_VIEW_IS_AXIS(rv3d->view)) {
/* if we can't rotate, fallback to translate (locked axis views) */
- const bool has_translate = NDOF_HAS_TRANSLATE;
+ const bool has_translate = ndof_has_translate(ndof, v3d, rv3d);
const bool has_zoom = (ndof->tvec[2] != 0.0f) && ED_view3d_offset_lock_check(v3d, rv3d);
if (has_translate || has_zoom) {
@@ -1431,41 +1441,33 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
xform_flag |= HAS_TRANSLATE;
}
}
- else if ((U.ndof_flag & NDOF_MODE_ORBIT) || ED_view3d_offset_lock_check(v3d, rv3d)) {
- const bool has_rotation = NDOF_HAS_ROTATE;
+ else {
+ /* Note: based on feedback from T67579, users want to have pan and orbit enabled at once.
+ * It's arguable that orbit shouldn't pan (since we have a pan only operator),
+ * so if there are users who like to separate orbit/pan operations - it can be a preference. */
+ const bool is_orbit_around_pivot = (U.ndof_flag & NDOF_MODE_ORBIT) ||
+ ED_view3d_offset_lock_check(v3d, rv3d);
+ const bool has_rotation = ndof_has_rotate(ndof, rv3d);
+ const bool has_translate = !is_zero_v2(ndof->tvec) && ndof_has_translate(ndof, v3d, rv3d);
const bool has_zoom = (ndof->tvec[2] != 0.0f);
- if (has_zoom) {
- view3d_ndof_pan_zoom(ndof, vod->sa, vod->ar, false, has_zoom);
- xform_flag |= HAS_TRANSLATE;
- }
-
+ /* Rotation first because dynamic offset resets offset otherwise (and disasbles panning). */
if (has_rotation) {
- view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod, true);
+ const float dist_backup = rv3d->dist;
+ if (!is_orbit_around_pivot) {
+ ED_view3d_distance_set(rv3d, 0.0f);
+ }
+ view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod, is_orbit_around_pivot);
xform_flag |= HAS_ROTATE;
+ if (!is_orbit_around_pivot) {
+ ED_view3d_distance_set(rv3d, dist_backup);
+ }
}
- }
- else { /* free/explore (like fly mode) */
- const bool has_rotation = NDOF_HAS_ROTATE;
- const bool has_translate = NDOF_HAS_TRANSLATE;
- const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp;
-
- float dist_backup;
if (has_translate || has_zoom) {
view3d_ndof_pan_zoom(ndof, vod->sa, vod->ar, has_translate, has_zoom);
xform_flag |= HAS_TRANSLATE;
}
-
- dist_backup = rv3d->dist;
- ED_view3d_distance_set(rv3d, 0.0f);
-
- if (has_rotation) {
- view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod, false);
- xform_flag |= HAS_ROTATE;
- }
-
- ED_view3d_distance_set(rv3d, dist_backup);
}
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
@@ -1514,7 +1516,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e
const wmNDOFMotionData *ndof = event->customdata;
char xform_flag = 0;
- const bool has_translate = NDOF_HAS_TRANSLATE;
+ const bool has_translate = ndof_has_translate(ndof, v3d, rv3d);
const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp;
/* we're panning here! so erase any leftover rotation from other operators */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
index d6d3a3dc563..504b10888e8 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -466,7 +466,7 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
{
float point_local[2] = {UNPACK2(mval)};
sub_v2_v2(point_local, gz->matrix_basis[3]);
- mul_v2_fl(point_local, 1.0f / (gz->scale_basis * UI_DPI_FAC));
+ mul_v2_fl(point_local, 1.0f / gz->scale_final);
const float len_sq = len_squared_v2(point_local);
if (len_sq > 1.0) {
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
new file mode 100644
index 00000000000..0a4505b1bac
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
@@ -0,0 +1,224 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spview3d
+ */
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_gizmo_library.h"
+#include "ED_gizmo_utils.h"
+
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "WM_toolsystem.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_toolsystem.h"
+#include "WM_message.h"
+
+#include "view3d_intern.h" /* own include */
+
+static const char *handle_normal_id;
+static const char *handle_free_id;
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Tool
+ * \{ */
+
+static bool WIDGETGROUP_tool_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
+{
+ if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
+ return false;
+ }
+
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)) {
+ return false;
+ }
+
+ return true;
+}
+
+static wmGizmo *tool_generic_create_gizmo(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmGizmo *gz = WM_gizmo_new("GIZMO_GT_button_2d", gzgroup, NULL);
+ gz->flag |= WM_GIZMO_OPERATOR_TOOL_INIT;
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+
+ unit_m4(gz->matrix_offset);
+
+ RNA_enum_set(gz->ptr, "icon", ICON_NONE);
+
+ if (gzgroup->type->idname == handle_normal_id) {
+ gz->scale_basis = 0.12f;
+ gz->matrix_offset[3][2] -= 12.0;
+ RNA_enum_set(gz->ptr,
+ "draw_options",
+ (ED_GIZMO_BUTTON_SHOW_BACKDROP | ED_GIZMO_BUTTON_SHOW_HELPLINE |
+ ED_GIZMO_BUTTON_SHOW_OUTLINE));
+ }
+ else {
+ gz->scale_basis = 0.16f * 3;
+
+ RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
+
+ /* Make the center low alpha. */
+ WM_gizmo_set_line_width(gz, 2.0f);
+ RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.125f);
+ }
+
+ bToolRef *tref = WM_toolsystem_ref_from_context((bContext *)C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ struct wmKeyConfig *kc = wm->defaultconf;
+
+ gz->keymap = WM_keymap_ensure(kc, tref->runtime->keymap, tref->space_type, RGN_TYPE_WINDOW);
+ return gz;
+}
+
+static void WIDGETGROUP_tool_generic_setup(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__);
+ wwrapper->gizmo = tool_generic_create_gizmo(C, gzgroup);
+ gzgroup->customdata = wwrapper;
+}
+
+static void WIDGETGROUP_tool_generic_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmGizmoWrapper *wwrapper = gzgroup->customdata;
+ wmGizmo *gz = wwrapper->gizmo;
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ if (ts->workspace_tool_type != SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = false;
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
+ return;
+ }
+ else {
+ gzgroup->use_fallback_keymap = true;
+ }
+
+ /* skip, we don't draw anything anyway */
+ {
+ int orientation;
+ if (gzgroup->type->idname == handle_normal_id) {
+ orientation = V3D_ORIENT_NORMAL;
+ }
+ else {
+ orientation = V3D_ORIENT_GLOBAL; /* dummy, use view. */
+ }
+
+ struct TransformBounds tbounds;
+ const bool hide = ED_transform_calc_gizmo_stats(C,
+ &(struct TransformCalcParams){
+ .use_only_center = true,
+ .orientation_type = orientation + 1,
+ },
+ &tbounds) == 0;
+
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, hide);
+ if (hide) {
+ return;
+ }
+ copy_m4_m3(gz->matrix_basis, tbounds.axis);
+ copy_v3_v3(gz->matrix_basis[3], tbounds.center);
+ negate_v3(gz->matrix_basis[2]);
+ }
+
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_OFFSET_SCALE, true);
+}
+
+static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
+ wmGizmoGroup *gzgroup,
+ struct wmMsgBus *mbus)
+{
+ ARegion *ar = CTX_wm_region(C);
+
+ wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
+ .owner = ar,
+ .user_data = gzgroup->parent_gzmap,
+ .notify = WM_gizmo_do_msg_notify_tag_refresh,
+ };
+
+ {
+ extern PropertyRNA rna_ToolSettings_workspace_tool_type;
+ const PropertyRNA *props[] = {
+ &rna_ToolSettings_workspace_tool_type,
+ };
+
+ Scene *scene = CTX_data_scene(C);
+ PointerRNA toolsettings_ptr;
+ RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
+
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(
+ mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
+ }
+ }
+}
+
+static const char *handle_normal_id = "VIEW3D_GGT_tool_generic_handle_normal";
+static const char *handle_free_id = "VIEW3D_GGT_tool_generic_handle_free";
+
+void VIEW3D_GGT_tool_generic_handle_normal(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Generic Tool Widget Normal";
+ gzgt->idname = handle_normal_id;
+
+ 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;
+
+ gzgt->poll = WIDGETGROUP_tool_generic_poll;
+ gzgt->setup = WIDGETGROUP_tool_generic_setup;
+ gzgt->refresh = WIDGETGROUP_tool_generic_refresh;
+ gzgt->message_subscribe = WIDGETGROUP_gizmo_message_subscribe;
+}
+
+void VIEW3D_GGT_tool_generic_handle_free(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Generic Tool Widget Free";
+ gzgt->idname = handle_free_id;
+
+ /* Don't use 'WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK' here since this style of gizmo
+ * is better suited to being activated immediately. */
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP);
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = WIDGETGROUP_tool_generic_poll;
+ gzgt->setup = WIDGETGROUP_tool_generic_setup;
+ gzgt->refresh = WIDGETGROUP_tool_generic_refresh;
+ gzgt->message_subscribe = WIDGETGROUP_gizmo_message_subscribe;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 6b5c27b68f4..ddbb64bf067 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -261,6 +261,8 @@ void VIEW3D_GGT_armature_spline(struct wmGizmoGroupType *gzgt);
void VIEW3D_GGT_navigate(struct wmGizmoGroupType *gzgt);
void VIEW3D_GGT_mesh_preselect_elem(struct wmGizmoGroupType *gzgt);
void VIEW3D_GGT_mesh_preselect_edgering(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_tool_generic_handle_normal(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_tool_generic_handle_free(struct wmGizmoGroupType *gzgt);
void VIEW3D_GGT_ruler(struct wmGizmoGroupType *gzgt);
void VIEW3D_GT_ruler_item(struct wmGizmoType *gzt);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 092142a83cd..85e9a2d7680 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -2077,7 +2077,8 @@ static bool ed_object_select_pick(bContext *C,
if (has_bones && basact) {
if (basact->object->type == OB_CAMERA) {
- if (oldbasact == basact) {
+ MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
+ if (clip != NULL && oldbasact == basact) {
int i, hitresult;
bool changed = false;
@@ -2094,7 +2095,6 @@ static bool ed_object_select_pick(bContext *C,
* in height word, this buffer value belongs to camera. not to bundle
*/
if (buffer[4 * i + 3] & 0xFFFF0000) {
- MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase;
MovieTrackingTrack *track;
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 35a116dc4b3..f13f41779c2 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -61,14 +61,16 @@
static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]);
static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3]);
-/* *********************** operators ******************** */
+/* -------------------------------------------------------------------- */
+/** \name Snap Selection to Grid Operator
+ * \{ */
/** Snaps every individual object center to its nearest point on the grid. */
static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
- Object *obedit = CTX_data_edit_object(C);
+ Object *obact = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
RegionView3D *rv3d = CTX_wm_region_data(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -79,13 +81,13 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
gridf = ED_view3d_grid_view_scale(scene, v3d, rv3d, NULL);
- if (obedit) {
+ if (OBEDIT_FROM_OBACT(obact)) {
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
view_layer, CTX_wm_view3d(C), &objects_len);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- obedit = objects[ob_index];
+ Object *obedit = objects[ob_index];
if (obedit->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -122,91 +124,117 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
}
MEM_freeN(objects);
}
- else {
+ else if (OBPOSE_FROM_OBACT(obact)) {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
-
- FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN (view_layer_eval, v3d, ob_eval) {
+ uint objects_len = 0;
+ Object **objects_eval = BKE_object_pose_array_get(view_layer_eval, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_eval = objects_eval[ob_index];
Object *ob = DEG_get_original_object(ob_eval);
- if (ob->mode & OB_MODE_POSE) {
- bPoseChannel *pchan_eval;
- bArmature *arm_eval = ob_eval->data;
-
- invert_m4_m4(ob_eval->imat, ob_eval->obmat);
-
- for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval;
- pchan_eval = pchan_eval->next) {
- if (pchan_eval->bone->flag & BONE_SELECTED) {
- if (pchan_eval->bone->layer & arm_eval->layer) {
- if ((pchan_eval->bone->flag & BONE_CONNECTED) == 0) {
- float nLoc[3];
-
- /* get nearest grid point to snap to */
- copy_v3_v3(nLoc, pchan_eval->pose_mat[3]);
- /* We must operate in world space! */
- mul_m4_v3(ob_eval->obmat, nLoc);
- vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf);
- vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf);
- vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf);
- /* Back in object space... */
- mul_m4_v3(ob_eval->imat, vec);
-
- /* Get location of grid point in pose space. */
- BKE_armature_loc_pose_to_bone(pchan_eval, vec, vec);
-
- /* adjust location on the original pchan*/
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, pchan_eval->name);
- if ((pchan->protectflag & OB_LOCK_LOCX) == 0) {
- pchan->loc[0] = vec[0];
- }
- if ((pchan->protectflag & OB_LOCK_LOCY) == 0) {
- pchan->loc[1] = vec[1];
- }
- if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) {
- pchan->loc[2] = vec[2];
- }
-
- /* auto-keyframing */
- ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
+ bPoseChannel *pchan_eval;
+ bArmature *arm_eval = ob_eval->data;
+
+ invert_m4_m4(ob_eval->imat, ob_eval->obmat);
+
+ for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval; pchan_eval = pchan_eval->next) {
+ if (pchan_eval->bone->flag & BONE_SELECTED) {
+ if (pchan_eval->bone->layer & arm_eval->layer) {
+ if ((pchan_eval->bone->flag & BONE_CONNECTED) == 0) {
+ float nLoc[3];
+
+ /* get nearest grid point to snap to */
+ copy_v3_v3(nLoc, pchan_eval->pose_mat[3]);
+ /* We must operate in world space! */
+ mul_m4_v3(ob_eval->obmat, nLoc);
+ vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf);
+ vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf);
+ vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf);
+ /* Back in object space... */
+ mul_m4_v3(ob_eval->imat, vec);
+
+ /* Get location of grid point in pose space. */
+ BKE_armature_loc_pose_to_bone(pchan_eval, vec, vec);
+
+ /* adjust location on the original pchan*/
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, pchan_eval->name);
+ if ((pchan->protectflag & OB_LOCK_LOCX) == 0) {
+ pchan->loc[0] = vec[0];
}
- /* if the bone has a parent and is connected to the parent,
- * don't do anything - will break chain unless we do auto-ik.
- */
+ if ((pchan->protectflag & OB_LOCK_LOCY) == 0) {
+ pchan->loc[1] = vec[1];
+ }
+ if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) {
+ pchan->loc[2] = vec[2];
+ }
+
+ /* auto-keyframing */
+ ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
}
+ /* if the bone has a parent and is connected to the parent,
+ * don't do anything - will break chain unless we do auto-ik.
+ */
}
}
- ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
- else {
- vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf);
- vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf);
- vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf);
+ ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
- if (ob->parent) {
- float originmat[3][3];
- BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ MEM_freeN(objects_eval);
+ }
+ else {
+ /* Object mode. */
+ Main *bmain = CTX_data_main(C);
- invert_m3_m3(imat, originmat);
- mul_m3_v3(imat, vec);
- }
- if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
- ob->loc[0] = ob_eval->loc[0] + vec[0];
- }
- if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
- ob->loc[1] = ob_eval->loc[1] + vec[1];
- }
- if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
- ob->loc[2] = ob_eval->loc[2] + vec[2];
- }
+ struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
- /* auto-keyframing */
- ED_autokeyframe_object(C, scene, ob, ks);
+ const bool use_transform_data_origin = (scene->toolsettings->transform_flag &
+ SCE_XFORM_DATA_ORIGIN);
+ struct XFormObjectData_Container *xds = NULL;
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ if (use_transform_data_origin) {
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ xds = ED_object_data_xform_container_create();
+ }
+
+ FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN (view_layer_eval, v3d, ob_eval) {
+ Object *ob = DEG_get_original_object(ob_eval);
+ vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf);
+ vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf);
+ vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf);
+
+ if (ob->parent) {
+ float originmat[3][3];
+ BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat);
+
+ invert_m3_m3(imat, originmat);
+ mul_m3_v3(imat, vec);
+ }
+ if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
+ ob->loc[0] = ob_eval->loc[0] + vec[0];
+ }
+ if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
+ ob->loc[1] = ob_eval->loc[1] + vec[1];
}
+ if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
+ ob->loc[2] = ob_eval->loc[2] + vec[2];
+ }
+
+ /* auto-keyframing */
+ ED_autokeyframe_object(C, scene, ob, ks);
+
+ if (use_transform_data_origin) {
+ ED_object_data_xform_container_item_ensure(xds, ob);
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
}
FOREACH_SELECTED_EDITABLE_OBJECT_END;
+
+ if (use_transform_data_origin) {
+ ED_object_data_xform_container_update_all(xds, bmain, depsgraph);
+ ED_object_data_xform_container_destroy(xds);
+ }
}
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -229,7 +257,11 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* *************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Selection to Location (Utility)
+ * \{ */
/**
* Snaps the selection as a whole (use_offset=true) or each selected object to the given location.
@@ -317,12 +349,12 @@ static int snap_selected_to_location(bContext *C,
}
MEM_freeN(objects);
}
- else if (obact && (obact->mode & OB_MODE_POSE)) {
+ else if (OBPOSE_FROM_OBACT(obact)) {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
- view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
+ Object **objects = BKE_object_pose_array_get(view_layer, v3d, &objects_len);
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob = objects[ob_index];
bPoseChannel *pchan;
@@ -393,6 +425,7 @@ static int snap_selected_to_location(bContext *C,
else {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ListBase ctx_data_list;
CollectionPointerLink *ctx_ob;
@@ -411,6 +444,22 @@ static int snap_selected_to_location(bContext *C,
ob->flag |= OB_DONE;
}
+ const bool use_transform_data_origin = (scene->toolsettings->transform_flag &
+ SCE_XFORM_DATA_ORIGIN);
+ struct XFormObjectData_Container *xds = NULL;
+
+ if (use_transform_data_origin) {
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ xds = ED_object_data_xform_container_create();
+
+ /* Initialize the transform data in a separate loop because the depsgraph
+ * may be evaluated while setting the locations. */
+ for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) {
+ ob = ctx_ob->ptr.data;
+ ED_object_data_xform_container_item_ensure(xds, ob);
+ }
+ }
+
for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) {
ob = ctx_ob->ptr.data;
@@ -431,7 +480,7 @@ static int snap_selected_to_location(bContext *C,
float originmat[3][3], parentmat[4][4];
/* Use the evaluated object here because sometimes
* `ob->parent->runtime.curve_cache` is required. */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
BKE_object_get_parent_matrix(ob_eval, ob_eval->parent, parentmat);
@@ -457,6 +506,11 @@ static int snap_selected_to_location(bContext *C,
}
BLI_freelistN(&ctx_data_list);
+
+ if (use_transform_data_origin) {
+ ED_object_data_xform_container_update_all(xds, bmain, depsgraph);
+ ED_object_data_xform_container_destroy(xds);
+ }
}
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -464,6 +518,12 @@ static int snap_selected_to_location(bContext *C,
return OPERATOR_FINISHED;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Selection to Cursor Operator
+ * \{ */
+
static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op)
{
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
@@ -497,7 +557,11 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
"If the selection should be snapped as a whole or by each object center");
}
-/* *************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Selection to Active Operator
+ * \{ */
/** Snaps each selected object to the location of the active selected object. */
static int snap_selected_to_active_exec(bContext *C, wmOperator *op)
@@ -527,7 +591,11 @@ void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* *************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Cursor to Grid Operator
+ * \{ */
/** Snaps the 3D cursor location to its nearest point on the grid. */
static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
@@ -565,7 +633,11 @@ void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* **************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Cursor to Selection Operator
+ * \{ */
/**
* Returns the center position of a tracking marker visible on the viewport
@@ -761,7 +833,11 @@ void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Cursor to Active Operator
+ * \{ */
/**
* Calculates the center position of the active object in global space.
@@ -809,7 +885,11 @@ void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* **************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Cursor to Center Operator
+ * \{ */
/** Snaps the 3D cursor location to the origin and clears cursor rotation. */
static int snap_curs_to_center_exec(bContext *C, wmOperator *UNUSED(op))
@@ -842,7 +922,11 @@ void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* **************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Min/Max Object Vertices Utility
+ * \{ */
/**
* Calculates the bounding box corners (min and max) for \a obedit.
@@ -890,3 +974,5 @@ bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3])
return true;
}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index d7f7e96ba08..8b4012d6547 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -1099,7 +1099,7 @@ int view3d_opengl_select(ViewContext *vc,
GPU_depth_test(true);
}
- if (vc->rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(vc->v3d, vc->rv3d)) {
ED_view3d_clipping_set(vc->rv3d);
}
@@ -1167,7 +1167,7 @@ int view3d_opengl_select(ViewContext *vc,
GPU_depth_test(false);
}
- if (vc->rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, vc->rv3d)) {
ED_view3d_clipping_disable();
}
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 5853574dced..6f39a8c3b9c 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -59,6 +59,7 @@ set(SRC
transform_convert_sculpt.c
transform_convert_sequencer.c
transform_convert_tracking.c
+ transform_draw_cursors.c
transform_generics.c
transform_gizmo_2d.c
transform_gizmo_3d.c
@@ -71,6 +72,7 @@ set(SRC
transform.h
transform_convert.h
+ transform_draw_cursors.h
transform_snap.h
)
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index f3d26f85471..7112444655b 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -95,6 +95,7 @@
#include "transform.h"
#include "transform_convert.h"
+#include "transform_draw_cursors.h"
#include "transform_snap.h"
/* Disabling, since when you type you know what you are doing,
@@ -1684,285 +1685,6 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
return success;
}
-typedef enum {
- UP,
- DOWN,
- LEFT,
- RIGHT,
-} ArrowDirection;
-
-#define POS_INDEX 0
-/* NOTE: this --^ is a bit hackish, but simplifies GPUVertFormat usage among functions
- * private to this file - merwin
- */
-
-static void drawArrow(ArrowDirection d, short offset, short length, short size)
-{
- immBegin(GPU_PRIM_LINES, 6);
-
- switch (d) {
- case LEFT:
- offset = -offset;
- length = -length;
- size = -size;
- ATTR_FALLTHROUGH;
- case RIGHT:
- immVertex2f(POS_INDEX, offset, 0);
- immVertex2f(POS_INDEX, offset + length, 0);
- immVertex2f(POS_INDEX, offset + length, 0);
- immVertex2f(POS_INDEX, offset + length - size, -size);
- immVertex2f(POS_INDEX, offset + length, 0);
- immVertex2f(POS_INDEX, offset + length - size, size);
- break;
-
- case DOWN:
- offset = -offset;
- length = -length;
- size = -size;
- ATTR_FALLTHROUGH;
- case UP:
- immVertex2f(POS_INDEX, 0, offset);
- immVertex2f(POS_INDEX, 0, offset + length);
- immVertex2f(POS_INDEX, 0, offset + length);
- immVertex2f(POS_INDEX, -size, offset + length - size);
- immVertex2f(POS_INDEX, 0, offset + length);
- immVertex2f(POS_INDEX, size, offset + length - size);
- break;
- }
-
- immEnd();
-}
-
-static void drawArrowHead(ArrowDirection d, short size)
-{
- immBegin(GPU_PRIM_LINES, 4);
-
- switch (d) {
- case LEFT:
- size = -size;
- ATTR_FALLTHROUGH;
- case RIGHT:
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, -size, -size);
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, -size, size);
- break;
-
- case DOWN:
- size = -size;
- ATTR_FALLTHROUGH;
- case UP:
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, -size, -size);
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, size, -size);
- break;
- }
-
- immEnd();
-}
-
-static void drawArc(float size, float angle_start, float angle_end, int segments)
-{
- float delta = (angle_end - angle_start) / segments;
- float angle;
- int a;
-
- immBegin(GPU_PRIM_LINE_STRIP, segments + 1);
-
- for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
- immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
- }
- immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
-
- immEnd();
-}
-
-static bool helpline_poll(bContext *C)
-{
- ARegion *ar = CTX_wm_region(C);
-
- if (ar && ar->regiontype == RGN_TYPE_WINDOW) {
- return 1;
- }
- return 0;
-}
-
-static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
-{
- TransInfo *t = (TransInfo *)customdata;
-
- if (t->helpline != HLP_NONE) {
- float cent[2];
- const float mval[3] = {
- x,
- y,
- 0.0f,
- };
- float tmval[2] = {
- (float)t->mval[0],
- (float)t->mval[1],
- };
-
- projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
- /* Offset the values for the area region. */
- const float offset[2] = {
- t->ar->winrct.xmin,
- t->ar->winrct.ymin,
- };
-
- for (int i = 0; i < 2; i++) {
- cent[i] += offset[i];
- tmval[i] += offset[i];
- }
-
- GPU_matrix_push();
-
- /* Dashed lines first. */
- if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
- const uint shdr_pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
- BLI_assert(shdr_pos == POS_INDEX);
-
- GPU_line_width(1.0f);
-
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
-
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
-
- immUniform1i("colors_len", 0); /* "simple" mode */
- immUniformThemeColor(TH_VIEW_OVERLAY);
- immUniform1f("dash_width", 6.0f);
- immUniform1f("dash_factor", 0.5f);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2fv(POS_INDEX, cent);
- immVertex2f(POS_INDEX, tmval[0], tmval[1]);
- immEnd();
-
- immUnbindProgram();
- }
-
- /* And now, solid lines. */
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- UNUSED_VARS_NDEBUG(pos); /* silence warning */
- BLI_assert(pos == POS_INDEX);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- switch (t->helpline) {
- case HLP_SPRING:
- immUniformThemeColor(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3fv(mval);
- GPU_matrix_rotate_axis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
-
- GPU_line_width(3.0f);
- drawArrow(UP, 5, 10, 5);
- drawArrow(DOWN, 5, 10, 5);
- break;
- case HLP_HARROW:
- immUniformThemeColor(TH_VIEW_OVERLAY);
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
- drawArrow(RIGHT, 5, 10, 5);
- drawArrow(LEFT, 5, 10, 5);
- break;
- case HLP_VARROW:
- immUniformThemeColor(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
- drawArrow(UP, 5, 10, 5);
- drawArrow(DOWN, 5, 10, 5);
- break;
- case HLP_CARROW: {
- /* Draw arrow based on direction defined by custom-points. */
- immUniformThemeColor(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
-
- const int *data = t->mouse.data;
- const float dx = data[2] - data[0], dy = data[3] - data[1];
- const float angle = -atan2f(dx, dy);
-
- GPU_matrix_push();
-
- GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
-
- drawArrow(UP, 5, 10, 5);
- drawArrow(DOWN, 5, 10, 5);
-
- GPU_matrix_pop();
- break;
- }
- case HLP_ANGLE: {
- float dx = tmval[0] - cent[0], dy = tmval[1] - cent[1];
- float angle = atan2f(dy, dx);
- float dist = hypotf(dx, dy);
- float delta_angle = min_ff(15.0f / dist, (float)M_PI / 4.0f);
- float spacing_angle = min_ff(5.0f / dist, (float)M_PI / 12.0f);
-
- immUniformThemeColor(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3f(cent[0] - tmval[0] + mval[0], cent[1] - tmval[1] + mval[1], 0);
-
- GPU_line_width(3.0f);
- drawArc(dist, angle - delta_angle, angle - spacing_angle, 10);
- drawArc(dist, angle + spacing_angle, angle + delta_angle, 10);
-
- GPU_matrix_push();
-
- GPU_matrix_translate_3f(
- cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
- GPU_matrix_rotate_axis(RAD2DEGF(angle - delta_angle), 'Z');
-
- drawArrowHead(DOWN, 5);
-
- GPU_matrix_pop();
-
- GPU_matrix_translate_3f(
- cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
- GPU_matrix_rotate_axis(RAD2DEGF(angle + delta_angle), 'Z');
-
- drawArrowHead(UP, 5);
- break;
- }
- case HLP_TRACKBALL: {
- unsigned char col[3], col2[3];
- UI_GetThemeColor3ubv(TH_GRID, col);
-
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
-
- UI_make_axis_color(col, col2, 'X');
- immUniformColor3ubv(col2);
-
- drawArrow(RIGHT, 5, 10, 5);
- drawArrow(LEFT, 5, 10, 5);
-
- UI_make_axis_color(col, col2, 'Y');
- immUniformColor3ubv(col2);
-
- drawArrow(UP, 5, 10, 5);
- drawArrow(DOWN, 5, 10, 5);
- break;
- }
- }
-
- immUnbindProgram();
- GPU_matrix_pop();
- }
-}
-
static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegion *ar)
{
/* Don't show overlays when not the active view and when overlay is disabled: T57139 */
@@ -2380,38 +2102,62 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_pixel = ED_region_draw_cb_activate(
t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
else if (t->spacetype == SPACE_IMAGE) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
else if (t->spacetype == SPACE_CLIP) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
else if (t->spacetype == SPACE_NODE) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
else if (t->spacetype == SPACE_GRAPH) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
else if (t->spacetype == SPACE_ACTION) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
createTransData(C, t); // make TransData structs from selection
@@ -3524,10 +3270,29 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
static void initShear_mouseInputMode(TransInfo *t)
{
float dir[3];
+ bool dir_flip = false;
copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
+ /* Needed for axis aligned view gizmo. */
+ if (t->orientation.user == V3D_ORIENT_VIEW) {
+ if (t->orient_axis_ortho == 0) {
+ if (t->center2d[1] > t->mouse.imval[1]) {
+ dir_flip = !dir_flip;
+ }
+ }
+ else if (t->orient_axis_ortho == 1) {
+ if (t->center2d[0] > t->mouse.imval[0]) {
+ dir_flip = !dir_flip;
+ }
+ }
+ }
+
/* Without this, half the gizmo handles move in the opposite direction. */
if ((t->orient_axis_ortho + 1) % 3 != t->orient_axis) {
+ dir_flip = !dir_flip;
+ }
+
+ if (dir_flip) {
negate_v3(dir);
}
@@ -5262,12 +5027,12 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
copy_v3_v3(tvec, vec);
}
+ mul_m3_v3(td->smtx, tvec);
+
if (use_rotate_offset) {
add_v3_v3(tvec, rotate_offset);
}
- mul_m3_v3(td->smtx, tvec);
-
if (t->options & CTX_GPENCIL_STROKES) {
/* grease pencil multiframe falloff */
bGPDstroke *gps = (bGPDstroke *)td->extra;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 4b529765ab0..95506918d98 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -649,7 +649,7 @@ typedef struct TransInfo {
short index;
short *types[2];
/* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */
- TransformOrientation *custom;
+ struct TransformOrientation *custom;
} orientation;
/** backup from view3d, to restore on end. */
short gizmo_flag;
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index db8f36883f8..a214eb1c80b 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -450,20 +450,15 @@ int count_set_pose_transflags(Object *ob,
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
+ bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
if (PBONE_VISIBLE(arm, bone)) {
if ((bone->flag & BONE_SELECTED)) {
bone->flag |= BONE_TRANSFORM;
}
- else {
- bone->flag &= ~BONE_TRANSFORM;
- }
bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
bone->flag &= ~BONE_TRANSFORM_CHILD;
}
- else {
- bone->flag &= ~BONE_TRANSFORM;
- }
}
/* make sure no bone can be transformed when a parent is transformed */
@@ -1350,6 +1345,15 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list)
return true;
}
}
+ else if (con->type == CONSTRAINT_TYPE_ACTION) {
+ /* The Action constraint only does this in the Before mode. */
+ bActionConstraint *data = (bActionConstraint *)con->data;
+
+ if (ELEM(data->mix_mode, ACTCON_MIX_BEFORE) &&
+ ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION)) {
+ return true;
+ }
+ }
else if (con->type == CONSTRAINT_TYPE_TRANSFORM) {
/* Transform constraint needs it for rotation at least (r.57309),
* but doing so when translating may also mess things up [#36203]
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index cc023688c8e..0edf55ece7e 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -86,6 +86,7 @@ static void add_pose_transdata(
td->flag |= TD_NO_LOC;
}
+ td->extra = pchan;
td->protectflag = pchan->protectflag;
td->loc = pchan->loc;
@@ -364,7 +365,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
* (but they must be selected, and only one ik-solver per chain should get added) */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone->layer & arm->layer) {
- if (pchan->bone->flag & BONE_SELECTED) {
+ if (pchan->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) {
/* Rule: no IK for solitatry (unconnected) bones */
for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) {
if (bonec->flag & BONE_CONNECTED) {
@@ -379,7 +380,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
if (pchan->parent) {
/* only adds if there's no IK yet (and no parent bone was selected) */
for (parent = pchan->parent; parent; parent = parent->parent) {
- if (parent->bone->flag & BONE_SELECTED) {
+ if (parent->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) {
break;
}
}
@@ -513,14 +514,6 @@ void createTransPose(TransInfo *t)
}
}
- /* do we need to add temporal IK chains? */
- if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) {
- if (pose_grab_with_ik(bmain, ob)) {
- t->flag |= T_AUTOIK;
- has_translate_rotate[0] = true;
- }
- }
-
if (mirror) {
int total_mirrored = 0;
for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -541,16 +534,6 @@ void createTransPose(TransInfo *t)
}
}
- /* if there are no translatable bones, do rotation */
- if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
- if (has_translate_rotate[1]) {
- t->mode = TFM_ROTATION;
- }
- else {
- t->mode = TFM_RESIZE;
- }
- }
-
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
if (tc->data_len == 0) {
continue;
@@ -582,20 +565,32 @@ void createTransPose(TransInfo *t)
td->val = NULL;
}
- /* use pose channels to fill trans data */
- td = tc->data;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_TRANSFORM) {
- add_pose_transdata(t, pchan, ob, tc, td);
-
- if (mirror) {
+ if (mirror) {
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
if (pchan_mirror) {
+ pchan_mirror->bone->flag |= BONE_TRANSFORM_MIRROR;
pose_mirror_info_init(&pid[pid_index], pchan_mirror, pchan, is_mirror_relative);
pid_index++;
}
}
+ }
+ }
+ /* do we need to add temporal IK chains? */
+ if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) {
+ if (pose_grab_with_ik(bmain, ob)) {
+ t->flag |= T_AUTOIK;
+ has_translate_rotate[0] = true;
+ }
+ }
+
+ /* use pose channels to fill trans data */
+ td = tc->data;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ add_pose_transdata(t, pchan, ob, tc, td);
td++;
}
}
@@ -603,10 +598,20 @@ void createTransPose(TransInfo *t)
if (td != (tc->data + tc->data_len)) {
BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
}
+ }
- /* initialize initial auto=ik chainlen's? */
- if (t->flag & T_AUTOIK) {
- transform_autoik_update(t, 0);
+ /* initialize initial auto=ik chainlen's? */
+ if (t->flag & T_AUTOIK) {
+ transform_autoik_update(t, 0);
+ }
+
+ /* if there are no translatable bones, do rotation */
+ if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
+ if (has_translate_rotate[1]) {
+ t->mode = TFM_ROTATION;
+ }
+ else {
+ t->mode = TFM_RESIZE;
}
}
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 8b7dcecf9e8..006f913f218 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1451,7 +1451,7 @@ void createTransUVs(bContext *C, TransInfo *t)
if (is_prop_connected || 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, use_facesel, false, true);
+ elementmap = BM_uv_element_map_create(em->bm, scene, use_facesel, true, false, true);
if (elementmap == NULL) {
continue;
}
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 331a3eea59f..16dfdd35c32 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -55,10 +55,8 @@ typedef struct TransDataObject {
* Object to object data transform table.
* Don't add these to transform data because we may want to include child objects
* which aren't being transformed.
- * - The key is object data #ID.
- * - The value is #XFormObjectData_Extra.
*/
- struct GHash *obdata_in_obmode_map;
+ struct XFormObjectData_Container *xds;
/**
* Transform
@@ -69,7 +67,6 @@ typedef struct TransDataObject {
} TransDataObject;
-static void trans_obdata_in_obmode_free_all(TransDataObject *tdo);
static void trans_obchild_in_obmode_free_all(TransDataObject *tdo);
static void freeTransObjectCustomData(TransInfo *t,
@@ -80,7 +77,7 @@ static void freeTransObjectCustomData(TransInfo *t,
custom_data->data = NULL;
if (t->options & CTX_OBMODE_XFORM_OBDATA) {
- trans_obdata_in_obmode_free_all(tdo);
+ ED_object_data_xform_container_destroy(tdo->xds);
}
if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
@@ -98,81 +95,18 @@ static void freeTransObjectCustomData(TransInfo *t,
* We need this to be detached from transform data because,
* unlike transforming regular objects, we need to transform the children.
*
+ * Nearly all of the logic here is in the 'ED_object_data_xform_container_*' API.
* \{ */
-struct XFormObjectData_Extra {
- Object *ob;
- float obmat_orig[4][4];
- struct XFormObjectData *xod;
-};
-
-static void trans_obdata_in_obmode_ensure_object(TransDataObject *tdo, Object *ob)
-{
- if (tdo->obdata_in_obmode_map == NULL) {
- tdo->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
- }
-
- void **xf_p;
- if (!BLI_ghash_ensure_p(tdo->obdata_in_obmode_map, ob->data, &xf_p)) {
- struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__);
- copy_m4_m4(xf->obmat_orig, ob->obmat);
- xf->ob = ob;
- /* Result may be NULL, that's OK. */
- xf->xod = ED_object_data_xform_create(ob->data);
- *xf_p = xf;
- }
-}
-
void trans_obdata_in_obmode_update_all(TransInfo *t)
{
TransDataObject *tdo = t->custom.type.data;
- if (tdo->obdata_in_obmode_map == NULL) {
+ if (tdo->xds == NULL) {
return;
}
struct Main *bmain = CTX_data_main(t->context);
- BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain);
-
- GHashIterator gh_iter;
- GHASH_ITER (gh_iter, tdo->obdata_in_obmode_map) {
- ID *id = BLI_ghashIterator_getKey(&gh_iter);
- struct XFormObjectData_Extra *xf = BLI_ghashIterator_getValue(&gh_iter);
- if (xf->xod == NULL) {
- continue;
- }
-
- Object *ob_eval = DEG_get_evaluated_object(t->depsgraph, xf->ob);
- float imat[4][4], dmat[4][4];
- invert_m4_m4(imat, xf->obmat_orig);
- mul_m4_m4m4(dmat, imat, ob_eval->obmat);
- invert_m4(dmat);
-
- ED_object_data_xform_by_mat4(xf->xod, dmat);
- if (xf->ob->type == OB_ARMATURE) {
- /* TODO: none of the current flags properly update armatures, needs investigation. */
- DEG_id_tag_update(id, 0);
- }
- else {
- DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- }
- }
-}
-
-/** Callback for #GHash free. */
-static void trans_obdata_in_obmode_free_elem(void *xf_p)
-{
- struct XFormObjectData_Extra *xf = xf_p;
- if (xf->xod) {
- ED_object_data_xform_destroy(xf->xod);
- }
- MEM_freeN(xf);
-}
-
-static void trans_obdata_in_obmode_free_all(TransDataObject *tdo)
-{
- if (tdo->obdata_in_obmode_map != NULL) {
- BLI_ghash_free(tdo->obdata_in_obmode_map, NULL, trans_obdata_in_obmode_free_elem);
- }
+ ED_object_data_xform_container_update_all(tdo->xds, bmain, t->depsgraph);
}
/** \} */
@@ -697,6 +631,10 @@ void createTransObject(bContext *C, TransInfo *t)
t->custom.type.data = tdo;
t->custom.type.free_cb = freeTransObjectCustomData;
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ tdo->xds = ED_object_data_xform_container_create();
+ }
+
CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
Object *ob = base->object;
@@ -729,7 +667,7 @@ void createTransObject(bContext *C, TransInfo *t)
if (t->options & CTX_OBMODE_XFORM_OBDATA) {
if ((td->flag & TD_SKIP) == 0) {
- trans_obdata_in_obmode_ensure_object(tdo, ob);
+ ED_object_data_xform_container_item_ensure(tdo->xds, ob);
}
}
@@ -797,7 +735,7 @@ void createTransObject(bContext *C, TransInfo *t)
ob_parent = ob_parent->parent;
}
if (parent_in_transdata) {
- trans_obdata_in_obmode_ensure_object(tdo, ob);
+ ED_object_data_xform_container_item_ensure(tdo->xds, ob);
}
}
}
diff --git a/source/blender/editors/transform/transform_draw.c b/source/blender/editors/transform/transform_draw.c
new file mode 100644
index 00000000000..e44442b7e49
--- /dev/null
+++ b/source/blender/editors/transform/transform_draw.c
@@ -0,0 +1,114 @@
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Key (Pixel Space)
+ * \{ */
+
+/* just draw a little warning message in the top-right corner of the viewport
+ * to warn that autokeying is enabled */
+static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
+{
+ const char *printable = IFACE_("Auto Keying On");
+ float printable_size[2];
+ int xco, yco;
+
+ const rcti *rect = ED_region_visible_rect(ar);
+
+ const int font_id = BLF_default();
+ BLF_width_and_height(
+ font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
+
+ xco = (rect->xmax - U.widget_unit) - (int)printable_size[0];
+ yco = (rect->ymax - U.widget_unit);
+
+ /* warning text (to clarify meaning of overlays)
+ * - original color was red to match the icon, but that clashes badly with a less nasty border
+ */
+ unsigned char color[3];
+ UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color);
+ BLF_color3ubv(font_id, color);
+#ifdef WITH_INTERNATIONAL
+ BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+#else
+ BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+#endif
+
+ /* autokey recording icon... */
+ GPU_blend_set_func_separate(
+ GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ xco -= U.widget_unit;
+ yco -= (int)printable_size[1] / 2;
+
+ UI_icon_draw(xco, yco, ICON_REC);
+
+ GPU_blend(false);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Constraints (View Space)
+ * \{ */
+
+/* called from drawview.c, as an extra per-window draw option */
+void drawPropCircle(const struct bContext *C, TransInfo *t)
+{
+ if (t->flag & T_PROP_EDIT) {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ float tmat[4][4], imat[4][4];
+ int depth_test_enabled;
+
+ if (t->spacetype == SPACE_VIEW3D && rv3d != NULL) {
+ copy_m4_m4(tmat, rv3d->viewmat);
+ invert_m4_m4(imat, tmat);
+ }
+ else {
+ unit_m4(tmat);
+ unit_m4(imat);
+ }
+
+ GPU_matrix_push();
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* pass */
+ }
+ else if (t->spacetype == SPACE_IMAGE) {
+ GPU_matrix_scale_2f(1.0f / t->aspect[0], 1.0f / t->aspect[1]);
+ }
+ else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION)) {
+ /* only scale y */
+ rcti *mask = &t->ar->v2d.mask;
+ rctf *datamask = &t->ar->v2d.cur;
+ float xsize = BLI_rctf_size_x(datamask);
+ float ysize = BLI_rctf_size_y(datamask);
+ float xmask = BLI_rcti_size_x(mask);
+ float ymask = BLI_rcti_size_y(mask);
+ GPU_matrix_scale_2f(1.0f, (ysize / xsize) * (xmask / ymask));
+ }
+
+ depth_test_enabled = GPU_depth_test_enabled();
+ if (depth_test_enabled) {
+ GPU_depth_test(false);
+ }
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_GRID);
+
+ GPU_logic_op_invert_set(true);
+ imm_drawcircball(t->center_global, t->prop_size, imat, pos);
+ GPU_logic_op_invert_set(false);
+
+ immUnbindProgram();
+
+ if (depth_test_enabled) {
+ GPU_depth_test(true);
+ }
+
+ GPU_matrix_pop();
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c
new file mode 100644
index 00000000000..dc2ebdca56a
--- /dev/null
+++ b/source/blender/editors/transform/transform_draw_cursors.c
@@ -0,0 +1,344 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "BLI_math.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "BKE_context.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "transform.h"
+#include "transform_draw_cursors.h" /* Own include. */
+
+enum eArrowDirection {
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT,
+};
+
+struct ArrowDims {
+ int offset;
+ int length;
+ int size;
+};
+
+#define POS_INDEX 0
+/* NOTE: this --^ is a bit hackish, but simplifies GPUVertFormat usage among functions
+ * private to this file - merwin
+ */
+
+static void drawArrow(enum eArrowDirection dir, const struct ArrowDims *arrow_dims)
+{
+ int offset = arrow_dims->offset;
+ int length = arrow_dims->length;
+ int size = arrow_dims->size;
+
+ immBegin(GPU_PRIM_LINES, 6);
+
+ switch (dir) {
+ case LEFT:
+ offset = -offset;
+ length = -length;
+ size = -size;
+ ATTR_FALLTHROUGH;
+ case RIGHT:
+ immVertex2f(POS_INDEX, offset, 0);
+ immVertex2f(POS_INDEX, offset + length, 0);
+ immVertex2f(POS_INDEX, offset + length, 0);
+ immVertex2f(POS_INDEX, offset + length - size, -size);
+ immVertex2f(POS_INDEX, offset + length, 0);
+ immVertex2f(POS_INDEX, offset + length - size, size);
+ break;
+
+ case DOWN:
+ offset = -offset;
+ length = -length;
+ size = -size;
+ ATTR_FALLTHROUGH;
+ case UP:
+ immVertex2f(POS_INDEX, 0, offset);
+ immVertex2f(POS_INDEX, 0, offset + length);
+ immVertex2f(POS_INDEX, 0, offset + length);
+ immVertex2f(POS_INDEX, -size, offset + length - size);
+ immVertex2f(POS_INDEX, 0, offset + length);
+ immVertex2f(POS_INDEX, size, offset + length - size);
+ break;
+ }
+
+ immEnd();
+}
+
+static void drawArrowHead(enum eArrowDirection dir, int size)
+{
+ immBegin(GPU_PRIM_LINES, 4);
+
+ switch (dir) {
+ case LEFT:
+ size = -size;
+ ATTR_FALLTHROUGH;
+ case RIGHT:
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, -size, -size);
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, -size, size);
+ break;
+
+ case DOWN:
+ size = -size;
+ ATTR_FALLTHROUGH;
+ case UP:
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, -size, -size);
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, size, -size);
+ break;
+ }
+
+ immEnd();
+}
+
+static void drawArc(float angle_start, float angle_end, int segments, float size)
+{
+ float delta = (angle_end - angle_start) / segments;
+ float angle;
+ int a;
+
+ immBegin(GPU_PRIM_LINE_STRIP, segments + 1);
+
+ for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
+ immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
+ }
+ immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
+
+ immEnd();
+}
+
+/**
+ * Poll callback for cursor drawing:
+ * #WM_paint_cursor_activate
+ */
+bool transform_draw_cursor_poll(bContext *C)
+{
+ ARegion *ar = CTX_wm_region(C);
+
+ if (ar && ar->regiontype == RGN_TYPE_WINDOW) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Cursor and help-line drawing, callback for:
+ * #WM_paint_cursor_activate
+ */
+void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customdata)
+{
+ TransInfo *t = (TransInfo *)customdata;
+
+ if (t->helpline != HLP_NONE) {
+ struct ArrowDims arrow_dims = {
+ .offset = 5 * UI_DPI_FAC,
+ .length = 10 * UI_DPI_FAC,
+ .size = 5 * UI_DPI_FAC,
+ };
+
+ float cent[2];
+ const float mval[3] = {x, y, 0.0f};
+ float tmval[2] = {
+ (float)t->mval[0],
+ (float)t->mval[1],
+ };
+
+ projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
+ /* Offset the values for the area region. */
+ const float offset[2] = {
+ t->ar->winrct.xmin,
+ t->ar->winrct.ymin,
+ };
+
+ for (int i = 0; i < 2; i++) {
+ cent[i] += offset[i];
+ tmval[i] += offset[i];
+ }
+
+ GPU_line_smooth(true);
+ GPU_blend(true);
+
+ GPU_matrix_push();
+
+ /* Dashed lines first. */
+ if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
+ const uint shdr_pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
+ BLI_assert(shdr_pos == POS_INDEX);
+
+ GPU_line_width(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+ immUniform1f("dash_width", 6.0f * UI_DPI_FAC);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(POS_INDEX, cent);
+ immVertex2f(POS_INDEX, tmval[0], tmval[1]);
+ immEnd();
+
+ immUnbindProgram();
+ }
+
+ /* And now, solid lines. */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ UNUSED_VARS_NDEBUG(pos); /* silence warning */
+ BLI_assert(pos == POS_INDEX);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ switch (t->helpline) {
+ case HLP_SPRING:
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+
+ GPU_matrix_translate_3fv(mval);
+ GPU_matrix_rotate_axis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
+
+ GPU_line_width(3.0f);
+ drawArrow(UP, &arrow_dims);
+ drawArrow(DOWN, &arrow_dims);
+ break;
+ case HLP_HARROW:
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+ GPU_matrix_translate_3fv(mval);
+
+ GPU_line_width(3.0f);
+ drawArrow(RIGHT, &arrow_dims);
+ drawArrow(LEFT, &arrow_dims);
+ break;
+ case HLP_VARROW:
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+
+ GPU_matrix_translate_3fv(mval);
+
+ GPU_line_width(3.0f);
+ drawArrow(UP, &arrow_dims);
+ drawArrow(DOWN, &arrow_dims);
+ break;
+ case HLP_CARROW: {
+ /* Draw arrow based on direction defined by custom-points. */
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+
+ GPU_matrix_translate_3fv(mval);
+
+ GPU_line_width(3.0f);
+
+ const int *data = t->mouse.data;
+ const float dx = data[2] - data[0], dy = data[3] - data[1];
+ const float angle = -atan2f(dx, dy);
+
+ GPU_matrix_push();
+
+ GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
+
+ drawArrow(UP, &arrow_dims);
+ drawArrow(DOWN, &arrow_dims);
+
+ GPU_matrix_pop();
+ break;
+ }
+ case HLP_ANGLE: {
+ float dx = tmval[0] - cent[0], dy = tmval[1] - cent[1];
+ float angle = atan2f(dy, dx);
+ float dist = hypotf(dx, dy);
+ float delta_angle = min_ff(15.0f / (dist / UI_DPI_FAC), (float)M_PI / 4.0f);
+ float spacing_angle = min_ff(5.0f / (dist / UI_DPI_FAC), (float)M_PI / 12.0f);
+
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+
+ GPU_matrix_translate_3f(cent[0] - tmval[0] + mval[0], cent[1] - tmval[1] + mval[1], 0);
+
+ GPU_line_width(3.0f);
+ drawArc(angle - delta_angle, angle - spacing_angle, 10, dist);
+ drawArc(angle + spacing_angle, angle + delta_angle, 10, dist);
+
+ GPU_matrix_push();
+
+ GPU_matrix_translate_3f(
+ cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
+ GPU_matrix_rotate_axis(RAD2DEGF(angle - delta_angle), 'Z');
+
+ drawArrowHead(DOWN, arrow_dims.size);
+
+ GPU_matrix_pop();
+
+ GPU_matrix_translate_3f(
+ cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
+ GPU_matrix_rotate_axis(RAD2DEGF(angle + delta_angle), 'Z');
+
+ drawArrowHead(UP, arrow_dims.size);
+ break;
+ }
+ case HLP_TRACKBALL: {
+ unsigned char col[3], col2[3];
+ UI_GetThemeColor3ubv(TH_GRID, col);
+
+ GPU_matrix_translate_3fv(mval);
+
+ GPU_line_width(3.0f);
+
+ UI_make_axis_color(col, col2, 'X');
+ immUniformColor3ubv(col2);
+
+ drawArrow(RIGHT, &arrow_dims);
+ drawArrow(LEFT, &arrow_dims);
+
+ UI_make_axis_color(col, col2, 'Y');
+ immUniformColor3ubv(col2);
+
+ drawArrow(UP, &arrow_dims);
+ drawArrow(DOWN, &arrow_dims);
+ break;
+ }
+ }
+
+ immUnbindProgram();
+ GPU_matrix_pop();
+
+ GPU_line_smooth(false);
+ GPU_blend(false);
+ }
+}
diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/transform/transform_draw_cursors.h
index 84820c3c564..e7696bad5a7 100644
--- a/source/blender/editors/include/BIF_gl.h
+++ b/source/blender/editors/transform/transform_draw_cursors.h
@@ -15,30 +15,17 @@
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
- * os dependent include locations of gl.h
*/
/** \file
- * \ingroup editorui
+ * \ingroup edtransform
*/
-#ifndef __BIF_GL_H__
-#define __BIF_GL_H__
+#ifndef __TRANSFORM_DRAW_CURSORS_H__
+#define __TRANSFORM_DRAW_CURSORS_H__
-#include "GPU_glew.h"
-#include "BLI_utildefines.h"
+/* Callbacks for #WM_paint_cursor_activate */
+bool transform_draw_cursor_poll(struct bContext *C);
+void transform_draw_cursor_draw(struct bContext *C, int x, int y, void *customdata);
-/* hacking pointsize and linewidth */
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
-# define glPointSize(f) \
- glPointSize(U.pixelsize *_Generic((f), double : (float)(f), default : (f)))
-# define glLineWidth(f) \
- glLineWidth(U.pixelsize *_Generic((f), double : (float)(f), default : (f)))
-#else
-# define glPointSize(f) glPointSize(U.pixelsize *(f))
-# define glLineWidth(f) glLineWidth(U.pixelsize *(f))
-#endif /* C11 */
-
-#define GLA_PIXEL_OFS 0.375f
-
-#endif /* #ifdef __BIF_GL_H__ */
+#endif /* __TRANSFORM_DRAW_CURSORS_H__ */
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 43e241da313..5595c3a0e38 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -31,6 +31,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
+#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_lattice_types.h"
#include "DNA_screen_types.h"
@@ -785,50 +786,61 @@ static void recalcData_spaceclip(TransInfo *t)
* if pose bone (partial) selected, copy data.
* context; posemode armature, with mirror editing enabled.
*
- * \param pid: Optional, apply relative transform when set.
+ * \param pid: Optional, apply relative transform when set (has no effect on mirrored bones).
*/
-static void pose_transform_mirror_update(Object *ob, PoseInitData_Mirror *pid)
+static void pose_transform_mirror_update(TransInfo *t,
+ TransDataContainer *tc,
+ Object *ob,
+ PoseInitData_Mirror *pid)
{
float flip_mtx[4][4];
unit_m4(flip_mtx);
flip_mtx[0][0] = -1;
- for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig;
- pchan_orig = pchan_orig->next) {
- /* Clear the MIRROR flag from previous runs */
- pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR;
- }
-
- for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig;
- pchan_orig = pchan_orig->next) {
- /* no layer check, correct mirror is more important */
- if (pchan_orig->bone->flag & BONE_TRANSFORM) {
- bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name);
-
- if (pchan) {
- /* also do bbone scaling */
- pchan->bone->xwidth = pchan_orig->bone->xwidth;
- pchan->bone->zwidth = pchan_orig->bone->zwidth;
-
- /* we assume X-axis flipping for now */
- pchan->curve_in_x = pchan_orig->curve_in_x * -1;
- pchan->curve_out_x = pchan_orig->curve_out_x * -1;
- pchan->roll1 = pchan_orig->roll1 * -1; // XXX?
- pchan->roll2 = pchan_orig->roll2 * -1; // XXX?
-
- float pchan_mtx_final[4][4];
- BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final);
- mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx);
- mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final);
- if (pid) {
- mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final);
- pid++;
- }
- BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false);
+ TransData *td = tc->data;
+ for (int i = tc->data_len; i--; td++) {
+ bPoseChannel *pchan_orig = td->extra;
+ BLI_assert(pchan_orig->bone->flag & BONE_TRANSFORM);
+ /* No layer check, correct mirror is more important. */
+ bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name);
+ if (pchan == NULL) {
+ continue;
+ }
+
+ /* Also do bbone scaling. */
+ pchan->bone->xwidth = pchan_orig->bone->xwidth;
+ pchan->bone->zwidth = pchan_orig->bone->zwidth;
+
+ /* We assume X-axis flipping for now. */
+ pchan->curve_in_x = pchan_orig->curve_in_x * -1;
+ pchan->curve_out_x = pchan_orig->curve_out_x * -1;
+ pchan->roll1 = pchan_orig->roll1 * -1; // XXX?
+ pchan->roll2 = pchan_orig->roll2 * -1; // XXX?
- /* set flag to let autokeyframe know to keyframe the mirrred bone */
- pchan->bone->flag |= BONE_TRANSFORM_MIRROR;
+ float pchan_mtx_final[4][4];
+ BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final);
+ mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx);
+ mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final);
+ if (pid) {
+ mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final);
+ }
+ BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false);
+
+ /* In this case we can do target-less IK grabbing. */
+ if (t->mode == TFM_TRANSLATION) {
+ bKinematicConstraint *data = has_targetless_ik(pchan);
+ if (data == NULL) {
+ continue;
+ }
+ mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc);
+ if (pid) {
+ /* TODO(germano): Realitve Mirror support */
}
+ data->flag |= CONSTRAINT_IK_AUTO;
+ }
+
+ if (pid) {
+ pid++;
}
}
}
@@ -1007,6 +1019,9 @@ static void recalcData_objects(TransInfo *t)
restoreBones(tc);
}
}
+
+ /* Tag for redraw/invalidate overlay cache. */
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
}
else {
@@ -1042,7 +1057,7 @@ static void recalcData_objects(TransInfo *t)
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
bPose *pose = ob->pose;
if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) {
- pose_transform_mirror_update(ob, NULL);
+ pose_transform_mirror_update(t, tc, ob, NULL);
}
}
}
@@ -1060,7 +1075,7 @@ static void recalcData_objects(TransInfo *t)
if (pose->flag & POSE_MIRROR_RELATIVE) {
pid = tc->custom.type.data;
}
- pose_transform_mirror_update(ob, pid);
+ pose_transform_mirror_update(t, tc, ob, pid);
}
else {
restoreMirrorPoseBones(tc);
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 4ae64c7ca5f..e76ece987df 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -52,6 +52,18 @@
#include "transform.h" /* own include */
+/* -------------------------------------------------------------------- */
+/** \name Arrow / Cage Gizmo Group
+ *
+ * Defines public functions, not the gizmo it's self:
+ *
+ * - #ED_widgetgroup_gizmo2d_xform_setup
+ * - #ED_widgetgroup_gizmo2d_xform_refresh
+ * - #ED_widgetgroup_gizmo2d_xform_draw_prepare
+ * - #ED_widgetgroup_gizmo2d_xform_poll
+ *
+ * \{ */
+
/* axes as index */
enum {
MAN2D_AXIS_TRANS_X = 0,
@@ -61,8 +73,7 @@ enum {
};
typedef struct GizmoGroup2D {
- wmGizmo *translate_x, *translate_y;
-
+ wmGizmo *translate_xy[3];
wmGizmo *cage;
/* Current origin in view space, used to update widget origin for possible view changes */
@@ -70,37 +81,12 @@ typedef struct GizmoGroup2D {
float min[2];
float max[2];
+ bool no_cage;
+
} GizmoGroup2D;
/* **************** Utilities **************** */
-/* loop over axes */
-#define MAN2D_ITER_AXES_BEGIN(axis, axis_idx) \
- { \
- wmGizmo *axis; \
- int axis_idx; \
- for (axis_idx = 0; axis_idx < MAN2D_AXIS_LAST; axis_idx++) { \
- axis = gizmo2d_get_axis_from_index(ggd, axis_idx);
-
-#define MAN2D_ITER_AXES_END \
- } \
- } \
- ((void)0)
-
-static wmGizmo *gizmo2d_get_axis_from_index(const GizmoGroup2D *ggd, const short axis_idx)
-{
- BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN2D_AXIS_TRANS_X, (float)MAN2D_AXIS_TRANS_Y));
-
- switch (axis_idx) {
- case MAN2D_AXIS_TRANS_X:
- return ggd->translate_x;
- case MAN2D_AXIS_TRANS_Y:
- return ggd->translate_y;
- }
-
- return NULL;
-}
-
static void gizmo2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi)
{
const float alpha = 0.6f;
@@ -129,13 +115,15 @@ static void gizmo2d_get_axis_color(const int axis_idx, float *r_col, float *r_co
static GizmoGroup2D *gizmogroup2d_init(wmGizmoGroup *gzgroup)
{
- const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_2d", true);
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_2d", true);
+ const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
GizmoGroup2D *ggd = MEM_callocN(sizeof(GizmoGroup2D), __func__);
- ggd->translate_x = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
- ggd->translate_y = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->translate_xy[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->translate_xy[1] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->translate_xy[2] = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL);
ggd->cage = WM_gizmo_new_ptr(gzt_cage, gzgroup, NULL);
RNA_enum_set(ggd->cage->ptr,
@@ -208,39 +196,64 @@ static int gizmo2d_modal(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
-void ED_widgetgroup_gizmo2d_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+void ED_widgetgroup_gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
GizmoGroup2D *ggd = gizmogroup2d_init(gzgroup);
gzgroup->customdata = ggd;
- MAN2D_ITER_AXES_BEGIN (axis, axis_idx) {
- const float offset[3] = {0.0f, 0.2f};
-
- float color[4], color_hi[4];
- gizmo2d_get_axis_color(axis_idx, color, color_hi);
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ wmGizmo *gz = ggd->translate_xy[i];
/* custom handler! */
- WM_gizmo_set_fn_custom_modal(axis, gizmo2d_modal);
- /* set up widget data */
- RNA_float_set(axis->ptr, "angle", -M_PI_2 * axis_idx);
- RNA_float_set(axis->ptr, "length", 0.8f);
- WM_gizmo_set_matrix_offset_location(axis, offset);
- WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH);
- WM_gizmo_set_scale(axis, U.gizmo_size);
- WM_gizmo_set_color(axis, color);
- WM_gizmo_set_color_highlight(axis, color_hi);
+ WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
- /* assign operator */
- PointerRNA *ptr = WM_gizmo_operator_set(axis, 0, ot_translate, NULL);
- bool constraint[3] = {0};
- constraint[(axis_idx + 1) % 2] = 1;
- if (RNA_struct_find_property(ptr, "constraint_axis")) {
- RNA_boolean_set_array(ptr, "constraint_axis", constraint);
+ if (i < 2) {
+ float color[4], color_hi[4];
+ gizmo2d_get_axis_color(i, color, color_hi);
+
+ /* set up widget data */
+ RNA_float_set(gz->ptr, "length", 0.8f);
+ float axis[3] = {0.0f};
+ axis[(i + 1) % 2] = 1.0f;
+ WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis);
+
+ float offset[3] = {0, 0, 0};
+ offset[2] = 0.18f;
+ WM_gizmo_set_matrix_offset_location(gz, offset);
+ gz->flag |= WM_GIZMO_DRAW_OFFSET_SCALE;
+
+ WM_gizmo_set_line_width(gz, GIZMO_AXIS_LINE_WIDTH);
+ WM_gizmo_set_color(gz, color);
+ WM_gizmo_set_color_highlight(gz, color_hi);
+
+ WM_gizmo_set_scale(gz, 1.0f);
+ }
+ else {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
+ RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
+
+ RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
+ /* Make the center low alpha. */
+ WM_gizmo_set_line_width(gz, 2.0f);
+ RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
+ WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6});
+
+ WM_gizmo_set_scale(gz, 0.2f);
+ }
+
+ /* Assign operator. */
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_translate, NULL);
+ if (i < 2) {
+ bool constraint[3] = {0};
+ constraint[(i + 1) % 2] = 1;
+ if (RNA_struct_find_property(ptr, "constraint_axis")) {
+ RNA_boolean_set_array(ptr, "constraint_axis", constraint);
+ }
}
+
RNA_boolean_set(ptr, "release_confirm", 1);
}
- MAN2D_ITER_AXES_END;
{
wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
@@ -286,23 +299,44 @@ void ED_widgetgroup_gizmo2d_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgro
}
}
-void ED_widgetgroup_gizmo2d_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+void ED_widgetgroup_gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ED_widgetgroup_gizmo2d_xform_setup(C, gzgroup);
+ GizmoGroup2D *ggd = gzgroup->customdata;
+ ggd->no_cage = true;
+}
+
+void ED_widgetgroup_gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup2D *ggd = gzgroup->customdata;
float origin[3];
gizmo2d_calc_bounds(C, origin, ggd->min, ggd->max);
copy_v2_v2(ggd->origin, origin);
- bool show_cage = !equals_v2v2(ggd->min, ggd->max);
+ bool show_cage = !ggd->no_cage && !equals_v2v2(ggd->min, ggd->max);
+
+ if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
+ Scene *scene = CTX_data_scene(C);
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+ }
if (show_cage) {
ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
- ggd->translate_x->flag |= WM_GIZMO_HIDDEN;
- ggd->translate_y->flag |= WM_GIZMO_HIDDEN;
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ wmGizmo *gz = ggd->translate_xy[i];
+ gz->flag |= WM_GIZMO_HIDDEN;
+ }
}
else {
ggd->cage->flag |= WM_GIZMO_HIDDEN;
- ggd->translate_x->flag &= ~WM_GIZMO_HIDDEN;
- ggd->translate_y->flag &= ~WM_GIZMO_HIDDEN;
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ wmGizmo *gz = ggd->translate_xy[i];
+ gz->flag &= ~WM_GIZMO_HIDDEN;
+ }
}
if (show_cage) {
@@ -345,7 +379,7 @@ void ED_widgetgroup_gizmo2d_refresh(const bContext *C, wmGizmoGroup *gzgroup)
}
}
-void ED_widgetgroup_gizmo2d_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+void ED_widgetgroup_gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *ar = CTX_wm_region(C);
GizmoGroup2D *ggd = gzgroup->customdata;
@@ -354,10 +388,10 @@ void ED_widgetgroup_gizmo2d_draw_prepare(const bContext *C, wmGizmoGroup *gzgrou
gizmo2d_origin_to_region(ar, origin);
- MAN2D_ITER_AXES_BEGIN (axis, axis_idx) {
- WM_gizmo_set_matrix_location(axis, origin);
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ wmGizmo *gz = ggd->translate_xy[i];
+ WM_gizmo_set_matrix_location(gz, origin);
}
- MAN2D_ITER_AXES_END;
UI_view2d_view_to_region_m4(&ar->v2d, ggd->cage->matrix_space);
WM_gizmo_set_matrix_offset_location(ggd->cage, origin_aa);
@@ -369,7 +403,7 @@ void ED_widgetgroup_gizmo2d_draw_prepare(const bContext *C, wmGizmoGroup *gzgrou
* - Called on every redraw, better to do a more simple poll and check for selection in _refresh
* - UV editing only, could be expanded for other things.
*/
-bool ED_widgetgroup_gizmo2d_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+bool ED_widgetgroup_gizmo2d_xform_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
{
if ((U.gizmo_flag & USER_GIZMO_DRAW) == 0) {
return false;
@@ -404,3 +438,229 @@ bool ED_widgetgroup_gizmo2d_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzg
return false;
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scale Handles
+ *
+ * Defines public functions, not the gizmo it's self:
+ *
+ * - #ED_widgetgroup_gizmo2d_resize_setup
+ * - #ED_widgetgroup_gizmo2d_resize_refresh
+ * - #ED_widgetgroup_gizmo2d_resize_draw_prepare
+ * - #ED_widgetgroup_gizmo2d_resize_poll
+ *
+ * \{ */
+
+typedef struct GizmoGroup_Resize2D {
+ wmGizmo *gizmo_xy[3];
+ float origin[2];
+} GizmoGroup_Resize2D;
+
+static GizmoGroup_Resize2D *gizmogroup2d_resize_init(wmGizmoGroup *gzgroup)
+{
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
+ const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
+
+ GizmoGroup_Resize2D *ggd = MEM_callocN(sizeof(GizmoGroup_Resize2D), __func__);
+
+ ggd->gizmo_xy[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->gizmo_xy[1] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->gizmo_xy[2] = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL);
+
+ return ggd;
+}
+
+void ED_widgetgroup_gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoGroup_Resize2D *ggd = gzgroup->customdata;
+ float origin[3];
+ gizmo2d_calc_bounds(C, origin, NULL, NULL);
+ copy_v2_v2(ggd->origin, origin);
+}
+
+void ED_widgetgroup_gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *ar = CTX_wm_region(C);
+ GizmoGroup_Resize2D *ggd = gzgroup->customdata;
+ float origin[3] = {UNPACK2(ggd->origin), 0.0f};
+
+ if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
+ Scene *scene = CTX_data_scene(C);
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+ }
+
+ gizmo2d_origin_to_region(ar, origin);
+
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
+ wmGizmo *gz = ggd->gizmo_xy[i];
+ WM_gizmo_set_matrix_location(gz, origin);
+ }
+}
+
+bool ED_widgetgroup_gizmo2d_resize_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ return ED_widgetgroup_gizmo2d_xform_poll(C, NULL);
+}
+
+void ED_widgetgroup_gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+
+ wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
+ GizmoGroup_Resize2D *ggd = gizmogroup2d_resize_init(gzgroup);
+ gzgroup->customdata = ggd;
+
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
+ wmGizmo *gz = ggd->gizmo_xy[i];
+
+ /* custom handler! */
+ WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
+
+ if (i < 2) {
+ float color[4], color_hi[4];
+ gizmo2d_get_axis_color(i, color, color_hi);
+
+ /* set up widget data */
+ RNA_float_set(gz->ptr, "length", 1.0f);
+ float axis[3] = {0.0f};
+ axis[(i + 1) % 2] = 1.0f;
+ WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis);
+
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
+
+ WM_gizmo_set_line_width(gz, GIZMO_AXIS_LINE_WIDTH);
+ WM_gizmo_set_color(gz, color);
+ WM_gizmo_set_color_highlight(gz, color_hi);
+
+ WM_gizmo_set_scale(gz, 1.0f);
+ }
+ else {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
+ RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
+
+ RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
+ /* Make the center low alpha. */
+ WM_gizmo_set_line_width(gz, 2.0f);
+ RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
+ WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6});
+
+ WM_gizmo_set_scale(gz, 1.2f);
+ }
+
+ /* Assign operator. */
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, NULL);
+ if (i < 2) {
+ bool constraint[3] = {0};
+ constraint[(i + 1) % 2] = 1;
+ if (RNA_struct_find_property(ptr, "constraint_axis")) {
+ RNA_boolean_set_array(ptr, "constraint_axis", constraint);
+ }
+ }
+ RNA_boolean_set(ptr, "release_confirm", true);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rotate Handles
+ *
+ * Defines public functions, not the gizmo it's self:
+ *
+ * - #ED_widgetgroup_gizmo2d_rotate_setup
+ * - #ED_widgetgroup_gizmo2d_rotate_refresh
+ * - #ED_widgetgroup_gizmo2d_rotate_draw_prepare
+ * - #ED_widgetgroup_gizmo2d_rotate_poll
+ *
+ * \{ */
+
+typedef struct GizmoGroup_Rotate2D {
+ wmGizmo *gizmo;
+ float origin[2];
+} GizmoGroup_Rotate2D;
+
+static GizmoGroup_Rotate2D *gizmogroup2d_rotate_init(wmGizmoGroup *gzgroup)
+{
+ const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
+
+ GizmoGroup_Rotate2D *ggd = MEM_callocN(sizeof(GizmoGroup_Rotate2D), __func__);
+
+ ggd->gizmo = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL);
+
+ return ggd;
+}
+
+void ED_widgetgroup_gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
+ float origin[3];
+ gizmo2d_calc_bounds(C, origin, NULL, NULL);
+ copy_v2_v2(ggd->origin, origin);
+}
+
+void ED_widgetgroup_gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *ar = CTX_wm_region(C);
+ GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
+ float origin[3] = {UNPACK2(ggd->origin), 0.0f};
+
+ if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
+ Scene *scene = CTX_data_scene(C);
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+ }
+
+ gizmo2d_origin_to_region(ar, origin);
+
+ wmGizmo *gz = ggd->gizmo;
+ WM_gizmo_set_matrix_location(gz, origin);
+}
+
+bool ED_widgetgroup_gizmo2d_rotate_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ return ED_widgetgroup_gizmo2d_xform_poll(C, NULL);
+}
+
+void ED_widgetgroup_gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+
+ wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_rotate", true);
+ GizmoGroup_Rotate2D *ggd = gizmogroup2d_rotate_init(gzgroup);
+ gzgroup->customdata = ggd;
+
+ /* Other setup functions iterate over axis. */
+ {
+ wmGizmo *gz = ggd->gizmo;
+
+ /* custom handler! */
+ WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
+ WM_gizmo_set_scale(gz, 1.2f);
+
+ {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
+ RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
+
+ RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
+ /* Make the center low alpha. */
+ WM_gizmo_set_line_width(gz, 2.0f);
+ RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
+ WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6});
+ }
+
+ /* Assign operator. */
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, NULL);
+ RNA_boolean_set(ptr, "release_confirm", true);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 237bf50be7c..b3c1fbd3aad 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -1322,6 +1322,17 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
}
}
+ {
+ extern PropertyRNA rna_ToolSettings_workspace_tool_type;
+ const PropertyRNA *props[] = {
+ &rna_ToolSettings_workspace_tool_type,
+ };
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(
+ mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
+ }
+ }
+
PointerRNA view3d_ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceView3D, sa->spacedata.first, &view3d_ptr);
@@ -1732,6 +1743,13 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
RegionView3D *rv3d = ar->regiondata;
struct TransformBounds tbounds;
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+
if (ggd->use_twtype_refresh) {
ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
if (ggd->twtype != ggd->twtype_prev) {
@@ -2028,7 +2046,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;
+ 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;
@@ -2062,7 +2081,8 @@ void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
gzgt->name = "3D View: Transform Gizmo Context";
gzgt->idname = "VIEW3D_GGT_xform_gizmo_context";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_PERSISTENT;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_PERSISTENT |
+ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->poll = WIDGETGROUP_gizmo_poll_context;
gzgt->setup = WIDGETGROUP_gizmo_setup;
@@ -2157,6 +2177,13 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr
struct TransformBounds tbounds;
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene,
SCE_ORIENT_SCALE);
@@ -2263,7 +2290,8 @@ void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
gzgt->name = "Transform Cage";
gzgt->idname = "VIEW3D_GGT_xform_cage";
- gzgt->flag |= WM_GIZMOGROUPTYPE_3D;
+ 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;
@@ -2284,6 +2312,9 @@ void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
struct XFormShearWidgetGroup {
wmGizmo *gizmo[3][2];
+ /** View aligned gizmos. */
+ wmGizmo *gizmo_view[4];
+
/* Only for view orientation. */
struct {
float viewinv_m3[3][3];
@@ -2328,6 +2359,25 @@ static void WIDGETGROUP_xform_shear_setup(const bContext *UNUSED(C), wmGizmoGrou
}
}
+ for (int i = 0; i < 4; i++) {
+ wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
+ RNA_enum_set(gz->ptr, "draw_options", 0); /* No stem. */
+ copy_v3_fl(gz->color, 1.0f);
+ gz->color[3] = 0.5f;
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_OFFSET_SCALE, true);
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, NULL);
+ RNA_boolean_set(ptr, "release_confirm", 1);
+ xgzgroup->gizmo_view[i] = gz;
+
+ /* Unlike the other gizmos, this never changes so can be set on setup. */
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
+ RNA_enum_set(&gzop->ptr, "orient_type", V3D_ORIENT_VIEW);
+
+ RNA_enum_set(&gzop->ptr, "orient_axis", 2);
+ RNA_enum_set(&gzop->ptr, "orient_axis_ortho", ((i % 2) ? 0 : 1));
+ }
+
gzgroup->customdata = xgzgroup;
}
@@ -2340,6 +2390,16 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg
struct XFormShearWidgetGroup *xgzgroup = gzgroup->customdata;
struct TransformBounds tbounds;
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+
+ /* Needed to test view orientation changes. */
+ copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
+
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene,
SCE_ORIENT_ROTATE);
@@ -2356,6 +2416,11 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
}
+
+ for (int i = 0; i < 4; i++) {
+ wmGizmo *gz = xgzgroup->gizmo_view[i];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
+ }
}
else {
gizmo_prepare_mat(C, rv3d, &tbounds);
@@ -2381,10 +2446,12 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg
mul_v3_fl(gz->matrix_basis[1], 6.0f);
}
}
- }
- /* Needed to test view orientation changes. */
- copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
+ for (int i = 0; i < 4; i++) {
+ wmGizmo *gz = xgzgroup->gizmo_view[i];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+ }
+ }
}
static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C,
@@ -2421,6 +2488,25 @@ static void WIDGETGROUP_xform_shear_draw_prepare(const bContext *C, wmGizmoGroup
}
}
+ for (int i = 0; i < 4; i++) {
+ const float outer_thin = 0.3f;
+ const float outer_offset = 1.0f / 0.3f;
+ wmGizmo *gz = xgzgroup->gizmo_view[i];
+ WM_gizmo_set_matrix_rotation_from_yz_axis(
+ gz, rv3d->viewinv[(i + 1) % 2], rv3d->viewinv[i % 2]);
+ if (i >= 2) {
+ negate_v3(gz->matrix_basis[1]);
+ negate_v3(gz->matrix_basis[2]);
+ }
+
+ /* No need for depth with view aligned gizmos. */
+ mul_v3_fl(gz->matrix_basis[0], 0.0f);
+ mul_v3_fl(gz->matrix_basis[1], 20.0f + ((1.0f / outer_thin) * 1.8f));
+ mul_v3_fl(gz->matrix_basis[2], outer_thin);
+ WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
+ gz->matrix_offset[3][2] = outer_offset;
+ }
+
/* Basic ordering for drawing only. */
{
LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
@@ -2446,7 +2532,8 @@ void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
gzgt->name = "Transform Shear";
gzgt->idname = "VIEW3D_GGT_xform_shear";
- gzgt->flag |= WM_GIZMOGROUPTYPE_3D;
+ 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_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
index 513a8afa9b6..fb33471cf3f 100644
--- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
@@ -55,9 +55,10 @@ enum {
static const float extrude_button_scale = 0.15f;
static const float extrude_button_offset_scale = 1.5f;
-static const float extrude_arrow_scale = 1.0f;
-static const float extrude_arrow_xyz_axis_scale = 1.0f;
-static const float extrude_arrow_normal_axis_scale = 1.0f;
+static const float extrude_outer_scale = 1.2f;
+static const float extrude_arrow_scale = 0.7f;
+static const float extrude_arrow_xyz_axis_scale = 0.6666f;
+static const float extrude_arrow_normal_axis_scale = 0.6666f;
static const float extrude_dial_scale = 0.2;
static const uchar shape_plus[] = {
@@ -69,6 +70,8 @@ typedef struct GizmoExtrudeGroup {
/* XYZ & normal. */
wmGizmo *invoke_xyz_no[4];
+ /* Only visible when 'drag' tool option is disabled. */
+ wmGizmo *invoke_view;
/* Constrained & unconstrained (arrow & circle). */
wmGizmo *adjust[2];
int adjust_axis;
@@ -126,12 +129,20 @@ static void gizmo_mesh_extrude_setup(const bContext *C, wmGizmoGroup *gzgroup)
ggd->adjust[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
ggd->adjust[1] = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
+ RNA_enum_set(ggd->adjust[1]->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT);
+
for (int i = 0; i < 4; i++) {
ggd->invoke_xyz_no[i] = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL);
ggd->invoke_xyz_no[i]->flag |= WM_GIZMO_DRAW_OFFSET_SCALE;
}
{
+ ggd->invoke_view = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
+ ggd->invoke_view->select_bias = -2.0f;
+ RNA_enum_set(ggd->invoke_view->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT);
+ }
+
+ {
PropertyRNA *prop = RNA_struct_find_property(ggd->invoke_xyz_no[3]->ptr, "shape");
for (int i = 0; i < 4; i++) {
RNA_property_string_set_bytes(
@@ -170,6 +181,8 @@ static void gizmo_mesh_extrude_setup(const bContext *C, wmGizmoGroup *gzgroup)
UI_GetThemeColor3fv(TH_AXIS_X + i, ggd->invoke_xyz_no[i]->color);
}
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->invoke_xyz_no[3]->color);
+ ggd->invoke_view->color[3] = 0.5f;
+
for (int i = 0; i < 2; i++) {
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->adjust[i]->color);
}
@@ -177,6 +190,9 @@ static void gizmo_mesh_extrude_setup(const bContext *C, wmGizmoGroup *gzgroup)
for (int i = 0; i < 4; i++) {
WM_gizmo_set_scale(ggd->invoke_xyz_no[i], extrude_button_scale);
}
+ WM_gizmo_set_scale(ggd->invoke_view, extrude_outer_scale);
+ ggd->invoke_view->line_width = 2.0f;
+
WM_gizmo_set_scale(ggd->adjust[0], extrude_arrow_scale);
WM_gizmo_set_scale(ggd->adjust[1], extrude_dial_scale);
ggd->adjust[1]->line_width = 2.0f;
@@ -193,6 +209,15 @@ static void gizmo_mesh_extrude_setup(const bContext *C, wmGizmoGroup *gzgroup)
}
}
+ {
+ PointerRNA *ptr = WM_gizmo_operator_set(ggd->invoke_view, 0, ggd->ot_extrude, NULL);
+ PointerRNA macroptr = RNA_pointer_get(ptr, "TRANSFORM_OT_translate");
+ RNA_boolean_set(&macroptr, "release_confirm", true);
+
+ bool constraint[3] = {0, 0, 0};
+ RNA_boolean_set_array(&macroptr, "constraint_axis", constraint);
+ }
+
/* Adjust extrude. */
for (int i = 0; i < 2; i++) {
wmGizmo *gz = ggd->adjust[i];
@@ -211,6 +236,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
for (int i = 0; i < 4; i++) {
WM_gizmo_set_flag(ggd->invoke_xyz_no[i], WM_GIZMO_HIDDEN, true);
}
+ WM_gizmo_set_flag(ggd->invoke_view, WM_GIZMO_HIDDEN, true);
for (int i = 0; i < 2; i++) {
WM_gizmo_set_flag(ggd->adjust[i], WM_GIZMO_HIDDEN, true);
}
@@ -303,6 +329,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
for (int i = 0; i < axis_len_used; i++) {
WM_gizmo_set_matrix_location(ggd->invoke_xyz_no[i], tbounds.center);
}
+ WM_gizmo_set_matrix_location(ggd->invoke_view, tbounds.center);
/* Un-hide. */
for (int i = 0; i < axis_len_used; i++) {
WM_gizmo_set_flag(ggd->invoke_xyz_no[i], WM_GIZMO_HIDDEN, false);
@@ -351,6 +378,15 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
WM_gizmo_set_flag(ggd->invoke_xyz_no[3], WM_GIZMO_HIDDEN, true);
break;
}
+
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ WM_gizmo_set_flag(ggd->invoke_view, WM_GIZMO_HIDDEN, false);
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ WM_gizmo_set_flag(ggd->invoke_view, WM_GIZMO_HIDDEN, true);
+ gzgroup->use_fallback_keymap = false;
+ }
}
static void gizmo_mesh_extrude_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
@@ -380,6 +416,11 @@ static void gizmo_mesh_extrude_draw_prepare(const bContext *C, wmGizmoGroup *gzg
copy_v3_v3(ggd->adjust[1]->matrix_basis[1], rv3d->viewinv[1]);
copy_v3_v3(ggd->adjust[1]->matrix_basis[2], rv3d->viewinv[2]);
}
+ if ((ggd->invoke_view->flag & WM_GIZMO_HIDDEN) == 0) {
+ copy_v3_v3(ggd->invoke_view->matrix_basis[0], rv3d->viewinv[0]);
+ copy_v3_v3(ggd->invoke_view->matrix_basis[1], rv3d->viewinv[1]);
+ copy_v3_v3(ggd->invoke_view->matrix_basis[2], rv3d->viewinv[2]);
+ }
}
}
@@ -400,6 +441,9 @@ static void gizmo_mesh_extrude_invoke_prepare(const bContext *UNUSED(C),
}
RNA_float_set_array(&macroptr, "value", ggd->redo_xform.value);
}
+ else if (gz == ggd->invoke_view) {
+ /* pass */
+ }
else {
/* Workaround for extrude action modifying normals. */
const int i = BLI_array_findindex(ggd->invoke_xyz_no, ARRAY_SIZE(ggd->invoke_xyz_no), &gz);
@@ -449,6 +493,20 @@ static void gizmo_mesh_extrude_message_subscribe(const bContext *C,
},
&msg_sub_value_gz_tag_refresh,
__func__);
+
+ {
+ Scene *scene = CTX_data_scene(C);
+ PointerRNA toolsettings_ptr;
+ RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
+ extern PropertyRNA rna_ToolSettings_workspace_tool_type;
+ const PropertyRNA *props[] = {
+ &rna_ToolSettings_workspace_tool_type,
+ };
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(
+ mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
+ }
+ }
}
void VIEW3D_GGT_xform_extrude(struct wmGizmoGroupType *gzgt)
@@ -456,7 +514,8 @@ void VIEW3D_GGT_xform_extrude(struct wmGizmoGroupType *gzgt)
gzgt->name = "3D View Extrude";
gzgt->idname = "VIEW3D_GGT_xform_extrude";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+ 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_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 3159464072e..1952a2c862e 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -413,7 +413,7 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
int total = 0;
for (bone = lb->first; bone; bone = bone->next) {
- bone->flag &= ~BONE_TRANSFORM;
+ bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
do_next = do_it;
if (do_it) {
if (bone->layer & arm->layer) {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 15208c1a7d2..4b6ab2045c0 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -256,6 +256,9 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
immUnbindProgram();
immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
immUniform1f("dash_width", 6.0f * U.pixelsize);
immUniform1f("dash_factor", 1.0f / 4.0f);
immUniformColor4ubv(col);
@@ -1359,6 +1362,7 @@ static void TargetSnapClosest(TransInfo *t)
short snapObjectsTransform(
TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3])
{
+ float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global;
return ED_transform_snap_object_project_view3d_ex(
t->tsnap.object_context,
t->scene->toolsettings->snap_mode,
@@ -1370,7 +1374,7 @@ short snapObjectsTransform(
SCE_SNAP_BACKFACE_CULLING) != 0,
},
mval,
- t->tsnap.snapTarget,
+ target,
dist_px,
r_loc,
r_no,
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index f9f6a513f63..a188e2eb829 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -26,6 +26,8 @@
/* For enum. */
#include "DNA_space_types.h"
+struct SnapObjectParams;
+
bool peelObjectsTransform(struct TransInfo *t,
const float mval[2],
const bool use_peel_object,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 41486a2f767..604ecb984a9 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -1424,7 +1424,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
elem = SCE_SNAP_MODE_EDGE;
- BM_mesh_elem_index_ensure(em->bm, BM_EDGE);
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_EDGE);
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE);
do {
cb_snap_edge(&nearest2d,
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 0c52dd15092..987327eefc1 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -44,7 +44,6 @@ set(SRC
select_utils.c
# general includes
- ../include/BIF_gl.h
../include/BIF_glutil.h
../include/ED_anim_api.h
../include/ED_armature.h
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index fafd54804c0..528fca85fa7 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -217,7 +217,7 @@ static void uvedit_get_batches(Object *ob,
}
static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
- Scene *scene,
+ const Scene *scene,
Object *obedit,
Depsgraph *depsgraph)
{
@@ -237,11 +237,11 @@ static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
}
}
-static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
+static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgraph)
{
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *me = ob_eval->data;
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
float col[4];
UI_GetThemeColor4fv(TH_UV_SHADOW, col);
@@ -296,7 +296,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
/* draws uv's in the image space */
static void draw_uvs(SpaceImage *sima,
- Scene *scene,
+ const Scene *scene,
Depsgraph *depsgraph,
UVEditGPUBatches *batch,
float tot_area_ratio,
@@ -496,7 +496,7 @@ static void draw_uv_shadows_get(
}
void ED_uvedit_draw_main(SpaceImage *sima,
- Scene *scene,
+ const Scene *scene,
ViewLayer *view_layer,
Object *obedit,
Object *obact,
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index eb3d47ba1b5..33fcd67f6ed 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -274,7 +274,7 @@ bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa)
return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
}
}
-bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
+bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa)
{
return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa);
}
@@ -290,7 +290,7 @@ bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *
return uvedit_face_visible_nolocal_ex(ts, efa);
}
}
-bool uvedit_face_visible_test(Scene *scene, Object *obedit, Image *ima, BMFace *efa)
+bool uvedit_face_visible_test(const Scene *scene, Object *obedit, Image *ima, BMFace *efa)
{
return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa);
}
@@ -315,12 +315,12 @@ bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int c
return true;
}
}
-bool uvedit_face_select_test(Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
+bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
{
return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
}
-bool uvedit_face_select_set(struct Scene *scene,
+bool uvedit_face_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
const bool select,
@@ -335,10 +335,13 @@ bool uvedit_face_select_set(struct Scene *scene,
}
}
-bool uvedit_face_select_enable(
- Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, const int cd_loop_uv_offset)
+bool uvedit_face_select_enable(const Scene *scene,
+ BMEditMesh *em,
+ BMFace *efa,
+ const bool do_history,
+ const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
BM_face_select_set(em->bm, efa, true);
@@ -362,12 +365,12 @@ bool uvedit_face_select_enable(
return false;
}
-bool uvedit_face_select_disable(Scene *scene,
+bool uvedit_face_select_disable(const Scene *scene,
BMEditMesh *em,
BMFace *efa,
const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
BM_face_select_set(em->bm, efa, false);
@@ -411,13 +414,13 @@ bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_
return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
}
}
-bool uvedit_edge_select_test(Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
{
return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
}
void uvedit_edge_select_set(BMEditMesh *em,
- Scene *scene,
+ const Scene *scene,
BMLoop *l,
const bool select,
const bool do_history,
@@ -432,11 +435,14 @@ void uvedit_edge_select_set(BMEditMesh *em,
}
}
-void uvedit_edge_select_enable(
- BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
+void uvedit_edge_select_enable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool do_history,
+ const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
@@ -466,12 +472,12 @@ void uvedit_edge_select_enable(
}
void uvedit_edge_select_disable(BMEditMesh *em,
- Scene *scene,
+ const Scene *scene,
BMLoop *l,
const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
@@ -511,13 +517,13 @@ bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_lo
return (luv->flag & MLOOPUV_VERTSEL) != 0;
}
}
-bool uvedit_uv_select_test(Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+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);
}
void uvedit_uv_select_set(BMEditMesh *em,
- Scene *scene,
+ const Scene *scene,
BMLoop *l,
const bool select,
const bool do_history,
@@ -531,10 +537,13 @@ void uvedit_uv_select_set(BMEditMesh *em,
}
}
-void uvedit_uv_select_enable(
- BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
+void uvedit_uv_select_enable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool do_history,
+ const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
@@ -554,9 +563,12 @@ void uvedit_uv_select_enable(
}
}
-void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+void uvedit_uv_select_disable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
@@ -618,7 +630,7 @@ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float as
}
}
-bool ED_uvedit_minmax_multi(Scene *scene,
+bool ED_uvedit_minmax_multi(const Scene *scene,
Image *ima,
Object **objects_edit,
uint objects_len,
@@ -656,7 +668,8 @@ bool ED_uvedit_minmax_multi(Scene *scene,
return changed;
}
-bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
+bool ED_uvedit_minmax(
+ const Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
{
return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max);
}
@@ -680,7 +693,7 @@ void ED_uvedit_select_all(BMesh *bm)
}
static bool ED_uvedit_median_multi(
- Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
+ const Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
{
unsigned int sel = 0;
zero_v2(co);
@@ -724,8 +737,12 @@ static bool UNUSED_FUNCTION(ED_uvedit_median)(Scene *scene,
return ED_uvedit_median_multi(scene, ima, &obedit, 1, co);
}
-bool ED_uvedit_center_multi(
- Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float cent[2], char mode)
+bool ED_uvedit_center_multi(const Scene *scene,
+ Image *ima,
+ Object **objects_edit,
+ uint objects_len,
+ float cent[2],
+ char mode)
{
bool changed = false;
@@ -745,7 +762,7 @@ bool ED_uvedit_center_multi(
return changed;
}
-bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode)
+bool ED_uvedit_center(const Scene *scene, Image *ima, Object *obedit, float cent[2], char mode)
{
return ED_uvedit_center_multi(scene, ima, &obedit, 1, cent, mode);
}
@@ -976,8 +993,12 @@ bool uv_find_nearest_vert_multi(Scene *scene,
return found;
}
-bool ED_uvedit_nearest_uv(
- Scene *scene, Object *obedit, Image *ima, const float co[2], float *dist_sq, float r_uv[2])
+bool ED_uvedit_nearest_uv(const Scene *scene,
+ Object *obedit,
+ Image *ima,
+ const float co[2],
+ float *dist_sq,
+ float r_uv[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMIter iter;
@@ -1011,7 +1032,7 @@ bool ED_uvedit_nearest_uv(
}
}
-bool ED_uvedit_nearest_uv_multi(Scene *scene,
+bool ED_uvedit_nearest_uv_multi(const Scene *scene,
Image *ima,
Object **objects,
const uint objects_len,
@@ -1286,7 +1307,7 @@ static void uv_select_linked_multi(Scene *scene,
vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
if (vmap == NULL) {
- return;
+ continue;
}
stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
@@ -1472,7 +1493,7 @@ static int uv_select_more_less(bContext *C, const bool select)
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
@@ -1639,7 +1660,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
float cent[2], min[2], max[2];
@@ -1952,7 +1973,7 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
const float threshold = RNA_float_get(op->ptr, "threshold");
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -2097,7 +2118,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
const float threshold = RNA_float_get(op->ptr, "threshold");
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -2271,7 +2292,7 @@ static void UV_OT_weld(wmOperatorType *ot)
static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -2316,7 +2337,7 @@ static bool uv_select_is_any_selected_multi(Scene *scene,
static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -2389,7 +2410,7 @@ static int uv_select_all_exec(bContext *C, wmOperator *op)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
Image *ima = CTX_data_edit_image(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -2470,7 +2491,7 @@ static int uv_mouse_select_multi(bContext *C,
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
Image *ima = CTX_data_edit_image(C);
BMFace *efa;
BMLoop *l;
@@ -2905,7 +2926,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
float limit[2];
@@ -3078,7 +3099,7 @@ static int uv_select_split_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
Image *ima = CTX_data_edit_image(C);
BMFace *efa;
@@ -3163,7 +3184,7 @@ static void UV_OT_select_split(wmOperatorType *ot)
ot->poll = ED_operator_uvedit; /* requires space image */
}
-static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short select)
+static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select)
{
/* bmesh API handles flushing but not on de-select */
if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -3278,7 +3299,7 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima,
* This only needs to be done when the Mesh is not used for
* selection (so for sticky modes, vertex or location based). */
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -3364,7 +3385,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima,
* This only needs to be done when the Mesh is not used for
* selection (so for sticky modes, vertex or location based). */
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -3443,7 +3464,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
@@ -3603,7 +3624,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
Image *ima = CTX_data_edit_image(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
ARegion *ar = CTX_wm_region(C);
BMFace *efa;
BMLoop *l;
@@ -3743,7 +3764,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
(ts->selectmode == SCE_SELECT_FACE) :
@@ -4119,7 +4140,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
const int target = RNA_enum_get(op->ptr, "target");
float offset[2] = {0};
@@ -4214,7 +4235,7 @@ static int uv_pin_exec(bContext *C, wmOperator *op)
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
const bool clear = RNA_boolean_get(op->ptr, "clear");
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -4291,7 +4312,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
BMFace *efa;
@@ -4622,7 +4643,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
SpaceImage *sima = CTX_wm_space_image(C);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -4745,7 +4766,7 @@ static int uv_reveal_exec(bContext *C, wmOperator *op)
SpaceImage *sima = CTX_wm_space_image(C);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -5098,7 +5119,7 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMFace *efa;
BMLoop *loop;
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index bb96b4ba10c..e4d73c2b229 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -2048,14 +2048,13 @@ static float p_collapse_cost(PEdge *edge, PEdge *pair)
float *co2 = e->next->next->vert->co;
if ((e->face != oldf1) && (e->face != oldf2)) {
- float tetrav2[3], tetrav3[3], c[3];
+ float tetrav2[3], tetrav3[3];
/* tetrahedron volume = (1/3!)*|a.(b x c)| */
sub_v3_v3v3(tetrav2, co1, oldv->co);
sub_v3_v3v3(tetrav3, co2, oldv->co);
- cross_v3_v3v3(c, tetrav2, tetrav3);
+ volumecost += fabsf(volume_tri_tetrahedron_signed_v3(tetrav2, tetrav3, edgevec));
- volumecost += fabsf(dot_v3v3(edgevec, c) / 6.0f);
# if 0
shapecost += dot_v3v3(co1, keepv->co);
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 5a8301fae67..5d3d016e6c1 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1935,10 +1935,10 @@ static StitchState *stitch_init(bContext *C,
/* 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, false, true, true);
+ 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, true, true, true);
+ state->element_map = BM_uv_element_map_create(state->em->bm, scene, true, false, true, true);
}
if (!state->element_map) {
state_delete(state);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 1db038bef94..1e758771f6a 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -75,7 +75,7 @@
#include "uvedit_intern.h"
#include "uvedit_parametrizer.h"
-static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subsurf)
+static void modifier_unwrap_state(Object *obedit, const Scene *scene, bool *r_use_subsurf)
{
ModifierData *md;
bool subsurf = (scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF) != 0;
@@ -95,56 +95,28 @@ static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subs
*r_use_subsurf = subsurf;
}
-static bool ED_uvedit_ensure_uvs(bContext *C, Scene *UNUSED(scene), Object *obedit)
+static bool ED_uvedit_ensure_uvs(Object *obedit)
{
+ if (ED_uvedit_test(obedit)) {
+ return 1;
+ }
+
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMIter iter;
- Image *ima;
- bScreen *sc;
- ScrArea *sa;
- SpaceLink *slink;
- SpaceImage *sima;
int cd_loop_uv_offset;
- if (ED_uvedit_test(obedit)) {
- return 1;
- }
-
if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
ED_mesh_uv_texture_add(obedit->data, NULL, true, true);
}
+ /* Happens when there are no faces. */
if (!ED_uvedit_test(obedit)) {
return 0;
}
cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- ima = CTX_data_edit_image(C);
-
- if (!ima) {
- /* no image in context in the 3d view, we find first image window .. */
- sc = CTX_wm_screen(C);
-
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- slink = sa->spacedata.first;
- if (slink->spacetype == SPACE_IMAGE) {
- sima = (SpaceImage *)slink;
-
- ima = sima->image;
- if (ima) {
- if (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE) {
- ima = NULL;
- }
- else {
- break;
- }
- }
- }
- }
- }
-
/* select new UV's (ignore UV_SYNC_SELECTION in this case) */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BMIter liter;
@@ -168,7 +140,7 @@ typedef struct UnwrapOptions {
bool correct_aspect; /* Correct for mapped image texture aspect ratio. */
} UnwrapOptions;
-static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, const UnwrapOptions *options)
+static bool uvedit_have_selection(const Scene *scene, BMEditMesh *em, const UnwrapOptions *options)
{
BMFace *efa;
BMLoop *l;
@@ -207,7 +179,7 @@ static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, const UnwrapOpti
return false;
}
-static bool uvedit_have_selection_multi(Scene *scene,
+static bool uvedit_have_selection_multi(const Scene *scene,
Object **objects,
const uint objects_len,
const UnwrapOptions *options)
@@ -224,7 +196,8 @@ static bool uvedit_have_selection_multi(Scene *scene,
return have_select;
}
-void ED_uvedit_get_aspect(Scene *UNUSED(scene), Object *ob, BMesh *bm, float *aspx, float *aspy)
+void ED_uvedit_get_aspect(
+ const Scene *UNUSED(scene), Object *ob, BMesh *bm, float *aspx, float *aspy)
{
bool sloppy = true;
bool selected = false;
@@ -244,8 +217,11 @@ void ED_uvedit_get_aspect(Scene *UNUSED(scene), Object *ob, BMesh *bm, float *as
}
}
-static void construct_param_handle_face_add(
- ParamHandle *handle, Scene *scene, BMFace *efa, int face_index, const int cd_loop_uv_offset)
+static void construct_param_handle_face_add(ParamHandle *handle,
+ const Scene *scene,
+ BMFace *efa,
+ int face_index,
+ const int cd_loop_uv_offset)
{
ParamKey key;
ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
@@ -276,7 +252,7 @@ static void construct_param_handle_face_add(
}
/* See: construct_param_handle_multi to handle multiple objects at once. */
-static ParamHandle *construct_param_handle(Scene *scene,
+static ParamHandle *construct_param_handle(const Scene *scene,
Object *ob,
BMesh *bm,
const UnwrapOptions *options)
@@ -348,7 +324,7 @@ static ParamHandle *construct_param_handle(Scene *scene,
/**
* Version of #construct_param_handle_single that handles multiple objects.
*/
-static ParamHandle *construct_param_handle_multi(Scene *scene,
+static ParamHandle *construct_param_handle_multi(const Scene *scene,
Object **objects,
const uint objects_len,
const UnwrapOptions *options)
@@ -437,7 +413,7 @@ static void texface_from_original_index(BMFace *efa,
float **uv,
ParamBool *pin,
ParamBool *select,
- Scene *scene,
+ const Scene *scene,
const int cd_loop_uv_offset)
{
BMLoop *l;
@@ -468,7 +444,7 @@ static void texface_from_original_index(BMFace *efa,
* The many modifications required to make the original function(see above)
* work justified the existence of a new function.
*/
-static ParamHandle *construct_param_handle_subsurfed(Scene *scene,
+static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
Object *ob,
BMEditMesh *em,
const UnwrapOptions *options)
@@ -656,7 +632,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene,
/* ******************** Minimize Stretch operator **************** */
typedef struct MinStretch {
- Scene *scene;
+ const Scene *scene;
Object **objects_edit;
uint objects_len;
ParamHandle *handle;
@@ -668,7 +644,7 @@ typedef struct MinStretch {
static bool minimize_stretch_init(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
const UnwrapOptions options = {
@@ -711,7 +687,7 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
{
MinStretch *ms = op->customdata;
ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -752,7 +728,7 @@ static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
{
MinStretch *ms = op->customdata;
ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -928,7 +904,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/* ******************** Pack Islands operator **************** */
-static void uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm)
+static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm)
{
const UnwrapOptions options = {
.topology_from_uvs = true,
@@ -947,7 +923,7 @@ static void uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm)
param_delete(handle);
}
-static void uvedit_pack_islands_multi(Scene *scene,
+static void uvedit_pack_islands_multi(const Scene *scene,
Object **objects,
const uint objects_len,
const UnwrapOptions *options,
@@ -970,7 +946,7 @@ static void uvedit_pack_islands_multi(Scene *scene,
static int pack_islands_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
const UnwrapOptions options = {
.topology_from_uvs = true,
@@ -1028,7 +1004,7 @@ void UV_OT_pack_islands(wmOperatorType *ot)
static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -1200,8 +1176,12 @@ static void uv_map_transform_calc_center_median(BMEditMesh *em, float r_center[3
mul_v3_fl(r_center, 1.0f / (float)center_accum_num);
}
-static void uv_map_transform_center(
- Scene *scene, View3D *v3d, Object *ob, BMEditMesh *em, float r_center[3], float r_bounds[2][3])
+static void uv_map_transform_center(const Scene *scene,
+ View3D *v3d,
+ Object *ob,
+ BMEditMesh *em,
+ float r_center[3],
+ float r_bounds[2][3])
{
/* only operates on the edit object - this is all that's needed now */
const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS;
@@ -1395,7 +1375,7 @@ static void uv_transform_properties(wmOperatorType *ot, int radius)
}
}
-static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em)
+static void correct_uv_aspect(const Scene *scene, Object *ob, BMEditMesh *em)
{
BMLoop *l;
BMIter iter, liter;
@@ -1462,7 +1442,7 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
"Scale UV coordinates to bounds after unwrapping");
}
-static void uv_map_clip_correct_multi(Scene *scene,
+static void uv_map_clip_correct_multi(const Scene *scene,
Object **objects,
uint objects_len,
wmOperator *op)
@@ -1552,7 +1532,7 @@ static void uv_map_clip_correct_multi(Scene *scene,
}
}
-static void uv_map_clip_correct(Scene *scene, Object *ob, wmOperator *op)
+static void uv_map_clip_correct(const Scene *scene, Object *ob, wmOperator *op)
{
uv_map_clip_correct_multi(scene, &ob, 1, op);
}
@@ -1560,7 +1540,7 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, wmOperator *op)
/* ******************** Unwrap operator **************** */
/* Assumes UV Map exists, doesn't run update funcs. */
-static void uvedit_unwrap(Scene *scene, Object *obedit, const UnwrapOptions *options)
+static void uvedit_unwrap(const Scene *scene, Object *obedit, const UnwrapOptions *options)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
@@ -1589,7 +1569,7 @@ static void uvedit_unwrap(Scene *scene, Object *obedit, const UnwrapOptions *opt
param_delete(handle);
}
-static void uvedit_unwrap_multi(Scene *scene,
+static void uvedit_unwrap_multi(const Scene *scene,
Object **objects,
const int objects_len,
const UnwrapOptions *options)
@@ -1602,7 +1582,7 @@ static void uvedit_unwrap_multi(Scene *scene,
}
}
-void ED_uvedit_live_unwrap(Scene *scene, Object **objects, int objects_len)
+void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len)
{
if (scene->toolsettings->edge_mode_live_unwrap) {
const UnwrapOptions options = {
@@ -1628,7 +1608,7 @@ enum {
static int unwrap_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
int method = RNA_enum_get(op->ptr, "method");
const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
int reported_errors = 0;
@@ -1661,7 +1641,7 @@ static int unwrap_exec(bContext *C, wmOperator *op)
float obsize[3];
bool use_subsurf_final;
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -1823,7 +1803,7 @@ static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
static int uv_from_view_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -1861,7 +1841,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
bool changed = false;
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -1987,7 +1967,6 @@ void UV_OT_project_from_view(wmOperatorType *ot)
static int reset_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -2004,7 +1983,7 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op))
}
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -2087,7 +2066,7 @@ static void uv_map_mirror(BMEditMesh *em, BMFace *efa)
static int sphere_project_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -2107,7 +2086,7 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
}
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -2181,7 +2160,7 @@ static void uv_cylinder_project(float target[2],
static int cylinder_project_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -2201,7 +2180,7 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
}
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -2298,7 +2277,7 @@ static void uvedit_unwrap_cube_project(BMesh *bm,
static int cube_project_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size");
@@ -2317,7 +2296,7 @@ static int cube_project_exec(bContext *C, wmOperator *op)
}
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -2384,7 +2363,7 @@ void UV_OT_cube_project(wmOperatorType *ot)
/************************* Simple UVs for texture painting *****************/
-void ED_uvedit_add_simple_uvs(Main *bmain, Scene *scene, Object *ob)
+void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
{
Mesh *me = ob->data;
bool sync_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
diff --git a/source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.cpp b/source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.cpp
index ee207e06b35..a631b45f6d4 100644
--- a/source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.cpp
@@ -139,11 +139,7 @@ static PyObject *BinaryPredicate0D_name_get(BPy_BinaryPredicate0D *self, void *U
}
static PyGetSetDef BPy_BinaryPredicate0D_getseters[] = {
- {(char *)"name",
- (getter)BinaryPredicate0D_name_get,
- (setter)NULL,
- (char *)BinaryPredicate0D_name_doc,
- NULL},
+ {"name", (getter)BinaryPredicate0D_name_get, (setter)NULL, BinaryPredicate0D_name_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.cpp b/source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.cpp
index 647b5522d35..9add706bea7 100644
--- a/source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.cpp
@@ -175,11 +175,7 @@ static PyObject *BinaryPredicate1D_name_get(BPy_BinaryPredicate1D *self, void *U
}
static PyGetSetDef BPy_BinaryPredicate1D_getseters[] = {
- {(char *)"name",
- (getter)BinaryPredicate1D_name_get,
- (setter)NULL,
- (char *)BinaryPredicate1D_name_doc,
- NULL},
+ {"name", (getter)BinaryPredicate1D_name_get, (setter)NULL, BinaryPredicate1D_name_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
index 367ad556d02..a6512a64776 100644
--- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -266,8 +266,8 @@ static PyObject *Freestyle_evaluateCurveMappingF(PyObject * /*self*/, PyObject *
cumap = (CurveMapping *)py_srna->ptr.data;
BKE_curvemapping_initialize(cumap);
/* disable extrapolation if enabled */
- if ((cumap->cm[cur].flag & CUMA_EXTEND_EXTRAPOLATE)) {
- cumap->cm[cur].flag &= ~(CUMA_EXTEND_EXTRAPOLATE);
+ if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE)) {
+ cumap->flag &= ~(CUMA_EXTEND_EXTRAPOLATE);
BKE_curvemapping_changed(cumap, 0);
}
return PyFloat_FromDouble(BKE_curvemapping_evaluateF(cumap, cur, value));
diff --git a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
index 7a5469cd414..2c226e330d7 100644
--- a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
+++ b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
@@ -459,40 +459,40 @@ static int FrsMaterial_priority_set(BPy_FrsMaterial *self, PyObject *value, void
}
static PyGetSetDef BPy_FrsMaterial_getseters[] = {
- {(char *)"line",
+ {"line",
(getter)FrsMaterial_line_get,
(setter)FrsMaterial_line_set,
- (char *)FrsMaterial_line_doc,
+ FrsMaterial_line_doc,
NULL},
- {(char *)"diffuse",
+ {"diffuse",
(getter)FrsMaterial_diffuse_get,
(setter)FrsMaterial_diffuse_set,
- (char *)FrsMaterial_diffuse_doc,
+ FrsMaterial_diffuse_doc,
NULL},
- {(char *)"specular",
+ {"specular",
(getter)FrsMaterial_specular_get,
(setter)FrsMaterial_specular_set,
- (char *)FrsMaterial_specular_doc,
+ FrsMaterial_specular_doc,
NULL},
- {(char *)"ambient",
+ {"ambient",
(getter)FrsMaterial_ambient_get,
(setter)FrsMaterial_ambient_set,
- (char *)FrsMaterial_ambient_doc,
+ FrsMaterial_ambient_doc,
NULL},
- {(char *)"emission",
+ {"emission",
(getter)FrsMaterial_emission_get,
(setter)FrsMaterial_emission_set,
- (char *)FrsMaterial_emission_doc,
+ FrsMaterial_emission_doc,
NULL},
- {(char *)"shininess",
+ {"shininess",
(getter)FrsMaterial_shininess_get,
(setter)FrsMaterial_shininess_set,
- (char *)FrsMaterial_shininess_doc,
+ FrsMaterial_shininess_doc,
NULL},
- {(char *)"priority",
+ {"priority",
(getter)FrsMaterial_priority_get,
(setter)FrsMaterial_priority_set,
- (char *)FrsMaterial_priority_doc,
+ FrsMaterial_priority_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_Id.cpp b/source/blender/freestyle/intern/python/BPy_Id.cpp
index 2c50767c5aa..4f61ba847f6 100644
--- a/source/blender/freestyle/intern/python/BPy_Id.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Id.cpp
@@ -162,8 +162,8 @@ static int Id_second_set(BPy_Id *self, PyObject *value, void *UNUSED(closure))
}
static PyGetSetDef BPy_Id_getseters[] = {
- {(char *)"first", (getter)Id_first_get, (setter)Id_first_set, (char *)Id_first_doc, NULL},
- {(char *)"second", (getter)Id_second_get, (setter)Id_second_set, (char *)Id_second_doc, NULL},
+ {"first", (getter)Id_first_get, (setter)Id_first_set, Id_first_doc, NULL},
+ {"second", (getter)Id_second_get, (setter)Id_second_set, Id_second_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_Interface0D.cpp b/source/blender/freestyle/intern/python/BPy_Interface0D.cpp
index 40e5267460b..628a9d43b6c 100644
--- a/source/blender/freestyle/intern/python/BPy_Interface0D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Interface0D.cpp
@@ -275,42 +275,26 @@ static PyObject *Interface0D_nature_get(BPy_Interface0D *self, void *UNUSED(clos
}
static PyGetSetDef BPy_Interface0D_getseters[] = {
- {(char *)"name",
- (getter)Interface0D_name_get,
- (setter)NULL,
- (char *)Interface0D_name_doc,
- NULL},
- {(char *)"point_3d",
- (getter)Interface0D_point_3d_get,
- (setter)NULL,
- (char *)Interface0D_point_3d_doc,
- NULL},
- {(char *)"projected_x",
+ {"name", (getter)Interface0D_name_get, (setter)NULL, Interface0D_name_doc, NULL},
+ {"point_3d", (getter)Interface0D_point_3d_get, (setter)NULL, Interface0D_point_3d_doc, NULL},
+ {"projected_x",
(getter)Interface0D_projected_x_get,
(setter)NULL,
- (char *)Interface0D_projected_x_doc,
+ Interface0D_projected_x_doc,
NULL},
- {(char *)"projected_y",
+ {"projected_y",
(getter)Interface0D_projected_y_get,
(setter)NULL,
- (char *)Interface0D_projected_y_doc,
+ Interface0D_projected_y_doc,
NULL},
- {(char *)"projected_z",
+ {"projected_z",
(getter)Interface0D_projected_z_get,
(setter)NULL,
- (char *)Interface0D_projected_z_doc,
- NULL},
- {(char *)"point_2d",
- (getter)Interface0D_point_2d_get,
- (setter)NULL,
- (char *)Interface0D_point_2d_doc,
- NULL},
- {(char *)"id", (getter)Interface0D_id_get, (setter)NULL, (char *)Interface0D_id_doc, NULL},
- {(char *)"nature",
- (getter)Interface0D_nature_get,
- (setter)NULL,
- (char *)Interface0D_nature_doc,
+ Interface0D_projected_z_doc,
NULL},
+ {"point_2d", (getter)Interface0D_point_2d_get, (setter)NULL, Interface0D_point_2d_doc, NULL},
+ {"id", (getter)Interface0D_id_get, (setter)NULL, Interface0D_id_doc, NULL},
+ {"nature", (getter)Interface0D_nature_get, (setter)NULL, Interface0D_nature_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_Interface1D.cpp b/source/blender/freestyle/intern/python/BPy_Interface1D.cpp
index ca14a473216..af1f8d2d549 100644
--- a/source/blender/freestyle/intern/python/BPy_Interface1D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Interface1D.cpp
@@ -318,26 +318,18 @@ static int Interface1D_time_stamp_set(BPy_Interface1D *self,
}
static PyGetSetDef BPy_Interface1D_getseters[] = {
- {(char *)"name",
- (getter)Interface1D_name_get,
- (setter)NULL,
- (char *)Interface1D_name_doc,
- NULL},
- {(char *)"id", (getter)Interface1D_id_get, (setter)NULL, (char *)Interface1D_id_doc, NULL},
- {(char *)"nature",
- (getter)Interface1D_nature_get,
- (setter)NULL,
- (char *)Interface1D_nature_doc,
- NULL},
- {(char *)"length_2d",
+ {"name", (getter)Interface1D_name_get, (setter)NULL, Interface1D_name_doc, NULL},
+ {"id", (getter)Interface1D_id_get, (setter)NULL, Interface1D_id_doc, NULL},
+ {"nature", (getter)Interface1D_nature_get, (setter)NULL, Interface1D_nature_doc, NULL},
+ {"length_2d",
(getter)Interface1D_length_2d_get,
(setter)NULL,
- (char *)Interface1D_length_2d_doc,
+ Interface1D_length_2d_doc,
NULL},
- {(char *)"time_stamp",
+ {"time_stamp",
(getter)Interface1D_time_stamp_get,
(setter)Interface1D_time_stamp_set,
- (char *)Interface1D_time_stamp_doc,
+ Interface1D_time_stamp_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_Iterator.cpp b/source/blender/freestyle/intern/python/BPy_Iterator.cpp
index d2575b3b5e9..daa2bdbef81 100644
--- a/source/blender/freestyle/intern/python/BPy_Iterator.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Iterator.cpp
@@ -217,17 +217,9 @@ static PyObject *Iterator_is_end_get(BPy_Iterator *self, void *UNUSED(closure))
}
static PyGetSetDef BPy_Iterator_getseters[] = {
- {(char *)"name", (getter)Iterator_name_get, (setter)NULL, (char *)Iterator_name_doc, NULL},
- {(char *)"is_begin",
- (getter)Iterator_is_begin_get,
- (setter)NULL,
- (char *)Iterator_is_begin_doc,
- NULL},
- {(char *)"is_end",
- (getter)Iterator_is_end_get,
- (setter)NULL,
- (char *)Iterator_is_end_doc,
- NULL},
+ {"name", (getter)Iterator_name_get, (setter)NULL, Iterator_name_doc, NULL},
+ {"is_begin", (getter)Iterator_is_begin_get, (setter)NULL, Iterator_is_begin_doc, NULL},
+ {"is_end", (getter)Iterator_is_end_get, (setter)NULL, Iterator_is_end_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_SShape.cpp b/source/blender/freestyle/intern/python/BPy_SShape.cpp
index d007fead345..d4b5f426a8b 100644
--- a/source/blender/freestyle/intern/python/BPy_SShape.cpp
+++ b/source/blender/freestyle/intern/python/BPy_SShape.cpp
@@ -268,23 +268,11 @@ static PyObject *SShape_edges_get(BPy_SShape *self, void *UNUSED(closure))
}
static PyGetSetDef BPy_SShape_getseters[] = {
- {(char *)"id", (getter)SShape_id_get, (setter)SShape_id_set, (char *)SShape_id_doc, NULL},
- {(char *)"name",
- (getter)SShape_name_get,
- (setter)SShape_name_set,
- (char *)SShape_name_doc,
- NULL},
- {(char *)"bbox",
- (getter)SShape_bbox_get,
- (setter)SShape_bbox_set,
- (char *)SShape_bbox_doc,
- NULL},
- {(char *)"edges", (getter)SShape_edges_get, (setter)NULL, (char *)SShape_edges_doc, NULL},
- {(char *)"vertices",
- (getter)SShape_vertices_get,
- (setter)NULL,
- (char *)SShape_vertices_doc,
- NULL},
+ {"id", (getter)SShape_id_get, (setter)SShape_id_set, SShape_id_doc, NULL},
+ {"name", (getter)SShape_name_get, (setter)SShape_name_set, SShape_name_doc, NULL},
+ {"bbox", (getter)SShape_bbox_get, (setter)SShape_bbox_set, SShape_bbox_doc, NULL},
+ {"edges", (getter)SShape_edges_get, (setter)NULL, SShape_edges_doc, NULL},
+ {"vertices", (getter)SShape_vertices_get, (setter)NULL, SShape_vertices_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
index e3d6738058e..5f5407e82e3 100644
--- a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
+++ b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
@@ -657,25 +657,25 @@ static int StrokeAttribute_visible_set(BPy_StrokeAttribute *self,
}
static PyGetSetDef BPy_StrokeAttribute_getseters[] = {
- {(char *)"alpha",
+ {"alpha",
(getter)StrokeAttribute_alpha_get,
(setter)StrokeAttribute_alpha_set,
- (char *)StrokeAttribute_alpha_doc,
+ StrokeAttribute_alpha_doc,
NULL},
- {(char *)"color",
+ {"color",
(getter)StrokeAttribute_color_get,
(setter)StrokeAttribute_color_set,
- (char *)StrokeAttribute_color_doc,
+ StrokeAttribute_color_doc,
NULL},
- {(char *)"thickness",
+ {"thickness",
(getter)StrokeAttribute_thickness_get,
(setter)StrokeAttribute_thickness_set,
- (char *)StrokeAttribute_thickness_doc,
+ StrokeAttribute_thickness_doc,
NULL},
- {(char *)"visible",
+ {"visible",
(getter)StrokeAttribute_visible_get,
(setter)StrokeAttribute_visible_set,
- (char *)StrokeAttribute_visible_doc,
+ StrokeAttribute_visible_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp b/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp
index baeb8cc4994..993afc2e32e 100644
--- a/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp
+++ b/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp
@@ -273,11 +273,7 @@ static PyObject *StrokeShader_name_get(BPy_StrokeShader *self, void *UNUSED(clos
}
static PyGetSetDef BPy_StrokeShader_getseters[] = {
- {(char *)"name",
- (getter)StrokeShader_name_get,
- (setter)NULL,
- (char *)StrokeShader_name_doc,
- NULL},
+ {"name", (getter)StrokeShader_name_get, (setter)NULL, StrokeShader_name_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
index 81e72c2c7f2..6214ea94f41 100644
--- a/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
@@ -109,11 +109,7 @@ static PyObject *UnaryFunction0D_name_get(BPy_UnaryFunction0D *self, void *UNUSE
}
static PyGetSetDef BPy_UnaryFunction0D_getseters[] = {
- {(char *)"name",
- (getter)UnaryFunction0D_name_get,
- (setter)NULL,
- (char *)UnaryFunction0D_name_doc,
- NULL},
+ {"name", (getter)UnaryFunction0D_name_get, (setter)NULL, UnaryFunction0D_name_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
index b2bd6e657fe..18d6479a498 100644
--- a/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
@@ -103,11 +103,7 @@ static PyObject *UnaryFunction1D_name_get(BPy_UnaryFunction1D *self, void *UNUSE
}
static PyGetSetDef BPy_UnaryFunction1D_getseters[] = {
- {(char *)"name",
- (getter)UnaryFunction1D_name_get,
- (setter)NULL,
- (char *)UnaryFunction1D_name_doc,
- NULL},
+ {"name", (getter)UnaryFunction1D_name_get, (setter)NULL, UnaryFunction1D_name_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.cpp
index f4f1205bb09..3d4191c2c44 100644
--- a/source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.cpp
@@ -154,11 +154,7 @@ static PyObject *UnaryPredicate0D_name_get(BPy_UnaryPredicate0D *self, void *UNU
}
static PyGetSetDef BPy_UnaryPredicate0D_getseters[] = {
- {(char *)"name",
- (getter)UnaryPredicate0D_name_get,
- (setter)NULL,
- (char *)UnaryPredicate0D_name_doc,
- NULL},
+ {"name", (getter)UnaryPredicate0D_name_get, (setter)NULL, UnaryPredicate0D_name_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.cpp
index 8bdd9823140..ba68d21f941 100644
--- a/source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.cpp
@@ -212,11 +212,7 @@ static PyObject *UnaryPredicate1D_name_get(BPy_UnaryPredicate1D *self, void *UNU
}
static PyGetSetDef BPy_UnaryPredicate1D_getseters[] = {
- {(char *)"name",
- (getter)UnaryPredicate1D_name_get,
- (setter)NULL,
- (char *)UnaryPredicate1D_name_doc,
- NULL},
+ {"name", (getter)UnaryPredicate1D_name_get, (setter)NULL, UnaryPredicate1D_name_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_ViewMap.cpp b/source/blender/freestyle/intern/python/BPy_ViewMap.cpp
index b6ca377fb40..1f162997c44 100644
--- a/source/blender/freestyle/intern/python/BPy_ViewMap.cpp
+++ b/source/blender/freestyle/intern/python/BPy_ViewMap.cpp
@@ -171,10 +171,10 @@ static int ViewMap_scene_bbox_set(BPy_ViewMap *self, PyObject *value, void *UNUS
}
static PyGetSetDef BPy_ViewMap_getseters[] = {
- {(char *)"scene_bbox",
+ {"scene_bbox",
(getter)ViewMap_scene_bbox_get,
(setter)ViewMap_scene_bbox_set,
- (char *)ViewMap_scene_bbox_doc,
+ ViewMap_scene_bbox_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
index 79eeba17529..c08e7eea7b9 100644
--- a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
+++ b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
@@ -326,28 +326,24 @@ static PyObject *ViewShape_id_get(BPy_ViewShape *self, void *UNUSED(closure))
}
static PyGetSetDef BPy_ViewShape_getseters[] = {
- {(char *)"sshape",
+ {"sshape",
(getter)ViewShape_sshape_get,
(setter)ViewShape_sshape_set,
- (char *)ViewShape_sshape_doc,
+ ViewShape_sshape_doc,
NULL},
- {(char *)"vertices",
+ {"vertices",
(getter)ViewShape_vertices_get,
(setter)ViewShape_vertices_set,
- (char *)ViewShape_vertices_doc,
+ ViewShape_vertices_doc,
NULL},
- {(char *)"edges",
- (getter)ViewShape_edges_get,
- (setter)ViewShape_edges_set,
- (char *)ViewShape_edges_doc,
- NULL},
- {(char *)"name", (getter)ViewShape_name_get, (setter)NULL, (char *)ViewShape_name_doc, NULL},
- {(char *)"library_path",
+ {"edges", (getter)ViewShape_edges_get, (setter)ViewShape_edges_set, ViewShape_edges_doc, NULL},
+ {"name", (getter)ViewShape_name_get, (setter)NULL, ViewShape_name_doc, NULL},
+ {"library_path",
(getter)ViewShape_library_path_get,
(setter)NULL,
- (char *)ViewShape_library_path_doc,
+ ViewShape_library_path_doc,
NULL},
- {(char *)"id", (getter)ViewShape_id_get, (setter)NULL, (char *)ViewShape_id_doc, NULL},
+ {"id", (getter)ViewShape_id_get, (setter)NULL, ViewShape_id_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
index 49cd98376c5..6af80c4bfd9 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
@@ -233,22 +233,18 @@ static int CurvePoint_t2d_set(BPy_CurvePoint *self, PyObject *value, void *UNUSE
}
static PyGetSetDef BPy_CurvePoint_getseters[] = {
- {(char *)"first_svertex",
+ {"first_svertex",
(getter)CurvePoint_first_svertex_get,
(setter)CurvePoint_first_svertex_set,
- (char *)CurvePoint_first_svertex_doc,
+ CurvePoint_first_svertex_doc,
NULL},
- {(char *)"second_svertex",
+ {"second_svertex",
(getter)CurvePoint_second_svertex_get,
(setter)CurvePoint_second_svertex_set,
- (char *)CurvePoint_second_svertex_doc,
- NULL},
- {(char *)"fedge", (getter)CurvePoint_fedge_get, NULL, CurvePoint_fedge_doc, NULL},
- {(char *)"t2d",
- (getter)CurvePoint_t2d_get,
- (setter)CurvePoint_t2d_set,
- (char *)CurvePoint_t2d_doc,
+ CurvePoint_second_svertex_doc,
NULL},
+ {"fedge", (getter)CurvePoint_fedge_get, NULL, CurvePoint_fedge_doc, NULL},
+ {"t2d", (getter)CurvePoint_t2d_get, (setter)CurvePoint_t2d_set, CurvePoint_t2d_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
index 08ad378ab75..71a87c2c01e 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
@@ -424,37 +424,25 @@ static PyObject *SVertex_curvatures_get(BPy_SVertex *self, void *UNUSED(closure)
}
static PyGetSetDef BPy_SVertex_getseters[] = {
- {(char *)"point_3d",
+ {"point_3d",
(getter)SVertex_point_3d_get,
(setter)SVertex_point_3d_set,
- (char *)SVertex_point_3d_doc,
+ SVertex_point_3d_doc,
NULL},
- {(char *)"point_2d",
+ {"point_2d",
(getter)SVertex_point_2d_get,
(setter)SVertex_point_2d_set,
- (char *)SVertex_point_2d_doc,
+ SVertex_point_2d_doc,
NULL},
- {(char *)"id", (getter)SVertex_id_get, (setter)SVertex_id_set, (char *)SVertex_id_doc, NULL},
- {(char *)"normals",
- (getter)SVertex_normals_get,
- (setter)NULL,
- (char *)SVertex_normals_doc,
- NULL},
- {(char *)"normals_size",
+ {"id", (getter)SVertex_id_get, (setter)SVertex_id_set, SVertex_id_doc, NULL},
+ {"normals", (getter)SVertex_normals_get, (setter)NULL, SVertex_normals_doc, NULL},
+ {"normals_size",
(getter)SVertex_normals_size_get,
(setter)NULL,
- (char *)SVertex_normals_size_doc,
- NULL},
- {(char *)"viewvertex",
- (getter)SVertex_viewvertex_get,
- (setter)NULL,
- (char *)SVertex_viewvertex_doc,
- NULL},
- {(char *)"curvatures",
- (getter)SVertex_curvatures_get,
- (setter)NULL,
- (char *)SVertex_curvatures_doc,
+ SVertex_normals_size_doc,
NULL},
+ {"viewvertex", (getter)SVertex_viewvertex_get, (setter)NULL, SVertex_viewvertex_doc, NULL},
+ {"curvatures", (getter)SVertex_curvatures_get, (setter)NULL, SVertex_curvatures_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
index 29bba040316..5ddb8a605ff 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
@@ -150,10 +150,10 @@ static int ViewVertex_nature_set(BPy_ViewVertex *self, PyObject *value, void *UN
}
static PyGetSetDef BPy_ViewVertex_getseters[] = {
- {(char *)"nature",
+ {"nature",
(getter)ViewVertex_nature_get,
(setter)ViewVertex_nature_set,
- (char *)ViewVertex_nature_doc,
+ ViewVertex_nature_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
index 74d8fe4ce60..07373c91726 100644
--- a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
@@ -348,27 +348,27 @@ static PyObject *StrokeVertex_u_get(BPy_StrokeVertex *self, void *UNUSED(closure
}
static PyGetSetDef BPy_StrokeVertex_getseters[] = {
- {(char *)"attribute",
+ {"attribute",
(getter)StrokeVertex_attribute_get,
(setter)StrokeVertex_attribute_set,
- (char *)StrokeVertex_attribute_doc,
+ StrokeVertex_attribute_doc,
NULL},
- {(char *)"curvilinear_abscissa",
+ {"curvilinear_abscissa",
(getter)StrokeVertex_curvilinear_abscissa_get,
(setter)StrokeVertex_curvilinear_abscissa_set,
- (char *)StrokeVertex_curvilinear_abscissa_doc,
+ StrokeVertex_curvilinear_abscissa_doc,
NULL},
- {(char *)"point",
+ {"point",
(getter)StrokeVertex_point_get,
(setter)StrokeVertex_point_set,
- (char *)StrokeVertex_point_doc,
+ StrokeVertex_point_doc,
NULL},
- {(char *)"stroke_length",
+ {"stroke_length",
(getter)StrokeVertex_stroke_length_get,
(setter)StrokeVertex_stroke_length_set,
- (char *)StrokeVertex_stroke_length_doc,
+ StrokeVertex_stroke_length_doc,
NULL},
- {(char *)"u", (getter)StrokeVertex_u_get, (setter)NULL, (char *)StrokeVertex_u_doc, NULL},
+ {"u", (getter)StrokeVertex_u_get, (setter)NULL, StrokeVertex_u_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp
index 315c0b16061..9295e4f424b 100644
--- a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp
@@ -97,10 +97,10 @@ static int NonTVertex_svertex_set(BPy_NonTVertex *self, PyObject *value, void *U
}
static PyGetSetDef BPy_NonTVertex_getseters[] = {
- {(char *)"svertex",
+ {"svertex",
(getter)NonTVertex_svertex_get,
(setter)NonTVertex_svertex_set,
- (char *)NonTVertex_svertex_doc,
+ NonTVertex_svertex_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp
index 7b23fdb04f1..8fa48e54b55 100644
--- a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp
@@ -199,17 +199,17 @@ static int TVertex_id_set(BPy_TVertex *self, PyObject *value, void *UNUSED(closu
}
static PyGetSetDef BPy_TVertex_getseters[] = {
- {(char *)"front_svertex",
+ {"front_svertex",
(getter)TVertex_front_svertex_get,
(setter)TVertex_front_svertex_set,
- (char *)TVertex_front_svertex_doc,
+ TVertex_front_svertex_doc,
NULL},
- {(char *)"back_svertex",
+ {"back_svertex",
(getter)TVertex_back_svertex_get,
(setter)TVertex_back_svertex_set,
- (char *)TVertex_back_svertex_doc,
+ TVertex_back_svertex_doc,
NULL},
- {(char *)"id", (getter)TVertex_id_get, (setter)TVertex_id_set, (char *)TVertex_id_doc, NULL},
+ {"id", (getter)TVertex_id_get, (setter)TVertex_id_set, TVertex_id_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
index 070e54c9305..adbf01cd777 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
@@ -323,42 +323,34 @@ static int FEdge_nature_set(BPy_FEdge *self, PyObject *value, void *UNUSED(closu
}
static PyGetSetDef BPy_FEdge_getseters[] = {
- {(char *)"first_svertex",
+ {"first_svertex",
(getter)FEdge_first_svertex_get,
(setter)FEdge_first_svertex_set,
- (char *)FEdge_first_svertex_doc,
+ FEdge_first_svertex_doc,
NULL},
- {(char *)"second_svertex",
+ {"second_svertex",
(getter)FEdge_second_svertex_get,
(setter)FEdge_second_svertex_set,
- (char *)FEdge_second_svertex_doc,
+ FEdge_second_svertex_doc,
NULL},
- {(char *)"next_fedge",
+ {"next_fedge",
(getter)FEdge_next_fedge_get,
(setter)FEdge_next_fedge_set,
- (char *)FEdge_next_fedge_doc,
+ FEdge_next_fedge_doc,
NULL},
- {(char *)"previous_fedge",
+ {"previous_fedge",
(getter)FEdge_previous_fedge_get,
(setter)FEdge_previous_fedge_set,
- (char *)FEdge_previous_fedge_doc,
+ FEdge_previous_fedge_doc,
NULL},
- {(char *)"viewedge",
- (getter)FEdge_viewedge_get,
- (setter)FEdge_viewedge_set,
- (char *)FEdge_viewedge_doc,
- NULL},
- {(char *)"is_smooth",
+ {"viewedge", (getter)FEdge_viewedge_get, (setter)FEdge_viewedge_set, FEdge_viewedge_doc, NULL},
+ {"is_smooth",
(getter)FEdge_is_smooth_get,
(setter)FEdge_is_smooth_set,
- (char *)FEdge_is_smooth_doc,
- NULL},
- {(char *)"id", (getter)FEdge_id_get, (setter)FEdge_id_set, (char *)FEdge_id_doc, NULL},
- {(char *)"nature",
- (getter)FEdge_nature_get,
- (setter)FEdge_nature_set,
- (char *)FEdge_nature_doc,
+ FEdge_is_smooth_doc,
NULL},
+ {"id", (getter)FEdge_id_get, (setter)FEdge_id_set, FEdge_id_doc, NULL},
+ {"nature", (getter)FEdge_nature_get, (setter)FEdge_nature_set, FEdge_nature_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
index 932911fb6e6..fd434f9c4ef 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
@@ -180,15 +180,11 @@ static PyObject *FrsCurve_segments_size_get(BPy_FrsCurve *self, void *UNUSED(clo
}
static PyGetSetDef BPy_FrsCurve_getseters[] = {
- {(char *)"is_empty",
- (getter)FrsCurve_is_empty_get,
- (setter)NULL,
- (char *)FrsCurve_is_empty_doc,
- NULL},
- {(char *)"segments_size",
+ {"is_empty", (getter)FrsCurve_is_empty_get, (setter)NULL, FrsCurve_is_empty_doc, NULL},
+ {"segments_size",
(getter)FrsCurve_segments_size_get,
(setter)NULL,
- (char *)FrsCurve_segments_size_doc,
+ FrsCurve_segments_size_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
index df80f61a7a6..444a69adf30 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
@@ -466,27 +466,23 @@ static int Stroke_id_set(BPy_Stroke *self, PyObject *value, void *UNUSED(closure
}
static PyGetSetDef BPy_Stroke_getseters[] = {
- {(char *)"medium_type",
+ {"medium_type",
(getter)Stroke_medium_type_get,
(setter)Stroke_medium_type_set,
- (char *)Stroke_medium_type_doc,
+ Stroke_medium_type_doc,
NULL},
- {(char *)"texture_id",
+ {"texture_id",
(getter)Stroke_texture_id_get,
(setter)Stroke_texture_id_set,
- (char *)Stroke_texture_id_doc,
+ Stroke_texture_id_doc,
NULL},
- {(char *)"tips",
- (getter)Stroke_tips_get,
- (setter)Stroke_tips_set,
- (char *)Stroke_tips_doc,
- NULL},
- {(char *)"length_2d",
+ {"tips", (getter)Stroke_tips_get, (setter)Stroke_tips_set, Stroke_tips_doc, NULL},
+ {"length_2d",
(getter)Stroke_length_2d_get,
(setter)Stroke_length_2d_set,
- (char *)Stroke_length_2d_doc,
+ Stroke_length_2d_doc,
NULL},
- {(char *)"id", (getter)Stroke_id_get, (setter)Stroke_id_set, (char *)Stroke_id_doc, NULL},
+ {"id", (getter)Stroke_id_get, (setter)Stroke_id_set, Stroke_id_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp
index 208d6cbfd6d..0570d9790ab 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp
@@ -331,60 +331,48 @@ static int ViewEdge_chaining_time_stamp_set(BPy_ViewEdge *self,
}
static PyGetSetDef BPy_ViewEdge_getseters[] = {
- {(char *)"first_viewvertex",
+ {"first_viewvertex",
(getter)ViewEdge_first_viewvertex_get,
(setter)ViewEdge_first_viewvertex_set,
- (char *)ViewEdge_first_viewvertex_doc,
+ ViewEdge_first_viewvertex_doc,
NULL},
- {(char *)"last_viewvertex",
+ {"last_viewvertex",
(getter)ViewEdge_last_viewvertex_get,
(setter)ViewEdge_last_viewvertex_set,
- (char *)ViewEdge_last_viewvertex_doc,
+ ViewEdge_last_viewvertex_doc,
NULL},
- {(char *)"first_fedge",
+ {"first_fedge",
(getter)ViewEdge_first_fedge_get,
(setter)ViewEdge_first_fedge_set,
- (char *)ViewEdge_first_fedge_doc,
+ ViewEdge_first_fedge_doc,
NULL},
- {(char *)"last_fedge",
+ {"last_fedge",
(getter)ViewEdge_last_fedge_get,
(setter)ViewEdge_last_fedge_set,
- (char *)ViewEdge_last_fedge_doc,
+ ViewEdge_last_fedge_doc,
NULL},
- {(char *)"viewshape",
+ {"viewshape",
(getter)ViewEdge_viewshape_get,
(setter)ViewEdge_viewshape_set,
- (char *)ViewEdge_viewshape_doc,
+ ViewEdge_viewshape_doc,
NULL},
- {(char *)"occludee",
+ {"occludee",
(getter)ViewEdge_occludee_get,
(setter)ViewEdge_occludee_set,
- (char *)ViewEdge_occludee_doc,
+ ViewEdge_occludee_doc,
NULL},
- {(char *)"is_closed",
- (getter)ViewEdge_is_closed_get,
- (setter)NULL,
- (char *)ViewEdge_is_closed_doc,
- NULL},
- {(char *)"id",
- (getter)ViewEdge_id_get,
- (setter)ViewEdge_id_set,
- (char *)ViewEdge_id_doc,
- NULL},
- {(char *)"nature",
+ {"is_closed", (getter)ViewEdge_is_closed_get, (setter)NULL, ViewEdge_is_closed_doc, NULL},
+ {"id", (getter)ViewEdge_id_get, (setter)ViewEdge_id_set, ViewEdge_id_doc, NULL},
+ {"nature",
(getter)ViewEdge_nature_get,
(setter)ViewEdge_nature_set,
- (char *)ViewEdge_nature_doc,
- NULL},
- {(char *)"qi",
- (getter)ViewEdge_qi_get,
- (setter)ViewEdge_qi_set,
- (char *)ViewEdge_qi_doc,
+ ViewEdge_nature_doc,
NULL},
- {(char *)"chaining_time_stamp",
+ {"qi", (getter)ViewEdge_qi_get, (setter)ViewEdge_qi_set, ViewEdge_qi_doc, NULL},
+ {"chaining_time_stamp",
(getter)ViewEdge_chaining_time_stamp_get,
(setter)ViewEdge_chaining_time_stamp_set,
- (char *)ViewEdge_chaining_time_stamp_doc,
+ ViewEdge_chaining_time_stamp_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
index 018d0c77bb0..725daa80b5e 100644
--- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
@@ -364,45 +364,45 @@ static int FEdgeSharp_face_mark_left_set(BPy_FEdgeSharp *self,
}
static PyGetSetDef BPy_FEdgeSharp_getseters[] = {
- {(char *)"normal_right",
+ {"normal_right",
(getter)FEdgeSharp_normal_right_get,
(setter)FEdgeSharp_normal_right_set,
- (char *)FEdgeSharp_normal_right_doc,
+ FEdgeSharp_normal_right_doc,
NULL},
- {(char *)"normal_left",
+ {"normal_left",
(getter)FEdgeSharp_normal_left_get,
(setter)FEdgeSharp_normal_left_set,
- (char *)FEdgeSharp_normal_left_doc,
+ FEdgeSharp_normal_left_doc,
NULL},
- {(char *)"material_index_right",
+ {"material_index_right",
(getter)FEdgeSharp_material_index_right_get,
(setter)FEdgeSharp_material_index_right_set,
- (char *)FEdgeSharp_material_index_right_doc,
+ FEdgeSharp_material_index_right_doc,
NULL},
- {(char *)"material_index_left",
+ {"material_index_left",
(getter)FEdgeSharp_material_index_left_get,
(setter)FEdgeSharp_material_index_left_set,
- (char *)FEdgeSharp_material_index_left_doc,
+ FEdgeSharp_material_index_left_doc,
NULL},
- {(char *)"material_right",
+ {"material_right",
(getter)FEdgeSharp_material_right_get,
(setter)NULL,
- (char *)FEdgeSharp_material_right_doc,
+ FEdgeSharp_material_right_doc,
NULL},
- {(char *)"material_left",
+ {"material_left",
(getter)FEdgeSharp_material_left_get,
(setter)NULL,
- (char *)FEdgeSharp_material_left_doc,
+ FEdgeSharp_material_left_doc,
NULL},
- {(char *)"face_mark_right",
+ {"face_mark_right",
(getter)FEdgeSharp_face_mark_right_get,
(setter)FEdgeSharp_face_mark_right_set,
- (char *)FEdgeSharp_face_mark_right_doc,
+ FEdgeSharp_face_mark_right_doc,
NULL},
- {(char *)"face_mark_left",
+ {"face_mark_left",
(getter)FEdgeSharp_face_mark_left_get,
(setter)FEdgeSharp_face_mark_left_set,
- (char *)FEdgeSharp_face_mark_left_doc,
+ FEdgeSharp_face_mark_left_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
index 4c2785509f0..65d9dcbe01f 100644
--- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
@@ -229,25 +229,21 @@ static int FEdgeSmooth_face_mark_set(BPy_FEdgeSmooth *self, PyObject *value, voi
}
static PyGetSetDef BPy_FEdgeSmooth_getseters[] = {
- {(char *)"normal",
+ {"normal",
(getter)FEdgeSmooth_normal_get,
(setter)FEdgeSmooth_normal_set,
- (char *)FEdgeSmooth_normal_doc,
+ FEdgeSmooth_normal_doc,
NULL},
- {(char *)"material_index",
+ {"material_index",
(getter)FEdgeSmooth_material_index_get,
(setter)FEdgeSmooth_material_index_set,
- (char *)FEdgeSmooth_material_index_doc,
+ FEdgeSmooth_material_index_doc,
NULL},
- {(char *)"material",
- (getter)FEdgeSmooth_material_get,
- (setter)NULL,
- (char *)FEdgeSmooth_material_doc,
- NULL},
- {(char *)"face_mark",
+ {"material", (getter)FEdgeSmooth_material_get, (setter)NULL, FEdgeSmooth_material_doc, NULL},
+ {"face_mark",
(getter)FEdgeSmooth_face_mark_get,
(setter)FEdgeSmooth_face_mark_set,
- (char *)FEdgeSmooth_face_mark_doc,
+ FEdgeSmooth_face_mark_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
index 4264e96afc3..74ae7809284 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
@@ -172,15 +172,15 @@ static PyObject *AdjacencyIterator_is_incoming_get(BPy_AdjacencyIterator *self,
}
static PyGetSetDef BPy_AdjacencyIterator_getseters[] = {
- {(char *)"is_incoming",
+ {"is_incoming",
(getter)AdjacencyIterator_is_incoming_get,
(setter)NULL,
- (char *)AdjacencyIterator_is_incoming_doc,
+ AdjacencyIterator_is_incoming_doc,
NULL},
- {(char *)"object",
+ {"object",
(getter)AdjacencyIterator_object_get,
(setter)NULL,
- (char *)AdjacencyIterator_object_doc,
+ AdjacencyIterator_object_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp
index b2042107453..b6d841c5b64 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp
@@ -234,20 +234,20 @@ static PyObject *ChainingIterator_is_incrementing_get(BPy_ChainingIterator *self
}
static PyGetSetDef BPy_ChainingIterator_getseters[] = {
- {(char *)"object",
+ {"object",
(getter)ChainingIterator_object_get,
(setter)NULL,
- (char *)ChainingIterator_object_doc,
+ ChainingIterator_object_doc,
NULL},
- {(char *)"next_vertex",
+ {"next_vertex",
(getter)ChainingIterator_next_vertex_get,
(setter)NULL,
- (char *)ChainingIterator_next_vertex_doc,
+ ChainingIterator_next_vertex_doc,
NULL},
- {(char *)"is_incrementing",
+ {"is_incrementing",
(getter)ChainingIterator_is_incrementing_get,
(setter)NULL,
- (char *)ChainingIterator_is_incrementing_doc,
+ ChainingIterator_is_incrementing_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp
index abc10b75ea1..6ea61a060cb 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp
@@ -123,21 +123,13 @@ static PyObject *CurvePointIterator_u_get(BPy_CurvePointIterator *self, void *UN
}
static PyGetSetDef BPy_CurvePointIterator_getseters[] = {
- {(char *)"object",
+ {"object",
(getter)CurvePointIterator_object_get,
(setter)NULL,
- (char *)CurvePointIterator_object_doc,
- NULL},
- {(char *)"t",
- (getter)CurvePointIterator_t_get,
- (setter)NULL,
- (char *)CurvePointIterator_t_doc,
- NULL},
- {(char *)"u",
- (getter)CurvePointIterator_u_get,
- (setter)NULL,
- (char *)CurvePointIterator_u_doc,
+ CurvePointIterator_object_doc,
NULL},
+ {"t", (getter)CurvePointIterator_t_get, (setter)NULL, CurvePointIterator_t_doc, NULL},
+ {"u", (getter)CurvePointIterator_u_get, (setter)NULL, CurvePointIterator_u_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
index 8428badc0fd..0dbef9f325c 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
@@ -192,25 +192,17 @@ static PyObject *Interface0DIterator_at_last_get(BPy_Interface0DIterator *self,
}
static PyGetSetDef BPy_Interface0DIterator_getseters[] = {
- {(char *)"object",
+ {"object",
(getter)Interface0DIterator_object_get,
(setter)NULL,
- (char *)Interface0DIterator_object_doc,
+ Interface0DIterator_object_doc,
NULL},
- {(char *)"t",
- (getter)Interface0DIterator_t_get,
- (setter)NULL,
- (char *)Interface0DIterator_t_doc,
- NULL},
- {(char *)"u",
- (getter)Interface0DIterator_u_get,
- (setter)NULL,
- (char *)Interface0DIterator_u_doc,
- NULL},
- {(char *)"at_last",
+ {"t", (getter)Interface0DIterator_t_get, (setter)NULL, Interface0DIterator_t_doc, NULL},
+ {"u", (getter)Interface0DIterator_u_get, (setter)NULL, Interface0DIterator_u_doc, NULL},
+ {"at_last",
(getter)Interface0DIterator_at_last_get,
(setter)NULL,
- (char *)Interface0DIterator_at_last_doc,
+ Interface0DIterator_at_last_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp
index 260776e8965..dd738b97473 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp
@@ -151,21 +151,9 @@ static PyObject *SVertexIterator_u_get(BPy_SVertexIterator *self, void *UNUSED(c
}
static PyGetSetDef BPy_SVertexIterator_getseters[] = {
- {(char *)"object",
- (getter)SVertexIterator_object_get,
- (setter)NULL,
- (char *)SVertexIterator_object_doc,
- NULL},
- {(char *)"t",
- (getter)SVertexIterator_t_get,
- (setter)NULL,
- (char *)SVertexIterator_t_doc,
- NULL},
- {(char *)"u",
- (getter)SVertexIterator_u_get,
- (setter)NULL,
- (char *)SVertexIterator_u_doc,
- NULL},
+ {"object", (getter)SVertexIterator_object_get, (setter)NULL, SVertexIterator_object_doc, NULL},
+ {"t", (getter)SVertexIterator_t_get, (setter)NULL, SVertexIterator_t_doc, NULL},
+ {"u", (getter)SVertexIterator_u_get, (setter)NULL, SVertexIterator_u_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
index 4269dfb3cdd..84f57f1fe31 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
@@ -265,25 +265,17 @@ static PyObject *StrokeVertexIterator_at_last_get(BPy_StrokeVertexIterator *self
}
static PyGetSetDef BPy_StrokeVertexIterator_getseters[] = {
- {(char *)"object",
+ {"object",
(getter)StrokeVertexIterator_object_get,
(setter)NULL,
- (char *)StrokeVertexIterator_object_doc,
+ StrokeVertexIterator_object_doc,
NULL},
- {(char *)"t",
- (getter)StrokeVertexIterator_t_get,
- (setter)NULL,
- (char *)StrokeVertexIterator_t_doc,
- NULL},
- {(char *)"u",
- (getter)StrokeVertexIterator_u_get,
- (setter)NULL,
- (char *)StrokeVertexIterator_u_doc,
- NULL},
- {(char *)"at_last",
+ {"t", (getter)StrokeVertexIterator_t_get, (setter)NULL, StrokeVertexIterator_t_doc, NULL},
+ {"u", (getter)StrokeVertexIterator_u_get, (setter)NULL, StrokeVertexIterator_u_doc, NULL},
+ {"at_last",
(getter)StrokeVertexIterator_at_last_get,
(setter)NULL,
- (char *)StrokeVertexIterator_at_last_doc,
+ StrokeVertexIterator_at_last_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp
index df56cbe822e..c8a978784a4 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp
@@ -214,25 +214,25 @@ static int ViewEdgeIterator_begin_set(BPy_ViewEdgeIterator *self,
}
static PyGetSetDef BPy_ViewEdgeIterator_getseters[] = {
- {(char *)"object",
+ {"object",
(getter)ViewEdgeIterator_object_get,
(setter)NULL,
- (char *)ViewEdgeIterator_object_doc,
+ ViewEdgeIterator_object_doc,
NULL},
- {(char *)"current_edge",
+ {"current_edge",
(getter)ViewEdgeIterator_current_edge_get,
(setter)ViewEdgeIterator_current_edge_set,
- (char *)ViewEdgeIterator_current_edge_doc,
+ ViewEdgeIterator_current_edge_doc,
NULL},
- {(char *)"orientation",
+ {"orientation",
(getter)ViewEdgeIterator_orientation_get,
(setter)ViewEdgeIterator_orientation_set,
- (char *)ViewEdgeIterator_orientation_doc,
+ ViewEdgeIterator_orientation_doc,
NULL},
- {(char *)"begin",
+ {"begin",
(getter)ViewEdgeIterator_begin_get,
(setter)ViewEdgeIterator_begin_set,
- (char *)ViewEdgeIterator_begin_doc,
+ ViewEdgeIterator_begin_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp
index 821a92184d1..fe6210468d1 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp
@@ -131,10 +131,10 @@ static PyObject *orientedViewEdgeIterator_object_get(BPy_orientedViewEdgeIterato
}
static PyGetSetDef BPy_orientedViewEdgeIterator_getseters[] = {
- {(char *)"object",
+ {"object",
(getter)orientedViewEdgeIterator_object_get,
(setter)NULL,
- (char *)orientedViewEdgeIterator_object_doc,
+ orientedViewEdgeIterator_object_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.cpp
index bed2d5d578a..543375fa85b 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.cpp
@@ -258,10 +258,10 @@ static int integration_type_set(BPy_UnaryFunction1DDouble *self,
}
static PyGetSetDef BPy_UnaryFunction1DDouble_getseters[] = {
- {(char *)"integration_type",
+ {"integration_type",
(getter)integration_type_get,
(setter)integration_type_set,
- (char *)integration_type_doc,
+ integration_type_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.cpp
index e122454c00d..fcc72cf7b71 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.cpp
@@ -165,10 +165,10 @@ static int integration_type_set(BPy_UnaryFunction1DEdgeNature *self,
}
static PyGetSetDef BPy_UnaryFunction1DEdgeNature_getseters[] = {
- {(char *)"integration_type",
+ {"integration_type",
(getter)integration_type_get,
(setter)integration_type_set,
- (char *)integration_type_doc,
+ integration_type_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.cpp
index 95d49612672..ef4de9a77dc 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.cpp
@@ -154,10 +154,10 @@ static int integration_type_set(BPy_UnaryFunction1DFloat *self,
}
static PyGetSetDef BPy_UnaryFunction1DFloat_getseters[] = {
- {(char *)"integration_type",
+ {"integration_type",
(getter)integration_type_get,
(setter)integration_type_set,
- (char *)integration_type_doc,
+ integration_type_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp
index 851fc45d583..5be9e2dee28 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp
@@ -165,10 +165,10 @@ static int integration_type_set(BPy_UnaryFunction1DUnsigned *self,
}
static PyGetSetDef BPy_UnaryFunction1DUnsigned_getseters[] = {
- {(char *)"integration_type",
+ {"integration_type",
(getter)integration_type_get,
(setter)integration_type_set,
- (char *)integration_type_doc,
+ integration_type_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.cpp
index 75225fd6381..58ab705e8c1 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.cpp
@@ -169,10 +169,10 @@ static int integration_type_set(BPy_UnaryFunction1DVec2f *self,
}
static PyGetSetDef BPy_UnaryFunction1DVec2f_getseters[] = {
- {(char *)"integration_type",
+ {"integration_type",
(getter)integration_type_get,
(setter)integration_type_set,
- (char *)integration_type_doc,
+ integration_type_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.cpp
index a2767e826ab..e1f64e7cd82 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.cpp
@@ -162,10 +162,10 @@ static int integration_type_set(BPy_UnaryFunction1DVec3f *self,
}
static PyGetSetDef BPy_UnaryFunction1DVec3f_getseters[] = {
- {(char *)"integration_type",
+ {"integration_type",
(getter)integration_type_get,
(setter)integration_type_set,
- (char *)integration_type_doc,
+ integration_type_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp
index 0739f327f55..12b985bc707 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp
@@ -190,10 +190,10 @@ static int integration_type_set(BPy_UnaryFunction1DVectorViewShape *self,
}
static PyGetSetDef BPy_UnaryFunction1DVectorViewShape_getseters[] = {
- {(char *)"integration_type",
+ {"integration_type",
(getter)integration_type_get,
(setter)integration_type_set,
- (char *)integration_type_doc,
+ integration_type_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.cpp
index ca1e35f66bd..3b55a20939e 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.cpp
@@ -177,10 +177,10 @@ static int integration_type_set(BPy_UnaryFunction1DVoid *self,
}
static PyGetSetDef BPy_UnaryFunction1DVoid_getseters[] = {
- {(char *)"integration_type",
+ {"integration_type",
(getter)integration_type_get,
(setter)integration_type_set,
- (char *)integration_type_doc,
+ integration_type_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 44335f4da25..87743911add 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -30,7 +30,6 @@ set(INC
../makesdna
../makesrna
../render/extern/include
- ../../../intern/elbeem/extern
../../../intern/eigen
../../../intern/guardedalloc
)
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
index c71d074e564..bc545ce6ce8 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
@@ -1,6 +1,4 @@
/*
- * ***** 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
@@ -17,12 +15,9 @@
*
* The Original Code is Copyright (C) 2017, Blender Foundation
* This is a new part of Blender
- *
- * ***** END GPL LICENSE BLOCK *****
- *
*/
-/** \file blender/gpencil_modifiers/intern/MOD_gpencilstrokes.c
+/** \file
* \ingroup modifiers
*/
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
index 01bb0ae2b93..e3ad5a64ac3 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
@@ -71,8 +71,14 @@ static int remapTime(struct GpencilModifierData *md,
const bool invpass = mmd->flag & GP_TIME_INVERT_LAYERPASS;
int sfra = custom ? mmd->sfra : scene->r.sfra;
int efra = custom ? mmd->efra : scene->r.efra;
- CLAMP_MIN(sfra, 1);
- CLAMP_MIN(efra, 1);
+ CLAMP_MIN(sfra, 0);
+ CLAMP_MIN(efra, 0);
+
+ /* Avoid inverse ranges. */
+ if (efra < sfra) {
+ return cfra;
+ }
+
const int time_range = efra - sfra + 1;
int offset = mmd->offset;
int segments = 0;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 9320e849194..8daeda67c80 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -44,7 +44,7 @@ set(INC
../../../intern/glew-mx
../../../intern/guardedalloc
- ../../../intern/smoke/extern
+ ../../../intern/mantaflow/extern
)
set(INC_SYS
@@ -61,6 +61,7 @@ set(SRC
intern/gpu_context.cpp
intern/gpu_debug.c
intern/gpu_draw.c
+ intern/gpu_draw_smoke.c
intern/gpu_element.c
intern/gpu_extensions.c
intern/gpu_framebuffer.c
@@ -158,7 +159,6 @@ data_to_c_simple(shaders/gpu_shader_2D_nodelink_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_flat_color_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_line_dashed_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_line_dashed_geom.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl SRC)
@@ -189,19 +189,7 @@ data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_passthrough_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_instance_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_instance_screen_aligned_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_instance_camera_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_instance_distance_line_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_instance_edges_variying_color_geom.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_instance_edges_variying_color_vert.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_3D_groundline_geom.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_groundpoint_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_point_uniform_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_point_uniform_color_aa_frag.glsl SRC)
@@ -225,10 +213,7 @@ data_to_c_simple(shaders/gpu_shader_2D_edituvs_edges_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_edituvs_faces_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_edituvs_stretch_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_text_simple_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_text_simple_geom.glsl SRC)
data_to_c_simple(shaders/gpu_shader_text_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_text_geom.glsl SRC)
data_to_c_simple(shaders/gpu_shader_text_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_keyframe_diamond_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_keyframe_diamond_frag.glsl SRC)
@@ -335,8 +320,8 @@ data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC)
data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC)
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_FLUID)
+ add_definitions(-DWITH_FLUID)
endif()
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index d7218e97bf0..3616189e673 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -41,6 +41,7 @@ typedef enum {
} GPUBatchPhase;
#define GPU_BATCH_VBO_MAX_LEN 6
+#define GPU_BATCH_INST_VBO_MAX_LEN 2
#define GPU_BATCH_VAO_STATIC_LEN 3
#define GPU_BATCH_VAO_DYN_ALLOC_COUNT 16
@@ -50,7 +51,7 @@ typedef struct GPUBatch {
/** verts[0] is required, others can be NULL */
GPUVertBuf *verts[GPU_BATCH_VBO_MAX_LEN];
/** Instance attributes. */
- GPUVertBuf *inst;
+ GPUVertBuf *inst[GPU_BATCH_INST_VBO_MAX_LEN];
/** NULL if element list not needed */
GPUIndexBuf *elem;
uint32_t gl_prim_type;
@@ -117,6 +118,7 @@ void GPU_batch_callback_free_set(GPUBatch *, void (*callback)(GPUBatch *, void *
void GPU_batch_instbuf_set(GPUBatch *, GPUVertBuf *, bool own_vbo); /* Instancing */
void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo);
+int GPU_batch_instbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
#define GPU_batch_vertbuf_add(batch, verts) GPU_batch_vertbuf_add_ex(batch, verts, false)
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 6d2b0ad3be3..2ed4ee44287 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -31,12 +31,12 @@ struct CCGElem;
struct CCGKey;
struct DMFlagMat;
struct GSet;
-struct Mesh;
struct MLoop;
struct MLoopCol;
struct MLoopTri;
struct MPoly;
struct MVert;
+struct Mesh;
struct PBVH;
/* Buffers for drawing from PBVH grids. */
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 7814c723fec..f89a76cf49c 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -28,11 +28,11 @@
extern "C" {
#endif
+struct FluidModifierData;
struct ImBuf;
struct Image;
struct ImageUser;
struct Main;
-struct SmokeModifierData;
#include "DNA_object_enums.h"
@@ -83,12 +83,12 @@ void GPU_free_images(struct Main *bmain);
void GPU_free_images_anim(struct Main *bmain);
void GPU_free_images_old(struct Main *bmain);
-/* smoke drawing functions */
-void GPU_free_smoke(struct SmokeModifierData *smd);
-void GPU_free_smoke_velocity(struct SmokeModifierData *smd);
-void GPU_create_smoke(struct SmokeModifierData *smd, int highres);
-void GPU_create_smoke_coba_field(struct SmokeModifierData *smd);
-void GPU_create_smoke_velocity(struct SmokeModifierData *smd);
+/* gpu_draw_smoke.c */
+void GPU_free_smoke(struct FluidModifierData *mmd);
+void GPU_free_smoke_velocity(struct FluidModifierData *mmd);
+void GPU_create_smoke(struct FluidModifierData *mmd, int highres);
+void GPU_create_smoke_coba_field(struct FluidModifierData *mmd);
+void GPU_create_smoke_velocity(struct FluidModifierData *mmd);
/* Delayed free of OpenGL buffers by main thread */
void GPU_free_unused_buffers(struct Main *bmain);
diff --git a/source/blender/gpu/GPU_element.h b/source/blender/gpu/GPU_element.h
index 75caf4cbd6a..996ade3e0f6 100644
--- a/source/blender/gpu/GPU_element.h
+++ b/source/blender/gpu/GPU_element.h
@@ -90,6 +90,10 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *);
/* Create a subrange of an existing indexbuffer. */
GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *ibo, uint start, uint length);
+void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *r_ibo,
+ GPUIndexBuf *ibo,
+ uint start,
+ uint length);
void GPU_indexbuf_discard(GPUIndexBuf *);
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 4dc0019978a..a5363c7a42c 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -142,7 +142,7 @@ typedef enum eGPUMaterialStatus {
GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
GPUNodeLink *GPU_constant(float *num);
GPUNodeLink *GPU_uniform(float *num);
-GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser);
+GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, int tile);
GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer);
GPUNodeLink *GPU_builtin(eGPUBuiltin builtin);
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 4d6f22a0240..23bd6815ce4 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -105,7 +105,6 @@ char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_bin
typedef enum eGPUBuiltinShader {
/* specialized drawing */
GPU_SHADER_TEXT,
- GPU_SHADER_TEXT_SIMPLE,
GPU_SHADER_KEYFRAME_DIAMOND,
GPU_SHADER_SIMPLE_LIGHTING,
GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR,
@@ -317,26 +316,8 @@ typedef enum eGPUBuiltinShader {
/* lines */
GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR,
GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR,
- /* light drawing */
- GPU_SHADER_3D_GROUNDPOINT,
- GPU_SHADER_3D_GROUNDLINE,
- GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR,
- /* bone drawing */
- GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR,
- GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR,
- /* camera drawing */
- GPU_SHADER_CAMERA,
- /* distance in front of objects */
- GPU_SHADER_DISTANCE_LINES,
- /* axis name */
- GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS,
- GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED,
/* instance */
- GPU_SHADER_INSTANCE_UNIFORM_COLOR,
- GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE, /* Uniformly scaled */
GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, /* Uniformly scaled */
- GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE,
- GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR,
/* grease pencil drawing */
GPU_SHADER_GPENCIL_STROKE,
GPU_SHADER_GPENCIL_FILL,
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index 2d728422c42..99d32f24cc3 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -88,6 +88,8 @@ void GPU_vertbuf_data_len_set(GPUVertBuf *, uint v_len);
void GPU_vertbuf_attr_set(GPUVertBuf *, uint a_idx, uint v_idx, const void *data);
+void GPU_vertbuf_vert_set(GPUVertBuf *verts, uint v_idx, const void *data);
+
/* Tightly packed, non interleaved input data. */
void GPU_vertbuf_attr_fill(GPUVertBuf *, uint a_idx, const void *data);
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index 17cbad21ec4..aff5c6a997d 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -32,6 +32,7 @@
#include "GPU_texture.h"
#define GPU_INFO_SIZE 512 /* IMA_MAX_RENDER_TEXT */
+#define GLA_PIXEL_OFS 0.375f
typedef struct GPUViewport GPUViewport;
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
index 168d741f92a..717983f94d8 100644
--- a/source/blender/gpu/intern/gpu_batch.c
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -103,7 +103,9 @@ void GPU_batch_init_ex(
for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) {
batch->verts[v] = NULL;
}
- batch->inst = NULL;
+ for (int v = 0; v < GPU_BATCH_INST_VBO_MAX_LEN; v++) {
+ batch->inst[v] = NULL;
+ }
batch->elem = elem;
batch->gl_prim_type = convert_prim_type_to_gl(prim_type);
batch->phase = GPU_BATCH_READY_TO_DRAW;
@@ -129,7 +131,8 @@ void GPU_batch_clear(GPUBatch *batch)
GPU_indexbuf_discard(batch->elem);
}
if (batch->owns_flag & GPU_BATCH_OWNS_INSTANCES) {
- GPU_vertbuf_discard(batch->inst);
+ GPU_vertbuf_discard(batch->inst[0]);
+ GPU_VERTBUF_DISCARD_SAFE(batch->inst[1]);
}
if ((batch->owns_flag & ~GPU_BATCH_OWNS_INDEX) != 0) {
for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
@@ -171,10 +174,11 @@ void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
/* redo the bindings */
GPU_batch_vao_cache_clear(batch);
- if (batch->inst != NULL && (batch->owns_flag & GPU_BATCH_OWNS_INSTANCES)) {
- GPU_vertbuf_discard(batch->inst);
+ if (batch->inst[0] != NULL && (batch->owns_flag & GPU_BATCH_OWNS_INSTANCES)) {
+ GPU_vertbuf_discard(batch->inst[0]);
+ GPU_VERTBUF_DISCARD_SAFE(batch->inst[1]);
}
- batch->inst = inst;
+ batch->inst[0] = inst;
if (own_vbo) {
batch->owns_flag |= GPU_BATCH_OWNS_INSTANCES;
@@ -203,6 +207,37 @@ void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo)
}
}
+/* A bit of a quick hack. Should be streamlined as the vbos handling */
+int GPU_batch_instbuf_add_ex(GPUBatch *batch, GPUVertBuf *insts, bool own_vbo)
+{
+ /* redo the bindings */
+ GPU_batch_vao_cache_clear(batch);
+
+ for (uint v = 0; v < GPU_BATCH_INST_VBO_MAX_LEN; v++) {
+ if (batch->inst[v] == NULL) {
+#if TRUST_NO_ONE
+ /* for now all VertexBuffers must have same vertex_len */
+ if (batch->inst[0] != NULL) {
+ /* Allow for different size of vertex buf (will choose the smallest number of verts). */
+ // assert(insts->vertex_len == batch->inst[0]->vertex_len);
+ assert(own_vbo == ((batch->owns_flag & GPU_BATCH_OWNS_INSTANCES) != 0));
+ }
+#endif
+ batch->inst[v] = insts;
+ if (own_vbo) {
+ batch->owns_flag |= GPU_BATCH_OWNS_INSTANCES;
+ }
+ return v;
+ }
+ }
+
+ /* we only make it this far if there is no room for another GPUVertBuf */
+#if TRUST_NO_ONE
+ assert(false);
+#endif
+ return -1;
+}
+
/* Returns the index of verts in the batch. */
int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
{
@@ -458,8 +493,10 @@ static void batch_update_program_bindings(GPUBatch *batch, uint i_first)
create_bindings(batch->verts[v], batch->interface, 0, false);
}
}
- if (batch->inst) {
- create_bindings(batch->inst, batch->interface, i_first, true);
+ for (int v = GPU_BATCH_INST_VBO_MAX_LEN - 1; v > -1; v--) {
+ if (batch->inst[v]) {
+ create_bindings(batch->inst[v], batch->interface, i_first, true);
+ }
}
if (batch->elem) {
GPU_indexbuf_use(batch->elem);
@@ -639,7 +676,11 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len;
}
if (i_count == 0) {
- i_count = (batch->inst) ? batch->inst->vertex_len : 1;
+ i_count = (batch->inst[0]) ? batch->inst[0]->vertex_len : 1;
+ /* Meh. This is to be able to use different numbers of verts in instance vbos. */
+ if (batch->inst[1] && i_count > batch->inst[1]->vertex_len) {
+ i_count = batch->inst[1]->vertex_len;
+ }
}
if (v_count == 0 || i_count == 0) {
@@ -655,11 +696,24 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
// BLI_assert(v_first + v_count <=
// (batch->elem ? batch->elem->index_len : batch->verts[0]->vertex_len));
+#ifdef __APPLE__
+ GLuint vao = 0;
+#endif
+
if (!GPU_arb_base_instance_is_supported()) {
if (i_first > 0) {
+#ifdef __APPLE__
+ /**
+ * There seems to be a nasty bug when drawing using the same VAO reconfiguring. (see T71147)
+ * We just use a throwaway VAO for that. Note that this is likely to degrade performance.
+ **/
+ glGenVertexArrays(1, &vao);
+ glBindVertexArray(vao);
+#else
/* If using offset drawing with instancing, we must
* use the default VAO and redo bindings. */
glBindVertexArray(GPU_vao_default());
+#endif
batch_update_program_bindings(batch, i_first);
}
else {
@@ -698,6 +752,12 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
glEnable(GL_PRIMITIVE_RESTART);
#endif
}
+
+#ifdef __APPLE__
+ if (vao != 0) {
+ glDeleteVertexArrays(1, &vao);
+ }
+#endif
}
/* just draw some vertices and let shader place them where we want. */
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 410e23c9576..ca804a26acd 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -581,17 +581,19 @@ const char *GPU_builtin_name(eGPUBuiltin builtin)
}
/* assign only one texid per buffer to avoid sampling the same texture twice */
-static void codegen_set_texid(GHash *bindhash, GPUInput *input, int *texid, void *key)
+static void codegen_set_texid(GHash *bindhash, GPUInput *input, int *texid, void *key1, int key2)
{
- if (BLI_ghash_haskey(bindhash, key)) {
+ GHashPair pair = {key1, POINTER_FROM_INT(key2)};
+ if (BLI_ghash_haskey(bindhash, &pair)) {
/* Reuse existing texid */
- input->texid = POINTER_AS_INT(BLI_ghash_lookup(bindhash, key));
+ input->texid = POINTER_AS_INT(BLI_ghash_lookup(bindhash, &pair));
}
else {
/* Allocate new texid */
input->texid = *texid;
(*texid)++;
input->bindtex = true;
+ void *key = BLI_ghashutil_pairalloc(key1, POINTER_FROM_INT(key2));
BLI_ghash_insert(bindhash, key, POINTER_FROM_INT(input->texid));
}
}
@@ -604,7 +606,7 @@ static void codegen_set_unique_ids(ListBase *nodes)
GPUOutput *output;
int id = 1, texid = 0;
- bindhash = BLI_ghash_ptr_new("codegen_set_unique_ids1 gh");
+ bindhash = BLI_ghash_pair_new("codegen_set_unique_ids1 gh");
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
@@ -616,11 +618,11 @@ static void codegen_set_unique_ids(ListBase *nodes)
input->bindtex = false;
if (input->ima) {
/* input is texture from image */
- codegen_set_texid(bindhash, input, &texid, input->ima);
+ codegen_set_texid(bindhash, input, &texid, input->ima, input->image_tile);
}
else if (input->coba) {
/* input is color band texture, check coba pointer */
- codegen_set_texid(bindhash, input, &texid, input->coba);
+ codegen_set_texid(bindhash, input, &texid, input->coba, 0);
}
else {
/* Either input->ima or input->coba should be non-NULL. */
@@ -635,7 +637,7 @@ static void codegen_set_unique_ids(ListBase *nodes)
}
}
- BLI_ghash_free(bindhash, NULL, NULL);
+ BLI_ghash_free(bindhash, BLI_ghashutil_pairfree, NULL);
}
/**
@@ -1545,6 +1547,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
input->source = GPU_SOURCE_TEX;
input->ima = link->ima;
input->iuser = link->iuser;
+ input->image_tile = link->image_tile;
break;
case GPU_NODE_LINK_ATTR:
input->source = GPU_SOURCE_ATTR;
@@ -1789,12 +1792,13 @@ GPUNodeLink *GPU_uniform(float *num)
return link;
}
-GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser)
+GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, int tile)
{
GPUNodeLink *link = GPU_node_link_create();
link->link_type = GPU_NODE_LINK_IMAGE_BLENDER;
link->ima = ima;
link->iuser = iuser;
+ link->image_tile = tile;
return link;
}
@@ -2127,8 +2131,10 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
static int count_active_texture_sampler(GPUShader *shader, char *source)
{
char *code = source;
- int samplers_id[64]; /* Remember this is per stage. */
- int sampler_len = 0;
+
+ /* Remember this is per stage. */
+ GSet *sampler_ids = BLI_gset_int_new(__func__);
+ int num_samplers = 0;
while ((code = strstr(code, "uniform "))) {
/* Move past "uniform". */
@@ -2163,22 +2169,16 @@ static int count_active_texture_sampler(GPUShader *shader, char *source)
continue;
}
/* Catch duplicates. */
- bool is_duplicate = false;
- for (int i = 0; i < sampler_len; i++) {
- if (samplers_id[i] == id) {
- is_duplicate = true;
- }
- }
-
- if (!is_duplicate) {
- samplers_id[sampler_len] = id;
- sampler_len++;
+ if (BLI_gset_add(sampler_ids, POINTER_FROM_INT(id))) {
+ num_samplers++;
}
}
}
}
- return sampler_len;
+ BLI_gset_free(sampler_ids, NULL);
+
+ return num_samplers;
}
static bool gpu_pass_shader_validate(GPUPass *pass, GPUShader *shader)
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 4e09f16ebf8..0e6982c603e 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -99,6 +99,7 @@ struct GPUNodeLink {
struct {
struct Image *ima;
struct ImageUser *iuser;
+ int image_tile;
};
};
};
@@ -138,6 +139,7 @@ typedef struct GPUInput {
struct ImageUser *iuser; /* image user */
bool bindtex; /* input is responsible for binding the texture? */
int texid; /* number for multitexture, starting from zero */
+ int image_tile; /* image tile */
eGPUType textype; /* texture type (2D, 1D Array ...) */
};
/* GPU_SOURCE_ATTR */
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 7fa2eb6424c..95738bb1a95 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -36,17 +36,9 @@
#include "BLI_threads.h"
#include "BLI_utildefines.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_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_particle_types.h"
+#include "DNA_image_types.h"
+#include "DNA_movieclip_types.h"
+#include "DNA_userdef_types.h"
#include "MEM_guardedalloc.h"
@@ -54,14 +46,10 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include "BKE_colorband.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
-#include "BKE_material.h"
#include "BKE_movieclip.h"
-#include "BKE_node.h"
-#include "BKE_scene.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
@@ -71,10 +59,6 @@
#include "PIL_time.h"
-#ifdef WITH_SMOKE
-# include "smoke_API.h"
-#endif
-
static void gpu_free_image_immediate(Image *ima);
//* Checking powers of two for images since OpenGL ES requires it */
@@ -195,13 +179,13 @@ float GPU_get_anisotropic(void)
/* Set OpenGL state for an MTFace */
-static GPUTexture **gpu_get_image_gputexture(Image *ima, GLenum textarget)
+static GPUTexture **gpu_get_tile_gputexture(ImageTile *tile, GLenum textarget)
{
if (textarget == GL_TEXTURE_2D) {
- return &ima->gputexture[TEXTARGET_TEXTURE_2D];
+ return &tile->gputexture[TEXTARGET_TEXTURE_2D];
}
else if (textarget == GL_TEXTURE_CUBE_MAP) {
- return &ima->gputexture[TEXTARGET_TEXTURE_CUBE_MAP];
+ return &tile->gputexture[TEXTARGET_TEXTURE_CUBE_MAP];
}
return NULL;
@@ -476,8 +460,19 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
/* Tag as in active use for garbage collector. */
BKE_image_tag_time(ima);
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+
+ if (tile == NULL) {
+ /* TODO(lukas): When a tile gets deleted, the materials using the image
+ * aren't rebuilt and therefore continue to use it.
+ * This workaround isn't ideal, the result should be a pink color
+ * (for a missing tile). With the current behavior, new tiles also won't
+ * be detected. */
+ tile = BKE_image_get_tile(ima, 0);
+ }
+
/* Test if we already have a texture. */
- GPUTexture **tex = gpu_get_image_gputexture(ima, textarget);
+ GPUTexture **tex = gpu_get_tile_gputexture(tile, textarget);
if (*tex) {
return *tex;
}
@@ -485,7 +480,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
/* Check if we have a valid image. If not, we return a dummy
* texture with zero bindcode so we don't keep trying. */
uint bindcode = 0;
- if (ima->ok == 0) {
+ if (tile->ok == 0) {
*tex = GPU_texture_from_bindcode(textarget, bindcode);
return *tex;
}
@@ -861,11 +856,14 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
if (BKE_image_has_opengl_texture(ima)) {
if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) {
- if (ima->gputexture[TEXTARGET_TEXTURE_2D]) {
- GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
+ if (tex != NULL) {
+ GPU_texture_bind(tex, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ GPU_texture_unbind(tex);
+ }
}
}
else {
@@ -880,11 +878,14 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
else {
for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
if (BKE_image_has_opengl_texture(ima)) {
- if (ima->gputexture[TEXTARGET_TEXTURE_2D]) {
- GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
+ if (tex != NULL) {
+ GPU_texture_bind(tex, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ GPU_texture_unbind(tex);
+ }
}
}
else {
@@ -897,14 +898,16 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+ GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
- if ((ima->gputexture[TEXTARGET_TEXTURE_2D] == NULL) || (ibuf == NULL) || (w == 0) || (h == 0)) {
+ if ((tex == NULL) || (ibuf == NULL) || (w == 0) || (h == 0)) {
/* Full reload of texture. */
GPU_free_image(ima);
}
else {
/* Partial update of texture. */
- GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
+ GPU_texture_bind(tex, 0);
gpu_texture_update_from_ibuf(ima, ibuf, x, y, w, h);
@@ -915,378 +918,12 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
}
- GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
+ GPU_texture_unbind(tex);
}
BKE_image_release_ibuf(ima, ibuf, NULL);
}
-/* *************************** Transfer functions *************************** */
-
-enum {
- TFUNC_FLAME_SPECTRUM = 0,
- TFUNC_COLOR_RAMP = 1,
-};
-
-#define TFUNC_WIDTH 256
-
-#ifdef WITH_SMOKE
-static void create_flame_spectrum_texture(float *data)
-{
-# define FIRE_THRESH 7
-# define MAX_FIRE_ALPHA 0.06f
-# define FULL_ON_FIRE 100
-
- float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
-
- blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
-
- for (int i = 0; i < 16; i++) {
- for (int j = 0; j < 16; j++) {
- for (int k = 0; k < TFUNC_WIDTH; k++) {
- int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4;
- if (k >= FIRE_THRESH) {
- spec_pixels[index] = (data[k * 4]);
- spec_pixels[index + 1] = (data[k * 4 + 1]);
- spec_pixels[index + 2] = (data[k * 4 + 2]);
- spec_pixels[index + 3] = MAX_FIRE_ALPHA *
- ((k > FULL_ON_FIRE) ?
- 1.0f :
- (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
- }
- else {
- zero_v4(&spec_pixels[index]);
- }
- }
- }
- }
-
- memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH);
-
- MEM_freeN(spec_pixels);
-
-# undef FIRE_THRESH
-# undef MAX_FIRE_ALPHA
-# undef FULL_ON_FIRE
-}
-
-static void create_color_ramp(const ColorBand *coba, float *data)
-{
- for (int i = 0; i < TFUNC_WIDTH; i++) {
- BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
- }
-}
-
-static GPUTexture *create_transfer_function(int type, const ColorBand *coba)
-{
- float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__);
-
- switch (type) {
- case TFUNC_FLAME_SPECTRUM:
- create_flame_spectrum_texture(data);
- break;
- case TFUNC_COLOR_RAMP:
- create_color_ramp(coba, data);
- break;
- }
-
- GPUTexture *tex = GPU_texture_create_1d(TFUNC_WIDTH, GPU_RGBA8, data, NULL);
-
- MEM_freeN(data);
-
- return tex;
-}
-
-static void swizzle_texture_channel_rrrr(GPUTexture *tex)
-{
- GPU_texture_bind(tex, 0);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
- GPU_texture_unbind(tex);
-}
-
-static GPUTexture *create_field_texture(SmokeDomainSettings *sds)
-{
- float *field = NULL;
-
- switch (sds->coba_field) {
- case FLUID_FIELD_DENSITY:
- field = smoke_get_density(sds->fluid);
- break;
- case FLUID_FIELD_HEAT:
- field = smoke_get_heat(sds->fluid);
- break;
- case FLUID_FIELD_FUEL:
- field = smoke_get_fuel(sds->fluid);
- break;
- case FLUID_FIELD_REACT:
- field = smoke_get_react(sds->fluid);
- break;
- case FLUID_FIELD_FLAME:
- field = smoke_get_flame(sds->fluid);
- break;
- case FLUID_FIELD_VELOCITY_X:
- field = smoke_get_velocity_x(sds->fluid);
- break;
- case FLUID_FIELD_VELOCITY_Y:
- field = smoke_get_velocity_y(sds->fluid);
- break;
- case FLUID_FIELD_VELOCITY_Z:
- field = smoke_get_velocity_z(sds->fluid);
- break;
- case FLUID_FIELD_COLOR_R:
- field = smoke_get_color_r(sds->fluid);
- break;
- case FLUID_FIELD_COLOR_G:
- field = smoke_get_color_g(sds->fluid);
- break;
- case FLUID_FIELD_COLOR_B:
- field = smoke_get_color_b(sds->fluid);
- break;
- case FLUID_FIELD_FORCE_X:
- field = smoke_get_force_x(sds->fluid);
- break;
- case FLUID_FIELD_FORCE_Y:
- field = smoke_get_force_y(sds->fluid);
- break;
- case FLUID_FIELD_FORCE_Z:
- field = smoke_get_force_z(sds->fluid);
- break;
- default:
- return NULL;
- }
-
- GPUTexture *tex = GPU_texture_create_nD(
- sds->res[0], sds->res[1], sds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
-
- swizzle_texture_channel_rrrr(tex);
- return tex;
-}
-
-static GPUTexture *create_density_texture(SmokeDomainSettings *sds, int highres)
-{
- float *data = NULL, *source;
- int cell_count = (highres) ? smoke_turbulence_get_cells(sds->wt) : sds->total_cells;
- const bool has_color = (highres) ? smoke_turbulence_has_colors(sds->wt) :
- smoke_has_colors(sds->fluid);
- int *dim = (highres) ? sds->res_wt : sds->res;
- eGPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8;
-
- if (has_color) {
- data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
- }
-
- if (highres) {
- if (has_color) {
- smoke_turbulence_get_rgba(sds->wt, data, 0);
- }
- else {
- source = smoke_turbulence_get_density(sds->wt);
- }
- }
- else {
- if (has_color) {
- smoke_get_rgba(sds->fluid, data, 0);
- }
- else {
- source = smoke_get_density(sds->fluid);
- }
- }
-
- GPUTexture *tex = GPU_texture_create_nD(dim[0],
- dim[1],
- dim[2],
- 3,
- (has_color) ? data : source,
- format,
- GPU_DATA_FLOAT,
- 0,
- true,
- NULL);
- if (data) {
- MEM_freeN(data);
- }
-
- if (format == GPU_R8) {
- /* Swizzle the RGBA components to read the Red channel so
- * that the shader stay the same for colored and non color
- * density textures. */
- swizzle_texture_channel_rrrr(tex);
- }
- return tex;
-}
-
-static GPUTexture *create_flame_texture(SmokeDomainSettings *sds, int highres)
-{
- float *source = NULL;
- const bool has_fuel = (highres) ? smoke_turbulence_has_fuel(sds->wt) :
- smoke_has_fuel(sds->fluid);
- int *dim = (highres) ? sds->res_wt : sds->res;
-
- if (!has_fuel) {
- return NULL;
- }
-
- if (highres) {
- source = smoke_turbulence_get_flame(sds->wt);
- }
- else {
- source = smoke_get_flame(sds->fluid);
- }
-
- GPUTexture *tex = GPU_texture_create_nD(
- dim[0], dim[1], dim[2], 3, source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
-
- swizzle_texture_channel_rrrr(tex);
-
- return tex;
-}
-#endif /* WITH_SMOKE */
-
-void GPU_free_smoke(SmokeModifierData *smd)
-{
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
- if (smd->domain->tex) {
- GPU_texture_free(smd->domain->tex);
- }
- smd->domain->tex = NULL;
-
- if (smd->domain->tex_shadow) {
- GPU_texture_free(smd->domain->tex_shadow);
- }
- smd->domain->tex_shadow = NULL;
-
- if (smd->domain->tex_flame) {
- GPU_texture_free(smd->domain->tex_flame);
- }
- smd->domain->tex_flame = NULL;
-
- if (smd->domain->tex_flame_coba) {
- GPU_texture_free(smd->domain->tex_flame_coba);
- }
- smd->domain->tex_flame_coba = NULL;
-
- if (smd->domain->tex_coba) {
- GPU_texture_free(smd->domain->tex_coba);
- }
- smd->domain->tex_coba = NULL;
-
- if (smd->domain->tex_field) {
- GPU_texture_free(smd->domain->tex_field);
- }
- smd->domain->tex_field = NULL;
- }
-}
-
-void GPU_create_smoke_coba_field(SmokeModifierData *smd)
-{
-#ifdef WITH_SMOKE
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- SmokeDomainSettings *sds = smd->domain;
-
- if (!sds->tex_field) {
- sds->tex_field = create_field_texture(sds);
- }
- if (!sds->tex_coba) {
- sds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, sds->coba);
- }
- }
-#else // WITH_SMOKE
- smd->domain->tex_field = NULL;
-#endif // WITH_SMOKE
-}
-
-void GPU_create_smoke(SmokeModifierData *smd, int highres)
-{
-#ifdef WITH_SMOKE
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- SmokeDomainSettings *sds = smd->domain;
-
- if (!sds->tex) {
- sds->tex = create_density_texture(sds, highres);
- }
- if (!sds->tex_flame) {
- sds->tex_flame = create_flame_texture(sds, highres);
- }
- if (!sds->tex_flame_coba && sds->tex_flame) {
- sds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL);
- }
- if (!sds->tex_shadow) {
- sds->tex_shadow = GPU_texture_create_nD(sds->res[0],
- sds->res[1],
- sds->res[2],
- 3,
- sds->shadow,
- GPU_R8,
- GPU_DATA_FLOAT,
- 0,
- true,
- NULL);
- }
- }
-#else // WITH_SMOKE
- (void)highres;
- smd->domain->tex = NULL;
- smd->domain->tex_flame = NULL;
- smd->domain->tex_flame_coba = NULL;
- smd->domain->tex_shadow = NULL;
-#endif // WITH_SMOKE
-}
-
-void GPU_create_smoke_velocity(SmokeModifierData *smd)
-{
-#ifdef WITH_SMOKE
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- SmokeDomainSettings *sds = smd->domain;
-
- const float *vel_x = smoke_get_velocity_x(sds->fluid);
- const float *vel_y = smoke_get_velocity_y(sds->fluid);
- const float *vel_z = smoke_get_velocity_z(sds->fluid);
-
- if (ELEM(NULL, vel_x, vel_y, vel_z)) {
- return;
- }
-
- if (!sds->tex_velocity_x) {
- sds->tex_velocity_x = GPU_texture_create_3d(
- sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_x, NULL);
- sds->tex_velocity_y = GPU_texture_create_3d(
- sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_y, NULL);
- sds->tex_velocity_z = GPU_texture_create_3d(
- sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_z, NULL);
- }
- }
-#else // WITH_SMOKE
- smd->domain->tex_velocity_x = NULL;
- smd->domain->tex_velocity_y = NULL;
- smd->domain->tex_velocity_z = NULL;
-#endif // WITH_SMOKE
-}
-
-/* TODO Unify with the other GPU_free_smoke. */
-void GPU_free_smoke_velocity(SmokeModifierData *smd)
-{
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
- if (smd->domain->tex_velocity_x) {
- GPU_texture_free(smd->domain->tex_velocity_x);
- }
-
- if (smd->domain->tex_velocity_y) {
- GPU_texture_free(smd->domain->tex_velocity_y);
- }
-
- if (smd->domain->tex_velocity_z) {
- GPU_texture_free(smd->domain->tex_velocity_z);
- }
-
- smd->domain->tex_velocity_x = NULL;
- smd->domain->tex_velocity_y = NULL;
- smd->domain->tex_velocity_z = NULL;
- }
-}
-
static LinkNode *image_free_queue = NULL;
static ThreadMutex img_queue_mutex = BLI_MUTEX_INITIALIZER;
@@ -1323,11 +960,13 @@ void GPU_free_unused_buffers(Main *bmain)
static void gpu_free_image_immediate(Image *ima)
{
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- /* free glsl image binding */
- if (ima->gputexture[i]) {
- GPU_texture_free(ima->gputexture[i]);
- ima->gputexture[i] = NULL;
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ /* free glsl image binding */
+ if (tile->gputexture[i] != NULL) {
+ GPU_texture_free(tile->gputexture[i]);
+ tile->gputexture[i] = NULL;
+ }
}
}
diff --git a/source/blender/gpu/intern/gpu_draw_smoke.c b/source/blender/gpu/intern/gpu_draw_smoke.c
new file mode 100644
index 00000000000..5cca472148a
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_draw_smoke.c
@@ -0,0 +1,416 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * GPU fluid drawing functions.
+ */
+
+#include <string.h>
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_fluid_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_colorband.h"
+
+#include "GPU_draw.h"
+#include "GPU_glew.h"
+#include "GPU_texture.h"
+
+#ifdef WITH_FLUID
+# include "manta_fluid_API.h"
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Private API
+ * \{ */
+
+#ifdef WITH_FLUID
+
+enum {
+ TFUNC_FLAME_SPECTRUM = 0,
+ TFUNC_COLOR_RAMP = 1,
+};
+
+# define TFUNC_WIDTH 256
+
+static void create_flame_spectrum_texture(float *data)
+{
+# define FIRE_THRESH 7
+# define MAX_FIRE_ALPHA 0.06f
+# define FULL_ON_FIRE 100
+
+ float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
+
+ blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
+
+ for (int i = 0; i < 16; i++) {
+ for (int j = 0; j < 16; j++) {
+ for (int k = 0; k < TFUNC_WIDTH; k++) {
+ int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4;
+ if (k >= FIRE_THRESH) {
+ spec_pixels[index] = (data[k * 4]);
+ spec_pixels[index + 1] = (data[k * 4 + 1]);
+ spec_pixels[index + 2] = (data[k * 4 + 2]);
+ spec_pixels[index + 3] = MAX_FIRE_ALPHA *
+ ((k > FULL_ON_FIRE) ?
+ 1.0f :
+ (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
+ }
+ else {
+ zero_v4(&spec_pixels[index]);
+ }
+ }
+ }
+ }
+
+ memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH);
+
+ MEM_freeN(spec_pixels);
+
+# undef FIRE_THRESH
+# undef MAX_FIRE_ALPHA
+# undef FULL_ON_FIRE
+}
+
+static void create_color_ramp(const struct ColorBand *coba, float *data)
+{
+ for (int i = 0; i < TFUNC_WIDTH; i++) {
+ BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
+ }
+}
+
+static GPUTexture *create_transfer_function(int type, const struct ColorBand *coba)
+{
+ float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__);
+
+ switch (type) {
+ case TFUNC_FLAME_SPECTRUM:
+ create_flame_spectrum_texture(data);
+ break;
+ case TFUNC_COLOR_RAMP:
+ create_color_ramp(coba, data);
+ break;
+ }
+
+ GPUTexture *tex = GPU_texture_create_1d(TFUNC_WIDTH, GPU_RGBA8, data, NULL);
+
+ MEM_freeN(data);
+
+ return tex;
+}
+
+static void swizzle_texture_channel_rrrr(GPUTexture *tex)
+{
+ GPU_texture_bind(tex, 0);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
+ GPU_texture_unbind(tex);
+}
+
+static GPUTexture *create_field_texture(FluidDomainSettings *mds)
+{
+ float *field = NULL;
+
+ switch (mds->coba_field) {
+ case FLUID_DOMAIN_FIELD_DENSITY:
+ field = manta_smoke_get_density(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_HEAT:
+ field = manta_smoke_get_heat(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_FUEL:
+ field = manta_smoke_get_fuel(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_REACT:
+ field = manta_smoke_get_react(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_FLAME:
+ field = manta_smoke_get_flame(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_VELOCITY_X:
+ field = manta_get_velocity_x(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_VELOCITY_Y:
+ field = manta_get_velocity_y(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_VELOCITY_Z:
+ field = manta_get_velocity_z(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_COLOR_R:
+ field = manta_smoke_get_color_r(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_COLOR_G:
+ field = manta_smoke_get_color_g(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_COLOR_B:
+ field = manta_smoke_get_color_b(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_FORCE_X:
+ field = manta_get_force_x(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_FORCE_Y:
+ field = manta_get_force_y(mds->fluid);
+ break;
+ case FLUID_DOMAIN_FIELD_FORCE_Z:
+ field = manta_get_force_z(mds->fluid);
+ break;
+ default:
+ return NULL;
+ }
+
+ GPUTexture *tex = GPU_texture_create_nD(
+ mds->res[0], mds->res[1], mds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
+
+ swizzle_texture_channel_rrrr(tex);
+ return tex;
+}
+
+static GPUTexture *create_density_texture(FluidDomainSettings *mds, int highres)
+{
+ float *data = NULL, *source;
+ int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells;
+ const bool has_color = (highres) ? manta_smoke_turbulence_has_colors(mds->fluid) :
+ manta_smoke_has_colors(mds->fluid);
+ int *dim = (highres) ? mds->res_noise : mds->res;
+ eGPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8;
+
+ if (has_color) {
+ data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
+ }
+
+ if (highres) {
+ if (has_color) {
+ manta_smoke_turbulence_get_rgba(mds->fluid, data, 0);
+ }
+ else {
+ source = manta_smoke_turbulence_get_density(mds->fluid);
+ }
+ }
+ else {
+ if (has_color) {
+ manta_smoke_get_rgba(mds->fluid, data, 0);
+ }
+ else {
+ source = manta_smoke_get_density(mds->fluid);
+ }
+ }
+
+ GPUTexture *tex = GPU_texture_create_nD(dim[0],
+ dim[1],
+ dim[2],
+ 3,
+ (has_color) ? data : source,
+ format,
+ GPU_DATA_FLOAT,
+ 0,
+ true,
+ NULL);
+ if (data) {
+ MEM_freeN(data);
+ }
+
+ if (format == GPU_R8) {
+ /* Swizzle the RGBA components to read the Red channel so
+ * that the shader stay the same for colored and non color
+ * density textures. */
+ swizzle_texture_channel_rrrr(tex);
+ }
+ return tex;
+}
+
+static GPUTexture *create_flame_texture(FluidDomainSettings *mds, int highres)
+{
+ float *source = NULL;
+ const bool has_fuel = (highres) ? manta_smoke_turbulence_has_fuel(mds->fluid) :
+ manta_smoke_has_fuel(mds->fluid);
+ int *dim = (highres) ? mds->res_noise : mds->res;
+
+ if (!has_fuel) {
+ return NULL;
+ }
+
+ if (highres) {
+ source = manta_smoke_turbulence_get_flame(mds->fluid);
+ }
+ else {
+ source = manta_smoke_get_flame(mds->fluid);
+ }
+
+ GPUTexture *tex = GPU_texture_create_nD(
+ dim[0], dim[1], dim[2], 3, source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
+
+ swizzle_texture_channel_rrrr(tex);
+
+ return tex;
+}
+
+#endif /* WITH_FLUID */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
+
+void GPU_free_smoke(FluidModifierData *mmd)
+{
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) {
+ if (mmd->domain->tex) {
+ GPU_texture_free(mmd->domain->tex);
+ }
+ mmd->domain->tex = NULL;
+
+ if (mmd->domain->tex_shadow) {
+ GPU_texture_free(mmd->domain->tex_shadow);
+ }
+ mmd->domain->tex_shadow = NULL;
+
+ if (mmd->domain->tex_flame) {
+ GPU_texture_free(mmd->domain->tex_flame);
+ }
+ mmd->domain->tex_flame = NULL;
+
+ if (mmd->domain->tex_flame_coba) {
+ GPU_texture_free(mmd->domain->tex_flame_coba);
+ }
+ mmd->domain->tex_flame_coba = NULL;
+
+ if (mmd->domain->tex_coba) {
+ GPU_texture_free(mmd->domain->tex_coba);
+ }
+ mmd->domain->tex_coba = NULL;
+
+ if (mmd->domain->tex_field) {
+ GPU_texture_free(mmd->domain->tex_field);
+ }
+ mmd->domain->tex_field = NULL;
+ }
+}
+
+void GPU_create_smoke_coba_field(FluidModifierData *mmd)
+{
+#ifndef WITH_FLUID
+ UNUSED_VARS(mmd);
+#else
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN) {
+ FluidDomainSettings *mds = mmd->domain;
+
+ if (!mds->tex_field) {
+ mds->tex_field = create_field_texture(mds);
+ }
+ if (!mds->tex_coba) {
+ mds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, mds->coba);
+ }
+ }
+#endif
+}
+
+void GPU_create_smoke(FluidModifierData *mmd, int highres)
+{
+#ifndef WITH_FLUID
+ UNUSED_VARS(mmd, highres);
+#else
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN) {
+ FluidDomainSettings *mds = mmd->domain;
+
+ if (!mds->tex) {
+ mds->tex = create_density_texture(mds, highres);
+ }
+ if (!mds->tex_flame) {
+ mds->tex_flame = create_flame_texture(mds, highres);
+ }
+ if (!mds->tex_flame_coba && mds->tex_flame) {
+ mds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL);
+ }
+ if (!mds->tex_shadow) {
+ mds->tex_shadow = GPU_texture_create_nD(mds->res[0],
+ mds->res[1],
+ mds->res[2],
+ 3,
+ manta_smoke_get_shadow(mds->fluid),
+ GPU_R8,
+ GPU_DATA_FLOAT,
+ 0,
+ true,
+ NULL);
+ }
+ }
+#endif /* WITH_FLUID */
+}
+
+void GPU_create_smoke_velocity(FluidModifierData *mmd)
+{
+#ifndef WITH_FLUID
+ UNUSED_VARS(mmd);
+#else
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN) {
+ FluidDomainSettings *mds = mmd->domain;
+
+ const float *vel_x = manta_get_velocity_x(mds->fluid);
+ const float *vel_y = manta_get_velocity_y(mds->fluid);
+ const float *vel_z = manta_get_velocity_z(mds->fluid);
+
+ if (ELEM(NULL, vel_x, vel_y, vel_z)) {
+ return;
+ }
+
+ if (!mds->tex_velocity_x) {
+ mds->tex_velocity_x = GPU_texture_create_3d(
+ mds->res[0], mds->res[1], mds->res[2], GPU_R16F, vel_x, NULL);
+ mds->tex_velocity_y = GPU_texture_create_3d(
+ mds->res[0], mds->res[1], mds->res[2], GPU_R16F, vel_y, NULL);
+ mds->tex_velocity_z = GPU_texture_create_3d(
+ mds->res[0], mds->res[1], mds->res[2], GPU_R16F, vel_z, NULL);
+ }
+ }
+#endif /* WITH_FLUID */
+}
+
+/* TODO Unify with the other GPU_free_smoke. */
+void GPU_free_smoke_velocity(FluidModifierData *mmd)
+{
+ if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) {
+ if (mmd->domain->tex_velocity_x) {
+ GPU_texture_free(mmd->domain->tex_velocity_x);
+ }
+
+ if (mmd->domain->tex_velocity_y) {
+ GPU_texture_free(mmd->domain->tex_velocity_y);
+ }
+
+ if (mmd->domain->tex_velocity_z) {
+ GPU_texture_free(mmd->domain->tex_velocity_z);
+ }
+
+ mmd->domain->tex_velocity_x = NULL;
+ mmd->domain->tex_velocity_y = NULL;
+ mmd->domain->tex_velocity_z = NULL;
+ }
+}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c
index 518829d1c78..036588b4a48 100644
--- a/source/blender/gpu/intern/gpu_element.c
+++ b/source/blender/gpu/intern/gpu_element.c
@@ -242,6 +242,15 @@ void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length)
{
GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
+ GPU_indexbuf_create_subrange_in_place(elem, elem_src, start, length);
+ return elem;
+}
+
+void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem,
+ GPUIndexBuf *elem_src,
+ uint start,
+ uint length)
+{
BLI_assert(elem_src && !elem_src->is_subrange);
BLI_assert((length == 0) || (start + length <= elem_src->index_len));
#if GPU_TRACK_INDEX_RANGE
@@ -253,7 +262,6 @@ GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uin
elem->src = elem_src;
elem->index_start = start;
elem->index_len = length;
- return elem;
}
#if GPU_TRACK_INDEX_RANGE
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
index 3a38eb5c600..08c36e24920 100644
--- a/source/blender/gpu/intern/gpu_material_library.h
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -316,7 +316,7 @@ static GPUMaterialLibrary gpu_shader_material_mapping_library = {
static GPUMaterialLibrary gpu_shader_material_map_range_library = {
.code = datatoc_gpu_shader_material_map_range_glsl,
- .dependencies = {NULL},
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
};
static GPUMaterialLibrary gpu_shader_material_math_library = {
diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c
index fb0dffb58d1..5e44a950ba7 100644
--- a/source/blender/gpu/intern/gpu_matrix.c
+++ b/source/blender/gpu/intern/gpu_matrix.c
@@ -535,6 +535,11 @@ bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *precalc,
&precalc->dims.ymax,
&precalc->dims.zmin,
&precalc->dims.zmax);
+ if (isinf(precalc->dims.zmax)) {
+ /* We cannot retrieve the actual value of the clip_end.
+ * Use `FLT_MAX` to avoid nans. */
+ precalc->dims.zmax = FLT_MAX;
+ }
for (int i = 0; i < 4; i++) {
precalc->view[i] = (float)view[i];
}
diff --git a/source/blender/gpu/intern/gpu_platform.c b/source/blender/gpu/intern/gpu_platform.c
index 871052bb070..a758787466f 100644
--- a/source/blender/gpu/intern/gpu_platform.c
+++ b/source/blender/gpu/intern/gpu_platform.c
@@ -158,7 +158,8 @@ void gpu_platform_init(void)
if (strstr(renderer, "UHD Graphics") ||
/* Not UHD but affected by the same bugs. */
- strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2")) {
+ strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2") ||
+ strstr(renderer, "Whiskey Lake")) {
GPG.device |= GPU_DEVICE_INTEL_UHD;
}
}
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 905def8251b..2b4d7feae74 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -102,20 +102,7 @@ extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
extern char datatoc_gpu_shader_3D_passthrough_vert_glsl[];
extern char datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl[];
-extern char datatoc_gpu_shader_instance_vert_glsl[];
extern char datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl[];
-extern char datatoc_gpu_shader_instance_variying_size_variying_id_vert_glsl[];
-extern char datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl[];
-extern char datatoc_gpu_shader_instance_screenspace_variying_color_vert_glsl[];
-extern char datatoc_gpu_shader_instance_screen_aligned_vert_glsl[];
-extern char datatoc_gpu_shader_instance_camera_vert_glsl[];
-extern char datatoc_gpu_shader_instance_distance_line_vert_glsl[];
-extern char datatoc_gpu_shader_instance_edges_variying_color_geom_glsl[];
-extern char datatoc_gpu_shader_instance_edges_variying_color_vert_glsl[];
-extern char datatoc_gpu_shader_instance_mball_handles_vert_glsl[];
-
-extern char datatoc_gpu_shader_3D_groundpoint_vert_glsl[];
-extern char datatoc_gpu_shader_3D_groundline_geom_glsl[];
extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[];
extern char datatoc_gpu_shader_point_uniform_color_aa_frag_glsl[];
@@ -141,14 +128,10 @@ extern char datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl[];
extern char datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl[];
extern char datatoc_gpu_shader_2D_line_dashed_frag_glsl[];
-extern char datatoc_gpu_shader_2D_line_dashed_geom_glsl[];
extern char datatoc_gpu_shader_3D_line_dashed_uniform_color_vert_glsl[];
extern char datatoc_gpu_shader_text_vert_glsl[];
-extern char datatoc_gpu_shader_text_geom_glsl[];
extern char datatoc_gpu_shader_text_frag_glsl[];
-extern char datatoc_gpu_shader_text_simple_vert_glsl[];
-extern char datatoc_gpu_shader_text_simple_geom_glsl[];
extern char datatoc_gpu_shader_keyframe_diamond_vert_glsl[];
extern char datatoc_gpu_shader_keyframe_diamond_frag_glsl[];
@@ -885,13 +868,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
[GPU_SHADER_TEXT] =
{
.vert = datatoc_gpu_shader_text_vert_glsl,
- .geom = datatoc_gpu_shader_text_geom_glsl,
- .frag = datatoc_gpu_shader_text_frag_glsl,
- },
- [GPU_SHADER_TEXT_SIMPLE] =
- {
- .vert = datatoc_gpu_shader_text_simple_vert_glsl,
- .geom = datatoc_gpu_shader_text_simple_geom_glsl,
.frag = datatoc_gpu_shader_text_frag_glsl,
},
[GPU_SHADER_KEYFRAME_DIAMOND] =
@@ -1110,70 +1086,17 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.frag = datatoc_gpu_shader_uniform_color_frag_glsl,
},
- [GPU_SHADER_3D_GROUNDPOINT] =
- {
- .vert = datatoc_gpu_shader_3D_groundpoint_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_frag_glsl,
- },
- [GPU_SHADER_3D_GROUNDLINE] =
- {
- .vert = datatoc_gpu_shader_3D_passthrough_vert_glsl,
- .geom = datatoc_gpu_shader_3D_groundline_geom_glsl,
- .frag = datatoc_gpu_shader_uniform_color_frag_glsl,
- },
-
[GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR] =
{
.vert = datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl,
- .geom = datatoc_gpu_shader_2D_line_dashed_geom_glsl,
.frag = datatoc_gpu_shader_2D_line_dashed_frag_glsl,
},
[GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR] =
{
.vert = datatoc_gpu_shader_3D_line_dashed_uniform_color_vert_glsl,
- .geom = datatoc_gpu_shader_2D_line_dashed_geom_glsl,
.frag = datatoc_gpu_shader_2D_line_dashed_frag_glsl,
},
- [GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR] =
- {
- .vert = datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl,
- .frag = datatoc_gpu_shader_simple_lighting_frag_glsl,
- .defs = "#define USE_INSTANCE_COLOR\n",
- },
- [GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR] =
- {
- .vert = datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
- [GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR] =
- {
- .vert = datatoc_gpu_shader_instance_screenspace_variying_color_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
- [GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS] =
- {
- .vert = datatoc_gpu_shader_instance_screen_aligned_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- .defs = "#define AXIS_NAME\n",
- },
- [GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED] =
- {
- .vert = datatoc_gpu_shader_instance_screen_aligned_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
-
- [GPU_SHADER_CAMERA] =
- {
- .vert = datatoc_gpu_shader_instance_camera_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
- [GPU_SHADER_DISTANCE_LINES] =
- {
- .vert = datatoc_gpu_shader_instance_distance_line_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
-
[GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR] =
{
.vert = datatoc_gpu_shader_2D_vert_glsl,
@@ -1230,34 +1153,12 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.frag = datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl,
},
- [GPU_SHADER_INSTANCE_UNIFORM_COLOR] =
- {
- .vert = datatoc_gpu_shader_instance_vert_glsl,
- .frag = datatoc_gpu_shader_uniform_color_frag_glsl,
- },
- [GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE] =
- {
- .vert = datatoc_gpu_shader_instance_variying_size_variying_id_vert_glsl,
- .frag = datatoc_gpu_shader_flat_id_frag_glsl,
- .defs = "#define UNIFORM_SCALE\n",
- },
[GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE] =
{
.vert = datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl,
.frag = datatoc_gpu_shader_flat_color_frag_glsl,
.defs = "#define UNIFORM_SCALE\n",
},
- [GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE] =
- {
- .vert = datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
- [GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR] =
- {
- .vert = datatoc_gpu_shader_instance_edges_variying_color_vert_glsl,
- .geom = datatoc_gpu_shader_instance_edges_variying_color_geom_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
[GPU_SHADER_2D_AREA_EDGES] =
{
@@ -1371,22 +1272,11 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
GPU_SHADER_3D_UNIFORM_COLOR,
GPU_SHADER_3D_SMOOTH_COLOR,
GPU_SHADER_3D_DEPTH_ONLY,
- GPU_SHADER_CAMERA,
GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE,
- GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE,
GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
- GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR,
- GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED,
-
- GPU_SHADER_3D_GROUNDLINE,
- GPU_SHADER_3D_GROUNDPOINT,
- GPU_SHADER_DISTANCE_LINES,
- GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR) ||
- ELEM(shader,
GPU_SHADER_3D_FLAT_COLOR,
- GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR,
- GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE));
+ GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR));
const char *world_clip_lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl;
const char *world_clip_def = "#define USE_WORLD_CLIP_PLANES\n";
/* In rare cases geometry shaders calculate clipping themselves. */
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c
index eecbcb9ec94..1df7e68e08b 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.c
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.c
@@ -196,6 +196,19 @@ void GPU_vertbuf_attr_fill(GPUVertBuf *verts, uint a_idx, const void *data)
GPU_vertbuf_attr_fill_stride(verts, a_idx, stride, data);
}
+/** Fills a whole vertex (all attribs). Data must match packed layout. */
+void GPU_vertbuf_vert_set(GPUVertBuf *verts, uint v_idx, const void *data)
+{
+ const GPUVertFormat *format = &verts->format;
+
+#if TRUST_NO_ONE
+ assert(v_idx < verts->vertex_alloc);
+ assert(verts->data != NULL);
+#endif
+ verts->dirty = true;
+ memcpy((GLubyte *)verts->data + v_idx * format->stride, data, format->stride);
+}
+
void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts, uint a_idx, uint stride, const void *data)
{
const GPUVertFormat *format = &verts->format;
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index 73f588ba3d1..59696d1fa41 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -29,8 +29,6 @@
#include "BLI_rect.h"
#include "BLI_memblock.h"
-#include "BIF_gl.h"
-
#include "DNA_vec_types.h"
#include "DNA_userdef_types.h"
@@ -147,6 +145,7 @@ GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs)
GPU_framebuffer_ensure_config(
&viewport->fbl->depth_only_fb,
{GPU_ATTACHMENT_TEXTURE(viewport->txl->depth), GPU_ATTACHMENT_NONE});
+ /* TODO infront buffer */
}
return viewport;
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
index b0fa9eaed21..3254a7e1508 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
@@ -90,7 +90,7 @@ void main()
stretch = stretch;
stretch = 1.0 - stretch * stretch;
#else
- float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio, -totalAreaRatioInv);
+ float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio, totalAreaRatioInv);
#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
index a29335046f2..44a9db76834 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
@@ -17,13 +17,16 @@ uniform float dash_factor; /* if > 1.0, solid line. */
uniform int colors_len; /* Enabled if > 0, 1 for solid line. */
uniform vec4 colors[32];
-noperspective in float distance_along_line;
-noperspective in vec4 color_geom;
+flat in vec4 color_vert;
+
+noperspective in vec2 stipple_pos;
+flat in vec2 stipple_start;
out vec4 fragColor;
void main()
{
+ float distance_along_line = distance(stipple_pos, stipple_start);
/* Multi-color option. */
if (colors_len > 0) {
/* Solid line case, simple. */
@@ -40,13 +43,13 @@ void main()
else {
/* Solid line case, simple. */
if (dash_factor >= 1.0f) {
- fragColor = color_geom;
+ fragColor = color_vert;
}
/* Actually dashed line... */
else {
float normalized_distance = fract(distance_along_line / dash_width);
if (normalized_distance <= dash_factor) {
- fragColor = color_geom;
+ fragColor = color_vert;
}
else {
discard;
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl
deleted file mode 100644
index 584a179a9ac..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl
+++ /dev/null
@@ -1,65 +0,0 @@
-
-/*
- * Geometry Shader for dashed lines, with uniform multi-color(s),
- * or any single-color, and unary thickness.
- *
- * Dashed is performed in screen space.
- */
-
-/* Make to be used with dynamic batching so no Model Matrix needed */
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec2 viewport_size;
-
-/* Uniforms from fragment shader,
- * used here to optimize out useless computation in case of solid line. */
-uniform float dash_factor; /* if > 1.0, solid line. */
-uniform int colors_len; /* Enabled if > 0, 1 for solid line. */
-
-layout(lines) in;
-
-in vec4 color_vert[];
-
-layout(line_strip, max_vertices = 2) out;
-noperspective out float distance_along_line;
-noperspective out vec4 color_geom;
-
-void main()
-{
- vec4 v1 = gl_in[0].gl_Position;
- vec4 v2 = gl_in[1].gl_Position;
-
- gl_Position = v1;
- color_geom = color_vert[0];
- distance_along_line = 0.0f;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance);
-#endif
- EmitVertex();
-
- gl_Position = v2;
- color_geom = color_vert[1];
- if ((colors_len == 1) || (dash_factor >= 1.0f)) {
- /* Solid line, optimize out distance computation! */
- distance_along_line = 0.0f;
- }
- else {
- vec2 p1 = (v1.xy / v1.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range.
- p1 = p1 * viewport_size; // <- 'virtual' screen coordinates.
-
- vec2 p2 = (v2.xy / v2.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range.
- p2 = p2 * viewport_size; // <- 'virtual' screen coordinates.
-
- distance_along_line = distance(p1, p2);
- }
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
-#endif
- EmitVertex();
-
- EndPrimitive();
-
- /* Note: we could also use similar approach as diag_stripes_frag,
- * but this would give us dashed 'anchored' to the screen, and not to one end of the line... */
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
index 8b5a5cd8c9a..15362d020e4 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
@@ -9,13 +9,19 @@
uniform mat4 ModelViewProjectionMatrix;
uniform vec4 color;
+uniform vec2 viewport_size;
in vec2 pos;
-out vec4 color_vert;
+flat out vec4 color_vert;
+
+/* We leverage hardware interpolation to compute distance along the line. */
+noperspective out vec2 stipple_pos; /* In screen space */
+flat out vec2 stipple_start; /* In screen space */
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ stipple_start = stipple_pos = viewport_size * 0.5 * (gl_Position.xy / gl_Position.w);
color_vert = color;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl
deleted file mode 100644
index 336f310837e..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl
+++ /dev/null
@@ -1,60 +0,0 @@
-
-// Draw dashed lines, perforated in screen space, with non-unary width.
-
-/* Make to be used with dynamic batching so no Model Matrix needed */
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec2 viewport_size;
-
-/* Width of the generated 'line'. */
-uniform float width; /* in pixels, screen space. */
-
-/* Uniforms from fragment shader,
- * used here to optimize out useless computation in case of solid line. */
-uniform float dash_factor; /* if > 1.0, solid line. */
-uniform int colors_len; /* Enabled if > 0, 1 for solid line. */
-
-layout(lines) in;
-
-layout(triangle_strip, max_vertices = 4) out;
-noperspective out float distance_along_line;
-
-void main()
-{
- vec4 v1 = gl_in[0].gl_Position;
- vec4 v2 = gl_in[1].gl_Position;
-
- /* Width, from 2D screen space in pixels, to ModelViewProjection space of each input vertices. */
- float w1 = (width / viewport_size) * v1.w * 2.0;
- float w2 = (width / viewport_size) * v2.w * 2.0;
-
- /* Normalized vector parallel to screen and orthogonal to line. */
- vec4 wdir = normalize(vec4(v1.y - v2.y, v2.x - v1.x, 0.0, 0.0))
-
- distance_along_line = 0.0f;
- gl_Position = v1 + (wdir * w1);
- EmitVertex();
-
- gl_Position = v1 - (wdir * w1);
- EmitVertex();
-
- if ((colors_len == 1) || (dash_factor >= 1.0f)) {
- /* Solid line, optimize out distance computation! */
- distance_along_line = 0.0f;
- }
- else {
- vec2 p1 = (v1.xy / v1.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range.
- p1 = p1 * viewport_size; // <- 'virtual' screen coordinates.
-
- vec2 p2 = (v2.xy / v2.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range.
- p2 = p2 * viewport_size; // <- 'virtual' screen coordinates.
-
- distance_along_line = distance(p1, p2);
- }
- gl_Position = v2 + (wdir * w2);
- EmitVertex();
-
- gl_Position = v2 - (wdir * w2);
- EmitVertex();
-
- EndPrimitive();
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl
deleted file mode 100644
index 03bee1b4e06..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl
+++ /dev/null
@@ -1,25 +0,0 @@
-
-/* Make to be used with dynamic batching so no Model Matrix needed */
-uniform mat4 ViewProjectionMatrix;
-
-layout(points) in;
-layout(line_strip, max_vertices = 2) out;
-
-void main()
-{
- vec3 vert = gl_in[0].gl_Position.xyz;
-
- gl_Position = ViewProjectionMatrix * vec4(vert.xyz, 1.0);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance);
-#endif
- EmitVertex();
-
- gl_Position = ViewProjectionMatrix * vec4(vert.xy, 0.0, 1.0);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(vec3(vert.xy, 0.0));
-#endif
- EmitVertex();
-
- EndPrimitive();
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl
deleted file mode 100644
index 6786b7b7405..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-/* Made to be used with dynamic batching so no Model Matrix needed */
-uniform mat4 ViewProjectionMatrix;
-
-in vec3 pos;
-
-void main()
-{
- vec4 pos_4d = vec4(pos.xy, 0.0, 1.0);
- gl_Position = ViewProjectionMatrix * pos_4d;
- gl_PointSize = 2.0;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(pos_4d.xyz);
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl
deleted file mode 100644
index 28c91343771..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl
+++ /dev/null
@@ -1,27 +0,0 @@
-
-/*
- * Vertex Shader for dashed lines with 3D coordinates,
- * with uniform multi-colors or uniform single-color, and unary thickness.
- *
- * Legacy version, without geometry shader support, always produce solid lines!
- */
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec2 viewport_size;
-
-uniform vec4 color;
-
-in vec3 pos;
-noperspective out float distance_along_line;
-noperspective out vec4 color_geom;
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
-
- /* Hack - prevent stupid GLSL compiler to optimize out unused viewport_size uniform,
- * which gives crash! */
- distance_along_line = viewport_size.x * 0.000001f - viewport_size.x * 0.0000009f;
-
- color_geom = color;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
index 7c317ecfb8c..aefa47275f5 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
@@ -13,15 +13,21 @@ uniform mat4 ModelMatrix;
#endif
uniform vec4 color;
+uniform vec2 viewport_size;
in vec3 pos;
-out vec4 color_vert;
+flat out vec4 color_vert;
+
+/* We leverage hardware interpolation to compute distance along the line. */
+noperspective out vec2 stipple_pos; /* In screen space */
+flat out vec2 stipple_start; /* In screen space */
void main()
{
vec4 pos_4d = vec4(pos, 1.0);
gl_Position = ModelViewProjectionMatrix * pos_4d;
+ stipple_start = stipple_pos = viewport_size * 0.5 * (gl_Position.xy / gl_Position.w);
color_vert = color;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz);
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
deleted file mode 100644
index f32c47bcec3..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
+++ /dev/null
@@ -1,55 +0,0 @@
-
-uniform mat4 ViewProjectionMatrix;
-
-/* ---- Instantiated Attrs ---- */
-in float pos;
-
-/* ---- Per instance Attrs ---- */
-in vec3 color;
-in vec4 corners[2]; /* trouble fetching vec2 */
-in float depth;
-in vec4 tria;
-in mat4 InstanceModelMatrix;
-
-flat out vec4 finalColor;
-
-void main()
-{
- vec3 pPos;
-
- if (pos == 1.0) {
- pPos = vec3(corners[0].xy, depth);
- }
- else if (pos == 2.0) {
- pPos = vec3(corners[0].zw, depth);
- }
- else if (pos == 3.0) {
- pPos = vec3(corners[1].xy, depth);
- }
- else if (pos == 4.0) {
- pPos = vec3(corners[1].zw, depth);
- }
- else if (pos == 5.0) {
- pPos = vec3(tria.xy, depth);
- }
- else if (pos == 6.0) {
- vec2 ofs = tria.xy - corners[0].xy;
- ofs.x = -ofs.x;
- pPos = vec3(corners[1].zw + ofs, depth);
- }
- else if (pos == 7.0) {
- pPos = vec3(tria.zw, depth);
- }
- else {
- pPos = vec3(0.0);
- }
-
- vec4 wPos = InstanceModelMatrix * vec4(pPos, 1.0);
- gl_Position = ViewProjectionMatrix * wPos;
-
- finalColor = vec4(color, 1.0);
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(wPos.xyz);
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
deleted file mode 100644
index 5bd29c55e42..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
+++ /dev/null
@@ -1,31 +0,0 @@
-
-uniform mat4 ViewProjectionMatrix;
-
-/* ---- Instantiated Attrs ---- */
-in vec3 pos;
-
-/* ---- Per instance Attrs ---- */
-in vec3 color;
-in float start;
-in float end;
-in mat4 InstanceModelMatrix;
-
-uniform float size;
-
-flat out vec4 finalColor;
-
-void main()
-{
- float len = end - start;
- vec3 sta = vec3(0.0, 0.0, -start);
-
- vec4 wPos = InstanceModelMatrix * vec4(pos * -len + sta, 1.0);
-
- gl_Position = ViewProjectionMatrix * wPos;
- gl_PointSize = size;
- finalColor = vec4(color, 1.0);
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(wPos.xyz);
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl
deleted file mode 100644
index 1193e1b5b9c..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl
+++ /dev/null
@@ -1,68 +0,0 @@
-
-// Draw "fancy" wireframe, displaying front-facing, back-facing and
-// silhouette lines differently.
-// Mike Erwin, April 2015
-
-// After working with this shader a while, convinced we should make
-// separate shaders for perpective & ortho. (Oct 2016)
-
-// Due to perspective, the line segment's endpoints might disagree on
-// whether the adjacent faces are front facing. This geometry shader
-// decides which edge type to use if endpoints disagree.
-
-uniform mat4 ProjectionMatrix;
-
-uniform bool drawFront = true;
-uniform bool drawBack = true;
-uniform bool drawSilhouette = true;
-
-layout(lines) in;
-layout(line_strip, max_vertices = 2) out;
-
-in vec4 MV_pos[];
-in float edgeClass[];
-in vec3 fCol[];
-
-flat out vec4 finalColor;
-
-void emitLine(vec4 color)
-{
- gl_Position = ProjectionMatrix * MV_pos[0];
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance);
-#endif
- EmitVertex();
-
- gl_Position = ProjectionMatrix * MV_pos[1];
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
-#endif
- finalColor = color;
- EmitVertex();
-
- EndPrimitive();
-}
-
-void main()
-{
- float finalEdgeClass = max(edgeClass[0], edgeClass[1]);
-
- if (finalEdgeClass > 0.0f) {
- // front-facing edge
- if (drawFront) {
- emitLine(vec4(fCol[0], 0.75));
- }
- }
- else if (finalEdgeClass < 0.0f) {
- // back-facing edge
- if (drawBack) {
- emitLine(vec4(fCol[0], 0.5));
- }
- }
- else {
- // exactly one face is front-facing, silhouette edge
- if (drawSilhouette) {
- emitLine(vec4(fCol[0], 1.0));
- }
- }
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl
deleted file mode 100644
index 543497e890b..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl
+++ /dev/null
@@ -1,71 +0,0 @@
-
-// Draw "fancy" wireframe, displaying front-facing, back-facing and
-// silhouette lines differently.
-// Mike Erwin, April 2015
-
-// After working with this shader a while, convinced we should make
-// separate shaders for perpective & ortho. (Oct 2016)
-
-// Due to perspective, the line segment's endpoints might disagree on
-// whether the adjacent faces are front facing. We use a geometry
-// shader to resolve this properly.
-
-uniform mat4 ViewMatrix;
-uniform mat4 ProjectionMatrix;
-
-in vec3 pos;
-in vec3 N1, N2; // normals of faces this edge joins (object coords)
-
-/* Instance attrs */
-in vec3 color;
-in mat4 InstanceModelMatrix;
-
-out vec4 MV_pos;
-out float edgeClass;
-out vec3 fCol;
-
-// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley
-
-bool front(mat3 normal_matrix, vec3 N, vec3 eye)
-{
- return dot(normal_matrix * N, eye) > 0.0;
-}
-
-void main()
-{
- vec3 eye;
-
- mat4 model_view_matrix = ViewMatrix * InstanceModelMatrix;
-
- vec4 pos_4d = vec4(pos, 1.0);
- MV_pos = model_view_matrix * pos_4d;
-
- mat3 normal_matrix = transpose(inverse(mat3(model_view_matrix)));
-
- /* if persp */
- if (ProjectionMatrix[3][3] == 0.0) {
- eye = normalize(-MV_pos.xyz);
- }
- else {
- eye = vec3(0.0, 0.0, 1.0);
- }
-
- bool face_1_front = front(normal_matrix, N1, eye);
- bool face_2_front = front(normal_matrix, N2, eye);
-
- if (face_1_front && face_2_front) {
- edgeClass = 1.0; // front-facing edge
- }
- else if (face_1_front || face_2_front) {
- edgeClass = 0.0; // exactly one face is front-facing, silhouette edge
- }
- else {
- edgeClass = -1.0; // back-facing edge
- }
-
- fCol = color;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((InstanceModelMatrix * vec4(pos, 1.0)).xyz);
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl
deleted file mode 100644
index 5b3922d7a72..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl
+++ /dev/null
@@ -1,26 +0,0 @@
-
-uniform mat4 ViewMatrixInverse;
-uniform mat4 ViewProjectionMatrix;
-
-/* ---- Instantiated Attrs ---- */
-in vec3 pos;
-in vec3 nor;
-
-/* ---- Per instance Attrs ---- */
-in mat4 InstanceModelMatrix;
-in vec4 color;
-
-out vec3 normal;
-flat out vec4 finalColor;
-
-void main()
-{
- gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0));
-
- /* This is slow and run per vertex, but it's still faster than
- * doing it per instance on CPU and sending it on via instance attribute. */
- mat3 normal_mat = transpose(inverse(mat3(InstanceModelMatrix)));
- normal = normalize((transpose(mat3(ViewMatrixInverse)) * (normal_mat * nor)));
-
- finalColor = color;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl
deleted file mode 100644
index 374dcab2415..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl
+++ /dev/null
@@ -1,43 +0,0 @@
-
-uniform mat4 ViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
-uniform vec3 screen_vecs[2];
-
-/* ---- Instantiated Attrs ---- */
-in vec3 pos; /* using Z as axis id */
-
-/* ---- Per instance Attrs ---- */
-in mat4 InstanceModelMatrix;
-in vec3 color;
-in float size;
-
-flat out vec4 finalColor;
-
-void main()
-{
- vec3 offset = vec3(0.0);
-
-#ifdef AXIS_NAME
- if (pos.z == 0.0) {
- offset = vec3(1.125, 0.0, 0.0);
- }
- else if (pos.z == 1.0) {
- offset = vec3(0.0, 1.125, 0.0);
- }
- else {
- offset = vec3(0.0, 0.0, 1.125);
- }
- offset *= size;
-#endif
-
- vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y;
- vec4 pos_4d = InstanceModelMatrix * vec4(offset, 1.0) + vec4(screen_pos * size, 0.0);
- gl_Position = ViewProjectionMatrix * pos_4d;
- finalColor = vec4(color, 1.0);
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz);
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl
deleted file mode 100644
index c7368f78890..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl
+++ /dev/null
@@ -1,32 +0,0 @@
-
-uniform mat4 ViewProjectionMatrix;
-uniform vec3 screen_vecs[2];
-uniform float size;
-uniform float pixel_size;
-
-/* ---- Instantiated Attrs ---- */
-in vec2 pos;
-
-/* ---- Per instance Attrs ---- */
-in vec3 world_pos;
-in vec3 color;
-
-flat out vec4 finalColor;
-
-float mul_project_m4_v3_zfac(in vec3 co)
-{
- return (ViewProjectionMatrix[0][3] * co.x) + (ViewProjectionMatrix[1][3] * co.y) +
- (ViewProjectionMatrix[2][3] * co.z) + ViewProjectionMatrix[3][3];
-}
-
-void main()
-{
- float pix_size = mul_project_m4_v3_zfac(world_pos) * pixel_size;
- vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y;
- gl_Position = ViewProjectionMatrix * vec4(world_pos + screen_pos * size * pix_size, 1.0);
- finalColor = vec4(color, 1.0);
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
deleted file mode 100644
index 32db8d17572..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
+++ /dev/null
@@ -1,29 +0,0 @@
-
-uniform mat4 ViewProjectionMatrix;
-
-uniform int baseId;
-
-/* ---- Instantiated Attrs ---- */
-in vec3 pos;
-
-/* ---- Per instance Attrs ---- */
-in mat4 InstanceModelMatrix;
-#ifdef UNIFORM_SCALE
-in float size;
-#else
-in vec3 size;
-#endif
-in int callId;
-
-flat out uint finalId;
-
-void main()
-{
- vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0);
- gl_Position = ViewProjectionMatrix * wPos;
- finalId = uint(baseId + callId);
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(wPos.xyz);
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
deleted file mode 100644
index b8d31f5540a..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
+++ /dev/null
@@ -1,13 +0,0 @@
-
-uniform mat4 ViewProjectionMatrix;
-
-/* ---- Instantiated Attrs ---- */
-in vec3 pos;
-
-/* ---- Per instance Attrs ---- */
-in mat4 InstanceModelMatrix;
-
-void main()
-{
- gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0));
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
index 4a6ce4fd3ac..f9f195c31d6 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
@@ -1,6 +1,5 @@
flat in vec4 color_flat;
-flat in vec4 texCoord_rect;
noperspective in vec2 texCoord_interp;
out vec4 fragColor;
@@ -34,16 +33,16 @@ void main()
fragColor.rgb = color_flat.rgb;
vec2 texel = 1.0 / vec2(textureSize(glyph, 0));
- vec2 texco = mix(abs(texCoord_rect.xy), abs(texCoord_rect.zw), texCoord_interp);
+ vec2 texco = abs(texCoord_interp);
// modulate input alpha & texture alpha
- if (texCoord_rect.x > 0) {
+ if (texCoord_interp.x > 0) {
fragColor.a = texture(glyph, texco).r;
}
else {
fragColor.a = 0.0;
- if (texCoord_rect.w > 0) {
+ if (texCoord_interp.y > 0) {
/* 3x3 blur */
/* Manual unroll for perf. (stupid glsl compiler) */
fragColor.a += sample_glyph_offset(texco, texel, offsets4[0]);
diff --git a/source/blender/gpu/shaders/gpu_shader_text_geom.glsl b/source/blender/gpu/shaders/gpu_shader_text_geom.glsl
deleted file mode 100644
index 12ccbf00130..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_text_geom.glsl
+++ /dev/null
@@ -1,37 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-
-layout(points) in;
-layout(triangle_strip, max_vertices = 4) out;
-
-in vec4 pos_rect[];
-in vec4 tex_rect[];
-in vec4 color[];
-
-flat out vec4 color_flat;
-flat out vec4 texCoord_rect;
-noperspective out vec2 texCoord_interp;
-
-void main()
-{
- color_flat = color[0];
- texCoord_rect = tex_rect[0];
-
- gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].xy, 0.0, 1.0));
- texCoord_interp = vec2(0.0, 0.0);
- EmitVertex();
-
- gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].zy, 0.0, 1.0));
- texCoord_interp = vec2(1.0, 0.0);
- EmitVertex();
-
- gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].xw, 0.0, 1.0));
- texCoord_interp = vec2(0.0, 1.0);
- EmitVertex();
-
- gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].zw, 0.0, 1.0));
- texCoord_interp = vec2(1.0, 1.0);
- EmitVertex();
-
- EndPrimitive();
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl b/source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl
deleted file mode 100644
index 7a8a872f919..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl
+++ /dev/null
@@ -1,36 +0,0 @@
-
-layout(points) in;
-layout(triangle_strip, max_vertices = 4) out;
-
-in vec4 pos_rect[];
-in vec4 tex_rect[];
-in vec4 color[];
-
-flat out vec4 color_flat;
-flat out vec4 texCoord_rect;
-noperspective out vec2 texCoord_interp;
-
-void main()
-{
- color_flat = color[0];
- texCoord_rect = tex_rect[0];
- gl_Position.zw = vec2(0.0, 1.0);
-
- gl_Position.xy = pos_rect[0].xy;
- texCoord_interp = vec2(0.0, 0.0);
- EmitVertex();
-
- gl_Position.xy = pos_rect[0].zy;
- texCoord_interp = vec2(1.0, 0.0);
- EmitVertex();
-
- gl_Position.xy = pos_rect[0].xw;
- texCoord_interp = vec2(0.0, 1.0);
- EmitVertex();
-
- gl_Position.xy = pos_rect[0].zw;
- texCoord_interp = vec2(1.0, 1.0);
- EmitVertex();
-
- EndPrimitive();
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl
deleted file mode 100644
index a8a79ffe6c9..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl
+++ /dev/null
@@ -1,22 +0,0 @@
-
-/* Simpler version of gpu_shader_text_vert that supports only 2D translation. */
-
-uniform mat4 ModelViewProjectionMatrix;
-
-in vec4 pos; /* rect */
-in vec4 tex; /* rect */
-in vec4 col;
-
-out vec4 pos_rect;
-out vec4 tex_rect;
-out vec4 color;
-
-void main()
-{
- /* Manual mat4*vec2 */
- pos_rect = ModelViewProjectionMatrix[0].xyxy * pos.xxzz;
- pos_rect += ModelViewProjectionMatrix[1].xyxy * pos.yyww;
- pos_rect += ModelViewProjectionMatrix[3].xyxy;
- tex_rect = tex;
- color = col;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
index d8e4b2bc986..28437208e91 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
@@ -5,13 +5,17 @@ in vec4 pos; /* rect */
in vec4 tex; /* rect */
in vec4 col;
-out vec4 pos_rect;
-out vec4 tex_rect;
-out vec4 color;
+flat out vec4 color_flat;
+noperspective out vec2 texCoord_interp;
void main()
{
- pos_rect = pos;
- tex_rect = tex;
- color = col;
+ /* Quad expension using instanced rendering. */
+ float x = float(gl_VertexID % 2);
+ float y = float(gl_VertexID / 2);
+ vec2 quad = vec2(x, y);
+
+ gl_Position = ModelViewProjectionMatrix * vec4(mix(pos.xy, pos.zw, quad), 0.0, 1.0);
+ texCoord_interp = mix(abs(tex.xy), abs(tex.zw), quad) * sign(tex.xw);
+ color_flat = col;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl
index b8842064b6f..b196aed690f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl
@@ -2,3 +2,8 @@ void clamp_value(float value, float min, float max, out float result)
{
result = clamp(value, min, max);
}
+
+void clamp_range(float value, float min, float max, out float result)
+{
+ result = (max > min) ? clamp(value, min, max) : clamp(value, max, min);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
index a185774f4b3..7853aae31a1 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
@@ -1,5 +1,16 @@
-void map_range(
- float value, float fromMin, float fromMax, float toMin, float toMax, out float result)
+float smootherstep(float edge0, float edge1, float x)
+{
+ x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0);
+ return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
+}
+
+void map_range_linear(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ out float result)
{
if (fromMax != fromMin) {
result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
@@ -8,3 +19,57 @@ void map_range(
result = 0.0;
}
}
+
+void map_range_stepped(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ out float result)
+{
+ if (fromMax != fromMin) {
+ float factor = (value - fromMin) / (fromMax - fromMin);
+ factor = (steps > 0.0) ? floor(factor * (steps + 1.0)) / steps : 0.0;
+ result = toMin + factor * (toMax - toMin);
+ }
+ else {
+ result = 0.0;
+ }
+}
+
+void map_range_smoothstep(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ out float result)
+{
+ if (fromMax != fromMin) {
+ float factor = (fromMin > fromMax) ? 1.0 - smoothstep(fromMax, fromMin, value) :
+ smoothstep(fromMin, fromMax, value);
+ result = toMin + factor * (toMax - toMin);
+ }
+ else {
+ result = 0.0;
+ }
+}
+
+void map_range_smootherstep(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ out float result)
+{
+ if (fromMax != fromMin) {
+ float factor = (fromMin > fromMax) ? 1.0 - smootherstep(fromMax, fromMin, value) :
+ smootherstep(fromMin, fromMax, value);
+ result = toMin + factor * (toMax - toMin);
+ }
+ else {
+ result = 0.0;
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
index 4fac770e8fe..de3be98b715 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
@@ -1,24 +1,24 @@
-void math_add(float a, float b, out float result)
+void math_add(float a, float b, float c, out float result)
{
result = a + b;
}
-void math_subtract(float a, float b, out float result)
+void math_subtract(float a, float b, float c, out float result)
{
result = a - b;
}
-void math_multiply(float a, float b, out float result)
+void math_multiply(float a, float b, float c, out float result)
{
result = a * b;
}
-void math_divide(float a, float b, out float result)
+void math_divide(float a, float b, float c, out float result)
{
result = safe_divide(a, b);
}
-void math_power(float a, float b, out float result)
+void math_power(float a, float b, float c, out float result)
{
if (a >= 0.0) {
result = compatible_pow(a, b);
@@ -34,97 +34,187 @@ void math_power(float a, float b, out float result)
}
}
-void math_logarithm(float a, float b, out float result)
+void math_logarithm(float a, float b, float c, out float result)
{
result = (a > 0.0 && b > 0.0) ? log2(a) / log2(b) : 0.0;
}
-void math_sqrt(float a, float b, out float result)
+void math_sqrt(float a, float b, float c, out float result)
{
result = (a > 0.0) ? sqrt(a) : 0.0;
}
-void math_absolute(float a, float b, out float result)
+void math_inversesqrt(float a, float b, float c, out float result)
+{
+ result = inversesqrt(a);
+}
+
+void math_absolute(float a, float b, float c, out float result)
{
result = abs(a);
}
-void math_minimum(float a, float b, out float result)
+void math_radians(float a, float b, float c, out float result)
+{
+ result = radians(a);
+}
+
+void math_degrees(float a, float b, float c, out float result)
+{
+ result = degrees(a);
+}
+
+void math_minimum(float a, float b, float c, out float result)
{
result = min(a, b);
}
-void math_maximum(float a, float b, out float result)
+void math_maximum(float a, float b, float c, out float result)
{
result = max(a, b);
}
-void math_less_than(float a, float b, out float result)
+void math_less_than(float a, float b, float c, out float result)
{
result = (a < b) ? 1.0 : 0.0;
}
-void math_greater_than(float a, float b, out float result)
+void math_greater_than(float a, float b, float c, out float result)
{
result = (a > b) ? 1.0 : 0.0;
}
-void math_round(float a, float b, out float result)
+void math_round(float a, float b, float c, out float result)
{
result = floor(a + 0.5);
}
-void math_floor(float a, float b, out float result)
+void math_floor(float a, float b, float c, out float result)
{
result = floor(a);
}
-void math_ceil(float a, float b, out float result)
+void math_ceil(float a, float b, float c, out float result)
{
result = ceil(a);
}
-void math_fraction(float a, float b, out float result)
+void math_fraction(float a, float b, float c, out float result)
{
result = a - floor(a);
}
-void math_modulo(float a, float b, out float result)
+void math_modulo(float a, float b, float c, out float result)
{
result = c_mod(a, b);
}
-void math_sine(float a, float b, out float result)
+void math_trunc(float a, float b, float c, out float result)
+{
+ result = trunc(a);
+}
+
+void math_snap(float a, float b, float c, out float result)
+{
+ result = floor(safe_divide(a, b)) * b;
+}
+
+void math_pingpong(float a, float b, float c, out float result)
+{
+ result = (b != 0.0) ? abs(fract((a - b) / (b * 2.0)) * b * 2.0 - b) : 0.0;
+}
+
+/* Adapted from godotengine math_funcs.h. */
+void math_wrap(float a, float b, float c, out float result)
+{
+ float range = b - c;
+ result = (range != 0.0) ? a - (range * floor((a - c) / range)) : c;
+}
+
+void math_sine(float a, float b, float c, out float result)
{
result = sin(a);
}
-void math_cosine(float a, float b, out float result)
+void math_cosine(float a, float b, float c, out float result)
{
result = cos(a);
}
-void math_tangent(float a, float b, out float result)
+void math_tangent(float a, float b, float c, out float result)
{
result = tan(a);
}
-void math_arcsine(float a, float b, out float result)
+void math_sinh(float a, float b, float c, out float result)
+{
+ result = sinh(a);
+}
+
+void math_cosh(float a, float b, float c, out float result)
+{
+ result = cosh(a);
+}
+
+void math_tanh(float a, float b, float c, out float result)
+{
+ result = tanh(a);
+}
+
+void math_arcsine(float a, float b, float c, out float result)
{
result = (a <= 1.0 && a >= -1.0) ? asin(a) : 0.0;
}
-void math_arccosine(float a, float b, out float result)
+void math_arccosine(float a, float b, float c, out float result)
{
result = (a <= 1.0 && a >= -1.0) ? acos(a) : 0.0;
}
-void math_arctangent(float a, float b, out float result)
+void math_arctangent(float a, float b, float c, out float result)
{
result = atan(a);
}
-void math_arctan2(float a, float b, out float result)
+void math_arctan2(float a, float b, float c, out float result)
{
result = atan(a, b);
}
+
+void math_sign(float a, float b, float c, out float result)
+{
+ result = sign(a);
+}
+
+void math_exponent(float a, float b, float c, out float result)
+{
+ result = exp(a);
+}
+
+void math_compare(float a, float b, float c, out float result)
+{
+ result = (abs(a - b) <= max(c, 1e-5)) ? 1.0 : 0.0;
+}
+
+void math_multiply_add(float a, float b, float c, out float result)
+{
+ result = a * b + c;
+}
+
+/* See: https://www.iquilezles.org/www/articles/smin/smin.htm. */
+void math_smoothmin(float a, float b, float c, out float result)
+{
+ if (c != 0.0) {
+ float h = max(c - abs(a - b), 0.0) / c;
+ result = min(a, b) - h * h * h * c * (1.0 / 6.0);
+ }
+ else {
+ result = min(a, b);
+ }
+}
+
+void math_smoothmax(float a, float b, float c, out float result)
+{
+ math_smoothmin(-a, -b, c, result);
+ result = -result;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
index d4f7866b206..e8487fb5d42 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
@@ -93,11 +93,6 @@ vec3 c_mod(vec3 a, vec3 b)
return vec3(c_mod(a.x, b.x), c_mod(a.y, b.y), c_mod(a.z, b.z));
}
-void vector_mix(float strength, vec3 a, vec3 b, out vec3 outVector)
-{
- outVector = strength * a + (1 - strength) * b;
-}
-
void invert_z(vec3 v, out vec3 outv)
{
v.z = -v.z;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
index 6930e0c5dad..2b4a0204d97 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
@@ -5,7 +5,7 @@ void node_normal_map(vec4 info, vec4 tangent, vec3 normal, vec3 texnormal, out v
return;
}
tangent *= (gl_FrontFacing ? 1.0 : -1.0);
- vec3 B = tangent.w * cross(normal, tangent.xyz) * info.w;
+ vec3 B = tangent.w * cross(normal, tangent.xyz) * sign(info.w);
outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
outnormal = normalize(outnormal);
@@ -20,3 +20,8 @@ void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
{
normal = vec3(2.0, -2.0, -2.0) * color - vec3(1.0);
}
+
+void node_normal_map_mix(float strength, vec3 newnormal, vec3 oldnormal, out vec3 outnormal)
+{
+ outnormal = normalize(mix(oldnormal, newnormal, max(strength, 0.0)));
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
index bc2bf998145..fadb3b92df4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
@@ -353,3 +353,68 @@ void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
color = vec4(0.0);
alpha = 0.0;
}
+
+void node_tex_tile_map(vec3 co, out vec4 color, out vec3 map)
+{
+ float tx = floor(co.x);
+ float ty = floor(co.y);
+
+ if (tx < 0 || ty < 0 || tx >= 10)
+ map = vec3(0, 0, -1);
+ else
+ map = vec3(co.x - tx, co.y - ty, 1001 + 10 * ty + tx);
+
+ color = vec4(1.0, 0.0, 1.0, 1.0);
+}
+
+void node_tex_tile_linear(
+ vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
+{
+ if (map.z == tile_id) {
+ vec3 co = map.xyy;
+ node_tex_image_linear(co, ima, color, alpha);
+ }
+ else {
+ color = in_color;
+ alpha = color.a;
+ }
+}
+
+void node_tex_tile_nearest(
+ vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
+{
+ if (map.z == tile_id) {
+ vec3 co = map.xyy;
+ node_tex_image_nearest(co, ima, color, alpha);
+ }
+ else {
+ color = in_color;
+ alpha = color.a;
+ }
+}
+
+void node_tex_tile_cubic(
+ vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
+{
+ if (map.z == tile_id) {
+ vec3 co = map.xyy;
+ node_tex_image_cubic(co, ima, color, alpha);
+ }
+ else {
+ color = in_color;
+ alpha = color.a;
+ }
+}
+
+void node_tex_tile_smart(
+ vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
+{
+ if (map.z == tile_id) {
+ vec3 co = map.xyy;
+ node_tex_image_smart(co, ima, color, alpha);
+ }
+ else {
+ color = in_color;
+ alpha = color.a;
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
index e56b4a1d135..6aeb23b1f99 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
@@ -37,7 +37,7 @@ void node_noise_texture_1d(
{
float p = w * scale;
if (distortion != 0.0) {
- p += noise(p + random_float_offset(0.0)) * distortion;
+ p += snoise(p + random_float_offset(0.0)) * distortion;
}
value = fractal_noise(p, detail);
@@ -52,8 +52,8 @@ void node_noise_texture_2d(
{
vec2 p = co.xy * scale;
if (distortion != 0.0) {
- p += vec2(noise(p + random_vec2_offset(0.0)) * distortion,
- noise(p + random_vec2_offset(1.0)) * distortion);
+ p += vec2(snoise(p + random_vec2_offset(0.0)) * distortion,
+ snoise(p + random_vec2_offset(1.0)) * distortion);
}
value = fractal_noise(p, detail);
@@ -68,9 +68,9 @@ void node_noise_texture_3d(
{
vec3 p = co * scale;
if (distortion != 0.0) {
- p += vec3(noise(p + random_vec3_offset(0.0)) * distortion,
- noise(p + random_vec3_offset(1.0)) * distortion,
- noise(p + random_vec3_offset(2.0)) * distortion);
+ p += vec3(snoise(p + random_vec3_offset(0.0)) * distortion,
+ snoise(p + random_vec3_offset(1.0)) * distortion,
+ snoise(p + random_vec3_offset(2.0)) * distortion);
}
value = fractal_noise(p, detail);
@@ -85,10 +85,10 @@ void node_noise_texture_4d(
{
vec4 p = vec4(co, w) * scale;
if (distortion != 0.0) {
- p += vec4(noise(p + random_vec4_offset(0.0)) * distortion,
- noise(p + random_vec4_offset(1.0)) * distortion,
- noise(p + random_vec4_offset(2.0)) * distortion,
- noise(p + random_vec4_offset(3.0)) * distortion);
+ p += vec4(snoise(p + random_vec4_offset(0.0)) * distortion,
+ snoise(p + random_vec4_offset(1.0)) * distortion,
+ snoise(p + random_vec4_offset(2.0)) * distortion,
+ snoise(p + random_vec4_offset(3.0)) * distortion);
}
value = fractal_noise(p, detail);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
index fa79e3dc310..957aa606a79 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
@@ -11,7 +11,7 @@ float calc_wave(
}
if (distortion != 0.0) {
- n += distortion * fractal_noise(p * detail_scale, detail);
+ n += distortion * (fractal_noise(p * detail_scale, detail) * 2.0 - 1.0);
}
if (wave_profile == 0) { /* profile sin */
diff --git a/source/blender/imbuf/IMB_moviecache.h b/source/blender/imbuf/IMB_moviecache.h
index 25494df9c00..84ad0724b1a 100644
--- a/source/blender/imbuf/IMB_moviecache.h
+++ b/source/blender/imbuf/IMB_moviecache.h
@@ -57,6 +57,7 @@ void IMB_moviecache_set_priority_callback(struct MovieCache *cache,
void IMB_moviecache_put(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf);
bool IMB_moviecache_put_if_possible(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf);
struct ImBuf *IMB_moviecache_get(struct MovieCache *cache, void *userkey);
+void IMB_moviecache_remove(struct MovieCache *cache, void *userkey);
bool IMB_moviecache_has_frame(struct MovieCache *cache, void *userkey);
void IMB_moviecache_free(struct MovieCache *cache);
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 1b911226c6f..71e9da70c35 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -1029,11 +1029,11 @@ void IMB_colormanagement_init_default_view_settings(
static void curve_mapping_apply_pixel(CurveMapping *curve_mapping, float *pixel, int channels)
{
if (channels == 1) {
- pixel[0] = BKE_curvemap_evaluateF(curve_mapping->cm, pixel[0]);
+ pixel[0] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[0]);
}
else if (channels == 2) {
- pixel[0] = BKE_curvemap_evaluateF(curve_mapping->cm, pixel[0]);
- pixel[1] = BKE_curvemap_evaluateF(curve_mapping->cm, pixel[1]);
+ pixel[0] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[0]);
+ pixel[1] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[1]);
}
else {
BKE_curvemapping_evaluate_premulRGBF(curve_mapping, pixel, pixel);
@@ -3904,10 +3904,11 @@ static void curve_mapping_to_ocio_settings(CurveMapping *curve_mapping,
BKE_curvemapping_table_RGBA(
curve_mapping, &curve_mapping_settings->lut, &curve_mapping_settings->lut_size);
+ curve_mapping_settings->use_extend_extrapolate = (curve_mapping->flag &
+ CUMA_EXTEND_EXTRAPOLATE) != 0;
+
for (i = 0; i < 4; i++) {
CurveMap *cuma = curve_mapping->cm + i;
- curve_mapping_settings->use_extend_extrapolate[i] = (cuma->flag & CUMA_EXTEND_EXTRAPOLATE) !=
- 0;
curve_mapping_settings->range[i] = cuma->range;
curve_mapping_settings->mintable[i] = cuma->mintable;
curve_mapping_settings->ext_in_x[i] = cuma->ext_in[0];
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 3cb976a6d9f..fbe074d0fd5 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -388,6 +388,14 @@ bool IMB_moviecache_put_if_possible(MovieCache *cache, void *userkey, ImBuf *ibu
return result;
}
+void IMB_moviecache_remove(MovieCache *cache, void *userkey)
+{
+ MovieCacheKey key;
+ key.cache_owner = cache;
+ key.userkey = userkey;
+ BLI_ghash_remove(cache->hash, &key, moviecache_keyfree, moviecache_valfree);
+}
+
ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
{
MovieCacheKey key;
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 7915f04b74e..e5396b4551b 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -282,7 +282,7 @@ void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
}
/**
- * Re-alloc buffers at a new size.
+ * Re-allocate buffers at a new size.
*/
static void rect_realloc_4bytes(void **buf_p, const uint size[2])
{
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index b7834e2c7e0..b95a4ca3d96 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -28,6 +28,10 @@
#ifndef __DNA_ACTION_TYPES_H__
#define __DNA_ACTION_TYPES_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "DNA_listBase.h"
#include "DNA_ID.h"
#include "DNA_view2d_types.h"
@@ -856,8 +860,8 @@ typedef enum eSAction_Flag {
SACTION_SHOW_INTERPOLATION = (1 << 12),
/* show extremes */
SACTION_SHOW_EXTREMES = (1 << 13),
- /* show vertical line markers */
- SACTION_SHOW_MARKER_LINES = (1 << 14),
+ /* show markers region */
+ SACTION_SHOW_MARKERS = (1 << 14),
} eSAction_Flag;
/* SpaceAction_Runtime.flag */
@@ -955,4 +959,8 @@ typedef enum eActionChannelFlag {
ACHAN_MOVED = (1u << 31),
} eActionChannelFlag;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __DNA_ACTION_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 4ead3165715..354344328d3 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -182,7 +182,7 @@ typedef enum eArmature_DeformFlag {
ARM_DEF_VGROUP = (1 << 0),
ARM_DEF_ENVELOPE = (1 << 1),
ARM_DEF_QUATERNION = (1 << 2),
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
ARM_DEF_B_BONE_REST = (1 << 3), /* deprecated */
#endif
ARM_DEF_INVERT_VGROUP = (1 << 4),
@@ -190,7 +190,7 @@ typedef enum eArmature_DeformFlag {
/* armature->pathflag */
// XXX deprecated... old animation system (armature only viz)
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
typedef enum eArmature_PathFlag {
ARM_PATH_FNUMS = (1 << 0),
ARM_PATH_KFRAS = (1 << 1),
@@ -228,7 +228,7 @@ typedef enum eBone_Flag {
BONE_UNKEYED = (1 << 13),
/** set to prevent hinge child bones from influencing the transform center */
BONE_HINGE_CHILD_TRANSFORM = (1 << 14),
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
/** No parent scale */
BONE_NO_SCALE = (1 << 15),
#endif
diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h
index 9d3689ce4ee..f7998fab8db 100644
--- a/source/blender/makesdna/DNA_brush_defaults.h
+++ b/source/blender/makesdna/DNA_brush_defaults.h
@@ -85,10 +85,10 @@
/* brush appearance */ \
\
/* add mode color is light red */ \
- .add_col = {1.0, 0.39, 0.39}, \
+ .add_col = {1.0, 0.39, 0.39, 0.9}, \
\
/* subtract mode color is light blue */ \
- .sub_col = {0.39, 0.39, 1.0}, \
+ .sub_col = {0.39, 0.39, 1.0, 0.9}, \
\
.stencil_pos = {256, 256}, \
.stencil_dimension = {256, 256}, \
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 3860ea6b312..8cd0b5d55cd 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -357,8 +357,8 @@ typedef struct Brush {
/* fill tool */
float fill_threshold;
- float add_col[3];
- float sub_col[3];
+ float add_col[4];
+ float sub_col[4];
float stencil_pos[2];
float stencil_dimension[2];
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index b78b2f64648..7c7d4bc182e 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -156,7 +156,7 @@ enum {
CAM_SHOWNAME = (1 << 4),
CAM_ANGLETOGGLE = (1 << 5),
CAM_DS_EXPAND = (1 << 6),
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
CAM_PANORAMA = (1 << 7), /* deprecated */
#endif
CAM_SHOWSENSOR = (1 << 8),
diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h
index 9cedd8f0ebf..8f3a26cf9c0 100644
--- a/source/blender/makesdna/DNA_cloth_types.h
+++ b/source/blender/makesdna/DNA_cloth_types.h
@@ -93,11 +93,25 @@ typedef struct ClothSimSettings {
float collider_friction;
/** Damp the velocity to speed up getting to the resting position. */
float vel_damping DNA_DEPRECATED;
- /** Min amount to shrink cloth by 0.0f (no shrink) - 1.0f (shrink to nothing). */
+ /** Min amount to shrink cloth by 0.0f (no shrink), 1.0f (shrink to nothing), -1.0f (double the
+ * edge length). */
float shrink_min;
- /** Max amount to shrink cloth by 0.0f (no shrink) - 1.0f (shrink to nothing). */
+ /** Max amount to shrink cloth by 0.0f (no shrink), 1.0f (shrink to nothing), -1.0f (double the
+ * edge length). */
float shrink_max;
+ /* Air pressure */
+ /* The uniform pressure that is constanty applied to the mesh. Can be negative */
+ float uniform_pressure_force;
+ /* User set volume. This is the volume the mesh wants to expand to (the equilibrium volume). */
+ float target_volume;
+ /* The scaling factor to apply to the actual pressure.
+ pressure=( (current_volume/target_volume) - 1 + uniform_pressure_force) *
+ pressure_factor */
+ float pressure_factor;
+ short vgroup_pressure;
+ char _pad7[2];
+
/* XXX various hair stuff
* should really be separate, this struct is a horrible mess already
*/
@@ -105,7 +119,6 @@ typedef struct ClothSimSettings {
float bending_damping;
/** Size of voxel grid cells for continuum dynamics. */
float voxel_cell_size;
- char _pad[4];
/** Number of time steps per frame. */
int stepsPerFrame;
@@ -131,7 +144,6 @@ typedef struct ClothSimSettings {
short presets;
short reset;
- char _pad0[4];
struct EffectorWeights *effector_weights;
short bending_model;
@@ -147,6 +159,20 @@ typedef struct ClothSimSettings {
float compression_damp;
/** Mechanical damping of shear springs. */
float shear_damp;
+
+ /** The maximum lenght an internal spring can have during creation. */
+ float internal_spring_max_length;
+ /** How much the interal spring can diverge from the vertex normal during creation. */
+ float internal_spring_max_diversion;
+ /** Vertex group for scaling structural stiffness. */
+ short vgroup_intern;
+ char _pad1[2];
+ float internal_tension;
+ float internal_compression;
+ float max_internal_tension;
+ float max_internal_compression;
+ char _pad0[4];
+
} ClothSimSettings;
typedef struct ClothCollSettings {
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index 219fc96554a..66adc547cf2 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -24,6 +24,7 @@
#ifndef __DNA_COLOR_TYPES_H__
#define __DNA_COLOR_TYPES_H__
+#include "DNA_defs.h"
#include "DNA_vec_types.h"
/* general defines for kernel functions */
@@ -47,7 +48,8 @@ enum {
};
typedef struct CurveMap {
- short totpoint, flag;
+ short totpoint;
+ short flag DNA_DEPRECATED;
/** Quick multiply value for reading table. */
float range;
@@ -67,9 +69,6 @@ typedef struct CurveMap {
float premul_ext_out[2];
} CurveMap;
-/* cuma->flag */
-#define CUMA_EXTEND_EXTRAPOLATE 1
-
typedef struct CurveMapping {
/** Cur; for buttons, to show active curve. */
int flag, cur;
@@ -93,11 +92,17 @@ typedef struct CurveMapping {
char _pad[6];
} CurveMapping;
-/* cumapping->flag */
-#define CUMA_DO_CLIP (1 << 0)
-#define CUMA_PREMULLED (1 << 1)
-#define CUMA_DRAW_CFRA (1 << 2)
-#define CUMA_DRAW_SAMPLE (1 << 3)
+/* CurveMapping.flag */
+typedef enum eCurveMappingFlags {
+ CUMA_DO_CLIP = (1 << 0),
+ CUMA_PREMULLED = (1 << 1),
+ CUMA_DRAW_CFRA = (1 << 2),
+ CUMA_DRAW_SAMPLE = (1 << 3),
+
+ /* The curve is extended by extrapolation. When not set the curve is extended
+ * Horizontally */
+ CUMA_EXTEND_EXTRAPOLATE = (1 << 4),
+} eCurveMappingFlags;
/* cumapping->preset */
typedef enum eCurveMappingPreset {
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index d7b392d5133..f816041010b 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -336,6 +336,8 @@ typedef struct bActionConstraint {
float min;
float max;
int flag;
+ char mix_mode;
+ char _pad[7];
struct bAction *act;
/** MAX_ID_NAME-2. */
char subtarget[64];
@@ -755,7 +757,7 @@ typedef enum eCopyRotation_Flags {
ROTLIKE_X_INVERT = (1 << 4),
ROTLIKE_Y_INVERT = (1 << 5),
ROTLIKE_Z_INVERT = (1 << 6),
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
ROTLIKE_OFFSET = (1 << 7),
#endif
} eCopyRotation_Flags;
@@ -865,6 +867,16 @@ typedef enum eActionConstraint_Flags {
ACTCON_BONE_USE_OBJECT_ACTION = (1 << 0),
} eActionConstraint_Flags;
+/* bActionConstraint.mix_mode */
+typedef enum eActionConstraint_MixMode {
+ /* Multiply the action transformation on the right. */
+ ACTCON_MIX_AFTER_FULL = 0,
+ /* Multiply the action transformation on the right, with anti-shear scale handling. */
+ ACTCON_MIX_AFTER,
+ /* Multiply the action transformation on the left, with anti-shear scale handling. */
+ ACTCON_MIX_BEFORE,
+} eActionConstraint_MixMode;
+
/* Locked-Axis Values (Locked Track) */
typedef enum eLockAxis_Modes {
LOCK_X = 0,
@@ -976,7 +988,7 @@ typedef enum eSplineIK_Flags {
CONSTRAINT_SPLINEIK_BOUND = (1 << 0),
/* root of chain is not influenced by the constraint */
CONSTRAINT_SPLINEIK_NO_ROOT = (1 << 1),
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
/* bones in the chain should not scale to fit the curve */
CONSTRAINT_SPLINEIK_SCALE_LIMITED = (1 << 2),
#endif
diff --git a/source/blender/makesdna/DNA_curveprofile_types.h b/source/blender/makesdna/DNA_curveprofile_types.h
index 13e638437c4..18d170e7bd5 100644
--- a/source/blender/makesdna/DNA_curveprofile_types.h
+++ b/source/blender/makesdna/DNA_curveprofile_types.h
@@ -21,8 +21,8 @@
* \ingroup DNA
*/
-#ifndef DNA_PROFILEPATH_TYPES_H
-#define DNA_PROFILEPATH_TYPES_H
+#ifndef __DNA_CURVEPROFILE_TYPES_H__
+#define __DNA_CURVEPROFILE_TYPES_H__
#include "DNA_vec_types.h"
@@ -90,4 +90,4 @@ typedef enum eCurveProfilePresets {
PROF_PRESET_STEPS = 4, /* Dynamic number of steps defined by segments_len. */
} eCurveProfilePresets;
-#endif
+#endif /* __DNA_CURVEPROFILE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 0a6423d569f..f70dc19616b 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -97,7 +97,7 @@ typedef enum CustomDataType {
CD_AUTO_FROM_NAME = -1,
CD_MVERT = 0,
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
CD_MSTICKY = 1, /* DEPRECATED */
#endif
CD_MDEFORMVERT = 2,
@@ -113,7 +113,7 @@ typedef enum CustomDataType {
CD_PROP_STR = 12,
CD_ORIGSPACE = 13, /* for modifier stack face location mapping */
CD_ORCO = 14, /* undeformed vertex coordinates, normalized to 0..1 range */
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
CD_MTEXPOLY = 15, /* deprecated */
#endif
CD_MLOOPUV = 16,
diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h
new file mode 100644
index 00000000000..e12bee13ebc
--- /dev/null
+++ b/source/blender/makesdna/DNA_fluid_types.h
@@ -0,0 +1,590 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_FLUID_TYPES_H__
+#define __DNA_FLUID_TYPES_H__
+
+/* Domain flags. */
+enum {
+ FLUID_DOMAIN_USE_NOISE = (1 << 1), /* Use noise. */
+ FLUID_DOMAIN_USE_DISSOLVE = (1 << 2), /* Let smoke dissolve. */
+ FLUID_DOMAIN_USE_DISSOLVE_LOG = (1 << 3), /* Using 1/x for dissolve. */
+
+#ifdef DNA_DEPRECATED_ALLOW
+ FLUID_DOMAIN_USE_HIGH_SMOOTH = (1 << 5), /* -- Deprecated -- */
+#endif
+ FLUID_DOMAIN_FILE_LOAD = (1 << 6), /* Flag for file load. */
+ FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN = (1 << 7),
+ FLUID_DOMAIN_USE_ADAPTIVE_TIME = (1 << 8), /* Adaptive time stepping in domain. */
+ FLUID_DOMAIN_USE_MESH = (1 << 9), /* Use mesh. */
+ FLUID_DOMAIN_USE_GUIDE = (1 << 10), /* Use guiding. */
+ FLUID_DOMAIN_USE_SPEED_VECTORS = (1 << 11), /* Generate mesh speed vectors. */
+ FLUID_DOMAIN_EXPORT_MANTA_SCRIPT = (1 << 12), /* Export mantaflow script during bake. */
+ FLUID_DOMAIN_USE_FRACTIONS = (1 << 13), /* Use second order obstacles. */
+};
+
+/* Border collisions. */
+enum {
+ FLUID_DOMAIN_BORDER_FRONT = (1 << 1),
+ FLUID_DOMAIN_BORDER_BACK = (1 << 2),
+ FLUID_DOMAIN_BORDER_RIGHT = (1 << 3),
+ FLUID_DOMAIN_BORDER_LEFT = (1 << 4),
+ FLUID_DOMAIN_BORDER_TOP = (1 << 5),
+ FLUID_DOMAIN_BORDER_BOTTOM = (1 << 6),
+};
+
+/* Cache file formats. */
+enum {
+ FLUID_DOMAIN_FILE_UNI = (1 << 0),
+ FLUID_DOMAIN_FILE_OPENVDB = (1 << 1),
+ FLUID_DOMAIN_FILE_RAW = (1 << 2),
+ FLUID_DOMAIN_FILE_OBJECT = (1 << 3),
+ FLUID_DOMAIN_FILE_BIN_OBJECT = (1 << 4),
+};
+
+/* Slice method. */
+enum {
+ FLUID_DOMAIN_SLICE_VIEW_ALIGNED = 0,
+ FLUID_DOMAIN_SLICE_AXIS_ALIGNED = 1,
+};
+
+/* Axis aligned method. */
+enum {
+ AXIS_SLICE_FULL = 0,
+ AXIS_SLICE_SINGLE = 1,
+};
+
+/* Single slice direction. */
+enum {
+ SLICE_AXIS_AUTO = 0,
+ SLICE_AXIS_X = 1,
+ SLICE_AXIS_Y = 2,
+ SLICE_AXIS_Z = 3,
+};
+
+/* Axis aligned method. */
+enum {
+ VOLUME_INTERP_LINEAR = 0,
+ VOLUME_INTERP_CUBIC = 1,
+};
+
+enum {
+ VECTOR_DRAW_NEEDLE = 0,
+ VECTOR_DRAW_STREAMLINE = 1,
+};
+
+enum {
+ SNDPARTICLE_BOUNDARY_DELETE = 0,
+ SNDPARTICLE_BOUNDARY_PUSHOUT = 1,
+};
+
+enum {
+ SNDPARTICLE_COMBINED_EXPORT_OFF = 0,
+ SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM = 1,
+ SNDPARTICLE_COMBINED_EXPORT_SPRAY_BUBBLE = 2,
+ SNDPARTICLE_COMBINED_EXPORT_FOAM_BUBBLE = 3,
+ SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM_BUBBLE = 4,
+};
+
+enum {
+ FLUID_DOMAIN_FIELD_DENSITY = 0,
+ FLUID_DOMAIN_FIELD_HEAT = 1,
+ FLUID_DOMAIN_FIELD_FUEL = 2,
+ FLUID_DOMAIN_FIELD_REACT = 3,
+ FLUID_DOMAIN_FIELD_FLAME = 4,
+ FLUID_DOMAIN_FIELD_VELOCITY_X = 5,
+ FLUID_DOMAIN_FIELD_VELOCITY_Y = 6,
+ FLUID_DOMAIN_FIELD_VELOCITY_Z = 7,
+ FLUID_DOMAIN_FIELD_COLOR_R = 8,
+ FLUID_DOMAIN_FIELD_COLOR_G = 9,
+ FLUID_DOMAIN_FIELD_COLOR_B = 10,
+ FLUID_DOMAIN_FIELD_FORCE_X = 11,
+ FLUID_DOMAIN_FIELD_FORCE_Y = 12,
+ FLUID_DOMAIN_FIELD_FORCE_Z = 13,
+};
+
+/* Fluid domain types. */
+enum {
+ FLUID_DOMAIN_TYPE_GAS = 0,
+ FLUID_DOMAIN_TYPE_LIQUID = 1,
+};
+
+/* Smoke noise types. */
+enum {
+ FLUID_NOISE_TYPE_WAVELET = (1 << 0),
+};
+
+/* Mesh levelset generator types. */
+enum {
+ FLUID_DOMAIN_MESH_IMPROVED = 0,
+ FLUID_DOMAIN_MESH_UNION = 1,
+};
+
+/* Guiding velocity source. */
+enum {
+ FLUID_DOMAIN_GUIDE_SRC_DOMAIN = 0,
+ FLUID_DOMAIN_GUIDE_SRC_EFFECTOR = 1,
+};
+
+/* Fluid data fields (active_fields). */
+enum {
+ FLUID_DOMAIN_ACTIVE_HEAT = (1 << 0),
+ FLUID_DOMAIN_ACTIVE_FIRE = (1 << 1),
+ FLUID_DOMAIN_ACTIVE_COLORS = (1 << 2),
+ FLUID_DOMAIN_ACTIVE_COLOR_SET = (1 << 3),
+ FLUID_DOMAIN_ACTIVE_OBSTACLE = (1 << 4),
+ FLUID_DOMAIN_ACTIVE_GUIDE = (1 << 5),
+ FLUID_DOMAIN_ACTIVE_INVEL = (1 << 6),
+ FLUID_DOMAIN_ACTIVE_OUTFLOW = (1 << 7),
+};
+
+/* Particle types. */
+enum {
+ FLUID_DOMAIN_PARTICLE_FLIP = (1 << 0),
+ FLUID_DOMAIN_PARTICLE_SPRAY = (1 << 1),
+ FLUID_DOMAIN_PARTICLE_BUBBLE = (1 << 2),
+ FLUID_DOMAIN_PARTICLE_FOAM = (1 << 3),
+ FLUID_DOMAIN_PARTICLE_TRACER = (1 << 4),
+};
+
+/* Liquid simulation methods. */
+enum {
+ FLUID_DOMAIN_METHOD_FLIP = (1 << 0),
+ FLUID_DOMAIN_METHOD_APIC = (1 << 1),
+};
+
+/* Cache options. */
+enum {
+ FLUID_DOMAIN_BAKING_DATA = (1 << 0),
+ FLUID_DOMAIN_BAKED_DATA = (1 << 1),
+ FLUID_DOMAIN_BAKING_NOISE = (1 << 2),
+ FLUID_DOMAIN_BAKED_NOISE = (1 << 3),
+ FLUID_DOMAIN_BAKING_MESH = (1 << 4),
+ FLUID_DOMAIN_BAKED_MESH = (1 << 5),
+ FLUID_DOMAIN_BAKING_PARTICLES = (1 << 6),
+ FLUID_DOMAIN_BAKED_PARTICLES = (1 << 7),
+ FLUID_DOMAIN_BAKING_GUIDE = (1 << 8),
+ FLUID_DOMAIN_BAKED_GUIDE = (1 << 9),
+ FLUID_DOMAIN_OUTDATED_DATA = (1 << 10),
+ FLUID_DOMAIN_OUTDATED_NOISE = (1 << 11),
+ FLUID_DOMAIN_OUTDATED_MESH = (1 << 12),
+ FLUID_DOMAIN_OUTDATED_PARTICLES = (1 << 13),
+ FLUID_DOMAIN_OUTDATED_GUIDE = (1 << 14),
+};
+
+#define FLUID_DOMAIN_BAKING_ALL \
+ (FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKING_MESH | \
+ FLUID_DOMAIN_BAKING_PARTICLES | FLUID_DOMAIN_BAKING_GUIDE)
+
+#define FLUID_DOMAIN_BAKED_ALL \
+ (FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_BAKED_MESH | \
+ FLUID_DOMAIN_BAKED_PARTICLES | FLUID_DOMAIN_BAKED_GUIDE)
+
+#define FLUID_DOMAIN_DIR_DEFAULT "cache_fluid"
+#define FLUID_DOMAIN_DIR_CONFIG "config"
+#define FLUID_DOMAIN_DIR_DATA "data"
+#define FLUID_DOMAIN_DIR_NOISE "noise"
+#define FLUID_DOMAIN_DIR_MESH "mesh"
+#define FLUID_DOMAIN_DIR_PARTICLES "particles"
+#define FLUID_DOMAIN_DIR_GUIDE "guiding"
+#define FLUID_DOMAIN_DIR_SCRIPT "script"
+#define FLUID_DOMAIN_SMOKE_SCRIPT "smoke_script.py"
+#define FLUID_DOMAIN_LIQUID_SCRIPT "liquid_script.py"
+
+enum {
+ FLUID_DOMAIN_CACHE_REPLAY = 0,
+ FLUID_DOMAIN_CACHE_MODULAR = 1,
+ FLUID_DOMAIN_CACHE_FINAL = 2,
+};
+
+/* Deprecated values (i.e. all defines and enums below this line up until typedefs). */
+/* Cache compression. */
+enum {
+ SM_CACHE_LIGHT = 0,
+ SM_CACHE_HEAVY = 1,
+};
+
+/* High resolution sampling types. */
+enum {
+ SM_HRES_NEAREST = 0,
+ SM_HRES_LINEAR = 1,
+ SM_HRES_FULLSAMPLE = 2,
+};
+
+enum {
+ VDB_COMPRESSION_BLOSC = 0,
+ VDB_COMPRESSION_ZIP = 1,
+ VDB_COMPRESSION_NONE = 2,
+};
+
+typedef struct FluidDomainVertexVelocity {
+ float vel[3];
+} FluidDomainVertexVelocity;
+
+typedef struct FluidDomainSettings {
+
+ /* -- Runtime-only fields (from here on). -- */
+
+ struct FluidModifierData *mmd; /* For fast RNA access. */
+ struct MANTA *fluid;
+ struct MANTA *fluid_old; /* Adaptive domain needs access to old fluid state. */
+ void *fluid_mutex;
+ struct Collection *fluid_group;
+ struct Collection *force_group; /* UNUSED */
+ struct Collection *effector_group; /* Effector objects group. */
+ struct GPUTexture *tex;
+ struct GPUTexture *tex_wt;
+ struct GPUTexture *tex_shadow;
+ struct GPUTexture *tex_flame;
+ struct GPUTexture *tex_flame_coba;
+ struct GPUTexture *tex_coba;
+ struct GPUTexture *tex_field;
+ struct GPUTexture *tex_velocity_x;
+ struct GPUTexture *tex_velocity_y;
+ struct GPUTexture *tex_velocity_z;
+ struct Object *guide_parent;
+ /** Vertex velocities of simulated fluid mesh. */
+ struct FluidDomainVertexVelocity *mesh_velocities;
+ struct EffectorWeights *effector_weights;
+
+ /* Domain object data. */
+ float p0[3]; /* Start point of BB in local space
+ * (includes sub-cell shift for adaptive domain). */
+ float p1[3]; /* End point of BB in local space. */
+ float dp0[3]; /* Difference from object center to grid start point. */
+ float cell_size[3]; /* Size of simulation cell in local space. */
+ float global_size[3]; /* Global size of domain axises. */
+ float prev_loc[3];
+ int shift[3]; /* Current domain shift in simulation cells. */
+ float shift_f[3]; /* Exact domain shift. */
+ float obj_shift_f[3]; /* How much object has shifted since previous smoke frame (used to "lock"
+ * domain while drawing). */
+ float imat[4][4]; /* Domain object imat. */
+ float obmat[4][4]; /* Domain obmat. */
+ float fluidmat[4][4]; /* Low res fluid matrix. */
+ float fluidmat_wt[4][4]; /* High res fluid matrix. */
+ int base_res[3]; /* Initial "non-adapted" resolution. */
+ int res_min[3]; /* Cell min. */
+ int res_max[3]; /* Cell max. */
+ int res[3]; /* Data resolution (res_max-res_min). */
+ int total_cells;
+ float dx; /* 1.0f / res. */
+ float scale; /* Largest domain size. */
+ int boundary_width; /* Usually this is just 1. */
+
+ /* -- User-accesible fields (from here on). -- */
+
+ /* Adaptive domain options. */
+ int adapt_margin;
+ int adapt_res;
+ float adapt_threshold;
+ char _pad1[4]; /* Unused. */
+
+ /* Fluid domain options */
+ int maxres; /* Longest axis on the BB gets this resolution assigned. */
+ int solver_res; /* Dimension of manta solver, 2d or 3d. */
+ int border_collisions; /* How domain border collisions are handled. */
+ int flags; /* Use-mesh, use-noise, etc. */
+ float gravity[3];
+ int active_fields;
+ short type; /* Gas, liquid. */
+ char _pad2[6]; /* Unused. */
+
+ /* Smoke domain options. */
+ float alpha;
+ float beta;
+ int diss_speed; /* In frames. */
+ float vorticity;
+ float active_color[3]; /* Monitor smoke color. */
+ int highres_sampling;
+
+ /* Flame options. */
+ float burning_rate, flame_smoke, flame_vorticity;
+ float flame_ignition, flame_max_temp;
+ float flame_smoke_color[3];
+
+ /* Noise options. */
+ float noise_strength;
+ float noise_pos_scale;
+ float noise_time_anim;
+ int res_noise[3];
+ int noise_scale;
+ short noise_type; /* Noise type: wave, curl, anisotropic. */
+ char _pad3[2]; /* Unused. */
+
+ /* Liquid domain options. */
+ float particle_randomness;
+ int particle_number;
+ int particle_minimum;
+ int particle_maximum;
+ float particle_radius;
+ float particle_band_width;
+ float fractions_threshold;
+ float flip_ratio;
+ short simulation_method;
+ char _pad4[6];
+
+ /* Diffusion options. */
+ float surface_tension;
+ float viscosity_base;
+ int viscosity_exponent;
+ float domain_size;
+
+ /* Mesh options. */
+ float mesh_concave_upper;
+ float mesh_concave_lower;
+ float mesh_particle_radius;
+ int mesh_smoothen_pos;
+ int mesh_smoothen_neg;
+ int mesh_scale;
+ int totvert;
+ short mesh_generator;
+ char _pad5[2]; /* Unused. */
+
+ /* Secondary particle options. */
+ int particle_type;
+ int particle_scale;
+ float sndparticle_tau_min_wc;
+ float sndparticle_tau_max_wc;
+ float sndparticle_tau_min_ta;
+ float sndparticle_tau_max_ta;
+ float sndparticle_tau_min_k;
+ float sndparticle_tau_max_k;
+ int sndparticle_k_wc;
+ int sndparticle_k_ta;
+ float sndparticle_k_b;
+ float sndparticle_k_d;
+ float sndparticle_l_min;
+ float sndparticle_l_max;
+ int sndparticle_potential_radius;
+ int sndparticle_update_radius;
+ char sndparticle_boundary;
+ char sndparticle_combined_export;
+ char _pad6[6]; /* Unused. */
+
+ /* Fluid guiding options. */
+ float guide_alpha; /* Guiding weight scalar (determines strength). */
+ int guide_beta; /* Guiding blur radius (affects size of vortices). */
+ float guide_vel_factor; /* Multiply guiding velocity by this factor. */
+ int guide_res[3]; /* Res for velocity guide grids - independent from base res. */
+ short guide_source;
+ char _pad7[2]; /* Unused. */
+
+ /* Cache options. */
+ int cache_frame_start;
+ int cache_frame_end;
+ int cache_frame_pause_data;
+ int cache_frame_pause_noise;
+ int cache_frame_pause_mesh;
+ int cache_frame_pause_particles;
+ int cache_frame_pause_guide;
+ int cache_flag;
+ char cache_mesh_format;
+ char cache_data_format;
+ char cache_particle_format;
+ char cache_noise_format;
+ char cache_directory[1024];
+ char error[64]; /* Bake error description. */
+ short cache_type;
+ char _pad8[2]; /* Unused. */
+
+ /* Time options. */
+ float dt;
+ float time_total;
+ float time_per_frame;
+ float frame_length;
+ float time_scale;
+ float cfl_condition;
+ int timesteps_minimum;
+ int timesteps_maximum;
+
+ /* Display options. */
+ char slice_method, axis_slice_method;
+ char slice_axis, draw_velocity;
+ float slice_per_voxel;
+ float slice_depth;
+ float display_thickness;
+ struct ColorBand *coba;
+ float vector_scale;
+ char vector_draw_type;
+ char use_coba;
+ char coba_field; /* Simulation field used for the color mapping. */
+ char interp_method;
+
+ /* -- Deprecated / unsed options (below). -- */
+
+ /* View options. */
+ int viewsettings;
+ char _pad9[4]; /* Unused. */
+
+ /* OpenVDB cache options. */
+ int openvdb_comp;
+ float clipping;
+ char data_depth;
+ char _pad10[7]; /* Unused. */
+
+ /* Pointcache options. */
+ /* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading
+ * old files. */
+ struct PointCache *point_cache[2]; /* Definition is in DNA_object_force_types.h. */
+ struct ListBase ptcaches[2];
+ int cache_comp;
+ int cache_high_comp;
+ char cache_file_format;
+ char _pad11[7]; /* Unused. */
+
+} FluidDomainSettings;
+
+/* Flow types. */
+enum {
+ FLUID_FLOW_TYPE_SMOKE = 1,
+ FLUID_FLOW_TYPE_FIRE = 2,
+ FLUID_FLOW_TYPE_SMOKEFIRE = 3,
+ FLUID_FLOW_TYPE_LIQUID = 4,
+};
+
+/* Flow behavior types. */
+enum {
+ FLUID_FLOW_BEHAVIOR_INFLOW = 0,
+ FLUID_FLOW_BEHAVIOR_OUTFLOW = 1,
+ FLUID_FLOW_BEHAVIOR_GEOMETRY = 2,
+};
+
+/* Flow source types. */
+enum {
+ FLUID_FLOW_SOURCE_PARTICLES = 0,
+ FLUID_FLOW_SOURCE_MESH = 1,
+};
+
+/* Flow texture types. */
+enum {
+ FLUID_FLOW_TEXTURE_MAP_AUTO = 0,
+ FLUID_FLOW_TEXTURE_MAP_UV = 1,
+};
+
+/* Flow flags. */
+enum {
+ /* Old style emission. */
+ FLUID_FLOW_ABSOLUTE = (1 << 1),
+ /* Passes particles speed to the smoke. */
+ FLUID_FLOW_INITVELOCITY = (1 << 2),
+ /* Use texture to control emission speed. */
+ FLUID_FLOW_TEXTUREEMIT = (1 << 3),
+ /* Use specific size for particles instead of closest cell. */
+ FLUID_FLOW_USE_PART_SIZE = (1 << 4),
+ /* Control when to apply inflow. */
+ FLUID_FLOW_USE_INFLOW = (1 << 5),
+ /* Control when to apply inflow. */
+ FLUID_FLOW_USE_PLANE_INIT = (1 << 6),
+};
+
+typedef struct FluidFlowSettings {
+
+ /* -- Runtime-only fields (from here on). -- */
+
+ /* For fast RNA access. */
+ struct FluidModifierData *mmd;
+ struct Mesh *mesh;
+ struct ParticleSystem *psys;
+ struct Tex *noise_texture;
+
+ /* Initial velocity. */
+ /* Previous vertex positions in domain space. */
+ float *verts_old;
+ int numverts;
+ float vel_multi; /* Multiplier for inherited velocity. */
+ float vel_normal;
+ float vel_random;
+ float vel_coord[3];
+ char _pad1[4];
+
+ /* -- User-accesible fields (from here on). -- */
+
+ /* Emission. */
+ float density;
+ float color[3];
+ float fuel_amount;
+ /* Delta temperature (temp - ambient temp). */
+ float temperature;
+ /* Density emitted within mesh volume. */
+ float volume_density;
+ /* Maximum emission distance from mesh surface. */
+ float surface_distance;
+ float particle_size;
+ int subframes;
+
+ /* Texture control. */
+ float texture_size;
+ float texture_offset;
+ char _pad2[4];
+ /* MAX_CUSTOMDATA_LAYER_NAME. */
+ char uvlayer_name[64];
+ short vgroup_density;
+
+ short type; /* Smoke, flames, both, outflow, liquid. */
+ short behavior; /* Inflow, outflow, static. */
+ short source;
+ short texture_type;
+ short _pad3[3];
+ int flags; /* Absolute emission etc. */
+} FluidFlowSettings;
+
+/* Effector types. */
+enum {
+ FLUID_EFFECTOR_TYPE_COLLISION = 0,
+ FLUID_EFFECTOR_TYPE_GUIDE = 1,
+};
+
+/* Guiding velocity modes. */
+enum {
+ FLUID_EFFECTOR_GUIDE_MAX = 0,
+ FLUID_EFFECTOR_GUIDE_MIN = 1,
+ FLUID_EFFECTOR_GUIDE_OVERRIDE = 2,
+ FLUID_EFFECTOR_GUIDE_AVERAGED = 3,
+};
+
+/* Collision objects (filled with smoke). */
+typedef struct FluidEffectorSettings {
+
+ /* -- Runtime-only fields (from here on). -- */
+
+ /* For fast RNA access. */
+ struct FluidModifierData *mmd;
+ struct Mesh *mesh;
+ float *verts_old;
+ int numverts;
+
+ /* -- User-accesible fields (from here on). -- */
+
+ float surface_distance; /* Thickness of mesh surface, used in obstacle sdf. */
+ int flags;
+ short type;
+ char _pad1[2];
+
+ /* Guiding options. */
+ float vel_multi; /* Multiplier for object velocity. */
+ short guide_mode;
+ char _pad2[2];
+} FluidEffectorSettings;
+
+#endif
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 5e4ed16d28e..1c58d03a1a8 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -56,6 +56,9 @@ typedef struct ImageUser {
short pass;
char _pad1[2];
+ int tile;
+ int _pad2;
+
/** Listbase indices, for menu browsing or retrieve buffer. */
short multi_index, view, layer;
short flag;
@@ -88,6 +91,19 @@ typedef struct RenderSlot {
struct RenderResult *render;
} RenderSlot;
+typedef struct ImageTile {
+ struct ImageTile *next, *prev;
+
+ /** Not written in file 2 = TEXTARGET_COUNT. */
+ struct GPUTexture *gputexture[2];
+
+ char ok;
+ char _pad[3];
+
+ int tile_number;
+ char label[64];
+} ImageTile;
+
/* iuser->flag */
#define IMA_ANIM_ALWAYS (1 << 0)
/* #define IMA_UNUSED_1 (1 << 1) */
@@ -109,8 +125,6 @@ typedef struct Image {
/** Not written in file. */
struct MovieCache *cache;
- /** Not written in file 2 = TEXTARGET_COUNT. */
- struct GPUTexture *gputexture[2];
/* sources from: */
ListBase anims;
@@ -134,8 +148,6 @@ typedef struct Image {
struct PreviewImage *preview;
int lastused;
- short ok;
- char _pad4[6];
/* for generated images */
int gen_x, gen_y;
@@ -150,12 +162,17 @@ typedef struct Image {
ColorManagedColorspaceSettings colorspace_settings;
char alpha_mode;
- char _pad[5];
+ char _pad;
/* Multiview */
/** For viewer node stereoscopy. */
char eye;
char views_format;
+
+ /* ImageTile list for UDIMs. */
+ int active_tile_index;
+ ListBase tiles;
+
/** ImageView. */
ListBase views;
struct Stereo3dFormat *stereo3d_format;
@@ -167,7 +184,7 @@ typedef struct Image {
enum {
IMA_FLAG_UNUSED_0 = (1 << 0), /* cleared */
IMA_FLAG_UNUSED_1 = (1 << 1), /* cleared */
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
IMA_DO_PREMUL = (1 << 2),
#endif
IMA_FLAG_UNUSED_4 = (1 << 4), /* cleared */
@@ -202,6 +219,7 @@ enum {
IMA_SRC_MOVIE = 3,
IMA_SRC_GENERATED = 4,
IMA_SRC_VIEWER = 5,
+ IMA_SRC_TILED = 6,
};
/* Image.type, how to handle or generate the image */
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index fb9e522dfa9..86ea22690ee 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -28,6 +28,10 @@
#include "DNA_ID.h"
#include "DNA_customdata_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct Ipo;
struct Key;
@@ -200,7 +204,7 @@ typedef struct Mesh {
} Mesh;
/* deprecated by MTFace, only here for file reading */
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
typedef struct TFace {
/** The faces image for the active UVLayer. */
void *tpage;
@@ -277,4 +281,8 @@ enum {
#define MESH_MAX_VERTS 2000000000L
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index a8db46238d8..9db993cca59 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -62,7 +62,9 @@ typedef enum ModifierType {
eModifierType_SimpleDeform = 28,
eModifierType_Multires = 29,
eModifierType_Surface = 30,
+#ifdef DNA_DEPRECATED_ALLOW
eModifierType_Smoke = 31,
+#endif
eModifierType_ShapeKey = 32,
eModifierType_Solidify = 33,
eModifierType_Screw = 34,
@@ -86,6 +88,8 @@ typedef enum ModifierType {
eModifierType_MeshSequenceCache = 52,
eModifierType_SurfaceDeform = 53,
eModifierType_WeightedNormal = 54,
+ eModifierType_Weld = 55,
+ eModifierType_Fluid = 56,
NUM_MODIFIER_TYPES,
} ModifierType;
@@ -450,24 +454,24 @@ enum {
MOD_BEVEL_VMESH_CUTOFF,
};
-typedef struct SmokeModifierData {
+typedef struct FluidModifierData {
ModifierData modifier;
- struct SmokeDomainSettings *domain;
+ struct FluidDomainSettings *domain;
/** Inflow, outflow, smoke objects. */
- struct SmokeFlowSettings *flow;
- /** Collision objects. */
- struct SmokeCollSettings *coll;
+ struct FluidFlowSettings *flow;
+ /** Effector objects (collision, guiding). */
+ struct FluidEffectorSettings *effector;
float time;
/** Domain, inflow, outflow, .... */
int type;
-} SmokeModifierData;
+} FluidModifierData;
-/* Smoke modifier flags */
+/* Fluid modifier flags */
enum {
- MOD_SMOKE_TYPE_DOMAIN = (1 << 0),
- MOD_SMOKE_TYPE_FLOW = (1 << 1),
- MOD_SMOKE_TYPE_COLL = (1 << 2),
+ MOD_FLUID_TYPE_DOMAIN = (1 << 0),
+ MOD_FLUID_TYPE_FLOW = (1 << 1),
+ MOD_FLUID_TYPE_EFFEC = (1 << 2),
};
typedef struct DisplaceModifierData {
@@ -976,6 +980,7 @@ typedef enum {
eMultiresModifierFlag_UseCrease = (1 << 2),
} MultiresModifierFlag;
+/* DEPRECATED, only used for versioning. */
typedef struct FluidsimModifierData {
ModifierData modifier;
@@ -983,6 +988,15 @@ typedef struct FluidsimModifierData {
struct FluidsimSettings *fss;
} FluidsimModifierData;
+/* DEPRECATED, only used for versioning. */
+typedef struct SmokeModifierData {
+ ModifierData modifier;
+
+ /** Domain, inflow, outflow, .... */
+ int type;
+ int _pad;
+} SmokeModifierData;
+
typedef struct ShrinkwrapModifierData {
ModifierData modifier;
@@ -1147,7 +1161,7 @@ enum {
MOD_SOLIDIFY_EVEN = (1 << 1),
MOD_SOLIDIFY_NORMAL_CALC = (1 << 2),
MOD_SOLIDIFY_VGROUP_INV = (1 << 3),
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
MOD_SOLIDIFY_RIM_MATERIAL = (1 << 4), /* deprecated, used in do_versions */
#endif
MOD_SOLIDIFY_FLIP = (1 << 5),
@@ -1594,7 +1608,7 @@ typedef struct TriangulateModifierData {
/* TriangulateModifierData.flag */
enum {
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
MOD_TRIANGULATE_BEAUTY = (1 << 0), /* deprecated */
#endif
MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS = 1 << 1,
@@ -1810,6 +1824,16 @@ enum {
MOD_WIREFRAME_CREASE = (1 << 5),
};
+typedef struct WeldModifierData {
+ ModifierData modifier;
+
+ /* The limit below which to merge vertices. */
+ float merge_dist;
+ unsigned int max_interactions;
+ /* Name of vertex group to use to mask, MAX_VGROUP_NAME. */
+ char defgrp_name[64];
+} WeldModifierData;
+
typedef struct DataTransferModifierData {
ModifierData modifier;
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index 8de79d9ea2b..2e0c43bdb51 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -24,6 +24,10 @@
#ifndef __DNA_MOVIECLIP_TYPES_H__
#define __DNA_MOVIECLIP_TYPES_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "DNA_ID.h"
#include "DNA_tracking_types.h"
#include "DNA_color_types.h" /* for color management */
@@ -207,4 +211,8 @@ enum {
MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER = 2,
};
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 7eecf23195a..22202717b0c 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1010,6 +1010,10 @@ typedef struct NodeShaderTexIES {
char filepath[1024];
} NodeShaderTexIES;
+typedef struct NodeShaderOutputAOV {
+ char name[64];
+} NodeShaderOutputAOV;
+
typedef struct NodeSunBeams {
float source[2];
@@ -1215,6 +1219,22 @@ enum {
NODE_MATH_CEIL = 21,
NODE_MATH_FRACTION = 22,
NODE_MATH_SQRT = 23,
+ NODE_MATH_INV_SQRT = 24,
+ NODE_MATH_SIGN = 25,
+ NODE_MATH_EXPONENT = 26,
+ NODE_MATH_RADIANS = 27,
+ NODE_MATH_DEGREES = 28,
+ NODE_MATH_SINH = 29,
+ NODE_MATH_COSH = 30,
+ NODE_MATH_TANH = 31,
+ NODE_MATH_TRUNC = 32,
+ NODE_MATH_SNAP = 33,
+ NODE_MATH_WRAP = 34,
+ NODE_MATH_COMPARE = 35,
+ NODE_MATH_MULTIPLY_ADD = 36,
+ NODE_MATH_PINGPONG = 37,
+ NODE_MATH_SMOOTH_MIN = 38,
+ NODE_MATH_SMOOTH_MAX = 39,
};
/* Vector Math node operations. */
@@ -1244,13 +1264,27 @@ enum {
NODE_VECTOR_MATH_MAXIMUM = 19,
};
+/* Clamp node types. */
+enum {
+ NODE_CLAMP_MINMAX = 0,
+ NODE_CLAMP_RANGE = 1,
+};
+
+/* Map range node types. */
+enum {
+ NODE_MAP_RANGE_LINEAR = 0,
+ NODE_MAP_RANGE_STEPPED = 1,
+ NODE_MAP_RANGE_SMOOTHSTEP = 2,
+ NODE_MAP_RANGE_SMOOTHERSTEP = 3,
+};
+
/* mix rgb node flags */
#define SHD_MIXRGB_USE_ALPHA 1
#define SHD_MIXRGB_CLAMP 2
/* subsurface */
enum {
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
SHD_SUBSURFACE_COMPATIBLE = 0, // Deprecated
#endif
SHD_SUBSURFACE_CUBIC = 1,
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index a1ea51ab573..fbed0754046 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -371,7 +371,8 @@ typedef struct Object {
struct Collection *instance_collection;
/** If fluidsim enabled, store additional settings. */
- struct FluidsimSettings *fluidsimSettings;
+ struct FluidsimSettings *fluidsimSettings
+ DNA_DEPRECATED; // XXX deprecated... replaced by mantaflow, keep for readfile
struct DerivedMesh *derivedDeform, *derivedFinal;
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index 4aaa1fe32f6..5012fbeca91 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -273,7 +273,7 @@ typedef struct ParticleSettings {
struct Collection *instance_collection;
struct ListBase instance_weights;
- struct Collection *eff_group DNA_DEPRECATED; // deprecated
+ struct Collection *force_group DNA_DEPRECATED; // deprecated
struct Object *instance_object;
struct Object *bb_ob;
/** Old animation system, deprecated for 2.5. */
@@ -406,7 +406,7 @@ typedef enum eParticleDrawFlag {
PART_DRAW_VEL = (1 << 0),
PART_DRAW_GLOBAL_OB = (1 << 1),
PART_DRAW_SIZE = (1 << 2),
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
/** Render emitter as well. */
PART_DRAW_EMITTER = (1 << 3), /* DEPRECATED */
#endif
@@ -429,13 +429,33 @@ typedef enum eParticleDrawFlag {
PART_DRAW_HAIR_GRID = (1 << 18),
} eParticleDrawFlag;
-/* part->type */
-/* hair is always baked static in object/geometry space */
-/* other types (normal particles) are in global space and not static baked */
-#define PART_EMITTER 0
-//#define PART_REACTOR 1
-#define PART_HAIR 2
-#define PART_FLUID 3
+/* part->type
+ * Hair is always baked static in object/geometry space.
+ * Other types (normal particles) are in global space and not static baked. */
+enum {
+ PART_EMITTER = 0,
+ /* REACTOR type currently unused */
+ /* PART_REACTOR = 1, */
+ PART_HAIR = 2,
+ PART_FLUID = 3, /* deprecated (belonged to elbeem) */
+ PART_FLUID_FLIP = 4,
+ PART_FLUID_SPRAY = 5,
+ PART_FLUID_BUBBLE = 6,
+ PART_FLUID_FOAM = 7,
+ PART_FLUID_TRACER = 8,
+};
+
+/* Mirroring Mantaflow particle types from particle.h (Mantaflow header). */
+enum {
+ PARTICLE_TYPE_NONE = (0 << 0),
+ PARTICLE_TYPE_NEW = (1 << 0),
+ PARTICLE_TYPE_SPRAY = (1 << 1),
+ PARTICLE_TYPE_BUBBLE = (1 << 2),
+ PARTICLE_TYPE_FOAM = (1 << 3),
+ PARTICLE_TYPE_TRACER = (1 << 4),
+ PARTICLE_TYPE_DELETE = (1 << 10),
+ PARTICLE_TYPE_INVALID = (1 << 30),
+};
/* part->flag */
#define PART_REACT_STA_END 1
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 0de43c1632f..7cfd19b4bd9 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -101,7 +101,7 @@ typedef struct AviCodecData {
typedef enum eFFMpegPreset {
FFM_PRESET_NONE,
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
/* Previously used by h.264 to control encoding speed vs. file size. */
FFM_PRESET_ULTRAFAST, /* DEPRECATED */
FFM_PRESET_SUPERFAST, /* DEPRECATED */
@@ -483,13 +483,23 @@ typedef struct ImageFormatData {
#define R_IMF_FLAG_PREVIEW_JPG (1 << 1) /* was R_PREVIEW_JPG */
/* return values from BKE_imtype_valid_depths, note this is depts per channel */
-#define R_IMF_CHAN_DEPTH_1 (1 << 0) /* 1bits (unused) */
-#define R_IMF_CHAN_DEPTH_8 (1 << 1) /* 8bits (default) */
-#define R_IMF_CHAN_DEPTH_10 (1 << 2) /* 10bits (uncommon, Cineon/DPX support) */
-#define R_IMF_CHAN_DEPTH_12 (1 << 3) /* 12bits (uncommon, jp2/DPX support) */
-#define R_IMF_CHAN_DEPTH_16 (1 << 4) /* 16bits (tiff, halff float exr) */
-#define R_IMF_CHAN_DEPTH_24 (1 << 5) /* 24bits (unused) */
-#define R_IMF_CHAN_DEPTH_32 (1 << 6) /* 32bits (full float exr) */
+/* ImageFormatData.depth */
+typedef enum eImageFormatDepth {
+ /* 1bits (unused) */
+ R_IMF_CHAN_DEPTH_1 = (1 << 0),
+ /* 8bits (default) */
+ R_IMF_CHAN_DEPTH_8 = (1 << 1),
+ /* 10bits (uncommon, Cineon/DPX support) */
+ R_IMF_CHAN_DEPTH_10 = (1 << 2),
+ /* 12bits (uncommon, jp2/DPX support) */
+ R_IMF_CHAN_DEPTH_12 = (1 << 3),
+ /* 16bits (tiff, half float exr) */
+ R_IMF_CHAN_DEPTH_16 = (1 << 4),
+ /* 24bits (unused) */
+ R_IMF_CHAN_DEPTH_24 = (1 << 5),
+ /* 32bits (full float exr) */
+ R_IMF_CHAN_DEPTH_32 = (1 << 6),
+} eImageFormatDepth;
/* ImageFormatData.planes */
#define R_IMF_PLANES_RGB 24
@@ -1267,6 +1277,9 @@ typedef struct UnifiedPaintSettings {
/* radius of brush, premultiplied with pressure.
* In case of anchored brushes contains the anchored radius */
float pixel_radius;
+ float initial_pixel_radius;
+
+ char _pad[4];
/* drawing pressure */
float size_pressure_value;
@@ -1288,14 +1301,11 @@ typedef enum {
UNIFIED_PAINT_WEIGHT = (1 << 5),
UNIFIED_PAINT_COLOR = (1 << 6),
- /* only used if unified size is enabled, mirrors the brush flags
- * BRUSH_LOCK_SIZE and BRUSH_SIZE_PRESSURE */
+ /* only used if unified size is enabled, mirrors the brush flag BRUSH_LOCK_SIZE */
UNIFIED_PAINT_BRUSH_LOCK_SIZE = (1 << 2),
- UNIFIED_PAINT_BRUSH_SIZE_PRESSURE = (1 << 3),
+ UNIFIED_PAINT_FLAG_UNUSED_0 = (1 << 3),
- /* only used if unified alpha is enabled, mirrors the brush flag
- * BRUSH_ALPHA_PRESSURE */
- UNIFIED_PAINT_BRUSH_ALPHA_PRESSURE = (1 << 4),
+ UNIFIED_PAINT_FLAG_UNUSED_1 = (1 << 4),
} eUnifiedPaintSettingsFlags;
typedef struct CurvePaintSettings {
@@ -1502,7 +1512,10 @@ typedef struct ToolSettings {
/* XXX: these sculpt_paint_* fields are deprecated, use the
* unified_paint_settings field instead! */
short sculpt_paint_settings DNA_DEPRECATED;
- char _pad5[2];
+
+ char workspace_tool_type;
+
+ char _pad5[1];
int sculpt_paint_unified_size DNA_DEPRECATED;
float sculpt_paint_unified_unprojected_radius DNA_DEPRECATED;
float sculpt_paint_unified_alpha DNA_DEPRECATED;
@@ -1916,7 +1929,7 @@ enum {
R_COLOR_MANAGEMENT_UNUSED_1 = (1 << 1),
};
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
/* RenderData.subimtype flag options for imtype */
enum {
R_OPENEXR_HALF = (1 << 0), /*deprecated*/
@@ -2035,6 +2048,12 @@ enum {
SCE_OBJECT_MODE_LOCK = (1 << 0),
};
+/* ToolSettings.workspace_tool_flag */
+enum {
+ SCE_WORKSPACE_TOOL_FALLBACK = 0,
+ SCE_WORKSPACE_TOOL_DEFAULT = 1,
+};
+
/* ToolSettings.snap_flag */
#define SCE_SNAP (1 << 0)
#define SCE_SNAP_ROTATE (1 << 1)
@@ -2150,7 +2169,7 @@ typedef enum eVGroupSelect {
/* FFMpegCodecData.flags */
enum {
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
FFMPEG_MULTIPLEX_AUDIO = (1 << 0), /* deprecated, you can choose none as audiocodec now */
#endif
FFMPEG_AUTOSPLIT_OUTPUT = (1 << 1),
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index ec42e9bd04f..d3c5a707b44 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -382,6 +382,9 @@ typedef struct ARegion_Runtime {
*
* Lazy initialize, zero'd when unset, relative to #ARegion.winrct x/y min. */
rcti visible_rect;
+
+ /* The offset needed to not overlap with window scrollbars. Only used by HUD regions for now. */
+ int offset_x, offset_y;
} ARegion_Runtime;
typedef struct ARegion {
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 8d9dc77c49b..fb941a61ae8 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -37,6 +37,10 @@
#include "DNA_vec_types.h"
#include "DNA_vfont_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct Ipo;
struct MovieClip;
struct Scene;
@@ -680,4 +684,8 @@ enum {
SEQ_CACHE_PREFETCH_ENABLE = (1 << 10),
};
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __DNA_SEQUENCE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
deleted file mode 100644
index d795800df2f..00000000000
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2006 by NaN Holding BV.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup DNA
- */
-
-#ifndef __DNA_SMOKE_TYPES_H__
-#define __DNA_SMOKE_TYPES_H__
-
-/* flags */
-enum {
- MOD_SMOKE_HIGHRES = (1 << 1), /* enable high resolution */
- MOD_SMOKE_DISSOLVE = (1 << 2), /* let smoke dissolve */
- MOD_SMOKE_DISSOLVE_LOG = (1 << 3), /* using 1/x for dissolve */
-
-#ifdef DNA_DEPRECATED
- MOD_SMOKE_HIGH_SMOOTH = (1 << 5), /* -- Deprecated -- */
-#endif
- MOD_SMOKE_FILE_LOAD = (1 << 6), /* flag for file load */
- MOD_SMOKE_ADAPTIVE_DOMAIN = (1 << 7),
-};
-
-/* noise */
-#define MOD_SMOKE_NOISEWAVE (1 << 0)
-#define MOD_SMOKE_NOISEFFT (1 << 1)
-#define MOD_SMOKE_NOISECURL (1 << 2)
-/* viewsettings */
-#define MOD_SMOKE_VIEW_SHOW_HIGHRES (1 << 0)
-
-/* slice method */
-enum {
- MOD_SMOKE_SLICE_VIEW_ALIGNED = 0,
- MOD_SMOKE_SLICE_AXIS_ALIGNED = 1,
-};
-
-/* axis aligned method */
-enum {
- AXIS_SLICE_FULL = 0,
- AXIS_SLICE_SINGLE = 1,
-};
-
-/* single slice direction */
-enum {
- SLICE_AXIS_AUTO = 0,
- SLICE_AXIS_X = 1,
- SLICE_AXIS_Y = 2,
- SLICE_AXIS_Z = 3,
-};
-
-/* axis aligned method */
-enum {
- VOLUME_INTERP_LINEAR = 0,
- VOLUME_INTERP_CUBIC = 1,
-};
-
-enum {
- VECTOR_DRAW_NEEDLE = 0,
- VECTOR_DRAW_STREAMLINE = 1,
-};
-
-enum {
- FLUID_FIELD_DENSITY = 0,
- FLUID_FIELD_HEAT = 1,
- FLUID_FIELD_FUEL = 2,
- FLUID_FIELD_REACT = 3,
- FLUID_FIELD_FLAME = 4,
- FLUID_FIELD_VELOCITY_X = 5,
- FLUID_FIELD_VELOCITY_Y = 6,
- FLUID_FIELD_VELOCITY_Z = 7,
- FLUID_FIELD_COLOR_R = 8,
- FLUID_FIELD_COLOR_G = 9,
- FLUID_FIELD_COLOR_B = 10,
- FLUID_FIELD_FORCE_X = 11,
- FLUID_FIELD_FORCE_Y = 12,
- FLUID_FIELD_FORCE_Z = 13,
-};
-
-/* cache compression */
-#define SM_CACHE_LIGHT 0
-#define SM_CACHE_HEAVY 1
-
-/* domain border collision */
-#define SM_BORDER_OPEN 0
-#define SM_BORDER_VERTICAL 1
-#define SM_BORDER_CLOSED 2
-
-/* collision types */
-#define SM_COLL_STATIC 0
-#define SM_COLL_RIGID 1
-#define SM_COLL_ANIMATED 2
-
-/* high resolution sampling types */
-#define SM_HRES_NEAREST 0
-#define SM_HRES_LINEAR 1
-#define SM_HRES_FULLSAMPLE 2
-
-/* smoke data fields (active_fields) */
-#define SM_ACTIVE_HEAT (1 << 0)
-#define SM_ACTIVE_FIRE (1 << 1)
-#define SM_ACTIVE_COLORS (1 << 2)
-#define SM_ACTIVE_COLOR_SET (1 << 3)
-
-enum {
- VDB_COMPRESSION_BLOSC = 0,
- VDB_COMPRESSION_ZIP = 1,
- VDB_COMPRESSION_NONE = 2,
-};
-
-typedef struct SmokeDomainSettings {
- /** For fast RNA access. */
- struct SmokeModifierData *smd;
- struct FLUID_3D *fluid;
- void *fluid_mutex;
- struct Collection *fluid_group;
- struct Collection *eff_group; // UNUSED
- struct Collection *coll_group; // collision objects group
- struct WTURBULENCE *wt; // WTURBULENCE object, if active
- struct GPUTexture *tex;
- struct GPUTexture *tex_wt;
- struct GPUTexture *tex_shadow;
- struct GPUTexture *tex_flame;
- struct GPUTexture *tex_flame_coba;
- struct GPUTexture *tex_coba;
- struct GPUTexture *tex_field;
- struct GPUTexture *tex_velocity_x;
- struct GPUTexture *tex_velocity_y;
- struct GPUTexture *tex_velocity_z;
- float *shadow;
-
- /* simulation data */
- /** Start point of BB in local space (includes sub-cell shift for adaptive domain.)*/
- float p0[3];
- /** End point of BB in local space. */
- float p1[3];
- /** Difference from object center to grid start point. */
- float dp0[3];
- /** Size of simulation cell in local space. */
- float cell_size[3];
- /** Global size of domain axises. */
- float global_size[3];
- float prev_loc[3];
- /** Current domain shift in simulation cells. */
- int shift[3];
- /** Exact domain shift. */
- float shift_f[3];
- /**
- * How much object has shifted since previous smoke frame
- * (used to "lock" domain while drawing).
- */
- float obj_shift_f[3];
- /** Domain object imat. */
- float imat[4][4];
- /** Domain obmat. */
- float obmat[4][4];
- /** Low res fluid matrix. */
- float fluidmat[4][4];
- /** High res fluid matrix. */
- float fluidmat_wt[4][4];
-
- /** Initial "non-adapted" resolution. */
- int base_res[3];
- /** Cell min. */
- int res_min[3];
- /** Cell max. */
- int res_max[3];
- /** Data resolution (res_max-res_min). */
- int res[3];
- int total_cells;
- /** 1.0f / res. */
- float dx;
- /** Largest domain size. */
- float scale;
-
- /* user settings */
- int adapt_margin;
- int adapt_res;
- float adapt_threshold;
-
- float alpha;
- float beta;
- /** Wavelet amplification. */
- int amplify;
- /** Longest axis on the BB gets this resolution assigned. */
- int maxres;
- /** Show up-res or low res, etc. */
- int flags;
- int viewsettings;
- /** Noise type: wave, curl, anisotropic. */
- short noise;
- short diss_percent;
- /** In frames. */
- int diss_speed;
- float strength;
- int res_wt[3];
- float dx_wt;
- /* point cache options */
- int cache_comp;
- int cache_high_comp;
- /* OpenVDB cache options */
- int openvdb_comp;
- char cache_file_format;
- char data_depth;
- char _pad[2];
-
- /* Smoke uses only one cache from now on (index [0]),
- * but keeping the array for now for reading old files. */
- /** Definition is in DNA_object_force_types.h. */
- struct PointCache *point_cache[2];
- struct ListBase ptcaches[2];
- struct EffectorWeights *effector_weights;
- /** How domain border collisions are handled. */
- int border_collisions;
- float time_scale;
- float vorticity;
- int active_fields;
- /** Monitor color situation of simulation. */
- float active_color[3];
- int highres_sampling;
-
- /* flame parameters */
- float burning_rate, flame_smoke, flame_vorticity;
- float flame_ignition, flame_max_temp;
- float flame_smoke_color[3];
-
- /* Display settings */
- char slice_method, axis_slice_method;
- char slice_axis, draw_velocity;
- float slice_per_voxel;
- float slice_depth;
- float display_thickness;
-
- struct ColorBand *coba;
- float vector_scale;
- char vector_draw_type;
- char use_coba;
- /** Simulation field used for the color mapping. */
- char coba_field;
- char interp_method;
-
- float clipping;
- char _pad3[4];
-} SmokeDomainSettings;
-
-/* inflow / outflow */
-
-/* type */
-#define MOD_SMOKE_FLOW_TYPE_SMOKE 0
-#define MOD_SMOKE_FLOW_TYPE_FIRE 1
-#define MOD_SMOKE_FLOW_TYPE_OUTFLOW 2
-#define MOD_SMOKE_FLOW_TYPE_SMOKEFIRE 3
-
-/* flow source */
-#define MOD_SMOKE_FLOW_SOURCE_PARTICLES 0
-#define MOD_SMOKE_FLOW_SOURCE_MESH 1
-
-/* flow texture type */
-#define MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO 0
-#define MOD_SMOKE_FLOW_TEXTURE_MAP_UV 1
-
-/* flags */
-enum {
- /** Old style emission. */
- MOD_SMOKE_FLOW_ABSOLUTE = (1 << 1),
- /** Passes particles speed to the smoke. */
- MOD_SMOKE_FLOW_INITVELOCITY = (1 << 2),
- /** Use texture to control emission speed. */
- MOD_SMOKE_FLOW_TEXTUREEMIT = (1 << 3),
- /** Use specific size for particles instead of closest cell. */
- MOD_SMOKE_FLOW_USE_PART_SIZE = (1 << 4),
-};
-
-typedef struct SmokeFlowSettings {
- /** For fast RNA access. */
- struct SmokeModifierData *smd;
- struct Mesh *mesh;
- struct ParticleSystem *psys;
- struct Tex *noise_texture;
-
- /* initial velocity */
- /** Previous vertex positions in domain space. */
- float *verts_old;
- int numverts;
- float vel_multi; // Multiplier for inherited velocity
- float vel_normal;
- float vel_random;
- /* emission */
- float density;
- float color[3];
- float fuel_amount;
- /** Delta temperature (temp - ambient temp). */
- float temp;
- /** Density emitted within mesh volume. */
- float volume_density;
- /** Maximum emission distance from mesh surface. */
- float surface_distance;
- float particle_size;
- int subframes;
- /* texture control */
- float texture_size;
- float texture_offset;
- char _pad[4];
- /** MAX_CUSTOMDATA_LAYER_NAME. */
- char uvlayer_name[64];
- short vgroup_density;
-
- /** Smoke, flames, both, outflow. */
- short type;
- short source;
- short texture_type;
- /** Absolute emission et.c*/
- int flags;
-} SmokeFlowSettings;
-
-// struct BVHTreeFromMesh *bvh;
-// float mat[4][4];
-// float mat_old[4][4];
-
-/* collision objects (filled with smoke) */
-typedef struct SmokeCollSettings {
- /** For fast RNA access. */
- struct SmokeModifierData *smd;
- struct Mesh *mesh;
- float *verts_old;
- int numverts;
- short type; // static = 0, rigid = 1, dynamic = 2
- char _pad[2];
-} SmokeCollSettings;
-
-#endif
diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h
index 1c1bb9b9ce1..81548343da0 100644
--- a/source/blender/makesdna/DNA_sound_types.h
+++ b/source/blender/makesdna/DNA_sound_types.h
@@ -112,7 +112,7 @@ enum {
/* bSound->flags */
enum {
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
/* deprecated! used for sound actuator loading */
SOUND_FLAGS_3D = (1 << 3),
#endif
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 9e8bda2d12f..7adba2b7dbe 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -466,8 +466,8 @@ typedef enum eGraphEdit_Flag {
/* normalize curves on display */
SIPO_NORMALIZE = (1 << 14),
SIPO_NORMALIZE_FREEZE = (1 << 15),
- /* show vertical line for every marker */
- SIPO_MARKER_LINES = (1 << 16),
+ /* show markers region */
+ SIPO_SHOW_MARKERS = (1 << 16),
} eGraphEdit_Flag;
/* SpaceGraph.mode (Graph Editor Mode) */
@@ -532,8 +532,8 @@ typedef enum eSpaceNla_Flag {
SNLA_NOREALTIMEUPDATES = (1 << 6),
/* don't show local strip marker indications */
SNLA_NOLOCALMARKERS = (1 << 7),
- /* show vertical line for every marker */
- SNLA_SHOW_MARKER_LINES = (1 << 8),
+ /* show markers region */
+ SNLA_SHOW_MARKERS = (1 << 8),
} eSpaceNla_Flag;
/** \} */
@@ -615,7 +615,7 @@ typedef enum eSpaceSeq_Flag {
SEQ_NO_WAVEFORMS = (1 << 8), /* draw no waveforms */
SEQ_SHOW_SAFE_CENTER = (1 << 9),
SEQ_SHOW_METADATA = (1 << 10),
- SEQ_SHOW_MARKER_LINES = (1 << 11),
+ SEQ_SHOW_MARKERS = (1 << 11), /* show markers region */
} eSpaceSeq_Flag;
/* SpaceSeq.view */
@@ -859,6 +859,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_ALEMBIC = (1 << 16),
/** For all kinds of recognized import/export formats. No need for specialized types. */
FILE_TYPE_OBJECT_IO = (1 << 17),
+ FILE_TYPE_USD = (1 << 18),
/** An FS directory (i.e. S_ISDIR on its path is true). */
FILE_TYPE_DIR = (1 << 30),
@@ -1070,6 +1071,8 @@ typedef struct SpaceImage {
char pixel_snap_mode;
char _pad2[3];
+ int tile_grid_shape[2];
+
MaskSpaceInfo mask_info;
} SpaceImage;
@@ -1167,6 +1170,41 @@ typedef enum eSpaceImage_OtherUVFilter {
/** \name Text Editor
* \{ */
+typedef struct SpaceText_Runtime {
+
+ /** Actual line height, scaled by dpi. */
+ int lheight_px;
+
+ /** Runtime computed, character width. */
+ int cwidth_px;
+
+ /** The handle of the scroll-bar which can be clicked and dragged. */
+ struct rcti scroll_region_handle;
+ /** The region for selected text to show in the scrolling area. */
+ struct rcti scroll_region_select;
+
+ /** Number of digits to show in the line numbers column (when enabled). */
+ int line_number_display_digits;
+
+ /** Number of lines this window can display (even when they aren't used). */
+ int viewlines;
+
+ /** Use for drawing scroll-bar & calculating scroll operator motion scaling. */
+ float scroll_px_per_line;
+
+ /**
+ * Run-time for scroll increments smaller than a line (smooth scroll).
+ * Values must be between zero and the line, column width: (cwidth, TXT_LINE_HEIGHT(st)).
+ */
+ int scroll_ofs_px[2];
+
+ char _pad1[4];
+
+ /** Cache for faster drawing. */
+ void *drawcache;
+
+} SpaceText_Runtime;
+
/* Text Editor */
typedef struct SpaceText {
SpaceLink *next, *prev;
@@ -1179,30 +1217,26 @@ typedef struct SpaceText {
struct Text *text;
- int top, viewlines;
- short flags, menunr;
+ int top, left;
+ char _pad1[4];
+
+ short flags;
/** User preference, is font_size! */
short lheight;
- /**
- * Runtime computed, character width
- * and the number of chars to use when showing line numbers.
- */
- char cwidth, linenrs_tot;
- int left;
- int showlinenrs;
+
int tabnumber;
- short showsyntax;
- short line_hlight;
- short overwrite;
+ /* Booleans */
+ char wordwrap;
+ char doplugins;
+ char showlinenrs;
+ char showsyntax;
+ char line_hlight;
+ char overwrite;
/** Run python while editing, evil. */
- short live_edit;
- float pix_per_line;
-
- struct rcti txtscroll, txtbar;
-
- int wordwrap, doplugins;
+ char live_edit;
+ char _pad2[1];
/** ST_MAX_FIND_STR. */
char findstr[256];
@@ -1211,26 +1245,18 @@ typedef struct SpaceText {
/** Column number to show right margin at. */
short margin_column;
- /** Actual lineheight, dpi controlled. */
- short lheight_dpi;
- char _pad[4];
+ char _pad3[2];
- /** Cache for faster drawing. */
- void *drawcache;
-
- /**
- * Run-time for scroll increments smaller than a line (smooth scroll).
- * Values must be between zero and the line, column width: (cwidth, TXT_LINE_HEIGHT(st)).
- */
- int scroll_ofs_px[2];
+ /** Keep last. */
+ SpaceText_Runtime runtime;
} SpaceText;
/* SpaceText flags (moved from DNA_text_types.h) */
typedef enum eSpaceText_Flags {
/* scrollable */
ST_SCROLL_SELECT = (1 << 0),
- /* clear namespace after script execution (BPY_main.c) */
- ST_CLEAR_NAMESPACE = (1 << 4),
+
+ ST_FLAG_UNUSED_4 = (1 << 4), /* dirty */
ST_FIND_WRAP = (1 << 5),
ST_FIND_ALL = (1 << 6),
@@ -1469,6 +1495,7 @@ typedef struct SpaceConsole {
/** Multiple consoles are possible, not just python. */
char language[32];
+ /** Selection offset in bytes. */
int sel_start;
int sel_end;
} SpaceConsole;
@@ -1670,7 +1697,7 @@ typedef enum eSpace_Type {
SPACE_INFO = 7,
SPACE_SEQ = 8,
SPACE_TEXT = 9,
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
SPACE_IMASEL = 10, /* Deprecated */
SPACE_SOUND = 11, /* Deprecated */
#endif
@@ -1678,11 +1705,11 @@ typedef enum eSpace_Type {
SPACE_NLA = 13,
/* TODO: fully deprecate */
SPACE_SCRIPT = 14, /* Deprecated */
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
SPACE_TIME = 15, /* Deprecated */
#endif
SPACE_NODE = 16,
-#ifdef DNA_DEPRECATED
+#ifdef DNA_DEPRECATED_ALLOW
SPACE_LOGIC = 17, /* Deprecated */
#endif
SPACE_CONSOLE = 18,
diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h
index 4eec2c1fde8..8303f2322b6 100644
--- a/source/blender/makesdna/DNA_text_types.h
+++ b/source/blender/makesdna/DNA_text_types.h
@@ -36,7 +36,8 @@ typedef struct TextLine {
/** May be NULL if syntax is off or not yet formatted. */
char *format;
/** Blen unused. */
- int len, blen;
+ int len;
+ char _pad0[4];
} TextLine;
typedef struct Text {
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 11a0e441392..f0a852a7a1a 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -276,7 +276,7 @@ typedef struct ThemeSpace {
unsigned char edge[4], edge_select[4];
unsigned char edge_seam[4], edge_sharp[4], edge_facesel[4], edge_crease[4], edge_bevel[4];
/** Solid faces. */
- unsigned char face[4], face_select[4];
+ unsigned char face[4], face_select[4], face_back[4], face_front[4];
/** selected color. */
unsigned char face_dot[4];
unsigned char extra_edge_len[4], extra_edge_angle[4], extra_face_angle[4], extra_face_area[4];
@@ -600,16 +600,13 @@ typedef struct UserDef_FileSpaceData {
int temp_win_sizey;
} UserDef_FileSpaceData;
-/**
- * Store UI data here instead of the space
- * since the space is typically a window which is freed.
- */
typedef struct UserDef_Experimental {
- /** #eUserPref_Experimental_Flag options. */
- int flag;
- char _pad0[4];
+ char _pad0[8]; /* makesdna does not allow empty structs. */
} UserDef_Experimental;
+#define USER_EXPERIMENTAL_TEST(userdef, member) \
+ (((userdef)->flag & USER_DEVELOPER_UI) && ((userdef)->experimental).member)
+
typedef struct UserDef {
/** UserDef has separate do-version handling, and can be read from other files. */
int versionfile, subversionfile;
@@ -905,11 +902,6 @@ typedef enum eUserPref_SpaceData_Flag {
USER_SPACEDATA_ADDONS_SHOW_ONLY_ENABLED = (1 << 1),
} eUserPref_SpaceData_Flag;
-/** #UserDef_Experimental.flag. */
-typedef enum eUserPref_Experimental_Flag {
- USER_EXPERIMENTAL_ALL = (1 << 0),
-} eUserPref_Experimental_Flag;
-
/** #UserDef.flag */
typedef enum eUserPref_Flag {
USER_AUTOSAVE = (1 << 0),
@@ -1017,10 +1009,10 @@ typedef enum eUserpref_UI_Flag {
USER_ZOOM_HORIZ = (1 << 26), /* for CONTINUE and DOLLY zoom */
USER_SPLASH_DISABLE = (1 << 27),
USER_HIDE_RECENT = (1 << 28),
-#ifdef DNA_DEPRECATED
- USER_SHOW_THUMBNAILS =
- (1 << 29), /* deprecated - We're just trying if there's much desire for this feature, or if
- we can make it go for good. Should be cleared if so - Julian, Oct. 2019 */
+#ifdef DNA_DEPRECATED_ALLOW
+ /* Deprecated: We're just trying if there's much desire for this feature,
+ * or if we can make it go for good. Should be cleared if so - Julian, Oct. 2019. */
+ USER_SHOW_THUMBNAILS = (1 << 29),
#endif
USER_SAVE_PROMPT = (1 << 30),
USER_HIDE_SYSTEM_BOOKMARKS = (1u << 31),
@@ -1042,6 +1034,7 @@ typedef enum eUserpref_UI_Flag2 {
typedef enum eUserpref_GPU_Flag {
USER_GPU_FLAG_NO_DEPT_PICK = (1 << 0),
USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE = (1 << 1),
+ USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE = (1 << 2),
} eUserpref_GPU_Flag;
/** #UserDef.tablet_api */
diff --git a/source/blender/makesdna/DNA_view3d_defaults.h b/source/blender/makesdna/DNA_view3d_defaults.h
index 365b1993d80..f6c8c0b1f6d 100644
--- a/source/blender/makesdna/DNA_view3d_defaults.h
+++ b/source/blender/makesdna/DNA_view3d_defaults.h
@@ -46,6 +46,7 @@
.single_color = {0.8f, 0.8f, 0.8f}, \
.background_color = {0.05f, 0.05f, 0.05f}, \
.studiolight_intensity = 1.0f, \
+ .render_pass = SCE_PASS_COMBINED, \
}
#define _DNA_DEFAULT_View3DOverlay \
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index ee0a94e0a5c..2555f111f73 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -179,6 +179,10 @@ typedef struct View3DShading {
float curvature_ridge_factor;
float curvature_valley_factor;
+ /* Render pass displayed in the viewport. Is an `eScenePassType` where one bit is set */
+ int render_pass;
+ char _pad2[4];
+
struct IDProperty *prop;
} View3DShading;
@@ -372,6 +376,9 @@ typedef struct View3D {
#define RV3D_VIEW_CAMERA 8
#define RV3D_VIEW_IS_AXIS(view) (((view) >= RV3D_VIEW_FRONT) && ((view) <= RV3D_VIEW_BOTTOM))
+#define RV3D_CLIPPING_ENABLED(v3d, rv3d) \
+ (rv3d && v3d && (rv3d->rflag & RV3D_CLIPPING) && ELEM(v3d->shading.type, OB_WIRE, OB_SOLID) && \
+ rv3d->clipbb)
/** #View3D.flag2 (int) */
#define V3D_HIDE_OVERLAYS (1 << 2)
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index dbfb0cc6346..d2461657480 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -35,6 +35,9 @@ typedef struct bToolRef_Runtime {
char gizmo_group[64];
char data_block[64];
+ /** Keymap for #bToolRef.idname_fallback, if set. */
+ char keymap_fallback[64];
+
/** Use to infer primary operator to use when setting accelerator keys. */
char op[64];
@@ -47,6 +50,9 @@ typedef struct bToolRef {
struct bToolRef *next, *prev;
char idname[64];
+ /** Optionally use these when not interacting directly with the primary tools gizmo. */
+ char idname_fallback[64];
+
/** Use to avoid initializing the same tool multiple times. */
short tag;
diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h
index af1e5123dc8..8d9fd9f1af4 100644
--- a/source/blender/makesdna/DNA_world_types.h
+++ b/source/blender/makesdna/DNA_world_types.h
@@ -85,9 +85,6 @@ typedef struct World {
/* nodes */
struct bNodeTree *nodetree;
- /** Runtime : miststa + mistdist, used for drawing camera. */
- float mistend;
- char _pad1[4];
/** Runtime. */
ListBase gpumaterial;
} World;
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 0bc35c15e35..404f483fde2 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -68,6 +68,13 @@ DNA_STRUCT_RENAME_ELEM(Camera, YF_dofdist, dof_distance)
DNA_STRUCT_RENAME_ELEM(Camera, clipend, clip_end)
DNA_STRUCT_RENAME_ELEM(Camera, clipsta, clip_start)
DNA_STRUCT_RENAME_ELEM(Collection, dupli_ofs, instance_offset)
+DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, cache_frame_pause_guiding, cache_frame_pause_guide)
+DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_alpha, guide_alpha)
+DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_beta, guide_beta)
+DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_parent, guide_parent)
+DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_source, guide_source)
+DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_vel_factor, guide_vel_factor)
+DNA_STRUCT_RENAME_ELEM(FluidEffectorSettings, guiding_mode, guide_mode)
DNA_STRUCT_RENAME_ELEM(Object, col, color)
DNA_STRUCT_RENAME_ELEM(Object, dup_group, instance_collection)
DNA_STRUCT_RENAME_ELEM(Object, dupfacesca, instance_faces_scale)
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index b131b1cce93..e292c0216f6 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -118,7 +118,7 @@ static const char *includefiles[] = {
"DNA_windowmanager_types.h",
"DNA_anim_types.h",
"DNA_boid_types.h",
- "DNA_smoke_types.h",
+ "DNA_fluid_types.h",
"DNA_speaker_types.h",
"DNA_movieclip_types.h",
"DNA_tracking_types.h",
@@ -904,7 +904,8 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char
/* Write test to verify sizes are accurate. */
fprintf(file_verify, "/* Verify struct sizes and member offsets are as expected by DNA. */\n");
fprintf(file_verify, "#include \"BLI_assert.h\"\n\n");
- fprintf(file_verify, "#define DNA_DEPRECATED\n");
+ /* Needed so we can find offsets of deprecated structs. */
+ fprintf(file_verify, "#define DNA_DEPRECATED_ALLOW\n");
/* Workaround enum naming collision in static asserts
* (ideally this included a unique name/id per file). */
fprintf(file_verify, "#define assert_line_ assert_line_DNA_\n");
@@ -1580,7 +1581,7 @@ int main(int argc, char **argv)
#include "DNA_windowmanager_types.h"
#include "DNA_anim_types.h"
#include "DNA_boid_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_speaker_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_tracking_types.h"
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 182f41873d1..211739eed24 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -35,6 +35,7 @@ struct ID;
struct IDOverrideLibrary;
struct IDOverrideLibraryProperty;
struct IDOverrideLibraryPropertyOperation;
+struct IDProperty;
struct ListBase;
struct Main;
struct ReportList;
@@ -261,7 +262,6 @@ extern StructRNA RNA_FloatProperty;
extern StructRNA RNA_FloorConstraint;
extern StructRNA RNA_FluidFluidSettings;
extern StructRNA RNA_FluidSettings;
-extern StructRNA RNA_FluidSimulationModifier;
extern StructRNA RNA_FollowPathConstraint;
extern StructRNA RNA_FreestyleLineSet;
extern StructRNA RNA_FreestyleLineStyle;
@@ -573,6 +573,7 @@ extern StructRNA RNA_ShaderNodeMath;
extern StructRNA RNA_ShaderNodeMixRGB;
extern StructRNA RNA_ShaderNodeNormal;
extern StructRNA RNA_ShaderNodeOutput;
+extern StructRNA RNA_ShaderNodeOutputAOV;
extern StructRNA RNA_ShaderNodeRGB;
extern StructRNA RNA_ShaderNodeRGBCurve;
extern StructRNA RNA_ShaderNodeRGBToBW;
@@ -594,10 +595,10 @@ extern StructRNA RNA_ShrinkwrapModifier;
extern StructRNA RNA_SimpleDeformModifier;
extern StructRNA RNA_SimplifyGpencilModifier;
extern StructRNA RNA_SkinModifier;
-extern StructRNA RNA_SmokeCollSettings;
-extern StructRNA RNA_SmokeDomainSettings;
-extern StructRNA RNA_SmokeFlowSettings;
-extern StructRNA RNA_SmokeModifier;
+extern StructRNA RNA_FluidEffectorSettings;
+extern StructRNA RNA_FluidDomainSettings;
+extern StructRNA RNA_FluidFlowSettings;
+extern StructRNA RNA_FluidModifier;
extern StructRNA RNA_SmoothGpencilModifier;
extern StructRNA RNA_SmoothModifier;
extern StructRNA RNA_SoftBodyModifier;
@@ -739,6 +740,7 @@ extern StructRNA RNA_Window;
extern StructRNA RNA_WindowManager;
extern StructRNA RNA_WipeSequence;
extern StructRNA RNA_WireframeModifier;
+extern StructRNA RNA_WeldModifier;
extern StructRNA RNA_WoodTexture;
extern StructRNA RNA_WorkSpace;
extern StructRNA RNA_World;
@@ -1157,6 +1159,8 @@ struct PropertyElemRNA {
};
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements);
+char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, struct IDProperty *needle);
+
struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path);
char *RNA_path_from_ID_to_struct(PointerRNA *ptr);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 9290b81f1af..d7f6ec1fb5a 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -188,6 +188,8 @@ extern const EnumPropertyItem rna_enum_node_math_items[];
extern const EnumPropertyItem rna_enum_mapping_type_items[];
extern const EnumPropertyItem rna_enum_node_vec_math_items[];
extern const EnumPropertyItem rna_enum_node_filter_items[];
+extern const EnumPropertyItem rna_enum_node_map_range_items[];
+extern const EnumPropertyItem rna_enum_node_clamp_items[];
extern const EnumPropertyItem rna_enum_ramp_blend_items[];
@@ -217,6 +219,7 @@ extern const EnumPropertyItem rna_enum_abc_compression_items[];
extern const EnumPropertyItem rna_enum_context_mode_items[];
extern const EnumPropertyItem rna_enum_curveprofile_preset_items[];
+extern const EnumPropertyItem rna_enum_preference_section_items[];
/* API calls */
int rna_node_tree_type_to_enum(struct bNodeTreeType *typeinfo);
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 32ae5d4c873..03d0f8971b9 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -44,7 +44,7 @@ set(DEFSRC
rna_depsgraph.c
rna_dynamicpaint.c
rna_fcurve.c
- rna_fluidsim.c
+ rna_fluid.c
rna_gpencil.c
rna_gpencil_modifier.c
rna_image.c
@@ -77,7 +77,6 @@ set(DEFSRC
rna_sculpt_paint.c
rna_sequencer.c
rna_shader_fx.c
- rna_smoke.c
rna_sound.c
rna_space.c
rna_speaker.c
@@ -247,16 +246,12 @@ if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
-if(WITH_MOD_FLUID)
- add_definitions(-DWITH_MOD_FLUID)
-endif()
-
if(WITH_FFTW3)
add_definitions(-DWITH_FFTW3)
endif()
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_FLUID)
+ add_definitions(-DWITH_FLUID)
endif()
if(WITH_MOD_OCEANSIM)
@@ -358,7 +353,7 @@ blender_include_dirs(
../../../../intern/glew-mx
../../../../intern/guardedalloc
../../../../intern/memutil
- ../../../../intern/smoke/extern
+ ../../../../intern/mantaflow/extern
)
blender_include_dirs_sys(
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 13e61fd8ace..631089a667f 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -4231,7 +4231,6 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_curve.c", "rna_curve_api.c", RNA_def_curve},
{"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint},
{"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve},
- {"rna_fluidsim.c", NULL, RNA_def_fluidsim},
{"rna_gpencil.c", NULL, RNA_def_gpencil},
{"rna_image.c", "rna_image_api.c", RNA_def_image},
{"rna_key.c", NULL, RNA_def_key},
@@ -4240,6 +4239,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_layer.c", NULL, RNA_def_view_layer},
{"rna_linestyle.c", NULL, RNA_def_linestyle},
{"rna_main.c", "rna_main_api.c", RNA_def_main},
+ {"rna_fluid.c", NULL, RNA_def_fluid},
{"rna_material.c", "rna_material_api.c", RNA_def_material},
{"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh},
{"rna_meta.c", "rna_meta_api.c", RNA_def_meta},
@@ -4263,7 +4263,6 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_screen.c", NULL, RNA_def_screen},
{"rna_sculpt_paint.c", NULL, RNA_def_sculpt_paint},
{"rna_sequencer.c", "rna_sequencer_api.c", RNA_def_sequencer},
- {"rna_smoke.c", NULL, RNA_def_smoke},
{"rna_space.c", "rna_space_api.c", RNA_def_space},
{"rna_speaker.c", NULL, RNA_def_speaker},
{"rna_test.c", NULL, RNA_def_test},
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 78cd99837c3..d8889455ac7 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -5738,11 +5738,28 @@ static char *rna_idp_path(PointerRNA *ptr,
return path;
}
+/**
+ * Find the path from the structure referenced by the pointer to the IDProperty object.
+ *
+ * \param ptr Reference to the object owning the custom property storage.
+ * \param needle Custom property object to find.
+ * \return Relative path or NULL.
+ */
+char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle)
+{
+ IDProperty *haystack = RNA_struct_idprops(ptr, false);
+
+ if (haystack) { /* can fail when called on bones */
+ return rna_idp_path(ptr, haystack, needle, NULL);
+ }
+ else {
+ return NULL;
+ }
+}
+
static char *rna_path_from_ID_to_idpgroup(PointerRNA *ptr)
{
PointerRNA id_ptr;
- IDProperty *haystack;
- IDProperty *needle;
BLI_assert(ptr->owner_id != NULL);
@@ -5753,14 +5770,7 @@ static char *rna_path_from_ID_to_idpgroup(PointerRNA *ptr)
*/
RNA_id_pointer_create(ptr->owner_id, &id_ptr);
- haystack = RNA_struct_idprops(&id_ptr, false);
- if (haystack) { /* can fail when called on bones */
- needle = ptr->data;
- return rna_idp_path(&id_ptr, haystack, needle, NULL);
- }
- else {
- return NULL;
- }
+ return RNA_path_from_struct_to_idproperty(&id_ptr, ptr->data);
}
/**
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index a22b261368c..7c9b4254e4d 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -27,7 +27,7 @@
#include "BLI_utildefines.h"
#include "BLI_string.h"
-#define DEBUG_OVERRIDE_TIMEIT
+// #define DEBUG_OVERRIDE_TIMEIT
#ifdef DEBUG_OVERRIDE_TIMEIT
# include "PIL_time_utildefines.h"
@@ -598,7 +598,6 @@ bool RNA_struct_override_matches(Main *bmain,
const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0;
const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0;
-//#define DEBUG_OVERRIDE_TIMEIT
#ifdef DEBUG_OVERRIDE_TIMEIT
static float _sum_time_global = 0.0f;
static float _num_time_global = 0.0f;
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index b09a19bb39f..232f3d86fd3 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -497,7 +497,12 @@ static void rna_EditBone_length_set(PointerRNA *ptr, float length)
float delta[3];
sub_v3_v3v3(delta, ebone->tail, ebone->head);
- normalize_v3(delta);
+ if (normalize_v3(delta) == 0.0f) {
+ /* Zero length means directional information is lost. Choose arbitrary direction to avoid
+ * getting stuck. */
+ delta[2] = 1.0f;
+ }
+
madd_v3_v3v3fl(ebone->tail, ebone->head, delta, length);
}
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 2d70950ce7b..29c792a3bfb 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1596,6 +1596,22 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem brush_jitter_unit_items[] = {
+ {BRUSH_ABSOLUTE_JITTER, "VIEW", 0, "View", "Jitterring happens in screen space, in pixels"},
+ {0, "BRUSH", 0, "Brush", "Jitterring happens relative to the brush size"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem falloff_shape_unit_items[] = {
+ {0, "SPHERE", 0, "Sphere", "Apply brush influence in a Sphere, outwards from the center"},
+ {PAINT_FALLOFF_SHAPE_TUBE,
+ "PROJECTED",
+ 0,
+ "Projected",
+ "Apply brush influence in a 2D circle, projected from the view"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static const EnumPropertyItem brush_curve_preset_items[] = {
{BRUSH_CURVE_CUSTOM, "CUSTOM", ICON_RNDCURVE, "Custom", ""},
{BRUSH_CURVE_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
@@ -1704,6 +1720,19 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "jitter_unit", PROP_ENUM, PROP_NONE); /* as an enum */
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, brush_jitter_unit_items);
+ RNA_def_property_ui_text(
+ prop, "Jitter Unit", "Jitter in screen space or relative to brush size");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "falloff_shape", PROP_ENUM, PROP_NONE); /* as an enum */
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "falloff_shape");
+ RNA_def_property_enum_items(prop, falloff_shape_unit_items);
+ RNA_def_property_ui_text(prop, "Falloff Shape", "Use projected or spherical falloff");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
/* number values */
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_funcs(prop, NULL, "rna_Brush_set_size", NULL);
@@ -1993,13 +2022,6 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* flag */
- /* This is an enum but its unlikely we add other shapes, so expose as a boolean. */
- prop = RNA_def_property(srna, "use_projected", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "falloff_shape", PAINT_FALLOFF_SHAPE_TUBE);
- RNA_def_property_ui_text(
- prop, "2D Falloff", "Apply brush influence in 2D circle instead of a sphere");
- RNA_def_property_update(prop, 0, "rna_Brush_update");
-
prop = RNA_def_property(srna, "use_airbrush", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_AIRBRUSH);
RNA_def_property_ui_text(
@@ -2045,7 +2067,7 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_paint_antialiasing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "sampling_flag", BRUSH_PAINT_ANTIALIASING);
- RNA_def_property_ui_text(prop, "Antialasing", "Smooths the edges of the strokes");
+ RNA_def_property_ui_text(prop, "Anti-Aliasing", "Smooths the edges of the strokes");
prop = RNA_def_property(srna, "use_multiplane_scrape_dynamic", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_MULTIPLANE_SCRAPE_DYNAMIC);
@@ -2117,13 +2139,6 @@ static void rna_def_brush(BlenderRNA *brna)
prop, "Inverse Smooth Pressure", "Lighter pressure causes more smoothing to be applied");
RNA_def_property_update(prop, 0, "rna_Brush_update");
- prop = RNA_def_property(srna, "use_relative_jitter", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BRUSH_ABSOLUTE_JITTER);
- RNA_def_property_ui_icon(prop, ICON_UNLOCKED, true);
- RNA_def_property_ui_text(
- prop, "Absolute Jitter", "Jittering happens in screen space, not relative to brush size");
- RNA_def_property_update(prop, 0, "rna_Brush_update");
-
prop = RNA_def_property(srna, "use_plane_trim", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_PLANE_TRIM);
RNA_def_property_ui_text(prop, "Use Plane Trim", "Enable Plane Trim");
@@ -2359,13 +2374,13 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "cursor_color_add", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "add_col");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Add Color", "Color of cursor when adding");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "cursor_color_subtract", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "sub_col");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Subtract Color", "Color of cursor when subtracting");
RNA_def_property_update(prop, 0, "rna_Brush_update");
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index e1a06a76235..c000e1059e6 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -29,6 +29,8 @@
#include "rna_internal.h"
+#include "BLI_math.h"
+
#include "BKE_cloth.h"
#include "BKE_modifier.h"
@@ -201,6 +203,54 @@ static void rna_ClothSettings_shrink_max_set(struct PointerRNA *ptr, float value
settings->shrink_max = value;
}
+static void rna_ClothSettings_internal_tension_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ settings->internal_tension = value;
+
+ /* check for max clipping */
+ if (value > settings->max_internal_tension) {
+ settings->max_internal_tension = value;
+ }
+}
+
+static void rna_ClothSettings_max_internal_tension_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ /* check for clipping */
+ if (value < settings->internal_tension) {
+ value = settings->internal_tension;
+ }
+
+ settings->max_internal_tension = value;
+}
+
+static void rna_ClothSettings_internal_compression_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ settings->internal_compression = value;
+
+ /* check for max clipping */
+ if (value > settings->max_internal_compression) {
+ settings->max_internal_compression = value;
+ }
+}
+
+static void rna_ClothSettings_max_internal_compression_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ /* check for clipping */
+ if (value < settings->internal_compression) {
+ value = settings->internal_compression;
+ }
+
+ settings->max_internal_compression = value;
+}
+
static void rna_ClothSettings_mass_vgroup_get(PointerRNA *ptr, char *value)
{
ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
@@ -291,6 +341,42 @@ static void rna_ClothSettings_bend_vgroup_set(PointerRNA *ptr, const char *value
rna_object_vgroup_name_index_set(ptr, value, &sim->vgroup_bend);
}
+static void rna_ClothSettings_internal_vgroup_get(PointerRNA *ptr, char *value)
+{
+ ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
+ rna_object_vgroup_name_index_get(ptr, value, sim->vgroup_intern);
+}
+
+static int rna_ClothSettings_internal_vgroup_length(PointerRNA *ptr)
+{
+ ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
+ return rna_object_vgroup_name_index_length(ptr, sim->vgroup_intern);
+}
+
+static void rna_ClothSettings_internal_vgroup_set(PointerRNA *ptr, const char *value)
+{
+ ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
+ rna_object_vgroup_name_index_set(ptr, value, &sim->vgroup_intern);
+}
+
+static void rna_ClothSettings_pressure_vgroup_get(PointerRNA *ptr, char *value)
+{
+ ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
+ rna_object_vgroup_name_index_get(ptr, value, sim->vgroup_pressure);
+}
+
+static int rna_ClothSettings_pressure_vgroup_length(PointerRNA *ptr)
+{
+ ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
+ return rna_object_vgroup_name_index_length(ptr, sim->vgroup_pressure);
+}
+
+static void rna_ClothSettings_pressure_vgroup_set(PointerRNA *ptr, const char *value)
+{
+ ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
+ rna_object_vgroup_name_index_set(ptr, value, &sim->vgroup_pressure);
+}
+
static void rna_CollSettings_selfcol_vgroup_get(PointerRNA *ptr, char *value)
{
ClothCollSettings *coll = (ClothCollSettings *)ptr->data;
@@ -375,6 +461,18 @@ static char *rna_ClothCollisionSettings_path(PointerRNA *ptr)
}
}
+static int rna_ClothSettings_internal_editable(struct PointerRNA *ptr, const char **r_info)
+{
+ ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
+
+ if (sim && (sim->bending_model == CLOTH_BENDING_LINEAR)) {
+ *r_info = "Only available with angular bending springs.";
+ return 0;
+ }
+
+ return sim ? PROP_EDITABLE : 0;
+}
+
#else
static void rna_def_cloth_solver_result(BlenderRNA *brna)
@@ -595,14 +693,16 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "shrink_min", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "shrink_min");
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_range(prop, -FLT_MAX, 1.0f);
+ RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.05f, 3);
RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_shrink_min_set", NULL);
RNA_def_property_ui_text(prop, "Shrink Factor", "Factor by which to shrink cloth");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "shrink_max", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "shrink_max");
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_range(prop, -FLT_MAX, 1.0f);
+ RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.05f, 3);
RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_shrink_max_set", NULL);
RNA_def_property_ui_text(prop, "Shrink Factor Max", "Max amount to shrink cloth by");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -774,6 +874,151 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_cloth_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ prop = RNA_def_property(srna, "use_internal_springs", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS);
+ RNA_def_property_ui_text(prop,
+ "Create Internal Springs",
+ "Simulate an internal volume structure by creating springs connecting "
+ "the opposite sides of the mesh");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ prop = RNA_def_property(srna, "internal_spring_normal_check", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS_NORMAL);
+ RNA_def_property_ui_text(prop,
+ "Check Internal Spring Normals",
+ "Require the points the internal springs connect to have opposite "
+ "normal directions");
+ RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ prop = RNA_def_property(srna, "internal_spring_max_length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "internal_spring_max_length");
+ RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_ui_text(
+ prop,
+ "Internal Spring Max Length",
+ "The maximum length an internal spring can have during creation. If the distance between "
+ "internal points is greater than this, no internal spring will be created between these "
+ "points. "
+ "A length of zero means that there is no length limit");
+ RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ prop = RNA_def_property(srna, "internal_spring_max_diversion", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "internal_spring_max_diversion");
+ RNA_def_property_range(prop, 0.0f, M_PI / 4.0f);
+ RNA_def_property_ui_text(prop,
+ "Internal Spring Max Diversion",
+ "How much the rays used to connect the internal points can diverge "
+ "from the vertex normal");
+ RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ prop = RNA_def_property(srna, "internal_tension_stiffness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "internal_tension");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_internal_tension_set", NULL);
+ RNA_def_property_ui_text(prop, "Tension Stiffness", "How much the material resists stretching");
+ RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "internal_tension_stiffness_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "max_internal_tension");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_max_internal_tension_set", NULL);
+ RNA_def_property_ui_text(prop, "Tension Stiffness Maximum", "Maximum tension stiffness value");
+ RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "internal_compression_stiffness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "internal_compression");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_internal_compression_set", NULL);
+ RNA_def_property_ui_text(
+ prop, "Compression Stiffness", "How much the material resists compression");
+ RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "internal_compression_stiffness_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "max_internal_compression");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_max_internal_compression_set", NULL);
+ RNA_def_property_ui_text(
+ prop, "Compression Stiffness Maximum", "Maximum compression stiffness value");
+ RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "vertex_group_intern", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop,
+ "rna_ClothSettings_internal_vgroup_get",
+ "rna_ClothSettings_internal_vgroup_length",
+ "rna_ClothSettings_internal_vgroup_set");
+ RNA_def_property_ui_text(prop,
+ "Internal Springs Vertex Group",
+ "Vertex group for fine control over the internal spring stiffness");
+ RNA_def_property_editable_func(prop, "rna_ClothSettings_internal_editable");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ /* Pressure */
+
+ prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_PRESSURE);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Simulate pressure inside a closed cloth mesh");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "use_pressure_volume", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL);
+ RNA_def_property_ui_text(
+ prop, "Use Custom Volume", "Use the Volume parameter as the initial volume");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "uniform_pressure_force", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "uniform_pressure_force");
+ RNA_def_property_range(prop, -10000.0f, 10000.0f);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(
+ prop,
+ "Pressure",
+ "The uniform pressure that is constanty applied to the mesh. Can be negative");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "target_volume", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "target_volume");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop,
+ "Target Volume",
+ "The mesh volume where the inner/outer pressure will be the same. If "
+ "set to zero the volume will not contribute to the total pressure");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "pressure_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "pressure_factor");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Pressure Scale", "Air pressure scaling factor");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "vertex_group_pressure", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop,
+ "rna_ClothSettings_pressure_vgroup_get",
+ "rna_ClothSettings_pressure_vgroup_length",
+ "rna_ClothSettings_pressure_vgroup_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Pressure Vertex Group",
+ "Vertex Group for where to apply pressure. Zero weight means no "
+ "pressure while a weight of one means full pressure. Faces with a vertex "
+ "that has zero weight will be excluded from the volume calculation");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
/* unused */
/* unused still */
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 011e373cc61..679ccc9725b 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -123,6 +123,14 @@ static void rna_CurveMapping_tone_update(Main *UNUSED(bmain),
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
+static void rna_CurveMapping_extend_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *UNUSED(ptr))
+{
+ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
+}
+
static void rna_CurveMapping_clipminx_range(
PointerRNA *ptr, float *min, float *max, float *UNUSED(softmin), float *UNUSED(softmax))
{
@@ -670,8 +678,17 @@ static void rna_ColorManagement_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
}
/* this function only exists because #BKE_curvemap_evaluateF uses a 'const' qualifier */
-static float rna_CurveMap_evaluateF(struct CurveMap *cuma, ReportList *reports, float value)
+static float rna_CurveMapping_evaluateF(struct CurveMapping *cumap,
+ ReportList *reports,
+ struct CurveMap *cuma,
+ float value)
{
+ if (&cumap->cm[0] != cuma && &cumap->cm[1] != cuma && &cumap->cm[2] != cuma &&
+ &cumap->cm[3] != cuma) {
+ BKE_report(reports, RPT_ERROR, "CurveMapping does not own CurveMap");
+ return 0.0f;
+ }
+
if (!cuma->table) {
BKE_report(
reports,
@@ -679,7 +696,7 @@ static float rna_CurveMap_evaluateF(struct CurveMap *cuma, ReportList *reports,
"CurveMap table not initialized, call initialize() on CurveMapping owner of the CurveMap");
return 0.0f;
}
- return BKE_curvemap_evaluateF(cuma, value);
+ return BKE_curvemap_evaluateF(cumap, cuma, value);
}
static void rna_CurveMap_initialize(struct CurveMapping *cumap)
@@ -758,58 +775,22 @@ static void rna_def_curvemap_points_api(BlenderRNA *brna, PropertyRNA *cprop)
static void rna_def_curvemap(BlenderRNA *brna)
{
StructRNA *srna;
- PropertyRNA *prop, *parm;
- FunctionRNA *func;
-
- static const EnumPropertyItem prop_extend_items[] = {
- {0, "HORIZONTAL", 0, "Horizontal", ""},
- {CUMA_EXTEND_EXTRAPOLATE, "EXTRAPOLATED", 0, "Extrapolated", ""},
- {0, NULL, 0, NULL, NULL},
- };
+ PropertyRNA *prop;
srna = RNA_def_struct(brna, "CurveMap", NULL);
RNA_def_struct_ui_text(srna, "CurveMap", "Curve in a curve mapping");
- prop = RNA_def_property(srna, "extend", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, prop_extend_items);
- RNA_def_property_ui_text(prop, "Extend", "Extrapolate the curve or extend it horizontally");
-
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "curve", "totpoint");
RNA_def_property_struct_type(prop, "CurveMapPoint");
RNA_def_property_ui_text(prop, "Points", "");
rna_def_curvemap_points_api(brna, prop);
-
- func = RNA_def_function(srna, "evaluate", "rna_CurveMap_evaluateF");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Evaluate curve at given location");
- parm = RNA_def_float(func,
- "position",
- 0.0f,
- -FLT_MAX,
- FLT_MAX,
- "Position",
- "Position to evaluate curve at",
- -FLT_MAX,
- FLT_MAX);
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_float(func,
- "value",
- 0.0f,
- -FLT_MAX,
- FLT_MAX,
- "Value",
- "Value of curve at given location",
- -FLT_MAX,
- FLT_MAX);
- RNA_def_function_return(func, parm);
}
static void rna_def_curvemapping(BlenderRNA *brna)
{
StructRNA *srna;
- PropertyRNA *prop;
+ PropertyRNA *prop, *parm;
FunctionRNA *func;
static const EnumPropertyItem tone_items[] = {
@@ -818,6 +799,12 @@ static void rna_def_curvemapping(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem prop_extend_items[] = {
+ {0, "HORIZONTAL", 0, "Horizontal", ""},
+ {CUMA_EXTEND_EXTRAPOLATE, "EXTRAPOLATED", 0, "Extrapolated", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "CurveMapping", NULL);
RNA_def_struct_ui_text(
srna,
@@ -860,6 +847,12 @@ static void rna_def_curvemapping(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Clip Max Y", "");
RNA_def_property_float_funcs(prop, NULL, NULL, "rna_CurveMapping_clipmaxy_range");
+ prop = RNA_def_property(srna, "extend", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, prop_extend_items);
+ RNA_def_property_ui_text(prop, "Extend", "Extrapolate the curve or extend it horizontally");
+ RNA_def_property_update(prop, 0, "rna_CurveMapping_extend_update");
+
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop,
"rna_CurveMapping_curves_begin",
@@ -894,6 +887,32 @@ static void rna_def_curvemapping(BlenderRNA *brna)
func = RNA_def_function(srna, "initialize", "rna_CurveMap_initialize");
RNA_def_function_ui_description(func, "Initialize curve");
+
+ func = RNA_def_function(srna, "evaluate", "rna_CurveMapping_evaluateF");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Evaluate curve at given location");
+ parm = RNA_def_pointer(func, "curve", "CurveMap", "curve", "Curve to evaluate");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_float(func,
+ "position",
+ 0.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Position",
+ "Position to evaluate curve at",
+ -FLT_MAX,
+ FLT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float(func,
+ "value",
+ 0.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Value",
+ "Value of curve at given location",
+ -FLT_MAX,
+ FLT_MAX);
+ RNA_def_function_return(func, parm);
}
static void rna_def_color_ramp_element(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 6a10074810d..8e57de9baeb 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -633,6 +633,23 @@ static void rna_ArmatureConstraint_target_clear(ID *id, bConstraint *con, Main *
ED_object_constraint_dependency_tag_update(bmain, (Object *)id, con);
}
+static void rna_ActionConstraint_mix_mode_set(PointerRNA *ptr, int value)
+{
+ bConstraint *con = (bConstraint *)ptr->data;
+ bActionConstraint *acon = (bActionConstraint *)con->data;
+
+ acon->mix_mode = value;
+
+ /* The After mode can be computed in world space for efficiency
+ * and backward compatibility, while Before requires Local. */
+ if (ELEM(value, ACTCON_MIX_AFTER, ACTCON_MIX_AFTER_FULL)) {
+ con->ownspace = CONSTRAINT_SPACE_WORLD;
+ }
+ else {
+ con->ownspace = CONSTRAINT_SPACE_LOCAL;
+ }
+}
+
static void rna_ActionConstraint_minmax_range(
PointerRNA *ptr, float *min, float *max, float *UNUSED(softmin), float *UNUSED(softmax))
{
@@ -1618,6 +1635,29 @@ static void rna_def_constraint_action(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem mix_mode_items[] = {
+ {ACTCON_MIX_BEFORE,
+ "BEFORE",
+ 0,
+ "Before Original",
+ "Apply the action channels before the original transformation, "
+ "as if applied to an imaginary parent with Aligned Inherit Scale"},
+ {ACTCON_MIX_AFTER,
+ "AFTER",
+ 0,
+ "After Original",
+ "Apply the action channels after the original transformation, "
+ "as if applied to an imaginary child with Aligned Inherit Scale"},
+ {ACTCON_MIX_AFTER_FULL,
+ "AFTER_FULL",
+ 0,
+ "After Original (Full Scale)",
+ "Apply the action channels after the original transformation, as if "
+ "applied to an imaginary child with Full Inherit Scale. This mode "
+ "can create shear and is provided only for backward compatibility"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "ActionConstraint", "Constraint");
RNA_def_struct_ui_text(
srna, "Action Constraint", "Map an action to the transform axes of a bone");
@@ -1626,6 +1666,16 @@ static void rna_def_constraint_action(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode");
+ RNA_def_property_enum_items(prop, mix_mode_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_ActionConstraint_mix_mode_set", NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Mix Mode",
+ "Specify how existing transformations and the action channels are combined");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
prop = RNA_def_property(srna, "transform_channel", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, transform_channel_items);
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
new file mode 100644
index 00000000000..53fa863f6da
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -0,0 +1,2530 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
+#include "BLI_sys_types.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "BKE_modifier.h"
+#include "BKE_fluid.h"
+#include "BKE_pointcache.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_fluid_types.h"
+#include "DNA_particle_types.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#ifdef RNA_RUNTIME
+
+# include "BLI_math.h"
+# include "BLI_threads.h"
+
+# include "BKE_colorband.h"
+# include "BKE_context.h"
+# include "BKE_particle.h"
+
+# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_build.h"
+
+# include "manta_fluid_API.h"
+
+static void rna_Fluid_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
+
+ // Needed for liquid domain objects
+ Object *ob = (Object *)ptr->owner_id;
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
+}
+
+static void rna_Fluid_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_Fluid_update(bmain, scene, ptr);
+ DEG_relations_tag_update(bmain);
+}
+
+static void rna_Fluid_resetCache(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ if (settings->mmd && settings->mmd->domain) {
+ settings->mmd->domain->cache_flag |= (FLUID_DOMAIN_OUTDATED_DATA |
+ FLUID_DOMAIN_OUTDATED_NOISE |
+ FLUID_DOMAIN_OUTDATED_MESH |
+ FLUID_DOMAIN_OUTDATED_PARTICLES);
+ scene->r.cfra = settings->cache_frame_start;
+ }
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
+}
+static void rna_Fluid_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+
+# ifdef WITH_FLUID
+ {
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_modifier_reset(settings->mmd);
+ }
+# endif
+
+ rna_Fluid_resetCache(bmain, scene, ptr);
+
+ rna_Fluid_update(bmain, scene, ptr);
+}
+
+static void rna_Fluid_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+
+# ifdef WITH_FLUID
+ BKE_fluid_modifier_reset(settings->mmd);
+# endif
+
+ if (settings->mmd && settings->mmd->domain) {
+ settings->mmd->domain->point_cache[0]->flag |= PTCACHE_OUTDATED;
+ }
+
+ rna_Fluid_dependency_update(bmain, scene, ptr);
+}
+
+static void rna_Fluid_parts_create(Main *bmain,
+ PointerRNA *ptr,
+ const char *pset_name,
+ const char *parts_name,
+ const char *psys_name,
+ int psys_type)
+{
+# ifndef WITH_FLUID
+ UNUSED_VARS(bmain, ptr, pset_name, parts_name, psys_name, psys_type);
+# else
+ Object *ob = (Object *)ptr->owner_id;
+ BKE_fluid_particle_system_create(bmain, ob, pset_name, parts_name, psys_name, psys_type);
+# endif
+}
+
+static void rna_Fluid_parts_delete(PointerRNA *ptr, int ptype)
+{
+# ifndef WITH_FLUID
+ UNUSED_VARS(ptr, ptype);
+# else
+ Object *ob = (Object *)ptr->owner_id;
+ BKE_fluid_particle_system_destroy(ob, ptype);
+# endif
+}
+
+static bool rna_Fluid_parts_exists(PointerRNA *ptr, int ptype)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ ParticleSystem *psys;
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ if (psys->part->type == ptype) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void rna_Fluid_draw_type_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ struct PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+
+ /* Wireframe mode more convenient when particles present */
+ if (settings->particle_type == 0) {
+ ob->dt = OB_SOLID;
+ }
+ else {
+ ob->dt = OB_WIRE;
+ }
+}
+
+static void rna_Fluid_flip_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ FluidModifierData *mmd;
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_FLIP);
+
+ if (ob->type == OB_MESH && !exists) {
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "FlipParticleSettings",
+ "FLIP Particles",
+ "FLIP Particle System",
+ PART_FLUID_FLIP);
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FLIP;
+ }
+ else {
+ rna_Fluid_parts_delete(ptr, PART_FLUID_FLIP);
+ rna_Fluid_resetCache(bmain, scene, ptr);
+
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP;
+ }
+ rna_Fluid_draw_type_update(NULL, NULL, ptr);
+ rna_Fluid_reset(bmain, scene, ptr);
+}
+
+static void rna_Fluid_spray_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ FluidModifierData *mmd;
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAY);
+
+ if (ob->type == OB_MESH && !exists) {
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "SprayParticleSettings",
+ "Spray Particles",
+ "Spray Particle System",
+ PART_FLUID_SPRAY);
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ }
+ else {
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAY);
+ rna_Fluid_resetCache(bmain, scene, ptr);
+
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_SPRAY;
+ }
+ rna_Fluid_draw_type_update(NULL, NULL, ptr);
+ rna_Fluid_reset(bmain, scene, ptr);
+}
+
+static void rna_Fluid_bubble_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ FluidModifierData *mmd;
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_BUBBLE);
+
+ if (ob->type == OB_MESH && !exists) {
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "BubbleParticleSettings",
+ "Bubble Particles",
+ "Bubble Particle System",
+ PART_FLUID_BUBBLE);
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+ }
+ else {
+ rna_Fluid_parts_delete(ptr, PART_FLUID_BUBBLE);
+ rna_Fluid_resetCache(bmain, scene, ptr);
+
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_BUBBLE;
+ }
+ rna_Fluid_draw_type_update(NULL, NULL, ptr);
+ rna_Fluid_reset(bmain, scene, ptr);
+}
+
+static void rna_Fluid_foam_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ FluidModifierData *mmd;
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_FOAM);
+
+ if (ob->type == OB_MESH && !exists) {
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "FoamParticleSettings",
+ "Foam Particles",
+ "Foam Particle System",
+ PART_FLUID_FOAM);
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+ }
+ else {
+ rna_Fluid_parts_delete(ptr, PART_FLUID_FOAM);
+ rna_Fluid_resetCache(bmain, scene, ptr);
+
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FOAM;
+ }
+ rna_Fluid_draw_type_update(NULL, NULL, ptr);
+ rna_Fluid_reset(bmain, scene, ptr);
+}
+
+static void rna_Fluid_tracer_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ FluidModifierData *mmd;
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_TRACER);
+
+ if (ob->type == OB_MESH && !exists) {
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "TracerParticleSettings",
+ "Tracer Particles",
+ "Tracer Particle System",
+ PART_FLUID_TRACER);
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_TRACER;
+ }
+ else {
+ rna_Fluid_parts_delete(ptr, PART_FLUID_TRACER);
+ rna_Fluid_resetCache(bmain, scene, ptr);
+
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_TRACER;
+ }
+ rna_Fluid_draw_type_update(NULL, NULL, ptr);
+ rna_Fluid_reset(bmain, scene, ptr);
+}
+
+static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ FluidModifierData *mmd;
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+
+ if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_OFF) {
+ rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE));
+
+ // re-add each particle type if enabled
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) != 0) {
+ rna_Fluid_spray_parts_update(bmain, scene, ptr);
+ }
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) != 0) {
+ rna_Fluid_foam_parts_update(bmain, scene, ptr);
+ }
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) != 0) {
+ rna_Fluid_bubble_parts_update(bmain, scene, ptr);
+ }
+ }
+ else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM) {
+ if (ob->type == OB_MESH &&
+ !rna_Fluid_parts_exists(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM))) {
+ rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM));
+ }
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "SprayFoamParticleSettings",
+ "Spray + Foam Particles",
+ "Spray + Foam Particle System",
+ (PART_FLUID_SPRAY | PART_FLUID_FOAM));
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+
+ // re-add bubbles if enabled
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) != 0) {
+ rna_Fluid_bubble_parts_update(bmain, scene, ptr);
+ }
+ }
+ else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_SPRAY_BUBBLE) {
+ if (ob->type == OB_MESH &&
+ !rna_Fluid_parts_exists(ptr, (PART_FLUID_SPRAY | PART_FLUID_BUBBLE))) {
+ rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_BUBBLE));
+ }
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "SprayBubbleParticleSettings",
+ "Spray + Bubble Particles",
+ "Spray + Bubble Particle System",
+ (PART_FLUID_SPRAY | PART_FLUID_BUBBLE));
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+
+ // re-add foam if enabled
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) != 0) {
+ rna_Fluid_foam_parts_update(bmain, scene, ptr);
+ }
+ }
+ else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_FOAM_BUBBLE) {
+ if (ob->type == OB_MESH &&
+ !rna_Fluid_parts_exists(ptr, (PART_FLUID_FOAM | PART_FLUID_BUBBLE))) {
+ rna_Fluid_parts_delete(ptr, (PART_FLUID_FOAM | PART_FLUID_BUBBLE));
+ }
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "FoamBubbleParticleSettings",
+ "Foam + Bubble Particles",
+ "Foam + Bubble Particle System",
+ (PART_FLUID_FOAM | PART_FLUID_BUBBLE));
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+
+ // re-add spray if enabled
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) != 0) {
+ rna_Fluid_spray_parts_update(bmain, scene, ptr);
+ }
+ }
+ else if (mmd->domain->sndparticle_combined_export ==
+ SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM_BUBBLE) {
+ if (ob->type == OB_MESH &&
+ !rna_Fluid_parts_exists(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE))) {
+ rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE));
+ }
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "SprayFoamBubbleParticleSettings",
+ "Spray + Foam + Bubble Particles",
+ "Spray + Foam + Bubble Particle System",
+ (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE));
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+ }
+ else {
+ // sanity check, should not occur
+ printf("ERROR: Unexpected combined export setting encountered!");
+ }
+ rna_Fluid_resetCache(bmain, scene, ptr);
+ rna_Fluid_draw_type_update(NULL, NULL, ptr);
+}
+
+static void rna_Fluid_cachetype_mesh_set(struct PointerRNA *ptr, int value)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_cachetype_mesh_set(settings, value);
+}
+
+static void rna_Fluid_cachetype_data_set(struct PointerRNA *ptr, int value)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_cachetype_data_set(settings, value);
+}
+
+static void rna_Fluid_cachetype_particle_set(struct PointerRNA *ptr, int value)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_cachetype_particle_set(settings, value);
+}
+
+static void rna_Fluid_cachetype_noise_set(struct PointerRNA *ptr, int value)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_cachetype_noise_set(settings, value);
+}
+
+static void rna_Fluid_cachetype_set(struct PointerRNA *ptr, int value)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+
+ if (value != settings->cache_type) {
+ settings->cache_type = value;
+ settings->cache_flag = 0;
+ }
+}
+
+static void rna_Fluid_guide_parent_set(struct PointerRNA *ptr,
+ struct PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+ Object *par = (Object *)value.data;
+
+ FluidModifierData *mmd_par = NULL;
+
+ if (par != NULL) {
+ mmd_par = (FluidModifierData *)modifiers_findByType(par, eModifierType_Fluid);
+ if (mmd_par && mmd_par->domain) {
+ mds->guide_parent = value.data;
+ copy_v3_v3_int(mds->guide_res, mmd_par->domain->res);
+ }
+ }
+ else {
+ mds->guide_parent = NULL;
+ }
+}
+
+static const EnumPropertyItem *rna_Fluid_cachetype_mesh_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ tmp.value = FLUID_DOMAIN_FILE_BIN_OBJECT;
+ tmp.identifier = "BOBJECT";
+ tmp.name = "Binary Object files";
+ tmp.description = "Binary object file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ tmp.value = FLUID_DOMAIN_FILE_OBJECT;
+ tmp.identifier = "OBJECT";
+ tmp.name = "Object files";
+ tmp.description = "Object file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static const EnumPropertyItem *rna_Fluid_cachetype_volume_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ tmp.value = FLUID_DOMAIN_FILE_UNI;
+ tmp.identifier = "UNI";
+ tmp.name = "Uni Cache";
+ tmp.description = "Uni file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+# ifdef WITH_OPENVDB
+ tmp.value = FLUID_DOMAIN_FILE_OPENVDB;
+ tmp.identifier = "OPENVDB";
+ tmp.name = "OpenVDB";
+ tmp.description = "OpenVDB file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+# endif
+
+ tmp.value = FLUID_DOMAIN_FILE_RAW;
+ tmp.identifier = "RAW";
+ tmp.name = "Raw Cache";
+ tmp.description = "Raw file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static const EnumPropertyItem *rna_Fluid_cachetype_particle_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ tmp.value = FLUID_DOMAIN_FILE_UNI;
+ tmp.identifier = "UNI";
+ tmp.name = "Uni Cache";
+ tmp.description = "Uni file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static void rna_Fluid_cache_directory_set(struct PointerRNA *ptr, const char *value)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+
+ if (STREQ(settings->cache_directory, value)) {
+ return;
+ }
+
+ BLI_strncpy(settings->cache_directory, value, sizeof(settings->cache_directory));
+
+ /* TODO (sebbas): Read cache state in order to set cache bake flags and cache pause frames
+ * correctly */
+ // settings->cache_flag = 0;
+}
+
+static void rna_Fluid_domaintype_set(struct PointerRNA *ptr, int value)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ Object *ob = (Object *)ptr->owner_id;
+ BKE_fluid_domain_type_set(ob, settings, value);
+}
+
+static char *rna_FluidDomainSettings_path(PointerRNA *ptr)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ ModifierData *md = (ModifierData *)settings->mmd;
+ char name_esc[sizeof(md->name) * 2];
+
+ BLI_strescape(name_esc, md->name, sizeof(name_esc));
+ return BLI_sprintfN("modifiers[\"%s\"].domain_settings", name_esc);
+}
+
+static char *rna_FluidFlowSettings_path(PointerRNA *ptr)
+{
+ FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data;
+ ModifierData *md = (ModifierData *)settings->mmd;
+ char name_esc[sizeof(md->name) * 2];
+
+ BLI_strescape(name_esc, md->name, sizeof(name_esc));
+ return BLI_sprintfN("modifiers[\"%s\"].flow_settings", name_esc);
+}
+
+static char *rna_FluidEffectorSettings_path(PointerRNA *ptr)
+{
+ FluidEffectorSettings *settings = (FluidEffectorSettings *)ptr->data;
+ ModifierData *md = (ModifierData *)settings->mmd;
+ char name_esc[sizeof(md->name) * 2];
+
+ BLI_strescape(name_esc, md->name, sizeof(name_esc));
+ return BLI_sprintfN("modifiers[\"%s\"].effector_settings", name_esc);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Grid Accessors
+ * \{ */
+
+# ifdef WITH_FLUID
+
+static int rna_FluidModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+ float *density = NULL;
+ int size = 0;
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) {
+ /* high resolution smoke */
+ int res[3];
+
+ manta_smoke_turbulence_get_res(mds->fluid, res);
+ size = res[0] * res[1] * res[2];
+
+ density = manta_smoke_turbulence_get_density(mds->fluid);
+ }
+ else if (mds->fluid) {
+ /* regular resolution */
+ size = mds->res[0] * mds->res[1] * mds->res[2];
+ density = manta_smoke_get_density(mds->fluid);
+ }
+
+ length[0] = (density) ? size : 0;
+ return length[0];
+}
+
+static int rna_FluidModifier_color_grid_get_length(PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ rna_FluidModifier_grid_get_length(ptr, length);
+
+ length[0] *= 4;
+ return length[0];
+}
+
+static int rna_FluidModifier_velocity_grid_get_length(PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+ float *vx = NULL;
+ float *vy = NULL;
+ float *vz = NULL;
+ int size = 0;
+
+ /* Velocity data is always low-resolution. */
+ if (mds->fluid) {
+ size = 3 * mds->res[0] * mds->res[1] * mds->res[2];
+ vx = manta_get_velocity_x(mds->fluid);
+ vy = manta_get_velocity_y(mds->fluid);
+ vz = manta_get_velocity_z(mds->fluid);
+ }
+
+ length[0] = (vx && vy && vz) ? size : 0;
+ return length[0];
+}
+
+static int rna_FluidModifier_heat_grid_get_length(PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+ float *heat = NULL;
+ int size = 0;
+
+ /* Heat data is always low-resolution. */
+ if (mds->fluid) {
+ size = mds->res[0] * mds->res[1] * mds->res[2];
+ heat = manta_smoke_get_heat(mds->fluid);
+ }
+
+ length[0] = (heat) ? size : 0;
+ return length[0];
+}
+
+static void rna_FluidModifier_density_grid_get(PointerRNA *ptr, float *values)
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_FluidModifier_grid_get_length(ptr, length);
+ float *density;
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) {
+ density = manta_smoke_turbulence_get_density(mds->fluid);
+ }
+ else {
+ density = manta_smoke_get_density(mds->fluid);
+ }
+
+ memcpy(values, density, size * sizeof(float));
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_FluidModifier_velocity_grid_get(PointerRNA *ptr, float *values)
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_FluidModifier_velocity_grid_get_length(ptr, length);
+ float *vx, *vy, *vz;
+ int i;
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ vx = manta_get_velocity_x(mds->fluid);
+ vy = manta_get_velocity_y(mds->fluid);
+ vz = manta_get_velocity_z(mds->fluid);
+
+ for (i = 0; i < size; i += 3) {
+ *(values++) = *(vx++);
+ *(values++) = *(vy++);
+ *(values++) = *(vz++);
+ }
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_FluidModifier_color_grid_get(PointerRNA *ptr, float *values)
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_FluidModifier_grid_get_length(ptr, length);
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ if (!mds->fluid) {
+ memset(values, 0, size * sizeof(float));
+ }
+ else {
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ if (manta_smoke_turbulence_has_colors(mds->fluid)) {
+ manta_smoke_turbulence_get_rgba(mds->fluid, values, 0);
+ }
+ else {
+ manta_smoke_turbulence_get_rgba_from_density(mds->fluid, mds->active_color, values, 0);
+ }
+ }
+ else {
+ if (manta_smoke_has_colors(mds->fluid)) {
+ manta_smoke_get_rgba(mds->fluid, values, 0);
+ }
+ else {
+ manta_smoke_get_rgba_from_density(mds->fluid, mds->active_color, values, 0);
+ }
+ }
+ }
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_FluidModifier_flame_grid_get(PointerRNA *ptr, float *values)
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_FluidModifier_grid_get_length(ptr, length);
+ float *flame;
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) {
+ flame = manta_smoke_turbulence_get_flame(mds->fluid);
+ }
+ else {
+ flame = manta_smoke_get_flame(mds->fluid);
+ }
+
+ if (flame) {
+ memcpy(values, flame, size * sizeof(float));
+ }
+ else {
+ memset(values, 0, size * sizeof(float));
+ }
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_FluidModifier_heat_grid_get(PointerRNA *ptr, float *values)
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_FluidModifier_heat_grid_get_length(ptr, length);
+ float *heat;
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ heat = manta_smoke_get_heat(mds->fluid);
+
+ if (heat != NULL) {
+ /* scale heat values from -2.0-2.0 to -1.0-1.0. */
+ for (int i = 0; i < size; i++) {
+ values[i] = heat[i] * 0.5f;
+ }
+ }
+ else {
+ memset(values, 0, size * sizeof(float));
+ }
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_FluidModifier_temperature_grid_get(PointerRNA *ptr, float *values)
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_FluidModifier_grid_get_length(ptr, length);
+ float *flame;
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) {
+ flame = manta_smoke_turbulence_get_flame(mds->fluid);
+ }
+ else {
+ flame = manta_smoke_get_flame(mds->fluid);
+ }
+
+ if (flame) {
+ /* Output is such that 0..1 maps to 0..1000K */
+ float offset = mds->flame_ignition;
+ float scale = mds->flame_max_temp - mds->flame_ignition;
+
+ for (int i = 0; i < size; i++) {
+ values[i] = (flame[i] > 0.01f) ? offset + flame[i] * scale : 0.0f;
+ }
+ }
+ else {
+ memset(values, 0, size * sizeof(float));
+ }
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+# endif /* WITH_FLUID */
+
+/** \} */
+
+static void rna_FluidFlow_density_vgroup_get(PointerRNA *ptr, char *value)
+{
+ FluidFlowSettings *flow = (FluidFlowSettings *)ptr->data;
+ rna_object_vgroup_name_index_get(ptr, value, flow->vgroup_density);
+}
+
+static int rna_FluidFlow_density_vgroup_length(PointerRNA *ptr)
+{
+ FluidFlowSettings *flow = (FluidFlowSettings *)ptr->data;
+ return rna_object_vgroup_name_index_length(ptr, flow->vgroup_density);
+}
+
+static void rna_FluidFlow_density_vgroup_set(struct PointerRNA *ptr, const char *value)
+{
+ FluidFlowSettings *flow = (FluidFlowSettings *)ptr->data;
+ rna_object_vgroup_name_index_set(ptr, value, &flow->vgroup_density);
+}
+
+static void rna_FluidFlow_uvlayer_set(struct PointerRNA *ptr, const char *value)
+{
+ FluidFlowSettings *flow = (FluidFlowSettings *)ptr->data;
+ rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name));
+}
+
+static void rna_Fluid_use_color_ramp_set(struct PointerRNA *ptr, bool value)
+{
+ FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data;
+
+ mds->use_coba = value;
+
+ if (value && mds->coba == NULL) {
+ mds->coba = BKE_colorband_add(false);
+ }
+}
+
+static void rna_Fluid_flowsource_set(struct PointerRNA *ptr, int value)
+{
+ FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data;
+
+ if (value != settings->source) {
+ settings->source = value;
+ }
+}
+
+static const EnumPropertyItem *rna_Fluid_flowsource_itemf(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data;
+
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ tmp.value = FLUID_FLOW_SOURCE_MESH;
+ tmp.identifier = "MESH";
+ tmp.icon = ICON_META_CUBE;
+ tmp.name = "Mesh";
+ tmp.description = "Emit fluid from mesh surface or volume";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ if (settings->type != FLUID_FLOW_TYPE_LIQUID) {
+ tmp.value = FLUID_FLOW_SOURCE_PARTICLES;
+ tmp.identifier = "PARTICLES";
+ tmp.icon = ICON_PARTICLES;
+ tmp.name = "Particle System";
+ tmp.description = "Emit smoke from particles";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static void rna_Fluid_flowtype_set(struct PointerRNA *ptr, int value)
+{
+ FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data;
+
+ if (value != settings->type) {
+ settings->type = value;
+
+ /* Force flow source to mesh */
+ if (value == FLUID_FLOW_TYPE_LIQUID) {
+ rna_Fluid_flowsource_set(ptr, FLUID_FLOW_SOURCE_MESH);
+ settings->surface_distance = 0.0f;
+ }
+ else {
+ settings->surface_distance = 1.5f;
+ }
+ }
+}
+
+#else
+
+static void rna_def_fluid_mesh_vertices(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "FluidDomainVertexVelocity", NULL);
+ RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh");
+ RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL);
+
+ prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_float_sdna(prop, NULL, "vel");
+ RNA_def_property_ui_text(prop, "Velocity", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
+static void rna_def_fluid_domain_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem domain_types[] = {
+ {FLUID_DOMAIN_TYPE_GAS, "GAS", 0, "Gas", "Create domain for gases"},
+ {FLUID_DOMAIN_TYPE_LIQUID, "LIQUID", 0, "Liquid", "Create domain for liquids"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem prop_noise_type_items[] = {
+ {FLUID_NOISE_TYPE_WAVELET, "NOISEWAVE", 0, "Wavelet", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem prop_compression_items[] = {
+ {VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression"},
+# ifdef WITH_OPENVDB_BLOSC
+ {VDB_COMPRESSION_BLOSC,
+ "BLOSC",
+ 0,
+ "Blosc",
+ "Multithreaded compression, similar in size and quality as 'Zip'"},
+# endif
+ {VDB_COMPRESSION_NONE, "NONE", 0, "None", "Do not use any compression"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem cache_comp_items[] = {
+ {SM_CACHE_LIGHT, "CACHELIGHT", 0, "Lite", "Fast but not so effective compression"},
+ {SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem smoke_highres_sampling_items[] = {
+ {SM_HRES_FULLSAMPLE, "FULLSAMPLE", 0, "Full Sample", ""},
+ {SM_HRES_LINEAR, "LINEAR", 0, "Linear", ""},
+ {SM_HRES_NEAREST, "NEAREST", 0, "Nearest", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static EnumPropertyItem cache_types[] = {
+ {FLUID_DOMAIN_CACHE_REPLAY,
+ "REPLAY",
+ 0,
+ "Replay",
+ "Use the timeline to bake the scene. Pausing and resuming possible."},
+ {FLUID_DOMAIN_CACHE_MODULAR,
+ "MODULAR",
+ 0,
+ "Modular",
+ "Bake every stage of the simulation on its own. Can pause and resume bake jobs."},
+ {FLUID_DOMAIN_CACHE_FINAL, "FINAL", 0, "Final", "Bake the entire simulation at once."},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem smoke_data_depth_items[] = {
+ {16, "16", 0, "Float (Half)", "Half float (16 bit data)"},
+ {0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static EnumPropertyItem fluid_mesh_quality_items[] = {
+ {FLUID_DOMAIN_MESH_IMPROVED,
+ "IMPROVED",
+ 0,
+ "Final",
+ "Use improved particle levelset (slower but more precise and with mesh smoothening "
+ "options)"},
+ {FLUID_DOMAIN_MESH_UNION,
+ "UNION",
+ 0,
+ "Preview",
+ "Use union particle levelset (faster but lower quality)"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static EnumPropertyItem fluid_guide_source_items[] = {
+ {FLUID_DOMAIN_GUIDE_SRC_DOMAIN,
+ "DOMAIN",
+ 0,
+ "Domain",
+ "Use a fluid domain for guiding (domain needs to be baked already so that velocities can "
+ "be extracted but can be of any type)"},
+ {FLUID_DOMAIN_GUIDE_SRC_EFFECTOR,
+ "EFFECTOR",
+ 0,
+ "Effector",
+ "Use guiding (effector) objects to create fluid guiding (guiding objects should be "
+ "animated and baked once set up completely)"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* Cache type - generated dynamically based on domain type */
+ static EnumPropertyItem cache_file_type_items[] = {
+ {0, "NONE", 0, "", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem view_items[] = {
+ {FLUID_DOMAIN_SLICE_VIEW_ALIGNED,
+ "VIEW_ALIGNED",
+ 0,
+ "View",
+ "Slice volume parallel to the view plane"},
+ {FLUID_DOMAIN_SLICE_AXIS_ALIGNED,
+ "AXIS_ALIGNED",
+ 0,
+ "Axis",
+ "Slice volume parallel to the major axis"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem axis_slice_method_items[] = {
+ {AXIS_SLICE_FULL, "FULL", 0, "Full", "Slice the whole domain object"},
+ {AXIS_SLICE_SINGLE, "SINGLE", 0, "Single", "Perform a single slice of the domain object"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem interp_method_item[] = {
+ {VOLUME_INTERP_LINEAR, "LINEAR", 0, "Linear", "Good smoothness and speed"},
+ {VOLUME_INTERP_CUBIC,
+ "CUBIC",
+ 0,
+ "Cubic",
+ "Smoothed high quality interpolation, but slower"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem axis_slice_position_items[] = {
+ {SLICE_AXIS_AUTO,
+ "AUTO",
+ 0,
+ "Auto",
+ "Adjust slice direction according to the view direction"},
+ {SLICE_AXIS_X, "X", 0, "X", "Slice along the X axis"},
+ {SLICE_AXIS_Y, "Y", 0, "Y", "Slice along the Y axis"},
+ {SLICE_AXIS_Z, "Z", 0, "Z", "Slice along the Z axis"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem vector_draw_items[] = {
+ {VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Display vectors as needles"},
+ {VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Display vectors as streamlines"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem sndparticle_boundary_items[] = {
+ {SNDPARTICLE_BOUNDARY_DELETE,
+ "DELETE",
+ 0,
+ "Delete",
+ "Delete secondary particles that are inside obstacles or left the domain"},
+ {SNDPARTICLE_BOUNDARY_PUSHOUT,
+ "PUSHOUT",
+ 0,
+ "Push Out",
+ "Push secondary particles that left the domain back into the domain"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem sndparticle_combined_export_items[] = {
+ {SNDPARTICLE_COMBINED_EXPORT_OFF,
+ "OFF",
+ 0,
+ "Off",
+ "Create a seperate particle system for every secondary particle type"},
+ {SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM,
+ "SPRAY_FOAM",
+ 0,
+ "Spray + Foam",
+ "Spray and foam particles are saved in the same particle system"},
+ {SNDPARTICLE_COMBINED_EXPORT_SPRAY_BUBBLE,
+ "SPRAY_BUBBLES",
+ 0,
+ "Spray + Bubbles",
+ "Spray and bubble particles are saved in the same particle system"},
+ {SNDPARTICLE_COMBINED_EXPORT_FOAM_BUBBLE,
+ "FOAM_BUBBLES",
+ 0,
+ "Foam + Bubbles",
+ "Foam and bubbles particles are saved in the same particle system"},
+ {SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM_BUBBLE,
+ "SPRAY_FOAM_BUBBLES",
+ 0,
+ "Spray + Foam + Bubbles",
+ "Create one particle system that contains all three secondary particle types"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem simulation_methods[] = {
+ {FLUID_DOMAIN_METHOD_FLIP, "FLIP", 0, "FLIP", "Use FLIP as the simulation method"},
+ /*{FLUID_DOMAIN_METHOD_APIC, "APIC", 0, "APIC", "Use APIC as the simulation method"},*/
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "FluidDomainSettings", NULL);
+ RNA_def_struct_ui_text(srna, "Domain Settings", "Fluid domain settings");
+ RNA_def_struct_sdna(srna, "FluidDomainSettings");
+ RNA_def_struct_path_func(srna, "rna_FluidDomainSettings_path");
+
+ prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "EffectorWeights");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Effector Weights", "");
+
+ /* object collections */
+
+ prop = RNA_def_property(srna, "effector_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "effector_group");
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Effector Collection", "Limit effectors to this collection");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset_dependency");
+
+ prop = RNA_def_property(srna, "fluid_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "fluid_group");
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Fluid Collection", "Limit fluid objects to this collection");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset_dependency");
+
+ prop = RNA_def_property(srna, "force_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "force_group");
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Force Collection", "Limit forces to this collection");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset_dependency");
+
+ /* grid access */
+
+# ifdef WITH_FLUID
+ prop = RNA_def_property(srna, "density_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_FluidModifier_density_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Density Grid", "Smoke density grid");
+
+ prop = RNA_def_property(srna, "velocity_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_velocity_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_FluidModifier_velocity_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Velocity Grid", "Smoke velocity grid");
+
+ prop = RNA_def_property(srna, "flame_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_FluidModifier_flame_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Flame Grid", "Smoke flame grid");
+
+ prop = RNA_def_property(srna, "color_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_color_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_FluidModifier_color_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Color Grid", "Smoke color grid");
+
+ prop = RNA_def_property(srna, "heat_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_heat_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_FluidModifier_heat_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Heat Grid", "Smoke heat grid");
+
+ prop = RNA_def_property(srna, "temperature_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_FluidModifier_temperature_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(
+ prop, "Temperature Grid", "Smoke temperature grid, range 0..1 represents 0..1000K");
+# endif /* WITH_FLUID */
+
+ /* domain object data */
+
+ prop = RNA_def_property(srna,
+ "start_point",
+ PROP_FLOAT,
+ PROP_XYZ); /* can change each frame when using adaptive domain */
+ RNA_def_property_float_sdna(prop, NULL, "p0");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "p0", "Start point");
+
+ prop = RNA_def_property(srna,
+ "cell_size",
+ PROP_FLOAT,
+ PROP_XYZ); /* can change each frame when using adaptive domain */
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "cell_size", "Cell Size");
+
+ prop = RNA_def_property(srna,
+ "domain_resolution",
+ PROP_INT,
+ PROP_XYZ); /* can change each frame when using adaptive domain */
+ RNA_def_property_int_sdna(prop, NULL, "res");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "res", "Smoke Grid Resolution");
+
+ /* adaptive domain options */
+
+ prop = RNA_def_property(srna, "additional_res", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "adapt_res");
+ RNA_def_property_range(prop, 0, 512);
+ RNA_def_property_ui_text(prop, "Additional", "Maximum number of additional cells");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "adapt_margin", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "adapt_margin");
+ RNA_def_property_range(prop, 2, 24);
+ RNA_def_property_ui_text(
+ prop, "Margin", "Margin added around fluid to minimize boundary interference");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "adapt_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01, 0.5);
+ RNA_def_property_ui_text(
+ prop, "Threshold", "Maximum amount of fluid cell can contain before it is considered empty");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "use_adaptive_domain", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
+ RNA_def_property_ui_text(
+ prop, "Adaptive Domain", "Adapt simulation resolution and size to fluid");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ /* fluid domain options */
+
+ prop = RNA_def_property(srna, "resolution_max", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "maxres");
+ RNA_def_property_range(prop, 6, 10000);
+ RNA_def_property_ui_range(prop, 24, 10000, 2, -1);
+ RNA_def_property_ui_text(prop, "Max Res", "Resolution used for the fluid domain");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_front", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_FRONT);
+ RNA_def_property_ui_text(prop, "Front", "Enable collisons with front domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_back", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_BACK);
+ RNA_def_property_ui_text(prop, "Back", "Enable collisons with back domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_right", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_RIGHT);
+ RNA_def_property_ui_text(prop, "Right", "Enable collisons with right domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_left", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_LEFT);
+ RNA_def_property_ui_text(prop, "Left", "Enable collisons with left domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_top", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_TOP);
+ RNA_def_property_ui_text(prop, "Top", "Enable collisons with top domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_bottom", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_BOTTOM);
+ RNA_def_property_ui_text(prop, "Bottom", "Enable collisons with bottom domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION);
+ RNA_def_property_float_sdna(prop, NULL, "gravity");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, -1000.1, 1000.1);
+ RNA_def_property_ui_text(prop, "Gravity", "Gravity in X, Y and Z direction");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "domain_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, domain_types);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_domaintype_set", NULL);
+ RNA_def_property_ui_text(prop, "Domain Type", "Change domain type of the simulation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_reset");
+
+ /* smoke domain options */
+
+ prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "alpha");
+ RNA_def_property_range(prop, -5.0, 5.0);
+ RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
+ RNA_def_property_ui_text(
+ prop,
+ "Density",
+ "How much density affects smoke motion (higher value results in faster rising smoke)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "beta");
+ RNA_def_property_range(prop, -5.0, 5.0);
+ RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
+ RNA_def_property_ui_text(
+ prop,
+ "Heat",
+ "How much heat affects smoke motion (higher value results in faster rising smoke)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "dissolve_speed", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "diss_speed");
+ RNA_def_property_range(prop, 1.0, 10000.0);
+ RNA_def_property_ui_range(prop, 1.0, 10000.0, 1, -1);
+ RNA_def_property_ui_text(prop, "Dissolve Speed", "Dissolve Speed");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "vorticity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vorticity");
+ RNA_def_property_range(prop, 0.0, 4.0);
+ RNA_def_property_ui_text(prop, "Vorticity", "Amount of turbulence/rotation in fluid");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "highres_sampling", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, smoke_highres_sampling_items);
+ RNA_def_property_ui_text(prop, "Emitter", "Method for sampling the high resolution flow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "use_dissolve_smoke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_DISSOLVE);
+ RNA_def_property_ui_text(prop, "Dissolve Smoke", "Enable smoke to disappear over time");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_DISSOLVE_LOG);
+ RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x ");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ /* flame options */
+
+ prop = RNA_def_property(srna, "burning_rate", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01, 4.0);
+ RNA_def_property_ui_range(prop, 0.01, 2.0, 1.0, 5);
+ RNA_def_property_ui_text(
+ prop, "Speed", "Speed of the burning reaction (use larger values for smaller flame)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "flame_smoke", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 8.0);
+ RNA_def_property_ui_range(prop, 0.0, 4.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Smoke", "Amount of smoke created by burning fuel");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "flame_vorticity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Vorticity", "Additional vorticity for the flames");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "flame_ignition", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.5, 5.0);
+ RNA_def_property_ui_range(prop, 0.5, 2.5, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Ignition", "Minimum temperature of flames");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "flame_max_temp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 1.0, 10.0);
+ RNA_def_property_ui_range(prop, 1.0, 5.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Maximum", "Maximum temperature of flames");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "flame_smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke emitted from burning fuel");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ /* noise options */
+
+ prop = RNA_def_property(srna, "noise_strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "noise_strength");
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 2);
+ RNA_def_property_ui_text(prop, "Strength", "Strength of noise");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "noise_pos_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "noise_pos_scale");
+ RNA_def_property_range(prop, 0.0001, 10.0);
+ RNA_def_property_ui_text(
+ prop, "Scale", "Scale of noise (higher value results in larger vortices)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "noise_time_anim", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "noise_time_anim");
+ RNA_def_property_range(prop, 0.0001, 10.0);
+ RNA_def_property_ui_text(prop, "Time", "Animation time of noise");
+
+ prop = RNA_def_property(srna, "noise_scale", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "noise_scale");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_range(prop, 1, 10, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Noise Scale",
+ "Scale underlying noise grids by this factor. Noise grids have size "
+ "factor times base resolution");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "noise_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "noise_type");
+ RNA_def_property_enum_items(prop, prop_noise_type_items);
+ RNA_def_property_ui_text(
+ prop, "Noise Method", "Noise method which is used for creating the high resolution");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_noise", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_NOISE);
+ RNA_def_property_ui_text(prop, "Use Noise", "Enable fluid noise (using amplification)");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_update");
+
+ /* liquid domain options */
+
+ prop = RNA_def_property(srna, "simulation_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "simulation_method");
+ RNA_def_property_enum_items(prop, simulation_methods);
+ RNA_def_property_ui_text(prop, "Simulation Method", "Change the underlying simulation method");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "flip_ratio", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_text(
+ prop,
+ "FLIP Ratio",
+ "PIC/FLIP Ratio. A value of 1.0 will result in a completely FLIP based simulation. Use a "
+ "lower value for simulations which should produce smaller splashes");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "particle_randomness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(prop, "Randomness", "Randomness factor for particle sampling");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "particle_number", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 5);
+ RNA_def_property_ui_text(
+ prop, "Number", "Particle number factor (higher value results in more particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "particle_min", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "particle_minimum");
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_text(prop,
+ "Minimum",
+ "Minimum number of particles per cell (ensures that each cell has at "
+ "least this amount of particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "particle_max", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "particle_maximum");
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_text(prop,
+ "Maximum",
+ "Maximum number of particles per cell (ensures that each cell has at "
+ "most this amount of particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "particle_radius", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Radius",
+ "Particle radius factor. Use this parameter when the simulation appears to leak volume");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "particle_band_width", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Width",
+ "Particle (narrow) band width (higher value results in thicker band and more particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "use_flip_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_FLIP);
+ RNA_def_property_ui_text(prop, "FLIP", "Create FLIP particle system");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Fluid_flip_parts_update");
+
+ prop = RNA_def_property(srna, "use_fractions", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_FRACTIONS);
+ RNA_def_property_ui_text(
+ prop,
+ "Fractional Obstacles",
+ "Fractional obstacles improve and smoothen the fluid-obstacle boundary");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "fractions_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.001, 1.0);
+ RNA_def_property_ui_range(prop, 0.01, 1.0, 0.05, -1);
+ RNA_def_property_ui_text(prop,
+ "Obstacle-Fluid Threshold ",
+ "Determines how much fluid is allowed in an obstacle cell "
+ "(higher values will tag a boundary cell as an obstacle easier "
+ "and reduce the boundary smoothening effect)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ /* diffusion options */
+
+ prop = RNA_def_property(srna, "surface_tension", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Tension",
+ "Surface tension of liquid (higher value results in greater hydrophobic behaviour)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "viscosity_base", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "viscosity_base");
+ RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_ui_text(
+ prop,
+ "Viscosity Base",
+ "Viscosity setting: value that is multiplied by 10 to the power of (exponent*-1)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "viscosity_exponent", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "viscosity_exponent");
+ RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_ui_text(
+ prop,
+ "Viscosity Exponent",
+ "Negative exponent for the viscosity value (to simplify entering small values "
+ "e.g. 5*10^-6)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "domain_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.001, 10000.0);
+ RNA_def_property_ui_text(prop, "Meters", "Domain size in meters (longest domain side)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ /* mesh options options */
+
+ prop = RNA_def_property(srna, "mesh_concave_upper", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Upper Concavity",
+ "Upper mesh concavity bound (high values tend to smoothen and fill out concave regions)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "mesh_concave_lower", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Lower Concavity",
+ "Lower mesh concavity bound (high values tend to smoothen and fill out concave regions)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "mesh_smoothen_pos", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Smoothen Pos", "Positive mesh smoothening");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "mesh_smoothen_neg", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Smoothen Neg", "Negative mesh smoothening");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "mesh_scale", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "mesh_scale");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_range(prop, 1, 10, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Mesh scale",
+ "Scale underlying mesh grids by this factor. Mesh grids have size "
+ "factor times base resolution");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "mesh_generator", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mesh_generator");
+ RNA_def_property_enum_items(prop, fluid_mesh_quality_items);
+ RNA_def_property_ui_text(prop, "Mesh generator", "Which particle levelset generator to use");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update");
+
+ prop = RNA_def_property(srna, "mesh_vertices", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "mesh_velocities", "totvert");
+ RNA_def_property_struct_type(prop, "FluidDomainVertexVelocity");
+ RNA_def_property_ui_text(
+ prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation");
+
+ rna_def_fluid_mesh_vertices(brna);
+
+ prop = RNA_def_property(srna, "use_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_MESH);
+ RNA_def_property_ui_text(prop, "Use Mesh", "Enable fluid mesh (using amplification)");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_update");
+
+ prop = RNA_def_property(srna, "use_speed_vectors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_SPEED_VECTORS);
+ RNA_def_property_ui_text(
+ prop,
+ "Speed Vectors",
+ "Generate speed vectors (will be loaded automatically during render for motion blur)");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "mesh_particle_radius", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Radius",
+ "Particle radius factor (higher value results in larger (meshed) particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ /* secondary particles options */
+
+ prop = RNA_def_property(srna, "sndparticle_tau_min_wc", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
+ RNA_def_property_ui_text(prop,
+ "tauMin_wc",
+ "Lower clamping threshold for marking fluid cells as wave crests "
+ "(lower values result in more marked cells)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_tau_max_wc", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
+ RNA_def_property_ui_text(prop,
+ "tauMax_wc",
+ "Upper clamping threshold for marking fluid cells as wave crests "
+ "(higher values result in less marked cells)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_tau_min_ta", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 3);
+ RNA_def_property_ui_text(prop,
+ "tauMin_ta",
+ "Lower clamping threshold for marking fluid cells where air is trapped "
+ "(lower values result in more marked cells)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_tau_max_ta", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
+ RNA_def_property_ui_text(prop,
+ "tauMax_ta",
+ "Upper clamping threshold for marking fluid cells where air is trapped "
+ "(higher values result in less marked cells)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_tau_min_k", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
+ RNA_def_property_ui_text(
+ prop,
+ "tauMin_k",
+ "Lower clamping threshold that indicates the fluid speed where cells start to emit "
+ "particles (lower values result in generally more particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_tau_max_k", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
+ RNA_def_property_ui_text(
+ prop,
+ "tauMax_k",
+ "Upper clamping threshold that indicates the fluid speed where cells no longer emit more "
+ "particles (higher values result in generally less particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_k_wc", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 10000);
+ RNA_def_property_ui_range(prop, 0, 10000, 1.0, -1);
+ RNA_def_property_ui_text(prop,
+ "Wave Crest Sampling",
+ "Maximum number of particles generated per wave crest cell per frame");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_k_ta", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 10000);
+ RNA_def_property_ui_range(prop, 0, 10000, 1.0, -1);
+ RNA_def_property_ui_text(prop,
+ "Trapped Air Sampling",
+ "Maximum number of particles generated per trapped air cell per frame");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_k_b", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 10.0, 2);
+ RNA_def_property_ui_text(prop,
+ "Buoyancy",
+ "Amount of buoyancy force that rises bubbles (high values result in "
+ "bubble movement mainly upwards)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_k_d", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 10.0, 2);
+ RNA_def_property_ui_text(prop,
+ "Drag",
+ "Amount of drag force that moves bubbles along with the fluid (high "
+ "values result in bubble movement mainly along with the fluid)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_l_min", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10000.0);
+ RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 1);
+ RNA_def_property_ui_text(prop, "Lifetime(min)", "Lowest possible particle lifetime");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_l_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10000.0);
+ RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 1);
+ RNA_def_property_ui_text(prop, "Lifetime(max)", "Highest possible particle lifetime");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_boundary", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "sndparticle_boundary");
+ RNA_def_property_enum_items(prop, sndparticle_boundary_items);
+ RNA_def_property_ui_text(
+ prop, "Particles in Boundary", "How particles that left the domain are treated");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "sndparticle_combined_export", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "sndparticle_combined_export");
+ RNA_def_property_enum_items(prop, sndparticle_combined_export_items);
+ RNA_def_property_ui_text(
+ prop,
+ "Combined Export",
+ "Determines which particle systems are created from secondary particles");
+ RNA_def_property_update(prop, 0, "rna_Fluid_combined_export_update");
+
+ prop = RNA_def_property(srna, "sndparticle_potential_radius", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sndparticle_potential_radius");
+ RNA_def_property_range(prop, 1, 4);
+ RNA_def_property_ui_range(prop, 1, 4, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Potential Radius",
+ "Radius to compute potential for each cell (higher values are slower "
+ "but create smoother potential grids)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_update_radius", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sndparticle_update_radius");
+ RNA_def_property_range(prop, 1, 4);
+ RNA_def_property_ui_range(prop, 1, 4, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Update Radius",
+ "Radius to compute position update for each particle (higher values "
+ "are slower but particles move less chaotic)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "particle_scale", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "particle_scale");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_range(prop, 1, 10, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Mesh scale",
+ "Scale underlying particle grids by this factor. Particle grids have "
+ "size factor times base resolution");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_spray_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_SPRAY);
+ RNA_def_property_ui_text(prop, "Spray", "Create spray particle system");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Fluid_spray_parts_update");
+
+ prop = RNA_def_property(srna, "use_bubble_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_BUBBLE);
+ RNA_def_property_ui_text(prop, "Bubble", "Create bubble particle system");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Fluid_bubble_parts_update");
+
+ prop = RNA_def_property(srna, "use_foam_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_FOAM);
+ RNA_def_property_ui_text(prop, "Foam", "Create foam particle system");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Fluid_foam_parts_update");
+
+ prop = RNA_def_property(srna, "use_tracer_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_TRACER);
+ RNA_def_property_ui_text(prop, "Tracer", "Create tracer particle system");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Fluid_tracer_parts_update");
+
+ /* fluid guiding options */
+
+ prop = RNA_def_property(srna, "guide_alpha", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "guide_alpha");
+ RNA_def_property_range(prop, 1.0, 100.0);
+ RNA_def_property_ui_text(prop, "Weight", "Guiding weight (higher value results in greater lag)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "guide_beta", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "guide_beta");
+ RNA_def_property_range(prop, 1, 50);
+ RNA_def_property_ui_text(prop, "Size", "Guiding size (higher value results in larger vortices)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "guide_vel_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "guide_vel_factor");
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Weight",
+ "Guiding velocity factor (higher value results in bigger guiding velocities)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "guide_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "guide_source");
+ RNA_def_property_enum_items(prop, fluid_guide_source_items);
+ RNA_def_property_ui_text(prop, "Guiding source", "Choose where to get guiding velocities from");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update");
+
+ prop = RNA_def_property(srna, "guide_parent", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "guide_parent");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_Fluid_guide_parent_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop,
+ "",
+ "Use velocities from this object for the guiding effect (object needs "
+ "to have fluid modifier and be of type domain))");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update");
+
+ prop = RNA_def_property(srna, "use_guide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_GUIDE);
+ RNA_def_property_ui_text(prop, "Use Guiding", "Enable fluid guiding");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ /* cache options */
+
+ prop = RNA_def_property(srna, "cache_frame_start", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_start");
+ RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
+ RNA_def_property_ui_range(prop, 1, MAXFRAME, 1, 1);
+ RNA_def_property_ui_text(prop, "Start", "Frame on which the simulation starts");
+
+ prop = RNA_def_property(srna, "cache_frame_end", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_end");
+ RNA_def_property_range(prop, 1, MAXFRAME);
+ RNA_def_property_ui_text(prop, "End", "Frame on which the simulation stops");
+
+ prop = RNA_def_property(srna, "cache_frame_pause_data", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_data");
+
+ prop = RNA_def_property(srna, "cache_frame_pause_noise", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_noise");
+
+ prop = RNA_def_property(srna, "cache_frame_pause_mesh", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_mesh");
+
+ prop = RNA_def_property(srna, "cache_frame_pause_particles", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_particles");
+
+ prop = RNA_def_property(srna, "cache_frame_pause_guide", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_guide");
+
+ prop = RNA_def_property(srna, "cache_mesh_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_mesh_format");
+ RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_enum_funcs(
+ prop, NULL, "rna_Fluid_cachetype_mesh_set", "rna_Fluid_cachetype_mesh_itemf");
+ RNA_def_property_ui_text(
+ prop, "File Format", "Select the file format to be used for caching surface data");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "cache_data_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_data_format");
+ RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_enum_funcs(
+ prop, NULL, "rna_Fluid_cachetype_data_set", "rna_Fluid_cachetype_volume_itemf");
+ RNA_def_property_ui_text(
+ prop, "File Format", "Select the file format to be used for caching volumetric data");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "cache_particle_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_particle_format");
+ RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_enum_funcs(
+ prop, NULL, "rna_Fluid_cachetype_particle_set", "rna_Fluid_cachetype_particle_itemf");
+ RNA_def_property_ui_text(
+ prop, "File Format", "Select the file format to be used for caching particle data");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "cache_noise_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_noise_format");
+ RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_enum_funcs(
+ prop, NULL, "rna_Fluid_cachetype_noise_set", "rna_Fluid_cachetype_volume_itemf");
+ RNA_def_property_ui_text(
+ prop, "File Format", "Select the file format to be used for caching noise data");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "cache_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_type");
+ RNA_def_property_enum_items(prop, cache_types);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_cachetype_set", NULL);
+ RNA_def_property_ui_text(prop, "Type", "Change the cache type of the simulation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "cache_directory", PROP_STRING, PROP_DIRPATH);
+ RNA_def_property_string_maxlength(prop, FILE_MAX);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Fluid_cache_directory_set");
+ RNA_def_property_string_sdna(prop, NULL, "cache_directory");
+ RNA_def_property_ui_text(prop, "Cache directory", "Directory that contains fluid cache files");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "is_cache_baking_data", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_DATA);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "has_cache_baked_data", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_DATA);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "is_cache_baking_noise", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_NOISE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "has_cache_baked_noise", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_NOISE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "is_cache_baking_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_MESH);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "has_cache_baked_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_MESH);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "is_cache_baking_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_PARTICLES);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "has_cache_baked_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_PARTICLES);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "is_cache_baking_guide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_GUIDE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "has_cache_baked_guide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_GUIDE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ /* Read only checks, avoids individually accessing flags above. */
+ prop = RNA_def_property(srna, "is_cache_baking_any", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_ALL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "has_cache_baked_any", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_ALL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "export_manta_script", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_EXPORT_MANTA_SCRIPT);
+ RNA_def_property_ui_text(
+ prop,
+ "Export Fluidflow Script",
+ "Generate and export Fluidflow script from current domain settings during bake. This is "
+ "only needed if you plan to analyse the cache (e.g. view grids, velocity vectors, "
+ "particles) in Fluidflow directly (outside of Blender) after baking the simulation");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ /* time options */
+
+ prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "time_scale");
+ RNA_def_property_range(prop, 0.0001, 10.0);
+ RNA_def_property_ui_text(prop, "Time Scale", "Adjust simulation speed");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "cfl_condition", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "cfl_condition");
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(
+ prop, "CFL", "Maximal velocity per cell (higher value results in larger timesteps)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "use_adaptive_timesteps", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_ADAPTIVE_TIME);
+ RNA_def_property_ui_text(prop, "Use Adaptive Time Steps", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+
+ prop = RNA_def_property(srna, "timesteps_min", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "timesteps_minimum");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_range(prop, 0, 100, 1, -1);
+ RNA_def_property_ui_text(
+ prop, "Minimum", "Minimum number of simulation steps to perform for one frame");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "timesteps_max", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "timesteps_maximum");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_range(prop, 0, 100, 1, -1);
+ RNA_def_property_ui_text(
+ prop, "Maximum", "Maximum number of simulation steps to perform for one frame");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ /* display settings */
+
+ prop = RNA_def_property(srna, "slice_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "slice_method");
+ RNA_def_property_enum_items(prop, view_items);
+ RNA_def_property_ui_text(prop, "View Method", "How to slice the volume for viewport rendering");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "axis_slice_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "axis_slice_method");
+ RNA_def_property_enum_items(prop, axis_slice_method_items);
+ RNA_def_property_ui_text(prop, "Method", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "slice_axis");
+ RNA_def_property_enum_items(prop, axis_slice_position_items);
+ RNA_def_property_ui_text(prop, "Axis", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_per_voxel", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "slice_per_voxel");
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 5.0, 0.1, 1);
+ RNA_def_property_ui_text(
+ prop, "Slice Per Voxel", "How many slices per voxel should be generated");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_depth", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "slice_depth");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Position", "Position of the slice");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "display_thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "display_thickness");
+ RNA_def_property_range(prop, 0.001, 1000.0);
+ RNA_def_property_ui_range(prop, 0.1, 100.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "display_interpolation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "interp_method");
+ RNA_def_property_enum_items(prop, interp_method_item);
+ RNA_def_property_ui_text(
+ prop, "Interpolation", "Interpolation method to use for smoke/fire volumes in solid mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "show_velocity", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "draw_velocity", 0);
+ RNA_def_property_ui_text(
+ prop, "Display Velocity", "Toggle visualization of the velocity field as needles");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "vector_display_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "vector_draw_type");
+ RNA_def_property_enum_items(prop, vector_draw_items);
+ RNA_def_property_ui_text(prop, "Display Type", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "vector_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vector_scale");
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ /* --------- Color mapping. --------- */
+
+ prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_Fluid_use_color_ramp_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Use Color Ramp",
+ "Render a simulation field while mapping its voxels values to the colors of a ramp");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ static const EnumPropertyItem coba_field_items[] = {
+ {FLUID_DOMAIN_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"},
+ {FLUID_DOMAIN_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"},
+ {FLUID_DOMAIN_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"},
+ {FLUID_DOMAIN_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"},
+ {FLUID_DOMAIN_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"},
+ {FLUID_DOMAIN_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"},
+ {FLUID_DOMAIN_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"},
+ {FLUID_DOMAIN_FIELD_VELOCITY_X,
+ "VELOCITY_X",
+ 0,
+ "X Velocity",
+ "X component of the velocity field"},
+ {FLUID_DOMAIN_FIELD_VELOCITY_Y,
+ "VELOCITY_Y",
+ 0,
+ "Y Velocity",
+ "Y component of the velocity field"},
+ {FLUID_DOMAIN_FIELD_VELOCITY_Z,
+ "VELOCITY_Z",
+ 0,
+ "Z Velocity",
+ "Z component of the velocity field"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "coba_field");
+ RNA_def_property_enum_items(prop, coba_field_items);
+ RNA_def_property_ui_text(prop, "Field", "Simulation field to color map");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "coba");
+ RNA_def_property_struct_type(prop, "ColorRamp");
+ RNA_def_property_ui_text(prop, "Color Ramp", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "clipping", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "clipping");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
+ RNA_def_property_ui_text(
+ prop,
+ "Clipping",
+ "Value under which voxels are considered empty space to optimize caching and rendering");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ /* -- Deprecated / unsed options (below)-- */
+
+ /* pointcache options */
+
+ prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "point_cache[0]");
+ RNA_def_property_struct_type(prop, "PointCache");
+ RNA_def_property_ui_text(prop, "Point Cache", "");
+
+ prop = RNA_def_property(srna, "point_cache_compress_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_comp");
+ RNA_def_property_enum_items(prop, cache_comp_items);
+ RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used");
+
+ /* OpenVDB options */
+
+ prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp");
+ RNA_def_property_enum_items(prop, prop_compression_items);
+ RNA_def_property_ui_text(prop, "Compression", "Compression method to be used");
+
+ prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth");
+ RNA_def_property_enum_items(prop, smoke_data_depth_items);
+ RNA_def_property_ui_text(prop,
+ "Data Depth",
+ "Bit depth for writing all scalar (including vector) "
+ "lower values reduce file size");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+}
+
+static void rna_def_fluid_flow_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem flow_types[] = {
+ {FLUID_FLOW_TYPE_SMOKE, "SMOKE", 0, "Smoke", "Add smoke"},
+ {FLUID_FLOW_TYPE_SMOKEFIRE, "BOTH", 0, "Fire + Smoke", "Add fire and smoke"},
+ {FLUID_FLOW_TYPE_FIRE, "FIRE", 0, "Fire", "Add fire"},
+ {FLUID_FLOW_TYPE_LIQUID, "LIQUID", 0, "Liquid", "Add liquid"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static EnumPropertyItem flow_behaviors[] = {
+ {FLUID_FLOW_BEHAVIOR_INFLOW, "INFLOW", 0, "Inflow", "Add fluid to simulation"},
+ {FLUID_FLOW_BEHAVIOR_OUTFLOW, "OUTFLOW", 0, "Outflow", "Delete fluid from simulation"},
+ {FLUID_FLOW_BEHAVIOR_GEOMETRY,
+ "GEOMETRY",
+ 0,
+ "Geometry",
+ "Only use given geometry for fluid"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* Flow source - generated dynamically based on flow type */
+ static EnumPropertyItem flow_sources[] = {
+ {0, "NONE", 0, "", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem flow_texture_types[] = {
+ {FLUID_FLOW_TEXTURE_MAP_AUTO,
+ "AUTO",
+ 0,
+ "Generated",
+ "Generated coordinates centered to flow object"},
+ {FLUID_FLOW_TEXTURE_MAP_UV, "UV", 0, "UV", "Use UV layer for texture coordinates"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "FluidFlowSettings", NULL);
+ RNA_def_struct_ui_text(srna, "Flow Settings", "Fluid flow settings");
+ RNA_def_struct_sdna(srna, "FluidFlowSettings");
+ RNA_def_struct_path_func(srna, "rna_FluidFlowSettings_path");
+
+ prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "density");
+ RNA_def_property_range(prop, 0.0, 1);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 4);
+ RNA_def_property_ui_text(prop, "Density", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "color");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "fuel_amount", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10);
+ RNA_def_property_ui_range(prop, 0.0, 5.0, 1.0, 4);
+ RNA_def_property_ui_text(prop, "Flame Rate", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "temperature");
+ RNA_def_property_range(prop, -10, 10);
+ RNA_def_property_ui_range(prop, -10, 10, 1, 1);
+ RNA_def_property_ui_text(prop, "Temp. Diff.", "Temperature difference to ambient temperature");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "psys");
+ RNA_def_property_struct_type(prop, "ParticleSystem");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Particle Systems", "Particle systems emitted from the object");
+ RNA_def_property_update(prop, 0, "rna_Fluid_reset_dependency");
+
+ prop = RNA_def_property(srna, "flow_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, flow_types);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_flowtype_set", NULL);
+ RNA_def_property_ui_text(prop, "Flow Type", "Change type of fluid in the simulation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "flow_behavior", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "behavior");
+ RNA_def_property_enum_items(prop, flow_behaviors);
+ RNA_def_property_ui_text(prop, "Flow Behavior", "Change flow behavior in the simulation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "flow_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "source");
+ RNA_def_property_enum_items(prop, flow_sources);
+ RNA_def_property_enum_funcs(
+ prop, NULL, "rna_Fluid_flowsource_set", "rna_Fluid_flowsource_itemf");
+ RNA_def_property_ui_text(prop, "Source", "Change how fluid is emitted");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_absolute", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_ABSOLUTE);
+ RNA_def_property_ui_text(prop,
+ "Absolute Density",
+ "Only allow given density value in emitter area and will not add up");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_initial_velocity", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_INITVELOCITY);
+ RNA_def_property_ui_text(
+ prop, "Initial Velocity", "Fluid has some initial velocity when it is emitted");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vel_multi");
+ RNA_def_property_range(prop, -100.0, 100.0);
+ RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
+ RNA_def_property_ui_text(prop,
+ "Source",
+ "Multiplier of source velocity passed to fluid (source velocity is "
+ "non-zero only if object is moving)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vel_normal");
+ RNA_def_property_range(prop, -100.0, 100.0);
+ RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Normal", "Amount of normal directional velocity");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vel_random");
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Random", "Amount of random velocity");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "velocity_coord", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "vel_coord");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, -1000.1, 1000.1);
+ RNA_def_property_ui_text(prop, "Initial", "Initial velocity in X, Y and Z direction");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "volume_density", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Volume", "Factor for smoke emitted from inside the mesh volume");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_range(prop, 0.0, 10.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Surface", "Maximum distance from mesh surface to emit fluid");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_plane_init", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_PLANE_INIT);
+ RNA_def_property_ui_text(prop, "Is Planar", "Treat this object as a planar, unclosed mesh");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "particle_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.1, 20.0);
+ RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Size", "Particle size in simulation cells");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_particle_size", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_PART_SIZE);
+ RNA_def_property_ui_text(
+ prop, "Set Size", "Set particle size in simulation cells or use nearest cell");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_inflow", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_INFLOW);
+ RNA_def_property_ui_text(prop, "Enabled", "Control when to apply inflow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "subframes", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 200);
+ RNA_def_property_ui_range(prop, 0, 10, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Subframes",
+ "Number of additional samples to take between frames to improve "
+ "quality of fast moving flows");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "density_vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop,
+ "rna_FluidFlow_density_vgroup_get",
+ "rna_FluidFlow_density_vgroup_length",
+ "rna_FluidFlow_density_vgroup_set");
+ RNA_def_property_ui_text(
+ prop, "Vertex Group", "Name of vertex group which determines surface emission rate");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_TEXTUREEMIT);
+ RNA_def_property_ui_text(prop, "Use Texture", "Use a texture to control emission strength");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "texture_map_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "texture_type");
+ RNA_def_property_enum_items(prop, flow_texture_types);
+ RNA_def_property_ui_text(prop, "Mapping", "Texture mapping type");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
+ RNA_def_property_ui_text(prop, "UV Map", "UV map name");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_FluidFlow_uvlayer_set");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "noise_texture", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Texture", "Texture that controls emission strength");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "texture_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01, 10.0);
+ RNA_def_property_ui_range(prop, 0.1, 5.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Size", "Size of texture mapping");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 200.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Offset", "Z-offset of texture mapping");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+}
+
+static void rna_def_fluid_effector_settings(BlenderRNA *brna)
+{
+ static EnumPropertyItem effector_type_items[] = {
+ {FLUID_EFFECTOR_TYPE_COLLISION, "COLLISION", 0, "Collision", "Create collision object"},
+ {FLUID_EFFECTOR_TYPE_GUIDE, "GUIDE", 0, "Guide", "Create guide object"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static EnumPropertyItem fluid_guide_mode_items[] = {
+ {FLUID_EFFECTOR_GUIDE_MAX,
+ "MAXIMUM",
+ 0,
+ "Maximize",
+ "Compare velocities from previous frame with new velocities from current frame and keep "
+ "the maximum"},
+ {FLUID_EFFECTOR_GUIDE_MIN,
+ "MINIMUM",
+ 0,
+ "Minimize",
+ "Compare velocities from previous frame with new velocities from current frame and keep "
+ "the minimum"},
+ {FLUID_EFFECTOR_GUIDE_OVERRIDE,
+ "OVERRIDE",
+ 0,
+ "Override",
+ "Always write new guide velocities for every frame (each frame only contains current "
+ "velocities from guiding objects)"},
+ {FLUID_EFFECTOR_GUIDE_AVERAGED,
+ "AVERAGED",
+ 0,
+ "Averaged",
+ "Take average of velocities from previous frame and new velocities from current frame"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "FluidEffectorSettings", NULL);
+ RNA_def_struct_ui_text(srna, "Effector Settings", "Smoke collision settings");
+ RNA_def_struct_sdna(srna, "FluidEffectorSettings");
+ RNA_def_struct_path_func(srna, "rna_FluidEffectorSettings_path");
+
+ prop = RNA_def_property(srna, "effector_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, effector_type_items);
+ RNA_def_property_ui_text(prop, "Effector Type", "Change type of effector in the simulation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_range(prop, 0.0, 10.0, 0.05, 5);
+ RNA_def_property_ui_text(
+ prop, "Surface", "Distance around mesh surface to consider as effector");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "use_plane_init", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_PLANE_INIT);
+ RNA_def_property_ui_text(prop, "Is Planar", "Treat this object as a planar, unclosed mesh");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vel_multi");
+ RNA_def_property_range(prop, -100.0, 100.0);
+ RNA_def_property_ui_text(prop, "Source", "Multiplier of obstacle velocity");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+
+ prop = RNA_def_property(srna, "guide_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "guide_mode");
+ RNA_def_property_enum_items(prop, fluid_guide_mode_items);
+ RNA_def_property_ui_text(prop, "Guiding mode", "How to create guiding velocities");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update");
+}
+
+void RNA_def_fluid(BlenderRNA *brna)
+{
+ rna_def_fluid_domain_settings(brna);
+ rna_def_fluid_flow_settings(brna);
+ rna_def_fluid_effector_settings(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
deleted file mode 100644
index 2f09b90a81e..00000000000
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup RNA
- */
-
-#include <stdlib.h>
-
-#include "DNA_object_fluidsim_types.h"
-
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
-
-#include "RNA_define.h"
-
-#include "rna_internal.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#ifdef RNA_RUNTIME
-
-# include "MEM_guardedalloc.h"
-
-# include "DNA_scene_types.h"
-# include "DNA_particle_types.h"
-
-# include "BKE_fluidsim.h"
-# include "BKE_global.h"
-# include "BKE_main.h"
-# include "BKE_modifier.h"
-# include "BKE_particle.h"
-# include "BKE_pointcache.h"
-
-# include "DEG_depsgraph.h"
-
-static StructRNA *rna_FluidSettings_refine(struct PointerRNA *ptr)
-{
- FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
-
- switch (fss->type) {
- case OB_FLUIDSIM_DOMAIN:
- return &RNA_DomainFluidSettings;
- case OB_FLUIDSIM_FLUID:
- return &RNA_FluidFluidSettings;
- case OB_FLUIDSIM_OBSTACLE:
- return &RNA_ObstacleFluidSettings;
- case OB_FLUIDSIM_INFLOW:
- return &RNA_InflowFluidSettings;
- case OB_FLUIDSIM_OUTFLOW:
- return &RNA_OutflowFluidSettings;
- case OB_FLUIDSIM_PARTICLE:
- return &RNA_ParticleFluidSettings;
- case OB_FLUIDSIM_CONTROL:
- return &RNA_ControlFluidSettings;
- default:
- return &RNA_FluidSettings;
- }
-}
-
-static void rna_fluid_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->owner_id;
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
-}
-
-static int fluidsim_find_lastframe(Main *bmain, Object *ob, FluidsimSettings *fss)
-{
- char targetFileTest[FILE_MAX];
- char targetFile[FILE_MAX];
- int curFrame = 1;
-
- BLI_join_dirfile(
- targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
- BLI_path_abs(targetFile, modifier_path_relbase(bmain, ob));
-
- do {
- BLI_strncpy(targetFileTest, targetFile, sizeof(targetFileTest));
- BLI_path_frame(targetFileTest, curFrame++, 0);
- } while (BLI_exists(targetFileTest));
-
- return curFrame - 1;
-}
-
-static void rna_fluid_find_enframe(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->owner_id;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
-
- if (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE) {
- fluidmd->fss->lastgoodframe = fluidsim_find_lastframe(bmain, ob, fluidmd->fss);
- }
- else {
- fluidmd->fss->lastgoodframe = -1;
- }
- rna_fluid_update(bmain, scene, ptr);
-}
-
-static void rna_FluidSettings_update_type(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->owner_id;
- FluidsimModifierData *fluidmd;
- ParticleSystemModifierData *psmd;
- ParticleSystem *psys, *next_psys;
- ParticleSettings *part;
-
- fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
- fluidmd->fss->flag &= ~OB_FLUIDSIM_REVERSE; /* clear flag */
-
- /* remove fluidsim particle system */
- if (fluidmd->fss->type & OB_FLUIDSIM_PARTICLE) {
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (psys->part->type == PART_FLUID) {
- break;
- }
- }
-
- if (ob->type == OB_MESH && !psys) {
- /* add particle system */
- part = BKE_particlesettings_add(bmain, "ParticleSettings");
- psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
-
- part->type = PART_FLUID;
- psys->part = part;
- psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
- BLI_strncpy(psys->name, "FluidParticles", sizeof(psys->name));
- BLI_addtail(&ob->particlesystem, psys);
-
- /* add modifier */
- psmd = (ParticleSystemModifierData *)modifier_new(eModifierType_ParticleSystem);
- BLI_strncpy(psmd->modifier.name, "FluidParticleSystem", sizeof(psmd->modifier.name));
- psmd->psys = psys;
- BLI_addtail(&ob->modifiers, psmd);
- modifier_unique_name(&ob->modifiers, (ModifierData *)psmd);
- }
- }
- else {
- for (psys = ob->particlesystem.first; psys; psys = next_psys) {
- next_psys = psys->next;
- if (psys->part->type == PART_FLUID) {
- /* clear modifier */
- psmd = psys_get_modifier(ob, psys);
- BLI_remlink(&ob->modifiers, psmd);
- modifier_free((ModifierData *)psmd);
-
- /* clear particle system */
- BLI_remlink(&ob->particlesystem, psys);
- psys_free(ob, psys);
- }
- }
- }
-
- rna_fluid_update(bmain, scene, ptr);
-}
-
-static void rna_DomainFluidSettings_memory_estimate_get(PointerRNA *ptr, char *value)
-{
-# ifndef WITH_MOD_FLUID
- (void)ptr;
- value[0] = '\0';
-# else
- Object *ob = (Object *)ptr->owner_id;
- FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
-
- fluid_estimate_memory(ob, fss, value);
-# endif
-}
-
-static int rna_DomainFluidSettings_memory_estimate_length(PointerRNA *ptr)
-{
-# ifndef WITH_MOD_FLUID
- UNUSED_VARS(ptr);
- return 0;
-# else
- char value[32];
-
- rna_DomainFluidSettings_memory_estimate_get(ptr, value);
- return strlen(value);
-# endif
-}
-
-static char *rna_FluidSettings_path(PointerRNA *ptr)
-{
- FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
- ModifierData *md = (ModifierData *)fss->fmd;
- char name_esc[sizeof(md->name) * 2];
-
- BLI_strescape(name_esc, md->name, sizeof(name_esc));
- return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc);
-}
-
-#else
-
-static void rna_def_fluidsim_slip(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- static const EnumPropertyItem slip_items[] = {
- {OB_FSBND_NOSLIP,
- "NOSLIP",
- 0,
- "No Slip",
- "Obstacle causes zero normal and tangential velocity (=sticky), default for all "
- "(only option for moving objects)"},
- {OB_FSBND_PARTSLIP,
- "PARTIALSLIP",
- 0,
- "Partial Slip",
- "Mix between no-slip and free-slip (non moving objects only!)"},
- {OB_FSBND_FREESLIP,
- "FREESLIP",
- 0,
- "Free Slip",
- "Obstacle only causes zero normal velocity (=not sticky, non moving objects only!)"},
- {0, NULL, 0, NULL, NULL},
- };
-
- prop = RNA_def_property(srna, "slip_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "typeFlags");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_enum_items(prop, slip_items);
- RNA_def_property_ui_text(prop, "Slip Type", "");
-
- prop = RNA_def_property(srna, "partial_slip_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "partSlipValue");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(
- prop,
- "Partial Slip Amount",
- "Amount of mixing between no- and free-slip, 0 is no slip and 1 is free slip");
-}
-
-static void rna_def_fluid_mesh_vertices(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "FluidVertexVelocity", NULL);
- RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh");
- RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL);
-
- prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY);
- RNA_def_property_array(prop, 3);
- RNA_def_property_float_sdna(prop, NULL, "vel");
- RNA_def_property_ui_text(prop, "Velocity", "");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-}
-
-static void rna_def_fluidsim_domain(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem quality_items[] = {
- {OB_FSDOM_GEOM, "GEOMETRY", 0, "Geometry", "Display geometry"},
- {OB_FSDOM_PREVIEW, "PREVIEW", 0, "Preview", "Display preview quality results"},
- {OB_FSDOM_FINAL, "FINAL", 0, "Final", "Display final quality results"},
- {0, NULL, 0, NULL, NULL},
- };
-
- srna = RNA_def_struct(brna, "DomainFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(srna,
- "Domain Fluid Simulation Settings",
- "Fluid simulation settings for the domain of a fluid simulation");
-
- /* standard settings */
-
- prop = RNA_def_property(srna, "threads", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "threads");
- RNA_def_property_range(prop, 0, BLENDER_MAX_THREADS);
- RNA_def_property_ui_text(
- prop, "Simulation Threads", "Override number of threads for the simulation, 0 is automatic");
-
- prop = RNA_def_property(srna, "resolution", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "resolutionxyz");
- RNA_def_property_range(prop, 1, 1024);
- RNA_def_property_ui_text(prop, "Resolution", "Domain resolution in X,Y and Z direction");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
- prop = RNA_def_property(srna, "preview_resolution", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "previewresxyz");
- RNA_def_property_range(prop, 1, 100);
- RNA_def_property_ui_text(
- prop, "Preview Resolution", "Preview resolution in X,Y and Z direction");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
- prop = RNA_def_property(srna, "viewport_display_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "guiDisplayMode");
- RNA_def_property_enum_items(prop, quality_items);
- RNA_def_property_ui_text(
- prop, "Viewport Display Mode", "How to display the mesh in the viewport");
- RNA_def_property_update(prop, 0, "rna_fluid_update");
-
- prop = RNA_def_property(srna, "render_display_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "renderDisplayMode");
- RNA_def_property_enum_items(prop, quality_items);
- RNA_def_property_ui_text(prop, "Render Display Mode", "How to display the mesh for rendering");
-
- prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_REVERSE);
- RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse fluid frames");
- RNA_def_property_update(prop, 0, "rna_fluid_find_enframe");
-
- prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
- RNA_def_property_string_maxlength(prop, FILE_MAX);
- RNA_def_property_string_sdna(prop, NULL, "surfdataPath");
- RNA_def_property_ui_text(
- prop, "Path", "Directory (and/or filename prefix) to store baked fluid simulation files in");
- RNA_def_property_update(prop, 0, "rna_fluid_update");
-
- prop = RNA_def_property(srna, "memory_estimate", PROP_STRING, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_string_funcs(prop,
- "rna_DomainFluidSettings_memory_estimate_get",
- "rna_DomainFluidSettings_memory_estimate_length",
- NULL);
- RNA_def_property_ui_text(
- prop, "Memory Estimate", "Estimated amount of memory needed for baking the domain");
-
- /* advanced settings */
- prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION);
- RNA_def_property_float_sdna(prop, NULL, "grav");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, -1000.1, 1000.1);
- RNA_def_property_ui_text(prop, "Gravity", "Gravity in X, Y and Z direction");
-
- prop = RNA_def_property(srna, "use_time_override", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_OVERRIDE_TIME);
- RNA_def_property_ui_text(
- prop,
- "Override Time",
- "Use a custom start and end time (in seconds) instead of the scene's timeline");
-
- prop = RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME);
- RNA_def_property_float_sdna(prop, NULL, "animStart");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_text(
- prop, "Start Time", "Simulation time of the first blender frame (in seconds)");
-
- prop = RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME);
- RNA_def_property_float_sdna(prop, NULL, "animEnd");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_text(
- prop, "End Time", "Simulation time of the last blender frame (in seconds)");
-
- prop = RNA_def_property(srna, "frame_offset", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "frameOffset");
- RNA_def_property_ui_text(prop, "Cache Offset", "Offset when reading baked cache");
- RNA_def_property_update(prop, NC_OBJECT, "rna_fluid_update");
-
- prop = RNA_def_property(srna, "simulation_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "realsize");
- RNA_def_property_range(prop, 0.001, 10);
- RNA_def_property_ui_text(prop, "Real World Size", "Size of the simulation domain in meters");
-
- prop = RNA_def_property(srna, "simulation_rate", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "animRate");
- RNA_def_property_range(prop, 0.0, 100.0);
- RNA_def_property_ui_text(
- prop, "Simulation Speed", "Fluid motion rate (0 = stationary, 1 = normal speed)");
-
- prop = RNA_def_property(srna, "viscosity_base", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "viscosityValue");
- RNA_def_property_range(prop, 0, 10);
- RNA_def_property_ui_text(
- prop,
- "Viscosity Base",
- "Viscosity setting: value that is multiplied by 10 to the power of (exponent*-1)");
-
- prop = RNA_def_property(srna, "viscosity_exponent", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "viscosityExponent");
- RNA_def_property_range(prop, 0, 10);
- RNA_def_property_ui_text(
- prop,
- "Viscosity Exponent",
- "Negative exponent for the viscosity value (to simplify entering small values "
- "e.g. 5*10^-6)");
-
- prop = RNA_def_property(srna, "grid_levels", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "maxRefine");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, -1, 4);
- RNA_def_property_ui_text(
- prop, "Grid Levels", "Number of coarsened grids to use (-1 for automatic)");
-
- prop = RNA_def_property(srna, "compressibility", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "gstar");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0.001, 0.1);
- RNA_def_property_ui_text(prop,
- "Compressibility",
- "Allowed compressibility due to gravitational force for standing fluid "
- "(directly affects simulation step size)");
-
- /* domain boundary settings */
-
- rna_def_fluidsim_slip(srna);
-
- prop = RNA_def_property(srna, "surface_smooth", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "surfaceSmoothing");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0.0, 5.0);
- RNA_def_property_ui_text(
- prop,
- "Surface Smoothing",
- "Amount of surface smoothing (a value of 0 is off, 1 is normal smoothing and "
- "more than 1 is extra smoothing)");
-
- prop = RNA_def_property(srna, "surface_subdivisions", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "surfaceSubdivs");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0, 5);
- RNA_def_property_ui_text(
- prop,
- "Surface Subdivisions",
- "Number of isosurface subdivisions (this is necessary for the inclusion of particles "
- "into the surface generation - WARNING: can lead to longer computation times !)");
-
- prop = RNA_def_property(srna, "use_speed_vectors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "domainNovecgen", 0);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(
- prop, "Generate Speed Vectors", "Generate speed vectors for vector blur");
-
- /* no collision object surface */
- prop = RNA_def_property(srna, "use_surface_noobs", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSSG_NOOBS);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(
- prop,
- "Remove Air Bubbles",
- "Removes the air gap between fluid surface and obstacles - WARNING: Can result "
- "in a dissolving surface in other areas");
-
- /* particles */
-
- prop = RNA_def_property(srna, "tracer_particles", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "generateTracers");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0, 10000);
- RNA_def_property_ui_text(prop, "Tracer Particles", "Number of tracer particles to generate");
-
- prop = RNA_def_property(srna, "generate_particles", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "generateParticles");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop, "Generate Particles", "Amount of particles to generate (0=off, 1=normal, >1=more)");
-
- /* simulated fluid mesh data */
- prop = RNA_def_property(srna, "fluid_mesh_vertices", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "meshVelocities", "totvert");
- RNA_def_property_struct_type(prop, "FluidVertexVelocity");
- RNA_def_property_ui_text(
- prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation");
-
- rna_def_fluid_mesh_vertices(brna);
-}
-
-static void rna_def_fluidsim_volume(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- static const EnumPropertyItem volume_type_items[] = {
- {1, "VOLUME", 0, "Volume", "Use only the inner volume of the mesh"},
- {2, "SHELL", 0, "Shell", "Use only the outer shell of the mesh"},
- {3, "BOTH", 0, "Both", "Use both the inner volume and the outer shell of the mesh"},
- {0, NULL, 0, NULL, NULL},
- };
-
- prop = RNA_def_property(srna, "volume_initialization", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "volumeInitType");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_enum_items(prop, volume_type_items);
- RNA_def_property_ui_text(
- prop,
- "Volume Initialization",
- "Volume initialization type "
- "(WARNING: complex volumes might require too much memory and break simulation)");
-
- prop = RNA_def_property(srna, "use_animated_mesh", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "domainNovecgen", 0);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(
- prop,
- "Export Animated Mesh",
- "Export this mesh as an animated one (slower and enforces No Slip, only use if really "
- "necessary [e.g. armatures or parented objects], animated pos/rot/scale F-Curves "
- "do not require it)");
-}
-
-static void rna_def_fluidsim_active(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_ACTIVE);
- RNA_def_property_ui_text(prop, "Enabled", "Object contributes to the fluid simulation");
-}
-
-static void rna_def_fluidsim_fluid(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "FluidFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(srna,
- "Fluid Fluid Simulation Settings",
- "Fluid simulation settings for the fluid in the simulation");
-
- rna_def_fluidsim_active(srna);
- rna_def_fluidsim_volume(srna);
-
- prop = RNA_def_property(srna, "initial_velocity", PROP_FLOAT, PROP_VELOCITY);
- RNA_def_property_float_sdna(prop, NULL, "iniVelx");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, -1000.1, 1000.1);
- RNA_def_property_ui_text(prop, "Initial Velocity", "Initial velocity of fluid");
-}
-
-static void rna_def_fluidsim_obstacle(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "ObstacleFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(srna,
- "Obstacle Fluid Simulation Settings",
- "Fluid simulation settings for obstacles in the simulation");
-
- rna_def_fluidsim_active(srna);
- rna_def_fluidsim_volume(srna);
- rna_def_fluidsim_slip(srna);
-
- prop = RNA_def_property(srna, "impact_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "surfaceSmoothing");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, -2.0, 10.0);
- RNA_def_property_ui_text(
- prop,
- "Impact Factor",
- "This is an unphysical value for moving objects - it controls the impact an obstacle "
- "has on the fluid, =0 behaves a bit like outflow (deleting fluid), =1 is default, "
- "while >1 results in high forces (can be used to tweak total mass)");
-}
-
-static void rna_def_fluidsim_inflow(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "InflowFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(srna,
- "Inflow Fluid Simulation Settings",
- "Fluid simulation settings for objects adding fluids in the simulation");
-
- rna_def_fluidsim_active(srna);
- rna_def_fluidsim_volume(srna);
-
- prop = RNA_def_property(srna, "inflow_velocity", PROP_FLOAT, PROP_VELOCITY);
- RNA_def_property_float_sdna(prop, NULL, "iniVelx");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, -1000.1, 1000.1);
- RNA_def_property_ui_text(prop, "Inflow Velocity", "Initial velocity of fluid");
-
- prop = RNA_def_property(srna, "use_local_coords", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSINFLOW_LOCALCOORD);
- RNA_def_property_ui_text(
- prop, "Local Coordinates", "Use local coordinates for inflow (e.g. for rotating objects)");
-}
-
-static void rna_def_fluidsim_outflow(BlenderRNA *brna)
-{
- StructRNA *srna;
-
- srna = RNA_def_struct(brna, "OutflowFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(
- srna,
- "Outflow Fluid Simulation Settings",
- "Fluid simulation settings for objects removing fluids from the simulation");
-
- rna_def_fluidsim_active(srna);
- rna_def_fluidsim_volume(srna);
-}
-
-static void rna_def_fluidsim_particle(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "ParticleFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(srna,
- "Particle Fluid Simulation Settings",
- "Fluid simulation settings for objects storing fluid particles generated"
- " by the simulation");
-
- prop = RNA_def_property(srna, "use_drops", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSPART_DROP);
- RNA_def_property_ui_text(prop, "Drops", "Show drop particles");
-
- prop = RNA_def_property(srna, "use_floats", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSPART_FLOAT);
- RNA_def_property_ui_text(prop, "Floats", "Show floating foam particles");
-
- prop = RNA_def_property(srna, "show_tracer", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSPART_TRACER);
- RNA_def_property_ui_text(prop, "Tracer", "Show tracer particles");
-
- prop = RNA_def_property(srna, "particle_influence", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "particleInfSize");
- RNA_def_property_range(prop, 0.0, 2.0);
- RNA_def_property_ui_text(
- prop,
- "Particle Influence",
- "Amount of particle size scaling: 0=off (all same size), 1=full (range 0.2-2.0), "
- ">1=stronger");
-
- prop = RNA_def_property(srna, "alpha_influence", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "particleInfAlpha");
- RNA_def_property_range(prop, 0.0, 2.0);
- RNA_def_property_ui_text(
- prop,
- "Alpha Influence",
- "Amount of particle alpha change, inverse of size influence: 0=off (all same alpha), "
- "1=full (larger particles get lower alphas, smaller ones higher values)");
-
- prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
- RNA_def_property_string_maxlength(prop, FILE_MAX);
- RNA_def_property_string_sdna(prop, NULL, "surfdataPath");
- RNA_def_property_ui_text(
- prop, "Path", "Directory (and/or filename prefix) to store and load particles from");
- RNA_def_property_update(prop, 0, "rna_fluid_update");
-}
-
-static void rna_def_fluidsim_control(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "ControlFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(
- srna,
- "Control Fluid Simulation Settings",
- "Fluid simulation settings for objects controlling the motion of fluid in the simulation");
-
- rna_def_fluidsim_active(srna);
-
- prop = RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME);
- RNA_def_property_float_sdna(prop, NULL, "cpsTimeStart");
- RNA_def_property_range(prop, 0.0, FLT_MAX);
- RNA_def_property_ui_text(prop, "Start Time", "Time when the control particles are activated");
-
- prop = RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME);
- RNA_def_property_float_sdna(prop, NULL, "cpsTimeEnd");
- RNA_def_property_range(prop, 0.0, FLT_MAX);
- RNA_def_property_ui_text(prop, "End Time", "Time when the control particles are deactivated");
-
- prop = RNA_def_property(srna, "attraction_strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "attractforceStrength");
- RNA_def_property_range(prop, -10.0, 10.0);
- RNA_def_property_ui_text(prop,
- "Attraction Strength",
- "Force strength for directional attraction towards the control object");
-
- prop = RNA_def_property(srna, "attraction_radius", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "attractforceRadius");
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop, "Attraction Radius", "Force field radius around the control object");
-
- prop = RNA_def_property(srna, "velocity_strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "velocityforceStrength");
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop,
- "Velocity Strength",
- "Force strength of how much of the control object's velocity is influencing the "
- "fluid velocity");
-
- prop = RNA_def_property(srna, "velocity_radius", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "velocityforceRadius");
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop, "Velocity Radius", "Force field radius around the control object");
-
- prop = RNA_def_property(srna, "quality", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "cpsQuality");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 5.0, 100.0);
- RNA_def_property_ui_text(
- prop, "Quality", "Quality which is used for object sampling (higher = better but slower)");
-
- prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_REVERSE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse control object movement");
- RNA_def_property_update(prop, 0, "rna_fluid_find_enframe");
-}
-
-void RNA_def_fluidsim(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_fluid_type_items[] = {
- {OB_FLUIDSIM_ENABLE, "NONE", 0, "None", ""},
- {OB_FLUIDSIM_DOMAIN,
- "DOMAIN",
- 0,
- "Domain",
- "Bounding box of this object represents the computational domain of the "
- "fluid simulation"},
- {OB_FLUIDSIM_FLUID,
- "FLUID",
- 0,
- "Fluid",
- "Object represents a volume of fluid in the simulation"},
- {OB_FLUIDSIM_OBSTACLE, "OBSTACLE", 0, "Obstacle", "Object is a fixed obstacle"},
- {OB_FLUIDSIM_INFLOW, "INFLOW", 0, "Inflow", "Object adds fluid to the simulation"},
- {OB_FLUIDSIM_OUTFLOW, "OUTFLOW", 0, "Outflow", "Object removes fluid from the simulation"},
- {OB_FLUIDSIM_PARTICLE,
- "PARTICLE",
- 0,
- "Particle",
- "Object is made a particle system to display particles generated by a "
- "fluidsim domain object"},
- {OB_FLUIDSIM_CONTROL,
- "CONTROL",
- 0,
- "Control",
- "Object is made a fluid control mesh, which influences the fluid"},
- {0, NULL, 0, NULL, NULL},
- };
-
- srna = RNA_def_struct(brna, "FluidSettings", NULL);
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_refine_func(srna, "rna_FluidSettings_refine");
- RNA_def_struct_path_func(srna, "rna_FluidSettings_path");
- RNA_def_struct_ui_text(srna,
- "Fluid Simulation Settings",
- "Fluid simulation settings for an object taking part in the simulation");
-
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_fluid_type_items);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Type", "Type of participation in the fluid simulation");
- RNA_def_property_update(prop, 0, "rna_FluidSettings_update_type");
-
-# if 0
- prop = RNA_def_property(srna, "ipo", PROP_POINTER, PROP_NONE);
- RNA_def_property_ui_text(prop, "IPO Curves", "IPO curves used by fluid simulation settings");
-# endif
-
- /* types */
-
- rna_def_fluidsim_domain(brna);
- rna_def_fluidsim_fluid(brna);
- rna_def_fluidsim_obstacle(brna);
- rna_def_fluidsim_inflow(brna);
- rna_def_fluidsim_outflow(brna);
- rna_def_fluidsim_particle(brna);
- rna_def_fluidsim_control(brna);
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 2601600c6ee..17163095d4b 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -167,32 +167,23 @@ static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene
WM_main_add_notifier(NC_SCENE | ND_MODE | NC_MOVIECLIP, NULL);
}
-static void UNUSED_FUNCTION(rna_GPencil_onion_skinning_update)(Main *bmain,
- Scene *scene,
- PointerRNA *ptr)
+/* Recalc UVs and Fill for all strokes. */
+static void rna_GPencil_strokes_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->owner_id;
- bGPDlayer *gpl;
- bool enabled = false;
-
- /* Ensure that the data-block's onion-skinning toggle flag
- * stays in sync with the status of the actual layers
- */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->onion_flag & GP_LAYER_ONIONSKIN) {
- enabled = true;
+ if (gpd) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ BKE_gpencil_triangulate_stroke_fill(gpd, gps);
+ }
+ }
}
}
- if (enabled) {
- gpd->flag |= GP_DATA_SHOW_ONIONSKINS;
- }
- else {
- gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
- }
-
/* Now do standard updates... */
- rna_GPencil_update(bmain, scene, ptr);
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
/* Poll Callback to filter GP Datablocks to only show those for Annotations */
@@ -1781,7 +1772,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_UV_ADAPTIVE);
RNA_def_property_ui_text(
prop, "Adaptive UV", "Automatic UVs are calculated depending of the stroke size");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_strokes_update");
prop = RNA_def_property(srna, "use_autolock_layers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_AUTOLOCK_LAYERS);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 7aa3ee60c5a..2f59cde7e94 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -43,7 +43,7 @@
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
-#include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */
+#include "BKE_fluid.h" /* For BKE_fluid_modifier_free & BKE_fluid_modifier_create_type_data */
#include "RNA_access.h"
#include "RNA_define.h"
@@ -174,7 +174,7 @@ static const EnumPropertyItem rna_enum_time_mode_items[] = {
# include "DNA_particle_types.h"
# include "DNA_curve_types.h"
-# include "DNA_smoke_types.h"
+# include "DNA_fluid_types.h"
# include "BKE_cachefile.h"
# include "BKE_context.h"
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 517bd2b7276..d07bf542954 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -57,6 +57,7 @@ static const EnumPropertyItem image_source_items[] = {
{IMA_SRC_MOVIE, "MOVIE", 0, "Movie", "Movie file"},
{IMA_SRC_GENERATED, "GENERATED", 0, "Generated", "Generated image"},
{IMA_SRC_VIEWER, "VIEWER", 0, "Viewer", "Compositing node viewer"},
+ {IMA_SRC_TILED, "TILED", 0, "Tiled", "Tiled image texture"},
{0, NULL, 0, NULL, NULL},
};
@@ -209,6 +210,7 @@ static const EnumPropertyItem *rna_Image_source_itemf(bContext *UNUSED(C),
RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_SEQUENCE);
RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_MOVIE);
RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_GENERATED);
+ RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_TILED);
}
RNA_enum_item_end(&item, &totitem);
@@ -238,6 +240,88 @@ static void rna_Image_file_format_set(PointerRNA *ptr, int value)
}
}
+static void rna_UDIMTile_label_get(PointerRNA *ptr, char *value)
+{
+ ImageTile *tile = (ImageTile *)ptr->data;
+ Image *image = (Image *)ptr->owner_id;
+
+ /* We don't know the length of the target string here, so we assume
+ * that it has been allocated according to what rna_UDIMTile_label_length returned. */
+ BKE_image_get_tile_label(image, tile, value, sizeof(tile->label));
+}
+
+static int rna_UDIMTile_label_length(PointerRNA *ptr)
+{
+ ImageTile *tile = (ImageTile *)ptr->data;
+ Image *image = (Image *)ptr->owner_id;
+
+ char label[sizeof(tile->label)];
+ BKE_image_get_tile_label(image, tile, label, sizeof(label));
+
+ return strlen(label);
+}
+
+static void rna_UDIMTile_tile_number_set(PointerRNA *ptr, int value)
+{
+ ImageTile *tile = (ImageTile *)ptr->data;
+ Image *image = (Image *)ptr->owner_id;
+
+ /* The index of the first tile can't be changed. */
+ if (tile->tile_number == 1001) {
+ return;
+ }
+
+ /* Check that no other tile already has that number. */
+ ImageTile *cur_tile = BKE_image_get_tile(image, value);
+ if (cur_tile == NULL || cur_tile == tile) {
+ tile->tile_number = value;
+ }
+}
+
+static int rna_Image_active_tile_index_get(PointerRNA *ptr)
+{
+ Image *image = (Image *)ptr->data;
+ return image->active_tile_index;
+}
+
+static void rna_Image_active_tile_index_set(PointerRNA *ptr, int value)
+{
+ Image *image = (Image *)ptr->data;
+ int num_tiles = BLI_listbase_count(&image->tiles);
+
+ image->active_tile_index = min_ii(value, num_tiles - 1);
+}
+
+static void rna_Image_active_tile_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ Image *image = (Image *)ptr->data;
+ int num_tiles = BLI_listbase_count(&image->tiles);
+
+ *min = 0;
+ *max = max_ii(0, num_tiles - 1);
+}
+
+static PointerRNA rna_Image_active_tile_get(PointerRNA *ptr)
+{
+ Image *image = (Image *)ptr->data;
+ ImageTile *tile = BLI_findlink(&image->tiles, image->active_tile_index);
+
+ return rna_pointer_inherit_refine(ptr, &RNA_UDIMTile, tile);
+}
+
+static void rna_Image_active_tile_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ Image *image = (Image *)ptr->data;
+ ImageTile *tile = (ImageTile *)value.data;
+ const int index = BLI_findindex(&image->tiles, tile);
+ if (index != -1) {
+ image->active_tile_index = index;
+ }
+}
+
static bool rna_Image_has_data_get(PointerRNA *ptr)
{
Image *image = (Image *)ptr->data;
@@ -301,7 +385,8 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values)
static int rna_Image_bindcode_get(PointerRNA *ptr)
{
Image *ima = (Image *)ptr->data;
- GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D];
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
return (tex) ? GPU_texture_opengl_bindcode(tex) : 0;
}
@@ -527,6 +612,23 @@ static void rna_render_slots_active_index_range(
*max = max_ii(0, BLI_listbase_count(&image->renderslots) - 1);
}
+static ImageTile *rna_UDIMTile_new(Image *image, int tile_number, const char *label)
+{
+ ImageTile *tile = BKE_image_add_tile(image, tile_number, label);
+
+ WM_main_add_notifier(NC_IMAGE | ND_DRAW, NULL);
+
+ return tile;
+}
+
+static void rna_UDIMTile_remove(Image *image, PointerRNA *ptr)
+{
+ ImageTile *tile = (ImageTile *)ptr->data;
+ BKE_image_remove_tile(image, tile);
+
+ WM_main_add_notifier(NC_IMAGE | ND_DRAW, NULL);
+}
+
#else
static void rna_def_imageuser(BlenderRNA *brna)
@@ -597,6 +699,11 @@ static void rna_def_imageuser(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "view");
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
RNA_def_property_ui_text(prop, "View", "View in multilayer image");
+
+ prop = RNA_def_property(srna, "tile", PROP_INT, PROP_UNSIGNED);
+ 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");
}
/* image.packed_files */
@@ -676,6 +783,79 @@ static void rna_def_render_slots(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
}
+static void rna_def_udim_tile(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "UDIMTile", NULL);
+ RNA_def_struct_sdna(srna, "ImageTile");
+ RNA_def_struct_ui_text(srna, "UDIM Tile", "Properties of the UDIM tile");
+
+ prop = RNA_def_property(srna, "label", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "label");
+ RNA_def_property_ui_text(prop, "Label", "Tile label");
+ RNA_def_property_string_funcs(prop, "rna_UDIMTile_label_get", "rna_UDIMTile_label_length", NULL);
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
+
+ prop = RNA_def_property(srna, "number", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "tile_number");
+ 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);
+}
+
+static void rna_def_udim_tiles(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "UDIMTiles");
+ srna = RNA_def_struct(brna, "UDIMTiles", NULL);
+ RNA_def_struct_sdna(srna, "Image");
+ RNA_def_struct_ui_text(srna, "UDIM Tiles", "Collection of UDIM tiles");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "active_tile_index");
+ RNA_def_property_int_funcs(prop,
+ "rna_Image_active_tile_index_get",
+ "rna_Image_active_tile_index_set",
+ "rna_Image_active_tile_index_range");
+ RNA_def_property_ui_text(prop, "Active Tile Index", "Active index in tiles array");
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "UDIMTile");
+ RNA_def_property_pointer_funcs(
+ prop, "rna_Image_active_tile_get", "rna_Image_active_tile_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_ui_text(prop, "Active Image Tile", "Active Image Tile");
+
+ func = RNA_def_function(srna, "new", "rna_UDIMTile_new");
+ RNA_def_function_ui_description(func, "Add a tile to the image");
+ parm = RNA_def_int(
+ func, "tile_number", 1, 1, INT_MAX, "", "Number of the newly created tile", 1, 100);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "label", NULL, 0, "", "Optional label for the tile");
+ parm = RNA_def_pointer(func, "result", "UDIMTile", "", "Newly created image tile");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "get", "BKE_image_get_tile");
+ RNA_def_function_ui_description(func, "Get a tile based on its tile number");
+ parm = RNA_def_int(func, "tile_number", 0, 0, INT_MAX, "", "Number of the tile", 0, 100);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "UDIMTile", "", "The tile");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_UDIMTile_remove");
+ RNA_def_function_ui_description(func, "Remove an image tile");
+ parm = RNA_def_pointer(func, "tile", "UDIMTile", "", "Image tile to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+}
+
static void rna_def_image(BlenderRNA *brna)
{
StructRNA *srna;
@@ -860,6 +1040,12 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Render Slots", "Render slots of the image");
rna_def_render_slots(brna, prop);
+ prop = RNA_def_property(srna, "tiles", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "UDIMTile");
+ RNA_def_property_collection_sdna(prop, NULL, "tiles", NULL);
+ RNA_def_property_ui_text(prop, "Image Tiles", "Tiles of the image");
+ rna_def_udim_tiles(brna, prop);
+
/*
* Image.has_data and Image.depth are temporary,
* Update import_obj.py when they are replaced (Arystan)
@@ -954,6 +1140,7 @@ static void rna_def_image(BlenderRNA *brna)
void RNA_def_image(BlenderRNA *brna)
{
rna_def_render_slot(brna);
+ rna_def_udim_tile(brna);
rna_def_image(brna);
rna_def_imageuser(brna);
rna_def_image_packed_files(brna);
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index d167c650683..c4ec0a84a2c 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -31,8 +31,6 @@
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
-#include "BIF_gl.h"
-
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -52,6 +50,8 @@
# include "DNA_image_types.h"
# include "DNA_scene_types.h"
+# include "GPU_glew.h"
+
# include "MEM_guardedalloc.h"
static void rna_ImagePackedFile_save(ImagePackedFile *imapf, Main *bmain, ReportList *reports)
@@ -174,8 +174,9 @@ static void rna_Image_unpack(Image *image, Main *bmain, ReportList *reports, int
if (!BKE_image_has_packedfile(image)) {
BKE_report(reports, RPT_ERROR, "Image not packed");
}
- else if (BKE_image_is_animated(image)) {
- BKE_report(reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
+ else if (BKE_image_has_multiple_ibufs(image)) {
+ BKE_report(
+ reports, RPT_ERROR, "Unpacking movies, image sequences or tiled images not supported");
return;
}
else {
@@ -215,11 +216,12 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
}
}
-static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
+static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int tile_number)
{
- ImageUser iuser = {NULL};
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
iuser.framenr = frame;
- iuser.ok = true;
+ iuser.tile = tile_number;
GPUTexture *tex = GPU_texture_from_blender(image, &iuser, GL_TEXTURE_2D);
@@ -231,14 +233,15 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
return GL_NO_ERROR;
}
-static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame)
+static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame, int tile_number)
{
int error = GL_NO_ERROR;
BKE_image_tag_time(image);
- if (image->gputexture[TEXTARGET_TEXTURE_2D] == NULL) {
- error = rna_Image_gl_load(image, reports, frame);
+ ImageTile *tile = BKE_image_get_tile(image, tile_number);
+ if (tile->gputexture[TEXTARGET_TEXTURE_2D] == NULL) {
+ error = rna_Image_gl_load(image, reports, frame, tile_number);
}
return error;
@@ -333,6 +336,7 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
+ RNA_def_int(func, "tile_number", 0, 0, INT_MAX, "Tile", "Tile of a tiled image", 0, INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
@@ -347,6 +351,7 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
+ RNA_def_int(func, "tile_number", 0, 0, INT_MAX, "Tile", "Tile of a tiled image", 0, INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 11a322564a4..4d3b009c1d4 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -155,7 +155,6 @@ void RNA_def_controller(struct BlenderRNA *brna);
void RNA_def_curve(struct BlenderRNA *brna);
void RNA_def_depsgraph(struct BlenderRNA *brna);
void RNA_def_dynamic_paint(struct BlenderRNA *brna);
-void RNA_def_fluidsim(struct BlenderRNA *brna);
void RNA_def_fcurve(struct BlenderRNA *brna);
void RNA_def_gpencil(struct BlenderRNA *brna);
void RNA_def_greasepencil_modifier(struct BlenderRNA *brna);
@@ -188,7 +187,7 @@ void RNA_def_view_layer(struct BlenderRNA *brna);
void RNA_def_screen(struct BlenderRNA *brna);
void RNA_def_sculpt_paint(struct BlenderRNA *brna);
void RNA_def_sequencer(struct BlenderRNA *brna);
-void RNA_def_smoke(struct BlenderRNA *brna);
+void RNA_def_fluid(struct BlenderRNA *brna);
void RNA_def_space(struct BlenderRNA *brna);
void RNA_def_speaker(struct BlenderRNA *brna);
void RNA_def_test(struct BlenderRNA *brna);
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 2c42dba9131..d85c5c5f249 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -372,14 +372,24 @@ static Image *rna_Main_images_new(Main *bmain,
bool alpha,
bool float_buffer,
bool stereo3d,
- bool is_data)
+ bool is_data,
+ bool tiled)
{
char safe_name[MAX_ID_NAME - 2];
rna_idname_validate(name, safe_name);
float color[4] = {0.0, 0.0, 0.0, 1.0};
- Image *image = BKE_image_add_generated(
- bmain, width, height, safe_name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d, is_data);
+ Image *image = BKE_image_add_generated(bmain,
+ width,
+ height,
+ safe_name,
+ alpha ? 32 : 24,
+ float_buffer,
+ 0,
+ color,
+ stereo3d,
+ is_data,
+ tiled);
id_us_min(&image->id);
return image;
}
@@ -1146,6 +1156,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
func, "float_buffer", 0, "Float Buffer", "Create an image with floating point color");
RNA_def_boolean(func, "stereo3d", 0, "Stereo 3D", "Create left and right views");
RNA_def_boolean(func, "is_data", 0, "Is Data", "Create image with non-color data color space");
+ RNA_def_boolean(func, "tiled", 0, "Tiled", "Create a tiled image");
/* return type */
parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 5890c3fe8a2..5e21fc883a9 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -2987,7 +2987,7 @@ static void rna_def_mesh(BlenderRNA *brna)
/* Remesh */
prop = RNA_def_property(srna, "remesh_voxel_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "remesh_voxel_size");
- RNA_def_property_range(prop, 0.00001f, FLT_MAX);
+ RNA_def_property_range(prop, 0.0001f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0001f, FLT_MAX, 0.01, 4);
RNA_def_property_ui_text(prop,
"Voxel Size",
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 789946d3268..589ce1414bb 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -45,7 +45,7 @@
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
#include "BKE_ocean.h"
-#include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */
+#include "BKE_fluid.h" /* For BKE_fluid_modifier_free & BKE_fluid_modifier_create_type_data */
#include "RNA_access.h"
#include "RNA_define.h"
@@ -58,92 +58,235 @@
const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
{0, "", 0, N_("Modify"), ""},
- {eModifierType_DataTransfer, "DATA_TRANSFER", ICON_MOD_DATA_TRANSFER, "Data Transfer", ""},
- {eModifierType_MeshCache, "MESH_CACHE", ICON_MOD_MESHDEFORM, "Mesh Cache", ""},
+ {eModifierType_DataTransfer,
+ "DATA_TRANSFER",
+ ICON_MOD_DATA_TRANSFER,
+ "Data Transfer",
+ "Transfer several types of data (vertex groups, UV maps, vertex colors, custom normals) from "
+ "one mesh to another"},
+ {eModifierType_MeshCache,
+ "MESH_CACHE",
+ ICON_MOD_MESHDEFORM,
+ "Mesh Cache",
+ "Deform the mesh using an external frame-by-frame vertex transform cache"},
{eModifierType_MeshSequenceCache,
"MESH_SEQUENCE_CACHE",
ICON_MOD_MESHDEFORM,
"Mesh Sequence Cache",
- ""},
- {eModifierType_NormalEdit, "NORMAL_EDIT", ICON_MOD_NORMALEDIT, "Normal Edit", ""},
- {eModifierType_WeightedNormal, "WEIGHTED_NORMAL", ICON_MOD_NORMALEDIT, "Weighted Normal", ""},
- {eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""},
- {eModifierType_UVWarp, "UV_WARP", ICON_MOD_UVPROJECT, "UV Warp", ""},
+ "Deform the mesh or curve using an external mesh cache in Alembic format"},
+ {eModifierType_NormalEdit,
+ "NORMAL_EDIT",
+ ICON_MOD_NORMALEDIT,
+ "Normal Edit",
+ "Modify the direction of the surface normals"},
+ {eModifierType_WeightedNormal,
+ "WEIGHTED_NORMAL",
+ ICON_MOD_NORMALEDIT,
+ "Weighted Normal",
+ "Modify the direction of the surface normals using a weighting method"},
+ {eModifierType_UVProject,
+ "UV_PROJECT",
+ ICON_MOD_UVPROJECT,
+ "UV Project",
+ "Project the UV map coordinates from the negative Z axis of another object"},
+ {eModifierType_UVWarp,
+ "UV_WARP",
+ ICON_MOD_UVPROJECT,
+ "UV Warp",
+ "Transform the UV map using the the difference between two objects"},
{eModifierType_WeightVGEdit,
"VERTEX_WEIGHT_EDIT",
ICON_MOD_VERTEX_WEIGHT,
"Vertex Weight Edit",
- ""},
+ "Modify of the weights of a vertex group"},
{eModifierType_WeightVGMix,
"VERTEX_WEIGHT_MIX",
ICON_MOD_VERTEX_WEIGHT,
"Vertex Weight Mix",
- ""},
+ "Mix the weights of two vertex groups"},
{eModifierType_WeightVGProximity,
"VERTEX_WEIGHT_PROXIMITY",
ICON_MOD_VERTEX_WEIGHT,
"Vertex Weight Proximity",
- ""},
+ "Set the vertex group weights based on the distance to another target object"},
{0, "", 0, N_("Generate"), ""},
- {eModifierType_Array, "ARRAY", ICON_MOD_ARRAY, "Array", ""},
- {eModifierType_Bevel, "BEVEL", ICON_MOD_BEVEL, "Bevel", ""},
- {eModifierType_Boolean, "BOOLEAN", ICON_MOD_BOOLEAN, "Boolean", ""},
- {eModifierType_Build, "BUILD", ICON_MOD_BUILD, "Build", ""},
- {eModifierType_Decimate, "DECIMATE", ICON_MOD_DECIM, "Decimate", ""},
- {eModifierType_EdgeSplit, "EDGE_SPLIT", ICON_MOD_EDGESPLIT, "Edge Split", ""},
- {eModifierType_Mask, "MASK", ICON_MOD_MASK, "Mask", ""},
- {eModifierType_Mirror, "MIRROR", ICON_MOD_MIRROR, "Mirror", ""},
- {eModifierType_Multires, "MULTIRES", ICON_MOD_MULTIRES, "Multiresolution", ""},
- {eModifierType_Remesh, "REMESH", ICON_MOD_REMESH, "Remesh", ""},
- {eModifierType_Screw, "SCREW", ICON_MOD_SCREW, "Screw", ""},
- {eModifierType_Skin, "SKIN", ICON_MOD_SKIN, "Skin", ""},
- {eModifierType_Solidify, "SOLIDIFY", ICON_MOD_SOLIDIFY, "Solidify", ""},
- {eModifierType_Subsurf, "SUBSURF", ICON_MOD_SUBSURF, "Subdivision Surface", ""},
- {eModifierType_Triangulate, "TRIANGULATE", ICON_MOD_TRIANGULATE, "Triangulate", ""},
+ {eModifierType_Array,
+ "ARRAY",
+ ICON_MOD_ARRAY,
+ "Array",
+ "Create copies of the shape with offsets"},
+ {eModifierType_Bevel,
+ "BEVEL",
+ ICON_MOD_BEVEL,
+ "Bevel",
+ "Generate sloped corners by adding geometry to the mesh's edges or vertices"},
+ {eModifierType_Boolean,
+ "BOOLEAN",
+ ICON_MOD_BOOLEAN,
+ "Boolean",
+ "Use another shape to cut, combine or perform a difference operation"},
+ {eModifierType_Build,
+ "BUILD",
+ ICON_MOD_BUILD,
+ "Build",
+ "Cause the faces of the mesh object to appear or disappear one after the other over time"},
+ {eModifierType_Decimate,
+ "DECIMATE",
+ ICON_MOD_DECIM,
+ "Decimate",
+ "Reduce the geometry density"},
+ {eModifierType_EdgeSplit,
+ "EDGE_SPLIT",
+ ICON_MOD_EDGESPLIT,
+ "Edge Split",
+ "Split away joined faces at the edges"},
+ {eModifierType_Mask,
+ "MASK",
+ ICON_MOD_MASK,
+ "Mask",
+ "Dynamically hide vertices based on a vertex group or armature"},
+ {eModifierType_Mirror,
+ "MIRROR",
+ ICON_MOD_MIRROR,
+ "Mirror",
+ "Mirror along the local X, Y and/or Z axes, over the object origin"},
+ {eModifierType_Multires,
+ "MULTIRES",
+ ICON_MOD_MULTIRES,
+ "Multiresolution",
+ "Subdivide the mesh in a way that allows editing the higher subdivision levels"},
+ {eModifierType_Remesh,
+ "REMESH",
+ ICON_MOD_REMESH,
+ "Remesh",
+ "Generate new mesh topology based on the current shape"},
+ {eModifierType_Screw,
+ "SCREW",
+ ICON_MOD_SCREW,
+ "Screw",
+ "Lathe around an axis, treating the inout mesh as a profile"},
+ {eModifierType_Skin,
+ "SKIN",
+ ICON_MOD_SKIN,
+ "Skin",
+ "Create a solid shape from vertices and edges, using the vertex radius to define the "
+ "thickness"},
+ {eModifierType_Solidify, "SOLIDIFY", ICON_MOD_SOLIDIFY, "Solidify", " Make the surface thick"},
+ {eModifierType_Subsurf,
+ "SUBSURF",
+ ICON_MOD_SUBSURF,
+ "Subdivision Surface",
+ "Split the faces into smaller parts, giving it a smoother appearance"},
+ {eModifierType_Triangulate,
+ "TRIANGULATE",
+ ICON_MOD_TRIANGULATE,
+ "Triangulate",
+ "Convert all polygons to triangles"},
{eModifierType_Wireframe,
"WIREFRAME",
ICON_MOD_WIREFRAME,
"Wireframe",
- "Generate a wireframe on the edges of a mesh"},
+ "Convert faces into thickened edges"},
+ {eModifierType_Weld,
+ "WELD",
+ ICON_AUTOMERGE_OFF,
+ "Weld",
+ "Find groups of vertices closer then dist and merges them together"},
{0, "", 0, N_("Deform"), ""},
- {eModifierType_Armature, "ARMATURE", ICON_MOD_ARMATURE, "Armature", ""},
- {eModifierType_Cast, "CAST", ICON_MOD_CAST, "Cast", ""},
- {eModifierType_Curve, "CURVE", ICON_MOD_CURVE, "Curve", ""},
- {eModifierType_Displace, "DISPLACE", ICON_MOD_DISPLACE, "Displace", ""},
- {eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", ""},
+ {eModifierType_Armature,
+ "ARMATURE",
+ ICON_MOD_ARMATURE,
+ "Armature",
+ "Deform the shape using an armature object"},
+ {eModifierType_Cast,
+ "CAST",
+ ICON_MOD_CAST,
+ "Cast",
+ "Shift the shape towards a predefined primitive"},
+ {eModifierType_Curve, "CURVE", ICON_MOD_CURVE, "Curve", "Bend the mesh using a curve object"},
+ {eModifierType_Displace,
+ "DISPLACE",
+ ICON_MOD_DISPLACE,
+ "Displace",
+ "Offset vertices based on a texture"},
+ {eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", "Deform specific points using another object"},
{eModifierType_LaplacianDeform,
"LAPLACIANDEFORM",
ICON_MOD_MESHDEFORM,
"Laplacian Deform",
- ""},
- {eModifierType_Lattice, "LATTICE", ICON_MOD_LATTICE, "Lattice", ""},
- {eModifierType_MeshDeform, "MESH_DEFORM", ICON_MOD_MESHDEFORM, "Mesh Deform", ""},
- {eModifierType_Shrinkwrap, "SHRINKWRAP", ICON_MOD_SHRINKWRAP, "Shrinkwrap", ""},
- {eModifierType_SimpleDeform, "SIMPLE_DEFORM", ICON_MOD_SIMPLEDEFORM, "Simple Deform", ""},
- {eModifierType_Smooth, "SMOOTH", ICON_MOD_SMOOTH, "Smooth", ""},
+ "Deform based a series of anchor points"},
+ {eModifierType_Lattice,
+ "LATTICE",
+ ICON_MOD_LATTICE,
+ "Lattice",
+ "Deform using the shape of a lattice object"},
+ {eModifierType_MeshDeform,
+ "MESH_DEFORM",
+ ICON_MOD_MESHDEFORM,
+ "Mesh Deform",
+ "Deform using a different mesh, which acts as a deformation cage"},
+ {eModifierType_Shrinkwrap,
+ "SHRINKWRAP",
+ ICON_MOD_SHRINKWRAP,
+ "Shrinkwrap",
+ "Project the shape onto another object"},
+ {eModifierType_SimpleDeform,
+ "SIMPLE_DEFORM",
+ ICON_MOD_SIMPLEDEFORM,
+ "Simple Deform",
+ "Deform the shape by twisting, bending, tapering or stretching"},
+ {eModifierType_Smooth,
+ "SMOOTH",
+ ICON_MOD_SMOOTH,
+ "Smooth",
+ "Smooth the mesh by flattening the angles between adjacent faces"},
{eModifierType_CorrectiveSmooth,
"CORRECTIVE_SMOOTH",
ICON_MOD_SMOOTH,
"Smooth Corrective",
- ""},
- {eModifierType_LaplacianSmooth, "LAPLACIANSMOOTH", ICON_MOD_SMOOTH, "Smooth Laplacian", ""},
- {eModifierType_SurfaceDeform, "SURFACE_DEFORM", ICON_MOD_MESHDEFORM, "Surface Deform", ""},
- {eModifierType_Warp, "WARP", ICON_MOD_WARP, "Warp", ""},
- {eModifierType_Wave, "WAVE", ICON_MOD_WAVE, "Wave", ""},
+ "Smooth the mesh while still preserving the volume"},
+ {eModifierType_LaplacianSmooth,
+ "LAPLACIANSMOOTH",
+ ICON_MOD_SMOOTH,
+ "Smooth Laplacian",
+ "Reduce the noise on a mesh surface with minimal changes to its shape"},
+ {eModifierType_SurfaceDeform,
+ "SURFACE_DEFORM",
+ ICON_MOD_MESHDEFORM,
+ "Surface Deform",
+ "Transfer motion from another mesh"},
+ {eModifierType_Warp,
+ "WARP",
+ ICON_MOD_WARP,
+ "Warp",
+ "Warp parts of a mesh to a new location in a very flexible way thanks to 2 specified "
+ "objects"},
+ {eModifierType_Wave,
+ "WAVE",
+ ICON_MOD_WAVE,
+ "Wave",
+ "Adds a ripple-like motion to an object’s geometry"},
{0, "", 0, N_("Simulate"), ""},
{eModifierType_Cloth, "CLOTH", ICON_MOD_CLOTH, "Cloth", ""},
{eModifierType_Collision, "COLLISION", ICON_MOD_PHYSICS, "Collision", ""},
{eModifierType_DynamicPaint, "DYNAMIC_PAINT", ICON_MOD_DYNAMICPAINT, "Dynamic Paint", ""},
- {eModifierType_Explode, "EXPLODE", ICON_MOD_EXPLODE, "Explode", ""},
- {eModifierType_Fluidsim, "FLUID_SIMULATION", ICON_MOD_FLUIDSIM, "Fluid Simulation", ""},
- {eModifierType_Ocean, "OCEAN", ICON_MOD_OCEAN, "Ocean", ""},
+ {eModifierType_Explode,
+ "EXPLODE",
+ ICON_MOD_EXPLODE,
+ "Explode",
+ "Break apart the mesh faces and let them follow particles"},
+ {eModifierType_Ocean, "OCEAN", ICON_MOD_OCEAN, "Ocean", "Generate a moving ocean surface"},
{eModifierType_ParticleInstance,
"PARTICLE_INSTANCE",
ICON_MOD_PARTICLE_INSTANCE,
"Particle Instance",
""},
- {eModifierType_ParticleSystem, "PARTICLE_SYSTEM", ICON_MOD_PARTICLES, "Particle System", ""},
- {eModifierType_Smoke, "SMOKE", ICON_MOD_SMOKE, "Smoke", ""},
+ {eModifierType_ParticleSystem,
+ "PARTICLE_SYSTEM",
+ ICON_MOD_PARTICLES,
+ "Particle System",
+ "Spawn particles from the shape"},
+ {eModifierType_Fluid, "FLUID", ICON_MOD_FLUIDSIM, "Fluid Simulation", ""},
{eModifierType_Softbody, "SOFT_BODY", ICON_MOD_SOFT, "Soft Body", ""},
{eModifierType_Surface, "SURFACE", ICON_MODIFIER, "Surface", ""},
{0, NULL, 0, NULL, NULL},
@@ -436,7 +579,7 @@ const EnumPropertyItem rna_enum_axis_flag_xyz_items[] = {
#ifdef RNA_RUNTIME
# include "DNA_particle_types.h"
# include "DNA_curve_types.h"
-# include "DNA_smoke_types.h"
+# include "DNA_fluid_types.h"
# include "BKE_cachefile.h"
# include "BKE_context.h"
@@ -517,8 +660,6 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_BevelModifier;
case eModifierType_Shrinkwrap:
return &RNA_ShrinkwrapModifier;
- case eModifierType_Fluidsim:
- return &RNA_FluidSimulationModifier;
case eModifierType_Mask:
return &RNA_MaskModifier;
case eModifierType_SimpleDeform:
@@ -527,8 +668,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_MultiresModifier;
case eModifierType_Surface:
return &RNA_SurfaceModifier;
- case eModifierType_Smoke:
- return &RNA_SmokeModifier;
+ case eModifierType_Fluid:
+ return &RNA_FluidModifier;
case eModifierType_Solidify:
return &RNA_SolidifyModifier;
case eModifierType_Screw:
@@ -561,6 +702,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_LaplacianDeformModifier;
case eModifierType_Wireframe:
return &RNA_WireframeModifier;
+ case eModifierType_Weld:
+ return &RNA_WeldModifier;
case eModifierType_DataTransfer:
return &RNA_DataTransferModifier;
case eModifierType_NormalEdit:
@@ -574,6 +717,7 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
case eModifierType_WeightedNormal:
return &RNA_WeightedNormalModifier;
/* Default */
+ case eModifierType_Fluidsim: /* deprecated */
case eModifierType_None:
case eModifierType_ShapeKey:
case NUM_MODIFIER_TYPES:
@@ -664,6 +808,7 @@ RNA_MOD_VGROUP_NAME_SET(WeightVGMix, mask_defgrp_name);
RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, mask_defgrp_name);
RNA_MOD_VGROUP_NAME_SET(WeightedNormal, defgrp_name);
+RNA_MOD_VGROUP_NAME_SET(Weld, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Wireframe, defgrp_name);
static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value)
@@ -882,25 +1027,27 @@ static void rna_UVProjector_object_set(PointerRNA *ptr,
/* Other rna callbacks */
-static void rna_Smoke_set_type(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_fluid_set_type(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- SmokeModifierData *smd = (SmokeModifierData *)ptr->data;
+ FluidModifierData *mmd = (FluidModifierData *)ptr->data;
Object *ob = (Object *)ptr->owner_id;
/* nothing changed */
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
+ if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) {
return;
}
- smokeModifier_free(smd); /* XXX TODO: completely free all 3 pointers */
- smokeModifier_createType(smd); /* create regarding of selected type */
+# ifdef WITH_FLUID
+ BKE_fluid_modifier_free(mmd); /* XXX TODO: completely free all 3 pointers */
+ BKE_fluid_modifier_create_type_data(mmd); /* create regarding of selected type */
+# endif
- switch (smd->type) {
- case MOD_SMOKE_TYPE_DOMAIN:
+ switch (mmd->type) {
+ case MOD_FLUID_TYPE_DOMAIN:
ob->dt = OB_WIRE;
break;
- case MOD_SMOKE_TYPE_FLOW:
- case MOD_SMOKE_TYPE_COLL:
+ case MOD_FLUID_TYPE_FLOW:
+ case MOD_FLUID_TYPE_EFFEC:
case 0:
default:
break;
@@ -3460,23 +3607,23 @@ static void rna_def_modifier_cloth(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Hair Grid Resolution", "");
}
-static void rna_def_modifier_smoke(BlenderRNA *brna)
+static void rna_def_modifier_fluid(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem prop_smoke_type_items[] = {
+ static const EnumPropertyItem prop_fluid_type_items[] = {
{0, "NONE", 0, "None", ""},
- {MOD_SMOKE_TYPE_DOMAIN, "DOMAIN", 0, "Domain", ""},
- {MOD_SMOKE_TYPE_FLOW, "FLOW", 0, "Flow", "Inflow/Outflow"},
- {MOD_SMOKE_TYPE_COLL, "COLLISION", 0, "Collision", ""},
+ {MOD_FLUID_TYPE_DOMAIN, "DOMAIN", 0, "Domain", ""},
+ {MOD_FLUID_TYPE_FLOW, "FLOW", 0, "Flow", "Inflow/Outflow"},
+ {MOD_FLUID_TYPE_EFFEC, "EFFECTOR", 0, "Effector", ""},
{0, NULL, 0, NULL, NULL},
};
- srna = RNA_def_struct(brna, "SmokeModifier", "Modifier");
- RNA_def_struct_ui_text(srna, "Smoke Modifier", "Smoke simulation modifier");
- RNA_def_struct_sdna(srna, "SmokeModifierData");
- RNA_def_struct_ui_icon(srna, ICON_MOD_SMOKE);
+ srna = RNA_def_struct(brna, "FluidModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Fluid Modifier", "Fluid simulation modifier");
+ RNA_def_struct_sdna(srna, "FluidModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_FLUIDSIM);
prop = RNA_def_property(srna, "domain_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "domain");
@@ -3486,16 +3633,16 @@ static void rna_def_modifier_smoke(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "flow");
RNA_def_property_ui_text(prop, "Flow Settings", "");
- prop = RNA_def_property(srna, "coll_settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "coll");
- RNA_def_property_ui_text(prop, "Collision Settings", "");
+ prop = RNA_def_property(srna, "effector_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "effector");
+ RNA_def_property_ui_text(prop, "Effector Settings", "");
- prop = RNA_def_property(srna, "smoke_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "fluid_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_smoke_type_items);
+ RNA_def_property_enum_items(prop, prop_fluid_type_items);
RNA_def_property_ui_text(prop, "Type", "");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, 0, "rna_Smoke_set_type");
+ RNA_def_property_update(prop, 0, "rna_fluid_set_type");
}
static void rna_def_modifier_dynamic_paint(BlenderRNA *brna)
@@ -3922,23 +4069,6 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
-static void rna_def_modifier_fluidsim(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "FluidSimulationModifier", "Modifier");
- RNA_def_struct_ui_text(srna, "Fluid Simulation Modifier", "Fluid simulation modifier");
- RNA_def_struct_sdna(srna, "FluidsimModifierData");
- RNA_def_struct_ui_icon(srna, ICON_MOD_FLUIDSIM);
-
- prop = RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "fss");
- RNA_def_property_ui_text(
- prop, "Settings", "Settings for how this object is used in the fluid simulation");
-}
-
static void rna_def_modifier_mask(BlenderRNA *brna)
{
StructRNA *srna;
@@ -5520,6 +5650,40 @@ static void rna_def_modifier_wireframe(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+static void rna_def_modifier_weld(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "WeldModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Weld Modifier", "Weld modifier");
+ RNA_def_struct_sdna(srna, "WeldModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_AUTOMERGE_OFF);
+
+ prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "merge_dist");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1, 0.001, 6);
+ RNA_def_property_ui_text(prop, "Merge Distance", "Limit below which to merge vertices");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "max_interactions", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "max_interactions");
+ RNA_def_property_ui_text(
+ prop,
+ "Duplicate Limit",
+ "For a better performance, limits the number of elements found per vertex. "
+ "(0 makes it infinite)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
+ RNA_def_property_ui_text(
+ prop, "Vertex Group", "Vertex group name for selecting the affected areas");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeldModifier_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+}
+
static void rna_def_modifier_datatransfer(BlenderRNA *brna)
{
StructRNA *srna;
@@ -6207,13 +6371,12 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_collision(brna);
rna_def_modifier_bevel(brna);
rna_def_modifier_shrinkwrap(brna);
- rna_def_modifier_fluidsim(brna);
rna_def_modifier_mask(brna);
rna_def_modifier_simpledeform(brna);
rna_def_modifier_warp(brna);
rna_def_modifier_multires(brna);
rna_def_modifier_surface(brna);
- rna_def_modifier_smoke(brna);
+ rna_def_modifier_fluid(brna);
rna_def_modifier_solidify(brna);
rna_def_modifier_screw(brna);
rna_def_modifier_uvwarp(brna);
@@ -6229,6 +6392,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_meshcache(brna);
rna_def_modifier_laplaciandeform(brna);
rna_def_modifier_wireframe(brna);
+ rna_def_modifier_weld(brna);
rna_def_modifier_datatransfer(brna);
rna_def_modifier_normaledit(brna);
rna_def_modifier_meshseqcache(brna);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 287c7502c41..68e3e522dff 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -123,21 +123,37 @@ const EnumPropertyItem rna_enum_mapping_type_items[] = {
};
const EnumPropertyItem rna_enum_node_math_items[] = {
+ {0, "", 0, N_("Functions"), ""},
{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},
{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"},
- {0, "", ICON_NONE, NULL, NULL},
+ {NODE_MATH_EXPONENT, "EXPONENT", 0, "Exponent", "exp(A)"},
+ {0, "", 0, N_("Comparison"), ""},
{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"},
{NODE_MATH_GREATER_THAN, "GREATER_THAN", 0, "Greater Than", "1 if A > B else 0"},
- {0, "", ICON_NONE, NULL, NULL},
+ {NODE_MATH_SIGN, "SIGN", 0, "Sign", "Returns the sign of A"},
+ {NODE_MATH_COMPARE, "COMPARE", 0, "Compare", "1 if (A == B) within tolerance C else 0"},
+ {NODE_MATH_SMOOTH_MIN,
+ "SMOOTH_MIN",
+ 0,
+ "Smooth Minimum",
+ "The minimum from A and B with smoothing C"},
+ {NODE_MATH_SMOOTH_MAX,
+ "SMOOTH_MAX",
+ 0,
+ "Smooth Maximum",
+ "The maximum from A and B with smoothing C"},
+ {0, "", 0, N_("Rounding"), ""},
{NODE_MATH_ROUND,
"ROUND",
0,
@@ -145,16 +161,33 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
"Round A to the nearest integer. Round upward if the fraction part is 0.5"},
{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", "trunc(A)"},
+ {0, "", ICON_NONE, NULL, NULL},
{NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"},
{NODE_MATH_MODULO, "MODULO", 0, "Modulo", "A mod B"},
- {0, "", ICON_NONE, NULL, NULL},
+ {NODE_MATH_SNAP, "SNAP", 0, "Snap", "Snap to increment, snap(A,B)"},
+ {NODE_MATH_WRAP, "WRAP", 0, "Wrap", "Wrap value to range, wrap(A,B)"},
+ {NODE_MATH_PINGPONG,
+ "PINGPONG",
+ 0,
+ "Pingpong",
+ "Wraps a value and reverses every other cycle (A,B)"},
+ {0, "", 0, N_("Trigonometric"), ""},
{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},
{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},
+ {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"), ""},
+ {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},
};
@@ -193,6 +226,36 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_node_map_range_items[] = {
+ {NODE_MAP_RANGE_LINEAR,
+ "LINEAR",
+ 0,
+ "Linear",
+ "Linear interpolation between From Min and From Max values"},
+ {NODE_MAP_RANGE_STEPPED,
+ "STEPPED",
+ 0,
+ "Stepped Linear",
+ "Stepped linear interpolation between From Min and From Max values"},
+ {NODE_MAP_RANGE_SMOOTHSTEP,
+ "SMOOTHSTEP",
+ 0,
+ "Smoothstep",
+ "Smooth hermite edge interpolation between From Min and From Max values"},
+ {NODE_MAP_RANGE_SMOOTHERSTEP,
+ "SMOOTHERSTEP",
+ 0,
+ "Smootherstep",
+ "Smoother hermite edge interpolation between From Min and From Max values"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_node_clamp_items[] = {
+ {NODE_CLAMP_MINMAX, "MINMAX", 0, "Min Max", "Clamp values using Min and Max values"},
+ {NODE_CLAMP_RANGE, "RANGE", 0, "Range", "Clamp values between Min and Max range"},
+ {0, NULL, 0, NULL, NULL},
+};
+
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"},
@@ -3888,6 +3951,17 @@ static void def_frame(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL);
}
+static void def_clamp(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "clamp_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_node_clamp_items);
+ RNA_def_property_ui_text(prop, "Clamp Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
+}
+
static void def_map_range(StructRNA *srna)
{
PropertyRNA *prop;
@@ -3896,6 +3970,12 @@ static void def_map_range(StructRNA *srna)
RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
RNA_def_property_ui_text(prop, "Clamp", "Clamp the result to the target range [To Min, To Max]");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "interpolation_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_items(prop, rna_enum_node_map_range_items);
+ RNA_def_property_ui_text(prop, "Interpolation Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_math(StructRNA *srna)
@@ -4426,7 +4506,7 @@ static void def_sh_tex_voronoi(StructRNA *srna)
"SMOOTH_F1",
0,
"Smooth F1",
- "Smoothed version of F1. Weighted sum of neighbour voronoi cells"},
+ "Smoothed version of F1. Weighted sum of neighbor voronoi cells"},
{SHD_VORONOI_DISTANCE_TO_EDGE,
"DISTANCE_TO_EDGE",
0,
@@ -5107,6 +5187,19 @@ static void def_sh_tex_ies(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "bNode", NULL);
}
+static void def_sh_output_aov(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeShaderOutputAOV", "storage");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Name", "Name of the AOV that this output writes to");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "bNode", NULL);
+}
+
static void def_sh_script(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 16d70e21ec2..559b8ca4cc1 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -25,7 +25,7 @@
#include "DNA_object_force_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -738,10 +738,10 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr)
}
/* check smoke modifier */
- md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke);
+ md = (ModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
if (md) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->domain->effector_weights == ew) {
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ if (mmd->domain->effector_weights == ew) {
char name_esc[sizeof(md->name) * 2];
BLI_strescape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].settings.effector_weights", name_esc);
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 211d9e19ab4..f3ca10e332a 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -950,11 +950,16 @@ static float rna_PartSetting_linelenhead_get(struct PointerRNA *ptr)
return settings->draw_line[1];
}
-static bool rna_PartSettings_is_fluid_get(PointerRNA *ptr)
+static int rna_PartSettings_is_fluid_get(PointerRNA *ptr)
{
- ParticleSettings *part = (ParticleSettings *)ptr->data;
-
- return part->type == PART_FLUID;
+ ParticleSettings *part = ptr->data;
+ return (ELEM(part->type,
+ PART_FLUID,
+ PART_FLUID_FLIP,
+ PART_FLUID_FOAM,
+ PART_FLUID_SPRAY,
+ PART_FLUID_BUBBLE,
+ PART_FLUID_TRACER));
}
static void rna_ParticleSettings_use_clump_curve_update(Main *bmain, Scene *scene, PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 8c4b7dd52d9..43d0402d00a 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -1663,7 +1663,9 @@ static void rna_def_pose(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mirror_relative", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", POSE_MIRROR_RELATIVE);
RNA_def_property_ui_text(
- prop, "Relative Mirror", "Apply relative transformations in X-mirror mode");
+ prop,
+ "Relative Mirror",
+ "Apply relative transformations in X-mirror mode (not supported with Auto IK)");
RNA_def_struct_path_func(srna, "rna_Pose_path");
RNA_def_property_update(prop, 0, "rna_Pose_update");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 2b47b1664d7..ea1fb1eb489 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -2867,6 +2867,17 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Lock Object Modes", "Restrict select to the current mode");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ static const EnumPropertyItem workspace_tool_items[] = {
+ {SCE_WORKSPACE_TOOL_DEFAULT, "DEFAULT", 0, "Active Tool", ""},
+ {SCE_WORKSPACE_TOOL_FALLBACK, "FALLBACK", 0, "Select", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ prop = RNA_def_property(srna, "workspace_tool_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "workspace_tool_type");
+ RNA_def_property_enum_items(prop, workspace_tool_items);
+ RNA_def_property_ui_text(prop, "Drag", "Action when dragging in the viewport");
+
/* Transform */
prop = RNA_def_property(srna, "use_proportional_edit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "proportional_edit", PROP_EDIT_USE);
@@ -3411,17 +3422,6 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Secondary Color", "");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update");
- prop = RNA_def_property(srna, "use_pressure_size", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", UNIFIED_PAINT_BRUSH_SIZE_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
- RNA_def_property_ui_text(prop, "Size Pressure", "Enable tablet pressure sensitivity for size");
-
- prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", UNIFIED_PAINT_BRUSH_ALPHA_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
- RNA_def_property_ui_text(
- prop, "Strength Pressure", "Enable tablet pressure sensitivity for strength");
-
prop = RNA_def_property(srna, "use_locked_size", PROP_ENUM, PROP_NONE); /* as an enum */
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, brush_size_unit_items);
@@ -5788,7 +5788,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_overwrite", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "mode", R_NO_OVERWRITE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Overwrite", "Overwrite existing files while rendering");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -6220,33 +6219,35 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_view_fill", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FILL);
- RNA_def_property_ui_text(prop, "Disable Fill", "Disable fill strokes in the viewport");
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FILL);
+ RNA_def_property_ui_text(prop, "Fill", "Display fill strokes in the viewport");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_remove_lines", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_REMOVE_FILL_LINE);
- RNA_def_property_ui_text(prop, "Disable Lines", "Disable external lines of fill strokes");
+ RNA_def_property_boolean_negative_sdna(
+ prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_REMOVE_FILL_LINE);
+ RNA_def_property_ui_text(prop, "Disable Lines", "Display external lines of fill strokes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_view_modifier", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_MODIFIER);
- RNA_def_property_ui_text(prop, "Disable Modifiers", "Do not apply modifiers in the viewport");
+ RNA_def_property_boolean_negative_sdna(
+ prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_MODIFIER);
+ RNA_def_property_ui_text(prop, "Disable Modifiers", "Display modifiers in the viewport");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_shader_fx", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FX);
- RNA_def_property_ui_text(prop, "Simplify Shaders", "Do not apply shader fx");
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FX);
+ RNA_def_property_ui_text(prop, "Simplify Shaders", "Display Shader FX");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_blend", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_BLEND);
- RNA_def_property_ui_text(prop, "Layers Blending", "Do not display blend layers");
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_BLEND);
+ RNA_def_property_ui_text(prop, "Layers Blending", "Display blend layers");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_tint", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_TINT);
- RNA_def_property_ui_text(prop, "Layers Tinting", "Do not display layer tint");
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_TINT);
+ RNA_def_property_ui_text(prop, "Layers Tinting", "Display layer tint");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* persistent data */
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 8a06d594c1f..3562569acec 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -216,7 +216,7 @@ static void rna_Scene_alembic_export(Scene *scene,
bool vcolors,
bool apply_subdiv,
bool flatten_hierarchy,
- bool visible_layers_only,
+ bool visible_objects_only,
bool renderable_only,
bool face_sets,
bool use_subdiv_schema,
@@ -251,7 +251,7 @@ static void rna_Scene_alembic_export(Scene *scene,
.vcolors = vcolors,
.apply_subdiv = apply_subdiv,
.flatten_hierarchy = flatten_hierarchy,
- .visible_layers_only = visible_layers_only,
+ .visible_objects_only = visible_objects_only,
.renderable_only = renderable_only,
.face_sets = face_sets,
.use_subdiv_schema = use_subdiv_schema,
@@ -391,7 +391,7 @@ void RNA_api_scene(StructRNA *srna)
func, "apply_subdiv", 1, "Subsurfs as meshes", "Export subdivision surfaces as meshes");
RNA_def_boolean(func, "flatten", 0, "Flatten hierarchy", "Flatten hierarchy");
RNA_def_boolean(func,
- "visible_layers_only",
+ "visible_objects_only",
0,
"Visible layers only",
"Export only objects in visible layers");
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
deleted file mode 100644
index c00cc789eff..00000000000
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ /dev/null
@@ -1,1218 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup RNA
- */
-
-#include <stdlib.h>
-#include <limits.h>
-
-#include "BLI_sys_types.h"
-
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "rna_internal.h"
-
-#include "BKE_modifier.h"
-#include "BKE_smoke.h"
-#include "BKE_pointcache.h"
-
-#include "DNA_modifier_types.h"
-#include "DNA_object_force_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
-
-#include "WM_types.h"
-
-#ifdef RNA_RUNTIME
-
-# include "BLI_threads.h"
-
-# include "BKE_colorband.h"
-# include "BKE_context.h"
-# include "BKE_particle.h"
-
-# include "DEG_depsgraph.h"
-# include "DEG_depsgraph_build.h"
-
-# include "smoke_API.h"
-
-static void rna_Smoke_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
-}
-
-static void rna_Smoke_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- rna_Smoke_update(bmain, scene, ptr);
- DEG_relations_tag_update(bmain);
-}
-
-static void rna_Smoke_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
- if (settings->smd && settings->smd->domain) {
- settings->point_cache[0]->flag |= PTCACHE_OUTDATED;
- }
- DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
-}
-
-static void rna_Smoke_cachetype_set(struct PointerRNA *ptr, int value)
-{
- SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
- Object *ob = (Object *)ptr->owner_id;
-
- if (value != settings->cache_file_format) {
- /* Clear old caches. */
- PTCacheID id;
- BKE_ptcache_id_from_smoke(&id, ob, settings->smd);
- BKE_ptcache_id_clear(&id, PTCACHE_CLEAR_ALL, 0);
-
- settings->cache_file_format = value;
- }
-}
-
-static void rna_Smoke_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
-
- smokeModifier_reset(settings->smd);
- rna_Smoke_resetCache(bmain, scene, ptr);
-
- rna_Smoke_update(bmain, scene, ptr);
-}
-
-static void rna_Smoke_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
-
- smokeModifier_reset(settings->smd);
-
- if (settings->smd && settings->smd->domain) {
- settings->smd->domain->point_cache[0]->flag |= PTCACHE_OUTDATED;
- }
-
- rna_Smoke_dependency_update(bmain, scene, ptr);
-}
-
-static char *rna_SmokeDomainSettings_path(PointerRNA *ptr)
-{
- SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->smd;
- char name_esc[sizeof(md->name) * 2];
-
- BLI_strescape(name_esc, md->name, sizeof(name_esc));
- return BLI_sprintfN("modifiers[\"%s\"].domain_settings", name_esc);
-}
-
-static char *rna_SmokeFlowSettings_path(PointerRNA *ptr)
-{
- SmokeFlowSettings *settings = (SmokeFlowSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->smd;
- char name_esc[sizeof(md->name) * 2];
-
- BLI_strescape(name_esc, md->name, sizeof(name_esc));
- return BLI_sprintfN("modifiers[\"%s\"].flow_settings", name_esc);
-}
-
-static char *rna_SmokeCollSettings_path(PointerRNA *ptr)
-{
- SmokeCollSettings *settings = (SmokeCollSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->smd;
- char name_esc[sizeof(md->name) * 2];
-
- BLI_strescape(name_esc, md->name, sizeof(name_esc));
- return BLI_sprintfN("modifiers[\"%s\"].coll_settings", name_esc);
-}
-
-static int rna_SmokeModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- float *density = NULL;
- int size = 0;
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- /* high resolution smoke */
- int res[3];
-
- smoke_turbulence_get_res(sds->wt, res);
- size = res[0] * res[1] * res[2];
-
- density = smoke_turbulence_get_density(sds->wt);
- }
- else if (sds->fluid) {
- /* regular resolution */
- size = sds->res[0] * sds->res[1] * sds->res[2];
- density = smoke_get_density(sds->fluid);
- }
-
- length[0] = (density) ? size : 0;
-# else
- (void)ptr;
- length[0] = 0;
-# endif
- return length[0];
-}
-
-static int rna_SmokeModifier_color_grid_get_length(PointerRNA *ptr,
- int length[RNA_MAX_ARRAY_DIMENSION])
-{
- rna_SmokeModifier_grid_get_length(ptr, length);
-
- length[0] *= 4;
- return length[0];
-}
-
-static int rna_SmokeModifier_velocity_grid_get_length(PointerRNA *ptr,
- int length[RNA_MAX_ARRAY_DIMENSION])
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- float *vx = NULL;
- float *vy = NULL;
- float *vz = NULL;
- int size = 0;
-
- /* Velocity data is always low-resolution. */
- if (sds->fluid) {
- size = 3 * sds->res[0] * sds->res[1] * sds->res[2];
- vx = smoke_get_velocity_x(sds->fluid);
- vy = smoke_get_velocity_y(sds->fluid);
- vz = smoke_get_velocity_z(sds->fluid);
- }
-
- length[0] = (vx && vy && vz) ? size : 0;
-# else
- (void)ptr;
- length[0] = 0;
-# endif
- return length[0];
-}
-
-static int rna_SmokeModifier_heat_grid_get_length(PointerRNA *ptr,
- int length[RNA_MAX_ARRAY_DIMENSION])
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- float *heat = NULL;
- int size = 0;
-
- /* Heat data is always low-resolution. */
- if (sds->fluid) {
- size = sds->res[0] * sds->res[1] * sds->res[2];
- heat = smoke_get_heat(sds->fluid);
- }
-
- length[0] = (heat) ? size : 0;
-# else
- (void)ptr;
- length[0] = 0;
-# endif
- return length[0];
-}
-
-static void rna_SmokeModifier_density_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_grid_get_length(ptr, length);
- float *density;
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- density = smoke_turbulence_get_density(sds->wt);
- }
- else {
- density = smoke_get_density(sds->fluid);
- }
-
- memcpy(values, density, size * sizeof(float));
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeModifier_velocity_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_velocity_grid_get_length(ptr, length);
- float *vx, *vy, *vz;
- int i;
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- vx = smoke_get_velocity_x(sds->fluid);
- vy = smoke_get_velocity_y(sds->fluid);
- vz = smoke_get_velocity_z(sds->fluid);
-
- for (i = 0; i < size; i += 3) {
- *(values++) = *(vx++);
- *(values++) = *(vy++);
- *(values++) = *(vz++);
- }
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeModifier_color_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_grid_get_length(ptr, length);
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- if (!sds->fluid) {
- memset(values, 0, size * sizeof(float));
- }
- else {
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- if (smoke_turbulence_has_colors(sds->wt)) {
- smoke_turbulence_get_rgba(sds->wt, values, 0);
- }
- else {
- smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, values, 0);
- }
- }
- else {
- if (smoke_has_colors(sds->fluid)) {
- smoke_get_rgba(sds->fluid, values, 0);
- }
- else {
- smoke_get_rgba_from_density(sds->fluid, sds->active_color, values, 0);
- }
- }
- }
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeModifier_flame_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_grid_get_length(ptr, length);
- float *flame;
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- flame = smoke_turbulence_get_flame(sds->wt);
- }
- else {
- flame = smoke_get_flame(sds->fluid);
- }
-
- if (flame) {
- memcpy(values, flame, size * sizeof(float));
- }
- else {
- memset(values, 0, size * sizeof(float));
- }
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeModifier_heat_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_heat_grid_get_length(ptr, length);
- float *heat;
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- heat = smoke_get_heat(sds->fluid);
-
- if (heat != NULL) {
- /* scale heat values from -2.0-2.0 to -1.0-1.0. */
- for (int i = 0; i < size; i++) {
- values[i] = heat[i] * 0.5f;
- }
- }
- else {
- memset(values, 0, size * sizeof(float));
- }
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeModifier_temperature_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_grid_get_length(ptr, length);
- float *flame;
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- flame = smoke_turbulence_get_flame(sds->wt);
- }
- else {
- flame = smoke_get_flame(sds->fluid);
- }
-
- if (flame) {
- /* Output is such that 0..1 maps to 0..1000K */
- float offset = sds->flame_ignition;
- float scale = sds->flame_max_temp - sds->flame_ignition;
-
- for (int i = 0; i < size; i++) {
- values[i] = (flame[i] > 0.01f) ? offset + flame[i] * scale : 0.0f;
- }
- }
- else {
- memset(values, 0, size * sizeof(float));
- }
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeFlow_density_vgroup_get(PointerRNA *ptr, char *value)
-{
- SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
- rna_object_vgroup_name_index_get(ptr, value, flow->vgroup_density);
-}
-
-static int rna_SmokeFlow_density_vgroup_length(PointerRNA *ptr)
-{
- SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
- return rna_object_vgroup_name_index_length(ptr, flow->vgroup_density);
-}
-
-static void rna_SmokeFlow_density_vgroup_set(PointerRNA *ptr, const char *value)
-{
- SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
- rna_object_vgroup_name_index_set(ptr, value, &flow->vgroup_density);
-}
-
-static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value)
-{
- SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
- rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name));
-}
-
-static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, bool value)
-{
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
-
- sds->use_coba = value;
-
- if (value && sds->coba == NULL) {
- sds->coba = BKE_colorband_add(false);
- }
-}
-
-#else
-
-static void rna_def_smoke_domain_settings(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_noise_type_items[] = {
- {MOD_SMOKE_NOISEWAVE, "NOISEWAVE", 0, "Wavelet", ""},
-# ifdef WITH_FFTW3
- {MOD_SMOKE_NOISEFFT, "NOISEFFT", 0, "FFT", ""},
-# endif
- /* {MOD_SMOKE_NOISECURL, "NOISECURL", 0, "Curl", ""}, */
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem prop_compression_items[] = {
- {VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression"},
-# ifdef WITH_OPENVDB_BLOSC
- {VDB_COMPRESSION_BLOSC,
- "BLOSC",
- 0,
- "Blosc",
- "Multithreaded compression, similar in size and quality as 'Zip'"},
-# endif
- {VDB_COMPRESSION_NONE, "NONE", 0, "None", "Do not use any compression"},
- {0, NULL, 0, NULL, NULL}};
-
- static const EnumPropertyItem smoke_cache_comp_items[] = {
- {SM_CACHE_LIGHT, "CACHELIGHT", 0, "Lite", "Fast but not so effective compression"},
- {SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_highres_sampling_items[] = {
- {SM_HRES_FULLSAMPLE, "FULLSAMPLE", 0, "Full Sample", ""},
- {SM_HRES_LINEAR, "LINEAR", 0, "Linear", ""},
- {SM_HRES_NEAREST, "NEAREST", 0, "Nearest", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_data_depth_items[] = {
- {16, "16", 0, "Float (Half)", "Half float (16 bit data)"},
- {0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_domain_colli_items[] = {
- {SM_BORDER_OPEN, "BORDEROPEN", 0, "Open", "Smoke doesn't collide with any border"},
- {SM_BORDER_VERTICAL,
- "BORDERVERTICAL",
- 0,
- "Vertically Open",
- "Smoke doesn't collide with top and bottom sides"},
- {SM_BORDER_CLOSED, "BORDERCLOSED", 0, "Collide All", "Smoke collides with every side"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem cache_file_type_items[] = {
- {PTCACHE_FILE_PTCACHE,
- "POINTCACHE",
- 0,
- "Point Cache",
- "Blender specific point cache file format"},
-# ifdef WITH_OPENVDB
- {PTCACHE_FILE_OPENVDB, "OPENVDB", 0, "OpenVDB", "OpenVDB file format"},
-# endif
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_view_items[] = {
- {MOD_SMOKE_SLICE_VIEW_ALIGNED,
- "VIEW_ALIGNED",
- 0,
- "View",
- "Slice volume parallel to the view plane"},
- {MOD_SMOKE_SLICE_AXIS_ALIGNED,
- "AXIS_ALIGNED",
- 0,
- "Axis",
- "Slice volume parallel to the major axis"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem axis_slice_method_items[] = {
- {AXIS_SLICE_FULL, "FULL", 0, "Full", "Slice the whole domain object"},
- {AXIS_SLICE_SINGLE, "SINGLE", 0, "Single", "Perform a single slice of the domain object"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem interp_method_item[] = {
- {VOLUME_INTERP_LINEAR, "LINEAR", 0, "Linear", "Good smoothness and speed"},
- {VOLUME_INTERP_CUBIC,
- "CUBIC",
- 0,
- "Cubic",
- "Smoothed high quality interpolation, but slower"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem axis_slice_position_items[] = {
- {SLICE_AXIS_AUTO,
- "AUTO",
- 0,
- "Auto",
- "Adjust slice direction according to the view direction"},
- {SLICE_AXIS_X, "X", 0, "X", "Slice along the X axis"},
- {SLICE_AXIS_Y, "Y", 0, "Y", "Slice along the Y axis"},
- {SLICE_AXIS_Z, "Z", 0, "Z", "Slice along the Z axis"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem vector_draw_items[] = {
- {VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Display vectors as needles"},
- {VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Display vectors as streamlines"},
- {0, NULL, 0, NULL, NULL},
- };
-
- srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL);
- RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings");
- RNA_def_struct_sdna(srna, "SmokeDomainSettings");
- RNA_def_struct_path_func(srna, "rna_SmokeDomainSettings_path");
-
- prop = RNA_def_property(srna, "resolution_max", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "maxres");
- RNA_def_property_range(prop, 6, 512);
- RNA_def_property_ui_range(prop, 24, 512, 2, -1);
- RNA_def_property_ui_text(prop, "Max Res", "Maximal resolution used in the fluid domain");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "amplify", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "amplify");
- RNA_def_property_range(prop, 1, 10);
- RNA_def_property_ui_range(prop, 1, 10, 1, -1);
- RNA_def_property_ui_text(
- prop, "Amplification", "Enhance the resolution of smoke by this factor using noise");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "use_high_resolution", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGHRES);
- RNA_def_property_ui_text(prop, "High Res", "Enable high resolution (using amplification)");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "show_high_resolution", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "viewsettings", MOD_SMOKE_VIEW_SHOW_HIGHRES);
- RNA_def_property_ui_text(
- prop, "Show High Resolution", "Show high resolution (using amplification)");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "noise_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "noise");
- RNA_def_property_enum_items(prop, prop_noise_type_items);
- RNA_def_property_ui_text(
- prop, "Noise Method", "Noise method which is used for creating the high resolution");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "alpha");
- RNA_def_property_range(prop, -5.0, 5.0);
- RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
- RNA_def_property_ui_text(
- prop,
- "Density",
- "How much density affects smoke motion (higher value results in faster rising smoke)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "beta");
- RNA_def_property_range(prop, -5.0, 5.0);
- RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
- RNA_def_property_ui_text(
- prop,
- "Heat",
- "How much heat affects smoke motion (higher value results in faster rising smoke)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "collision_collection", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "coll_group");
- RNA_def_property_struct_type(prop, "Collection");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Collision Collection", "Limit collisions to this collection");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency");
-
- prop = RNA_def_property(srna, "fluid_collection", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "fluid_group");
- RNA_def_property_struct_type(prop, "Collection");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Fluid Collection", "Limit fluid objects to this collection");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency");
-
- prop = RNA_def_property(srna, "effector_collection", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "eff_group");
- RNA_def_property_struct_type(prop, "Collection");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Effector Collection", "Limit effectors to this collection");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency");
-
- prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "strength");
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 2);
- RNA_def_property_ui_text(prop, "Strength", "Strength of noise");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "dissolve_speed", PROP_INT, PROP_TIME);
- RNA_def_property_int_sdna(prop, NULL, "diss_speed");
- RNA_def_property_range(prop, 1.0, 10000.0);
- RNA_def_property_ui_range(prop, 1.0, 10000.0, 1, -1);
- RNA_def_property_ui_text(prop, "Dissolve Speed", "Dissolve Speed");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "use_dissolve_smoke", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE);
- RNA_def_property_ui_text(prop, "Dissolve Smoke", "Enable smoke to disappear over time");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE_LOG);
- RNA_def_property_ui_text(prop, "Logarithmic Dissolve", "Using 1/x ");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "point_cache[0]");
- RNA_def_property_struct_type(prop, "PointCache");
- RNA_def_property_ui_text(prop, "Point Cache", "");
-
- prop = RNA_def_property(srna, "point_cache_compress_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "cache_comp");
- RNA_def_property_enum_items(prop, smoke_cache_comp_items);
- RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used");
-
- prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp");
- RNA_def_property_enum_items(prop, prop_compression_items);
- RNA_def_property_ui_text(prop, "Compression", "Compression method to be used");
-
- prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth");
- RNA_def_property_enum_items(prop, smoke_data_depth_items);
- RNA_def_property_ui_text(prop,
- "Data Depth",
- "Bit depth for writing all scalar (including vector) "
- "lower values reduce file size");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
-
- prop = RNA_def_property(srna, "collision_extents", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "border_collisions");
- RNA_def_property_enum_items(prop, smoke_domain_colli_items);
- RNA_def_property_ui_text(
- prop, "Border Collisions", "Select which domain border will be treated as collision object");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "EffectorWeights");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Effector Weights", "");
-
- prop = RNA_def_property(srna, "highres_sampling", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, smoke_highres_sampling_items);
- RNA_def_property_ui_text(prop, "Emitter", "Method for sampling the high resolution flow");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "time_scale");
- RNA_def_property_range(prop, 0.2, 1.5);
- RNA_def_property_ui_range(prop, 0.2, 1.5, 0.02, 5);
- RNA_def_property_ui_text(prop, "Time Scale", "Adjust simulation speed");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "vorticity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vorticity");
- RNA_def_property_range(prop, 0.01, 4.0);
- RNA_def_property_ui_range(prop, 0.01, 4.0, 0.02, 5);
- RNA_def_property_ui_text(prop, "Vorticity", "Amount of turbulence/rotation in fluid");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "density_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_density_grid_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Density Grid", "Smoke density grid");
-
- prop = RNA_def_property(srna, "velocity_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_velocity_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_velocity_grid_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Velocity Grid", "Smoke velocity grid");
-
- prop = RNA_def_property(srna, "flame_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_flame_grid_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Flame Grid", "Smoke flame grid");
-
- prop = RNA_def_property(srna, "color_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_color_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_color_grid_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Color Grid", "Smoke color grid");
-
- prop = RNA_def_property(srna, "heat_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_heat_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_heat_grid_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Heat Grid", "Smoke heat grid");
-
- prop = RNA_def_property(srna, "temperature_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_temperature_grid_get", NULL, NULL);
- RNA_def_property_ui_text(
- prop, "Temperature Grid", "Smoke temperature grid, range 0..1 represents 0..1000K");
-
- prop = RNA_def_property(srna,
- "cell_size",
- PROP_FLOAT,
- PROP_XYZ); /* can change each frame when using adaptive domain */
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "cell_size", "Cell Size");
-
- prop = RNA_def_property(srna,
- "start_point",
- PROP_FLOAT,
- PROP_XYZ); /* can change each frame when using adaptive domain */
- RNA_def_property_float_sdna(prop, NULL, "p0");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "p0", "Start point");
-
- prop = RNA_def_property(srna,
- "domain_resolution",
- PROP_INT,
- PROP_XYZ); /* can change each frame when using adaptive domain */
- RNA_def_property_int_sdna(prop, NULL, "res");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "res", "Smoke Grid Resolution");
-
- prop = RNA_def_property(srna, "burning_rate", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.01, 4.0);
- RNA_def_property_ui_range(prop, 0.01, 2.0, 1.0, 5);
- RNA_def_property_ui_text(
- prop, "Speed", "Speed of the burning reaction (use larger values for smaller flame)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "flame_smoke", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 8.0);
- RNA_def_property_ui_range(prop, 0.0, 4.0, 1.0, 5);
- RNA_def_property_ui_text(prop, "Smoke", "Amount of smoke created by burning fuel");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "flame_vorticity", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_range(prop, 0.0, 2.0);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 5);
- RNA_def_property_ui_text(prop, "Vorticity", "Additional vorticity for the flames");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "flame_ignition", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.5, 5.0);
- RNA_def_property_ui_range(prop, 0.5, 2.5, 1.0, 5);
- RNA_def_property_ui_text(prop, "Ignition", "Minimum temperature of flames");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "flame_max_temp", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 1.0, 10.0);
- RNA_def_property_ui_range(prop, 1.0, 5.0, 1.0, 5);
- RNA_def_property_ui_text(prop, "Maximum", "Maximum temperature of flames");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "flame_smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke emitted from burning fuel");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "use_adaptive_domain", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_ADAPTIVE_DOMAIN);
- RNA_def_property_ui_text(
- prop, "Adaptive Domain", "Adapt simulation resolution and size to fluid");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "additional_res", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "adapt_res");
- RNA_def_property_range(prop, 0, 512);
- RNA_def_property_ui_range(prop, 0, 512, 2, -1);
- RNA_def_property_ui_text(prop, "Additional", "Maximum number of additional cells");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "adapt_margin", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "adapt_margin");
- RNA_def_property_range(prop, 2, 24);
- RNA_def_property_ui_range(prop, 2, 24, 2, -1);
- RNA_def_property_ui_text(
- prop, "Margin", "Margin added around fluid to minimize boundary interference");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "adapt_threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.01, 0.5);
- RNA_def_property_ui_range(prop, 0.01, 0.5, 1.0, 5);
- RNA_def_property_ui_text(
- prop, "Threshold", "Maximum amount of fluid cell can contain before it is considered empty");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "cache_file_format", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "cache_file_format");
- RNA_def_property_enum_items(prop, cache_file_type_items);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Smoke_cachetype_set", NULL);
- RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- /* display settings */
-
- prop = RNA_def_property(srna, "slice_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "slice_method");
- RNA_def_property_enum_items(prop, smoke_view_items);
- RNA_def_property_ui_text(prop, "View Method", "How to slice the volume for viewport rendering");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "axis_slice_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "axis_slice_method");
- RNA_def_property_enum_items(prop, axis_slice_method_items);
- RNA_def_property_ui_text(prop, "Method", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "slice_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "slice_axis");
- RNA_def_property_enum_items(prop, axis_slice_position_items);
- RNA_def_property_ui_text(prop, "Axis", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "slice_per_voxel", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "slice_per_voxel");
- RNA_def_property_range(prop, 0.0, 100.0);
- RNA_def_property_ui_range(prop, 0.0, 5.0, 0.1, 1);
- RNA_def_property_ui_text(
- prop, "Slice Per Voxel", "How many slices per voxel should be generated");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "slice_depth", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "slice_depth");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
- RNA_def_property_ui_text(prop, "Position", "Position of the slice");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "display_thickness", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "display_thickness");
- RNA_def_property_range(prop, 0.001, 1000.0);
- RNA_def_property_ui_range(prop, 0.1, 100.0, 0.1, 3);
- RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
-
- prop = RNA_def_property(srna, "display_interpolation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "interp_method");
- RNA_def_property_enum_items(prop, interp_method_item);
- RNA_def_property_ui_text(
- prop, "Interpolation", "Interpolation method to use for smoke/fire volumes in solid mode");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "show_velocity", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "draw_velocity", 0);
- RNA_def_property_ui_text(
- prop, "Display Velocity", "Toggle visualization of the velocity field as needles");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "vector_display_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "vector_draw_type");
- RNA_def_property_enum_items(prop, vector_draw_items);
- RNA_def_property_ui_text(prop, "Display Type", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "vector_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vector_scale");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
- RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- /* --------- Color mapping. --------- */
-
- prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Smoke_use_color_ramp_set");
- RNA_def_property_ui_text(
- prop,
- "Use Color Ramp",
- "Render a simulation field while mapping its voxels values to the colors of a ramp");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- static const EnumPropertyItem coba_field_items[] = {
- {FLUID_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"},
- {FLUID_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"},
- {FLUID_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"},
- {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"},
- {FLUID_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"},
- {FLUID_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"},
- {FLUID_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"},
- {FLUID_FIELD_VELOCITY_X, "VELOCITY_X", 0, "X Velocity", "X component of the velocity field"},
- {FLUID_FIELD_VELOCITY_Y, "VELOCITY_Y", 0, "Y Velocity", "Y component of the velocity field"},
- {FLUID_FIELD_VELOCITY_Z, "VELOCITY_Z", 0, "Z Velocity", "Z component of the velocity field"},
- {0, NULL, 0, NULL, NULL},
- };
-
- prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "coba_field");
- RNA_def_property_enum_items(prop, coba_field_items);
- RNA_def_property_ui_text(prop, "Field", "Simulation field to color map");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "coba");
- RNA_def_property_struct_type(prop, "ColorRamp");
- RNA_def_property_ui_text(prop, "Color Ramp", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "clipping", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "clipping");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
- RNA_def_property_ui_text(
- prop,
- "Clipping",
- "Value under which voxels are considered empty space to optimize caching and rendering");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
-}
-
-static void rna_def_smoke_flow_settings(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem smoke_flow_types[] = {
- {MOD_SMOKE_FLOW_TYPE_OUTFLOW, "OUTFLOW", 0, "Outflow", "Delete smoke from simulation"},
- {MOD_SMOKE_FLOW_TYPE_SMOKE, "SMOKE", 0, "Smoke", "Add smoke"},
- {MOD_SMOKE_FLOW_TYPE_SMOKEFIRE, "BOTH", 0, "Fire + Smoke", "Add fire and smoke"},
- {MOD_SMOKE_FLOW_TYPE_FIRE, "FIRE", 0, "Fire", "Add fire"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_flow_sources[] = {
- {MOD_SMOKE_FLOW_SOURCE_PARTICLES,
- "PARTICLES",
- ICON_PARTICLES,
- "Particle System",
- "Emit smoke from particles"},
- {MOD_SMOKE_FLOW_SOURCE_MESH,
- "MESH",
- ICON_META_CUBE,
- "Mesh",
- "Emit smoke from mesh surface or volume"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_flow_texture_types[] = {
- {MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO,
- "AUTO",
- 0,
- "Generated",
- "Generated coordinates centered to flow object"},
- {MOD_SMOKE_FLOW_TEXTURE_MAP_UV, "UV", 0, "UV", "Use UV layer for texture coordinates"},
- {0, NULL, 0, NULL, NULL},
- };
-
- srna = RNA_def_struct(brna, "SmokeFlowSettings", NULL);
- RNA_def_struct_ui_text(srna, "Flow Settings", "Smoke flow settings");
- RNA_def_struct_sdna(srna, "SmokeFlowSettings");
- RNA_def_struct_path_func(srna, "rna_SmokeFlowSettings_path");
-
- prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "density");
- RNA_def_property_range(prop, 0.0, 1);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 4);
- RNA_def_property_ui_text(prop, "Density", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "color");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "fuel_amount", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 10);
- RNA_def_property_ui_range(prop, 0.0, 5.0, 1.0, 4);
- RNA_def_property_ui_text(prop, "Flame Rate", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "temp");
- RNA_def_property_range(prop, -10, 10);
- RNA_def_property_ui_range(prop, -10, 10, 1, 1);
- RNA_def_property_ui_text(prop, "Temp. Diff.", "Temperature difference to ambient temperature");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "psys");
- RNA_def_property_struct_type(prop, "ParticleSystem");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Particle Systems", "Particle systems emitted from the object");
- RNA_def_property_update(prop, 0, "rna_Smoke_reset_dependency");
-
- prop = RNA_def_property(srna, "smoke_flow_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, smoke_flow_types);
- RNA_def_property_ui_text(prop, "Flow Type", "Change how flow affects the simulation");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "smoke_flow_source", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "source");
- RNA_def_property_enum_items(prop, smoke_flow_sources);
- RNA_def_property_ui_text(prop, "Source", "Change how smoke is emitted");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "use_absolute", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_ABSOLUTE);
- RNA_def_property_ui_text(
- prop, "Absolute Density", "Only allow given density value in emitter area");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "use_initial_velocity", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_INITVELOCITY);
- RNA_def_property_ui_text(
- prop, "Initial Velocity", "Smoke has some initial velocity when it is emitted");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vel_multi");
- RNA_def_property_range(prop, -100.0, 100.0);
- RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Source", "Multiplier of source velocity passed to smoke");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vel_normal");
- RNA_def_property_range(prop, -100.0, 100.0);
- RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Normal", "Amount of normal directional velocity");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vel_random");
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Random", "Amount of random velocity");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "volume_density", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Volume", "Factor for smoke emitted from inside the mesh volume");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Surface", "Maximum distance from mesh surface to emit smoke");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "particle_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.1, 20.0);
- RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Size", "Particle size in simulation cells");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "use_particle_size", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_USE_PART_SIZE);
- RNA_def_property_ui_text(
- prop, "Set Size", "Set particle size in simulation cells or use nearest cell");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "subframes", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 0, 50);
- RNA_def_property_ui_range(prop, 0, 10, 1, -1);
- RNA_def_property_ui_text(prop,
- "Subframes",
- "Number of additional samples to take between frames to improve "
- "quality of fast moving flows");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "density_vertex_group", PROP_STRING, PROP_NONE);
- RNA_def_property_string_funcs(prop,
- "rna_SmokeFlow_density_vgroup_get",
- "rna_SmokeFlow_density_vgroup_length",
- "rna_SmokeFlow_density_vgroup_set");
- RNA_def_property_ui_text(
- prop, "Vertex Group", "Name of vertex group which determines surface emission rate");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_TEXTUREEMIT);
- RNA_def_property_ui_text(prop, "Use Texture", "Use a texture to control emission strength");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "texture_map_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "texture_type");
- RNA_def_property_enum_items(prop, smoke_flow_texture_types);
- RNA_def_property_ui_text(prop, "Mapping", "Texture mapping type");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
- RNA_def_property_ui_text(prop, "UV Map", "UV map name");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SmokeFlow_uvlayer_set");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "noise_texture", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Texture", "Texture that controls emission strength");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "texture_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.01, 10.0);
- RNA_def_property_ui_range(prop, 0.1, 5.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Size", "Size of texture mapping");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 200.0);
- RNA_def_property_ui_range(prop, 0.0, 100.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Offset", "Z-offset of texture mapping");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-}
-
-static void rna_def_smoke_coll_settings(BlenderRNA *brna)
-{
- static const EnumPropertyItem smoke_coll_type_items[] = {
- {SM_COLL_STATIC, "COLLSTATIC", 0, "Static", "Non moving obstacle"},
- {SM_COLL_RIGID, "COLLRIGID", 0, "Rigid", "Rigid obstacle"},
- {SM_COLL_ANIMATED, "COLLANIMATED", 0, "Animated", "Animated obstacle"},
- {0, NULL, 0, NULL, NULL},
- };
-
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "SmokeCollSettings", NULL);
- RNA_def_struct_ui_text(srna, "Collision Settings", "Smoke collision settings");
- RNA_def_struct_sdna(srna, "SmokeCollSettings");
- RNA_def_struct_path_func(srna, "rna_SmokeCollSettings_path");
-
- prop = RNA_def_property(srna, "collision_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, smoke_coll_type_items);
- RNA_def_property_ui_text(prop, "Collision Type", "Collision type");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-}
-
-void RNA_def_smoke(BlenderRNA *brna)
-{
- rna_def_smoke_domain_settings(brna);
- rna_def_smoke_flow_settings(brna);
- rna_def_smoke_coll_settings(brna);
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index f9fa6e78163..67b43cb13df 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -374,6 +374,18 @@ static const EnumPropertyItem rna_enum_studio_light_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] = {
+ {SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
+ /* {SCE_PASS_Z, "Z", 0, "Z", ""},*/
+ {SCE_PASS_AO, "AO", 0, "Ambient Occlusion", ""},
+ {SCE_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
+ {SCE_PASS_MIST, "MIST", 0, "Mist", ""},
+ {SCE_PASS_SUBSURFACE_DIRECT, "SUBSURFACE_DIRECT", 0, "Subsurface Direct", ""},
+ /* {SCE_PASS_SUBSURFACE_INDIRECT, "SUBSURFACE_INDIRECT", 0, "Subsurface Indirect", ""}, */
+ {SCE_PASS_SUBSURFACE_COLOR, "SUBSURFACE_COLOR", 0, "Subsurface Color", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_clip_editor_mode_items[] = {
{SC_MODE_TRACKING, "TRACKING", ICON_ANIM_DATA, "Tracking", "Show tracking and solving tools"},
{SC_MODE_MASKEDIT, "MASK", ICON_MOD_MASK, "Mask", "Show mask editing tools"},
@@ -1392,7 +1404,7 @@ static const EnumPropertyItem *rna_SpaceImageEditor_display_channels_itemf(
void *lock;
int zbuf, alpha, totitem = 0;
- ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
alpha = ibuf && (ibuf->channels == 4);
zbuf = ibuf && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1));
@@ -1500,7 +1512,8 @@ static void rna_SpaceImageEditor_scopes_update(struct bContext *C, struct Pointe
ImBuf *ibuf;
void *lock;
- ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ /* TODO(lukas): Support tiles in scopes? */
+ ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
if (ibuf) {
ED_space_image_scopes_update(C, sima, ibuf, true);
WM_main_add_notifier(NC_IMAGE, sima->image);
@@ -2300,6 +2313,18 @@ static int rna_FileBrowser_FSMenuEntry_name_get_editable(PointerRNA *ptr,
return fsm->save ? PROP_EDITABLE : 0;
}
+static int rna_FileBrowser_FSMenuEntry_icon_get(PointerRNA *ptr)
+{
+ FSMenuEntry *fsm = ptr->data;
+ return ED_fsmenu_entry_get_icon(fsm);
+}
+
+static void rna_FileBrowser_FSMenuEntry_icon_set(PointerRNA *ptr, int value)
+{
+ FSMenuEntry *fsm = ptr->data;
+ ED_fsmenu_entry_set_icon(fsm, value);
+}
+
static bool rna_FileBrowser_FSMenuEntry_use_save_get(PointerRNA *ptr)
{
FSMenuEntry *fsm = ptr->data;
@@ -2779,6 +2804,15 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Display Faces", "Display faces over the image");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ prop = RNA_def_property(srna, "tile_grid_shape", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "tile_grid_shape");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_int_default(prop, 1);
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_text(
+ prop, "Tile Grid Shape", "How many tiles will be shown in the background");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
/* todo: move edge and face drawing options here from G.f */
prop = RNA_def_property(srna, "pixel_snap_mode", PROP_ENUM, PROP_NONE);
@@ -3280,6 +3314,12 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "render_pass", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "render_pass");
+ RNA_def_property_enum_items(prop, rna_enum_view3dshading_render_pass_type_items);
+ RNA_def_property_ui_text(prop, "Render Pass", "Render Pass to show in the viewport");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
static void rna_def_space_view3d_overlay(BlenderRNA *brna)
@@ -3435,7 +3475,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_look_dev", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_LOOK_DEV);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Look Dev Preview", "Show look development spheres");
+ RNA_def_property_ui_text(prop, "HDRI Preview", "Show HDRI preview spheres");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_wireframes", PROP_BOOLEAN, PROP_NONE);
@@ -3446,8 +3486,10 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "wireframe_threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.wireframe_threshold");
- RNA_def_property_ui_text(
- prop, "Wireframe Threshold", "Adjust the number of wires displayed (1 for all wires)");
+ RNA_def_property_ui_text(prop,
+ "Wireframe Threshold",
+ "Adjust the angle threshold for displaying edges "
+ "(1.0 for all)");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3620,7 +3662,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "vertex_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.vertex_paint_mode_opacity");
RNA_def_property_ui_text(
- prop, "Vertex Paint Opacity", "Opacity of the vertex paint mode overlay");
+ prop, "Stencil Opacity", "Opacity of the texture paint mode stencil mask overlay");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -4542,9 +4584,12 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
- prop = RNA_def_property(srna, "show_marker_lines", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_MARKER_LINES);
- RNA_def_property_ui_text(prop, "Show Marker Lines", "Show a vertical line for every marker");
+ prop = RNA_def_property(srna, "show_markers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_MARKERS);
+ RNA_def_property_ui_text(
+ prop,
+ "Show Markers",
+ "If any exists, show markers in a separate row at the bottom of the editor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
@@ -4699,7 +4744,7 @@ static void rna_def_space_text(BlenderRNA *brna)
prop = RNA_def_property(srna, "visible_lines", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_int_sdna(prop, NULL, "viewlines");
+ RNA_def_property_int_sdna(prop, NULL, "runtime.viewlines");
RNA_def_property_ui_text(
prop, "Visible Lines", "Amount of lines that can be visible in current editor");
@@ -4829,10 +4874,13 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
"comparison with adjacent keys");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
- prop = RNA_def_property(srna, "show_marker_lines", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_SHOW_MARKER_LINES);
- RNA_def_property_ui_text(prop, "Show Marker Lines", "Show a vertical line for every marker");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+ prop = RNA_def_property(srna, "show_markers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_SHOW_MARKERS);
+ RNA_def_property_ui_text(
+ prop,
+ "Show Markers",
+ "If any exists, show markers in a separate row at the bottom of the editor");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
/* editing */
prop = RNA_def_property(srna, "use_auto_merge_keyframes", PROP_BOOLEAN, PROP_NONE);
@@ -4930,7 +4978,7 @@ static void rna_def_space_graph(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SpaceGraph");
RNA_def_struct_ui_text(srna, "Space Graph Editor", "Graph Editor space data");
- rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_UI));
+ rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_HUD));
/* mode */
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
@@ -4986,9 +5034,12 @@ static void rna_def_space_graph(BlenderRNA *brna)
"Display groups and channels with colors matching their corresponding groups");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
- prop = RNA_def_property(srna, "show_marker_lines", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_MARKER_LINES);
- RNA_def_property_ui_text(prop, "Show Marker Lines", "Show a vertical line for every marker");
+ prop = RNA_def_property(srna, "show_markers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_SHOW_MARKERS);
+ RNA_def_property_ui_text(
+ prop,
+ "Show Markers",
+ "If any exists, show markers in a separate row at the bottom of the editor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
/* editing */
@@ -5097,10 +5148,13 @@ static void rna_def_space_nla(BlenderRNA *brna)
"Show action-local markers on the strips, useful when synchronizing timing across strips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
- prop = RNA_def_property(srna, "show_marker_lines", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SNLA_SHOW_MARKER_LINES);
- RNA_def_property_ui_text(prop, "Show Marker Lines", "Show a vertical line for every marker");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+ prop = RNA_def_property(srna, "show_markers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SNLA_SHOW_MARKERS);
+ RNA_def_property_ui_text(
+ prop,
+ "Show Markers",
+ "If any exists, show markers in a separate row at the bottom of the editor");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
/* editing */
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
@@ -5543,6 +5597,11 @@ static void rna_def_filemenu_entry(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_struct_name_property(srna, prop);
+ prop = RNA_def_property(srna, "icon", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(
+ prop, "rna_FileBrowser_FSMenuEntry_icon_get", "rna_FileBrowser_FSMenuEntry_icon_set", NULL);
+ RNA_def_property_ui_text(prop, "Icon", "");
+
prop = RNA_def_property(srna, "use_save", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_FileBrowser_FSMenuEntry_use_save_get", NULL);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 5d2bf161020..56f19d313fd 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -69,7 +69,7 @@ static const EnumPropertyItem opensubdiv_compute_type_items[] = {
};
#endif
-static const EnumPropertyItem preference_section_items[] = {
+const EnumPropertyItem rna_enum_preference_section_items[] = {
{USER_SECTION_INTERFACE, "INTERFACE", 0, "Interface", ""},
{USER_SECTION_THEME, "THEMES", 0, "Themes", ""},
{USER_SECTION_VIEWPORT, "VIEWPORT", 0, "Viewport", ""},
@@ -92,6 +92,8 @@ static const EnumPropertyItem preference_section_items[] = {
{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},
+ {USER_SECTION_EXPERIMENTAL, "EXPERIMENTAL", 0, "Experimental", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -468,26 +470,22 @@ static const EnumPropertyItem *rna_UseDef_active_section_itemf(bContext *UNUSED(
{
UserDef *userdef = ptr->data;
- if ((userdef->flag & USER_DEVELOPER_UI) == 0) {
+ if ((userdef->flag & USER_DEVELOPER_UI) != 0) {
*r_free = false;
- return preference_section_items;
+ return rna_enum_preference_section_items;
}
EnumPropertyItem *items = NULL;
int totitem = 0;
- RNA_enum_items_add(&items, &totitem, preference_section_items);
- RNA_enum_item_add_separator(&items, &totitem);
-
- EnumPropertyItem item = {
- .value = USER_SECTION_EXPERIMENTAL,
- .name = "Experimental",
- .identifier = "EXPERIMENTAL",
- .icon = 0,
- .description = "",
- };
+ for (const EnumPropertyItem *it = rna_enum_preference_section_items; it->identifier != NULL;
+ it++) {
+ if (it->value == USER_SECTION_EXPERIMENTAL) {
+ continue;
+ }
+ RNA_enum_item_add(&items, &totitem, it);
+ }
- RNA_enum_item_add(&items, &totitem, &item);
RNA_enum_item_end(&items, &totitem);
*r_free = true;
@@ -575,6 +573,13 @@ static void rna_userdef_autosave_update(Main *bmain, Scene *scene, PointerRNA *p
rna_userdef_update(bmain, scene, ptr);
}
+# define RNA_USERDEF_EXPERIMENTAL_BOOLEAN_GET(member) \
+ static bool rna_userdef_experimental_##member##_get(PointerRNA *ptr) \
+ { \
+ UserDef *userdef = POINTER_OFFSET(ptr->data, -offsetof(UserDef, experimental)); \
+ return USER_EXPERIMENTAL_TEST(userdef, member); \
+ }
+
static bAddon *rna_userdef_addon_new(void)
{
ListBase *addons_list = &U.addons;
@@ -1891,6 +1896,16 @@ static void rna_def_userdef_theme_spaces_face(StructRNA *srna)
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Freestyle Face Mark", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ prop = RNA_def_property(srna, "face_back", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Face Orientation Back", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ prop = RNA_def_property(srna, "face_front", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Face Orientation Front", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
}
static void rna_def_userdef_theme_spaces_paint_curves(StructRNA *srna)
@@ -4265,12 +4280,14 @@ static void rna_def_userdef_view(BlenderRNA *brna)
"Show the frames per second screen refresh rate, while animation is played back");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ USERDEF_TAG_DIRTY_PROPERTY_UPDATE_DISABLE;
prop = RNA_def_property(srna, "show_addons_enabled_only", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, NULL, "space_data.flag", USER_SPACEDATA_ADDONS_SHOW_ONLY_ENABLED);
RNA_def_property_ui_text(prop,
"Enabled Add-ons Only",
"Only show enabled add-ons. Un-check to see all installed add-ons");
+ USERDEF_TAG_DIRTY_PROPERTY_UPDATE_ENABLE;
static const EnumPropertyItem factor_display_items[] = {
{USER_FACTOR_AS_FACTOR, "FACTOR", 0, "Factor", "Display factors as values between 0 and 1"},
@@ -4491,8 +4508,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "lookdev_sphere_size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "lookdev_sphere_size");
RNA_def_property_range(prop, 50, 400);
- RNA_def_property_ui_text(
- prop, "Look Dev Spheres Size", "Maximum diameter of the look development sphere size");
+ RNA_def_property_ui_text(prop, "HDRI Preview Size", "Diameter of the HDRI preview spheres");
RNA_def_property_update(prop, 0, "rna_userdef_update");
/* View2D Grid Displays */
@@ -5062,12 +5078,11 @@ static void rna_def_userdef_system(BlenderRNA *brna)
/* OpenGL */
- /* Full scene anti-aliasing */
- prop = RNA_def_property(srna, "multi_sample", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "ogl_multisamples");
- RNA_def_property_enum_items(prop, multi_sample_levels);
+ /* Viewport anti-aliasing */
+ prop = RNA_def_property(srna, "use_overlay_smooth_wire", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpu_flag", USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE);
RNA_def_property_ui_text(
- prop, "MultiSample", "Enable OpenGL multi-sampling, only for systems that support it");
+ prop, "Overlay Smooth Wires", "Enable overlay smooth wires, reducing aliasing");
RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
prop = RNA_def_property(srna, "use_edit_mode_smooth_wire", PROP_BOOLEAN, PROP_NONE);
@@ -5832,20 +5847,12 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
static void rna_def_userdef_experimental(BlenderRNA *brna)
{
StructRNA *srna;
- PropertyRNA *prop;
srna = RNA_def_struct(brna, "PreferencesExperimental", NULL);
RNA_def_struct_sdna(srna, "UserDef_Experimental");
RNA_def_struct_nested(brna, srna, "Preferences");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
RNA_def_struct_ui_text(srna, "Experimental", "Experimental features");
-
- prop = RNA_def_property(srna, "use_experimental_all", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_EXPERIMENTAL_ALL);
- RNA_def_property_ui_text(prop,
- "All Experimental Features",
- "Expose all the experimental features in the user interface");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
@@ -5918,7 +5925,7 @@ void RNA_def_userdef(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_section", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "space_data.section_active");
- RNA_def_property_enum_items(prop, preference_section_items);
+ RNA_def_property_enum_items(prop, rna_enum_preference_section_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_UseDef_active_section_itemf");
RNA_def_property_ui_text(
prop, "Active Section", "Active section of the preferences shown in the user interface");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 22129d7e481..98703a35314 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -242,6 +242,7 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{RIGHTSHIFTKEY, "RIGHT_SHIFT", 0, "Right Shift", "ShiftR"},
{0, "", 0, NULL, NULL},
{OSKEY, "OSKEY", 0, "OS Key", "Cmd"},
+ {APPKEY, "APP", 0, "Application", "App"},
{GRLESSKEY, "GRLESS", 0, "Grless", ""},
{ESCKEY, "ESC", 0, "Esc", ""},
{TABKEY, "TAB", 0, "Tab", ""},
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
index 47138653af1..4d4ab64abb9 100644
--- a/source/blender/makesrna/intern/rna_workspace.c
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -258,6 +258,10 @@ static void rna_def_workspace_tool(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Identifier", "");
RNA_def_struct_name_property(srna, prop);
+ prop = RNA_def_property(srna, "idname_fallback", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Identifier Fallback", "");
+ RNA_def_struct_name_property(srna, prop);
+
prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Index", "");
@@ -288,7 +292,6 @@ static void rna_def_workspace_tool(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Widget", "");
RNA_def_property_string_funcs(
prop, "rna_WorkSpaceTool_widget_get", "rna_WorkSpaceTool_widget_length", NULL);
- RNA_define_verify_sdna(1);
RNA_api_workspace_tool(srna);
}
diff --git a/source/blender/makesrna/intern/rna_workspace_api.c b/source/blender/makesrna/intern/rna_workspace_api.c
index 2d3b1e76b71..4fb6677199f 100644
--- a/source/blender/makesrna/intern/rna_workspace_api.c
+++ b/source/blender/makesrna/intern/rna_workspace_api.c
@@ -43,14 +43,16 @@
static void rna_WorkSpaceTool_setup(ID *id,
bToolRef *tref,
bContext *C,
- const char *tool_idname,
+ const char *idname,
/* Args for: 'bToolRef_Runtime'. */
int cursor,
const char *keymap,
const char *gizmo_group,
const char *data_block,
const char *op_idname,
- int index)
+ int index,
+ const char *idname_fallback,
+ const char *keymap_fallback)
{
bToolRef_Runtime tref_rt = {0};
@@ -61,7 +63,12 @@ static void rna_WorkSpaceTool_setup(ID *id,
STRNCPY(tref_rt.op, op_idname);
tref_rt.index = index;
- WM_toolsystem_ref_set_from_runtime(C, (WorkSpace *)id, tref, &tref_rt, tool_idname);
+ /* While it's logical to assign both these values from setup,
+ * it's useful to stored this in DNA for re-use, exceptional case: write to the 'tref'. */
+ STRNCPY(tref->idname_fallback, idname_fallback);
+ STRNCPY(tref_rt.keymap_fallback, keymap_fallback);
+
+ WM_toolsystem_ref_set_from_runtime(C, (WorkSpace *)id, tref, &tref_rt, idname);
}
static void rna_WorkSpaceTool_refresh_from_context(ID *id, bToolRef *tref, Main *bmain)
@@ -140,6 +147,9 @@ void RNA_api_workspace_tool(StructRNA *srna)
RNA_def_string(func, "operator", NULL, MAX_NAME, "Operator", "");
RNA_def_int(func, "index", 0, INT_MIN, INT_MAX, "Index", "", INT_MIN, INT_MAX);
+ RNA_def_string(func, "idname_fallback", NULL, MAX_NAME, "Fallback Identifier", "");
+ RNA_def_string(func, "keymap_fallback", NULL, KMAP_MAX_NAME, "Fallback Key Map", "");
+
/* Access tool operator options (optionally create). */
func = RNA_def_function(srna, "operator_properties", "rna_WorkSpaceTool_operator_properties");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 602ef634e1b..cec7ddb4b68 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -29,7 +29,6 @@ set(INC
../makesdna
../makesrna
../render/extern/include
- ../../../intern/elbeem/extern
../../../intern/eigen
../../../intern/guardedalloc
)
@@ -55,8 +54,7 @@ set(SRC
intern/MOD_dynamicpaint.c
intern/MOD_edgesplit.c
intern/MOD_explode.c
- intern/MOD_fluidsim.c
- intern/MOD_fluidsim_util.c
+ intern/MOD_fluid.c
intern/MOD_hook.c
intern/MOD_laplaciandeform.c
intern/MOD_laplaciansmooth.c
@@ -81,7 +79,6 @@ set(SRC
intern/MOD_shrinkwrap.c
intern/MOD_simpledeform.c
intern/MOD_skin.c
- intern/MOD_smoke.c
intern/MOD_smooth.c
intern/MOD_softbody.c
intern/MOD_solidify.c
@@ -101,10 +98,10 @@ set(SRC
intern/MOD_weightvgedit.c
intern/MOD_weightvgmix.c
intern/MOD_weightvgproximity.c
+ intern/MOD_weld.c
intern/MOD_wireframe.c
MOD_modifiertypes.h
- intern/MOD_fluidsim_util.h
intern/MOD_meshcache_util.h
intern/MOD_solidify_util.h
intern/MOD_util.h
@@ -137,7 +134,7 @@ if(WITH_MOD_REMESH)
endif()
if(WITH_MOD_FLUID)
- add_definitions(-DWITH_MOD_FLUID)
+ add_definitions(-DWITH_FLUID)
endif()
if(WITH_MOD_OCEANSIM)
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 96622bf7763..7dd1ce830aa 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -56,7 +56,7 @@ extern ModifierTypeInfo modifierType_Mask;
extern ModifierTypeInfo modifierType_SimpleDeform;
extern ModifierTypeInfo modifierType_Multires;
extern ModifierTypeInfo modifierType_Surface;
-extern ModifierTypeInfo modifierType_Smoke;
+extern ModifierTypeInfo modifierType_Fluid;
extern ModifierTypeInfo modifierType_ShapeKey;
extern ModifierTypeInfo modifierType_Solidify;
extern ModifierTypeInfo modifierType_Screw;
@@ -75,6 +75,7 @@ extern ModifierTypeInfo modifierType_UVWarp;
extern ModifierTypeInfo modifierType_MeshCache;
extern ModifierTypeInfo modifierType_LaplacianDeform;
extern ModifierTypeInfo modifierType_Wireframe;
+extern ModifierTypeInfo modifierType_Weld;
extern ModifierTypeInfo modifierType_DataTransfer;
extern ModifierTypeInfo modifierType_NormalEdit;
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_fluid.c
index 34275d91ee6..b48c80d8e32 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_fluid.c
@@ -30,7 +30,7 @@
#include "DNA_collection_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_object_force_types.h"
#include "DNA_mesh_types.h"
@@ -38,7 +38,7 @@
#include "BKE_layer.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-#include "BKE_smoke.h"
+#include "BKE_fluid.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -49,45 +49,53 @@
static void initData(ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ FluidModifierData *mmd = (FluidModifierData *)md;
- smd->domain = NULL;
- smd->flow = NULL;
- smd->coll = NULL;
- smd->type = 0;
- smd->time = -1;
+ mmd->domain = NULL;
+ mmd->flow = NULL;
+ mmd->effector = NULL;
+ mmd->type = 0;
+ mmd->time = -1;
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
- const SmokeModifierData *smd = (const SmokeModifierData *)md;
- SmokeModifierData *tsmd = (SmokeModifierData *)target;
-
- smokeModifier_free(tsmd);
- smokeModifier_copy(smd, tsmd, flag);
+#ifndef WITH_FLUID
+ UNUSED_VARS(md, target, flag);
+#else
+ const FluidModifierData *mmd = (const FluidModifierData *)md;
+ FluidModifierData *tmmd = (FluidModifierData *)target;
+
+ BKE_fluid_modifier_free(tmmd);
+ BKE_fluid_modifier_copy(mmd, tmmd, flag);
+#endif /* WITH_FLUID */
}
static void freeData(ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+#ifndef WITH_FLUID
+ UNUSED_VARS(md);
+#else
+ FluidModifierData *mmd = (FluidModifierData *)md;
- smokeModifier_free(smd);
+ BKE_fluid_modifier_free(mmd);
+#endif /* WITH_FLUID */
}
static void requiredDataMask(Object *UNUSED(ob),
ModifierData *md,
CustomData_MeshMasks *r_cddata_masks)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ FluidModifierData *mmd = (FluidModifierData *)md;
- if (smd && (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
- if (smd->flow->source == MOD_SMOKE_FLOW_SOURCE_MESH) {
+ if (mmd && (mmd->type & MOD_FLUID_TYPE_FLOW) && mmd->flow) {
+ if (mmd->flow->source == FLUID_FLOW_SOURCE_MESH) {
/* vertex groups */
- if (smd->flow->vgroup_density) {
+ if (mmd->flow->vgroup_density) {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
}
/* uv layer */
- if (smd->flow->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_UV) {
+ if (mmd->flow->texture_type == FLUID_FLOW_TEXTURE_MAP_UV) {
r_cddata_masks->fmask |= CD_MASK_MTFACE;
}
}
@@ -96,14 +104,22 @@ static void requiredDataMask(Object *UNUSED(ob),
static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+#ifndef WITH_FLUID
+ UNUSED_VARS(md, ctx);
+ return me;
+#else
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ Mesh *result = NULL;
if (ctx->flag & MOD_APPLY_ORCO) {
return me;
}
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
- return smokeModifier_do(smd, ctx->depsgraph, scene, ctx->object, me);
+
+ result = BKE_fluid_modifier_do(mmd, ctx->depsgraph, scene, ctx->object, me);
+ return result ? result : me;
+#endif /* WITH_FLUID */
}
static bool dependsOnTime(ModifierData *UNUSED(md))
@@ -113,68 +129,78 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
static bool is_flow_cb(Object *UNUSED(ob), ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
- return (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow;
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ return (mmd->type & MOD_FLUID_TYPE_FLOW) && mmd->flow;
}
static bool is_coll_cb(Object *UNUSED(ob), ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
- return (smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll;
+ FluidModifierData *mmd = (FluidModifierData *)md;
+ return (mmd->type & MOD_FLUID_TYPE_EFFEC) && mmd->effector;
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ FluidModifierData *mmd = (FluidModifierData *)md;
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
+ if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) {
DEG_add_collision_relations(ctx->node,
ctx->object,
- smd->domain->fluid_group,
- eModifierType_Smoke,
+ mmd->domain->fluid_group,
+ eModifierType_Fluid,
is_flow_cb,
- "Smoke Flow");
+ "Fluid Flow");
DEG_add_collision_relations(ctx->node,
ctx->object,
- smd->domain->coll_group,
- eModifierType_Smoke,
+ mmd->domain->effector_group,
+ eModifierType_Fluid,
is_coll_cb,
- "Smoke Coll");
+ "Fluid Effector");
DEG_add_forcefield_relations(ctx->node,
ctx->object,
- smd->domain->effector_weights,
+ mmd->domain->effector_weights,
true,
PFIELD_SMOKEFLOW,
- "Smoke Force Field");
+ "Fluid Force Field");
+
+ if (mmd->domain->guide_parent != NULL) {
+ DEG_add_object_relation(
+ ctx->node, mmd->domain->guide_parent, DEG_OB_COMP_TRANSFORM, "Fluid Guiding Object");
+ DEG_add_object_relation(
+ ctx->node, mmd->domain->guide_parent, DEG_OB_COMP_GEOMETRY, "Fluid Guiding Object");
+ }
}
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ FluidModifierData *mmd = (FluidModifierData *)md;
+
+ if (mmd->type == MOD_FLUID_TYPE_DOMAIN && mmd->domain) {
+ walk(userData, ob, (ID **)&mmd->domain->effector_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&mmd->domain->fluid_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&mmd->domain->force_group, IDWALK_CB_NOP);
- if (smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
- walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_CB_NOP);
- walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_CB_NOP);
- walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_CB_NOP);
+ if (mmd->domain->guide_parent) {
+ walk(userData, ob, (ID **)&mmd->domain->guide_parent, IDWALK_CB_NOP);
+ }
- if (smd->domain->effector_weights) {
- walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_CB_NOP);
+ if (mmd->domain->effector_weights) {
+ walk(userData, ob, (ID **)&mmd->domain->effector_weights->group, IDWALK_CB_NOP);
}
}
- if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) {
- walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_CB_USER);
+ if (mmd->type == MOD_FLUID_TYPE_FLOW && mmd->flow) {
+ walk(userData, ob, (ID **)&mmd->flow->noise_texture, IDWALK_CB_USER);
}
}
-ModifierTypeInfo modifierType_Smoke = {
- /* name */ "Smoke",
- /* structName */ "SmokeModifierData",
- /* structSize */ sizeof(SmokeModifierData),
+ModifierTypeInfo modifierType_Fluid = {
+ /* name */ "Fluid",
+ /* structName */ "FluidModifierData",
+ /* structSize */ sizeof(FluidModifierData),
/* type */ eModifierTypeType_Constructive,
- /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_UsesPointCache |
- eModifierTypeFlag_Single,
+ /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_Single,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c
deleted file mode 100644
index 620b21f3e0c..00000000000
--- a/source/blender/modifiers/intern/MOD_fluidsim.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 by the Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup modifiers
- */
-
-#include "BLI_utildefines.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_fluidsim_types.h"
-#include "DNA_object_types.h"
-
-#include "BKE_layer.h"
-#include "BKE_modifier.h"
-
-#include "DEG_depsgraph_build.h"
-
-#include "MOD_fluidsim_util.h"
-#include "MOD_modifiertypes.h"
-
-#include "MEM_guardedalloc.h"
-
-/* Fluidsim */
-static void initData(ModifierData *md)
-{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
-
- fluidsim_init(fluidmd);
-}
-static void freeData(ModifierData *md)
-{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
-
- fluidsim_free(fluidmd);
-}
-
-static void copyData(const ModifierData *md, ModifierData *target, const int UNUSED(flag))
-{
- const FluidsimModifierData *fluidmd = (const FluidsimModifierData *)md;
- FluidsimModifierData *tfluidmd = (FluidsimModifierData *)target;
-
- /* Free any FSS that was allocated in initData() */
- if (tfluidmd->fss) {
- MEM_SAFE_FREE(tfluidmd->fss->meshVelocities);
- MEM_freeN(tfluidmd->fss);
- }
-
- if (fluidmd->fss == NULL) {
- tfluidmd->fss = NULL;
- return;
- }
-
- tfluidmd->fss = MEM_dupallocN(fluidmd->fss);
- if (tfluidmd->fss->meshVelocities != NULL) {
- tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities);
- }
-}
-
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
-{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
- Mesh *result = NULL;
-
- /* check for alloc failing */
- if (!fluidmd->fss) {
- initData(md);
-
- if (!fluidmd->fss) {
- return mesh;
- }
- }
-
- result = fluidsimModifier_do(fluidmd, ctx, mesh);
-
- return result ? result : mesh;
-}
-
-static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
- if (fluidmd && fluidmd->fss) {
- if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
- FOREACH_SCENE_OBJECT_BEGIN (ctx->scene, ob1) {
- if (ob1 != ctx->object) {
- FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(
- ob1, eModifierType_Fluidsim);
-
- /* Only put dependencies from NON-DOMAIN fluids in here. */
- if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) {
- DEG_add_object_relation(ctx->node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object");
- }
- }
- }
- FOREACH_SCENE_OBJECT_END;
- }
- }
-}
-
-static bool dependsOnTime(ModifierData *UNUSED(md))
-{
- return true;
-}
-
-ModifierTypeInfo modifierType_Fluidsim = {
- /* name */ "Fluidsim",
- /* structName */ "FluidsimModifierData",
- /* structSize */ sizeof(FluidsimModifierData),
- /* type */ eModifierTypeType_Nonconstructive,
-
- /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_RequiresOriginalData |
- eModifierTypeFlag_Single,
-
- /* copyData */ copyData,
-
- /* deformVerts */ NULL,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
-
- /* initData */ initData,
- /* requiredDataMask */ NULL,
- /* freeData */ freeData,
- /* isDisabled */ NULL,
- /* updateDepsgraph */ updateDepsgraph,
- /* dependsOnTime */ dependsOnTime,
- /* dependsOnNormals */ NULL,
- /* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
-};
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
deleted file mode 100644
index 748bf4db4e2..00000000000
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 by the Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup modifiers
- */
-
-#include <stddef.h>
-#include <zlib.h>
-
-#include "BLI_utildefines.h"
-
-#ifdef WITH_MOD_FLUID
-# include "BLI_blenlib.h"
-# include "BLI_math.h"
-#endif
-
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_fluidsim_types.h"
-
-#include "BKE_fluidsim.h" /* ensure definitions here match */
-#include "BKE_mesh.h"
-#ifdef WITH_MOD_FLUID
-# include "BKE_global.h"
-# include "BKE_library.h"
-#endif
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
-
-#include "MOD_fluidsim_util.h"
-#include "MOD_modifiertypes.h"
-
-#include "MEM_guardedalloc.h"
-
-// headers for fluidsim bobj meshes
-#include "LBM_fluidsim.h"
-
-void fluidsim_init(FluidsimModifierData *fluidmd)
-{
-#ifdef WITH_MOD_FLUID
- if (fluidmd) {
- FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings");
-
- fluidmd->fss = fss;
-
- if (!fss) {
- return;
- }
-
- fss->fmd = fluidmd;
- fss->type = OB_FLUIDSIM_ENABLE;
- fss->threads = 0;
- fss->show_advancedoptions = 0;
-
- fss->resolutionxyz = 65;
- fss->previewresxyz = 45;
- fss->realsize = 0.5;
- fss->guiDisplayMode = OB_FSDOM_PREVIEW;
- fss->renderDisplayMode = OB_FSDOM_FINAL;
-
- fss->viscosityValue = 1.0;
- fss->viscosityExponent = 6;
-
- fss->grav[0] = 0.0;
- fss->grav[1] = 0.0;
- fss->grav[2] = -9.81;
-
- fss->animStart = 0.0;
- fss->animEnd = 4.0;
- fss->animRate = 1.0;
- fss->gstar = 0.005; // used as normgstar
- fss->maxRefine = -1;
- /* maxRefine is set according to resolutionxyz during bake */
-
- /* fluid/inflow settings
- * fss->iniVel --> automatically set to 0 */
-
- modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), OB_FLUIDSIM_SURF_DIR_DEFAULT);
-
- /* first init of bounding box */
- /* no bounding box needed */
-
- /* todo - reuse default init from elbeem! */
- fss->typeFlags = OB_FSBND_PARTSLIP | OB_FSSG_NOOBS;
- fss->domainNovecgen = 0;
- fss->volumeInitType = 1; /* volume */
- fss->partSlipValue = 0.2;
-
- fss->generateTracers = 0;
- fss->generateParticles = 0.0;
- fss->surfaceSmoothing = 1.0;
- fss->surfaceSubdivs = 0.0;
- fss->particleInfSize = 0.0;
- fss->particleInfAlpha = 0.0;
-
- /* init fluid control settings */
- fss->attractforceStrength = 0.2;
- fss->attractforceRadius = 0.75;
- fss->velocityforceStrength = 0.2;
- fss->velocityforceRadius = 0.75;
- fss->cpsTimeStart = fss->animStart;
- fss->cpsTimeEnd = fss->animEnd;
- fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width
-
- /*
- * BAD TODO: this is done in buttons_object.c in the moment
- * Mesh *mesh = ob->data;
- * // calculate bounding box
- * fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
- */
-
- fss->meshVelocities = NULL;
-
- fss->lastgoodframe = -1;
-
- fss->flag |= OB_FLUIDSIM_ACTIVE;
- }
-#else
- (void)fluidmd; /* unused */
-#endif
- return;
-}
-
-void fluidsim_free(FluidsimModifierData *fluidmd)
-{
- if (fluidmd && fluidmd->fss) {
- if (fluidmd->fss->meshVelocities) {
- MEM_freeN(fluidmd->fss->meshVelocities);
- }
- MEM_SAFE_FREE(fluidmd->fss);
- }
-
- return;
-}
-
-#ifdef WITH_MOD_FLUID
-/* read .bobj.gz file into a fluidsimMesh struct */
-static Mesh *fluidsim_read_obj(const char *filename, const MPoly *mp_example)
-{
- int wri = 0, i;
- int gotBytes;
- gzFile gzf;
- int numverts = 0, numfaces = 0;
- Mesh *mesh = NULL;
- MPoly *mp;
- MLoop *ml;
- MVert *mv;
- short *normals, *no_s;
- float no[3];
-
- const short mp_mat_nr = mp_example->mat_nr;
- const char mp_flag = mp_example->flag;
-
- /* ------------------------------------------------
- * get numverts + numfaces first
- * ------------------------------------------------ */
- gzf = BLI_gzopen(filename, "rb");
- if (!gzf) {
- return NULL;
- }
-
- /* read numverts */
- gotBytes = gzread(gzf, &wri, sizeof(wri));
- numverts = wri;
-
- /* skip verts */
- gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;
-
- /* read number of normals */
- if (gotBytes) {
- gotBytes = gzread(gzf, &wri, sizeof(wri));
- }
-
- /* skip normals */
- gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;
-
- /* get no. of triangles */
- if (gotBytes) {
- gotBytes = gzread(gzf, &wri, sizeof(wri));
- }
- numfaces = wri;
-
- gzclose(gzf);
- /* ------------------------------------------------ */
-
- if (!numfaces || !numverts || !gotBytes) {
- return NULL;
- }
-
- gzf = BLI_gzopen(filename, "rb");
- if (!gzf) {
- return NULL;
- }
-
- mesh = BKE_mesh_new_nomain(numverts, 0, 0, numfaces * 3, numfaces);
-
- if (!mesh) {
- gzclose(gzf);
- return NULL;
- }
-
- /* read numverts */
- gotBytes = gzread(gzf, &wri, sizeof(wri));
-
- /* read vertex position from file */
- mv = mesh->mvert;
-
- for (i = 0; i < numverts; i++, mv++) {
- gotBytes = gzread(gzf, mv->co, sizeof(float) * 3);
- }
-
- /* should be the same as numverts */
- gotBytes = gzread(gzf, &wri, sizeof(wri));
- if (wri != numverts) {
- if (mesh) {
- BKE_id_free(NULL, mesh);
- }
- gzclose(gzf);
- return NULL;
- }
-
- normals = MEM_calloc_arrayN(numverts, 3 * sizeof(short), "fluid_tmp_normals");
- if (!normals) {
- if (mesh) {
- BKE_id_free(NULL, mesh);
- }
- gzclose(gzf);
- return NULL;
- }
-
- /* read normals from file (but don't save them yet) */
- for (i = numverts, no_s = normals; i > 0; i--, no_s += 3) {
- gotBytes = gzread(gzf, no, sizeof(float) * 3);
- normal_float_to_short_v3(no_s, no);
- }
-
- /* read no. of triangles */
- gotBytes = gzread(gzf, &wri, sizeof(wri));
-
- if (wri != numfaces) {
- printf("Fluidsim: error in reading data from file.\n");
- if (mesh) {
- BKE_id_free(NULL, mesh);
- }
- gzclose(gzf);
- MEM_freeN(normals);
- return NULL;
- }
-
- /* read triangles from file */
- mp = mesh->mpoly;
- ml = mesh->mloop;
- for (i = 0; i < numfaces; i++, mp++, ml += 3) {
- int face[3];
-
- gotBytes = gzread(gzf, face, sizeof(int) * 3);
-
- /* initialize from existing face */
- mp->mat_nr = mp_mat_nr;
- mp->flag = mp_flag;
-
- mp->loopstart = i * 3;
- mp->totloop = 3;
-
- ml[0].v = face[0];
- ml[1].v = face[1];
- ml[2].v = face[2];
- }
-
- gzclose(gzf);
-
- BKE_mesh_calc_edges(mesh, false, false);
- BKE_mesh_vert_normals_apply(mesh, (short(*)[3])normals);
- MEM_freeN(normals);
-
- // CDDM_calc_normals(result);
- return mesh;
-}
-
-void fluid_get_bb(MVert *mvert,
- int totvert,
- float obmat[4][4],
- /*RET*/ float start[3],
- /*RET*/ float size[3])
-{
- float bbsx = 0.0, bbsy = 0.0, bbsz = 0.0;
- float bbex = 1.0, bbey = 1.0, bbez = 1.0;
- int i;
- float vec[3];
-
- if (totvert == 0) {
- zero_v3(start);
- zero_v3(size);
- return;
- }
-
- copy_v3_v3(vec, mvert[0].co);
- mul_m4_v3(obmat, vec);
- bbsx = vec[0];
- bbsy = vec[1];
- bbsz = vec[2];
- bbex = vec[0];
- bbey = vec[1];
- bbez = vec[2];
-
- for (i = 1; i < totvert; i++) {
- copy_v3_v3(vec, mvert[i].co);
- mul_m4_v3(obmat, vec);
-
- if (vec[0] < bbsx) {
- bbsx = vec[0];
- }
- if (vec[1] < bbsy) {
- bbsy = vec[1];
- }
- if (vec[2] < bbsz) {
- bbsz = vec[2];
- }
- if (vec[0] > bbex) {
- bbex = vec[0];
- }
- if (vec[1] > bbey) {
- bbey = vec[1];
- }
- if (vec[2] > bbez) {
- bbez = vec[2];
- }
- }
-
- /* return values... */
- if (start) {
- start[0] = bbsx;
- start[1] = bbsy;
- start[2] = bbsz;
- }
- if (size) {
- size[0] = bbex - bbsx;
- size[1] = bbey - bbsy;
- size[2] = bbez - bbsz;
- }
-}
-
-//-------------------------------------------------------------------------------
-// old interface
-//-------------------------------------------------------------------------------
-
-void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value)
-{
- Mesh *mesh;
-
- value[0] = '\0';
-
- if (ob->type == OB_MESH) {
- /* use mesh bounding box and object scaling */
- mesh = ob->data;
-
- fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
- elbeemEstimateMemreq(
- fss->resolutionxyz, fss->bbSize[0], fss->bbSize[1], fss->bbSize[2], fss->maxRefine, value);
- }
-}
-
-/* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
-static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, Mesh *mesh, char *filename)
-{
- int wri, i, j;
- float wrf;
- gzFile gzf;
- FluidsimSettings *fss = fluidmd->fss;
- int len = strlen(filename);
- int totvert = mesh->totvert;
- FluidVertexVelocity *velarray = NULL;
-
- /* mesh and vverts have to be valid from loading... */
-
- if (fss->meshVelocities) {
- MEM_freeN(fss->meshVelocities);
- }
-
- if (len < 7) {
- return;
- }
-
- if (fss->domainNovecgen > 0) {
- return;
- }
-
- fss->meshVelocities = MEM_calloc_arrayN(
- mesh->totvert, sizeof(FluidVertexVelocity), "Fluidsim_velocities");
- fss->totvert = totvert;
-
- velarray = fss->meshVelocities;
-
- /* .bobj.gz, correct filename
- * 87654321 */
- filename[len - 6] = 'v';
- filename[len - 5] = 'e';
- filename[len - 4] = 'l';
-
- gzf = BLI_gzopen(filename, "rb");
- if (!gzf) {
- MEM_freeN(fss->meshVelocities);
- fss->meshVelocities = NULL;
- return;
- }
-
- gzread(gzf, &wri, sizeof(wri));
- if (wri != totvert) {
- MEM_freeN(fss->meshVelocities);
- fss->meshVelocities = NULL;
- return;
- }
-
- for (i = 0; i < totvert; i++) {
- for (j = 0; j < 3; j++) {
- gzread(gzf, &wrf, sizeof(wrf));
- velarray[i].vel[j] = wrf;
- }
- }
-
- gzclose(gzf);
-}
-
-static Mesh *fluidsim_read_cache(
- Object *ob, Mesh *orgmesh, FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
-{
- int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */
- /* why start with 0 as start frame?? Animations + time are frozen for frame 0 anyway.
- * (See physics_fluid.c for that. - DG) */
- /* If we start with frame 0, we need to remap all animation channels, too,
- * because they will all be 1 frame late if using frame-1! - DG */
-
- char targetFile[FILE_MAX];
- FluidsimSettings *fss = fluidmd->fss;
- Mesh *newmesh = NULL;
- MPoly *mpoly;
- MPoly mp_example = {0};
-
- const int displaymode = useRenderParams ? fss->renderDisplayMode : fss->guiDisplayMode;
-
- switch (displaymode) {
- case OB_FSDOM_GEOM:
- /* just display original object */
- return NULL;
- case OB_FSDOM_PREVIEW:
- /* use preview mesh */
- BLI_join_dirfile(
- targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
- break;
- case OB_FSDOM_FINAL:
- /* use final mesh */
- BLI_join_dirfile(
- targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
- break;
- default:
- BLI_assert(!"Wrong fluidsim display type");
- return NULL;
- }
-
- /* offset baked frame */
- curFrame += fss->frameOffset;
-
- BLI_path_abs(targetFile, modifier_path_relbase_from_global(ob));
- BLI_path_frame(targetFile, curFrame, 0); // fixed #frame-no
-
- /* assign material + flags to new mesh.
- * if there's no faces in original mesh, keep materials and flags unchanged */
- mpoly = orgmesh->mpoly;
- if (mpoly) {
- mp_example = *mpoly;
- }
- /* else leave NULL'd */
-
- newmesh = fluidsim_read_obj(targetFile, &mp_example);
-
- if (!newmesh) {
- /* switch, abort background rendering when fluidsim mesh is missing */
- const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
-
- if (G.background == 1) {
- if (BLI_getenv(strEnvName2)) {
- int elevel = atoi(BLI_getenv(strEnvName2));
- if (elevel > 0) {
- printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",
- strEnvName2,
- targetFile);
- exit(1);
- }
- }
- }
-
- /* display org. object upon failure which is in new mesh */
- return NULL;
- }
-
- BKE_mesh_copy_settings(newmesh, orgmesh);
-
- /* Fluid simulation has a texture space that based on the bounds of the fluid mesh.
- * This does not seem particularly useful, but it's backwards compatible. */
- BKE_mesh_texspace_calc(newmesh);
-
- /* load vertex velocities, if they exist...
- * TODO? use generate flag as loading flag as well?
- * warning, needs original .bobj.gz mesh loading filename */
- if (displaymode == OB_FSDOM_FINAL) {
- fluidsim_read_vel_cache(fluidmd, newmesh, targetFile);
- }
- else {
- if (fss->meshVelocities) {
- MEM_freeN(fss->meshVelocities);
- }
-
- fss->meshVelocities = NULL;
- }
-
- return newmesh;
-}
-#endif // WITH_MOD_FLUID
-
-Mesh *fluidsimModifier_do(FluidsimModifierData *fluidmd,
- const ModifierEvalContext *ctx,
- Mesh *mesh)
-{
-#ifdef WITH_MOD_FLUID
- Object *ob = ctx->object;
- Depsgraph *depsgraph = ctx->depsgraph;
- const bool useRenderParams = (ctx->flag & MOD_APPLY_RENDER) != 0;
- // const bool isFinalCalc = (ctx->flag & MOD_APPLY_USECACHE) != 0;
- Mesh *result = NULL;
- int framenr;
- FluidsimSettings *fss = NULL;
-
- framenr = (int)DEG_get_ctime(depsgraph);
-
- /* only handle fluidsim domains */
- if (fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN)) {
- return mesh;
- }
-
- /* sanity check */
- if (!fluidmd || !fluidmd->fss) {
- return mesh;
- }
-
- fss = fluidmd->fss;
-
- /* timescale not supported yet
- * clmd->sim_parms->timescale = timescale; */
-
- /* support reversing of baked fluid frames here */
- if ((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0)) {
- framenr = fss->lastgoodframe - framenr + 1;
- CLAMP(framenr, 1, fss->lastgoodframe);
- }
-
- /* try to read from cache */
- /* if the frame is there, fine, otherwise don't do anything */
- if ((result = fluidsim_read_cache(ob, mesh, fluidmd, framenr, useRenderParams))) {
- return result;
- }
-
- return mesh;
-#else
- /* unused */
- UNUSED_VARS(fluidmd, ctx, mesh);
- return NULL;
-#endif
-}
diff --git a/source/blender/modifiers/intern/MOD_solidify_util.h b/source/blender/modifiers/intern/MOD_solidify_util.h
index dba360dc1ce..3a9608861dc 100644
--- a/source/blender/modifiers/intern/MOD_solidify_util.h
+++ b/source/blender/modifiers/intern/MOD_solidify_util.h
@@ -18,8 +18,8 @@
* \ingroup modifiers
*/
-#ifndef __MOD_MESHCACHE_UTIL_H__
-#define __MOD_MESHCACHE_UTIL_H__
+#ifndef __MOD_SOLIDIFY_UTIL_H__
+#define __MOD_SOLIDIFY_UTIL_H__
/* MOD_solidify_extrude.c */
Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
@@ -31,4 +31,4 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
const ModifierEvalContext *ctx,
Mesh *mesh);
-#endif /* __MOD_MESHCACHE_UTIL_H__ */
+#endif /* __MOD_SOLIDIFY_UTIL_H__ */
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 1e3c747022c..0b72c31ad7b 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -279,12 +279,11 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(ParticleInstance);
INIT_TYPE(Explode);
INIT_TYPE(Shrinkwrap);
- INIT_TYPE(Fluidsim);
INIT_TYPE(Mask);
INIT_TYPE(SimpleDeform);
INIT_TYPE(Multires);
INIT_TYPE(Surface);
- INIT_TYPE(Smoke);
+ INIT_TYPE(Fluid);
INIT_TYPE(ShapeKey);
INIT_TYPE(Solidify);
INIT_TYPE(Screw);
@@ -301,6 +300,7 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(MeshCache);
INIT_TYPE(LaplacianDeform);
INIT_TYPE(Wireframe);
+ INIT_TYPE(Weld);
INIT_TYPE(DataTransfer);
INIT_TYPE(NormalEdit);
INIT_TYPE(CorrectiveSmooth);
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
new file mode 100644
index 00000000000..9c8579e1cd3
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weld.c
@@ -0,0 +1,1918 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup modifiers
+ *
+ * Weld modifier: Remove doubles.
+ */
+
+/* TODOs:
+ * - Review weight and vertex color interpolation.;
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BLI_alloca.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_math.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_deform.h"
+#include "BKE_bvhutils.h"
+#include "BKE_modifier.h"
+#include "BKE_mesh.h"
+
+#include "DEG_depsgraph.h"
+
+//#define USE_WELD_DEBUG
+//#define USE_WELD_NORMALS
+
+/* Indicates when the element was not computed. */
+#define OUT_OF_CONTEXT (uint)(-1)
+/* Indicates if the edge or face will be collapsed. */
+#define ELEM_COLLAPSED (uint)(-2)
+/* indicates whether an edge or vertex in groups_map will be merged. */
+#define ELEM_MERGED (uint)(-2)
+
+/* Used to indicate a range in an array specifying a group. */
+struct WeldGroup {
+ uint len;
+ uint ofs;
+};
+
+/* Edge groups that will be merged. Final vertices are also indicated. */
+struct WeldGroupEdge {
+ struct WeldGroup group;
+ uint v1;
+ uint v2;
+};
+
+typedef struct WeldVert {
+ /* Indexes relative to the original Mesh. */
+ uint vert_dest;
+ uint vert_orig;
+} WeldVert;
+
+typedef struct WeldEdge {
+ union {
+ uint flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ uint edge_dest;
+ uint edge_orig;
+ uint vert_a;
+ uint vert_b;
+ };
+ };
+} WeldEdge;
+
+typedef struct WeldLoop {
+ union {
+ uint flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ uint vert;
+ uint edge;
+ uint loop_orig;
+ uint loop_skip_to;
+ };
+ };
+} WeldLoop;
+
+typedef struct WeldPoly {
+ union {
+ uint flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ uint poly_dst;
+ uint poly_orig;
+ uint loop_start;
+ uint loop_end;
+ /* Final Polygon Size. */
+ uint len;
+ /* Group of loops that will be affected. */
+ struct WeldGroup loops;
+ };
+ };
+} WeldPoly;
+
+typedef struct WeldMesh {
+ /* Group of vertices to be merged. */
+ struct WeldGroup *vert_groups;
+ uint *vert_groups_buffer;
+ /* From the original index of the vertex, this indicates which group it is or is going to be
+ * merged. */
+ uint *vert_groups_map;
+
+ /* Group of edges to be merged. */
+ struct WeldGroupEdge *edge_groups;
+ uint *edge_groups_buffer;
+ /* From the original index of the vertex, this indicates which group it is or is going to be
+ * merged. */
+ uint *edge_groups_map;
+
+ /* References all polygons and loops that will be affected. */
+ WeldLoop *wloop;
+ WeldPoly *wpoly;
+ WeldPoly *wpoly_new;
+ uint wloop_len;
+ uint wpoly_len;
+ uint wpoly_new_len;
+
+ /* From the actual index of the element in the mesh, it indicates what is the index of the Weld
+ * element above. */
+ uint *loop_map;
+ uint *poly_map;
+
+ uint vert_kill_len;
+ uint edge_kill_len;
+ uint loop_kill_len;
+ uint poly_kill_len; /* Including the new polygons. */
+
+ /* Size of the affected polygon with more sides. */
+ uint max_poly_len;
+} WeldMesh;
+
+typedef struct WeldLoopOfPolyIter {
+ uint loop_start;
+ uint loop_end;
+ const WeldLoop *wloop;
+ const MLoop *mloop;
+ const uint *loop_map;
+ /* Weld group. */
+ uint *group;
+
+ uint l_curr;
+ uint l_next;
+
+ /* Return */
+ uint group_len;
+ uint v;
+ uint e;
+ char type;
+} WeldLoopOfPolyIter;
+
+/* -------------------------------------------------------------------- */
+/** \name Debug Utils
+ * \{ */
+
+#ifdef USE_WELD_DEBUG
+static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
+ const WeldPoly *wp,
+ const WeldLoop *wloop,
+ const MLoop *mloop,
+ const uint *loop_map,
+ uint *group_buffer);
+
+static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter);
+
+static void weld_assert_vert_dest_map_setup(const BVHTreeOverlap *overlap,
+ const uint overlap_len,
+ const uint *vert_dest_map)
+{
+ const BVHTreeOverlap *overlap_iter = &overlap[0];
+ for (uint i = overlap_len; i--; overlap_iter++) {
+ uint indexA = overlap_iter->indexA;
+ uint indexB = overlap_iter->indexB;
+ uint va_dst = vert_dest_map[indexA];
+ uint vb_dst = vert_dest_map[indexB];
+
+ BLI_assert(va_dst == vb_dst);
+ }
+}
+
+static void weld_assert_edge_kill_len(const WeldEdge *wedge,
+ const uint wedge_len,
+ const uint supposed_kill_len)
+{
+ uint kills = 0;
+ const WeldEdge *we = &wedge[0];
+ for (uint i = wedge_len; i--; we++) {
+ uint edge_dest = we->edge_dest;
+ /* Magically includes collapsed edges. */
+ if (edge_dest != OUT_OF_CONTEXT) {
+ kills++;
+ }
+ }
+ BLI_assert(kills == supposed_kill_len);
+}
+
+static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
+ const WeldPoly *wpoly_new,
+ const uint wpoly_new_len,
+ const WeldLoop *wloop,
+ const MLoop *mloop,
+ const uint *loop_map,
+ const uint *poly_map,
+ const MPoly *mpoly,
+ const uint mpoly_len,
+ const uint mloop_len,
+ const uint supposed_poly_kill_len,
+ const uint supposed_loop_kill_len)
+{
+ uint poly_kills = 0;
+ uint loop_kills = mloop_len;
+ const MPoly *mp = &mpoly[0];
+ for (uint i = 0; i < mpoly_len; i++, mp++) {
+ uint poly_ctx = poly_map[i];
+ if (poly_ctx != OUT_OF_CONTEXT) {
+ const WeldPoly *wp = &wpoly[poly_ctx];
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ poly_kills++;
+ continue;
+ }
+ else {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ poly_kills++;
+ continue;
+ }
+ uint remain = wp->len;
+ uint l = wp->loop_start;
+ while (remain) {
+ uint l_next = l + 1;
+ uint loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag != ELEM_COLLAPSED) {
+ loop_kills--;
+ remain--;
+ }
+ }
+ else {
+ loop_kills--;
+ remain--;
+ }
+ l = l_next;
+ }
+ }
+ }
+ else {
+ loop_kills -= mp->totloop;
+ }
+ }
+
+ const WeldPoly *wp = &wpoly_new[0];
+ for (uint i = wpoly_new_len; i--; wp++) {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ poly_kills++;
+ continue;
+ }
+ uint remain = wp->len;
+ uint l = wp->loop_start;
+ while (remain) {
+ uint l_next = l + 1;
+ uint loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag != ELEM_COLLAPSED) {
+ loop_kills--;
+ remain--;
+ }
+ }
+ else {
+ loop_kills--;
+ remain--;
+ }
+ l = l_next;
+ }
+ }
+
+ BLI_assert(poly_kills == supposed_poly_kill_len);
+ BLI_assert(loop_kills == supposed_loop_kill_len);
+}
+
+static void weld_assert_poly_no_vert_repetition(const WeldPoly *wp,
+ const WeldLoop *wloop,
+ const MLoop *mloop,
+ const uint *loop_map)
+{
+ const uint len = wp->len;
+ uint *verts = BLI_array_alloca(verts, len);
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ return;
+ }
+ else {
+ uint i = 0;
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ verts[i++] = iter.v;
+ }
+ }
+ for (uint i = 0; i < len; i++) {
+ uint va = verts[i];
+ for (uint j = i + 1; j < len; j++) {
+ uint vb = verts[j];
+ BLI_assert(va != vb);
+ }
+ }
+}
+
+static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
+{
+ if (wp->flag == ELEM_COLLAPSED) {
+ return;
+ }
+
+ uint len = wp->len;
+ const WeldLoop *wl = &wloop[wp->loops.ofs];
+ BLI_assert(wp->loop_start <= wl->loop_orig);
+
+ uint end_wloop = wp->loops.ofs + wp->loops.len;
+ const WeldLoop *wl_end = &wloop[end_wloop - 1];
+
+ uint min_len = 0;
+ for (; wl <= wl_end; wl++) {
+ BLI_assert(wl->loop_skip_to == OUT_OF_CONTEXT); /* Not for this case. */
+ if (wl->flag != ELEM_COLLAPSED) {
+ min_len++;
+ }
+ }
+ BLI_assert(len >= min_len);
+
+ uint max_len = wp->loop_end - wp->loop_start + 1;
+ BLI_assert(len <= max_len);
+}
+#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Vert API
+ * \{ */
+
+static void weld_vert_ctx_alloc_and_setup(const uint mvert_len,
+ const BVHTreeOverlap *overlap,
+ const uint overlap_len,
+ uint *r_vert_dest_map,
+ WeldVert **r_wvert,
+ uint *r_wvert_len,
+ uint *r_vert_kill_len)
+{
+ uint *v_dest_iter = &r_vert_dest_map[0];
+ for (uint i = mvert_len; i--; v_dest_iter++) {
+ *v_dest_iter = OUT_OF_CONTEXT;
+ }
+
+ uint vert_kill_len = 0;
+ const BVHTreeOverlap *overlap_iter = &overlap[0];
+ for (uint i = 0; i < overlap_len; i++, overlap_iter++) {
+ uint indexA = overlap_iter->indexA;
+ uint indexB = overlap_iter->indexB;
+
+ BLI_assert(indexA < indexB);
+
+ uint va_dst = r_vert_dest_map[indexA];
+ uint vb_dst = r_vert_dest_map[indexB];
+ if (va_dst == OUT_OF_CONTEXT) {
+ if (vb_dst == OUT_OF_CONTEXT) {
+ vb_dst = indexA;
+ r_vert_dest_map[indexB] = vb_dst;
+ }
+ r_vert_dest_map[indexA] = vb_dst;
+ vert_kill_len++;
+ }
+ else if (vb_dst == OUT_OF_CONTEXT) {
+ r_vert_dest_map[indexB] = va_dst;
+ vert_kill_len++;
+ }
+ else if (va_dst != vb_dst) {
+ uint v_new, v_old;
+ if (va_dst < vb_dst) {
+ v_new = va_dst;
+ v_old = vb_dst;
+ }
+ else {
+ v_new = vb_dst;
+ v_old = va_dst;
+ }
+ BLI_assert(r_vert_dest_map[v_old] == v_old);
+ BLI_assert(r_vert_dest_map[v_new] == v_new);
+ vert_kill_len++;
+
+ const BVHTreeOverlap *overlap_iter_b = &overlap[0];
+ for (uint j = i + 1; j--; overlap_iter_b++) {
+ indexA = overlap_iter_b->indexA;
+ indexB = overlap_iter_b->indexB;
+ va_dst = r_vert_dest_map[indexA];
+ vb_dst = r_vert_dest_map[indexB];
+ if (ELEM(v_old, vb_dst, va_dst)) {
+ r_vert_dest_map[indexA] = v_new;
+ r_vert_dest_map[indexB] = v_new;
+ }
+ }
+ BLI_assert(r_vert_dest_map[v_old] == v_new);
+ }
+ }
+
+ /* Vert Context. */
+ uint wvert_len = 0;
+
+ WeldVert *wvert, *wv;
+ wvert = MEM_mallocN(sizeof(*wvert) * mvert_len, __func__);
+ wv = &wvert[0];
+
+ v_dest_iter = &r_vert_dest_map[0];
+ for (uint i = 0; i < mvert_len; i++, v_dest_iter++) {
+ if (*v_dest_iter != OUT_OF_CONTEXT) {
+ wv->vert_dest = *v_dest_iter;
+ wv->vert_orig = i;
+ wv++;
+ wvert_len++;
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_vert_dest_map_setup(overlap, overlap_len, r_vert_dest_map);
+#endif
+
+ *r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_len);
+ *r_wvert_len = wvert_len;
+ *r_vert_kill_len = vert_kill_len;
+}
+
+static void weld_vert_groups_setup(const uint mvert_len,
+ const uint wvert_len,
+ const WeldVert *wvert,
+ const uint *vert_dest_map,
+ uint *r_vert_groups_map,
+ uint **r_vert_groups_buffer,
+ struct WeldGroup **r_vert_groups)
+{
+ /* Get weld vert groups. */
+
+ uint wgroups_len = 0;
+ const uint *vert_dest_iter = &vert_dest_map[0];
+ uint *group_map_iter = &r_vert_groups_map[0];
+ for (uint i = 0; i < mvert_len; i++, group_map_iter++, vert_dest_iter++) {
+ uint vert_dest = *vert_dest_iter;
+ if (vert_dest != OUT_OF_CONTEXT) {
+ if (vert_dest != i) {
+ *group_map_iter = ELEM_MERGED;
+ }
+ else {
+ *group_map_iter = wgroups_len;
+ wgroups_len++;
+ }
+ }
+ else {
+ *group_map_iter = OUT_OF_CONTEXT;
+ }
+ }
+
+ struct WeldGroup *wgroups = MEM_callocN(sizeof(*wgroups) * wgroups_len, __func__);
+
+ const WeldVert *wv = &wvert[0];
+ for (uint i = wvert_len; i--; wv++) {
+ uint group_index = r_vert_groups_map[wv->vert_dest];
+ wgroups[group_index].len++;
+ }
+
+ uint ofs = 0;
+ struct WeldGroup *wg_iter = &wgroups[0];
+ for (uint i = wgroups_len; i--; wg_iter++) {
+ wg_iter->ofs = ofs;
+ ofs += wg_iter->len;
+ }
+
+ BLI_assert(ofs == wvert_len);
+
+ uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
+ wv = &wvert[0];
+ for (uint i = wvert_len; i--; wv++) {
+ uint group_index = r_vert_groups_map[wv->vert_dest];
+ groups_buffer[wgroups[group_index].ofs++] = wv->vert_orig;
+ }
+
+ wg_iter = &wgroups[0];
+ for (uint i = wgroups_len; i--; wg_iter++) {
+ wg_iter->ofs -= wg_iter->len;
+ }
+
+ *r_vert_groups = wgroups;
+ *r_vert_groups_buffer = groups_buffer;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Edge API
+ * \{ */
+
+static void weld_edge_ctx_setup(const uint mvert_len,
+ const uint wedge_len,
+ struct WeldGroup *r_vlinks,
+ uint *r_edge_dest_map,
+ WeldEdge *r_wedge,
+ uint *r_edge_kiil_len)
+{
+ WeldEdge *we;
+
+ /* Setup Edge Overlap. */
+ uint edge_kill_len = 0;
+
+ struct WeldGroup *vl_iter, *v_links;
+ v_links = r_vlinks;
+ vl_iter = &v_links[0];
+
+ we = &r_wedge[0];
+ for (uint i = wedge_len; i--; we++) {
+ uint dst_vert_a = we->vert_a;
+ uint dst_vert_b = we->vert_b;
+
+ if (dst_vert_a == dst_vert_b) {
+ BLI_assert(we->edge_dest == OUT_OF_CONTEXT);
+ r_edge_dest_map[we->edge_orig] = ELEM_COLLAPSED;
+ we->flag = ELEM_COLLAPSED;
+ edge_kill_len++;
+ continue;
+ }
+
+ v_links[dst_vert_a].len++;
+ v_links[dst_vert_b].len++;
+ }
+
+ uint link_len = 0;
+ vl_iter = &v_links[0];
+ for (uint i = mvert_len; i--; vl_iter++) {
+ vl_iter->ofs = link_len;
+ link_len += vl_iter->len;
+ }
+
+ if (link_len) {
+ uint *link_edge_buffer = MEM_mallocN(sizeof(*link_edge_buffer) * link_len, __func__);
+
+ we = &r_wedge[0];
+ for (uint i = 0; i < wedge_len; i++, we++) {
+ if (we->flag == ELEM_COLLAPSED) {
+ continue;
+ }
+
+ uint dst_vert_a = we->vert_a;
+ uint dst_vert_b = we->vert_b;
+
+ link_edge_buffer[v_links[dst_vert_a].ofs++] = i;
+ link_edge_buffer[v_links[dst_vert_b].ofs++] = i;
+ }
+
+ vl_iter = &v_links[0];
+ for (uint i = mvert_len; i--; vl_iter++) {
+ /* Fix offset */
+ vl_iter->ofs -= vl_iter->len;
+ }
+
+ we = &r_wedge[0];
+ for (uint i = 0; i < wedge_len; i++, we++) {
+ if (we->edge_dest != OUT_OF_CONTEXT) {
+ /* No need to retest edges.
+ * (Already includes collapsed edges). */
+ continue;
+ }
+
+ uint dst_vert_a = we->vert_a;
+ uint dst_vert_b = we->vert_b;
+
+ struct WeldGroup *link_a = &v_links[dst_vert_a];
+ struct WeldGroup *link_b = &v_links[dst_vert_b];
+
+ uint edges_len_a = link_a->len;
+ uint edges_len_b = link_b->len;
+
+ if (edges_len_a <= 1 || edges_len_b <= 1) {
+ continue;
+ }
+
+ uint *edges_ctx_a = &link_edge_buffer[link_a->ofs];
+ uint *edges_ctx_b = &link_edge_buffer[link_b->ofs];
+ uint edge_orig = we->edge_orig;
+
+ for (; edges_len_a--; edges_ctx_a++) {
+ uint e_ctx_a = *edges_ctx_a;
+ if (e_ctx_a == i) {
+ continue;
+ }
+ while (edges_len_b && *edges_ctx_b < e_ctx_a) {
+ edges_ctx_b++;
+ edges_len_b--;
+ }
+ if (edges_len_b == 0) {
+ break;
+ }
+ uint e_ctx_b = *edges_ctx_b;
+ if (e_ctx_a == e_ctx_b) {
+ WeldEdge *we_b = &r_wedge[e_ctx_b];
+ BLI_assert(ELEM(we_b->vert_a, dst_vert_a, dst_vert_b));
+ BLI_assert(ELEM(we_b->vert_b, dst_vert_a, dst_vert_b));
+ BLI_assert(we_b->edge_dest == OUT_OF_CONTEXT);
+ BLI_assert(we_b->edge_orig != edge_orig);
+ r_edge_dest_map[we_b->edge_orig] = edge_orig;
+ we_b->edge_dest = edge_orig;
+ edge_kill_len++;
+ }
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_edge_kill_len(r_wedge, wedge_len, edge_kill_len);
+#endif
+
+ MEM_freeN(link_edge_buffer);
+ }
+
+ *r_edge_kiil_len = edge_kill_len;
+}
+
+static void weld_edge_ctx_alloc(const MEdge *medge,
+ const uint medge_len,
+ const uint *vert_dest_map,
+ uint *r_edge_dest_map,
+ uint **r_edge_ctx_map,
+ WeldEdge **r_wedge,
+ uint *r_wedge_len)
+{
+ /* Edge Context. */
+ uint *edge_map = MEM_mallocN(sizeof(*edge_map) * medge_len, __func__);
+ uint wedge_len = 0;
+
+ WeldEdge *wedge, *we;
+ wedge = MEM_mallocN(sizeof(*wedge) * medge_len, __func__);
+ we = &wedge[0];
+
+ const MEdge *me = &medge[0];
+ uint *e_dest_iter = &r_edge_dest_map[0];
+ uint *iter = &edge_map[0];
+ for (uint i = 0; i < medge_len; i++, me++, iter++, e_dest_iter++) {
+ uint v1 = me->v1;
+ uint v2 = me->v2;
+ uint v_dest_1 = vert_dest_map[v1];
+ uint v_dest_2 = vert_dest_map[v2];
+ if ((v_dest_1 != OUT_OF_CONTEXT) || (v_dest_2 != OUT_OF_CONTEXT)) {
+ we->vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1;
+ we->vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2;
+ we->edge_dest = OUT_OF_CONTEXT;
+ we->edge_orig = i;
+ we++;
+ *e_dest_iter = i;
+ *iter = wedge_len++;
+ }
+ else {
+ *e_dest_iter = OUT_OF_CONTEXT;
+ *iter = OUT_OF_CONTEXT;
+ }
+ }
+
+ *r_wedge = MEM_reallocN(wedge, sizeof(*wedge) * wedge_len);
+ *r_wedge_len = wedge_len;
+ *r_edge_ctx_map = edge_map;
+}
+
+static void weld_edge_groups_setup(const uint medge_len,
+ const uint edge_kill_len,
+ const uint wedge_len,
+ WeldEdge *wedge,
+ const uint *wedge_map,
+ uint *r_edge_groups_map,
+ uint **r_edge_groups_buffer,
+ struct WeldGroupEdge **r_edge_groups)
+{
+
+ /* Get weld edge groups. */
+
+ struct WeldGroupEdge *wegroups, *wegrp_iter;
+
+ uint wgroups_len = wedge_len - edge_kill_len;
+ wegroups = MEM_callocN(sizeof(*wegroups) * wgroups_len, __func__);
+ wegrp_iter = &wegroups[0];
+
+ wgroups_len = 0;
+ const uint *edge_ctx_iter = &wedge_map[0];
+ uint *group_map_iter = &r_edge_groups_map[0];
+ for (uint i = medge_len; i--; edge_ctx_iter++, group_map_iter++) {
+ uint edge_ctx = *edge_ctx_iter;
+ if (edge_ctx != OUT_OF_CONTEXT) {
+ WeldEdge *we = &wedge[edge_ctx];
+ uint edge_dest = we->edge_dest;
+ if (edge_dest != OUT_OF_CONTEXT) {
+ BLI_assert(edge_dest != we->edge_orig);
+ *group_map_iter = ELEM_MERGED;
+ }
+ else {
+ we->edge_dest = we->edge_orig;
+ wegrp_iter->v1 = we->vert_a;
+ wegrp_iter->v2 = we->vert_b;
+ *group_map_iter = wgroups_len;
+ wgroups_len++;
+ wegrp_iter++;
+ }
+ }
+ else {
+ *group_map_iter = OUT_OF_CONTEXT;
+ }
+ }
+
+ BLI_assert(wgroups_len == wedge_len - edge_kill_len);
+
+ WeldEdge *we = &wedge[0];
+ for (uint i = wedge_len; i--; we++) {
+ if (we->flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ uint group_index = r_edge_groups_map[we->edge_dest];
+ wegroups[group_index].group.len++;
+ }
+
+ uint ofs = 0;
+ wegrp_iter = &wegroups[0];
+ for (uint i = wgroups_len; i--; wegrp_iter++) {
+ wegrp_iter->group.ofs = ofs;
+ ofs += wegrp_iter->group.len;
+ }
+
+ uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
+ we = &wedge[0];
+ for (uint i = wedge_len; i--; we++) {
+ if (we->flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ uint group_index = r_edge_groups_map[we->edge_dest];
+ groups_buffer[wegroups[group_index].group.ofs++] = we->edge_orig;
+ }
+
+ wegrp_iter = &wegroups[0];
+ for (uint i = wgroups_len; i--; wegrp_iter++) {
+ wegrp_iter->group.ofs -= wegrp_iter->group.len;
+ }
+
+ *r_edge_groups_buffer = groups_buffer;
+ *r_edge_groups = wegroups;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Poly and Loop API
+ * \{ */
+
+static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
+ const WeldPoly *wp,
+ const WeldLoop *wloop,
+ const MLoop *mloop,
+ const uint *loop_map,
+ uint *group_buffer)
+{
+ if (wp->flag == ELEM_COLLAPSED) {
+ return false;
+ }
+
+ iter->loop_start = wp->loop_start;
+ iter->loop_end = wp->loop_end;
+ iter->wloop = wloop;
+ iter->mloop = mloop;
+ iter->loop_map = loop_map;
+ iter->group = group_buffer;
+
+ iter->l_next = iter->loop_start;
+#ifdef USE_WELD_DEBUG
+ iter->v = OUT_OF_CONTEXT;
+#endif
+ return true;
+}
+
+static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
+{
+ uint loop_end = iter->loop_end;
+ const WeldLoop *wloop = iter->wloop;
+ const uint *loop_map = iter->loop_map;
+ iter->group_len = 0;
+ uint l = iter->l_curr = iter->l_next;
+ while (l <= loop_end) {
+ uint l_next = l + 1;
+ const uint loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag == ELEM_COLLAPSED) {
+ if (iter->group) {
+ if (l == iter->loop_start) {
+ uint l_prev = loop_end;
+ const uint loop_ctx_end = loop_map[l_prev];
+ if (loop_ctx_end != OUT_OF_CONTEXT) {
+ const WeldLoop *wl_prev = &wloop[loop_ctx_end];
+ while (wl_prev->flag == ELEM_COLLAPSED) {
+ iter->group[iter->group_len++] = l_prev--;
+ wl_prev--;
+ if (wl_prev->loop_orig != l_prev) {
+ break;
+ }
+ }
+ }
+ }
+ iter->group[iter->group_len++] = l;
+ }
+ l = l_next;
+ continue;
+ }
+#ifdef USE_WELD_DEBUG
+ BLI_assert(iter->v != wl->vert);
+#endif
+ iter->v = wl->vert;
+ iter->e = wl->edge;
+ iter->type = 1;
+ }
+ else {
+ const MLoop *ml = &iter->mloop[l];
+#ifdef USE_WELD_DEBUG
+ BLI_assert(iter->v != ml->v);
+#endif
+ iter->v = ml->v;
+ iter->e = ml->e;
+ iter->type = 0;
+ }
+ if (iter->group) {
+ iter->group[iter->group_len++] = l;
+ }
+ iter->l_next = l_next;
+ return true;
+ }
+
+ return false;
+}
+
+static void weld_poly_loop_ctx_alloc(const MPoly *mpoly,
+ const uint mpoly_len,
+ const MLoop *mloop,
+ const uint mloop_len,
+ const uint *vert_dest_map,
+ const uint *edge_dest_map,
+ WeldMesh *r_weld_mesh)
+{
+ /* Loop/Poly Context. */
+ uint *loop_map = MEM_mallocN(sizeof(*loop_map) * mloop_len, __func__);
+ uint *poly_map = MEM_mallocN(sizeof(*poly_map) * mpoly_len, __func__);
+ uint wloop_len = 0;
+ uint wpoly_len = 0;
+ uint max_ctx_poly_len = 4;
+
+ WeldLoop *wloop, *wl;
+ wloop = MEM_mallocN(sizeof(*wloop) * mloop_len, __func__);
+ wl = &wloop[0];
+
+ WeldPoly *wpoly, *wp;
+ wpoly = MEM_mallocN(sizeof(*wpoly) * mpoly_len, __func__);
+ wp = &wpoly[0];
+
+ uint maybe_new_poly = 0;
+
+ const MPoly *mp = &mpoly[0];
+ uint *iter = &poly_map[0];
+ uint *loop_map_iter = &loop_map[0];
+ for (uint i = 0; i < mpoly_len; i++, mp++, iter++) {
+ const uint loopstart = mp->loopstart;
+ const uint totloop = mp->totloop;
+
+ uint vert_ctx_len = 0;
+
+ uint l = loopstart;
+ uint prev_wloop_len = wloop_len;
+ const MLoop *ml = &mloop[l];
+ for (uint j = totloop; j--; l++, ml++, loop_map_iter++) {
+ uint v = ml->v;
+ uint e = ml->e;
+ uint v_dest = vert_dest_map[v];
+ uint e_dest = edge_dest_map[e];
+ bool is_vert_ctx = v_dest != OUT_OF_CONTEXT;
+ bool is_edge_ctx = e_dest != OUT_OF_CONTEXT;
+ if (is_vert_ctx) {
+ vert_ctx_len++;
+ }
+ if (is_vert_ctx || is_edge_ctx) {
+ wl->vert = is_vert_ctx ? v_dest : v;
+ wl->edge = is_edge_ctx ? e_dest : e;
+ wl->loop_orig = l;
+ wl->loop_skip_to = OUT_OF_CONTEXT;
+ wl++;
+
+ *loop_map_iter = wloop_len++;
+ }
+ else {
+ *loop_map_iter = OUT_OF_CONTEXT;
+ }
+ }
+ if (wloop_len != prev_wloop_len) {
+ uint loops_len = wloop_len - prev_wloop_len;
+
+ wp->poly_dst = OUT_OF_CONTEXT;
+ wp->poly_orig = i;
+ wp->loops.len = loops_len;
+ wp->loops.ofs = prev_wloop_len;
+ wp->loop_start = loopstart;
+ wp->loop_end = loopstart + totloop - 1;
+ wp->len = totloop;
+ wp++;
+
+ *iter = wpoly_len++;
+ if (totloop > 5 && vert_ctx_len > 1) {
+ uint max_new = (totloop / 3) - 1;
+ vert_ctx_len /= 2;
+ maybe_new_poly += MIN2(max_new, vert_ctx_len);
+ CLAMP_MIN(max_ctx_poly_len, totloop);
+ }
+ }
+ else {
+ *iter = OUT_OF_CONTEXT;
+ }
+ }
+
+ if (mpoly_len < (wpoly_len + maybe_new_poly)) {
+ WeldPoly *wpoly_tmp = wpoly;
+ wpoly = MEM_mallocN(sizeof(*wpoly) * ((size_t)wpoly_len + maybe_new_poly), __func__);
+ memcpy(wpoly, wpoly_tmp, sizeof(*wpoly) * wpoly_len);
+ MEM_freeN(wpoly_tmp);
+ }
+
+ WeldPoly *poly_new = &wpoly[wpoly_len];
+
+ r_weld_mesh->wloop = MEM_reallocN(wloop, sizeof(*wloop) * wloop_len);
+ r_weld_mesh->wpoly = wpoly;
+ r_weld_mesh->wpoly_new = poly_new;
+ r_weld_mesh->wloop_len = wloop_len;
+ r_weld_mesh->wpoly_len = wpoly_len;
+ r_weld_mesh->wpoly_new_len = 0;
+ r_weld_mesh->loop_map = loop_map;
+ r_weld_mesh->poly_map = poly_map;
+ r_weld_mesh->max_poly_len = max_ctx_poly_len;
+}
+
+static void weld_poly_split_recursive(const uint *vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ const MLoop *mloop,
+#endif
+ uint ctx_verts_len,
+ WeldPoly *r_wp,
+ WeldMesh *r_weld_mesh,
+ uint *r_poly_kill,
+ uint *r_loop_kill)
+{
+ uint poly_len = r_wp->len;
+ if (poly_len > 3 && ctx_verts_len > 1) {
+ const uint ctx_loops_len = r_wp->loops.len;
+ const uint ctx_loops_ofs = r_wp->loops.ofs;
+ WeldLoop *wloop = r_weld_mesh->wloop;
+ WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
+
+ uint loop_kill = 0;
+
+ WeldLoop *poly_loops = &wloop[ctx_loops_ofs];
+ WeldLoop *wla = &poly_loops[0];
+ WeldLoop *wla_prev = &poly_loops[ctx_loops_len - 1];
+ while (wla_prev->flag == ELEM_COLLAPSED) {
+ wla_prev--;
+ }
+ const uint la_len = ctx_loops_len - 1;
+ for (uint la = 0; la < la_len; la++, wla++) {
+ wa_continue:
+ if (wla->flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ uint vert_a = wla->vert;
+ /* Only test vertices that will be merged. */
+ if (vert_dest_map[vert_a] != OUT_OF_CONTEXT) {
+ uint lb = la + 1;
+ WeldLoop *wlb = wla + 1;
+ WeldLoop *wlb_prev = wla;
+ uint killed_ab = 0;
+ ctx_verts_len = 1;
+ for (; lb < ctx_loops_len; lb++, wlb++) {
+ BLI_assert(wlb->loop_skip_to == OUT_OF_CONTEXT);
+ if (wlb->flag == ELEM_COLLAPSED) {
+ killed_ab++;
+ continue;
+ }
+ uint vert_b = wlb->vert;
+ if (vert_dest_map[vert_b] != OUT_OF_CONTEXT) {
+ ctx_verts_len++;
+ }
+ if (vert_a == vert_b) {
+ const uint dist_a = wlb->loop_orig - wla->loop_orig - killed_ab;
+ const uint dist_b = poly_len - dist_a;
+
+ BLI_assert(dist_a != 0 && dist_b != 0);
+ if (dist_a == 1 || dist_b == 1) {
+ BLI_assert(dist_a != dist_b);
+ BLI_assert((wla->flag == ELEM_COLLAPSED) || (wlb->flag == ELEM_COLLAPSED));
+ }
+ else {
+ WeldLoop *wl_tmp = NULL;
+ if (dist_a == 2) {
+ wl_tmp = wlb_prev;
+ BLI_assert(wla->flag != ELEM_COLLAPSED);
+ BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
+ wla->flag = ELEM_COLLAPSED;
+ wl_tmp->flag = ELEM_COLLAPSED;
+ loop_kill += 2;
+ poly_len -= 2;
+ }
+ if (dist_b == 2) {
+ if (wl_tmp != NULL) {
+ r_wp->flag = ELEM_COLLAPSED;
+ *r_poly_kill += 1;
+ }
+ else {
+ wl_tmp = wla_prev;
+ BLI_assert(wlb->flag != ELEM_COLLAPSED);
+ BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
+ wlb->flag = ELEM_COLLAPSED;
+ wl_tmp->flag = ELEM_COLLAPSED;
+ }
+ loop_kill += 2;
+ poly_len -= 2;
+ }
+ if (wl_tmp == NULL) {
+ const uint new_loops_len = lb - la;
+ const uint new_loops_ofs = ctx_loops_ofs + la;
+
+ WeldPoly *new_wp = &wpoly_new[r_weld_mesh->wpoly_new_len++];
+ new_wp->poly_dst = OUT_OF_CONTEXT;
+ new_wp->poly_orig = r_wp->poly_orig;
+ new_wp->loops.len = new_loops_len;
+ new_wp->loops.ofs = new_loops_ofs;
+ new_wp->loop_start = wla->loop_orig;
+ new_wp->loop_end = wlb_prev->loop_orig;
+ new_wp->len = dist_a;
+ weld_poly_split_recursive(vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ mloop,
+#endif
+ ctx_verts_len,
+ new_wp,
+ r_weld_mesh,
+ r_poly_kill,
+ r_loop_kill);
+ BLI_assert(dist_b == poly_len - dist_a);
+ poly_len = dist_b;
+ if (wla_prev->loop_orig > wla->loop_orig) {
+ /* New start. */
+ r_wp->loop_start = wlb->loop_orig;
+ }
+ else {
+ /* The `loop_start` doesn't change but some loops must be skipped. */
+ wla_prev->loop_skip_to = wlb->loop_orig;
+ }
+ wla = wlb;
+ la = lb;
+ goto wa_continue;
+ }
+ break;
+ }
+ }
+ if (wlb->flag != ELEM_COLLAPSED) {
+ wlb_prev = wlb;
+ }
+ }
+ }
+ if (wla->flag != ELEM_COLLAPSED) {
+ wla_prev = wla;
+ }
+ }
+ r_wp->len = poly_len;
+ *r_loop_kill += loop_kill;
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_no_vert_repetition(r_wp, wloop, mloop, r_weld_mesh->loop_map);
+#endif
+ }
+}
+
+static void weld_poly_loop_ctx_setup(const MLoop *mloop,
+#ifdef USE_WELD_DEBUG
+ const MPoly *mpoly,
+ const uint mpoly_len,
+ const uint mloop_len,
+#endif
+ const uint mvert_len,
+ const uint *vert_dest_map,
+ const uint remain_edge_ctx_len,
+ struct WeldGroup *r_vlinks,
+ WeldMesh *r_weld_mesh)
+{
+ uint poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len;
+
+ WeldPoly *wpoly_new, *wpoly, *wp;
+ WeldLoop *wloop, *wl;
+
+ wpoly = r_weld_mesh->wpoly;
+ wloop = r_weld_mesh->wloop;
+ wpoly_new = r_weld_mesh->wpoly_new;
+ wpoly_len = r_weld_mesh->wpoly_len;
+ wpoly_new_len = 0;
+ poly_kill_len = 0;
+ loop_kill_len = 0;
+
+ const uint *loop_map = r_weld_mesh->loop_map;
+
+ if (remain_edge_ctx_len) {
+
+ /* Setup Poly/Loop. */
+
+ wp = &wpoly[0];
+ for (uint i = wpoly_len; i--; wp++) {
+ const uint ctx_loops_len = wp->loops.len;
+ const uint ctx_loops_ofs = wp->loops.ofs;
+
+ uint poly_len = wp->len;
+ uint ctx_verts_len = 0;
+ wl = &wloop[ctx_loops_ofs];
+ for (uint l = ctx_loops_len; l--; wl++) {
+ const uint edge_dest = wl->edge;
+ if (edge_dest == ELEM_COLLAPSED) {
+ wl->flag = ELEM_COLLAPSED;
+ if (poly_len == 3) {
+ wp->flag = ELEM_COLLAPSED;
+ poly_kill_len++;
+ loop_kill_len += 3;
+ poly_len = 0;
+ break;
+ }
+ loop_kill_len++;
+ poly_len--;
+ }
+ else {
+ const uint vert_dst = wl->vert;
+ if (vert_dest_map[vert_dst] != OUT_OF_CONTEXT) {
+ ctx_verts_len++;
+ }
+ }
+ }
+
+ if (poly_len) {
+ wp->len = poly_len;
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_len(wp, wloop);
+#endif
+
+ weld_poly_split_recursive(vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ mloop,
+#endif
+ ctx_verts_len,
+ wp,
+ r_weld_mesh,
+ &poly_kill_len,
+ &loop_kill_len);
+
+ wpoly_new_len = r_weld_mesh->wpoly_new_len;
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_and_loop_kill_len(wpoly,
+ wpoly_new,
+ wpoly_new_len,
+ wloop,
+ mloop,
+ loop_map,
+ r_weld_mesh->poly_map,
+ mpoly,
+ mpoly_len,
+ mloop_len,
+ poly_kill_len,
+ loop_kill_len);
+#endif
+
+ /* Setup Polygon Overlap. */
+
+ uint wpoly_and_new_len = wpoly_len + wpoly_new_len;
+
+ struct WeldGroup *vl_iter, *v_links = r_vlinks;
+ memset(v_links, 0, sizeof(*v_links) * mvert_len);
+
+ wp = &wpoly[0];
+ for (uint i = wpoly_and_new_len; i--; wp++) {
+ WeldLoopOfPolyIter iter;
+ if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ v_links[iter.v].len++;
+ }
+ }
+ }
+
+ uint link_len = 0;
+ vl_iter = &v_links[0];
+ for (uint i = mvert_len; i--; vl_iter++) {
+ vl_iter->ofs = link_len;
+ link_len += vl_iter->len;
+ }
+
+ if (link_len) {
+ uint *link_poly_buffer = MEM_mallocN(sizeof(*link_poly_buffer) * link_len, __func__);
+
+ wp = &wpoly[0];
+ for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
+ WeldLoopOfPolyIter iter;
+ if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ link_poly_buffer[v_links[iter.v].ofs++] = i;
+ }
+ }
+ }
+
+ vl_iter = &v_links[0];
+ for (uint i = mvert_len; i--; vl_iter++) {
+ /* Fix offset */
+ vl_iter->ofs -= vl_iter->len;
+ }
+
+ uint polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
+ polys_len_b = p_ctx_b = 0; /* silence warnings */
+
+ wp = &wpoly[0];
+ for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ /* No need to retest poly.
+ * (Already includes collapsed polygons). */
+ continue;
+ }
+
+ WeldLoopOfPolyIter iter;
+ weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL);
+ weld_iter_loop_of_poly_next(&iter);
+ struct WeldGroup *link_a = &v_links[iter.v];
+ polys_len_a = link_a->len;
+ if (polys_len_a == 1) {
+ BLI_assert(link_poly_buffer[link_a->ofs] == i);
+ continue;
+ }
+ uint wp_len = wp->len;
+ polys_ctx_a = &link_poly_buffer[link_a->ofs];
+ for (; polys_len_a--; polys_ctx_a++) {
+ p_ctx_a = *polys_ctx_a;
+ if (p_ctx_a == i) {
+ continue;
+ }
+
+ WeldPoly *wp_tmp = &wpoly[p_ctx_a];
+ if (wp_tmp->len != wp_len) {
+ continue;
+ }
+
+ WeldLoopOfPolyIter iter_b = iter;
+ while (weld_iter_loop_of_poly_next(&iter_b)) {
+ struct WeldGroup *link_b = &v_links[iter_b.v];
+ polys_len_b = link_b->len;
+ if (polys_len_b == 1) {
+ BLI_assert(link_poly_buffer[link_b->ofs] == i);
+ polys_len_b = 0;
+ break;
+ }
+
+ polys_ctx_b = &link_poly_buffer[link_b->ofs];
+ for (; polys_len_b; polys_len_b--, polys_ctx_b++) {
+ p_ctx_b = *polys_ctx_b;
+ if (p_ctx_b < p_ctx_a) {
+ continue;
+ }
+ if (p_ctx_b >= p_ctx_a) {
+ if (p_ctx_b > p_ctx_a) {
+ polys_len_b = 0;
+ }
+ break;
+ }
+ }
+ if (polys_len_b == 0) {
+ break;
+ }
+ }
+ if (polys_len_b == 0) {
+ continue;
+ }
+ BLI_assert(p_ctx_a > i);
+ BLI_assert(p_ctx_a == p_ctx_b);
+ BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT);
+ BLI_assert(wp_tmp != wp);
+ wp_tmp->poly_dst = wp->poly_orig;
+ loop_kill_len += wp_tmp->len;
+ poly_kill_len++;
+ }
+ }
+ MEM_freeN(link_poly_buffer);
+ }
+ }
+ else {
+ poly_kill_len = r_weld_mesh->wpoly_len;
+ loop_kill_len = r_weld_mesh->wloop_len;
+
+ wp = &wpoly[0];
+ for (uint i = wpoly_len; i--; wp++) {
+ wp->flag = ELEM_COLLAPSED;
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_and_loop_kill_len(wpoly,
+ wpoly_new,
+ wpoly_new_len,
+ wloop,
+ mloop,
+ loop_map,
+ r_weld_mesh->poly_map,
+ mpoly,
+ mpoly_len,
+ mloop_len,
+ poly_kill_len,
+ loop_kill_len);
+#endif
+
+ r_weld_mesh->wpoly_new = wpoly_new;
+ r_weld_mesh->poly_kill_len = poly_kill_len;
+ r_weld_mesh->loop_kill_len = loop_kill_len;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Mesh API
+ * \{ */
+
+static void weld_mesh_context_create(const Mesh *mesh,
+ BVHTreeOverlap *overlap,
+ const uint overlap_len,
+ WeldMesh *r_weld_mesh)
+{
+ const MEdge *medge = mesh->medge;
+ const MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+ const uint mvert_len = mesh->totvert;
+ const uint medge_len = mesh->totedge;
+ const uint mloop_len = mesh->totloop;
+ const uint mpoly_len = mesh->totpoly;
+
+ uint *vert_dest_map = MEM_mallocN(sizeof(*vert_dest_map) * mvert_len, __func__);
+ uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * medge_len, __func__);
+ struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * mvert_len, __func__);
+
+ WeldVert *wvert;
+ uint wvert_len;
+ weld_vert_ctx_alloc_and_setup(mvert_len,
+ overlap,
+ overlap_len,
+ vert_dest_map,
+ &wvert,
+ &wvert_len,
+ &r_weld_mesh->vert_kill_len);
+
+ uint *edge_ctx_map;
+ WeldEdge *wedge;
+ uint wedge_len;
+ weld_edge_ctx_alloc(
+ medge, medge_len, vert_dest_map, edge_dest_map, &edge_ctx_map, &wedge, &wedge_len);
+
+ weld_edge_ctx_setup(
+ mvert_len, wedge_len, v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len);
+
+ weld_poly_loop_ctx_alloc(
+ mpoly, mpoly_len, mloop, mloop_len, vert_dest_map, edge_dest_map, r_weld_mesh);
+
+ weld_poly_loop_ctx_setup(mloop,
+#ifdef USE_WELD_DEBUG
+ mpoly,
+ mpoly_len,
+ mloop_len,
+#endif
+ mvert_len,
+ vert_dest_map,
+ wedge_len - r_weld_mesh->edge_kill_len,
+ v_links,
+ r_weld_mesh);
+
+ weld_vert_groups_setup(mvert_len,
+ wvert_len,
+ wvert,
+ vert_dest_map,
+ vert_dest_map,
+ &r_weld_mesh->vert_groups_buffer,
+ &r_weld_mesh->vert_groups);
+
+ weld_edge_groups_setup(medge_len,
+ r_weld_mesh->edge_kill_len,
+ wedge_len,
+ wedge,
+ edge_ctx_map,
+ edge_dest_map,
+ &r_weld_mesh->edge_groups_buffer,
+ &r_weld_mesh->edge_groups);
+
+ r_weld_mesh->vert_groups_map = vert_dest_map;
+ r_weld_mesh->edge_groups_map = edge_dest_map;
+ MEM_freeN(v_links);
+ MEM_freeN(wvert);
+ MEM_freeN(edge_ctx_map);
+ MEM_freeN(wedge);
+}
+
+static void weld_mesh_context_free(WeldMesh *weld_mesh)
+{
+ MEM_freeN(weld_mesh->vert_groups);
+ MEM_freeN(weld_mesh->vert_groups_buffer);
+ MEM_freeN(weld_mesh->vert_groups_map);
+
+ MEM_freeN(weld_mesh->edge_groups);
+ MEM_freeN(weld_mesh->edge_groups_buffer);
+ MEM_freeN(weld_mesh->edge_groups_map);
+
+ MEM_freeN(weld_mesh->wloop);
+ MEM_freeN(weld_mesh->wpoly);
+ MEM_freeN(weld_mesh->loop_map);
+ MEM_freeN(weld_mesh->poly_map);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld CustomData
+ * \{ */
+
+static void customdata_weld(
+ const CustomData *source, CustomData *dest, const uint *src_indices, int count, int dest_index)
+{
+ if (count == 1) {
+ CustomData_copy_data(source, dest, src_indices[0], dest_index, 1);
+ return;
+ }
+
+ int src_i, dest_i;
+ int j;
+
+ float co[3] = {0.0f, 0.0f, 0.0f};
+#ifdef USE_WELD_NORMALS
+ float no[3] = {0.0f, 0.0f, 0.0f};
+#endif
+ uint crease = 0;
+ uint bweight = 0;
+ short flag = 0;
+
+ /* interpolates a layer at a time */
+ dest_i = 0;
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
+ const int type = source->layers[src_i].type;
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type < type) {
+ dest_i++;
+ }
+
+ /* if there are no more dest layers, we're done */
+ if (dest_i == dest->totlayer) {
+ break;
+ }
+
+ /* if we found a matching layer, add the data */
+ if (dest->layers[dest_i].type == type) {
+ void *src_data = source->layers[src_i].data;
+
+ if (CustomData_layer_has_math(dest, dest_i)) {
+ const int size = CustomData_sizeof(type);
+ void *dst_data = dest->layers[dest_i].data;
+ void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ for (j = 0; j < count; j++) {
+ CustomData_data_add(
+ type, v_dst, POINTER_OFFSET(src_data, (size_t)src_indices[j] * size));
+ }
+ }
+ else if (type == CD_MVERT) {
+ for (j = 0; j < count; j++) {
+ MVert *mv_src = &((MVert *)src_data)[src_indices[j]];
+ add_v3_v3(co, mv_src->co);
+#ifdef USE_WELD_NORMALS
+ short *mv_src_no = mv_src->no;
+ no[0] += mv_src_no[0];
+ no[1] += mv_src_no[1];
+ no[2] += mv_src_no[2];
+#endif
+ bweight += mv_src->bweight;
+ flag |= mv_src->flag;
+ }
+ }
+ else if (type == CD_MEDGE) {
+ for (j = 0; j < count; j++) {
+ MEdge *me_src = &((MEdge *)src_data)[src_indices[j]];
+ crease += me_src->crease;
+ bweight += me_src->bweight;
+ flag |= me_src->flag;
+ }
+ }
+ else {
+ CustomData_copy_layer_type_data(source, dest, type, src_indices[0], dest_index, 1);
+ }
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ dest_i++;
+ }
+ }
+
+ float fac = 1.0f / count;
+
+ for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
+ CustomDataLayer *layer_dst = &dest->layers[dest_i];
+ const int type = layer_dst->type;
+ if (CustomData_layer_has_math(dest, dest_i)) {
+ const int size = CustomData_sizeof(type);
+ void *dst_data = layer_dst->data;
+ void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ CustomData_data_multiply(type, v_dst, fac);
+ }
+ else if (type == CD_MVERT) {
+ MVert *mv = &((MVert *)layer_dst->data)[dest_index];
+ mul_v3_fl(co, fac);
+ bweight *= fac;
+ CLAMP_MAX(bweight, 255);
+
+ copy_v3_v3(mv->co, co);
+#ifdef USE_WELD_NORMALS
+ mul_v3_fl(no, fac);
+ short *mv_no = mv->no;
+ mv_no[0] = (short)no[0];
+ mv_no[1] = (short)no[1];
+ mv_no[2] = (short)no[2];
+#endif
+
+ mv->flag = (char)flag;
+ mv->bweight = (char)bweight;
+ }
+ else if (type == CD_MEDGE) {
+ MEdge *me = &((MEdge *)layer_dst->data)[dest_index];
+ crease *= fac;
+ bweight *= fac;
+ CLAMP_MAX(crease, 255);
+ CLAMP_MAX(bweight, 255);
+
+ me->crease = (char)crease;
+ me->bweight = (char)bweight;
+ me->flag = flag;
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Modifier Main
+ * \{ */
+
+struct WeldOverlapData {
+ const MVert *mvert;
+ float merge_dist_sq;
+};
+static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ if (index_a < index_b) {
+ struct WeldOverlapData *data = userdata;
+ const MVert *mvert = data->mvert;
+ const float dist_sq = len_squared_v3v3(mvert[index_a].co, mvert[index_b].co);
+ return dist_sq <= data->merge_dist_sq;
+ }
+ return false;
+}
+
+static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContext *ctx, Mesh *mesh)
+{
+ Mesh *result = mesh;
+
+ Object *ob = ctx->object;
+ BLI_bitmap *v_mask = NULL;
+ int v_mask_act = 0;
+
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MPoly *mpoly, *mp;
+ uint totvert, totedge, totloop, totpoly;
+ uint i;
+
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+
+ /* Vertex Group. */
+ const int defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
+ if (defgrp_index != -1) {
+ MDeformVert *dvert, *dv;
+ dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
+ if (dvert) {
+ dv = &dvert[0];
+ v_mask = BLI_BITMAP_NEW(totvert, __func__);
+ for (i = 0; i < totvert; i++, dv++) {
+ const bool found = defvert_find_weight(dv, defgrp_index) > 0.0f;
+ if (found) {
+ BLI_BITMAP_ENABLE(v_mask, i);
+ v_mask_act++;
+ }
+ }
+ }
+ }
+
+ /* Get overlap map. */
+ /* TODO: For a better performanse use KD-Tree. */
+ struct BVHTreeFromMesh treedata;
+ BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(
+ &treedata, mvert, totvert, false, v_mask, v_mask_act, wmd->merge_dist, 2, 6, 0, NULL);
+
+ if (v_mask) {
+ MEM_freeN(v_mask);
+ }
+
+ if (bvhtree == NULL) {
+ return result;
+ }
+
+ struct WeldOverlapData data;
+ data.mvert = mvert;
+ data.merge_dist_sq = SQUARE(wmd->merge_dist);
+
+ uint overlap_len;
+ BVHTreeOverlap *overlap = BLI_bvhtree_overlap_ex(bvhtree,
+ bvhtree,
+ &overlap_len,
+ bvhtree_weld_overlap_cb,
+ &data,
+ wmd->max_interactions,
+ BVH_OVERLAP_RETURN_PAIRS);
+
+ free_bvhtree_from_mesh(&treedata);
+
+ if (overlap_len) {
+ WeldMesh weld_mesh;
+ weld_mesh_context_create(mesh, overlap, overlap_len, &weld_mesh);
+
+ mloop = mesh->mloop;
+ mpoly = mesh->mpoly;
+
+ totedge = mesh->totedge;
+ totloop = mesh->totloop;
+ totpoly = mesh->totpoly;
+
+ const int result_nverts = totvert - weld_mesh.vert_kill_len;
+ const int result_nedges = totedge - weld_mesh.edge_kill_len;
+ const int result_nloops = totloop - weld_mesh.loop_kill_len;
+ const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len;
+
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
+
+ /* Vertices */
+
+ uint *vert_final = weld_mesh.vert_groups_map;
+ uint *index_iter = &vert_final[0];
+ int dest_index = 0;
+ for (i = 0; i < totvert; i++, index_iter++) {
+ int source_index = i;
+ int count = 0;
+ while (i < totvert && *index_iter == OUT_OF_CONTEXT) {
+ *index_iter = dest_index + count;
+ index_iter++;
+ count++;
+ i++;
+ }
+ if (count) {
+ CustomData_copy_data(&mesh->vdata, &result->vdata, source_index, dest_index, count);
+ dest_index += count;
+ }
+ if (i == totvert) {
+ break;
+ }
+ if (*index_iter != ELEM_MERGED) {
+ struct WeldGroup *wgroup = &weld_mesh.vert_groups[*index_iter];
+ customdata_weld(&mesh->vdata,
+ &result->vdata,
+ &weld_mesh.vert_groups_buffer[wgroup->ofs],
+ wgroup->len,
+ dest_index);
+ *index_iter = dest_index;
+ dest_index++;
+ }
+ }
+
+ BLI_assert(dest_index == result_nverts);
+
+ /* Edges */
+
+ uint *edge_final = weld_mesh.edge_groups_map;
+ index_iter = &edge_final[0];
+ dest_index = 0;
+ for (i = 0; i < totedge; i++, index_iter++) {
+ int source_index = i;
+ int count = 0;
+ while (i < totedge && *index_iter == OUT_OF_CONTEXT) {
+ *index_iter = dest_index + count;
+ index_iter++;
+ count++;
+ i++;
+ }
+ if (count) {
+ CustomData_copy_data(&mesh->edata, &result->edata, source_index, dest_index, count);
+ MEdge *me = &result->medge[dest_index];
+ dest_index += count;
+ for (; count--; me++) {
+ me->v1 = vert_final[me->v1];
+ me->v2 = vert_final[me->v2];
+ }
+ }
+ if (i == totedge) {
+ break;
+ }
+ if (*index_iter != ELEM_MERGED) {
+ struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[*index_iter];
+ customdata_weld(&mesh->edata,
+ &result->edata,
+ &weld_mesh.edge_groups_buffer[wegrp->group.ofs],
+ wegrp->group.len,
+ dest_index);
+ MEdge *me = &result->medge[dest_index];
+ me->v1 = vert_final[wegrp->v1];
+ me->v2 = vert_final[wegrp->v2];
+ me->flag |= ME_LOOSEEDGE;
+
+ *index_iter = dest_index;
+ dest_index++;
+ }
+ }
+
+ BLI_assert(dest_index == result_nedges);
+
+ /* Polys/Loops */
+
+ mp = &mpoly[0];
+ MPoly *r_mp = &result->mpoly[0];
+ MLoop *r_ml = &result->mloop[0];
+ uint r_i = 0;
+ int loop_cur = 0;
+ uint *group_buffer = BLI_array_alloca(group_buffer, weld_mesh.max_poly_len);
+ for (i = 0; i < totpoly; i++, mp++) {
+ int loop_start = loop_cur;
+ uint poly_ctx = weld_mesh.poly_map[i];
+ if (poly_ctx == OUT_OF_CONTEXT) {
+ uint mp_loop_len = mp->totloop;
+ CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart, loop_cur, mp_loop_len);
+ loop_cur += mp_loop_len;
+ for (; mp_loop_len--; r_ml++) {
+ r_ml->v = vert_final[r_ml->v];
+ r_ml->e = edge_final[r_ml->e];
+ }
+ }
+ else {
+ WeldPoly *wp = &weld_mesh.wpoly[poly_ctx];
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(
+ &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
+ continue;
+ }
+ else {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ continue;
+ }
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
+ uint v = vert_final[iter.v];
+ uint e = edge_final[iter.e];
+ r_ml->v = v;
+ r_ml->e = e;
+ r_ml++;
+ loop_cur++;
+ if (iter.type) {
+ result->medge[e].flag &= ~ME_LOOSEEDGE;
+ }
+ BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
+ }
+ }
+ }
+
+ CustomData_copy_data(&mesh->pdata, &result->pdata, i, r_i, 1);
+ r_mp->loopstart = loop_start;
+ r_mp->totloop = loop_cur - loop_start;
+ r_mp++;
+ r_i++;
+ }
+
+ WeldPoly *wp = &weld_mesh.wpoly_new[0];
+ for (i = 0; i < weld_mesh.wpoly_new_len; i++, wp++) {
+ int loop_start = loop_cur;
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(
+ &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
+ continue;
+ }
+ else {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ continue;
+ }
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
+ uint v = vert_final[iter.v];
+ uint e = edge_final[iter.e];
+ r_ml->v = v;
+ r_ml->e = e;
+ r_ml++;
+ loop_cur++;
+ if (iter.type) {
+ result->medge[e].flag &= ~ME_LOOSEEDGE;
+ }
+ BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
+ }
+ }
+ r_mp->loopstart = loop_start;
+ r_mp->totloop = loop_cur - loop_start;
+ r_mp++;
+ r_i++;
+ }
+
+ BLI_assert((int)r_i == result_npolys);
+ BLI_assert(loop_cur == result_nloops);
+
+ /* is this needed? */
+ /* recalculate normals */
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+ weld_mesh_context_free(&weld_mesh);
+ }
+
+ MEM_freeN(overlap);
+ return result;
+}
+
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+{
+ WeldModifierData *wmd = (WeldModifierData *)md;
+ return weldModifier_doWeld(wmd, ctx, mesh);
+}
+
+static void initData(ModifierData *md)
+{
+ WeldModifierData *wmd = (WeldModifierData *)md;
+
+ wmd->merge_dist = 0.001f;
+ wmd->max_interactions = 1;
+ wmd->defgrp_name[0] = '\0';
+}
+
+ModifierTypeInfo modifierType_Weld = {
+ /* name */ "Weld",
+ /* structName */ "WeldModifierData",
+ /* structSize */ sizeof(WeldModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
+ eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
+ eModifierTypeFlag_AcceptsCVs,
+
+ /* copyData */ modifier_copyData_generic,
+
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+
+ /* initData */ initData,
+ /* requiredDataMask */ NULL,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* freeRuntimeData */ NULL,
+};
+
+/** \} */
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index f618f964b22..2eb2a6b380a 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -173,6 +173,7 @@ set(SRC
shader/nodes/node_shader_normal.c
shader/nodes/node_shader_normal_map.c
shader/nodes/node_shader_object_info.c
+ shader/nodes/node_shader_output_aov.c
shader/nodes/node_shader_output_light.c
shader/nodes/node_shader_output_linestyle.c
shader/nodes/node_shader_output_material.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index a004090d03d..69d779c9b7f 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -120,6 +120,7 @@ void register_node_type_sh_output_material(void);
void register_node_type_sh_output_eevee_material(void);
void register_node_type_sh_output_world(void);
void register_node_type_sh_output_linestyle(void);
+void register_node_type_sh_output_aov(void);
void register_node_type_sh_tex_image(void);
void register_node_type_sh_tex_environment(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index f3bc5a0cafa..2b141e1a639 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -51,7 +51,7 @@ DefNode(ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_
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, 0, "CLAMP", Clamp, "Clamp", "" )
+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", "" )
@@ -130,6 +130,7 @@ DefNode(ShaderNode, SH_NODE_DISPLACEMENT, def_sh_displacement, "DIS
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(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.c b/source/blender/nodes/composite/nodes/node_composite_denoise.c
index ac30ed9576d..06c862fc3ab 100644
--- a/source/blender/nodes/composite/nodes/node_composite_denoise.c
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.c
@@ -1,6 +1,4 @@
/*
- * ***** 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
@@ -19,13 +17,9 @@
* All rights reserved.
*
* The Original Code is: all of this file.
- *
- * Contributor(s): Stefan Werner
- *
- * ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/nodes/composite/nodes/node_composite_denoise.c
+/** \file
* \ingroup cmpnodes
*/
diff --git a/source/blender/nodes/composite/nodes/node_composite_math.c b/source/blender/nodes/composite/nodes/node_composite_math.c
index 21a85b2168f..741c0e48806 100644
--- a/source/blender/nodes/composite/nodes/node_composite_math.c
+++ b/source/blender/nodes/composite/nodes/node_composite_math.c
@@ -27,10 +27,48 @@
static bNodeSocketTemplate cmp_node_math_in[] = {
{SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{-1, 0, ""}};
static bNodeSocketTemplate cmp_node_math_out[] = {{SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}};
+static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock = BLI_findlink(&node->inputs, 1);
+ nodeSetSocketAvailability(sock,
+ !ELEM(node->custom1,
+ NODE_MATH_SQRT,
+ NODE_MATH_SIGN,
+ NODE_MATH_CEIL,
+ NODE_MATH_SINE,
+ NODE_MATH_ROUND,
+ NODE_MATH_FLOOR,
+ NODE_MATH_COSINE,
+ NODE_MATH_ARCSINE,
+ NODE_MATH_TANGENT,
+ NODE_MATH_ABSOLUTE,
+ NODE_MATH_RADIANS,
+ NODE_MATH_DEGREES,
+ NODE_MATH_FRACTION,
+ NODE_MATH_ARCCOSINE,
+ NODE_MATH_ARCTANGENT) &&
+ !ELEM(node->custom1,
+ NODE_MATH_INV_SQRT,
+ NODE_MATH_TRUNC,
+ NODE_MATH_EXPONENT,
+ NODE_MATH_COSH,
+ NODE_MATH_SINH,
+ NODE_MATH_TANH));
+ bNodeSocket *sock2 = BLI_findlink(&node->inputs, 2);
+ nodeSetSocketAvailability(sock2,
+ ELEM(node->custom1,
+ NODE_MATH_COMPARE,
+ NODE_MATH_MULTIPLY_ADD,
+ NODE_MATH_WRAP,
+ NODE_MATH_SMOOTH_MIN,
+ NODE_MATH_SMOOTH_MAX));
+}
+
void register_node_type_cmp_math(void)
{
static bNodeType ntype;
@@ -38,6 +76,7 @@ void register_node_type_cmp_math(void)
cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, cmp_node_math_in, cmp_node_math_out);
node_type_label(&ntype, node_math_label);
+ node_type_update(&ntype, node_shader_update_math);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 4bcd77496c1..ffeeb7525d5 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -635,7 +635,8 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->tmp_flag >= 0) {
int id = node->tmp_flag;
- nodes_copy[id] = BKE_node_copy_ex(ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT);
+ nodes_copy[id] = BKE_node_copy_ex(
+ ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN);
nodes_copy[id]->tmp_flag = -2; /* Copy */
/* Make sure to clear all sockets links as they are invalid. */
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.c b/source/blender/nodes/shader/nodes/node_shader_clamp.c
index 8e5b90436ea..329d7492db6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.c
@@ -35,13 +35,19 @@ static bNodeSocketTemplate sh_node_clamp_out[] = {
{-1, 0, ""},
};
+static void node_shader_init_clamp(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = NODE_CLAMP_MINMAX; /* clamp type */
+}
+
static int gpu_shader_clamp(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
- return GPU_stack_link(mat, node, "clamp_value", in, out);
+ return (node->custom1 == NODE_CLAMP_MINMAX) ? GPU_stack_link(mat, node, "clamp_value", in, out) :
+ GPU_stack_link(mat, node, "clamp_range", in, out);
}
void register_node_type_sh_clamp(void)
@@ -50,6 +56,7 @@ void register_node_type_sh_clamp(void)
sh_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_clamp_in, sh_node_clamp_out);
+ node_type_init(&ntype, node_shader_init_clamp);
node_type_gpu(&ntype, gpu_shader_clamp);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.c b/source/blender/nodes/shader/nodes/node_shader_curves.c
index f5c89e6ba41..6292d7b5062 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.c
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.c
@@ -147,7 +147,7 @@ static int gpu_shader_curve_rgb(GPUMaterial *mat,
ext_rgba[a][2] = cm->maxtable;
range_rgba[a] = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable);
/* Compute extrapolation gradients. */
- if ((cm->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) {
+ if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) {
ext_rgba[a][1] = (cm->ext_in[0] != 0.0f) ?
(cm->ext_in[1] / (cm->ext_in[0] * range_rgba[a])) :
1e8f;
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.c b/source/blender/nodes/shader/nodes/node_shader_map_range.c
index 7ebf3faf1f3..c410dc7a981 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.c
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.c
@@ -30,6 +30,7 @@ static bNodeSocketTemplate sh_node_map_range_in[] = {
{SOCK_FLOAT, 1, N_("From Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_FLOAT, 1, N_("To Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_FLOAT, 1, N_("To Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("Steps"), 4.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_NONE},
{-1, 0, ""},
};
static bNodeSocketTemplate sh_node_map_range_out[] = {
@@ -37,9 +38,16 @@ static bNodeSocketTemplate sh_node_map_range_out[] = {
{-1, 0, ""},
};
+static void node_shader_update_map_range(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps");
+ nodeSetSocketAvailability(sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED);
+}
+
static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->custom1 = true;
+ node->custom1 = true; /* use_clamp */
+ node->custom2 = NODE_MAP_RANGE_LINEAR; /* interpolation */
}
static int gpu_shader_map_range(GPUMaterial *mat,
@@ -48,11 +56,25 @@ static int gpu_shader_map_range(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- GPU_stack_link(mat, node, "map_range", in, out);
- if (node->custom1) {
- GPU_link(mat, "clamp_value", out[0].link, in[3].link, in[4].link, &out[0].link);
+ static const char *names[] = {
+ [NODE_MAP_RANGE_LINEAR] = "map_range_linear",
+ [NODE_MAP_RANGE_STEPPED] = "map_range_stepped",
+ [NODE_MAP_RANGE_SMOOTHSTEP] = "map_range_smoothstep",
+ [NODE_MAP_RANGE_SMOOTHERSTEP] = "map_range_smootherstep",
+ };
+
+ int ret = 0;
+ if (node->custom2 < ARRAY_SIZE(names) && names[node->custom2]) {
+ ret = GPU_stack_link(mat, node, names[node->custom2], in, out);
+ }
+ else {
+ ret = GPU_stack_link(mat, node, "map_range_linear", in, out);
+ }
+ if (ret && node->custom1 &&
+ !ELEM(node->custom2, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) {
+ GPU_link(mat, "clamp_range", out[0].link, in[3].link, in[4].link, &out[0].link);
}
- return 1;
+ return ret;
}
void register_node_type_sh_map_range(void)
@@ -62,6 +84,7 @@ void register_node_type_sh_map_range(void)
sh_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_map_range_in, sh_node_map_range_out);
node_type_init(&ntype, node_shader_init_map_range);
+ node_type_update(&ntype, node_shader_update_map_range);
node_type_gpu(&ntype, gpu_shader_map_range);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c
index 0f1113920c9..5d9da7788ee 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_math.c
@@ -27,6 +27,7 @@
static bNodeSocketTemplate sh_node_math_in[] = {
{SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{-1, 0, ""}};
static bNodeSocketTemplate sh_node_math_out[] = {{SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}};
@@ -42,26 +43,42 @@ static int gpu_shader_math(GPUMaterial *mat,
[NODE_MATH_SUBTRACT] = "math_subtract",
[NODE_MATH_MULTIPLY] = "math_multiply",
[NODE_MATH_DIVIDE] = "math_divide",
+ [NODE_MATH_MULTIPLY_ADD] = "math_multiply_add",
[NODE_MATH_POWER] = "math_power",
[NODE_MATH_LOGARITHM] = "math_logarithm",
+ [NODE_MATH_EXPONENT] = "math_exponent",
[NODE_MATH_SQRT] = "math_sqrt",
+ [NODE_MATH_INV_SQRT] = "math_inversesqrt",
[NODE_MATH_ABSOLUTE] = "math_absolute",
+ [NODE_MATH_RADIANS] = "math_radians",
+ [NODE_MATH_DEGREES] = "math_degrees",
[NODE_MATH_MINIMUM] = "math_minimum",
[NODE_MATH_MAXIMUM] = "math_maximum",
[NODE_MATH_LESS_THAN] = "math_less_than",
[NODE_MATH_GREATER_THAN] = "math_greater_than",
+ [NODE_MATH_SIGN] = "math_sign",
+ [NODE_MATH_COMPARE] = "math_compare",
+ [NODE_MATH_SMOOTH_MIN] = "math_smoothmin",
+ [NODE_MATH_SMOOTH_MAX] = "math_smoothmax",
[NODE_MATH_ROUND] = "math_round",
[NODE_MATH_FLOOR] = "math_floor",
[NODE_MATH_CEIL] = "math_ceil",
[NODE_MATH_FRACTION] = "math_fraction",
[NODE_MATH_MODULO] = "math_modulo",
+ [NODE_MATH_TRUNC] = "math_trunc",
+ [NODE_MATH_SNAP] = "math_snap",
+ [NODE_MATH_WRAP] = "math_wrap",
+ [NODE_MATH_PINGPONG] = "math_pingpong",
[NODE_MATH_SINE] = "math_sine",
[NODE_MATH_COSINE] = "math_cosine",
[NODE_MATH_TANGENT] = "math_tangent",
+ [NODE_MATH_SINH] = "math_sinh",
+ [NODE_MATH_COSH] = "math_cosh",
+ [NODE_MATH_TANH] = "math_tanh",
[NODE_MATH_ARCSINE] = "math_arcsine",
[NODE_MATH_ARCCOSINE] = "math_arccosine",
[NODE_MATH_ARCTANGENT] = "math_arctangent",
@@ -90,6 +107,7 @@ static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node)
nodeSetSocketAvailability(sock,
!ELEM(node->custom1,
NODE_MATH_SQRT,
+ NODE_MATH_SIGN,
NODE_MATH_CEIL,
NODE_MATH_SINE,
NODE_MATH_ROUND,
@@ -98,9 +116,26 @@ static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node)
NODE_MATH_ARCSINE,
NODE_MATH_TANGENT,
NODE_MATH_ABSOLUTE,
+ NODE_MATH_RADIANS,
+ NODE_MATH_DEGREES,
NODE_MATH_FRACTION,
NODE_MATH_ARCCOSINE,
- NODE_MATH_ARCTANGENT));
+ NODE_MATH_ARCTANGENT) &&
+ !ELEM(node->custom1,
+ NODE_MATH_INV_SQRT,
+ NODE_MATH_TRUNC,
+ NODE_MATH_EXPONENT,
+ NODE_MATH_COSH,
+ NODE_MATH_SINH,
+ NODE_MATH_TANH));
+ bNodeSocket *sock2 = BLI_findlink(&node->inputs, 2);
+ nodeSetSocketAvailability(sock2,
+ ELEM(node->custom1,
+ NODE_MATH_COMPARE,
+ NODE_MATH_MULTIPLY_ADD,
+ NODE_MATH_WRAP,
+ NODE_MATH_SMOOTH_MIN,
+ NODE_MATH_SMOOTH_MAX));
}
void register_node_type_sh_math(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 18015d94f03..006f15f40a1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -54,12 +54,8 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
GPUNodeStack *out)
{
NodeShaderNormalMap *nm = node->storage;
- GPUNodeLink *negnorm;
- GPUNodeLink *realnorm;
- GPUNodeLink *strength;
-
- float strength_min[4] = {0, 0, 0, 0};
+ GPUNodeLink *strength;
if (in[0].link) {
strength = in[0].link;
}
@@ -72,27 +68,25 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
strength = GPU_constant(in[0].vec);
}
+ GPUNodeLink *newnormal;
if (in[1].link) {
- realnorm = in[1].link;
+ newnormal = in[1].link;
}
else if (node->original) {
bNodeSocket *socket = BLI_findlink(&node->original->inputs, 1);
bNodeSocketValueRGBA *socket_data = socket->default_value;
- realnorm = GPU_uniform(socket_data->value);
+ newnormal = GPU_uniform(socket_data->value);
}
else {
- realnorm = GPU_constant(in[1].vec);
+ newnormal = GPU_constant(in[1].vec);
}
- negnorm = GPU_builtin(GPU_WORLD_NORMAL);
- GPU_link(mat, "math_maximum", strength, GPU_constant(strength_min), &strength);
-
const char *color_to_normal_fnc_name = "color_to_normal_new_shading";
if (nm->space == SHD_SPACE_BLENDER_OBJECT || nm->space == SHD_SPACE_BLENDER_WORLD) {
color_to_normal_fnc_name = "color_to_blender_normal_new_shading";
}
- GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
+ GPU_link(mat, color_to_normal_fnc_name, newnormal, &newnormal);
switch (nm->space) {
case SHD_SPACE_TANGENT:
GPU_link(mat,
@@ -100,13 +94,13 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
GPU_builtin(GPU_OBJECT_INFO),
GPU_attribute(CD_TANGENT, nm->uv_map),
GPU_builtin(GPU_WORLD_NORMAL),
- realnorm,
- &realnorm);
+ newnormal,
+ &newnormal);
break;
case SHD_SPACE_OBJECT:
case SHD_SPACE_BLENDER_OBJECT:
GPU_link(
- mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
+ mat, "direction_transform_m4v3", newnormal, GPU_builtin(GPU_OBJECT_MATRIX), &newnormal);
break;
case SHD_SPACE_WORLD:
case SHD_SPACE_BLENDER_WORLD:
@@ -114,8 +108,8 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
break;
}
- GPU_link(mat, "vector_mix", strength, realnorm, negnorm, &out[0].link);
- GPU_link(mat, "vector_normalize", out[0].link, &out[0].link);
+ GPUNodeLink *oldnormal = GPU_builtin(GPU_WORLD_NORMAL);
+ GPU_link(mat, "node_normal_map_mix", strength, newnormal, oldnormal, &out[0].link);
return true;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.c b/source/blender/nodes/shader/nodes/node_shader_output_aov.c
new file mode 100644
index 00000000000..a3ecb06157e
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.c
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_output_aov_in[] = {
+ {SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ {SOCK_FLOAT, 1, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ {-1, 0, ""},
+};
+
+static void node_shader_init_output_aov(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeShaderOutputAOV *aov = MEM_callocN(sizeof(NodeShaderOutputAOV), "NodeShaderOutputAOV");
+ node->storage = aov;
+}
+
+/* node type definition */
+void register_node_type_sh_output_aov(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_AOV, "AOV Output", NODE_CLASS_OUTPUT, 0);
+ node_type_socket_templates(&ntype, sh_node_output_aov_in, NULL);
+ node_type_init(&ntype, node_shader_init_output_aov);
+ node_type_storage(
+ &ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage);
+
+ /* Do not allow muting output node. */
+ node_type_internal_links(&ntype, NULL);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 6c380efe0b2..72ad5581050 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -88,7 +88,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
"node_tex_environment_equirectangular",
in[0].link,
GPU_constant(&clamp_size),
- GPU_image(ima, iuser),
+ GPU_image(ima, iuser, 0),
&in[0].link);
}
else {
@@ -103,7 +103,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
GPU_link(mat,
"node_tex_image_linear_no_mip",
in[0].link,
- GPU_image(ima, iuser),
+ GPU_image(ima, iuser, 0),
&out[0].link,
&outalpha);
break;
@@ -111,13 +111,17 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
GPU_link(mat,
"node_tex_image_nearest",
in[0].link,
- GPU_image(ima, iuser),
+ GPU_image(ima, iuser, 0),
&out[0].link,
&outalpha);
break;
default:
- GPU_link(
- mat, "node_tex_image_cubic", in[0].link, GPU_image(ima, iuser), &out[0].link, &outalpha);
+ GPU_link(mat,
+ "node_tex_image_cubic",
+ in[0].link,
+ GPU_image(ima, iuser, 0),
+ &out[0].link,
+ &outalpha);
break;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index a6dfb2636fc..34a5e323490 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -74,6 +74,12 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
"node_tex_image_cubic",
"node_tex_image_smart",
};
+ static const char *names_tiled[] = {
+ "node_tex_tile_linear",
+ "node_tex_tile_nearest",
+ "node_tex_tile_cubic",
+ "node_tex_tile_smart",
+ };
static const char *names_box[] = {
"tex_box_sample_linear",
"tex_box_sample_nearest",
@@ -123,60 +129,89 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
node_shader_gpu_tex_mapping(mat, node, in, out);
- switch (tex->projection) {
- case SHD_PROJ_FLAT:
- if (do_texco_clip) {
- GPU_link(mat, "set_rgb", *texco, &input_coords);
- }
- if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco);
- }
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser));
- break;
-
- case SHD_PROJ_BOX:
- vnor = GPU_builtin(GPU_WORLD_NORMAL);
- ob_mat = GPU_builtin(GPU_OBJECT_MATRIX);
- blend = GPU_uniform(&tex->projection_blend);
- gpu_image = GPU_image(ima, iuser);
-
- /* equivalent to normal_world_to_object */
- GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &norm);
- GPU_link(mat, gpu_node_name, *texco, norm, GPU_image(ima, iuser), &col1, &col2, &col3);
- GPU_stack_link(
- mat, node, "node_tex_image_box", in, out, norm, col1, col2, col3, gpu_image, blend);
- break;
-
- case SHD_PROJ_SPHERE:
- GPU_link(mat, "point_texco_remap_square", *texco, texco);
- GPU_link(mat, "point_map_to_sphere", *texco, texco);
- if (do_texco_clip) {
- GPU_link(mat, "set_rgb", *texco, &input_coords);
- }
- if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco);
- }
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser));
- break;
+ if (ima->source == IMA_SRC_TILED) {
+ GPUNodeLink *map;
+ GPU_link(mat, "node_tex_tile_map", in[0].link, &out[0].link, &map);
+ /* This is not exactly great, but if we want to support different sizes per
+ * tile and older hardware, which rules out better methods like texture arrays. */
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ float tile_number = tile->tile_number;
+ GPU_link(mat,
+ names_tiled[tex->interpolation],
+ map,
+ GPU_uniform(&tile_number),
+ GPU_image(ima, iuser, tile->tile_number),
+ out[0].link,
+ &out[0].link,
+ &out[1].link);
+ }
+ }
+ else {
+ switch (tex->projection) {
+ case SHD_PROJ_FLAT:
+ if (do_texco_clip) {
+ /* This seems redundant, but is required to ensure the texco link
+ * is not freed by GPU_link, as it is still needed for GPU_stack_link.
+ * Intermediate links like this can only be used once and are then
+ * freed immediately, but if we make it the output link of a set_rgb
+ * node it will be kept and can be used multiple times. */
+ GPU_link(mat, "set_rgb", *texco, texco);
+ GPU_link(mat, "set_rgb", *texco, &input_coords);
+ }
+ if (do_texco_extend) {
+ GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, 0), texco);
+ }
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, 0));
+ break;
+
+ case SHD_PROJ_BOX:
+ vnor = GPU_builtin(GPU_WORLD_NORMAL);
+ ob_mat = GPU_builtin(GPU_OBJECT_MATRIX);
+ blend = GPU_uniform(&tex->projection_blend);
+ gpu_image = GPU_image(ima, iuser, 0);
- case SHD_PROJ_TUBE:
- GPU_link(mat, "point_texco_remap_square", *texco, texco);
- GPU_link(mat, "point_map_to_tube", *texco, texco);
+ /* equivalent to normal_world_to_object */
+ GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &norm);
+ GPU_link(mat, gpu_node_name, *texco, norm, GPU_image(ima, iuser, 0), &col1, &col2, &col3);
+ GPU_stack_link(
+ mat, node, "node_tex_image_box", in, out, norm, col1, col2, col3, gpu_image, blend);
+ break;
+
+ case SHD_PROJ_SPHERE:
+ GPU_link(mat, "point_texco_remap_square", *texco, texco);
+ GPU_link(mat, "point_map_to_sphere", *texco, texco);
+ if (do_texco_clip) {
+ /* See SHD_PROJ_FLAT for explanation. */
+ GPU_link(mat, "set_rgb", *texco, texco);
+ GPU_link(mat, "set_rgb", *texco, &input_coords);
+ }
+ if (do_texco_extend) {
+ GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, 0), texco);
+ }
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, 0));
+ break;
+
+ case SHD_PROJ_TUBE:
+ GPU_link(mat, "point_texco_remap_square", *texco, texco);
+ GPU_link(mat, "point_map_to_tube", *texco, texco);
+ if (do_texco_clip) {
+ /* See SHD_PROJ_FLAT for explanation. */
+ GPU_link(mat, "set_rgb", *texco, texco);
+ GPU_link(mat, "set_rgb", *texco, &input_coords);
+ }
+ if (do_texco_extend) {
+ GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, 0), texco);
+ }
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, 0));
+ break;
+ }
+
+ if (tex->projection != SHD_PROJ_BOX) {
if (do_texco_clip) {
- GPU_link(mat, "set_rgb", *texco, &input_coords);
- }
- if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco);
+ gpu_node_name = names_clip[tex->interpolation];
+ in[0].link = input_coords;
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, 0), out[0].link);
}
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser));
- break;
- }
-
- if (tex->projection != SHD_PROJ_BOX) {
- if (do_texco_clip) {
- gpu_node_name = names_clip[tex->interpolation];
- in[0].link = input_coords;
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser), out[0].link);
}
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c
index b1d67a5a953..310300df204 100644
--- a/source/blender/nodes/texture/nodes/node_texture_math.c
+++ b/source/blender/nodes/texture/nodes/node_texture_math.c
@@ -28,6 +28,7 @@
static bNodeSocketTemplate inputs[] = {
{SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f, PROP_NONE},
{SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f, PROP_NONE},
{-1, 0, ""},
};
@@ -74,6 +75,18 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
*out = tanf(in0);
break;
}
+ case NODE_MATH_SINH: {
+ *out = sinhf(in0);
+ break;
+ }
+ case NODE_MATH_COSH: {
+ *out = coshf(in0);
+ break;
+ }
+ case NODE_MATH_TANH: {
+ *out = tanhf(in0);
+ break;
+ }
case NODE_MATH_ARCSINE: {
/* Can't do the impossible... */
if (in0 <= 1 && in0 >= -1) {
@@ -182,11 +195,31 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
+ case NODE_MATH_RADIANS: {
+ *out = DEG2RADF(in0);
+ break;
+ }
+
+ case NODE_MATH_DEGREES: {
+ *out = RAD2DEGF(in0);
+ break;
+ }
+
case NODE_MATH_ARCTAN2: {
*out = atan2(in0, in1);
break;
}
+ case NODE_MATH_SIGN: {
+ *out = compatible_signf(in0);
+ break;
+ }
+
+ case NODE_MATH_EXPONENT: {
+ *out = expf(in0);
+ break;
+ }
+
case NODE_MATH_FLOOR: {
*out = floorf(in0);
break;
@@ -212,6 +245,76 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
+ case NODE_MATH_INV_SQRT: {
+ if (in0 > 0.0f) {
+ *out = 1.0f / sqrtf(in0);
+ }
+ else {
+ *out = 0.0f;
+ }
+ break;
+ }
+
+ case NODE_MATH_TRUNC: {
+ if (in0 > 0.0f) {
+ *out = floorf(in0);
+ }
+ else {
+ *out = ceilf(in0);
+ }
+ break;
+ }
+
+ case NODE_MATH_SNAP: {
+ if (in1 == 0) {
+ *out = 0.0;
+ }
+ else {
+ *out = floorf(in0 / in1) * in1;
+ }
+ break;
+ }
+
+ case NODE_MATH_WRAP: {
+ float in2 = tex_input_value(in[2], p, thread);
+ *out = wrapf(in0, in1, in2);
+ break;
+ }
+
+ case NODE_MATH_PINGPONG: {
+ if (in1 == 0.0f) {
+ *out = 0.0f;
+ }
+ else {
+ *out = fabsf(fractf((in0 - in1) / (in1 * 2.0f)) * in1 * 2.0f - in1);
+ }
+ break;
+ }
+
+ case NODE_MATH_COMPARE: {
+ float in2 = tex_input_value(in[2], p, thread);
+ *out = (fabsf(in0 - in1) <= MAX2(in2, 1e-5f)) ? 1.0f : 0.0f;
+ break;
+ }
+
+ case NODE_MATH_MULTIPLY_ADD: {
+ float in2 = tex_input_value(in[2], p, thread);
+ *out = in0 * in1 + in2;
+ break;
+ }
+
+ case NODE_MATH_SMOOTH_MIN: {
+ float in2 = tex_input_value(in[2], p, thread);
+ *out = smoothminf(in0, in1, in2);
+ break;
+ }
+
+ case NODE_MATH_SMOOTH_MAX: {
+ float in2 = tex_input_value(in[2], p, thread);
+ *out = -smoothminf(-in0, -in1, in2);
+ break;
+ }
+
default: {
BLI_assert(0);
break;
@@ -233,6 +336,43 @@ static void exec(void *data,
tex_output(node, execdata, in, out[0], &valuefn, data);
}
+static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock = BLI_findlink(&node->inputs, 1);
+ nodeSetSocketAvailability(sock,
+ !ELEM(node->custom1,
+ NODE_MATH_SQRT,
+ NODE_MATH_SIGN,
+ NODE_MATH_CEIL,
+ NODE_MATH_SINE,
+ NODE_MATH_ROUND,
+ NODE_MATH_FLOOR,
+ NODE_MATH_COSINE,
+ NODE_MATH_ARCSINE,
+ NODE_MATH_TANGENT,
+ NODE_MATH_ABSOLUTE,
+ NODE_MATH_RADIANS,
+ NODE_MATH_DEGREES,
+ NODE_MATH_FRACTION,
+ NODE_MATH_ARCCOSINE,
+ NODE_MATH_ARCTANGENT) &&
+ !ELEM(node->custom1,
+ NODE_MATH_INV_SQRT,
+ NODE_MATH_TRUNC,
+ NODE_MATH_EXPONENT,
+ NODE_MATH_COSH,
+ NODE_MATH_SINH,
+ NODE_MATH_TANH));
+ bNodeSocket *sock2 = BLI_findlink(&node->inputs, 2);
+ nodeSetSocketAvailability(sock2,
+ ELEM(node->custom1,
+ NODE_MATH_COMPARE,
+ NODE_MATH_MULTIPLY_ADD,
+ NODE_MATH_WRAP,
+ NODE_MATH_SMOOTH_MIN,
+ NODE_MATH_SMOOTH_MAX));
+}
+
void register_node_type_tex_math(void)
{
static bNodeType ntype;
@@ -242,6 +382,7 @@ void register_node_type_tex_math(void)
node_type_label(&ntype, node_math_label);
node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
+ node_type_update(&ntype, node_shader_update_math);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/physics/BPH_mass_spring.h b/source/blender/physics/BPH_mass_spring.h
index c0ceff4d8cf..5a8c78812a4 100644
--- a/source/blender/physics/BPH_mass_spring.h
+++ b/source/blender/physics/BPH_mass_spring.h
@@ -53,6 +53,7 @@ int BPH_cloth_solve(struct Depsgraph *depsgraph,
struct ClothModifierData *clmd,
struct ListBase *effectors);
void BKE_cloth_solver_set_positions(struct ClothModifierData *clmd);
+void BKE_cloth_solver_set_volume(ClothModifierData *clmd);
#ifdef __cplusplus
}
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index c057e74b72b..999cefde104 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -74,6 +74,46 @@ static int cloth_count_nondiag_blocks(Cloth *cloth)
return nondiag;
}
+static float cloth_calc_volume(ClothModifierData *clmd)
+{
+ /* Calculate the (closed) cloth volume. */
+ Cloth *cloth = clmd->clothObject;
+ const MVertTri *tri = cloth->tri;
+ Implicit_Data *data = cloth->implicit;
+ float vol = 0;
+
+ if (clmd->sim_parms->vgroup_pressure > 0) {
+ for (unsigned int i = 0; i < cloth->tri_num; i++) {
+ bool skip_face = false;
+ /* We have custom vertex weights for pressure. */
+ const MVertTri *vt = &tri[i];
+ for (unsigned int j = 0; j < 3; j++) {
+ /* If any weight is zero, don't take this face into account for volume calculation. */
+ ClothVertex *verts = clmd->clothObject->verts;
+
+ if (verts[vt->tri[j]].pressure_factor == 0.0f) {
+ skip_face = true;
+ }
+ }
+ if (skip_face) {
+ continue;
+ }
+
+ vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]);
+ }
+ }
+ else {
+ for (unsigned int i = 0; i < cloth->tri_num; i++) {
+ const MVertTri *vt = &tri[i];
+ vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]);
+ }
+ }
+ /* We need to divide by 6 to get the actual volume. */
+ vol = vol / 6.0f;
+
+ return vol;
+}
+
int BPH_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd)
{
Cloth *cloth = clmd->clothObject;
@@ -127,6 +167,13 @@ void BKE_cloth_solver_set_positions(ClothModifierData *clmd)
}
}
+void BKE_cloth_solver_set_volume(ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+
+ cloth->initial_mesh_volume = cloth_calc_volume(clmd);
+}
+
static bool collision_response(ClothModifierData *clmd,
CollisionModifierData *collmd,
CollPair *collpair,
@@ -380,7 +427,8 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
}
/* Calculate force of structural + shear springs. */
- if (s->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SEWING)) {
+ if (s->type &
+ (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SEWING | CLOTH_SPRING_TYPE_INTERNAL)) {
#ifdef CLOTH_FORCE_SPRING_STRUCTURAL
float k_tension, scaling_tension;
@@ -406,7 +454,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
false,
parms->max_sewing);
}
- else {
+ else if (s->type & CLOTH_SPRING_TYPE_STRUCTURAL) {
float k_compression, scaling_compression;
scaling_compression = parms->compression +
s->lin_stiffness * fabsf(parms->max_compression - parms->compression);
@@ -424,6 +472,44 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
using_angular,
0.0f);
}
+ else {
+ /* CLOTH_SPRING_TYPE_INTERNAL */
+ BLI_assert(s->type & CLOTH_SPRING_TYPE_INTERNAL);
+
+ scaling_tension = parms->internal_tension +
+ s->lin_stiffness *
+ fabsf(parms->max_internal_tension - parms->internal_tension);
+ k_tension = scaling_tension / (parms->avg_spring_len + FLT_EPSILON);
+ float scaling_compression = parms->internal_compression +
+ s->lin_stiffness * fabsf(parms->max_internal_compression -
+ parms->internal_compression);
+ float k_compression = scaling_compression / (parms->avg_spring_len + FLT_EPSILON);
+
+ float k_tension_damp = parms->tension_damp;
+ float k_compression_damp = parms->compression_damp;
+
+ if (k_tension == 0.0f) {
+ /* No damping so it behaves as if no tension spring was there at all. */
+ k_tension_damp = 0.0f;
+ }
+
+ if (k_compression == 0.0f) {
+ /* No damping so it behaves as if no compression spring was there at all. */
+ k_compression_damp = 0.0f;
+ }
+
+ BPH_mass_spring_force_spring_linear(data,
+ s->ij,
+ s->kl,
+ s->restlen,
+ k_tension,
+ k_tension_damp,
+ k_compression,
+ k_compression_damp,
+ resist_compress,
+ using_angular,
+ 0.0f);
+ }
#endif
}
else if (s->type & CLOTH_SPRING_TYPE_SHEAR) {
@@ -526,6 +612,7 @@ static void cloth_calc_force(
{
/* Collect forces and derivatives: F, dFdX, dFdV */
Cloth *cloth = clmd->clothObject;
+ ClothSimSettings *parms = clmd->sim_parms;
Implicit_Data *data = cloth->implicit;
unsigned int i = 0;
float drag = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */
@@ -570,6 +657,78 @@ static void cloth_calc_force(
#ifdef CLOTH_FORCE_DRAG
BPH_mass_spring_force_drag(data, drag);
#endif
+ /* handle pressure forces */
+ if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) {
+ /* The difference in pressure between the inside and outside of the mesh.*/
+ float pressure_difference = 0.0f;
+
+ float init_vol;
+ if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE_VOL) {
+ init_vol = clmd->sim_parms->target_volume;
+ }
+ else {
+ init_vol = cloth->initial_mesh_volume;
+ }
+
+ /* Check if we need to calculate the volume of the mesh. */
+ if (init_vol > 1E-6f) {
+ float f;
+ float vol = cloth_calc_volume(clmd);
+
+ /* Calculate an artifical maximum value for cloth pressure. */
+ f = fabs(clmd->sim_parms->uniform_pressure_force) + 200.0f;
+
+ /* Clamp the cloth pressure to the calculated maximum value. */
+ if (vol * f < init_vol) {
+ pressure_difference = f;
+ }
+ else {
+ /* If the volume is the same don't apply any pressure. */
+ pressure_difference = (init_vol / vol) - 1;
+ }
+ }
+ pressure_difference += clmd->sim_parms->uniform_pressure_force;
+
+ pressure_difference *= clmd->sim_parms->pressure_factor;
+
+ for (i = 0; i < cloth->tri_num; i++) {
+ const MVertTri *vt = &tri[i];
+ if (fabs(pressure_difference) > 1E-6f) {
+ if (clmd->sim_parms->vgroup_pressure > 0) {
+ /* We have custom vertex weights for pressure. */
+ ClothVertex *verts = clmd->clothObject->verts;
+ int v1, v2, v3;
+ v1 = vt->tri[0];
+ v2 = vt->tri[1];
+ v3 = vt->tri[2];
+
+ float weights[3];
+ bool skip_face = false;
+
+ weights[0] = verts[v1].pressure_factor;
+ weights[1] = verts[v2].pressure_factor;
+ weights[2] = verts[v3].pressure_factor;
+ for (unsigned int j = 0; j < 3; j++) {
+ if (weights[j] == 0.0f) {
+ /* Exclude faces which has a zero weight vert. */
+ skip_face = true;
+ break;
+ }
+ }
+ if (skip_face) {
+ continue;
+ }
+
+ BPH_mass_spring_force_pressure(data, v1, v2, v3, pressure_difference, weights);
+ }
+ else {
+ float weights[3] = {1.0f, 1.0f, 1.0f};
+ BPH_mass_spring_force_pressure(
+ data, vt->tri[0], vt->tri[1], vt->tri[2], pressure_difference, weights);
+ }
+ }
+ }
+ }
/* handle external forces like wind */
if (effectors) {
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
index 32416fa01ab..490e727b5f2 100644
--- a/source/blender/physics/intern/implicit.h
+++ b/source/blender/physics/intern/implicit.h
@@ -182,6 +182,15 @@ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data,
float stiffness,
float damping);
+float BPH_tri_tetra_volume_signed_6x(struct Implicit_Data *data, int v1, int v2, int v3);
+
+void BPH_mass_spring_force_pressure(struct Implicit_Data *data,
+ int v1,
+ int v2,
+ int v3,
+ float pressure_difference,
+ float weights[3]);
+
/* ======== Hair Volumetric Forces ======== */
struct HairGrid;
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index d8b3f647591..fd9903baa41 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -1455,7 +1455,7 @@ static float calc_nor_area_tri(float nor[3],
sub_v3_v3v3(n2, v2, v3);
cross_v3_v3v3(nor, n1, n2);
- return normalize_v3(nor);
+ return normalize_v3(nor) / 2.0f;
}
/* XXX does not support force jacobians yet, since the effector system does not provide them either
@@ -1469,6 +1469,7 @@ void BPH_mass_spring_force_face_wind(
/* calculate face normal and area */
area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]);
+ /* The force is calculated and split up evenly for each of the three face verts */
factor = effector_scale * area / 3.0f;
world_to_root_v3(data, v1, win, winvec[v1]);
@@ -1481,6 +1482,29 @@ void BPH_mass_spring_force_face_wind(
madd_v3_v3fl(data->F[v3], nor, factor * dot_v3v3(win, nor));
}
+float BPH_tri_tetra_volume_signed_6x(Implicit_Data *data, int v1, int v2, int v3)
+{
+ /* The result will be 6x the volume */
+ return volume_tri_tetrahedron_signed_v3_6x(data->X[v1], data->X[v2], data->X[v3]);
+}
+
+void BPH_mass_spring_force_pressure(
+ Implicit_Data *data, int v1, int v2, int v3, float pressure_difference, float weights[3])
+{
+ float nor[3], area;
+ float factor;
+
+ /* calculate face normal and area */
+ area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]);
+ /* The force is calculated and split up evenly for each of the three face verts */
+ factor = pressure_difference * area / 3.0f;
+
+ /* add pressure to each of the face verts */
+ madd_v3_v3fl(data->F[v1], nor, factor * weights[0]);
+ madd_v3_v3fl(data->F[v2], nor, factor * weights[1]);
+ madd_v3_v3fl(data->F[v3], nor, factor * weights[2]);
+}
+
static void edge_wind_vertex(const float dir[3],
float length,
float radius,
diff --git a/source/blender/physics/intern/implicit_eigen.cpp b/source/blender/physics/intern/implicit_eigen.cpp
index 9e1c03638d7..b801e851b90 100644
--- a/source/blender/physics/intern/implicit_eigen.cpp
+++ b/source/blender/physics/intern/implicit_eigen.cpp
@@ -830,7 +830,7 @@ static float calc_nor_area_tri(float nor[3],
sub_v3_v3v3(n2, v2, v3);
cross_v3_v3v3(nor, n1, n2);
- return normalize_v3(nor);
+ return normalize_v3(nor) / 2.0f;
}
/* XXX does not support force jacobians yet,
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 11c06f6191e..be2fd6c4e53 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -85,6 +85,12 @@ bool BPY_execute_string_as_intptr(struct bContext *C,
const char *expr,
const bool verbose,
intptr_t *r_value);
+bool BPY_execute_string_as_string_and_size(struct bContext *C,
+ const char *imports[],
+ const char *expr,
+ const bool verbose,
+ char **r_value,
+ size_t *r_value_size);
bool BPY_execute_string_as_string(struct bContext *C,
const char *imports[],
const char *expr,
diff --git a/source/blender/python/bmesh/bmesh_py_ops.c b/source/blender/python/bmesh/bmesh_py_ops.c
index b6ba119f695..a3bfe791c88 100644
--- a/source/blender/python/bmesh/bmesh_py_ops.c
+++ b/source/blender/python/bmesh/bmesh_py_ops.c
@@ -154,7 +154,7 @@ static PyObject *bpy_bmesh_op_doc_get(BPy_BMeshOpFunc *self, void *UNUSED(closur
}
static PyGetSetDef bpy_bmesh_op_getseters[] = {
- {(char *)"__doc__", (getter)bpy_bmesh_op_doc_get, (setter)NULL, NULL, NULL},
+ {"__doc__", (getter)bpy_bmesh_op_doc_get, (setter)NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index af595de2ee4..73107ebc16c 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -613,264 +613,232 @@ static int bpy_bmfaceseq_active_set(BPy_BMElem *self, PyObject *value, void *UNU
}
static PyGetSetDef bpy_bmesh_getseters[] = {
- {(char *)"verts", (getter)bpy_bmvertseq_get, (setter)NULL, (char *)bpy_bmvertseq_doc, NULL},
- {(char *)"edges", (getter)bpy_bmedgeseq_get, (setter)NULL, (char *)bpy_bmedgeseq_doc, NULL},
- {(char *)"faces", (getter)bpy_bmfaceseq_get, (setter)NULL, (char *)bpy_bmfaceseq_doc, NULL},
- {(char *)"loops", (getter)bpy_bmloopseq_get, (setter)NULL, (char *)bpy_bmloopseq_doc, NULL},
- {(char *)"select_mode",
+ {"verts", (getter)bpy_bmvertseq_get, (setter)NULL, bpy_bmvertseq_doc, NULL},
+ {"edges", (getter)bpy_bmedgeseq_get, (setter)NULL, bpy_bmedgeseq_doc, NULL},
+ {"faces", (getter)bpy_bmfaceseq_get, (setter)NULL, bpy_bmfaceseq_doc, NULL},
+ {"loops", (getter)bpy_bmloopseq_get, (setter)NULL, bpy_bmloopseq_doc, NULL},
+ {"select_mode",
(getter)bpy_bmesh_select_mode_get,
(setter)bpy_bmesh_select_mode_set,
- (char *)bpy_bmesh_select_mode_doc,
+ bpy_bmesh_select_mode_doc,
NULL},
- {(char *)"select_history",
+ {"select_history",
(getter)bpy_bmesh_select_history_get,
(setter)bpy_bmesh_select_history_set,
- (char *)bpy_bmesh_select_history_doc,
+ bpy_bmesh_select_history_doc,
NULL},
/* readonly checks */
- {(char *)"is_wrapped",
+ {"is_wrapped",
(getter)bpy_bmesh_is_wrapped_get,
(setter)NULL,
- (char *)bpy_bmesh_is_wrapped_doc,
+ bpy_bmesh_is_wrapped_doc,
NULL}, /* as with mathutils */
- {(char *)"is_valid",
- (getter)bpy_bm_is_valid_get,
- (setter)NULL,
- (char *)bpy_bm_is_valid_doc,
- NULL},
+ {"is_valid", (getter)bpy_bm_is_valid_get, (setter)NULL, bpy_bm_is_valid_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static PyGetSetDef bpy_bmvert_getseters[] = {
/* generic */
- {(char *)"select",
+ {"select",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_select_doc,
+ bpy_bm_elem_select_doc,
(void *)BM_ELEM_SELECT},
- {(char *)"hide",
+ {"hide",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_hide_doc,
+ bpy_bm_elem_hide_doc,
(void *)BM_ELEM_HIDDEN},
- {(char *)"tag",
+ {"tag",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_tag_doc,
+ bpy_bm_elem_tag_doc,
(void *)BM_ELEM_TAG},
- {(char *)"index",
+ {"index",
(getter)bpy_bm_elem_index_get,
(setter)bpy_bm_elem_index_set,
- (char *)bpy_bm_elem_index_doc,
+ bpy_bm_elem_index_doc,
NULL},
- {(char *)"co",
- (getter)bpy_bmvert_co_get,
- (setter)bpy_bmvert_co_set,
- (char *)bpy_bmvert_co_doc,
- NULL},
- {(char *)"normal",
+ {"co", (getter)bpy_bmvert_co_get, (setter)bpy_bmvert_co_set, bpy_bmvert_co_doc, NULL},
+ {"normal",
(getter)bpy_bmvert_normal_get,
(setter)bpy_bmvert_normal_set,
- (char *)bpy_bmvert_normal_doc,
+ bpy_bmvert_normal_doc,
NULL},
/* connectivity data */
- {(char *)"link_edges",
+ {"link_edges",
(getter)bpy_bmelemseq_elem_get,
(setter)NULL,
- (char *)bpy_bmvert_link_edges_doc,
+ bpy_bmvert_link_edges_doc,
(void *)BM_EDGES_OF_VERT},
- {(char *)"link_faces",
+ {"link_faces",
(getter)bpy_bmelemseq_elem_get,
(setter)NULL,
- (char *)bpy_bmvert_link_faces_doc,
+ bpy_bmvert_link_faces_doc,
(void *)BM_FACES_OF_VERT},
- {(char *)"link_loops",
+ {"link_loops",
(getter)bpy_bmelemseq_elem_get,
(setter)NULL,
- (char *)bpy_bmvert_link_loops_doc,
+ bpy_bmvert_link_loops_doc,
(void *)BM_LOOPS_OF_VERT},
/* readonly checks */
- {(char *)"is_manifold",
+ {"is_manifold",
(getter)bpy_bmvert_is_manifold_get,
(setter)NULL,
- (char *)bpy_bmvert_is_manifold_doc,
- NULL},
- {(char *)"is_wire",
- (getter)bpy_bmvert_is_wire_get,
- (setter)NULL,
- (char *)bpy_bmvert_is_wire_doc,
+ bpy_bmvert_is_manifold_doc,
NULL},
- {(char *)"is_boundary",
+ {"is_wire", (getter)bpy_bmvert_is_wire_get, (setter)NULL, bpy_bmvert_is_wire_doc, NULL},
+ {"is_boundary",
(getter)bpy_bmvert_is_boundary_get,
(setter)NULL,
- (char *)bpy_bmvert_is_boundary_doc,
- NULL},
- {(char *)"is_valid",
- (getter)bpy_bm_is_valid_get,
- (setter)NULL,
- (char *)bpy_bm_is_valid_doc,
+ bpy_bmvert_is_boundary_doc,
NULL},
+ {"is_valid", (getter)bpy_bm_is_valid_get, (setter)NULL, bpy_bm_is_valid_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static PyGetSetDef bpy_bmedge_getseters[] = {
/* generic */
- {(char *)"select",
+ {"select",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_select_doc,
+ bpy_bm_elem_select_doc,
(void *)BM_ELEM_SELECT},
- {(char *)"hide",
+ {"hide",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_hide_doc,
+ bpy_bm_elem_hide_doc,
(void *)BM_ELEM_HIDDEN},
- {(char *)"tag",
+ {"tag",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_tag_doc,
+ bpy_bm_elem_tag_doc,
(void *)BM_ELEM_TAG},
- {(char *)"index",
+ {"index",
(getter)bpy_bm_elem_index_get,
(setter)bpy_bm_elem_index_set,
- (char *)bpy_bm_elem_index_doc,
+ bpy_bm_elem_index_doc,
NULL},
- {(char *)"smooth",
+ {"smooth",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_smooth_doc,
+ bpy_bm_elem_smooth_doc,
(void *)BM_ELEM_SMOOTH},
- {(char *)"seam",
+ {"seam",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_seam_doc,
+ bpy_bm_elem_seam_doc,
(void *)BM_ELEM_SEAM},
/* connectivity data */
- {(char *)"verts",
+ {"verts",
(getter)bpy_bmelemseq_elem_get,
(setter)NULL,
- (char *)bpy_bmedge_verts_doc,
+ bpy_bmedge_verts_doc,
(void *)BM_VERTS_OF_EDGE},
- {(char *)"link_faces",
+ {"link_faces",
(getter)bpy_bmelemseq_elem_get,
(setter)NULL,
- (char *)bpy_bmedge_link_faces_doc,
+ bpy_bmedge_link_faces_doc,
(void *)BM_FACES_OF_EDGE},
- {(char *)"link_loops",
+ {"link_loops",
(getter)bpy_bmelemseq_elem_get,
(setter)NULL,
- (char *)bpy_bmedge_link_loops_doc,
+ bpy_bmedge_link_loops_doc,
(void *)BM_LOOPS_OF_EDGE},
/* readonly checks */
- {(char *)"is_manifold",
+ {"is_manifold",
(getter)bpy_bmedge_is_manifold_get,
(setter)NULL,
- (char *)bpy_bmedge_is_manifold_doc,
+ bpy_bmedge_is_manifold_doc,
NULL},
- {(char *)"is_contiguous",
+ {"is_contiguous",
(getter)bpy_bmedge_is_contiguous_get,
(setter)NULL,
- (char *)bpy_bmedge_is_contiguous_doc,
+ bpy_bmedge_is_contiguous_doc,
NULL},
- {(char *)"is_convex",
- (getter)bpy_bmedge_is_convex_get,
- (setter)NULL,
- (char *)bpy_bmedge_is_convex_doc,
- NULL},
- {(char *)"is_wire",
- (getter)bpy_bmedge_is_wire_get,
- (setter)NULL,
- (char *)bpy_bmedge_is_wire_doc,
- NULL},
- {(char *)"is_boundary",
+ {"is_convex", (getter)bpy_bmedge_is_convex_get, (setter)NULL, bpy_bmedge_is_convex_doc, NULL},
+ {"is_wire", (getter)bpy_bmedge_is_wire_get, (setter)NULL, bpy_bmedge_is_wire_doc, NULL},
+ {"is_boundary",
(getter)bpy_bmedge_is_boundary_get,
(setter)NULL,
- (char *)bpy_bmedge_is_boundary_doc,
- NULL},
- {(char *)"is_valid",
- (getter)bpy_bm_is_valid_get,
- (setter)NULL,
- (char *)bpy_bm_is_valid_doc,
+ bpy_bmedge_is_boundary_doc,
NULL},
+ {"is_valid", (getter)bpy_bm_is_valid_get, (setter)NULL, bpy_bm_is_valid_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static PyGetSetDef bpy_bmface_getseters[] = {
/* generic */
- {(char *)"select",
+ {"select",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_select_doc,
+ bpy_bm_elem_select_doc,
(void *)BM_ELEM_SELECT},
- {(char *)"hide",
+ {"hide",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_hide_doc,
+ bpy_bm_elem_hide_doc,
(void *)BM_ELEM_HIDDEN},
- {(char *)"tag",
+ {"tag",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_tag_doc,
+ bpy_bm_elem_tag_doc,
(void *)BM_ELEM_TAG},
- {(char *)"index",
+ {"index",
(getter)bpy_bm_elem_index_get,
(setter)bpy_bm_elem_index_set,
- (char *)bpy_bm_elem_index_doc,
+ bpy_bm_elem_index_doc,
NULL},
- {(char *)"smooth",
+ {"smooth",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_smooth_doc,
+ bpy_bm_elem_smooth_doc,
(void *)BM_ELEM_SMOOTH},
- {(char *)"normal",
+ {"normal",
(getter)bpy_bmface_normal_get,
(setter)bpy_bmface_normal_set,
- (char *)bpy_bmface_normal_doc,
+ bpy_bmface_normal_doc,
NULL},
- {(char *)"material_index",
+ {"material_index",
(getter)bpy_bmface_material_index_get,
(setter)bpy_bmface_material_index_set,
- (char *)bpy_bmface_material_index_doc,
+ bpy_bmface_material_index_doc,
NULL},
/* connectivity data */
- {(char *)"verts",
+ {"verts",
(getter)bpy_bmelemseq_elem_get,
(setter)NULL,
- (char *)bpy_bmface_verts_doc,
+ bpy_bmface_verts_doc,
(void *)BM_VERTS_OF_FACE},
- {(char *)"edges",
+ {"edges",
(getter)bpy_bmelemseq_elem_get,
(setter)NULL,
- (char *)bpy_bmface_edges_doc,
+ bpy_bmface_edges_doc,
(void *)BM_EDGES_OF_FACE},
- {(char *)"loops",
+ {"loops",
(getter)bpy_bmelemseq_elem_get,
(setter)NULL,
- (char *)bpy_bmface_loops_doc,
+ bpy_bmface_loops_doc,
(void *)BM_LOOPS_OF_FACE},
/* readonly checks */
- {(char *)"is_valid",
- (getter)bpy_bm_is_valid_get,
- (setter)NULL,
- (char *)bpy_bm_is_valid_doc,
- NULL},
+ {"is_valid", (getter)bpy_bm_is_valid_get, (setter)NULL, bpy_bm_is_valid_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -879,109 +847,101 @@ static PyGetSetDef bpy_bmloop_getseters[] = {
/* generic */
/* flags are available but not used for loops. */
#if 0
- {(char *)"select",
+ {"select",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_select_doc,
+ bpy_bm_elem_select_doc,
(void *)BM_ELEM_SELECT},
- {(char *)"hide",
+ {"hide",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_hide_doc,
+ bpy_bm_elem_hide_doc,
(void *)BM_ELEM_HIDDEN},
#endif
- {(char *)"tag",
+ {"tag",
(getter)bpy_bm_elem_hflag_get,
(setter)bpy_bm_elem_hflag_set,
- (char *)bpy_bm_elem_tag_doc,
+ bpy_bm_elem_tag_doc,
(void *)BM_ELEM_TAG},
- {(char *)"index",
+ {"index",
(getter)bpy_bm_elem_index_get,
(setter)bpy_bm_elem_index_set,
- (char *)bpy_bm_elem_index_doc,
+ bpy_bm_elem_index_doc,
NULL},
- {(char *)"vert", (getter)bpy_bmloop_vert_get, (setter)NULL, (char *)bpy_bmloop_vert_doc, NULL},
- {(char *)"edge", (getter)bpy_bmloop_edge_get, (setter)NULL, (char *)bpy_bmloop_edge_doc, NULL},
- {(char *)"face", (getter)bpy_bmloop_face_get, (setter)NULL, (char *)bpy_bmloop_face_doc, NULL},
+ {"vert", (getter)bpy_bmloop_vert_get, (setter)NULL, bpy_bmloop_vert_doc, NULL},
+ {"edge", (getter)bpy_bmloop_edge_get, (setter)NULL, bpy_bmloop_edge_doc, NULL},
+ {"face", (getter)bpy_bmloop_face_get, (setter)NULL, bpy_bmloop_face_doc, NULL},
/* connectivity data */
- {(char *)"link_loops",
+ {"link_loops",
(getter)bpy_bmelemseq_elem_get,
(setter)NULL,
- (char *)bpy_bmloops_link_loops_doc,
+ bpy_bmloops_link_loops_doc,
(void *)BM_LOOPS_OF_LOOP},
- {(char *)"link_loop_next",
+ {"link_loop_next",
(getter)bpy_bmloop_link_loop_next_get,
(setter)NULL,
- (char *)bpy_bmloop_link_loop_next_doc,
+ bpy_bmloop_link_loop_next_doc,
NULL},
- {(char *)"link_loop_prev",
+ {"link_loop_prev",
(getter)bpy_bmloop_link_loop_prev_get,
(setter)NULL,
- (char *)bpy_bmloop_link_loop_prev_doc,
+ bpy_bmloop_link_loop_prev_doc,
NULL},
- {(char *)"link_loop_radial_next",
+ {"link_loop_radial_next",
(getter)bpy_bmloop_link_loop_radial_next_get,
(setter)NULL,
- (char *)bpy_bmloop_link_loop_radial_next_doc,
+ bpy_bmloop_link_loop_radial_next_doc,
NULL},
- {(char *)"link_loop_radial_prev",
+ {"link_loop_radial_prev",
(getter)bpy_bmloop_link_loop_radial_prev_get,
(setter)NULL,
- (char *)bpy_bmloop_link_loop_radial_prev_doc,
+ bpy_bmloop_link_loop_radial_prev_doc,
NULL},
/* readonly checks */
- {(char *)"is_convex",
- (getter)bpy_bmloop_is_convex_get,
- (setter)NULL,
- (char *)bpy_bmloop_is_convex_doc,
- NULL},
- {(char *)"is_valid",
- (getter)bpy_bm_is_valid_get,
- (setter)NULL,
- (char *)bpy_bm_is_valid_doc,
- NULL},
+ {"is_convex", (getter)bpy_bmloop_is_convex_get, (setter)NULL, bpy_bmloop_is_convex_doc, NULL},
+ {"is_valid", (getter)bpy_bm_is_valid_get, (setter)NULL, bpy_bm_is_valid_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static PyGetSetDef bpy_bmvertseq_getseters[] = {
- {(char *)"layers",
+ {"layers",
(getter)bpy_bmelemseq_layers_get,
(setter)NULL,
- (char *)bpy_bmelemseq_layers_vert_doc,
+ bpy_bmelemseq_layers_vert_doc,
(void *)BM_VERT},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static PyGetSetDef bpy_bmedgeseq_getseters[] = {
- {(char *)"layers",
+ {"layers",
(getter)bpy_bmelemseq_layers_get,
(setter)NULL,
- (char *)bpy_bmelemseq_layers_edge_doc,
+ bpy_bmelemseq_layers_edge_doc,
(void *)BM_EDGE},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static PyGetSetDef bpy_bmfaceseq_getseters[] = {
- {(char *)"layers",
+ {"layers",
(getter)bpy_bmelemseq_layers_get,
(setter)NULL,
- (char *)bpy_bmelemseq_layers_face_doc,
+ bpy_bmelemseq_layers_face_doc,
(void *)BM_FACE},
/* face only */
- {(char *)"active",
+ {"active",
(getter)bpy_bmfaceseq_active_get,
(setter)bpy_bmfaceseq_active_set,
- (char *)bpy_bmfaceseq_active_doc,
+ bpy_bmfaceseq_active_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static PyGetSetDef bpy_bmloopseq_getseters[] = {
- {(char *)"layers",
+ {"layers",
(getter)bpy_bmelemseq_layers_get,
(setter)NULL,
- (char *)bpy_bmelemseq_layers_loop_doc,
+ bpy_bmelemseq_layers_loop_doc,
(void *)BM_LOOP},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -1091,7 +1051,9 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
bm = self->bm;
struct Main *bmain = NULL;
- struct BMeshToMeshParams params = {0};
+ struct BMeshToMeshParams params = {
+ .update_shapekey_indices = true,
+ };
if (me->id.tag & LIB_TAG_NO_MAIN) {
/* Mesh might be coming from a self-contained source like object.to_mesh(). No need to remap
* anything in this case. */
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index a7f4e30b494..ce700849cf3 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -174,84 +174,84 @@ static PyObject *bpy_bmlayeritem_name_get(BPy_BMLayerItem *self, void *UNUSED(fl
}
static PyGetSetDef bpy_bmlayeraccess_vert_getseters[] = {
- {(char *)"deform",
+ {"deform",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__deform_doc,
+ bpy_bmlayeraccess_collection__deform_doc,
(void *)CD_MDEFORMVERT},
- {(char *)"float",
+ {"float",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__float_doc,
+ bpy_bmlayeraccess_collection__float_doc,
(void *)CD_PROP_FLT},
- {(char *)"int",
+ {"int",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__int_doc,
+ bpy_bmlayeraccess_collection__int_doc,
(void *)CD_PROP_INT},
- {(char *)"string",
+ {"string",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__string_doc,
+ bpy_bmlayeraccess_collection__string_doc,
(void *)CD_PROP_STR},
- {(char *)"shape",
+ {"shape",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__shape_doc,
+ bpy_bmlayeraccess_collection__shape_doc,
(void *)CD_SHAPEKEY},
- {(char *)"bevel_weight",
+ {"bevel_weight",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__bevel_weight_doc,
+ bpy_bmlayeraccess_collection__bevel_weight_doc,
(void *)CD_BWEIGHT},
- {(char *)"skin",
+ {"skin",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__skin_doc,
+ bpy_bmlayeraccess_collection__skin_doc,
(void *)CD_MVERT_SKIN},
- {(char *)"paint_mask",
+ {"paint_mask",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__paint_mask_doc,
+ bpy_bmlayeraccess_collection__paint_mask_doc,
(void *)CD_PAINT_MASK},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static PyGetSetDef bpy_bmlayeraccess_edge_getseters[] = {
- {(char *)"float",
+ {"float",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__float_doc,
+ bpy_bmlayeraccess_collection__float_doc,
(void *)CD_PROP_FLT},
- {(char *)"int",
+ {"int",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__int_doc,
+ bpy_bmlayeraccess_collection__int_doc,
(void *)CD_PROP_INT},
- {(char *)"string",
+ {"string",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__string_doc,
+ bpy_bmlayeraccess_collection__string_doc,
(void *)CD_PROP_STR},
- {(char *)"bevel_weight",
+ {"bevel_weight",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__bevel_weight_doc,
+ bpy_bmlayeraccess_collection__bevel_weight_doc,
(void *)CD_BWEIGHT},
- {(char *)"crease",
+ {"crease",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__crease_doc,
+ bpy_bmlayeraccess_collection__crease_doc,
(void *)CD_CREASE},
#ifdef WITH_FREESTYLE
- {(char *)"freestyle",
+ {"freestyle",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__freestyle_edge_doc,
+ bpy_bmlayeraccess_collection__freestyle_edge_doc,
(void *)CD_FREESTYLE_EDGE},
#endif
@@ -259,32 +259,32 @@ static PyGetSetDef bpy_bmlayeraccess_edge_getseters[] = {
};
static PyGetSetDef bpy_bmlayeraccess_face_getseters[] = {
- {(char *)"float",
+ {"float",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__float_doc,
+ bpy_bmlayeraccess_collection__float_doc,
(void *)CD_PROP_FLT},
- {(char *)"int",
+ {"int",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__int_doc,
+ bpy_bmlayeraccess_collection__int_doc,
(void *)CD_PROP_INT},
- {(char *)"string",
+ {"string",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__string_doc,
+ bpy_bmlayeraccess_collection__string_doc,
(void *)CD_PROP_STR},
- {(char *)"face_map",
+ {"face_map",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__face_map_doc,
+ bpy_bmlayeraccess_collection__face_map_doc,
(void *)CD_FACEMAP},
#ifdef WITH_FREESTYLE
- {(char *)"freestyle",
+ {"freestyle",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__freestyle_face_doc,
+ bpy_bmlayeraccess_collection__freestyle_face_doc,
(void *)CD_FREESTYLE_FACE},
#endif
@@ -292,31 +292,31 @@ static PyGetSetDef bpy_bmlayeraccess_face_getseters[] = {
};
static PyGetSetDef bpy_bmlayeraccess_loop_getseters[] = {
- {(char *)"float",
+ {"float",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__float_doc,
+ bpy_bmlayeraccess_collection__float_doc,
(void *)CD_PROP_FLT},
- {(char *)"int",
+ {"int",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__int_doc,
+ bpy_bmlayeraccess_collection__int_doc,
(void *)CD_PROP_INT},
- {(char *)"string",
+ {"string",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__string_doc,
+ bpy_bmlayeraccess_collection__string_doc,
(void *)CD_PROP_STR},
- {(char *)"uv",
+ {"uv",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__uv_doc,
+ bpy_bmlayeraccess_collection__uv_doc,
(void *)CD_MLOOPUV},
- {(char *)"color",
+ {"color",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
- (char *)bpy_bmlayeraccess_collection__color_doc,
+ bpy_bmlayeraccess_collection__color_doc,
(void *)CD_MLOOPCOL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
@@ -324,15 +324,15 @@ static PyGetSetDef bpy_bmlayeraccess_loop_getseters[] = {
static PyGetSetDef bpy_bmlayercollection_getseters[] = {
/* BMESH_TODO, make writeable */
- {(char *)"active",
+ {"active",
(getter)bpy_bmlayercollection_active_get,
(setter)NULL,
- (char *)bpy_bmlayercollection_active_doc,
+ bpy_bmlayercollection_active_doc,
NULL},
- {(char *)"is_singleton",
+ {"is_singleton",
(getter)bpy_bmlayercollection_is_singleton_get,
(setter)NULL,
- (char *)bpy_bmlayercollection_is_singleton_doc,
+ bpy_bmlayercollection_is_singleton_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
@@ -340,11 +340,7 @@ static PyGetSetDef bpy_bmlayercollection_getseters[] = {
static PyGetSetDef bpy_bmlayeritem_getseters[] = {
/* BMESH_TODO, make writeable */
- {(char *)"name",
- (getter)bpy_bmlayeritem_name_get,
- (setter)NULL,
- (char *)bpy_bmlayercollection_name_doc,
- NULL},
+ {"name", (getter)bpy_bmlayeritem_name_get, (setter)NULL, bpy_bmlayercollection_name_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
index 0fd6d74c324..08d934251af 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
@@ -99,25 +99,21 @@ static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag
static PyGetSetDef bpy_bmloopuv_getseters[] = {
/* attributes match rna_def_mloopuv */
- {(char *)"uv",
- (getter)bpy_bmloopuv_uv_get,
- (setter)bpy_bmloopuv_uv_set,
- (char *)bpy_bmloopuv_uv_doc,
- NULL},
- {(char *)"pin_uv",
+ {"uv", (getter)bpy_bmloopuv_uv_get, (setter)bpy_bmloopuv_uv_set, bpy_bmloopuv_uv_doc, NULL},
+ {"pin_uv",
(getter)bpy_bmloopuv_flag_get,
(setter)bpy_bmloopuv_flag_set,
- (char *)bpy_bmloopuv_flag__pin_uv_doc,
+ bpy_bmloopuv_flag__pin_uv_doc,
(void *)MLOOPUV_PINNED},
- {(char *)"select",
+ {"select",
(getter)bpy_bmloopuv_flag_get,
(setter)bpy_bmloopuv_flag_set,
- (char *)bpy_bmloopuv_flag__select_doc,
+ bpy_bmloopuv_flag__select_doc,
(void *)MLOOPUV_VERTSEL},
- {(char *)"select_edge",
+ {"select_edge",
(getter)bpy_bmloopuv_flag_get,
(setter)bpy_bmloopuv_flag_set,
- (char *)bpy_bmloopuv_flag__select_edge_doc,
+ bpy_bmloopuv_flag__select_edge_doc,
(void *)MLOOPUV_EDGESEL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
@@ -219,20 +215,20 @@ static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void *
static PyGetSetDef bpy_bmvertskin_getseters[] = {
/* attributes match rna_mesh_gen */
- {(char *)"radius",
+ {"radius",
(getter)bpy_bmvertskin_radius_get,
(setter)bpy_bmvertskin_radius_set,
- (char *)bpy_bmvertskin_radius_doc,
+ bpy_bmvertskin_radius_doc,
NULL},
- {(char *)"use_root",
+ {"use_root",
(getter)bpy_bmvertskin_flag_get,
(setter)bpy_bmvertskin_flag_set,
- (char *)bpy_bmvertskin_flag__use_root_doc,
+ bpy_bmvertskin_flag__use_root_doc,
(void *)MVERT_SKIN_ROOT},
- {(char *)"use_loose",
+ {"use_loose",
(getter)bpy_bmvertskin_flag_get,
(setter)bpy_bmvertskin_flag_set,
- (char *)bpy_bmvertskin_flag__use_loose_doc,
+ bpy_bmvertskin_flag__use_loose_doc,
(void *)MVERT_SKIN_LOOSE},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c
index 228874a86e3..dc0cf59d38c 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.c
+++ b/source/blender/python/bmesh/bmesh_py_types_select.c
@@ -57,10 +57,10 @@ static PyObject *bpy_bmeditselseq_active_get(BPy_BMEditSelSeq *self, void *UNUSE
}
static PyGetSetDef bpy_bmeditselseq_getseters[] = {
- {(char *)"active",
+ {"active",
(getter)bpy_bmeditselseq_active_get,
(setter)NULL,
- (char *)bpy_bmeditselseq_active_doc,
+ bpy_bmeditselseq_active_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 1b6466dee68..3f8ec826cc3 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -576,7 +576,7 @@ static PyMethodDef Buffer_methods[] = {
};
static PyGetSetDef Buffer_getseters[] = {
- {(char *)"dimensions", (getter)Buffer_dimensions, NULL, NULL, NULL},
+ {"dimensions", (getter)Buffer_dimensions, NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL},
};
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 1ea7795a0e3..ae9ffe4f3b8 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -267,10 +267,10 @@ static PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self)
#endif
static PyGetSetDef BPy_IDGroup_getseters[] = {
- {(char *)"name",
+ {"name",
(getter)BPy_IDGroup_GetName,
(setter)BPy_IDGroup_SetName,
- (char *)"The name of this Group.",
+ "The name of this Group.",
NULL},
{NULL, NULL, NULL, NULL, NULL},
};
@@ -1269,7 +1269,7 @@ static PyObject *BPy_IDArray_get_typecode(BPy_IDArray *self)
static PyGetSetDef BPy_IDArray_getseters[] = {
/* matches pythons array.typecode */
- {(char *)"typecode",
+ {"typecode",
(getter)BPy_IDArray_get_typecode,
(setter)NULL,
BPy_IDArray_get_typecode_doc,
diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c
index d35fc027f43..32fe522b84d 100644
--- a/source/blender/python/generic/imbuf_py_api.c
+++ b/source/blender/python/generic/imbuf_py_api.c
@@ -289,19 +289,15 @@ static PyObject *py_imbuf_channels_get(Py_ImBuf *self, void *UNUSED(closure))
}
static PyGetSetDef Py_ImBuf_getseters[] = {
- {(char *)"size", (getter)py_imbuf_size_get, (setter)NULL, (char *)py_imbuf_size_doc, NULL},
- {(char *)"ppm",
- (getter)py_imbuf_ppm_get,
- (setter)py_imbuf_ppm_set,
- (char *)py_imbuf_ppm_doc,
- NULL},
- {(char *)"filepath",
+ {"size", (getter)py_imbuf_size_get, (setter)NULL, py_imbuf_size_doc, NULL},
+ {"ppm", (getter)py_imbuf_ppm_get, (setter)py_imbuf_ppm_set, py_imbuf_ppm_doc, NULL},
+ {"filepath",
(getter)py_imbuf_filepath_get,
(setter)py_imbuf_filepath_set,
- (char *)py_imbuf_filepath_doc,
+ py_imbuf_filepath_doc,
NULL},
- {(char *)"planes", (getter)py_imbuf_planes_get, NULL, (char *)py_imbuf_planes_doc, NULL},
- {(char *)"channels", (getter)py_imbuf_channels_get, NULL, (char *)py_imbuf_channels_doc, NULL},
+ {"planes", (getter)py_imbuf_planes_get, NULL, py_imbuf_planes_doc, NULL},
+ {"channels", (getter)py_imbuf_channels_get, NULL, py_imbuf_channels_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 8470d1ccdf3..8ea627589f2 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -1257,10 +1257,11 @@ bool PyC_RunString_AsIntPtr(const char *imports[],
return ok;
}
-bool PyC_RunString_AsString(const char *imports[],
- const char *expr,
- const char *filename,
- char **r_value)
+bool PyC_RunString_AsStringAndSize(const char *imports[],
+ const char *expr,
+ const char *filename,
+ char **r_value,
+ size_t *r_value_size)
{
PyObject *py_dict, *retval;
bool ok = true;
@@ -1288,6 +1289,7 @@ bool PyC_RunString_AsString(const char *imports[],
char *val_alloc = MEM_mallocN(val_len + 1, __func__);
memcpy(val_alloc, val, val_len + 1);
*r_value = val_alloc;
+ *r_value_size = val_len;
}
Py_DECREF(retval);
@@ -1298,6 +1300,15 @@ bool PyC_RunString_AsString(const char *imports[],
return ok;
}
+bool PyC_RunString_AsString(const char *imports[],
+ const char *expr,
+ const char *filename,
+ char **r_value)
+{
+ size_t value_size;
+ return PyC_RunString_AsStringAndSize(imports, expr, filename, r_value, &value_size);
+}
+
#endif /* #ifndef MATH_STANDALONE */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 5be44ad1af6..5fb5737e1f9 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -119,6 +119,11 @@ bool PyC_RunString_AsIntPtr(const char **imports,
const char *expr,
const char *filename,
intptr_t *r_value);
+bool PyC_RunString_AsStringAndSize(const char **imports,
+ const char *expr,
+ const char *filename,
+ char **r_value,
+ size_t *r_value_size);
bool PyC_RunString_AsString(const char **imports,
const char *expr,
const char *filename,
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 6505e59624b..77dd4891e17 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -303,17 +303,13 @@ static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self)
}
static PyGetSetDef bpygpu_offscreen_getseters[] = {
- {(char *)"color_texture",
+ {"color_texture",
(getter)bpygpu_offscreen_color_texture_get,
(setter)NULL,
bpygpu_offscreen_color_texture_doc,
NULL},
- {(char *)"width",
- (getter)bpygpu_offscreen_width_get,
- (setter)NULL,
- bpygpu_offscreen_width_doc,
- NULL},
- {(char *)"height",
+ {"width", (getter)bpygpu_offscreen_width_get, (setter)NULL, bpygpu_offscreen_width_doc, NULL},
+ {"height",
(getter)bpygpu_offscreen_height_get,
(setter)NULL,
bpygpu_offscreen_height_doc,
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index 87091e311f3..bd52fbb0de5 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -578,11 +578,7 @@ static PyObject *bpygpu_shader_program_get(BPyGPUShader *self, void *UNUSED(clos
}
static PyGetSetDef bpygpu_shader_getseters[] = {
- {(char *)"program",
- (getter)bpygpu_shader_program_get,
- (setter)NULL,
- bpygpu_shader_program_doc,
- NULL},
+ {"program", (getter)bpygpu_shader_program_get, (setter)NULL, bpygpu_shader_program_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 880cc93649e..a2e7e5c2f34 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -33,6 +33,7 @@ set(INC
../../windowmanager
../../../../intern/clog
../../../../intern/guardedalloc
+ ../../../../intern/mantaflow/extern
../../../../intern/opencolorio
)
@@ -257,10 +258,6 @@ if(WITH_LIBMV)
add_definitions(-DWITH_LIBMV)
endif()
-if(WITH_MOD_FLUID)
- add_definitions(-DWITH_MOD_FLUID)
-endif()
-
if(WITH_MOD_OCEANSIM)
add_definitions(-DWITH_OCEANSIM)
endif()
@@ -269,8 +266,8 @@ if(WITH_MOD_REMESH)
add_definitions(-DWITH_MOD_REMESH)
endif()
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_FLUID)
+ add_definitions(-DWITH_FLUID)
endif()
if(WITH_OPENCOLLADA)
@@ -299,6 +296,10 @@ if(WITH_ALEMBIC)
)
endif()
+if(WITH_USD)
+ add_definitions(-DWITH_USD)
+endif()
+
if(WITH_OPENIMAGEIO)
add_definitions(-DWITH_OPENIMAGEIO)
list(APPEND INC
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index cbd57b28242..043b31007f1 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -81,49 +81,46 @@ extern char build_system[];
static PyTypeObject BlenderAppType;
static PyStructSequence_Field app_info_fields[] = {
- {(char *)"version", (char *)"The Blender version as a tuple of 3 numbers. eg. (2, 50, 11)"},
- {(char *)"version_string", (char *)"The Blender version formatted as a string"},
- {(char *)"version_char", (char *)"The Blender version character (for minor releases)"},
- {(char *)"version_cycle", (char *)"The release status of this build alpha/beta/rc/release"},
- {(char *)"binary_path",
- (char *)"The location of Blender's executable, useful for utilities that open new instances"},
- {(char *)"background",
- (char *)"Boolean, True when blender is running without a user interface (started with -b)"},
- {(char *)"factory_startup",
- (char *)"Boolean, True when blender is running with --factory-startup)"},
+ {"version", "The Blender version as a tuple of 3 numbers. eg. (2, 50, 11)"},
+ {"version_string", "The Blender version formatted as a string"},
+ {"version_char", "The Blender version character (for minor releases)"},
+ {"version_cycle", "The release status of this build alpha/beta/rc/release"},
+ {"binary_path",
+ "The location of Blender's executable, useful for utilities that open new instances"},
+ {"background",
+ "Boolean, True when blender is running without a user interface (started with -b)"},
+ {"factory_startup", "Boolean, True when blender is running with --factory-startup)"},
/* buildinfo */
- {(char *)"build_date", (char *)"The date this blender instance was built"},
- {(char *)"build_time", (char *)"The time this blender instance was built"},
- {(char *)"build_commit_timestamp",
- (char *)"The unix timestamp of commit this blender instance was built"},
- {(char *)"build_commit_date", (char *)"The date of commit this blender instance was built"},
- {(char *)"build_commit_time", (char *)"The time of commit this blender instance was built"},
- {(char *)"build_hash", (char *)"The commit hash this blender instance was built with"},
- {(char *)"build_branch", (char *)"The branch this blender instance was built from"},
- {(char *)"build_platform", (char *)"The platform this blender instance was built for"},
- {(char *)"build_type", (char *)"The type of build (Release, Debug)"},
- {(char *)"build_cflags", (char *)"C compiler flags"},
- {(char *)"build_cxxflags", (char *)"C++ compiler flags"},
- {(char *)"build_linkflags", (char *)"Binary linking flags"},
- {(char *)"build_system", (char *)"Build system used"},
+ {"build_date", "The date this blender instance was built"},
+ {"build_time", "The time this blender instance was built"},
+ {"build_commit_timestamp", "The unix timestamp of commit this blender instance was built"},
+ {"build_commit_date", "The date of commit this blender instance was built"},
+ {"build_commit_time", "The time of commit this blender instance was built"},
+ {"build_hash", "The commit hash this blender instance was built with"},
+ {"build_branch", "The branch this blender instance was built from"},
+ {"build_platform", "The platform this blender instance was built for"},
+ {"build_type", "The type of build (Release, Debug)"},
+ {"build_cflags", "C compiler flags"},
+ {"build_cxxflags", "C++ compiler flags"},
+ {"build_linkflags", "Binary linking flags"},
+ {"build_system", "Build system used"},
/* submodules */
- {(char *)"alembic", (char *)"Alembic library information backend"},
- {(char *)"ffmpeg", (char *)"FFmpeg library information backend"},
- {(char *)"ocio", (char *)"OpenColorIO library information backend"},
- {(char *)"oiio", (char *)"OpenImageIO library information backend"},
- {(char *)"opensubdiv", (char *)"OpenSubdiv library information backend"},
- {(char *)"openvdb", (char *)"OpenVDB library information backend"},
- {(char *)"sdl", (char *)"SDL library information backend"},
- {(char *)"build_options",
- (char *)"A set containing most important enabled optional build features"},
- {(char *)"handlers", (char *)"Application handler callbacks"},
- {(char *)"translations", (char *)"Application and addons internationalization API"},
+ {"alembic", "Alembic library information backend"},
+ {"ffmpeg", "FFmpeg library information backend"},
+ {"ocio", "OpenColorIO library information backend"},
+ {"oiio", "OpenImageIO library information backend"},
+ {"opensubdiv", "OpenSubdiv library information backend"},
+ {"openvdb", "OpenVDB library information backend"},
+ {"sdl", "SDL library information backend"},
+ {"build_options", "A set containing most important enabled optional build features"},
+ {"handlers", "Application handler callbacks"},
+ {"translations", "Application and addons internationalization API"},
/* Modules (not struct sequence). */
- {(char *)"icons", (char *)"Manage custom icons"},
- {(char *)"timers", (char *)"Manage timers"},
+ {"icons", "Manage custom icons"},
+ {"timers", "Manage timers"},
{NULL},
};
@@ -141,9 +138,9 @@ PyDoc_STRVAR(bpy_app_doc,
" bpy.app.translations.rst\n");
static PyStructSequence_Desc app_info_desc = {
- (char *)"bpy.app", /* name */
- bpy_app_doc, /* doc */
- app_info_fields, /* fields */
+ "bpy.app", /* name */
+ bpy_app_doc, /* doc */
+ app_info_fields, /* fields */
ARRAY_SIZE(app_info_fields) - 1,
};
@@ -416,145 +413,125 @@ static int bpy_app_use_override_library_set(PyObject *UNUSED(self),
}
static PyGetSetDef bpy_app_getsets[] = {
- {(char *)"debug",
+ {"debug", bpy_app_debug_get, bpy_app_debug_set, bpy_app_debug_doc, (void *)G_DEBUG},
+ {"debug_ffmpeg",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
- (void *)G_DEBUG},
- {(char *)"debug_ffmpeg",
- bpy_app_debug_get,
- bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_FFMPEG},
- {(char *)"debug_freestyle",
+ {"debug_freestyle",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_FREESTYLE},
- {(char *)"debug_python",
+ {"debug_python",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_PYTHON},
- {(char *)"debug_events",
+ {"debug_events",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_EVENTS},
- {(char *)"debug_handlers",
+ {"debug_handlers",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_HANDLERS},
- {(char *)"debug_wm",
- bpy_app_debug_get,
- bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
- (void *)G_DEBUG_WM},
- {(char *)"debug_depsgraph",
+ {"debug_wm", bpy_app_debug_get, bpy_app_debug_set, bpy_app_debug_doc, (void *)G_DEBUG_WM},
+ {"debug_depsgraph",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_DEPSGRAPH},
- {(char *)"debug_depsgraph_build",
+ {"debug_depsgraph_build",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_DEPSGRAPH_BUILD},
- {(char *)"debug_depsgraph_eval",
+ {"debug_depsgraph_eval",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_DEPSGRAPH_EVAL},
- {(char *)"debug_depsgraph_tag",
+ {"debug_depsgraph_tag",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_DEPSGRAPH_TAG},
- {(char *)"debug_depsgraph_time",
+ {"debug_depsgraph_time",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_DEPSGRAPH_TIME},
- {(char *)"debug_depsgraph_pretty",
+ {"debug_depsgraph_pretty",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_DEPSGRAPH_PRETTY},
- {(char *)"debug_simdata",
+ {"debug_simdata",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_SIMDATA},
- {(char *)"debug_gpumem",
+ {"debug_gpumem",
bpy_app_debug_get,
bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
+ bpy_app_debug_doc,
(void *)G_DEBUG_GPU_MEM},
- {(char *)"debug_io",
- bpy_app_debug_get,
- bpy_app_debug_set,
- (char *)bpy_app_debug_doc,
- (void *)G_DEBUG_IO},
+ {"debug_io", bpy_app_debug_get, bpy_app_debug_set, bpy_app_debug_doc, (void *)G_DEBUG_IO},
- {(char *)"use_override_library",
+ {"use_override_library",
bpy_app_use_override_library_get,
bpy_app_use_override_library_set,
- (char *)bpy_app_use_override_library_doc,
+ bpy_app_use_override_library_doc,
NULL},
- {(char *)"use_event_simulate",
+ {"use_event_simulate",
bpy_app_global_flag_get,
bpy_app_global_flag_set__only_disable,
- (char *)bpy_app_global_flag_doc,
+ bpy_app_global_flag_doc,
(void *)G_FLAG_EVENT_SIMULATE},
- {(char *)"use_userpref_skip_save_on_exit",
+ {"use_userpref_skip_save_on_exit",
bpy_app_global_flag_get,
bpy_app_global_flag_set,
- (char *)bpy_app_global_flag_doc,
+ bpy_app_global_flag_doc,
(void *)G_FLAG_USERPREF_NO_SAVE_ON_EXIT},
- {(char *)"binary_path_python",
+ {"binary_path_python",
bpy_app_binary_path_python_get,
NULL,
- (char *)bpy_app_binary_path_python_doc,
+ bpy_app_binary_path_python_doc,
NULL},
- {(char *)"debug_value",
+ {"debug_value",
bpy_app_debug_value_get,
bpy_app_debug_value_set,
- (char *)bpy_app_debug_value_doc,
- NULL},
- {(char *)"tempdir", bpy_app_tempdir_get, NULL, (char *)bpy_app_tempdir_doc, NULL},
- {(char *)"driver_namespace",
- bpy_app_driver_dict_get,
- NULL,
- (char *)bpy_app_driver_dict_doc,
+ bpy_app_debug_value_doc,
NULL},
+ {"tempdir", bpy_app_tempdir_get, NULL, bpy_app_tempdir_doc, NULL},
+ {"driver_namespace", bpy_app_driver_dict_get, NULL, bpy_app_driver_dict_doc, NULL},
- {(char *)"render_icon_size",
+ {"render_icon_size",
bpy_app_preview_render_size_get,
NULL,
- (char *)bpy_app_preview_render_size_doc,
+ bpy_app_preview_render_size_doc,
(void *)ICON_SIZE_ICON},
- {(char *)"render_preview_size",
+ {"render_preview_size",
bpy_app_preview_render_size_get,
NULL,
- (char *)bpy_app_preview_render_size_doc,
+ bpy_app_preview_render_size_doc,
(void *)ICON_SIZE_PREVIEW},
/* security */
- {(char *)"autoexec_fail",
- bpy_app_global_flag_get,
- NULL,
- NULL,
- (void *)G_FLAG_SCRIPT_AUTOEXEC_FAIL},
- {(char *)"autoexec_fail_quiet",
+ {"autoexec_fail", bpy_app_global_flag_get, NULL, NULL, (void *)G_FLAG_SCRIPT_AUTOEXEC_FAIL},
+ {"autoexec_fail_quiet",
bpy_app_global_flag_get,
NULL,
NULL,
(void *)G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET},
- {(char *)"autoexec_fail_message", bpy_app_autoexec_fail_message_get, NULL, NULL, NULL},
+ {"autoexec_fail_message", bpy_app_autoexec_fail_message_get, NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL},
};
diff --git a/source/blender/python/intern/bpy_app_alembic.c b/source/blender/python/intern/bpy_app_alembic.c
index 6032e062d09..c02bb546553 100644
--- a/source/blender/python/intern/bpy_app_alembic.c
+++ b/source/blender/python/intern/bpy_app_alembic.c
@@ -35,16 +35,16 @@
static PyTypeObject BlenderAppABCType;
static PyStructSequence_Field app_alembic_info_fields[] = {
- {(char *)"supported", (char *)"Boolean, True when Blender is built with Alembic support"},
- {(char *)"version", (char *)"The Alembic version as a tuple of 3 numbers"},
- {(char *)"version_string", (char *)"The Alembic version formatted as a string"},
+ {"supported", "Boolean, True when Blender is built with Alembic support"},
+ {"version", "The Alembic version as a tuple of 3 numbers"},
+ {"version_string", "The Alembic version formatted as a string"},
{NULL},
};
static PyStructSequence_Desc app_alembic_info_desc = {
- (char *)"bpy.app.alembic", /* name */
- (char *)"This module contains information about Alembic blender is linked against", /* doc */
- app_alembic_info_fields, /* fields */
+ "bpy.app.alembic", /* name */
+ "This module contains information about Alembic blender is linked against", /* doc */
+ app_alembic_info_fields, /* fields */
ARRAY_SIZE(app_alembic_info_fields) - 1,
};
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index 4331662eb31..6ec67a504f3 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -28,46 +28,46 @@ static PyTypeObject BlenderAppBuildOptionsType;
static PyStructSequence_Field app_builtopts_info_fields[] = {
/* names mostly follow CMake options, lowercase, after WITH_ */
- {(char *)"bullet", NULL},
- {(char *)"codec_avi", NULL},
- {(char *)"codec_ffmpeg", NULL},
- {(char *)"codec_sndfile", NULL},
- {(char *)"compositor", NULL},
- {(char *)"cycles", NULL},
- {(char *)"cycles_osl", NULL},
- {(char *)"freestyle", NULL},
- {(char *)"image_cineon", NULL},
- {(char *)"image_dds", NULL},
- {(char *)"image_hdr", NULL},
- {(char *)"image_openexr", NULL},
- {(char *)"image_openjpeg", NULL},
- {(char *)"image_tiff", NULL},
- {(char *)"input_ndof", NULL},
- {(char *)"audaspace", NULL},
- {(char *)"international", NULL},
- {(char *)"openal", NULL},
- {(char *)"opensubdiv", NULL},
- {(char *)"sdl", NULL},
- {(char *)"sdl_dynload", NULL},
- {(char *)"jack", NULL},
- {(char *)"libmv", NULL},
- {(char *)"mod_fluid", NULL},
- {(char *)"mod_oceansim", NULL},
- {(char *)"mod_remesh", NULL},
- {(char *)"mod_smoke", NULL},
- {(char *)"collada", NULL},
- {(char *)"opencolorio", NULL},
- {(char *)"openmp", NULL},
- {(char *)"openvdb", NULL},
- {(char *)"alembic", NULL},
- {(char *)"openxr", NULL},
+ {"bullet", NULL},
+ {"codec_avi", NULL},
+ {"codec_ffmpeg", NULL},
+ {"codec_sndfile", NULL},
+ {"compositor", NULL},
+ {"cycles", NULL},
+ {"cycles_osl", NULL},
+ {"freestyle", NULL},
+ {"image_cineon", NULL},
+ {"image_dds", NULL},
+ {"image_hdr", NULL},
+ {"image_openexr", NULL},
+ {"image_openjpeg", NULL},
+ {"image_tiff", NULL},
+ {"input_ndof", NULL},
+ {"audaspace", NULL},
+ {"international", NULL},
+ {"openal", NULL},
+ {"opensubdiv", NULL},
+ {"sdl", NULL},
+ {"sdl_dynload", NULL},
+ {"jack", NULL},
+ {"libmv", NULL},
+ {"mod_oceansim", NULL},
+ {"mod_remesh", NULL},
+ {"collada", NULL},
+ {"opencolorio", NULL},
+ {"openmp", NULL},
+ {"openvdb", NULL},
+ {"alembic", NULL},
+ {"usd", NULL},
+ {"fluid", NULL},
+ {"openxr", NULL},
{NULL},
};
static PyStructSequence_Desc app_builtopts_info_desc = {
- (char *)"bpy.app.build_options", /* name */
- (char *)"This module contains information about options blender is built with", /* doc */
- app_builtopts_info_fields, /* fields */
+ "bpy.app.build_options", /* name */
+ "This module contains information about options blender is built with", /* doc */
+ app_builtopts_info_fields, /* fields */
ARRAY_SIZE(app_builtopts_info_fields) - 1,
};
@@ -222,55 +222,55 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
-#ifdef WITH_MOD_FLUID
+#ifdef WITH_OCEANSIM
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
-#ifdef WITH_OCEANSIM
+#ifdef WITH_MOD_REMESH
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
-#ifdef WITH_MOD_REMESH
+#ifdef WITH_COLLADA
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
-#ifdef WITH_SMOKE
+#ifdef WITH_OCIO
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
-#ifdef WITH_COLLADA
+#ifdef _OPENMP
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
-#ifdef WITH_OCIO
+#ifdef WITH_OPENVDB
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
-#ifdef _OPENMP
+#ifdef WITH_ALEMBIC
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
-#ifdef WITH_OPENVDB
+#ifdef WITH_USD
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
-#ifdef WITH_ALEMBIC
+#ifdef WITH_FLUID
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c
index d1aa7817538..7f12f7be7ab 100644
--- a/source/blender/python/intern/bpy_app_ffmpeg.c
+++ b/source/blender/python/intern/bpy_app_ffmpeg.c
@@ -36,13 +36,13 @@
static PyTypeObject BlenderAppFFmpegType;
#define DEF_FFMPEG_LIB_VERSION(lib) \
- {(char *)(#lib "_version"), (char *)("The " #lib " version as a tuple of 3 numbers")}, \
+ {(#lib "_version"), ("The " #lib " version as a tuple of 3 numbers")}, \
{ \
- (char *)(#lib "_version_string"), (char *)("The " #lib " version formatted as a string") \
+ (#lib "_version_string"), ("The " #lib " version formatted as a string") \
}
static PyStructSequence_Field app_ffmpeg_info_fields[] = {
- {(char *)"supported", (char *)("Boolean, True when Blender is built with FFmpeg support")},
+ {"supported", "Boolean, True when Blender is built with FFmpeg support"},
DEF_FFMPEG_LIB_VERSION(avcodec),
DEF_FFMPEG_LIB_VERSION(avdevice),
@@ -55,9 +55,9 @@ static PyStructSequence_Field app_ffmpeg_info_fields[] = {
#undef DEF_FFMPEG_LIB_VERSION
static PyStructSequence_Desc app_ffmpeg_info_desc = {
- (char *)"bpy.app.ffmpeg", /* name */
- (char *)"This module contains information about FFmpeg blender is linked against", /* doc */
- app_ffmpeg_info_fields, /* fields */
+ "bpy.app.ffmpeg", /* name */
+ "This module contains information about FFmpeg blender is linked against", /* doc */
+ app_ffmpeg_info_fields, /* fields */
ARRAY_SIZE(app_ffmpeg_info_fields) - 1,
};
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index 2fbefe3be74..01618f0184a 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -44,42 +44,41 @@ void bpy_app_generic_callback(struct Main *main,
static PyTypeObject BlenderAppCbType;
static PyStructSequence_Field app_cb_info_fields[] = {
- {(char *)"frame_change_pre", (char *)"on frame change for playback and rendering (before)"},
- {(char *)"frame_change_post", (char *)"on frame change for playback and rendering (after)"},
- {(char *)"render_pre", (char *)"on render (before)"},
- {(char *)"render_post", (char *)"on render (after)"},
- {(char *)"render_write",
- (char *)"on writing a render frame (directly after the frame is written)"},
- {(char *)"render_stats", (char *)"on printing render statistics"},
- {(char *)"render_init", (char *)"on initialization of a render job"},
- {(char *)"render_complete", (char *)"on completion of render job"},
- {(char *)"render_cancel", (char *)"on canceling a render job"},
- {(char *)"load_pre", (char *)"on loading a new blend file (before)"},
- {(char *)"load_post", (char *)"on loading a new blend file (after)"},
- {(char *)"save_pre", (char *)"on saving a blend file (before)"},
- {(char *)"save_post", (char *)"on saving a blend file (after)"},
- {(char *)"undo_pre", (char *)"on loading an undo step (before)"},
- {(char *)"undo_post", (char *)"on loading an undo step (after)"},
- {(char *)"redo_pre", (char *)"on loading a redo step (before)"},
- {(char *)"redo_post", (char *)"on loading a redo step (after)"},
- {(char *)"depsgraph_update_pre", (char *)"on depsgraph update (pre)"},
- {(char *)"depsgraph_update_post", (char *)"on depsgraph update (post)"},
- {(char *)"version_update", (char *)"on ending the versioning code"},
- {(char *)"load_factory_preferences_post", (char *)"on loading factory preferences (after)"},
- {(char *)"load_factory_startup_post", (char *)"on loading factory startup (after)"},
+ {"frame_change_pre", "on frame change for playback and rendering (before)"},
+ {"frame_change_post", "on frame change for playback and rendering (after)"},
+ {"render_pre", "on render (before)"},
+ {"render_post", "on render (after)"},
+ {"render_write", "on writing a render frame (directly after the frame is written)"},
+ {"render_stats", "on printing render statistics"},
+ {"render_init", "on initialization of a render job"},
+ {"render_complete", "on completion of render job"},
+ {"render_cancel", "on canceling a render job"},
+ {"load_pre", "on loading a new blend file (before)"},
+ {"load_post", "on loading a new blend file (after)"},
+ {"save_pre", "on saving a blend file (before)"},
+ {"save_post", "on saving a blend file (after)"},
+ {"undo_pre", "on loading an undo step (before)"},
+ {"undo_post", "on loading an undo step (after)"},
+ {"redo_pre", "on loading a redo step (before)"},
+ {"redo_post", "on loading a redo step (after)"},
+ {"depsgraph_update_pre", "on depsgraph update (pre)"},
+ {"depsgraph_update_post", "on depsgraph update (post)"},
+ {"version_update", "on ending the versioning code"},
+ {"load_factory_preferences_post", "on loading factory preferences (after)"},
+ {"load_factory_startup_post", "on loading factory startup (after)"},
/* sets the permanent tag */
#define APP_CB_OTHER_FIELDS 1
- {(char *)"persistent",
- (char *)"Function decorator for callback functions not to be removed when loading new files"},
+ {"persistent",
+ "Function decorator for callback functions not to be removed when loading new files"},
{NULL},
};
static PyStructSequence_Desc app_cb_info_desc = {
- (char *)"bpy.app.handlers", /* name */
- (char *)"This module contains callback lists", /* doc */
- app_cb_info_fields, /* fields */
+ "bpy.app.handlers", /* name */
+ "This module contains callback lists", /* doc */
+ app_cb_info_fields, /* fields */
ARRAY_SIZE(app_cb_info_fields) - 1,
};
diff --git a/source/blender/python/intern/bpy_app_ocio.c b/source/blender/python/intern/bpy_app_ocio.c
index 9dcadbac2af..750fe93d1de 100644
--- a/source/blender/python/intern/bpy_app_ocio.c
+++ b/source/blender/python/intern/bpy_app_ocio.c
@@ -32,18 +32,17 @@
static PyTypeObject BlenderAppOCIOType;
static PyStructSequence_Field app_ocio_info_fields[] = {
- {(char *)"supported",
- (char *)("Boolean, True when Blender is built with OpenColorIO support")},
- {(char *)("version"), (char *)("The OpenColorIO version as a tuple of 3 numbers")},
- {(char *)("version_string"), (char *)("The OpenColorIO version formatted as a string")},
+ {"supported", "Boolean, True when Blender is built with OpenColorIO support"},
+ {"version", "The OpenColorIO version as a tuple of 3 numbers"},
+ {"version_string", "The OpenColorIO version formatted as a string"},
{NULL},
};
static PyStructSequence_Desc app_ocio_info_desc = {
/* name */
- (char *)"bpy.app.ocio",
+ "bpy.app.ocio",
/* doc */
- (char *)"This module contains information about OpenColorIO blender is linked against",
+ "This module contains information about OpenColorIO blender is linked against",
/* fields */
app_ocio_info_fields,
ARRAY_SIZE(app_ocio_info_fields) - 1,
diff --git a/source/blender/python/intern/bpy_app_oiio.c b/source/blender/python/intern/bpy_app_oiio.c
index 05c192f6e2e..44ffce2ad07 100644
--- a/source/blender/python/intern/bpy_app_oiio.c
+++ b/source/blender/python/intern/bpy_app_oiio.c
@@ -32,18 +32,16 @@
static PyTypeObject BlenderAppOIIOType;
static PyStructSequence_Field app_oiio_info_fields[] = {
- {(char *)"supported",
- (char *)("Boolean, True when Blender is built with OpenImageIO support")},
- {(char *)("version"), (char *)("The OpenImageIO version as a tuple of 3 numbers")},
- {(char *)("version_string"), (char *)("The OpenImageIO version formatted as a string")},
+ {"supported", "Boolean, True when Blender is built with OpenImageIO support"},
+ {"version", "The OpenImageIO version as a tuple of 3 numbers"},
+ {"version_string", "The OpenImageIO version formatted as a string"},
{NULL},
};
static PyStructSequence_Desc app_oiio_info_desc = {
- (char *)"bpy.app.oiio", /* name */
- (char
- *)"This module contains information about OpeImageIO blender is linked against", /* doc */
- app_oiio_info_fields, /* fields */
+ "bpy.app.oiio", /* name */
+ "This module contains information about OpeImageIO blender is linked against", /* doc */
+ app_oiio_info_fields, /* fields */
ARRAY_SIZE(app_oiio_info_fields) - 1,
};
diff --git a/source/blender/python/intern/bpy_app_opensubdiv.c b/source/blender/python/intern/bpy_app_opensubdiv.c
index e6e84ac30c0..2b3c2f18e43 100644
--- a/source/blender/python/intern/bpy_app_opensubdiv.c
+++ b/source/blender/python/intern/bpy_app_opensubdiv.c
@@ -32,17 +32,16 @@
static PyTypeObject BlenderAppOpenSubdivType;
static PyStructSequence_Field app_opensubdiv_info_fields[] = {
- {(char *)"supported", (char *)("Boolean, True when Blender is built with OpenSubdiv support")},
- {(char *)("version"), (char *)("The OpenSubdiv version as a tuple of 3 numbers")},
- {(char *)("version_string"), (char *)("The OpenSubdiv version formatted as a string")},
+ {"supported", "Boolean, True when Blender is built with OpenSubdiv support"},
+ {"version", "The OpenSubdiv version as a tuple of 3 numbers"},
+ {"version_string", "The OpenSubdiv version formatted as a string"},
{NULL},
};
static PyStructSequence_Desc app_opensubdiv_info_desc = {
- (char *)"bpy.app.opensubdiv", /* name */
- (char
- *)"This module contains information about OpenSubdiv blender is linked against", /* doc */
- app_opensubdiv_info_fields, /* fields */
+ "bpy.app.opensubdiv", /* name */
+ "This module contains information about OpenSubdiv blender is linked against", /* doc */
+ app_opensubdiv_info_fields, /* fields */
ARRAY_SIZE(app_opensubdiv_info_fields) - 1,
};
diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c
index a3d02294c07..80732b7fecb 100644
--- a/source/blender/python/intern/bpy_app_openvdb.c
+++ b/source/blender/python/intern/bpy_app_openvdb.c
@@ -35,16 +35,16 @@
static PyTypeObject BlenderAppOVDBType;
static PyStructSequence_Field app_openvdb_info_fields[] = {
- {(char *)"supported", (char *)("Boolean, True when Blender is built with OpenVDB support")},
- {(char *)("version"), (char *)("The OpenVDB version as a tuple of 3 numbers")},
- {(char *)("version_string"), (char *)("The OpenVDB version formatted as a string")},
+ {"supported", "Boolean, True when Blender is built with OpenVDB support"},
+ {"version", "The OpenVDB version as a tuple of 3 numbers"},
+ {"version_string", "The OpenVDB version formatted as a string"},
{NULL},
};
static PyStructSequence_Desc app_openvdb_info_desc = {
- (char *)"bpy.app.openvdb", /* name */
- (char *)"This module contains information about OpenVDB blender is linked against", /* doc */
- app_openvdb_info_fields, /* fields */
+ "bpy.app.openvdb", /* name */
+ "This module contains information about OpenVDB blender is linked against", /* doc */
+ app_openvdb_info_fields, /* fields */
ARRAY_SIZE(app_openvdb_info_fields) - 1,
};
diff --git a/source/blender/python/intern/bpy_app_sdl.c b/source/blender/python/intern/bpy_app_sdl.c
index 7e3d02076f2..1bc3d07473a 100644
--- a/source/blender/python/intern/bpy_app_sdl.c
+++ b/source/blender/python/intern/bpy_app_sdl.c
@@ -46,20 +46,20 @@
static PyTypeObject BlenderAppSDLType;
static PyStructSequence_Field app_sdl_info_fields[] = {
- {(char *)"supported", (char *)("Boolean, True when Blender is built with SDL support")},
- {(char *)"version", (char *)("The SDL version as a tuple of 3 numbers")},
- {(char *)"version_string", (char *)("The SDL version formatted as a string")},
- {(char *)"available",
- (char *)("Boolean, True when SDL is available. This is False when "
- "either *supported* is False, or *dynload* is True and "
- "Blender cannot find the correct library.")},
+ {"supported", ("Boolean, True when Blender is built with SDL support")},
+ {"version", ("The SDL version as a tuple of 3 numbers")},
+ {"version_string", ("The SDL version formatted as a string")},
+ {"available",
+ ("Boolean, True when SDL is available. This is False when "
+ "either *supported* is False, or *dynload* is True and "
+ "Blender cannot find the correct library.")},
{NULL},
};
static PyStructSequence_Desc app_sdl_info_desc = {
- (char *)"bpy.app.sdl", /* name */
- (char *)"This module contains information about SDL blender is linked against", /* doc */
- app_sdl_info_fields, /* fields */
+ "bpy.app.sdl", /* name */
+ "This module contains information about SDL blender is linked against", /* doc */
+ app_sdl_info_fields, /* fields */
ARRAY_SIZE(app_sdl_info_fields) - 1,
};
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index fffa43c1dcd..2e88a9ccca7 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -402,9 +402,9 @@ static BLT_i18n_contexts_descriptor _contexts[] = BLT_I18NCONTEXTS_DESC;
static PyStructSequence_Field app_translations_contexts_fields[ARRAY_SIZE(_contexts)] = {{NULL}};
static PyStructSequence_Desc app_translations_contexts_desc = {
- (char *)"bpy.app.translations.contexts", /* name */
- (char *)"This named tuple contains all pre-defined translation contexts", /* doc */
- app_translations_contexts_fields, /* fields */
+ "bpy.app.translations.contexts", /* name */
+ "This named tuple contains all pre-defined translation contexts", /* doc */
+ app_translations_contexts_fields, /* fields */
ARRAY_SIZE(app_translations_contexts_fields) - 1,
};
@@ -453,12 +453,12 @@ PyDoc_STRVAR(app_translations_contexts_C_to_py_doc,
"A readonly dict mapping contexts' C-identifiers to their py-identifiers.");
static PyMemberDef app_translations_members[] = {
- {(char *)"contexts",
+ {"contexts",
T_OBJECT_EX,
offsetof(BlenderAppTranslations, contexts),
READONLY,
app_translations_contexts_doc},
- {(char *)"contexts_C_to_py",
+ {"contexts_C_to_py",
T_OBJECT_EX,
offsetof(BlenderAppTranslations, contexts_C_to_py),
READONLY,
@@ -508,16 +508,8 @@ static PyObject *app_translations_locales_get(PyObject *UNUSED(self), void *UNUS
static PyGetSetDef app_translations_getseters[] = {
/* {name, getter, setter, doc, userdata} */
- {(char *)"locale",
- (getter)app_translations_locale_get,
- NULL,
- app_translations_locale_doc,
- NULL},
- {(char *)"locales",
- (getter)app_translations_locales_get,
- NULL,
- app_translations_locales_doc,
- NULL},
+ {"locale", (getter)app_translations_locale_get, NULL, app_translations_locale_doc, NULL},
+ {"locales", (getter)app_translations_locales_get, NULL, app_translations_locales_doc, NULL},
{NULL},
};
@@ -865,7 +857,7 @@ PyObject *BPY_app_translations_struct(void)
/* We really populate the contexts' fields here! */
for (ctxt = _contexts, desc = app_translations_contexts_desc.fields; ctxt->c_id;
ctxt++, desc++) {
- desc->name = (char *)ctxt->py_id;
+ desc->name = ctxt->py_id;
desc->doc = NULL;
}
desc->name = desc->doc = NULL; /* End sentinel! */
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index a69ce068aec..9acf05abfe2 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -197,8 +197,15 @@ void BPY_context_set(bContext *C)
BPy_SetContext(C);
}
+#ifdef WITH_FLUID
+/* defined in manta module */
+extern PyObject *Manta_initPython(void);
+#endif
+
+#ifdef WITH_AUDASPACE
/* defined in AUD_C-API.cpp */
extern PyObject *AUD_initPython(void);
+#endif
#ifdef WITH_CYCLES
/* defined in cycles module */
@@ -225,6 +232,9 @@ static struct _inittab bpy_internal_modules[] = {
{"bmesh.utils", BPyInit_bmesh_utils},
{"bmesh.utils", BPyInit_bmesh_geometry},
#endif
+#ifdef WITH_FLUID
+ {"manta", Manta_initPython},
+#endif
#ifdef WITH_AUDASPACE
{"aud", AUD_initPython},
#endif
@@ -285,6 +295,13 @@ void BPY_python_start(int argc, const char **argv)
/* Initialize thread support (also acquires lock) */
PyEval_InitThreads();
+
+# ifdef WITH_FLUID
+ /* Required to prevent assertion error, see:
+ * https://stackoverflow.com/questions/27844676 */
+ Py_DECREF(PyImport_ImportModule("threading"));
+# endif
+
#else
(void)argc;
(void)argv;
@@ -618,8 +635,12 @@ bool BPY_execute_string_as_number(
/**
* \return success
*/
-bool BPY_execute_string_as_string(
- bContext *C, const char *imports[], const char *expr, const bool verbose, char **r_value)
+bool BPY_execute_string_as_string_and_size(bContext *C,
+ const char *imports[],
+ const char *expr,
+ const bool verbose,
+ char **r_value,
+ size_t *r_value_size)
{
BLI_assert(r_value && expr);
PyGILState_STATE gilstate;
@@ -632,7 +653,7 @@ bool BPY_execute_string_as_string(
bpy_context_set(C, &gilstate);
- ok = PyC_RunString_AsString(imports, expr, "<expr as str>", r_value);
+ ok = PyC_RunString_AsStringAndSize(imports, expr, "<expr as str>", r_value, r_value_size);
if (ok == false) {
if (verbose) {
@@ -648,6 +669,14 @@ bool BPY_execute_string_as_string(
return ok;
}
+bool BPY_execute_string_as_string(
+ bContext *C, const char *imports[], const char *expr, const bool verbose, char **r_value)
+{
+ size_t value_dummy_size;
+ return BPY_execute_string_as_string_and_size(
+ C, imports, expr, verbose, r_value, &value_dummy_size);
+}
+
/**
* Support both int and pointers.
*
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 6fb2b2fd7ee..6c2896db703 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -4771,29 +4771,25 @@ static PyObject *pyrna_struct_get_rna_type(BPy_PropertyRNA *self)
/*****************************************************************************/
static PyGetSetDef pyrna_prop_getseters[] = {
- {(char *)"id_data",
+ {"id_data",
(getter)pyrna_struct_get_id_data,
(setter)NULL,
- (char *)pyrna_struct_get_id_data_doc,
+ pyrna_struct_get_id_data_doc,
NULL},
- {(char *)"data",
- (getter)pyrna_struct_get_data,
- (setter)NULL,
- (char *)pyrna_struct_get_data_doc,
- NULL},
- {(char *)"rna_type",
+ {"data", (getter)pyrna_struct_get_data, (setter)NULL, pyrna_struct_get_data_doc, NULL},
+ {"rna_type",
(getter)pyrna_struct_get_rna_type,
(setter)NULL,
- (char *)pyrna_struct_get_rna_type_doc,
+ pyrna_struct_get_rna_type_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static PyGetSetDef pyrna_struct_getseters[] = {
- {(char *)"id_data",
+ {"id_data",
(getter)pyrna_struct_get_id_data,
(setter)NULL,
- (char *)pyrna_struct_get_id_data_doc,
+ pyrna_struct_get_id_data_doc,
NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -4801,7 +4797,7 @@ static PyGetSetDef pyrna_struct_getseters[] = {
static PyObject *pyrna_func_doc_get(BPy_FunctionRNA *self, void *closure);
static PyGetSetDef pyrna_func_getseters[] = {
- {(char *)"__doc__", (getter)pyrna_func_doc_get, (setter)NULL, NULL, NULL},
+ {"__doc__", (getter)pyrna_func_doc_get, (setter)NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -7818,7 +7814,7 @@ static int pyrna_deferred_register_props(StructRNA *srna, PyObject *class_dict)
}
}
- {
+ if (ret == 0) {
/* This block can be removed once 2.8x is released and annotations are in use. */
bool has_warning = false;
while (PyDict_Next(class_dict, &pos, &key, &item)) {
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index 645b7e1c7af..fb9a28be430 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -73,15 +73,15 @@ static PyStructSequence_Field bpyunits_systems_fields[ARRAY_SIZE(bpyunits_usyste
static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategorie_items)];
static PyStructSequence_Desc bpyunits_systems_desc = {
- (char *)"bpy.utils.units.systems", /* name */
- (char *)"This named tuple contains all pre-defined unit systems", /* doc */
- bpyunits_systems_fields, /* fields */
+ "bpy.utils.units.systems", /* name */
+ "This named tuple contains all pre-defined unit systems", /* doc */
+ bpyunits_systems_fields, /* fields */
ARRAY_SIZE(bpyunits_systems_fields) - 1,
};
static PyStructSequence_Desc bpyunits_categories_desc = {
- (char *)"bpy.utils.units.categories", /* name */
- (char *)"This named tuple contains all pre-defined unit names", /* doc */
- bpyunits_categories_fields, /* fields */
+ "bpy.utils.units.categories", /* name */
+ "This named tuple contains all pre-defined unit names", /* doc */
+ bpyunits_categories_fields, /* fields */
ARRAY_SIZE(bpyunits_categories_fields) - 1,
};
diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index b587738c8d7..739ffb87dbb 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -841,59 +841,39 @@ static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closur
/* Python attributes get/set structure: */
/*****************************************************************************/
static PyGetSetDef Color_getseters[] = {
- {(char *)"r",
- (getter)Color_channel_get,
- (setter)Color_channel_set,
- Color_channel_r_doc,
- (void *)0},
- {(char *)"g",
- (getter)Color_channel_get,
- (setter)Color_channel_set,
- Color_channel_g_doc,
- (void *)1},
- {(char *)"b",
- (getter)Color_channel_get,
- (setter)Color_channel_set,
- Color_channel_b_doc,
- (void *)2},
+ {"r", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_r_doc, (void *)0},
+ {"g", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_g_doc, (void *)1},
+ {"b", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_b_doc, (void *)2},
- {(char *)"h",
+ {"h",
(getter)Color_channel_hsv_get,
(setter)Color_channel_hsv_set,
- (char *)Color_channel_hsv_h_doc,
+ Color_channel_hsv_h_doc,
(void *)0},
- {(char *)"s",
+ {"s",
(getter)Color_channel_hsv_get,
(setter)Color_channel_hsv_set,
- (char *)Color_channel_hsv_s_doc,
+ Color_channel_hsv_s_doc,
(void *)1},
- {(char *)"v",
+ {"v",
(getter)Color_channel_hsv_get,
(setter)Color_channel_hsv_set,
- (char *)Color_channel_hsv_v_doc,
+ Color_channel_hsv_v_doc,
(void *)2},
- {(char *)"hsv",
- (getter)Color_hsv_get,
- (setter)Color_hsv_set,
- (char *)Color_hsv_doc,
- (void *)0},
+ {"hsv", (getter)Color_hsv_get, (setter)Color_hsv_set, Color_hsv_doc, (void *)0},
- {(char *)"is_wrapped",
+ {"is_wrapped",
(getter)BaseMathObject_is_wrapped_get,
(setter)NULL,
BaseMathObject_is_wrapped_doc,
NULL},
- {(char *)"is_frozen",
+ {"is_frozen",
(getter)BaseMathObject_is_frozen_get,
(setter)NULL,
BaseMathObject_is_frozen_doc,
NULL},
- {(char *)"owner",
- (getter)BaseMathObject_owner_get,
- (setter)NULL,
- BaseMathObject_owner_doc,
- NULL},
+ {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index 3fd9bf666e2..65ca932d118 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -688,30 +688,22 @@ static int Euler_order_set(EulerObject *self, PyObject *value, void *UNUSED(clos
/* Python attributes get/set structure: */
/*****************************************************************************/
static PyGetSetDef Euler_getseters[] = {
- {(char *)"x", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)0},
- {(char *)"y", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)1},
- {(char *)"z", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)2},
- {(char *)"order",
- (getter)Euler_order_get,
- (setter)Euler_order_set,
- Euler_order_doc,
- (void *)NULL},
-
- {(char *)"is_wrapped",
+ {"x", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)0},
+ {"y", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)1},
+ {"z", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)2},
+ {"order", (getter)Euler_order_get, (setter)Euler_order_set, Euler_order_doc, (void *)NULL},
+
+ {"is_wrapped",
(getter)BaseMathObject_is_wrapped_get,
(setter)NULL,
BaseMathObject_is_wrapped_doc,
NULL},
- {(char *)"is_frozen",
+ {"is_frozen",
(getter)BaseMathObject_is_frozen_get,
(setter)NULL,
BaseMathObject_is_frozen_doc,
NULL},
- {(char *)"owner",
- (getter)BaseMathObject_owner_get,
- (setter)NULL,
- BaseMathObject_owner_doc,
- NULL},
+ {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index c6e6d395b6b..32921ae0ca9 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -3021,48 +3021,36 @@ static PyObject *Matrix_is_orthogonal_axis_vectors_get(MatrixObject *self, void
/* Python attributes get/set structure: */
/*****************************************************************************/
static PyGetSetDef Matrix_getseters[] = {
- {(char *)"median_scale",
- (getter)Matrix_median_scale_get,
- (setter)NULL,
- Matrix_median_scale_doc,
- NULL},
- {(char *)"translation",
+ {"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, Matrix_median_scale_doc, NULL},
+ {"translation",
(getter)Matrix_translation_get,
(setter)Matrix_translation_set,
Matrix_translation_doc,
NULL},
- {(char *)"row", (getter)Matrix_row_get, (setter)NULL, Matrix_row_doc, NULL},
- {(char *)"col", (getter)Matrix_col_get, (setter)NULL, Matrix_col_doc, NULL},
- {(char *)"is_negative",
- (getter)Matrix_is_negative_get,
- (setter)NULL,
- Matrix_is_negative_doc,
- NULL},
- {(char *)"is_orthogonal",
+ {"row", (getter)Matrix_row_get, (setter)NULL, Matrix_row_doc, NULL},
+ {"col", (getter)Matrix_col_get, (setter)NULL, Matrix_col_doc, NULL},
+ {"is_negative", (getter)Matrix_is_negative_get, (setter)NULL, Matrix_is_negative_doc, NULL},
+ {"is_orthogonal",
(getter)Matrix_is_orthogonal_get,
(setter)NULL,
Matrix_is_orthogonal_doc,
NULL},
- {(char *)"is_orthogonal_axis_vectors",
+ {"is_orthogonal_axis_vectors",
(getter)Matrix_is_orthogonal_axis_vectors_get,
(setter)NULL,
Matrix_is_orthogonal_axis_vectors_doc,
NULL},
- {(char *)"is_wrapped",
+ {"is_wrapped",
(getter)BaseMathObject_is_wrapped_get,
(setter)NULL,
BaseMathObject_is_wrapped_doc,
NULL},
- {(char *)"is_frozen",
+ {"is_frozen",
(getter)BaseMathObject_is_frozen_get,
(setter)NULL,
BaseMathObject_is_frozen_doc,
NULL},
- {(char *)"owner",
- (getter)BaseMathObject_owner_get,
- (setter)NULL,
- BaseMathObject_owner_doc,
- NULL},
+ {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index d7cccd5c352..ac7dd8590f2 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -1480,56 +1480,48 @@ static struct PyMethodDef Quaternion_methods[] = {
/* Python attributes get/set structure: */
/*****************************************************************************/
static PyGetSetDef Quaternion_getseters[] = {
- {(char *)"w",
+ {"w",
(getter)Quaternion_axis_get,
(setter)Quaternion_axis_set,
Quaternion_axis_doc,
(void *)0},
- {(char *)"x",
+ {"x",
(getter)Quaternion_axis_get,
(setter)Quaternion_axis_set,
Quaternion_axis_doc,
(void *)1},
- {(char *)"y",
+ {"y",
(getter)Quaternion_axis_get,
(setter)Quaternion_axis_set,
Quaternion_axis_doc,
(void *)2},
- {(char *)"z",
+ {"z",
(getter)Quaternion_axis_get,
(setter)Quaternion_axis_set,
Quaternion_axis_doc,
(void *)3},
- {(char *)"magnitude",
- (getter)Quaternion_magnitude_get,
- (setter)NULL,
- Quaternion_magnitude_doc,
- NULL},
- {(char *)"angle",
+ {"magnitude", (getter)Quaternion_magnitude_get, (setter)NULL, Quaternion_magnitude_doc, NULL},
+ {"angle",
(getter)Quaternion_angle_get,
(setter)Quaternion_angle_set,
Quaternion_angle_doc,
NULL},
- {(char *)"axis",
+ {"axis",
(getter)Quaternion_axis_vector_get,
(setter)Quaternion_axis_vector_set,
Quaternion_axis_vector_doc,
NULL},
- {(char *)"is_wrapped",
+ {"is_wrapped",
(getter)BaseMathObject_is_wrapped_get,
(setter)NULL,
BaseMathObject_is_wrapped_doc,
NULL},
- {(char *)"is_frozen",
+ {"is_frozen",
(getter)BaseMathObject_is_frozen_get,
(setter)NULL,
BaseMathObject_is_frozen_doc,
NULL},
- {(char *)"owner",
- (getter)BaseMathObject_owner_get,
- (setter)NULL,
- BaseMathObject_owner_doc,
- NULL},
+ {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c
index d28b9a0de8f..82f1d17fe52 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -349,7 +349,7 @@ static PyObject *py_bvhtree_ray_cast(PyBVHTree *self, PyObject *args)
{
PyObject *py_co, *py_direction;
- if (!PyArg_ParseTuple(args, (char *)"OO|f:ray_cast", &py_co, &py_direction, &max_dist)) {
+ if (!PyArg_ParseTuple(args, "OO|f:ray_cast", &py_co, &py_direction, &max_dist)) {
return NULL;
}
@@ -397,7 +397,7 @@ static PyObject *py_bvhtree_find_nearest(PyBVHTree *self, PyObject *args)
{
PyObject *py_co;
- if (!PyArg_ParseTuple(args, (char *)"O|f:find_nearest", &py_co, &max_dist)) {
+ if (!PyArg_ParseTuple(args, "O|f:find_nearest", &py_co, &max_dist)) {
return NULL;
}
@@ -478,7 +478,7 @@ static PyObject *py_bvhtree_find_nearest_range(PyBVHTree *self, PyObject *args)
{
PyObject *py_co;
- if (!PyArg_ParseTuple(args, (char *)"O|f:find_nearest_range", &py_co, &max_dist)) {
+ if (!PyArg_ParseTuple(args, "O|f:find_nearest_range", &py_co, &max_dist)) {
return NULL;
}
@@ -678,7 +678,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P
if (!PyArg_ParseTupleAndKeywords(args,
kwargs,
- (char *)"OO|$O&f:BVHTree.FromPolygons",
+ "OO|$O&f:BVHTree.FromPolygons",
(char **)keywords,
&py_coords,
&py_tris,
@@ -951,7 +951,7 @@ static PyObject *C_BVHTree_FromBMesh(PyObject *UNUSED(cls), PyObject *args, PyOb
if (!PyArg_ParseTupleAndKeywords(args,
kwargs,
- (char *)"O!|$f:BVHTree.FromBMesh",
+ "O!|$f:BVHTree.FromBMesh",
(char **)keywords,
&BPy_BMesh_Type,
&py_bm,
@@ -1142,7 +1142,7 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO
if (!PyArg_ParseTupleAndKeywords(args,
kwargs,
- (char *)"OO|$O&O&f:BVHTree.FromObject",
+ "OO|$O&O&f:BVHTree.FromObject",
(char **)keywords,
&py_ob,
&py_depsgraph,
diff --git a/source/blender/python/mathutils/mathutils_kdtree.c b/source/blender/python/mathutils/mathutils_kdtree.c
index e3f2cd9bd14..c6383f23d60 100644
--- a/source/blender/python/mathutils/mathutils_kdtree.c
+++ b/source/blender/python/mathutils/mathutils_kdtree.c
@@ -134,8 +134,7 @@ static PyObject *py_kdtree_insert(PyKDTree *self, PyObject *args, PyObject *kwar
int index;
const char *keywords[] = {"co", "index", NULL};
- if (!PyArg_ParseTupleAndKeywords(
- args, kwargs, (char *)"Oi:insert", (char **)keywords, &py_co, &index)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi:insert", (char **)keywords, &py_co, &index)) {
return NULL;
}
@@ -223,7 +222,7 @@ static PyObject *py_kdtree_find(PyKDTree *self, PyObject *args, PyObject *kwargs
const char *keywords[] = {"co", "filter", NULL};
if (!PyArg_ParseTupleAndKeywords(
- args, kwargs, (char *)"O|O:find", (char **)keywords, &py_co, &py_filter)) {
+ args, kwargs, "O|O:find", (char **)keywords, &py_co, &py_filter)) {
return NULL;
}
@@ -278,8 +277,7 @@ static PyObject *py_kdtree_find_n(PyKDTree *self, PyObject *args, PyObject *kwar
int i, found;
const char *keywords[] = {"co", "n", NULL};
- if (!PyArg_ParseTupleAndKeywords(
- args, kwargs, (char *)"OI:find_n", (char **)keywords, &py_co, &n)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OI:find_n", (char **)keywords, &py_co, &n)) {
return NULL;
}
@@ -335,7 +333,7 @@ static PyObject *py_kdtree_find_range(PyKDTree *self, PyObject *args, PyObject *
const char *keywords[] = {"co", "radius", NULL};
if (!PyArg_ParseTupleAndKeywords(
- args, kwargs, (char *)"Of:find_range", (char **)keywords, &py_co, &radius)) {
+ args, kwargs, "Of:find_range", (char **)keywords, &py_co, &radius)) {
return NULL;
}
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index e265197646c..a92be8509d5 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -36,7 +36,7 @@ set(INC
../../../intern/atomic
../../../intern/guardedalloc
../../../intern/mikktspace
- ../../../intern/smoke/extern
+ ../../../intern/mantaflow/extern
)
set(INC_SYS
@@ -86,8 +86,8 @@ if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_FLUID)
+ add_definitions(-DWITH_FLUID)
endif()
if(WITH_FREESTYLE)
diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h
index d47413717d4..f051d3ed318 100644
--- a/source/blender/render/intern/include/texture.h
+++ b/source/blender/render/intern/include/texture.h
@@ -83,7 +83,6 @@ int imagewraposa(struct Tex *tex,
const bool skip_load_image);
int imagewrap(struct Tex *tex,
struct Image *ima,
- struct ImBuf *ibuf,
const float texvec[3],
struct TexResult *texres,
struct ImagePool *pool,
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index dc7288234b3..47d0986fabd 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -100,7 +100,6 @@ static void ibuf_get_color(float col[4], struct ImBuf *ibuf, int x, int y)
int imagewrap(Tex *tex,
Image *ima,
- ImBuf *ibuf,
const float texvec[3],
TexResult *texres,
struct ImagePool *pool,
@@ -116,35 +115,44 @@ int imagewrap(Tex *tex,
retval = texres->nor ? 3 : 1;
/* quick tests */
- if (ibuf == NULL && ima == NULL) {
+ if (ima == NULL) {
return retval;
}
- if (ima) {
- /* hack for icon render */
- if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) {
- return retval;
- }
+ /* hack for icon render */
+ if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) {
+ return retval;
+ }
- ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
+ ImageUser *iuser = &tex->iuser;
+ ImageUser local_iuser;
+ if (ima->source == IMA_SRC_TILED) {
+ /* tex->iuser might be shared by threads, so create a local copy. */
+ local_iuser = tex->iuser;
+ iuser = &local_iuser;
- ima->flag |= IMA_USED_FOR_RENDER;
+ float new_uv[2];
+ iuser->tile = BKE_image_get_tile_from_pos(ima, texvec, new_uv, NULL);
+ fx = new_uv[0];
+ fy = new_uv[1];
+ }
+ else {
+ fx = texvec[0];
+ fy = texvec[1];
}
+
+ ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, iuser, pool);
+
+ ima->flag |= IMA_USED_FOR_RENDER;
+
if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
- if (ima) {
- BKE_image_pool_release_ibuf(ima, ibuf, pool);
- }
+ BKE_image_pool_release_ibuf(ima, ibuf, pool);
return retval;
}
/* setup mapping */
if (tex->imaflag & TEX_IMAROT) {
- fy = texvec[0];
- fx = texvec[1];
- }
- else {
- fx = texvec[0];
- fy = texvec[1];
+ SWAP(float, fx, fy);
}
if (tex->extend == TEX_CHECKER) {
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 3f3dc9842a5..fe162212b9c 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -1219,7 +1219,7 @@ static int multitex(Tex *tex,
tex, tex->ima, NULL, texvec, dxt, dyt, texres, pool, skip_load_image);
}
else {
- retval = imagewrap(tex, tex->ima, NULL, texvec, texres, pool, skip_load_image);
+ retval = imagewrap(tex, tex->ima, texvec, texres, pool, skip_load_image);
}
if (tex->ima) {
BKE_image_tag_time(tex->ima);
diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt
index 57c7345076e..6d918763996 100644
--- a/source/blender/shader_fx/CMakeLists.txt
+++ b/source/blender/shader_fx/CMakeLists.txt
@@ -30,7 +30,6 @@ set(INC
../makesdna
../makesrna
../render/extern/include
- ../../../intern/elbeem/extern
../../../intern/eigen
../../../intern/guardedalloc
)
diff --git a/source/blender/usd/CMakeLists.txt b/source/blender/usd/CMakeLists.txt
new file mode 100644
index 00000000000..12d281f643d
--- /dev/null
+++ b/source/blender/usd/CMakeLists.txt
@@ -0,0 +1,81 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2019, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+# This suppresses the warning "This file includes at least one deprecated or antiquated
+# header which may be removed without further notice at a future date", which is caused
+# by the USD library including <ext/hash_set> on Linux. This has been reported at:
+# https://github.com/PixarAnimationStudios/USD/issues/1057.
+if(UNIX AND NOT APPLE)
+ add_definitions(-D_GLIBCXX_PERMIT_BACKWARD_HASH)
+endif()
+if(WIN32)
+ add_definitions(-DNOMINMAX)
+endif()
+add_definitions(-DPXR_STATIC)
+
+set(INC
+ .
+ ../blenkernel
+ ../blenlib
+ ../blenloader
+ ../bmesh
+ ../depsgraph
+ ../editors/include
+ ../makesdna
+ ../makesrna
+ ../windowmanager
+ ../../../intern/guardedalloc
+ ../../../intern/utfconv
+)
+
+set(INC_SYS
+ ${USD_INCLUDE_DIRS}
+ ${BOOST_INCLUDE_DIR}
+ ${TBB_INCLUDE_DIR}
+)
+
+set(SRC
+ intern/abstract_hierarchy_iterator.cc
+ intern/usd_capi.cc
+ intern/usd_hierarchy_iterator.cc
+ intern/usd_writer_abstract.cc
+ intern/usd_writer_camera.cc
+ intern/usd_writer_hair.cc
+ intern/usd_writer_light.cc
+ intern/usd_writer_mesh.cc
+ intern/usd_writer_transform.cc
+
+ usd.h
+ intern/abstract_hierarchy_iterator.h
+ intern/usd_hierarchy_iterator.h
+ intern/usd_writer_abstract.h
+ intern/usd_writer_camera.h
+ intern/usd_writer_hair.h
+ intern/usd_writer_light.h
+ intern/usd_writer_mesh.h
+ intern/usd_writer_transform.h
+)
+
+set(LIB
+ bf_blenkernel
+ bf_blenlib
+)
+
+blender_add_lib(bf_usd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/usd/intern/abstract_hierarchy_iterator.cc
new file mode 100644
index 00000000000..3ad2b2ce5d8
--- /dev/null
+++ b/source/blender/usd/intern/abstract_hierarchy_iterator.cc
@@ -0,0 +1,559 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "abstract_hierarchy_iterator.h"
+
+#include <iostream>
+#include <limits.h>
+#include <sstream>
+#include <string>
+
+extern "C" {
+#include "BKE_anim.h"
+#include "BKE_particle.h"
+
+#include "BLI_assert.h"
+#include "BLI_listbase.h"
+#include "BLI_math_matrix.h"
+
+#include "DNA_ID.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+
+#include "DEG_depsgraph_query.h"
+}
+
+namespace USD {
+
+const HierarchyContext *HierarchyContext::root()
+{
+ return nullptr;
+}
+
+bool HierarchyContext::operator<(const HierarchyContext &other) const
+{
+ if (object != other.object) {
+ return object < other.object;
+ }
+ if (duplicator != NULL && duplicator == other.duplicator) {
+ // Only resort to string comparisons when both objects are created by the same duplicator.
+ return export_name < other.export_name;
+ }
+
+ return export_parent < other.export_parent;
+}
+
+bool HierarchyContext::is_instance() const
+{
+ return !original_export_path.empty();
+}
+void HierarchyContext::mark_as_instance_of(const std::string &reference_export_path)
+{
+ original_export_path = reference_export_path;
+}
+void HierarchyContext::mark_as_not_instanced()
+{
+ original_export_path.clear();
+}
+
+AbstractHierarchyWriter::~AbstractHierarchyWriter()
+{
+}
+
+AbstractHierarchyIterator::AbstractHierarchyIterator(Depsgraph *depsgraph)
+ : depsgraph_(depsgraph), writers_()
+{
+}
+
+AbstractHierarchyIterator::~AbstractHierarchyIterator()
+{
+}
+
+void AbstractHierarchyIterator::iterate_and_write()
+{
+ export_graph_construct();
+ export_graph_prune();
+ determine_export_paths(HierarchyContext::root());
+ determine_duplication_references(HierarchyContext::root(), "");
+ make_writers(HierarchyContext::root());
+ export_graph_clear();
+}
+
+void AbstractHierarchyIterator::release_writers()
+{
+ for (WriterMap::value_type it : writers_) {
+ delete_object_writer(it.second);
+ }
+ writers_.clear();
+}
+
+std::string AbstractHierarchyIterator::make_valid_name(const std::string &name) const
+{
+ return name;
+}
+
+std::string AbstractHierarchyIterator::get_id_name(const ID *id) const
+{
+ if (id == nullptr) {
+ return "";
+ }
+
+ return make_valid_name(std::string(id->name + 2));
+}
+
+std::string AbstractHierarchyIterator::get_object_data_path(const HierarchyContext *context) const
+{
+ BLI_assert(!context->export_path.empty());
+ BLI_assert(context->object->data);
+
+ return path_concatenate(context->export_path, get_object_data_name(context->object));
+}
+
+void AbstractHierarchyIterator::debug_print_export_graph() const
+{
+ size_t total_graph_size = 0;
+ for (const ExportGraph::value_type &map_iter : export_graph_) {
+ const DupliAndDuplicator &parent_info = map_iter.first;
+ Object *const export_parent = parent_info.first;
+ Object *const duplicator = parent_info.second;
+
+ if (duplicator != nullptr) {
+ printf(" DU %s (as dupped by %s):\n",
+ export_parent == nullptr ? "-null-" : (export_parent->id.name + 2),
+ duplicator->id.name + 2);
+ }
+ else {
+ printf(" OB %s:\n", export_parent == nullptr ? "-null-" : (export_parent->id.name + 2));
+ }
+
+ total_graph_size += map_iter.second.size();
+ for (HierarchyContext *child_ctx : map_iter.second) {
+ if (child_ctx->duplicator == nullptr) {
+ printf(" - %s%s%s\n",
+ child_ctx->object->id.name + 2,
+ child_ctx->weak_export ? " (weak)" : "",
+ child_ctx->original_export_path.size() ?
+ (std::string("ref ") + child_ctx->original_export_path).c_str() :
+ "");
+ }
+ else {
+ printf(" - %s (dup by %s%s) %s\n",
+ child_ctx->object->id.name + 2,
+ child_ctx->duplicator->id.name + 2,
+ child_ctx->weak_export ? ", weak" : "",
+ child_ctx->original_export_path.size() ?
+ (std::string("ref ") + child_ctx->original_export_path).c_str() :
+ "");
+ }
+ }
+ }
+ printf(" (Total graph size: %lu objects\n", total_graph_size);
+}
+
+void AbstractHierarchyIterator::export_graph_construct()
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph_);
+
+ DEG_OBJECT_ITER_BEGIN (depsgraph_,
+ object,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) {
+ if (object->base_flag & BASE_HOLDOUT) {
+ visit_object(object, object->parent, true);
+ continue;
+ }
+
+ // Non-instanced objects always have their object-parent as export-parent.
+ const bool weak_export = mark_as_weak_export(object);
+ visit_object(object, object->parent, weak_export);
+
+ if (weak_export) {
+ // If a duplicator shouldn't be exported, its duplilist also shouldn't be.
+ continue;
+ }
+
+ // Export the duplicated objects instanced by this object.
+ ListBase *lb = object_duplilist(depsgraph_, scene, object);
+ if (lb) {
+ // Construct the set of duplicated objects, so that later we can determine whether a parent
+ // is also duplicated itself.
+ std::set<Object *> dupli_set;
+ LISTBASE_FOREACH (DupliObject *, dupli_object, lb) {
+ if (!should_visit_dupli_object(dupli_object)) {
+ continue;
+ }
+ dupli_set.insert(dupli_object->ob);
+ }
+
+ LISTBASE_FOREACH (DupliObject *, dupli_object, lb) {
+ if (!should_visit_dupli_object(dupli_object)) {
+ continue;
+ }
+
+ visit_dupli_object(dupli_object, object, dupli_set);
+ }
+ }
+
+ free_object_duplilist(lb);
+ }
+ DEG_OBJECT_ITER_END;
+}
+
+static bool remove_weak_subtrees(const HierarchyContext *context,
+ AbstractHierarchyIterator::ExportGraph &clean_graph,
+ const AbstractHierarchyIterator::ExportGraph &input_graph)
+{
+ bool all_is_weak = context != nullptr && context->weak_export;
+ Object *object = context != nullptr ? context->object : nullptr;
+ Object *duplicator = context != nullptr ? context->duplicator : nullptr;
+
+ const AbstractHierarchyIterator::DupliAndDuplicator map_key = std::make_pair(object, duplicator);
+ AbstractHierarchyIterator::ExportGraph::const_iterator child_iterator;
+
+ child_iterator = input_graph.find(map_key);
+ if (child_iterator != input_graph.end()) {
+ for (HierarchyContext *child_context : child_iterator->second) {
+ bool child_tree_is_weak = remove_weak_subtrees(child_context, clean_graph, input_graph);
+ all_is_weak &= child_tree_is_weak;
+
+ if (child_tree_is_weak) {
+ // This subtree is all weak, so we can remove it from the current object's children.
+ clean_graph[map_key].erase(child_context);
+ delete child_context;
+ }
+ }
+ }
+
+ if (all_is_weak) {
+ // This node and all its children are weak, so it can be removed from the export graph.
+ clean_graph.erase(map_key);
+ }
+
+ return all_is_weak;
+}
+
+void AbstractHierarchyIterator::export_graph_prune()
+{
+ // Take a copy of the map so that we can modify while recursing.
+ ExportGraph unpruned_export_graph = export_graph_;
+ remove_weak_subtrees(HierarchyContext::root(), export_graph_, unpruned_export_graph);
+}
+
+void AbstractHierarchyIterator::export_graph_clear()
+{
+ for (ExportGraph::iterator::value_type &it : export_graph_) {
+ for (HierarchyContext *context : it.second) {
+ delete context;
+ }
+ }
+ export_graph_.clear();
+}
+
+void AbstractHierarchyIterator::visit_object(Object *object,
+ Object *export_parent,
+ bool weak_export)
+{
+ HierarchyContext *context = new HierarchyContext();
+ context->object = object;
+ context->export_name = get_object_name(object);
+ context->export_parent = export_parent;
+ context->duplicator = nullptr;
+ context->weak_export = weak_export;
+ context->animation_check_include_parent = false;
+ context->export_path = "";
+ context->original_export_path = "";
+ copy_m4_m4(context->matrix_world, object->obmat);
+
+ export_graph_[std::make_pair(export_parent, nullptr)].insert(context);
+}
+
+void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object,
+ Object *duplicator,
+ const std::set<Object *> &dupli_set)
+{
+ ExportGraph::key_type graph_index;
+ bool animation_check_include_parent = false;
+
+ HierarchyContext *context = new HierarchyContext();
+ context->object = dupli_object->ob;
+ context->duplicator = duplicator;
+ context->weak_export = false;
+ context->export_path = "";
+ context->original_export_path = "";
+
+ /* If the dupli-object's parent is also instanced by this object, use that as the
+ * export parent. Otherwise use the dupli-parent as export parent. */
+ Object *parent = dupli_object->ob->parent;
+ if (parent != nullptr && dupli_set.find(parent) != dupli_set.end()) {
+ // The parent object is part of the duplicated collection.
+ context->export_parent = parent;
+ graph_index = std::make_pair(parent, duplicator);
+ }
+ else {
+ /* The parent object is NOT part of the duplicated collection. This means that the world
+ * transform of this dupliobject can be influenced by objects that are not part of its
+ * export graph. */
+ animation_check_include_parent = true;
+ context->export_parent = duplicator;
+ graph_index = std::make_pair(duplicator, nullptr);
+ }
+
+ context->animation_check_include_parent = animation_check_include_parent;
+ copy_m4_m4(context->matrix_world, dupli_object->mat);
+
+ // Construct export name for the dupli-instance.
+ std::stringstream suffix_stream;
+ suffix_stream << std::hex;
+ for (int i = 0; i < MAX_DUPLI_RECUR && dupli_object->persistent_id[i] != INT_MAX; i++) {
+ suffix_stream << "-" << dupli_object->persistent_id[i];
+ }
+ context->export_name = make_valid_name(get_object_name(context->object) + suffix_stream.str());
+
+ export_graph_[graph_index].insert(context);
+}
+
+AbstractHierarchyIterator::ExportChildren &AbstractHierarchyIterator::graph_children(
+ const HierarchyContext *context)
+{
+ if (context == nullptr) {
+ return export_graph_[std::make_pair(nullptr, nullptr)];
+ }
+
+ return export_graph_[std::make_pair(context->object, context->duplicator)];
+}
+
+void AbstractHierarchyIterator::determine_export_paths(const HierarchyContext *parent_context)
+{
+ const std::string &parent_export_path = parent_context ? parent_context->export_path : "";
+
+ for (HierarchyContext *context : graph_children(parent_context)) {
+ context->export_path = path_concatenate(parent_export_path, context->export_name);
+
+ if (context->duplicator == nullptr) {
+ /* This is an original (i.e. non-instanced) object, so we should keep track of where it was
+ * exported to, just in case it gets instanced somewhere. */
+ ID *source_ob = &context->object->id;
+ duplisource_export_path_[source_ob] = context->export_path;
+
+ if (context->object->data != nullptr) {
+ ID *object_data = static_cast<ID *>(context->object->data);
+ ID *source_data = object_data;
+ duplisource_export_path_[source_data] = get_object_data_path(context);
+ }
+ }
+
+ determine_export_paths(context);
+ }
+}
+
+void AbstractHierarchyIterator::determine_duplication_references(
+ const HierarchyContext *parent_context, std::string indent)
+{
+ ExportChildren children = graph_children(parent_context);
+
+ for (HierarchyContext *context : children) {
+ if (context->duplicator != nullptr) {
+ ID *source_id = &context->object->id;
+ const ExportPathMap::const_iterator &it = duplisource_export_path_.find(source_id);
+
+ if (it == duplisource_export_path_.end()) {
+ // The original was not found, so mark this instance as "the original".
+ context->mark_as_not_instanced();
+ duplisource_export_path_[source_id] = context->export_path;
+ }
+ else {
+ context->mark_as_instance_of(it->second);
+ }
+
+ if (context->object->data) {
+ ID *source_data_id = (ID *)context->object->data;
+ const ExportPathMap::const_iterator &it = duplisource_export_path_.find(source_data_id);
+
+ if (it == duplisource_export_path_.end()) {
+ // The original was not found, so mark this instance as "original".
+ std::string data_path = get_object_data_path(context);
+ context->mark_as_not_instanced();
+ duplisource_export_path_[source_id] = context->export_path;
+ duplisource_export_path_[source_data_id] = data_path;
+ }
+ }
+ }
+
+ determine_duplication_references(context, indent + " ");
+ }
+}
+
+void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_context)
+{
+ AbstractHierarchyWriter *transform_writer = nullptr;
+ float parent_matrix_inv_world[4][4];
+
+ if (parent_context) {
+ invert_m4_m4(parent_matrix_inv_world, parent_context->matrix_world);
+ }
+ else {
+ unit_m4(parent_matrix_inv_world);
+ }
+
+ const std::string &parent_export_path = parent_context ? parent_context->export_path : "";
+
+ for (HierarchyContext *context : graph_children(parent_context)) {
+ copy_m4_m4(context->parent_matrix_inv_world, parent_matrix_inv_world);
+
+ // Get or create the transform writer.
+ transform_writer = ensure_writer(context, &AbstractHierarchyIterator::create_transform_writer);
+ if (transform_writer == nullptr) {
+ // Unable to export, so there is nothing to attach any children to; just abort this entire
+ // branch of the export hierarchy.
+ return;
+ }
+
+ BLI_assert(DEG_is_evaluated_object(context->object));
+ /* XXX This can lead to too many XForms being written. For example, a camera writer can refuse
+ * to write an orthographic camera. By the time that this is known, the XForm has already been
+ * written. */
+ transform_writer->write(*context);
+
+ if (!context->weak_export) {
+ make_writers_particle_systems(context);
+ make_writer_object_data(context);
+ }
+
+ // Recurse into this object's children.
+ make_writers(context);
+ }
+
+ // TODO(Sybren): iterate over all unused writers and call unused_during_iteration() or something.
+}
+
+void AbstractHierarchyIterator::make_writer_object_data(const HierarchyContext *context)
+{
+ if (context->object->data == nullptr) {
+ return;
+ }
+
+ HierarchyContext data_context = *context;
+ data_context.export_path = get_object_data_path(context);
+
+ /* data_context.original_export_path is just a copy from the context. It points to the object,
+ * but needs to point to the object data. */
+ if (data_context.is_instance()) {
+ ID *object_data = static_cast<ID *>(context->object->data);
+ data_context.original_export_path = duplisource_export_path_[object_data];
+
+ /* If the object is marked as an instance, so should the object data. */
+ BLI_assert(data_context.is_instance());
+ }
+
+ AbstractHierarchyWriter *data_writer;
+ data_writer = ensure_writer(&data_context, &AbstractHierarchyIterator::create_data_writer);
+ if (data_writer == nullptr) {
+ return;
+ }
+
+ data_writer->write(data_context);
+}
+
+void AbstractHierarchyIterator::make_writers_particle_systems(
+ const HierarchyContext *transform_context)
+{
+ Object *object = transform_context->object;
+ ParticleSystem *psys = static_cast<ParticleSystem *>(object->particlesystem.first);
+ for (; psys; psys = psys->next) {
+ if (!psys_check_enabled(object, psys, true)) {
+ continue;
+ }
+
+ HierarchyContext hair_context = *transform_context;
+ hair_context.export_path = path_concatenate(transform_context->export_path,
+ get_id_name(&psys->part->id));
+ hair_context.particle_system = psys;
+
+ AbstractHierarchyWriter *writer = nullptr;
+ switch (psys->part->type) {
+ case PART_HAIR:
+ writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_hair_writer);
+ break;
+ case PART_EMITTER:
+ writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_particle_writer);
+ break;
+ }
+
+ if (writer != nullptr) {
+ writer->write(hair_context);
+ }
+ }
+}
+
+std::string AbstractHierarchyIterator::get_object_name(const Object *object) const
+{
+ return get_id_name(&object->id);
+}
+
+std::string AbstractHierarchyIterator::get_object_data_name(const Object *object) const
+{
+ ID *object_data = static_cast<ID *>(object->data);
+ return get_id_name(object_data);
+}
+
+AbstractHierarchyWriter *AbstractHierarchyIterator::get_writer(const std::string &export_path)
+{
+ WriterMap::iterator it = writers_.find(export_path);
+
+ if (it == writers_.end()) {
+ return nullptr;
+ }
+ return it->second;
+}
+
+AbstractHierarchyWriter *AbstractHierarchyIterator::ensure_writer(
+ HierarchyContext *context, AbstractHierarchyIterator::create_writer_func create_func)
+{
+ AbstractHierarchyWriter *writer = get_writer(context->export_path);
+ if (writer != nullptr) {
+ return writer;
+ }
+
+ writer = (this->*create_func)(context);
+ if (writer == nullptr) {
+ return nullptr;
+ }
+
+ writers_[context->export_path] = writer;
+
+ return writer;
+}
+
+std::string AbstractHierarchyIterator::path_concatenate(const std::string &parent_path,
+ const std::string &child_path) const
+{
+ return parent_path + "/" + child_path;
+}
+
+bool AbstractHierarchyIterator::mark_as_weak_export(const Object * /*object*/) const
+{
+ return false;
+}
+bool AbstractHierarchyIterator::should_visit_dupli_object(const DupliObject *dupli_object) const
+{
+ // Removing dupli_object->no_draw hides things like custom bone shapes.
+ return !dupli_object->no_draw;
+}
+
+} // namespace USD
diff --git a/source/blender/usd/intern/abstract_hierarchy_iterator.h b/source/blender/usd/intern/abstract_hierarchy_iterator.h
new file mode 100644
index 00000000000..ea31e94cf9b
--- /dev/null
+++ b/source/blender/usd/intern/abstract_hierarchy_iterator.h
@@ -0,0 +1,248 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/*
+ * This file contains the AbstractHierarchyIterator. It is intended for exporters for file
+ * formats that concern an entire hierarchy of objects (rather than, for example, an OBJ file that
+ * contains only a single mesh). Examples are Universal Scene Description (USD) and Alembic.
+ * AbstractHierarchyIterator is intended to be subclassed to support concrete file formats.
+ *
+ * The AbstractHierarchyIterator makes a distinction between the actual object hierarchy and the
+ * export hierarchy. The former is the parent/child structure in Blender, which can have multiple
+ * parent-like objects. For example, a duplicated object can have both a duplicator and a parent,
+ * both determining the final transform. The export hierarchy is the hierarchy as written to the
+ * file, and every object has only one export-parent.
+ *
+ * Currently the AbstractHierarchyIterator does not make any decisions about *what* to export.
+ * Selections like "selected only" or "no hair systems" are left to concrete subclasses.
+ */
+
+#ifndef __ABSTRACT_HIERARCHY_ITERATOR_H__
+#define __ABSTRACT_HIERARCHY_ITERATOR_H__
+
+#include <map>
+#include <string>
+#include <set>
+
+struct Base;
+struct Depsgraph;
+struct DupliObject;
+struct ID;
+struct Object;
+struct ParticleSystem;
+struct ViewLayer;
+
+namespace USD {
+
+class AbstractHierarchyWriter;
+
+/* HierarchyContext structs are created by the AbstractHierarchyIterator. Each HierarchyContext
+ * struct contains everything necessary to export a single object to a file. */
+struct HierarchyContext {
+ /*********** Determined during hierarchy iteration: ***************/
+ Object *object;
+ Object *export_parent;
+ Object *duplicator;
+ float matrix_world[4][4];
+ std::string export_name;
+
+ /* When weak_export=true, the object will be exported only as transform, and only if is an
+ * ancestor of an object with weak_export=false.
+ *
+ * In other words: when weak_export=true but this object has no children, or all decendants also
+ * have weak_export=true, this object (and by recursive reasoning all its decendants) will be
+ * excluded from the export.
+ *
+ * The export hierarchy is kept as close to the 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. */
+ bool weak_export;
+
+ /* When true, this object should check its parents for animation data when determining whether
+ * it's animated. This is necessary when a parent object in Blender is not part of the export. */
+ bool animation_check_include_parent;
+
+ /*********** Determined during writer creation: ***************/
+ float parent_matrix_inv_world[4][4]; // Inverse of the parent's world matrix.
+ std::string export_path; // Hierarchical path, such as "/grandparent/parent/objectname".
+ ParticleSystem *particle_system; // Only set for particle/hair writers.
+
+ /* Hierarchical path of the object this object is duplicating; only set when this object should
+ * be stored as a reference to its original. It can happen that the original is not part of the
+ * exported objects, in which case this string is empty even though 'duplicator' is set. */
+ std::string original_export_path;
+
+ bool operator<(const HierarchyContext &other) const;
+
+ /* Return a HierarchyContext representing the root of the export hierarchy. */
+ static const HierarchyContext *root();
+
+ /* For handling instanced collections, instances created by particles, etc. */
+ bool is_instance() const;
+ void mark_as_instance_of(const std::string &reference_export_path);
+ void mark_as_not_instanced();
+};
+
+/* Abstract writer for objects. Create concrete subclasses to write to USD, Alembic, etc.
+ *
+ * Instantiated by the AbstractHierarchyIterator on the first frame an object exists. Generally
+ * that's the first frame to be exported, but can be later, for example when objects are
+ * instantiated by particles. The AbstractHierarchyWriter::write() function is called on every
+ * frame the object exists in the dependency graph and should be exported.
+ */
+class AbstractHierarchyWriter {
+ public:
+ virtual ~AbstractHierarchyWriter();
+ virtual void write(HierarchyContext &context) = 0;
+ // TODO(Sybren): add function like absent() that's called when a writer was previously created,
+ // but wasn't used while exporting the current frame (for example, a particle-instanced mesh of
+ // which the particle is no longer alive).
+};
+
+/* AbstractHierarchyIterator iterates over objects in a dependency graph, and constructs export
+ * writers. These writers are then called to perform the actual writing to a USD or Alembic file.
+ *
+ * Dealing with file- and scene-level data (for example, creating a USD scene, setting the frame
+ * rate, etc.) is not part of the AbstractHierarchyIterator class structure, and should be done
+ * in separate code.
+ */
+class AbstractHierarchyIterator {
+ public:
+ /* Mapping from export path to writer. */
+ typedef std::map<std::string, AbstractHierarchyWriter *> WriterMap;
+ /* Pair of a duplicated object and its duplicator, typically a pair of HierarchyContext::object
+ * and HierarchyContext::duplicator. */
+ typedef std::pair<Object *, Object *> DupliAndDuplicator;
+ /* All the children of some object, as per the export hierarchy. */
+ typedef std::set<HierarchyContext *> ExportChildren;
+ /* Mapping from an object and its duplicator to the object's export-children. */
+ typedef std::map<DupliAndDuplicator, ExportChildren> ExportGraph;
+ /* Mapping from (potential) duplicator ID to export path. */
+ typedef std::map<ID *, std::string> ExportPathMap;
+
+ protected:
+ ExportGraph export_graph_;
+ ExportPathMap duplisource_export_path_;
+ Depsgraph *depsgraph_;
+ WriterMap writers_;
+
+ public:
+ explicit AbstractHierarchyIterator(Depsgraph *depsgraph);
+ virtual ~AbstractHierarchyIterator();
+
+ /* Iterate over the depsgraph, create writers, and tell the writers to write.
+ * Main entry point for the AbstractHierarchyIterator, must be called for every to-be-exported
+ * frame. */
+ void iterate_and_write();
+
+ /* Release all writers. Call after all frames have been exported. */
+ void release_writers();
+
+ /* Convert the given name to something that is valid for the exported file format.
+ * This base implementation is a no-op; override in a concrete subclass. */
+ virtual std::string make_valid_name(const std::string &name) const;
+
+ /* Return the name of this ID datablock that is valid for the exported file format. Overriding is
+ * only necessary if make_valid_name(id->name+2) is not suitable for the exported file format.
+ * NULL-safe: when `id == nullptr` this returns an empty string. */
+ virtual std::string get_id_name(const ID *id) const;
+
+ /* Given a HierarchyContext of some Object *, return an export path that is valid for its
+ * object->data. Overriding is necessary when the exported format does NOT expect the object's
+ * data to be a child of the object. */
+ virtual std::string get_object_data_path(const HierarchyContext *context) const;
+
+ private:
+ void debug_print_export_graph() const;
+
+ void export_graph_construct();
+ void export_graph_prune();
+ void export_graph_clear();
+
+ void visit_object(Object *object, Object *export_parent, bool weak_export);
+ void visit_dupli_object(DupliObject *dupli_object,
+ Object *duplicator,
+ const std::set<Object *> &dupli_set);
+
+ ExportChildren &graph_children(const HierarchyContext *parent_context);
+
+ void determine_export_paths(const HierarchyContext *parent_context);
+ void determine_duplication_references(const HierarchyContext *parent_context,
+ std::string indent);
+
+ void make_writers(const HierarchyContext *parent_context);
+ void make_writer_object_data(const HierarchyContext *context);
+ void make_writers_particle_systems(const HierarchyContext *context);
+
+ /* Convenience wrappers around get_id_name(). */
+ std::string get_object_name(const Object *object) const;
+ std::string get_object_data_name(const Object *object) const;
+
+ AbstractHierarchyWriter *get_writer(const std::string &export_path);
+
+ typedef AbstractHierarchyWriter *(AbstractHierarchyIterator::*create_writer_func)(
+ const HierarchyContext *);
+ /* Ensure that a writer exists; if it doesn't, call create_func(context). The create_func
+ * function should be one of the create_XXXX_writer(context) functions declared below. */
+ AbstractHierarchyWriter *ensure_writer(HierarchyContext *context,
+ create_writer_func create_func);
+
+ protected:
+ /* Construct a valid path for the export file format. This class concatenates by using '/' as a
+ * path separator, which is valid for both Alembic and USD. */
+ virtual std::string path_concatenate(const std::string &parent_path,
+ const std::string &child_path) const;
+
+ /* Return whether this object should be marked as 'weak export' or not.
+ *
+ * When this returns false, writers for the transform and data are created,
+ * and dupli-objects dupli-object generated from this object will be passed to
+ * should_visit_dupli_object().
+ *
+ * When this returns true, only a transform writer is created and marked as
+ * 'weak export'. In this case, the transform writer will be removed before
+ * exporting starts, unless a decendant of this object is to be exported.
+ * Dupli-object generated from this object will also be skipped.
+ *
+ * See HierarchyContext::weak_export.
+ */
+ virtual bool mark_as_weak_export(const Object *object) const;
+
+ virtual bool should_visit_dupli_object(const DupliObject *dupli_object) const;
+
+ /* These functions should create an AbstractHierarchyWriter subclass instance, or return
+ * nullptr if the object or its data should not be exported. Returning a nullptr for
+ * data/hair/particle will NOT prevent the transform to be written.
+ *
+ * The returned writer is owned by the AbstractHierarchyWriter, and should be freed in
+ * delete_object_writer(). */
+ virtual AbstractHierarchyWriter *create_transform_writer(const HierarchyContext *context) = 0;
+ virtual AbstractHierarchyWriter *create_data_writer(const HierarchyContext *context) = 0;
+ virtual AbstractHierarchyWriter *create_hair_writer(const HierarchyContext *context) = 0;
+ virtual AbstractHierarchyWriter *create_particle_writer(const HierarchyContext *context) = 0;
+
+ /* Called by release_writers() to free what the create_XXX_writer() functions allocated. */
+ virtual void delete_object_writer(AbstractHierarchyWriter *writer) = 0;
+};
+
+} // namespace USD
+
+#endif /* __ABSTRACT_HIERARCHY_ITERATOR_H__ */
diff --git a/source/blender/usd/intern/usd_capi.cc b/source/blender/usd/intern/usd_capi.cc
new file mode 100644
index 00000000000..502f8677174
--- /dev/null
+++ b/source/blender/usd/intern/usd_capi.cc
@@ -0,0 +1,218 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "usd.h"
+#include "usd_hierarchy_iterator.h"
+
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdGeom/tokens.h>
+
+extern "C" {
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_scene_types.h"
+
+#include "BKE_blender_version.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_scene.h"
+
+#include "BLI_fileops.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+namespace USD {
+
+struct ExportJobData {
+ ViewLayer *view_layer;
+ Main *bmain;
+ Depsgraph *depsgraph;
+ wmWindowManager *wm;
+
+ char filename[FILE_MAX];
+ USDExportParams params;
+
+ short *stop;
+ short *do_update;
+ float *progress;
+
+ bool was_canceled;
+ bool export_ok;
+};
+
+static void export_startjob(void *customdata, short *stop, short *do_update, float *progress)
+{
+ ExportJobData *data = static_cast<ExportJobData *>(customdata);
+
+ data->stop = stop;
+ data->do_update = do_update;
+ data->progress = progress;
+ data->was_canceled = false;
+
+ G.is_rendering = true;
+ WM_set_locked_interface(data->wm, true);
+ G.is_break = false;
+
+ // Construct the depsgraph for exporting.
+ Scene *scene = DEG_get_input_scene(data->depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(data->depsgraph);
+ DEG_graph_build_from_view_layer(data->depsgraph, data->bmain, scene, view_layer);
+ BKE_scene_graph_update_tagged(data->depsgraph, data->bmain);
+
+ *progress = 0.0f;
+ *do_update = true;
+
+ // For restoring the current frame after exporting animation is done.
+ const int orig_frame = CFRA;
+
+ pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(data->filename);
+ if (!usd_stage) {
+ /* This happens when the USD JSON files cannot be found. When that happens,
+ * the USD library doesn't know it has the functionality to write USDA and
+ * USDC files, and creating a new UsdStage fails. */
+ WM_reportf(
+ RPT_ERROR, "USD Export: unable to find suitable USD plugin to write %s", data->filename);
+ data->export_ok = false;
+ return;
+ }
+
+ usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z));
+ usd_stage->SetMetadata(pxr::UsdGeomTokens->metersPerUnit,
+ pxr::VtValue(scene->unit.scale_length));
+ usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender ") + versionstr);
+
+ // Set up the stage for animated data.
+ if (data->params.export_animation) {
+ usd_stage->SetTimeCodesPerSecond(FPS);
+ usd_stage->SetStartTimeCode(scene->r.sfra);
+ usd_stage->SetEndTimeCode(scene->r.efra);
+ }
+
+ USDHierarchyIterator iter(data->depsgraph, usd_stage, data->params);
+
+ if (data->params.export_animation) {
+ // Writing the animated frames is not 100% of the work, but it's our best guess.
+ float progress_per_frame = 1.0f / std::max(1, (scene->r.efra - scene->r.sfra + 1));
+
+ for (float frame = scene->r.sfra; frame <= scene->r.efra; frame++) {
+ if (G.is_break || (stop != nullptr && *stop)) {
+ break;
+ }
+
+ // Update the scene for the next frame to render.
+ scene->r.cfra = static_cast<int>(frame);
+ scene->r.subframe = frame - scene->r.cfra;
+ BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain);
+
+ iter.set_export_frame(frame);
+ iter.iterate_and_write();
+
+ *progress += progress_per_frame;
+ *do_update = true;
+ }
+ }
+ else {
+ // If we're not animating, a single iteration over all objects is enough.
+ iter.iterate_and_write();
+ }
+
+ iter.release_writers();
+ 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;
+ BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain);
+ }
+
+ data->export_ok = !data->was_canceled;
+
+ *progress = 1.0f;
+ *do_update = true;
+}
+
+static void export_endjob(void *customdata)
+{
+ ExportJobData *data = static_cast<ExportJobData *>(customdata);
+
+ DEG_graph_free(data->depsgraph);
+
+ if (data->was_canceled && BLI_exists(data->filename)) {
+ BLI_delete(data->filename, false, false);
+ }
+
+ G.is_rendering = false;
+ WM_set_locked_interface(data->wm, false);
+}
+
+} // namespace USD
+
+bool USD_export(bContext *C,
+ const char *filepath,
+ const USDExportParams *params,
+ bool as_background_job)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
+
+ USD::ExportJobData *job = static_cast<USD::ExportJobData *>(
+ MEM_mallocN(sizeof(USD::ExportJobData), "ExportJobData"));
+
+ job->bmain = CTX_data_main(C);
+ job->wm = CTX_wm_manager(C);
+ job->export_ok = false;
+ BLI_strncpy(job->filename, filepath, sizeof(job->filename));
+
+ job->depsgraph = DEG_graph_new(job->bmain, scene, view_layer, params->evaluation_mode);
+ job->params = *params;
+
+ bool export_ok = false;
+ if (as_background_job) {
+ wmJob *wm_job = WM_jobs_get(
+ job->wm, CTX_wm_window(C), scene, "USD Export", WM_JOB_PROGRESS, WM_JOB_TYPE_ALEMBIC);
+
+ /* setup job */
+ WM_jobs_customdata_set(wm_job, job, MEM_freeN);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
+ WM_jobs_callbacks(wm_job, USD::export_startjob, NULL, NULL, USD::export_endjob);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+ else {
+ /* Fake a job context, so that we don't need NULL pointer checks while exporting. */
+ short stop = 0, do_update = 0;
+ float progress = 0.f;
+
+ USD::export_startjob(job, &stop, &do_update, &progress);
+ USD::export_endjob(job);
+ export_ok = job->export_ok;
+
+ MEM_freeN(job);
+ }
+
+ return export_ok;
+}
diff --git a/source/blender/usd/intern/usd_exporter_context.h b/source/blender/usd/intern/usd_exporter_context.h
new file mode 100644
index 00000000000..35ff13b2e91
--- /dev/null
+++ b/source/blender/usd/intern/usd_exporter_context.h
@@ -0,0 +1,44 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __USD_EXPORTER_CONTEXT_H__
+#define __USD_EXPORTER_CONTEXT_H__
+
+#include "usd.h"
+
+#include <pxr/usd/sdf/path.h>
+#include <pxr/usd/usd/common.h>
+
+struct Depsgraph;
+struct Object;
+
+namespace USD {
+
+class USDHierarchyIterator;
+
+struct USDExporterContext {
+ const Depsgraph *depsgraph;
+ const pxr::UsdStageRefPtr stage;
+ const pxr::SdfPath usd_path;
+ const USDHierarchyIterator *hierarchy_iterator;
+ const USDExportParams &export_params;
+};
+
+} // namespace USD
+
+#endif /* __USD_EXPORTER_CONTEXT_H__ */
diff --git a/source/blender/usd/intern/usd_hierarchy_iterator.cc b/source/blender/usd/intern/usd_hierarchy_iterator.cc
new file mode 100644
index 00000000000..f53cba8b2c6
--- /dev/null
+++ b/source/blender/usd/intern/usd_hierarchy_iterator.cc
@@ -0,0 +1,150 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "usd.h"
+
+#include "usd_hierarchy_iterator.h"
+#include "usd_writer_abstract.h"
+#include "usd_writer_camera.h"
+#include "usd_writer_hair.h"
+#include "usd_writer_light.h"
+#include "usd_writer_mesh.h"
+#include "usd_writer_transform.h"
+
+#include <string>
+
+#include <pxr/base/tf/stringUtils.h>
+
+extern "C" {
+#include "BKE_anim.h"
+
+#include "BLI_assert.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_ID.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+}
+
+namespace USD {
+
+USDHierarchyIterator::USDHierarchyIterator(Depsgraph *depsgraph,
+ pxr::UsdStageRefPtr stage,
+ const USDExportParams &params)
+ : AbstractHierarchyIterator(depsgraph), stage_(stage), params_(params)
+{
+}
+
+bool USDHierarchyIterator::mark_as_weak_export(const Object *object) const
+{
+ if (params_.selected_objects_only && (object->base_flag & BASE_SELECTED) == 0) {
+ return true;
+ }
+ if (params_.visible_objects_only && (object->base_flag & BASE_VISIBLE_VIEWLAYER) == 0) {
+ return true;
+ }
+ return false;
+}
+
+void USDHierarchyIterator::delete_object_writer(AbstractHierarchyWriter *writer)
+{
+ delete static_cast<USDAbstractWriter *>(writer);
+}
+
+std::string USDHierarchyIterator::make_valid_name(const std::string &name) const
+{
+ return pxr::TfMakeValidIdentifier(name);
+}
+
+void USDHierarchyIterator::set_export_frame(float frame_nr)
+{
+ // The USD stage is already set up to have FPS timecodes per frame.
+ export_time_ = pxr::UsdTimeCode(frame_nr);
+}
+
+const pxr::UsdTimeCode &USDHierarchyIterator::get_export_time_code() const
+{
+ return export_time_;
+}
+
+USDExporterContext USDHierarchyIterator::create_usd_export_context(const HierarchyContext *context)
+{
+ return USDExporterContext{depsgraph_, stage_, pxr::SdfPath(context->export_path), this, params_};
+}
+
+AbstractHierarchyWriter *USDHierarchyIterator::create_transform_writer(
+ const HierarchyContext *context)
+{
+ return new USDTransformWriter(create_usd_export_context(context));
+}
+
+AbstractHierarchyWriter *USDHierarchyIterator::create_data_writer(const HierarchyContext *context)
+{
+ USDExporterContext usd_export_context = create_usd_export_context(context);
+ USDAbstractWriter *data_writer = nullptr;
+
+ switch (context->object->type) {
+ case OB_MESH:
+ data_writer = new USDMeshWriter(usd_export_context);
+ break;
+ case OB_CAMERA:
+ data_writer = new USDCameraWriter(usd_export_context);
+ break;
+ case OB_LAMP:
+ data_writer = new USDLightWriter(usd_export_context);
+ break;
+
+ case OB_EMPTY:
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ case OB_MBALL:
+ case OB_SPEAKER:
+ case OB_LIGHTPROBE:
+ case OB_LATTICE:
+ case OB_ARMATURE:
+ case OB_GPENCIL:
+ return nullptr;
+ case OB_TYPE_MAX:
+ BLI_assert(!"OB_TYPE_MAX should not be used");
+ return nullptr;
+ }
+
+ if (!data_writer->is_supported(context)) {
+ delete data_writer;
+ return nullptr;
+ }
+
+ return data_writer;
+}
+
+AbstractHierarchyWriter *USDHierarchyIterator::create_hair_writer(const HierarchyContext *context)
+{
+ if (!params_.export_hair) {
+ return nullptr;
+ }
+ return new USDHairWriter(create_usd_export_context(context));
+}
+
+AbstractHierarchyWriter *USDHierarchyIterator::create_particle_writer(const HierarchyContext *)
+{
+ return nullptr;
+}
+
+} // namespace USD
diff --git a/source/blender/usd/intern/usd_hierarchy_iterator.h b/source/blender/usd/intern/usd_hierarchy_iterator.h
new file mode 100644
index 00000000000..90c82c6e551
--- /dev/null
+++ b/source/blender/usd/intern/usd_hierarchy_iterator.h
@@ -0,0 +1,71 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __USD_HIERARCHY_ITERATOR_H__
+#define __USD_HIERARCHY_ITERATOR_H__
+
+#include "abstract_hierarchy_iterator.h"
+#include "usd_exporter_context.h"
+#include "usd.h"
+
+#include <string>
+
+#include <pxr/usd/usd/common.h>
+#include <pxr/usd/usd/timeCode.h>
+
+struct Depsgraph;
+struct ID;
+struct Object;
+
+namespace USD {
+
+class USDHierarchyIterator : public AbstractHierarchyIterator {
+ private:
+ const pxr::UsdStageRefPtr stage_;
+ pxr::UsdTimeCode export_time_;
+ const USDExportParams &params_;
+
+ public:
+ USDHierarchyIterator(Depsgraph *depsgraph,
+ pxr::UsdStageRefPtr stage,
+ const USDExportParams &params);
+
+ void set_export_frame(float frame_nr);
+ const pxr::UsdTimeCode &get_export_time_code() const;
+
+ virtual std::string make_valid_name(const std::string &name) const override;
+
+ protected:
+ virtual bool mark_as_weak_export(const Object *object) const override;
+
+ virtual AbstractHierarchyWriter *create_transform_writer(
+ const HierarchyContext *context) override;
+ virtual AbstractHierarchyWriter *create_data_writer(const HierarchyContext *context) override;
+ virtual AbstractHierarchyWriter *create_hair_writer(const HierarchyContext *context) override;
+ virtual AbstractHierarchyWriter *create_particle_writer(
+ const HierarchyContext *context) override;
+
+ virtual void delete_object_writer(AbstractHierarchyWriter *writer) override;
+
+ private:
+ USDExporterContext create_usd_export_context(const HierarchyContext *context);
+};
+
+} // namespace USD
+
+#endif /* __USD_HIERARCHY_ITERATOR_H__ */
diff --git a/source/blender/usd/intern/usd_writer_abstract.cc b/source/blender/usd/intern/usd_writer_abstract.cc
new file mode 100644
index 00000000000..4d0b4364fb5
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_abstract.cc
@@ -0,0 +1,147 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "usd_writer_abstract.h"
+#include "usd_hierarchy_iterator.h"
+
+#include <pxr/base/tf/stringUtils.h>
+
+extern "C" {
+#include "BKE_animsys.h"
+#include "BKE_key.h"
+
+#include "DNA_modifier_types.h"
+}
+
+/* TfToken objects are not cheap to construct, so we do it once. */
+namespace usdtokens {
+// Materials
+static const pxr::TfToken diffuse_color("diffuseColor", pxr::TfToken::Immortal);
+static const pxr::TfToken metallic("metallic", pxr::TfToken::Immortal);
+static const pxr::TfToken preview_shader("previewShader", pxr::TfToken::Immortal);
+static const pxr::TfToken preview_surface("UsdPreviewSurface", pxr::TfToken::Immortal);
+static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal);
+static const pxr::TfToken surface("surface", pxr::TfToken::Immortal);
+} // namespace usdtokens
+
+namespace USD {
+
+USDAbstractWriter::USDAbstractWriter(const USDExporterContext &usd_export_context)
+ : usd_export_context_(usd_export_context),
+ usd_value_writer_(),
+ frame_has_been_written_(false),
+ is_animated_(false)
+{
+}
+
+USDAbstractWriter::~USDAbstractWriter()
+{
+}
+
+bool USDAbstractWriter::is_supported(const HierarchyContext * /*context*/) const
+{
+ return true;
+}
+
+pxr::UsdTimeCode USDAbstractWriter::get_export_time_code() const
+{
+ if (is_animated_) {
+ return usd_export_context_.hierarchy_iterator->get_export_time_code();
+ }
+ // By using the default timecode USD won't even write a single `timeSample` for non-animated
+ // data. Instead, it writes it as non-timesampled.
+ static pxr::UsdTimeCode default_timecode = pxr::UsdTimeCode::Default();
+ return default_timecode;
+}
+
+void USDAbstractWriter::write(HierarchyContext &context)
+{
+ if (!frame_has_been_written_) {
+ is_animated_ = usd_export_context_.export_params.export_animation &&
+ check_is_animated(context);
+ }
+ else if (!is_animated_) {
+ /* A frame has already been written, and without animation one frame is enough. */
+ return;
+ }
+
+ do_write(context);
+
+ frame_has_been_written_ = true;
+}
+
+bool USDAbstractWriter::check_is_animated(const HierarchyContext &context) const
+{
+ const Object *object = context.object;
+
+ if (BKE_animdata_id_is_animated(static_cast<ID *>(object->data))) {
+ return true;
+ }
+ if (BKE_key_from_object(object) != nullptr) {
+ return true;
+ }
+
+ /* Test modifiers. */
+ /* TODO(Sybren): replace this with a check on the depsgraph to properly check for dependency on
+ * time. */
+ ModifierData *md = static_cast<ModifierData *>(object->modifiers.first);
+ while (md) {
+ if (md->type != eModifierType_Subsurf) {
+ return true;
+ }
+ md = md->next;
+ }
+
+ return false;
+}
+
+const pxr::SdfPath &USDAbstractWriter::usd_path() const
+{
+ return usd_export_context_.usd_path;
+}
+
+pxr::UsdShadeMaterial USDAbstractWriter::ensure_usd_material(Material *material)
+{
+ static pxr::SdfPath material_library_path("/_materials");
+ pxr::UsdStageRefPtr stage = usd_export_context_.stage;
+
+ // Construct the material.
+ pxr::TfToken material_name(usd_export_context_.hierarchy_iterator->get_id_name(&material->id));
+ pxr::SdfPath usd_path = material_library_path.AppendChild(material_name);
+ pxr::UsdShadeMaterial usd_material = pxr::UsdShadeMaterial::Get(stage, usd_path);
+ if (usd_material) {
+ return usd_material;
+ }
+ usd_material = pxr::UsdShadeMaterial::Define(stage, usd_path);
+
+ // Construct the shader.
+ pxr::SdfPath shader_path = usd_path.AppendChild(usdtokens::preview_shader);
+ pxr::UsdShadeShader shader = pxr::UsdShadeShader::Define(stage, shader_path);
+ shader.CreateIdAttr(pxr::VtValue(usdtokens::preview_surface));
+ shader.CreateInput(usdtokens::diffuse_color, pxr::SdfValueTypeNames->Color3f)
+ .Set(pxr::GfVec3f(material->r, material->g, material->b));
+ shader.CreateInput(usdtokens::roughness, pxr::SdfValueTypeNames->Float).Set(material->roughness);
+ shader.CreateInput(usdtokens::metallic, pxr::SdfValueTypeNames->Float).Set(material->metallic);
+
+ // Connect the shader and the material together.
+ usd_material.CreateSurfaceOutput().ConnectToSource(shader, usdtokens::surface);
+
+ return usd_material;
+}
+
+} // namespace USD
diff --git a/source/blender/usd/intern/usd_writer_abstract.h b/source/blender/usd/intern/usd_writer_abstract.h
new file mode 100644
index 00000000000..8f727638704
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_abstract.h
@@ -0,0 +1,78 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __USD_WRITER_ABSTRACT_H__
+#define __USD_WRITER_ABSTRACT_H__
+
+#include "usd_exporter_context.h"
+#include "abstract_hierarchy_iterator.h"
+
+#include <pxr/usd/sdf/path.h>
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdShade/material.h>
+#include <pxr/usd/usdUtils/sparseValueWriter.h>
+
+#include <vector>
+
+extern "C" {
+#include "DEG_depsgraph_query.h"
+#include "DNA_material_types.h"
+}
+
+struct Main;
+struct Material;
+struct Object;
+
+namespace USD {
+
+class USDAbstractWriter : public AbstractHierarchyWriter {
+ protected:
+ const USDExporterContext usd_export_context_;
+ pxr::UsdUtilsSparseValueWriter usd_value_writer_;
+
+ bool frame_has_been_written_;
+ bool is_animated_;
+
+ public:
+ USDAbstractWriter(const USDExporterContext &usd_export_context);
+ virtual ~USDAbstractWriter();
+
+ virtual void write(HierarchyContext &context) override;
+
+ /* Returns true if the data to be written is actually supported. This would, for example, allow a
+ * hypothetical camera writer accept a perspective camera but reject an orthogonal one.
+ *
+ * Returning false from a transform writer will prevent the object and all its decendants from
+ * being exported. Returning false from a data writer (object data, hair, or particles) will
+ * only prevent that data from being written (and thus cause the object to be exported as an
+ * Empty). */
+ virtual bool is_supported(const HierarchyContext *context) const;
+
+ const pxr::SdfPath &usd_path() const;
+
+ protected:
+ virtual void do_write(HierarchyContext &context) = 0;
+ virtual bool check_is_animated(const HierarchyContext &context) const;
+ pxr::UsdTimeCode get_export_time_code() const;
+
+ pxr::UsdShadeMaterial ensure_usd_material(Material *material);
+};
+
+} // namespace USD
+
+#endif /* __USD_WRITER_ABSTRACT_H__ */
diff --git a/source/blender/usd/intern/usd_writer_camera.cc b/source/blender/usd/intern/usd_writer_camera.cc
new file mode 100644
index 00000000000..9b85d69559c
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_camera.cc
@@ -0,0 +1,111 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "usd_writer_camera.h"
+#include "usd_hierarchy_iterator.h"
+
+#include <pxr/usd/usdGeom/camera.h>
+#include <pxr/usd/usdGeom/tokens.h>
+
+extern "C" {
+#include "BKE_camera.h"
+#include "BLI_assert.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_scene_types.h"
+}
+
+namespace USD {
+
+USDCameraWriter::USDCameraWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx)
+{
+}
+
+bool USDCameraWriter::is_supported(const HierarchyContext *context) const
+{
+ Camera *camera = static_cast<Camera *>(context->object->data);
+ return camera->type == CAM_PERSP;
+}
+
+static void camera_sensor_size_for_render(const Camera *camera,
+ const struct RenderData *rd,
+ float *r_sensor_x,
+ float *r_sensor_y)
+{
+ /* Compute the final image size in pixels. */
+ float sizex = rd->xsch * rd->xasp;
+ float sizey = rd->ysch * rd->yasp;
+
+ int sensor_fit = BKE_camera_sensor_fit(camera->sensor_fit, sizex, sizey);
+
+ switch (sensor_fit) {
+ case CAMERA_SENSOR_FIT_HOR:
+ *r_sensor_x = camera->sensor_x;
+ *r_sensor_y = camera->sensor_x * sizey / sizex;
+ break;
+ case CAMERA_SENSOR_FIT_VERT:
+ *r_sensor_x = camera->sensor_y * sizex / sizey;
+ *r_sensor_y = camera->sensor_y;
+ break;
+ case CAMERA_SENSOR_FIT_AUTO:
+ BLI_assert(!"Camera fit should be either horizontal or vertical");
+ break;
+ }
+}
+
+void USDCameraWriter::do_write(HierarchyContext &context)
+{
+ pxr::UsdTimeCode timecode = get_export_time_code();
+ pxr::UsdGeomCamera usd_camera = pxr::UsdGeomCamera::Define(usd_export_context_.stage,
+ usd_export_context_.usd_path);
+
+ Camera *camera = static_cast<Camera *>(context.object->data);
+ Scene *scene = DEG_get_evaluated_scene(usd_export_context_.depsgraph);
+
+ usd_camera.CreateProjectionAttr().Set(pxr::UsdGeomTokens->perspective);
+
+ /* USD stores the focal length in "millimeters or tenths of world units", because at some point
+ * they decided world units might be centimeters. Quite confusing, as the USD Viewer shows the
+ * correct FoV when we write millimeters and not "tenths of world units".
+ */
+ usd_camera.CreateFocalLengthAttr().Set(camera->lens, timecode);
+
+ float aperture_x, aperture_y;
+ camera_sensor_size_for_render(camera, &scene->r, &aperture_x, &aperture_y);
+
+ float film_aspect = aperture_x / aperture_y;
+ usd_camera.CreateHorizontalApertureAttr().Set(aperture_x, timecode);
+ usd_camera.CreateVerticalApertureAttr().Set(aperture_y, timecode);
+ usd_camera.CreateHorizontalApertureOffsetAttr().Set(aperture_x * camera->shiftx, timecode);
+ usd_camera.CreateVerticalApertureOffsetAttr().Set(aperture_y * camera->shifty * film_aspect,
+ timecode);
+
+ usd_camera.CreateClippingRangeAttr().Set(
+ pxr::VtValue(pxr::GfVec2f(camera->clip_start, camera->clip_end)), timecode);
+
+ // Write DoF-related attributes.
+ if (camera->dof.flag & CAM_DOF_ENABLED) {
+ usd_camera.CreateFStopAttr().Set(camera->dof.aperture_fstop, timecode);
+
+ float focus_distance = scene->unit.scale_length *
+ BKE_camera_object_dof_distance(context.object);
+ usd_camera.CreateFocusDistanceAttr().Set(focus_distance, timecode);
+ }
+}
+
+} // namespace USD
diff --git a/source/blender/usd/intern/usd_writer_camera.h b/source/blender/usd/intern/usd_writer_camera.h
new file mode 100644
index 00000000000..971264ef11e
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_camera.h
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __USD_WRITER_CAMERA_H__
+#define __USD_WRITER_CAMERA_H__
+
+#include "usd_writer_abstract.h"
+
+namespace USD {
+
+/* Writer for writing camera data to UsdGeomCamera. */
+class USDCameraWriter : public USDAbstractWriter {
+ public:
+ USDCameraWriter(const USDExporterContext &ctx);
+
+ protected:
+ virtual bool is_supported(const HierarchyContext *context) const override;
+ virtual void do_write(HierarchyContext &context) override;
+};
+
+} // namespace USD
+
+#endif /* __USD_WRITER_CAMERA_H__ */
diff --git a/source/blender/usd/intern/usd_writer_hair.cc b/source/blender/usd/intern/usd_writer_hair.cc
new file mode 100644
index 00000000000..9251425c0b8
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_hair.cc
@@ -0,0 +1,90 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "usd_writer_hair.h"
+#include "usd_hierarchy_iterator.h"
+
+#include <pxr/usd/usdGeom/basisCurves.h>
+#include <pxr/usd/usdGeom/tokens.h>
+
+extern "C" {
+#include "BKE_particle.h"
+
+#include "DNA_particle_types.h"
+}
+
+namespace USD {
+
+USDHairWriter::USDHairWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx)
+{
+}
+
+void USDHairWriter::do_write(HierarchyContext &context)
+{
+ ParticleSystem *psys = context.particle_system;
+ ParticleCacheKey **cache = psys->pathcache;
+ if (cache == nullptr) {
+ return;
+ }
+
+ pxr::UsdTimeCode timecode = get_export_time_code();
+ pxr::UsdGeomBasisCurves curves = pxr::UsdGeomBasisCurves::Define(usd_export_context_.stage,
+ usd_export_context_.usd_path);
+
+ // TODO(Sybren): deal with (psys->part->flag & PART_HAIR_BSPLINE)
+ curves.CreateBasisAttr(pxr::VtValue(pxr::UsdGeomTokens->bspline));
+ curves.CreateTypeAttr(pxr::VtValue(pxr::UsdGeomTokens->cubic));
+
+ pxr::VtArray<pxr::GfVec3f> points;
+ pxr::VtIntArray curve_point_counts;
+ curve_point_counts.reserve(psys->totpart);
+
+ ParticleCacheKey *strand;
+ for (int strand_index = 0; strand_index < psys->totpart; ++strand_index) {
+ strand = cache[strand_index];
+
+ int point_count = strand->segments + 1;
+ curve_point_counts.push_back(point_count);
+
+ for (int point_index = 0; point_index < point_count; ++point_index, ++strand) {
+ points.push_back(pxr::GfVec3f(strand->co));
+ }
+ }
+
+ pxr::UsdAttribute attr_points = curves.CreatePointsAttr(pxr::VtValue(), true);
+ pxr::UsdAttribute attr_vertex_counts = curves.CreateCurveVertexCountsAttr(pxr::VtValue(), true);
+ if (!attr_points.HasValue()) {
+ attr_points.Set(points, pxr::UsdTimeCode::Default());
+ attr_vertex_counts.Set(curve_point_counts, pxr::UsdTimeCode::Default());
+ }
+ usd_value_writer_.SetAttribute(attr_points, pxr::VtValue(points), timecode);
+ usd_value_writer_.SetAttribute(attr_vertex_counts, pxr::VtValue(curve_point_counts), timecode);
+
+ if (psys->totpart > 0) {
+ pxr::VtArray<pxr::GfVec3f> colors;
+ colors.push_back(pxr::GfVec3f(cache[0]->col));
+ curves.CreateDisplayColorAttr(pxr::VtValue(colors));
+ }
+}
+
+bool USDHairWriter::check_is_animated(const HierarchyContext &) const
+{
+ return true;
+}
+
+} // namespace USD
diff --git a/source/blender/usd/intern/usd_writer_hair.h b/source/blender/usd/intern/usd_writer_hair.h
new file mode 100644
index 00000000000..1e882fa1654
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_hair.h
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __USD_WRITER_HAIR_H__
+#define __USD_WRITER_HAIR_H__
+
+#include "usd_writer_abstract.h"
+
+namespace USD {
+
+/* Writer for writing hair particle data as USD curves. */
+class USDHairWriter : public USDAbstractWriter {
+ public:
+ USDHairWriter(const USDExporterContext &ctx);
+
+ protected:
+ virtual void do_write(HierarchyContext &context) override;
+ virtual bool check_is_animated(const HierarchyContext &context) const override;
+};
+
+} // namespace USD
+
+#endif /* __USD_WRITER_HAIR_H__ */
diff --git a/source/blender/usd/intern/usd_writer_light.cc b/source/blender/usd/intern/usd_writer_light.cc
new file mode 100644
index 00000000000..e13e2c58a79
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_light.cc
@@ -0,0 +1,112 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "usd_writer_light.h"
+#include "usd_hierarchy_iterator.h"
+
+#include <pxr/usd/usdLux/diskLight.h>
+#include <pxr/usd/usdLux/distantLight.h>
+#include <pxr/usd/usdLux/rectLight.h>
+#include <pxr/usd/usdLux/sphereLight.h>
+
+extern "C" {
+#include "BLI_assert.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_light_types.h"
+#include "DNA_object_types.h"
+}
+
+namespace USD {
+
+USDLightWriter::USDLightWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx)
+{
+}
+
+bool USDLightWriter::is_supported(const HierarchyContext *context) const
+{
+ Light *light = static_cast<Light *>(context->object->data);
+ return ELEM(light->type, LA_AREA, LA_LOCAL, LA_SUN);
+}
+
+void USDLightWriter::do_write(HierarchyContext &context)
+{
+ pxr::UsdStageRefPtr stage = usd_export_context_.stage;
+ const pxr::SdfPath &usd_path = usd_export_context_.usd_path;
+ pxr::UsdTimeCode timecode = get_export_time_code();
+
+ Light *light = static_cast<Light *>(context.object->data);
+ pxr::UsdLuxLight usd_light;
+
+ switch (light->type) {
+ case LA_AREA:
+ switch (light->area_shape) {
+ case LA_AREA_DISK:
+ case LA_AREA_ELLIPSE: { /* An ellipse light will deteriorate into a disk light. */
+ pxr::UsdLuxDiskLight disk_light = pxr::UsdLuxDiskLight::Define(stage, usd_path);
+ disk_light.CreateRadiusAttr().Set(light->area_size, timecode);
+ usd_light = disk_light;
+ break;
+ }
+ case LA_AREA_RECT: {
+ pxr::UsdLuxRectLight rect_light = pxr::UsdLuxRectLight::Define(stage, usd_path);
+ rect_light.CreateWidthAttr().Set(light->area_size, timecode);
+ rect_light.CreateHeightAttr().Set(light->area_sizey, timecode);
+ usd_light = rect_light;
+ break;
+ }
+ case LA_AREA_SQUARE: {
+ pxr::UsdLuxRectLight rect_light = pxr::UsdLuxRectLight::Define(stage, usd_path);
+ rect_light.CreateWidthAttr().Set(light->area_size, timecode);
+ rect_light.CreateHeightAttr().Set(light->area_size, timecode);
+ usd_light = rect_light;
+ break;
+ }
+ }
+ break;
+ case LA_LOCAL: {
+ pxr::UsdLuxSphereLight sphere_light = pxr::UsdLuxSphereLight::Define(stage, usd_path);
+ sphere_light.CreateRadiusAttr().Set(light->area_size, timecode);
+ usd_light = sphere_light;
+ break;
+ }
+ case LA_SUN:
+ usd_light = pxr::UsdLuxDistantLight::Define(stage, usd_path);
+ break;
+ default:
+ BLI_assert(!"is_supported() returned true for unsupported light type");
+ }
+
+ /* Scale factor to get to somewhat-similar illumination. Since the USDViewer had similar
+ * over-exposure as Blender Internal with the same values, this code applies the reverse of the
+ * versioning code in light_emission_unify(). */
+ float usd_intensity;
+ if (light->type == LA_SUN) {
+ /* Untested, as the Hydra GL viewport of USDViewer doesn't support distant lights. */
+ usd_intensity = light->energy;
+ }
+ else {
+ usd_intensity = light->energy / 100.f;
+ }
+ usd_light.CreateIntensityAttr().Set(usd_intensity, timecode);
+
+ usd_light.CreateColorAttr().Set(pxr::GfVec3f(light->r, light->g, light->b), timecode);
+ usd_light.CreateSpecularAttr().Set(light->spec_fac, timecode);
+}
+
+} // namespace USD
diff --git a/source/blender/usd/intern/usd_writer_light.h b/source/blender/usd/intern/usd_writer_light.h
new file mode 100644
index 00000000000..349c034b6bc
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_light.h
@@ -0,0 +1,37 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __USD_WRITER_LIGHT_H__
+#define __USD_WRITER_LIGHT_H__
+
+#include "usd_writer_abstract.h"
+
+namespace USD {
+
+class USDLightWriter : public USDAbstractWriter {
+ public:
+ USDLightWriter(const USDExporterContext &ctx);
+
+ protected:
+ virtual bool is_supported(const HierarchyContext *context) const override;
+ virtual void do_write(HierarchyContext &context) override;
+};
+
+} // namespace USD
+
+#endif /* __USD_WRITER_LIGHT_H__ */
diff --git a/source/blender/usd/intern/usd_writer_mesh.cc b/source/blender/usd/intern/usd_writer_mesh.cc
new file mode 100644
index 00000000000..28e13013cfd
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_mesh.cc
@@ -0,0 +1,489 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "usd_writer_mesh.h"
+#include "usd_hierarchy_iterator.h"
+
+#include <pxr/usd/usdGeom/mesh.h>
+#include <pxr/usd/usdShade/material.h>
+#include <pxr/usd/usdShade/materialBindingAPI.h>
+
+extern "C" {
+#include "BLI_assert.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_anim.h"
+#include "BKE_customdata.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+
+#include "DNA_layer_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_fluidsim_types.h"
+#include "DNA_particle_types.h"
+}
+
+namespace USD {
+
+USDGenericMeshWriter::USDGenericMeshWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx)
+{
+}
+
+bool USDGenericMeshWriter::is_supported(const HierarchyContext *context) const
+{
+ Object *object = context->object;
+ bool is_dupli = context->duplicator != nullptr;
+ int base_flag;
+
+ if (is_dupli) {
+ /* Construct the object's base flags from its dupliparent, just like is done in
+ * deg_objects_dupli_iterator_next(). Without this, the visiblity check below will fail. Doing
+ * this here, instead of a more suitable location in AbstractHierarchyIterator, prevents
+ * copying the Object for every dupli. */
+ base_flag = object->base_flag;
+ object->base_flag = context->duplicator->base_flag | BASE_FROM_DUPLI;
+ }
+
+ int visibility = BKE_object_visibility(object,
+ usd_export_context_.export_params.evaluation_mode);
+
+ if (is_dupli) {
+ object->base_flag = base_flag;
+ }
+
+ return (visibility & OB_VISIBLE_SELF) != 0;
+}
+
+void USDGenericMeshWriter::do_write(HierarchyContext &context)
+{
+ Object *object_eval = context.object;
+ bool needsfree = false;
+ Mesh *mesh = get_export_mesh(object_eval, needsfree);
+
+ if (mesh == NULL) {
+ return;
+ }
+
+ try {
+ write_mesh(context, mesh);
+
+ if (needsfree) {
+ free_export_mesh(mesh);
+ }
+ }
+ catch (...) {
+ if (needsfree) {
+ free_export_mesh(mesh);
+ }
+ throw;
+ }
+}
+
+void USDGenericMeshWriter::free_export_mesh(Mesh *mesh)
+{
+ BKE_id_free(NULL, mesh);
+}
+
+struct USDMeshData {
+ pxr::VtArray<pxr::GfVec3f> points;
+ pxr::VtIntArray face_vertex_counts;
+ pxr::VtIntArray face_indices;
+ std::map<short, pxr::VtIntArray> face_groups;
+
+ /* The length of this array specifies the number of creases on the surface. Each element gives
+ * the number of (must be adjacent) vertices in each crease, whose indices are linearly laid out
+ * in the 'creaseIndices' attribute. Since each crease must be at least one edge long, each
+ * element of this array should be greater than one. */
+ pxr::VtIntArray crease_lengths;
+ /* The indices of all vertices forming creased edges. The size of this array must be equal to the
+ * sum of all elements of the 'creaseLengths' attribute. */
+ pxr::VtIntArray crease_vertex_indices;
+ /* The per-crease or per-edge sharpness for all creases (Usd.Mesh.SHARPNESS_INFINITE for a
+ * perfectly sharp crease). Since 'creaseLengths' encodes the number of vertices in each crease,
+ * the number of elements in this array will be either len(creaseLengths) or the sum over all X
+ * of (creaseLengths[X] - 1). Note that while the RI spec allows each crease to have either a
+ * single sharpness or a value per-edge, USD will encode either a single sharpness per crease on
+ * a mesh, or sharpnesses for all edges making up the creases on a mesh. */
+ pxr::VtFloatArray crease_sharpnesses;
+};
+
+void USDGenericMeshWriter::write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
+{
+ pxr::UsdTimeCode timecode = get_export_time_code();
+
+ const CustomData *ldata = &mesh->ldata;
+ for (int layer_idx = 0; layer_idx < ldata->totlayer; layer_idx++) {
+ const CustomDataLayer *layer = &ldata->layers[layer_idx];
+ if (layer->type != CD_MLOOPUV) {
+ continue;
+ }
+
+ /* UV coordinates are stored in a Primvar on the Mesh, and can be referenced from materials.
+ * The primvar name is the same as the UV Map name. This is to allow the standard name "st"
+ * for texture coordinates by naming the UV Map as such, without having to guess which UV Map
+ * is the "standard" one. */
+ pxr::TfToken primvar_name(pxr::TfMakeValidIdentifier(layer->name));
+ pxr::UsdGeomPrimvar uv_coords_primvar = usd_mesh.CreatePrimvar(
+ primvar_name, pxr::SdfValueTypeNames->TexCoord2fArray, pxr::UsdGeomTokens->faceVarying);
+
+ MLoopUV *mloopuv = static_cast<MLoopUV *>(layer->data);
+ pxr::VtArray<pxr::GfVec2f> uv_coords;
+ for (int loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
+ uv_coords.push_back(pxr::GfVec2f(mloopuv[loop_idx].uv));
+ }
+
+ if (!uv_coords_primvar.HasValue()) {
+ uv_coords_primvar.Set(uv_coords, pxr::UsdTimeCode::Default());
+ }
+ const pxr::UsdAttribute &uv_coords_attr = uv_coords_primvar.GetAttr();
+ usd_value_writer_.SetAttribute(uv_coords_attr, pxr::VtValue(uv_coords), timecode);
+ }
+}
+
+void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
+{
+ pxr::UsdTimeCode timecode = get_export_time_code();
+ pxr::UsdTimeCode defaultTime = pxr::UsdTimeCode::Default();
+ pxr::UsdStageRefPtr stage = usd_export_context_.stage;
+ const pxr::SdfPath &usd_path = usd_export_context_.usd_path;
+
+ pxr::UsdGeomMesh usd_mesh = pxr::UsdGeomMesh::Define(stage, usd_path);
+ USDMeshData usd_mesh_data;
+ get_geometry_data(mesh, usd_mesh_data);
+
+ if (usd_export_context_.export_params.use_instancing && context.is_instance()) {
+ // This object data is instanced, just reference the original instead of writing a copy.
+ if (context.export_path == context.original_export_path) {
+ printf("USD ref error: export path is reference path: %s\n", context.export_path.c_str());
+ BLI_assert(!"USD reference error");
+ return;
+ }
+ pxr::SdfPath ref_path(context.original_export_path);
+ if (!usd_mesh.GetPrim().GetReferences().AddInternalReference(ref_path)) {
+ /* See this URL for a description fo why referencing may fail"
+ * https://graphics.pixar.com/usd/docs/api/class_usd_references.html#Usd_Failing_References
+ */
+ printf("USD Export warning: unable to add reference from %s to %s, not instancing object\n",
+ context.export_path.c_str(),
+ context.original_export_path.c_str());
+ return;
+ }
+ /* The material path will be of the form </_materials/{material name}>, which is outside the
+ subtree pointed to by ref_path. As a result, the referenced data is not allowed to point out
+ of its own subtree. It does work when we override the material with exactly the same path,
+ though.*/
+ if (usd_export_context_.export_params.export_materials) {
+ assign_materials(context, usd_mesh, usd_mesh_data.face_groups);
+ }
+ return;
+ }
+
+ pxr::UsdAttribute attr_points = usd_mesh.CreatePointsAttr(pxr::VtValue(), true);
+ pxr::UsdAttribute attr_face_vertex_counts = usd_mesh.CreateFaceVertexCountsAttr(pxr::VtValue(),
+ true);
+ pxr::UsdAttribute attr_face_vertex_indices = usd_mesh.CreateFaceVertexIndicesAttr(pxr::VtValue(),
+ true);
+
+ if (!attr_points.HasValue()) {
+ // Provide the initial value as default. This makes USD write the value as constant if they
+ // don't change over time.
+ attr_points.Set(usd_mesh_data.points, defaultTime);
+ attr_face_vertex_counts.Set(usd_mesh_data.face_vertex_counts, defaultTime);
+ attr_face_vertex_indices.Set(usd_mesh_data.face_indices, defaultTime);
+ }
+
+ usd_value_writer_.SetAttribute(attr_points, pxr::VtValue(usd_mesh_data.points), timecode);
+ usd_value_writer_.SetAttribute(
+ attr_face_vertex_counts, pxr::VtValue(usd_mesh_data.face_vertex_counts), timecode);
+ usd_value_writer_.SetAttribute(
+ attr_face_vertex_indices, pxr::VtValue(usd_mesh_data.face_indices), timecode);
+
+ if (!usd_mesh_data.crease_lengths.empty()) {
+ pxr::UsdAttribute attr_crease_lengths = usd_mesh.CreateCreaseLengthsAttr(pxr::VtValue(), true);
+ pxr::UsdAttribute attr_crease_indices = usd_mesh.CreateCreaseIndicesAttr(pxr::VtValue(), true);
+ pxr::UsdAttribute attr_crease_sharpness = usd_mesh.CreateCreaseSharpnessesAttr(pxr::VtValue(),
+ true);
+
+ if (!attr_crease_lengths.HasValue()) {
+ attr_crease_lengths.Set(usd_mesh_data.crease_lengths, defaultTime);
+ attr_crease_indices.Set(usd_mesh_data.crease_vertex_indices, defaultTime);
+ attr_crease_sharpness.Set(usd_mesh_data.crease_sharpnesses, defaultTime);
+ }
+
+ usd_value_writer_.SetAttribute(
+ attr_crease_lengths, pxr::VtValue(usd_mesh_data.crease_lengths), timecode);
+ usd_value_writer_.SetAttribute(
+ attr_crease_indices, pxr::VtValue(usd_mesh_data.crease_vertex_indices), timecode);
+ usd_value_writer_.SetAttribute(
+ attr_crease_sharpness, pxr::VtValue(usd_mesh_data.crease_sharpnesses), timecode);
+ }
+
+ if (usd_export_context_.export_params.export_uvmaps) {
+ write_uv_maps(mesh, usd_mesh);
+ }
+ if (usd_export_context_.export_params.export_normals) {
+ write_normals(mesh, usd_mesh);
+ }
+ write_surface_velocity(context.object, mesh, usd_mesh);
+
+ // TODO(Sybren): figure out what happens when the face groups change.
+ if (frame_has_been_written_) {
+ return;
+ }
+
+ usd_mesh.CreateSubdivisionSchemeAttr().Set(pxr::UsdGeomTokens->none);
+
+ if (usd_export_context_.export_params.export_materials) {
+ assign_materials(context, usd_mesh, usd_mesh_data.face_groups);
+ }
+}
+
+static void get_vertices(const Mesh *mesh, USDMeshData &usd_mesh_data)
+{
+ usd_mesh_data.points.reserve(mesh->totvert);
+
+ const MVert *verts = mesh->mvert;
+ for (int i = 0; i < mesh->totvert; ++i) {
+ usd_mesh_data.points.push_back(pxr::GfVec3f(verts[i].co));
+ }
+}
+
+static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data)
+{
+ /* Only construct face groups (a.k.a. geometry subsets) when we need them for material
+ * assignments. */
+ bool construct_face_groups = mesh->totcol > 1;
+
+ usd_mesh_data.face_vertex_counts.reserve(mesh->totpoly);
+ usd_mesh_data.face_indices.reserve(mesh->totloop);
+
+ MLoop *mloop = mesh->mloop;
+ MPoly *mpoly = mesh->mpoly;
+ for (int i = 0; i < mesh->totpoly; ++i, ++mpoly) {
+ MLoop *loop = mloop + mpoly->loopstart;
+ usd_mesh_data.face_vertex_counts.push_back(mpoly->totloop);
+ for (int j = 0; j < mpoly->totloop; ++j, ++loop) {
+ usd_mesh_data.face_indices.push_back(loop->v);
+ }
+
+ if (construct_face_groups) {
+ usd_mesh_data.face_groups[mpoly->mat_nr].push_back(i);
+ }
+ }
+}
+
+static void get_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
+{
+ const float factor = 1.0f / 255.0f;
+
+ MEdge *edge = mesh->medge;
+ float sharpness;
+ for (int edge_idx = 0, totedge = mesh->totedge; edge_idx < totedge; ++edge_idx, ++edge) {
+ if (edge->crease == 0) {
+ continue;
+ }
+
+ if (edge->crease == 255) {
+ sharpness = pxr::UsdGeomMesh::SHARPNESS_INFINITE;
+ }
+ else {
+ sharpness = static_cast<float>(edge->crease) * factor;
+ }
+
+ usd_mesh_data.crease_vertex_indices.push_back(edge->v1);
+ usd_mesh_data.crease_vertex_indices.push_back(edge->v2);
+ usd_mesh_data.crease_lengths.push_back(2);
+ usd_mesh_data.crease_sharpnesses.push_back(sharpness);
+ }
+}
+
+void USDGenericMeshWriter::get_geometry_data(const Mesh *mesh, USDMeshData &usd_mesh_data)
+{
+ get_vertices(mesh, usd_mesh_data);
+ get_loops_polys(mesh, usd_mesh_data);
+ get_creases(mesh, usd_mesh_data);
+}
+
+void USDGenericMeshWriter::assign_materials(const HierarchyContext &context,
+ pxr::UsdGeomMesh usd_mesh,
+ const MaterialFaceGroups &usd_face_groups)
+{
+ if (context.object->totcol == 0) {
+ return;
+ }
+
+ /* Binding a material to a geometry subset isn't supported by the Hydra GL viewport yet,
+ * which is why we always bind the first material to the entire mesh. See
+ * https://github.com/PixarAnimationStudios/USD/issues/542 for more info. */
+ bool mesh_material_bound = false;
+ for (short mat_num = 0; mat_num < context.object->totcol; mat_num++) {
+ Material *material = give_current_material(context.object, mat_num + 1);
+ if (material == nullptr) {
+ continue;
+ }
+
+ pxr::UsdShadeMaterial usd_material = ensure_usd_material(material);
+ usd_material.Bind(usd_mesh.GetPrim());
+
+ /* USD seems to support neither per-material nor per-face-group double-sidedness, so we just
+ * use the flag from the first non-empty material slot. */
+ usd_mesh.CreateDoubleSidedAttr(
+ pxr::VtValue((material->blend_flag & MA_BL_CULL_BACKFACE) == 0));
+
+ mesh_material_bound = true;
+ break;
+ }
+
+ if (!mesh_material_bound) {
+ /* Blender defaults to double-sided, but USD to single-sided. */
+ usd_mesh.CreateDoubleSidedAttr(pxr::VtValue(true));
+ }
+
+ if (!mesh_material_bound || usd_face_groups.size() < 2) {
+ /* Either all material slots were empty or there is only one material in use. As geometry
+ * subsets are only written when actually used to assign a material, and the mesh already has
+ * the material assigned, there is no need to continue. */
+ return;
+ }
+
+ // Define a geometry subset per material.
+ for (const MaterialFaceGroups::value_type &face_group : usd_face_groups) {
+ short material_number = face_group.first;
+ const pxr::VtIntArray &face_indices = face_group.second;
+
+ Material *material = give_current_material(context.object, material_number + 1);
+ if (material == nullptr) {
+ continue;
+ }
+
+ pxr::UsdShadeMaterial usd_material = ensure_usd_material(material);
+ pxr::TfToken material_name = usd_material.GetPath().GetNameToken();
+
+ pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(usd_mesh);
+ pxr::UsdGeomSubset usd_face_subset = api.CreateMaterialBindSubset(material_name, face_indices);
+ usd_material.Bind(usd_face_subset.GetPrim());
+ }
+}
+
+void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
+{
+ pxr::UsdTimeCode timecode = get_export_time_code();
+ const float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL));
+
+ pxr::VtVec3fArray loop_normals;
+ loop_normals.reserve(mesh->totloop);
+
+ if (lnors != nullptr) {
+ /* Export custom loop normals. */
+ for (int loop_idx = 0, totloop = mesh->totloop; loop_idx < totloop; ++loop_idx) {
+ loop_normals.push_back(pxr::GfVec3f(lnors[loop_idx]));
+ }
+ }
+ else {
+ /* Compute the loop normals based on the 'smooth' flag. */
+ float normal[3];
+ MPoly *mpoly = mesh->mpoly;
+ const MVert *mvert = mesh->mvert;
+ for (int poly_idx = 0, totpoly = mesh->totpoly; poly_idx < totpoly; ++poly_idx, ++mpoly) {
+ MLoop *mloop = mesh->mloop + mpoly->loopstart;
+
+ if ((mpoly->flag & ME_SMOOTH) == 0) {
+ /* Flat shaded, use common normal for all verts. */
+ BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, normal);
+ pxr::GfVec3f pxr_normal(normal);
+ for (int loop_idx = 0; loop_idx < mpoly->totloop; ++loop_idx) {
+ loop_normals.push_back(pxr_normal);
+ }
+ }
+ else {
+ /* Smooth shaded, use individual vert normals. */
+ for (int loop_idx = 0; loop_idx < mpoly->totloop; ++loop_idx, ++mloop) {
+ normal_short_to_float_v3(normal, mvert[mloop->v].no);
+ loop_normals.push_back(pxr::GfVec3f(normal));
+ }
+ }
+ }
+ }
+
+ pxr::UsdAttribute attr_normals = usd_mesh.CreateNormalsAttr(pxr::VtValue(), true);
+ if (!attr_normals.HasValue()) {
+ attr_normals.Set(loop_normals, pxr::UsdTimeCode::Default());
+ }
+ usd_value_writer_.SetAttribute(attr_normals, pxr::VtValue(loop_normals), timecode);
+ usd_mesh.SetNormalsInterpolation(pxr::UsdGeomTokens->faceVarying);
+}
+
+void USDGenericMeshWriter::write_surface_velocity(Object *object,
+ const Mesh *mesh,
+ pxr::UsdGeomMesh usd_mesh)
+{
+ /* Only velocities from the fluid simulation are exported. This is the most important case,
+ * though, as the baked mesh changes topology all the time, and thus computing the velocities
+ * at import time in a post-processing step is hard. */
+ ModifierData *md = modifiers_findByType(object, eModifierType_Fluidsim);
+ if (md == nullptr) {
+ return;
+ }
+
+ /* Check that the fluid sim modifier is enabled and has useful data. */
+ const bool use_render = (DEG_get_mode(usd_export_context_.depsgraph) == DAG_EVAL_RENDER);
+ const ModifierMode required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ const Scene *scene = DEG_get_evaluated_scene(usd_export_context_.depsgraph);
+ if (!modifier_isEnabled(scene, md, required_mode)) {
+ return;
+ }
+ FluidsimModifierData *fsmd = reinterpret_cast<FluidsimModifierData *>(md);
+ if (!fsmd->fss || fsmd->fss->type != OB_FLUIDSIM_DOMAIN) {
+ return;
+ }
+ FluidsimSettings *fss = fsmd->fss;
+ if (!fss->meshVelocities) {
+ return;
+ }
+
+ /* Export per-vertex velocity vectors. */
+ pxr::VtVec3fArray usd_velocities;
+ usd_velocities.reserve(mesh->totvert);
+
+ FluidVertexVelocity *mesh_velocities = fss->meshVelocities;
+ for (int vertex_idx = 0, totvert = mesh->totvert; vertex_idx < totvert;
+ ++vertex_idx, ++mesh_velocities) {
+ usd_velocities.push_back(pxr::GfVec3f(mesh_velocities->vel));
+ }
+
+ pxr::UsdTimeCode timecode = get_export_time_code();
+ usd_mesh.CreateVelocitiesAttr().Set(usd_velocities, timecode);
+}
+
+USDMeshWriter::USDMeshWriter(const USDExporterContext &ctx) : USDGenericMeshWriter(ctx)
+{
+}
+
+Mesh *USDMeshWriter::get_export_mesh(Object *object_eval, bool & /*r_needsfree*/)
+{
+ return object_eval->runtime.mesh_eval;
+}
+
+} // namespace USD
diff --git a/source/blender/usd/intern/usd_writer_mesh.h b/source/blender/usd/intern/usd_writer_mesh.h
new file mode 100644
index 00000000000..56738e9747d
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_mesh.h
@@ -0,0 +1,66 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __USD_WRITER_MESH_H__
+#define __USD_WRITER_MESH_H__
+
+#include "usd_writer_abstract.h"
+
+#include <pxr/usd/usdGeom/mesh.h>
+
+namespace USD {
+
+struct USDMeshData;
+
+/* Writer for USD geometry. Does not assume the object is a mesh object. */
+class USDGenericMeshWriter : public USDAbstractWriter {
+ public:
+ USDGenericMeshWriter(const USDExporterContext &ctx);
+
+ protected:
+ virtual bool is_supported(const HierarchyContext *context) const override;
+ virtual void do_write(HierarchyContext &context) override;
+
+ virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) = 0;
+ virtual void free_export_mesh(Mesh *mesh);
+
+ private:
+ /* Mapping from material slot number to array of face indices with that material. */
+ typedef std::map<short, pxr::VtIntArray> MaterialFaceGroups;
+
+ void write_mesh(HierarchyContext &context, Mesh *mesh);
+ void get_geometry_data(const Mesh *mesh, struct USDMeshData &usd_mesh_data);
+ void assign_materials(const HierarchyContext &context,
+ pxr::UsdGeomMesh usd_mesh,
+ const MaterialFaceGroups &usd_face_groups);
+ void write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
+ void write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
+ void write_surface_velocity(Object *object, const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
+};
+
+class USDMeshWriter : public USDGenericMeshWriter {
+ public:
+ USDMeshWriter(const USDExporterContext &ctx);
+
+ protected:
+ virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree);
+};
+
+} // namespace USD
+
+#endif /* __USD_WRITER_MESH_H__ */
diff --git a/source/blender/usd/intern/usd_writer_transform.cc b/source/blender/usd/intern/usd_writer_transform.cc
new file mode 100644
index 00000000000..321b516221a
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_transform.cc
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "usd_writer_transform.h"
+#include "usd_hierarchy_iterator.h"
+
+#include <pxr/base/gf/matrix4f.h>
+#include <pxr/usd/usdGeom/xform.h>
+
+extern "C" {
+#include "BKE_object.h"
+
+#include "BLI_math_matrix.h"
+
+#include "DNA_layer_types.h"
+}
+
+namespace USD {
+
+USDTransformWriter::USDTransformWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx)
+{
+}
+
+void USDTransformWriter::do_write(HierarchyContext &context)
+{
+ float parent_relative_matrix[4][4]; // The object matrix relative to the parent.
+ mul_m4_m4m4(parent_relative_matrix, context.parent_matrix_inv_world, context.matrix_world);
+
+ // Write the transform relative to the parent.
+ pxr::UsdGeomXform xform = pxr::UsdGeomXform::Define(usd_export_context_.stage,
+ usd_export_context_.usd_path);
+ if (!xformOp_) {
+ xformOp_ = xform.AddTransformOp();
+ }
+ xformOp_.Set(pxr::GfMatrix4d(parent_relative_matrix), get_export_time_code());
+}
+
+bool USDTransformWriter::check_is_animated(const HierarchyContext &context) const
+{
+ if (context.duplicator != NULL) {
+ /* This object is being duplicated, so could be emitted by a particle system and thus
+ * influenced by forces. TODO(Sybren): Make this more strict. Probably better to get from the
+ * depsgraph whether this object instance has a time source. */
+ return true;
+ }
+ return BKE_object_moves_in_time(context.object, context.animation_check_include_parent);
+}
+
+} // namespace USD
diff --git a/source/blender/usd/intern/usd_writer_transform.h b/source/blender/usd/intern/usd_writer_transform.h
new file mode 100644
index 00000000000..52c4a657f33
--- /dev/null
+++ b/source/blender/usd/intern/usd_writer_transform.h
@@ -0,0 +1,42 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __USD_WRITER_TRANSFORM_H__
+#define __USD_WRITER_TRANSFORM_H__
+
+#include "usd_writer_abstract.h"
+
+#include <pxr/usd/usdGeom/xform.h>
+
+namespace USD {
+
+class USDTransformWriter : public USDAbstractWriter {
+ private:
+ pxr::UsdGeomXformOp xformOp_;
+
+ public:
+ USDTransformWriter(const USDExporterContext &ctx);
+
+ protected:
+ void do_write(HierarchyContext &context) override;
+ bool check_is_animated(const HierarchyContext &context) const override;
+};
+
+} // namespace USD
+
+#endif /* __USD_WRITER_TRANSFORM_H__ */
diff --git a/source/blender/usd/usd.h b/source/blender/usd/usd.h
new file mode 100644
index 00000000000..1a6f5819e21
--- /dev/null
+++ b/source/blender/usd/usd.h
@@ -0,0 +1,62 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+#ifndef __USD_H__
+#define __USD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "DEG_depsgraph.h"
+
+struct Scene;
+struct bContext;
+
+struct USDExportParams {
+ bool export_animation;
+ bool export_hair;
+ bool export_uvmaps;
+ bool export_normals;
+ bool export_materials;
+ bool selected_objects_only;
+ bool visible_objects_only;
+ bool use_instancing;
+ enum eEvaluationMode evaluation_mode;
+};
+
+/* The USD_export takes a as_background_job parameter, and returns a boolean.
+ *
+ * When as_background_job=true, returns false immediately after scheduling
+ * a background job.
+ *
+ * When as_background_job=false, performs the export synchronously, and returns
+ * true when the export was ok, and false if there were any errors.
+ */
+
+bool USD_export(struct bContext *C,
+ const char *filepath,
+ const struct USDExportParams *params,
+ bool as_background_job);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USD_H__ */
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index cb95353554f..3d73a1b591f 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -232,6 +232,8 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *han
typedef struct wmKeyMap *(wmEventHandler_KeymapDynamicFn)(
wmWindowManager *wm, struct wmEventHandler_Keymap *handler)ATTR_WARN_UNUSED_RESULT;
+struct wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(
+ struct wmWindowManager *wm, struct wmEventHandler_Keymap *handler);
struct wmKeyMap *WM_event_get_keymap_from_toolsystem(struct wmWindowManager *wm,
struct wmEventHandler_Keymap *handler);
@@ -825,15 +827,18 @@ typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C,
void WM_tooltip_immediate_init(struct bContext *C,
struct wmWindow *win,
+ struct ScrArea *sa,
struct ARegion *ar,
wmTooltipInitFn init);
void WM_tooltip_timer_init_ex(struct bContext *C,
struct wmWindow *win,
+ struct ScrArea *sa,
struct ARegion *ar,
wmTooltipInitFn init,
double delay);
void WM_tooltip_timer_init(struct bContext *C,
struct wmWindow *win,
+ struct ScrArea *sa,
struct ARegion *ar,
wmTooltipInitFn init);
void WM_tooltip_timer_clear(struct bContext *C, struct wmWindow *win);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 15ad8cbedc4..0c3a5f92113 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -894,6 +894,8 @@ typedef struct wmDropBox {
typedef struct wmTooltipState {
/** Create tooltip on this event. */
struct wmTimer *timer;
+ /** The area the tooltip is created in. */
+ struct ScrArea *area_from;
/** The region the tooltip is created in. */
struct ARegion *region_from;
/** The tooltip region. */
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index 5896424d5fe..c2fbaaaa83c 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -280,7 +280,13 @@ const struct ListBase *WM_gizmomap_group_list(struct wmGizmoMap *gzmap);
struct wmGizmoGroup *WM_gizmomap_group_find(struct wmGizmoMap *gzmap, const char *idname);
struct wmGizmoGroup *WM_gizmomap_group_find_ptr(struct wmGizmoMap *gzmap,
const struct wmGizmoGroupType *gzgt);
+
+eWM_GizmoFlagMapDrawStep WM_gizmomap_drawstep_from_gizmo_group(const struct wmGizmoGroup *gzgroup);
+void WM_gizmomap_tag_refresh_drawstep(struct wmGizmoMap *gzmap,
+ const eWM_GizmoFlagMapDrawStep drawstep);
void WM_gizmomap_tag_refresh(struct wmGizmoMap *gzmap);
+bool WM_gizmomap_tag_refresh_check(struct wmGizmoMap *gzmap);
+
void WM_gizmomap_draw(struct wmGizmoMap *gzmap,
const struct bContext *C,
const eWM_GizmoFlagMapDrawStep drawstep);
@@ -371,7 +377,6 @@ void WM_gizmo_group_type_reinit(struct Main *bmain, const char *idname);
/* Utilities */
bool WM_gizmo_context_check_drawstep(const struct bContext *C, eWM_GizmoFlagMapDrawStep step);
-bool WM_gizmo_group_type_poll(const struct bContext *C, const struct wmGizmoGroupType *gzgt);
void WM_gizmo_group_remove_by_tool(struct bContext *C,
struct Main *bmain,
const struct wmGizmoGroupType *gzgt,
@@ -379,4 +384,8 @@ void WM_gizmo_group_remove_by_tool(struct bContext *C,
void WM_gizmo_group_tag_remove(struct wmGizmoGroup *gzgroup);
+/* Wrap Group Type Callbacks. */
+bool WM_gizmo_group_type_poll(const struct bContext *C, const struct wmGizmoGroupType *gzgt);
+void WM_gizmo_group_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+
#endif /* __WM_GIZMO_API_H__ */
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
index 7bb77375934..c667dd564f7 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
@@ -120,6 +120,25 @@ typedef enum eWM_GizmoFlagGroupTypeFlag {
* We could even move the options into the key-map item.
* ~ campbell. */
WM_GIZMOGROUPTYPE_TOOL_INIT = (1 << 6),
+
+ /**
+ * This gizmo type supports using the fallback tools keymap.
+ * #wmGizmoGroup.use_tool_fallback will need to be set too.
+ *
+ * Often useful in combination with #WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK
+ */
+ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP = (1 << 7),
+
+ /**
+ * Use this from a gizmos refresh callback so we can postpone the refresh operation
+ * until the tweak operation is finished.
+ * Only do this when the group doesn't have a highlighted gizmo.
+ *
+ * The result for the user is tweak events delay the gizmo from flashing under the users cursor,
+ * for selection operations. This means gizmos that use this check don't interfere
+ * with click drag events by popping up under the cursor and catching the tweak event.
+ */
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK = (1 << 8),
} eWM_GizmoFlagGroupTypeFlag;
/**
@@ -441,8 +460,20 @@ typedef struct wmGizmoGroup {
/** Errors and warnings storage. */
struct ReportList *reports;
+ /** Has the same result as hiding all gizmos individually. */
+ union {
+ /** Reasons for hiding. */
+ struct {
+ uint delay_refresh_for_tweak : 1;
+ };
+ /** All, when we only want to check if any are hidden. */
+ uint any;
+ } hide;
+
bool tag_remove;
+ bool use_fallback_keymap;
+
void *customdata;
/** For freeing customdata from above. */
void (*customdata_free)(void *);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
index a8ca65a8a83..e2fb4dc3e0e 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
@@ -503,9 +503,6 @@ void wm_gizmo_calculate_scale(wmGizmo *gz, const bContext *C)
/* Exclude matrix_offset from scale. */
scale *= ED_view3d_pixel_size_no_ui_scale(rv3d, matrix_world[3]);
}
- else {
- scale *= 0.02f;
- }
}
gz->scale_final = gz->scale_basis * scale;
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
index 77950c11c63..73bee883cf8 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
@@ -284,27 +284,13 @@ void WM_gizmogroup_ensure_init(const bContext *C, wmGizmoGroup *gzgroup)
/* Refresh may be called multiple times,
* this just ensures its called at least once before we draw. */
if (UNLIKELY((gzgroup->init_flag & WM_GIZMOGROUP_INIT_REFRESH) == 0)) {
- if (gzgroup->type->refresh) {
- gzgroup->type->refresh(C, gzgroup);
- }
+ /* Clear the flag before calling refresh so the callback
+ * can postpone the refresh by clearing this flag. */
gzgroup->init_flag |= WM_GIZMOGROUP_INIT_REFRESH;
+ WM_gizmo_group_refresh(C, gzgroup);
}
}
-bool WM_gizmo_group_type_poll(const bContext *C, const struct wmGizmoGroupType *gzgt)
-{
- /* If we're tagged, only use compatible. */
- if (gzgt->owner_id[0] != '\0') {
- const WorkSpace *workspace = CTX_wm_workspace(C);
- if (BKE_workspace_owner_id_check(workspace, gzgt->owner_id) == false) {
- return false;
- }
- }
- /* Check for poll function, if gizmo-group belongs to an operator,
- * also check if the operator is running. */
- return (!gzgt->poll || gzgt->poll(C, (wmGizmoGroupType *)gzgt));
-}
-
void WM_gizmo_group_remove_by_tool(bContext *C,
Main *bmain,
const wmGizmoGroupType *gzgt,
@@ -1140,3 +1126,52 @@ void WM_gizmo_group_unlink_delayed_ptr_from_space(wmGizmoGroupType *gzgt,
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Gizmo Group Type Callback Wrappers
+ *
+ * \{ */
+
+bool WM_gizmo_group_type_poll(const bContext *C, const wmGizmoGroupType *gzgt)
+{
+ /* If we're tagged, only use compatible. */
+ if (gzgt->owner_id[0] != '\0') {
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ if (BKE_workspace_owner_id_check(workspace, gzgt->owner_id) == false) {
+ return false;
+ }
+ }
+ /* Check for poll function, if gizmo-group belongs to an operator,
+ * also check if the operator is running. */
+ return (!gzgt->poll || gzgt->poll(C, (wmGizmoGroupType *)gzgt));
+}
+
+void WM_gizmo_group_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ const wmGizmoGroupType *gzgt = gzgroup->type;
+ if (gzgt->flag & WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK) {
+ wmGizmoMap *gzmap = gzgroup->parent_gzmap;
+ wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
+ if (!gz || gz->parent_gzgroup != gzgroup) {
+ wmWindow *win = CTX_wm_window(C);
+ if (win->tweak) {
+ /* We need to run refresh again. */
+ gzgroup->init_flag &= ~WM_GIZMOGROUP_INIT_REFRESH;
+ WM_gizmomap_tag_refresh_drawstep(gzmap, WM_gizmomap_drawstep_from_gizmo_group(gzgroup));
+ gzgroup->hide.delay_refresh_for_tweak = true;
+ return;
+ }
+ }
+ gzgroup->hide.delay_refresh_for_tweak = false;
+ }
+
+ if (gzgroup->hide.any) {
+ return;
+ }
+
+ if (gzgt->refresh) {
+ gzgt->refresh(C, gzgroup);
+ }
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index ef4d8174718..c3dfdd9a419 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -304,16 +304,47 @@ static GHash *WM_gizmomap_gizmo_hash_new(const bContext *C,
return hash;
}
+eWM_GizmoFlagMapDrawStep WM_gizmomap_drawstep_from_gizmo_group(const wmGizmoGroup *gzgroup)
+{
+ eWM_GizmoFlagMapDrawStep step;
+ if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
+ step = WM_GIZMOMAP_DRAWSTEP_3D;
+ }
+ else {
+ step = WM_GIZMOMAP_DRAWSTEP_2D;
+ }
+ return step;
+}
+
+void WM_gizmomap_tag_refresh_drawstep(wmGizmoMap *gzmap, const eWM_GizmoFlagMapDrawStep drawstep)
+{
+ BLI_assert((uint)drawstep < WM_GIZMOMAP_DRAWSTEP_MAX);
+ if (gzmap) {
+ gzmap->update_flag[drawstep] |= (GIZMOMAP_IS_PREPARE_DRAW | GIZMOMAP_IS_REFRESH_CALLBACK);
+ }
+}
+
void WM_gizmomap_tag_refresh(wmGizmoMap *gzmap)
{
if (gzmap) {
- /* We might want only to refresh some, for tag all steps. */
for (int i = 0; i < WM_GIZMOMAP_DRAWSTEP_MAX; i++) {
gzmap->update_flag[i] |= (GIZMOMAP_IS_PREPARE_DRAW | GIZMOMAP_IS_REFRESH_CALLBACK);
}
}
}
+bool WM_gizmomap_tag_refresh_check(wmGizmoMap *gzmap)
+{
+ if (gzmap) {
+ for (int i = 0; i < WM_GIZMOMAP_DRAWSTEP_MAX; i++) {
+ if (gzmap->update_flag[i] & (GIZMOMAP_IS_PREPARE_DRAW | GIZMOMAP_IS_REFRESH_CALLBACK)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
static bool gizmo_prepare_drawing(wmGizmoMap *gzmap,
wmGizmo *gz,
const bContext *C,
@@ -359,7 +390,8 @@ static void gizmomap_prepare_drawing(wmGizmoMap *gzmap,
/* only active gizmo needs updating */
if (gz_modal) {
if ((gz_modal->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL) == 0) {
- if (wm_gizmogroup_is_visible_in_drawstep(gz_modal->parent_gzgroup, drawstep)) {
+ if ((gz_modal->parent_gzgroup->hide.any == 0) &&
+ wm_gizmogroup_is_visible_in_drawstep(gz_modal->parent_gzgroup, drawstep)) {
if (gizmo_prepare_drawing(gzmap, gz_modal, C, draw_gizmos, drawstep)) {
gzmap->update_flag[drawstep] &= ~GIZMOMAP_IS_PREPARE_DRAW;
}
@@ -369,6 +401,10 @@ static void gizmomap_prepare_drawing(wmGizmoMap *gzmap,
}
}
+ /* Allow refresh functions to ask to be refreshed again, clear before the loop below. */
+ const bool do_refresh = gzmap->update_flag[drawstep] & GIZMOMAP_IS_REFRESH_CALLBACK;
+ gzmap->update_flag[drawstep] &= ~GIZMOMAP_IS_REFRESH_CALLBACK;
+
for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
/* check group visibility - drawstep first to avoid unnecessary call of group poll callback */
if (!wm_gizmogroup_is_visible_in_drawstep(gzgroup, drawstep) ||
@@ -379,13 +415,18 @@ static void gizmomap_prepare_drawing(wmGizmoMap *gzmap,
/* Needs to be initialized on first draw. */
/* XXX weak: Gizmo-group may skip refreshing if it's invisible
* (map gets untagged nevertheless). */
- if (gzmap->update_flag[drawstep] & GIZMOMAP_IS_REFRESH_CALLBACK) {
+ if (do_refresh) {
/* force refresh again. */
gzgroup->init_flag &= ~WM_GIZMOGROUP_INIT_REFRESH;
}
/* Calls `setup`, `setup_keymap` and `refresh` if they're defined. */
WM_gizmogroup_ensure_init(C, gzgroup);
+ /* Check after ensure which can run refresh and update this value. */
+ if (gzgroup->hide.any != 0) {
+ continue;
+ }
+
/* prepare drawing */
if (gzgroup->type->draw_prepare) {
gzgroup->type->draw_prepare(C, gzgroup);
@@ -396,7 +437,7 @@ static void gizmomap_prepare_drawing(wmGizmoMap *gzmap,
}
}
- gzmap->update_flag[drawstep] &= ~(GIZMOMAP_IS_REFRESH_CALLBACK | GIZMOMAP_IS_PREPARE_DRAW);
+ gzmap->update_flag[drawstep] &= ~GIZMOMAP_IS_PREPARE_DRAW;
}
/**
@@ -716,7 +757,7 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
/* If it were important we could initialize here,
* but this only happens when events are handled before drawing,
* just skip to keep code-path for initializing gizmos simple. */
- if ((gzgroup->init_flag & WM_GIZMOGROUP_INIT_SETUP) == 0) {
+ if ((gzgroup->hide.any != 0) || ((gzgroup->init_flag & WM_GIZMOGROUP_INIT_SETUP) == 0)) {
continue;
}
@@ -730,9 +771,8 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
}
if (do_step[step]) {
- if ((gzmap->update_flag[step] & GIZMOMAP_IS_REFRESH_CALLBACK) &&
- (gzgroup->type->refresh != NULL)) {
- gzgroup->type->refresh(C, gzgroup);
+ if (gzmap->update_flag[step] & GIZMOMAP_IS_REFRESH_CALLBACK) {
+ WM_gizmo_group_refresh(C, gzgroup);
/* cleared below */
}
if (step == WM_GIZMOMAP_DRAWSTEP_3D) {
@@ -1127,7 +1167,7 @@ void WM_gizmomap_message_subscribe(bContext *C,
struct wmMsgBus *mbus)
{
for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
- if ((gzgroup->init_flag & WM_GIZMOGROUP_INIT_SETUP) == 0 ||
+ if ((gzgroup->hide.any != 0) || (gzgroup->init_flag & WM_GIZMOGROUP_INIT_SETUP) == 0 ||
!WM_gizmo_group_type_poll(C, gzgroup->type)) {
continue;
}
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 901594850dd..e2462bb59b1 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -34,14 +34,15 @@
#include "BLI_blenlib.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "BKE_context.h"
#include "BKE_idcode.h"
+#include "GPU_glew.h"
#include "GPU_shader.h"
#include "GPU_state.h"
+#include "GPU_viewport.h"
#include "IMB_imbuf_types.h"
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 37e519fd0e7..22fb8ec0a91 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -39,8 +39,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BIF_gl.h"
-
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_main.h"
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index c63bc24d58e..8eaba61fb5b 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -2265,9 +2265,18 @@ static int wm_handler_operator_call(bContext *C,
bool use_last_properties = true;
PointerRNA tool_properties = {0};
- bToolRef *keymap_tool = ((handler_base->type == WM_HANDLER_TYPE_KEYMAP) ?
- ((wmEventHandler_Keymap *)handler_base)->keymap_tool :
- NULL);
+ bToolRef *keymap_tool = NULL;
+ if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
+ keymap_tool = ((wmEventHandler_Keymap *)handler_base)->keymap_tool;
+ }
+ else if (handler_base->type == WM_HANDLER_TYPE_GIZMO) {
+ wmGizmoMap *gizmo_map = ((wmEventHandler_Gizmo *)handler_base)->gizmo_map;
+ wmGizmo *gz = wm_gizmomap_highlight_get(gizmo_map);
+ if (gz && (gz->flag & WM_GIZMO_OPERATOR_TOOL_INIT)) {
+ keymap_tool = WM_toolsystem_ref_from_context(C);
+ }
+ }
+
const bool is_tool = (keymap_tool != NULL);
const bool use_tool_properties = is_tool;
@@ -2802,6 +2811,12 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
BLI_assert(gzmap != NULL);
wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
+ /* Special case, needed so postponed refresh can respond to events,
+ * see #WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK for details. */
+ if (WM_gizmomap_tag_refresh_check(gzmap)) {
+ ED_region_tag_redraw(region);
+ }
+
if (region->gizmo_map != handler->gizmo_map) {
WM_gizmomap_tag_refresh(handler->gizmo_map);
}
@@ -2850,7 +2865,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) {
if (gz != NULL) {
if (U.flag & USER_TOOLTIPS) {
- WM_tooltip_timer_init(C, CTX_wm_window(C), region, WM_gizmomap_tooltip_init);
+ WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init);
}
}
}
@@ -3721,22 +3736,89 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap
return handler;
}
-/** Follow #wmEventHandler_KeymapDynamicFn signature. */
+/**
+ * Implements fallback tool when enabled by:
+ * #SCE_WORKSPACE_TOOL_FALLBACK, #WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP.
+ *
+ * This runs before #WM_event_get_keymap_from_toolsystem,
+ * allowing both the fallback-tool and active-tool to be activated
+ * providing the key-map is configured so the keys don't conflict.
+ * For example one mouse button can run the active-tool, another button for the fallback-tool.
+ * See T72567.
+ *
+ * Follow #wmEventHandler_KeymapDynamicFn signature.
+ */
+wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
+ wmEventHandler_Keymap *handler)
+{
+ ScrArea *sa = handler->dynamic.user_data;
+ handler->keymap_tool = NULL;
+ bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
+ if (tref_rt && tref_rt->keymap_fallback[0]) {
+ const char *keymap_id = NULL;
+
+ /* Support for the gizmo owning the tool keymap. */
+ if (tref_rt->gizmo_group[0] != '\0' && tref_rt->keymap_fallback[0] != '\n') {
+ wmGizmoMap *gzmap = NULL;
+ wmGizmoGroup *gzgroup = NULL;
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->gizmo_map != NULL) {
+ gzmap = ar->gizmo_map;
+ gzgroup = WM_gizmomap_group_find(gzmap, tref_rt->gizmo_group);
+ if (gzgroup != NULL) {
+ break;
+ }
+ }
+ }
+ if (gzgroup != NULL) {
+ if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
+ /* If all are hidden, don't override. */
+ if (gzgroup->use_fallback_keymap) {
+ wmGizmo *highlight = wm_gizmomap_highlight_get(gzmap);
+ if (highlight == NULL) {
+ keymap_id = tref_rt->keymap_fallback;
+ }
+ }
+ }
+ }
+ }
+
+ if (keymap_id && keymap_id[0]) {
+ wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
+ &wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW);
+ /* We shouldn't use keymaps from unrelated spaces. */
+ if (km != NULL) {
+ handler->keymap_tool = sa->runtime.tool;
+ return km;
+ }
+ else {
+ printf(
+ "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname);
+ }
+ }
+ }
+ return NULL;
+}
+
wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandler_Keymap *handler)
{
ScrArea *sa = handler->dynamic.user_data;
handler->keymap_tool = NULL;
bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
if (tref_rt && tref_rt->keymap[0]) {
- wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
- &wm->userconf->keymaps, tref_rt->keymap, sa->spacetype, RGN_TYPE_WINDOW);
- /* We shouldn't use keymaps from unrelated spaces. */
- if (km != NULL) {
- handler->keymap_tool = sa->runtime.tool;
- return km;
- }
- else {
- printf("Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname);
+ const char *keymap_id = tref_rt->keymap;
+ {
+ wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
+ &wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW);
+ /* We shouldn't use keymaps from unrelated spaces. */
+ if (km != NULL) {
+ handler->keymap_tool = sa->runtime.tool;
+ return km;
+ }
+ else {
+ printf(
+ "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname);
+ }
}
}
return NULL;
@@ -4133,6 +4215,8 @@ static int convert_key(GHOST_TKey key)
return LEFTALTKEY;
case GHOST_kKeyRightAlt:
return RIGHTALTKEY;
+ case GHOST_kKeyApp:
+ return APPKEY;
case GHOST_kKeyCapsLock:
return CAPSLOCKKEY;
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index f96a8c3d7fd..aa74aa81a74 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -1251,7 +1251,6 @@ static ImBuf *blend_file_thumb(const bContext *C,
IB_rect,
V3D_OFSDRAW_NONE,
R_ALPHAPREMUL,
- 0,
NULL,
NULL,
err_out);
@@ -1266,7 +1265,6 @@ static ImBuf *blend_file_thumb(const bContext *C,
BLEN_THUMB_SIZE * 2,
IB_rect,
R_ALPHAPREMUL,
- 0,
NULL,
NULL,
err_out);
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 3374d17cbfd..f0b186761ce 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -828,7 +828,7 @@ static void lib_relocate_do(Main *bmain,
BLI_strncpy(&old_id->name[len], "~000", 7);
}
- id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id);
+ id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL);
BKE_reportf(
reports,
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index bee007bde7f..16d71df6161 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -262,7 +262,6 @@ void WM_init(bContext *C, int argc, const char **argv)
ED_spacetypes_init(); /* editors/space_api/spacetype.c */
- ED_file_init(); /* for fsmenu */
ED_node_init_butfuncs();
BLF_init();
@@ -292,6 +291,8 @@ void WM_init(bContext *C, int argc, const char **argv)
* otherwise the versioning cannot find the default studio-light. */
BKE_studiolight_init();
+ BLI_assert((G.fileflags & G_FILE_NO_UI) == 0);
+
wm_homefile_read(C,
NULL,
G.factory_startup,
@@ -305,6 +306,9 @@ void WM_init(bContext *C, int argc, const char **argv)
/* Call again to set from userpreferences... */
BLT_lang_set(NULL);
+ /* For fsMenu. Called here so can include user preference paths if needed. */
+ ED_file_init();
+
/* That one is generated on demand, we need to be sure it's clear on init. */
IMB_thumb_clear_translations();
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 9aefb4f68cb..2a40fb138c0 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -157,6 +157,8 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna, "filter_alembic", (filter & FILE_TYPE_ALEMBIC) != 0, "Filter Alembic files", "");
+ prop = RNA_def_boolean(
+ ot->srna, "filter_usd", (filter & FILE_TYPE_USD) != 0, "Filter USD files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna, "filter_folder", (filter & FILE_TYPE_FOLDER) != 0, "Filter folders", "");
diff --git a/source/blender/windowmanager/intern/wm_operator_utils.c b/source/blender/windowmanager/intern/wm_operator_utils.c
index ce10ea56251..c2af82c007e 100644
--- a/source/blender/windowmanager/intern/wm_operator_utils.c
+++ b/source/blender/windowmanager/intern/wm_operator_utils.c
@@ -194,6 +194,10 @@ static void op_generic_value_cancel(bContext *UNUSED(C), wmOperator *op)
static int op_generic_value_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ if (RNA_property_is_set(op->ptr, op->type->prop)) {
+ return WM_operator_call_notest(C, op);
+ }
+
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index c862009161d..d3b91d7d91b 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -2209,7 +2209,7 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
short strdrawlen = 0;
float strwidth, strheight;
float r1 = 0.0f, r2 = 0.0f, rmin = 0.0, tex_radius, alpha;
- float zoom[2], col[3] = {1, 1, 1};
+ float zoom[2], col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
switch (rc->subtype) {
case PROP_NONE:
@@ -2477,7 +2477,7 @@ static int radial_control_get_properties(bContext *C, wmOperator *op)
}
if (!radial_control_get_path(
- &ctx_ptr, op, "color_path", &rc->col_ptr, &rc->col_prop, 3, RC_PROP_REQUIRE_FLOAT)) {
+ &ctx_ptr, op, "color_path", &rc->col_ptr, &rc->col_prop, 4, RC_PROP_REQUIRE_FLOAT)) {
return 0;
}
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 9b62e532132..54953c097eb 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -32,8 +32,6 @@
#include "BLI_utildefines.h"
-#include "BIF_gl.h"
-
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
@@ -44,6 +42,7 @@
#include "GPU_immediate.h"
#include "GPU_texture.h"
+#include "GPU_viewport.h"
#include "WM_api.h"
#include "WM_types.h"
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 2f40947b395..6a5de84ac31 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -29,9 +29,9 @@
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
-#include "BIF_gl.h"
-
+#include "GPU_glew.h"
#include "GPU_matrix.h"
+#include "GPU_viewport.h"
#include "WM_api.h"
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index f64acf20581..3218f8c45e4 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -351,6 +351,25 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C,
*tref->runtime = *tref_rt;
}
+ /* Ideally Python could check this gizmo group flag and not
+ * pass in the argument to begin with. */
+ bool use_fallback_keymap = false;
+
+ if (tref->idname_fallback[0] || tref->runtime->keymap_fallback[0]) {
+ if (tref_rt->gizmo_group[0]) {
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(tref_rt->gizmo_group, false);
+ if (gzgt) {
+ if (gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
+ use_fallback_keymap = true;
+ }
+ }
+ }
+ }
+ if (use_fallback_keymap == false) {
+ tref->idname_fallback[0] = '\0';
+ tref->runtime->keymap_fallback[0] = '\0';
+ }
+
toolsystem_ref_link(C, workspace, tref);
toolsystem_refresh_screen_from_active_tool(bmain, workspace, tref);
diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c
index 3a219d7a573..b192ea94010 100644
--- a/source/blender/windowmanager/intern/wm_tooltip.c
+++ b/source/blender/windowmanager/intern/wm_tooltip.c
@@ -42,7 +42,8 @@ double WM_tooltip_time_closed(void)
return g_tooltip_time_closed;
}
-void WM_tooltip_immediate_init(bContext *C, wmWindow *win, ARegion *ar, wmTooltipInitFn init)
+void WM_tooltip_immediate_init(
+ bContext *C, wmWindow *win, ScrArea *sa, ARegion *ar, wmTooltipInitFn init)
{
WM_tooltip_timer_clear(C, win);
@@ -50,13 +51,14 @@ void WM_tooltip_immediate_init(bContext *C, wmWindow *win, ARegion *ar, wmToolti
if (screen->tool_tip == NULL) {
screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__);
}
+ screen->tool_tip->area_from = sa;
screen->tool_tip->region_from = ar;
screen->tool_tip->init = init;
WM_tooltip_init(C, win);
}
void WM_tooltip_timer_init_ex(
- bContext *C, wmWindow *win, ARegion *ar, wmTooltipInitFn init, double delay)
+ bContext *C, wmWindow *win, ScrArea *sa, ARegion *ar, wmTooltipInitFn init, double delay)
{
WM_tooltip_timer_clear(C, win);
@@ -65,14 +67,16 @@ void WM_tooltip_timer_init_ex(
if (screen->tool_tip == NULL) {
screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__);
}
+ screen->tool_tip->area_from = sa;
screen->tool_tip->region_from = ar;
screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, delay);
screen->tool_tip->init = init;
}
-void WM_tooltip_timer_init(bContext *C, wmWindow *win, ARegion *ar, wmTooltipInitFn init)
+void WM_tooltip_timer_init(
+ bContext *C, wmWindow *win, ScrArea *sa, ARegion *ar, wmTooltipInitFn init)
{
- WM_tooltip_timer_init_ex(C, win, ar, init, UI_TOOLTIP_DELAY);
+ WM_tooltip_timer_init_ex(C, win, sa, ar, init, UI_TOOLTIP_DELAY);
}
void WM_tooltip_timer_clear(bContext *C, wmWindow *win)
@@ -112,11 +116,21 @@ void WM_tooltip_init(bContext *C, wmWindow *win)
}
const int pass_prev = screen->tool_tip->pass;
double pass_delay = 0.0;
- screen->tool_tip->region = screen->tool_tip->init(C,
- screen->tool_tip->region_from,
- &screen->tool_tip->pass,
- &pass_delay,
- &screen->tool_tip->exit_on_event);
+
+ {
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *ar_prev = CTX_wm_region(C);
+ CTX_wm_area_set(C, screen->tool_tip->area_from);
+ CTX_wm_region_set(C, screen->tool_tip->region_from);
+ screen->tool_tip->region = screen->tool_tip->init(C,
+ screen->tool_tip->region_from,
+ &screen->tool_tip->pass,
+ &pass_delay,
+ &screen->tool_tip->exit_on_event);
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, ar_prev);
+ }
+
copy_v2_v2_int(screen->tool_tip->event_xy, &win->eventstate->x);
if (pass_prev != screen->tool_tip->pass) {
/* The pass changed, add timer for next pass. */
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 0048e2b5fc8..73a811d663e 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -1888,12 +1888,17 @@ void WM_clipboard_text_set(const char *buf, bool selection)
void WM_progress_set(wmWindow *win, float progress)
{
- GHOST_SetProgressBar(win->ghostwin, progress);
+ /* In background mode we may have windows, but not actual GHOST windows. */
+ if (win->ghostwin) {
+ GHOST_SetProgressBar(win->ghostwin, progress);
+ }
}
void WM_progress_clear(wmWindow *win)
{
- GHOST_EndProgressBar(win->ghostwin);
+ if (win->ghostwin) {
+ GHOST_EndProgressBar(win->ghostwin);
+ }
}
/** \} */
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 7a25a6dfa4d..3bd0851d60c 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -202,6 +202,8 @@ enum {
MEDIAFIRST = 0x00b0, /* 176 */
MEDIALAST = 0x00b1, /* 177 */
+ APPKEY = 0x00b2, /* 178 */
+
F1KEY = 0x012c, /* 300 */
F2KEY = 0x012d, /* 301 */
F3KEY = 0x012e, /* 302 */
@@ -315,7 +317,7 @@ enum {
EVT_TWEAK_L = 0x5002,
EVT_TWEAK_M = 0x5003,
EVT_TWEAK_R = 0x5004,
- EVT_GESTURE = 0x5010,
+ /* 0x5010 (and lower) should be left to add other tweak types in the future. */
/* 0x5011 is taken, see EVT_ACTIONZONE_FULLSCREEN */
@@ -367,7 +369,7 @@ enum {
BUTTON7MOUSE))
/* test whether the event is tweak event */
-#define ISTWEAK(event_type) ((event_type) >= EVT_TWEAK_L && (event_type) <= EVT_GESTURE)
+#define ISTWEAK(event_type) ((event_type) >= EVT_TWEAK_L && (event_type) <= EVT_TWEAK_R)
/* test whether the event is a NDOF event */
#define ISNDOF(event_type) ((event_type) >= NDOF_MOTION && (event_type) < NDOF_LAST)
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 4407c58f122..2c16a097f9b 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -38,20 +38,15 @@ blender_include_dirs(
)
set(LIB
- bf_blenkernel
- bf_blenloader
- bf_depsgraph
- bf_dna
- bf_imbuf
- bf_intern_clog
- bf_intern_guardedalloc
- bf_intern_memutil
- bf_intern_opencolorio
- bf_render
- bf_rna
bf_windowmanager
)
+# Note: this should not be needed, but causes issues in some situations:
+# See reply to daf290dcc80c.
+if(WITH_TBB AND WITH_OPENIMAGEDENOISE)
+ list(INSERT LIB 0 bf_blenkernel)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_include_dirs("${GLEW_INCLUDE_PATH}")
@@ -69,9 +64,6 @@ if(WITH_CYCLES)
blender_include_dirs(../../intern/cycles/blender)
add_definitions(-DWITH_CYCLES_LOGGING)
endif()
- list(APPEND LIB
- bf_intern_cycles
- )
endif()
if(WITH_CODEC_FFMPEG)
@@ -86,9 +78,6 @@ endif()
if(WITH_PYTHON)
blender_include_dirs(../blender/python)
- list(APPEND LIB
- bf_python
- )
add_definitions(-DWITH_PYTHON)
if(WITH_PYTHON_SECURITY)
@@ -110,17 +99,11 @@ endif()
if(WITH_BINRELOC)
blender_include_dirs(${BINRELOC_INCLUDE_DIRS})
- list(APPEND LIB
- extern_binreloc
- )
add_definitions(-DWITH_BINRELOC)
endif()
if(WITH_FREESTYLE)
blender_include_dirs(../blender/freestyle)
- list(APPEND LIB
- bf_freestyle
- )
add_definitions(-DWITH_FREESTYLE)
endif()
@@ -153,6 +136,7 @@ if(WIN32 AND NOT UNIX)
list(APPEND SRC
${CMAKE_SOURCE_DIR}/release/windows/icons/winblender.rc
+ ${CMAKE_BINARY_DIR}/blender.exe.manifest
)
endif()
@@ -1067,6 +1051,19 @@ unset(LIB)
setup_liblinks(blender)
+# -----------------------------------------------------------------------------
+# USD registry.
+# USD requires a set of JSON files that define the standard schemas. These
+# files are required at runtime.
+if(WITH_USD)
+ add_definitions(-DWITH_USD)
+ install(DIRECTORY
+ ${LIBDIR}/usd/lib/usd
+ DESTINATION "${TARGETDIR_VER}/datafiles"
+ )
+endif()
+
+
# vcpkg substitutes our libs with theirs, which will cause issues when you
# you run these builds on other systems due to missing dlls. So we opt out
# the use of vcpkg
diff --git a/source/creator/creator.c b/source/creator/creator.c
index f4f5e3dcbde..58d12527f1c 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -112,6 +112,21 @@ int main_python_enter(int argc, const char **argv);
void main_python_exit(void);
#endif
+#ifdef WITH_USD
+/**
+ * Workaround to make it possible to pass a path at runtime to USD.
+ *
+ * USD requires some JSON files, and it uses a static constructor to determine the possible
+ * file-system paths to find those files. This made it impossible for Blender to pass a path to the
+ * USD library at runtime, as the constructor would run before Blender's main() function. We have
+ * patched USD (see usd.diff) to avoid that particular static constructor, and have an
+ * initialization function instead.
+ *
+ * This function is implemented in the USD source code, pxr/base/lib/plug/initConfig.cpp.
+ */
+void usd_initialise_plugin_path(const char *datafiles_usd_path);
+#endif
+
/* written to by 'creator_args.c' */
struct ApplicationState app_state = {
.signal =
@@ -411,6 +426,13 @@ int main(int argc,
init_def_material();
+#ifdef WITH_USD
+ /* Tell USD which directory to search for its JSON files. If datafiles/usd
+ * does not exist, the USD library will not be able to read or write any files.
+ */
+ usd_initialise_plugin_path(BKE_appdir_folder_id(BLENDER_DATAFILES, "usd"));
+#endif
+
if (G.background == 0) {
#ifndef WITH_PYTHON_MODULE
BLI_argsParse(ba, 2, NULL, NULL);
diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt
index 285b414e997..7da65bcc8b9 100644
--- a/tests/gtests/CMakeLists.txt
+++ b/tests/gtests/CMakeLists.txt
@@ -13,9 +13,13 @@ if(WITH_GTESTS)
add_subdirectory(testing)
add_subdirectory(blenlib)
+ add_subdirectory(blenloader)
add_subdirectory(guardedalloc)
add_subdirectory(bmesh)
if(WITH_ALEMBIC)
add_subdirectory(alembic)
endif()
+ if(WITH_USD)
+ add_subdirectory(usd)
+ endif()
endif()
diff --git a/tests/gtests/blenlib/BLI_delaunay_2d_test.cc b/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
index 8b29128eb0d..85e8ae3f141 100644
--- a/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
+++ b/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
@@ -15,6 +15,10 @@ extern "C" {
#include <fstream>
#include <sstream>
+#define DO_REGULAR_TESTS 1
+#define DO_RANDOM_TESTS 0
+#define DO_FILE_TESTS 0
+
static void fill_input_verts(CDT_input *r_input, float (*vcos)[2], int nverts)
{
r_input->verts_len = nverts;
@@ -43,6 +47,117 @@ static void add_input_faces(
r_input->faces_len_table = faces_len_table;
}
+/* The spec should have the form:
+ * #verts #edges #faces
+ * <float> <float> [#verts lines)
+ * <int> <int> [#edges lines]
+ * <int> <int> ... <int> [#faces lines]
+ */
+static void fill_input_from_string(CDT_input *r_input, const char *spec)
+{
+ std::string line;
+ std::vector<std::vector<int>> faces;
+ int i, j;
+ int nverts, nedges, nfaces;
+ float(*p)[2];
+ int(*e)[2];
+ int *farr;
+ int *flen;
+ int *fstart;
+
+ std::istringstream ss(spec);
+ getline(ss, line);
+ std::istringstream hdrss(line);
+ hdrss >> nverts >> nedges >> nfaces;
+ if (nverts == 0) {
+ return;
+ }
+ p = (float(*)[2])MEM_malloc_arrayN(nverts, 2 * sizeof(float), __func__);
+ if (nedges > 0) {
+ e = (int(*)[2])MEM_malloc_arrayN(nedges, 2 * sizeof(int), __func__);
+ }
+ if (nfaces > 0) {
+ flen = (int *)MEM_malloc_arrayN(nfaces, sizeof(int), __func__);
+ fstart = (int *)MEM_malloc_arrayN(nfaces, sizeof(int), __func__);
+ }
+ i = 0;
+ while (i < nverts && getline(ss, line)) {
+ std::istringstream iss(line);
+ iss >> p[i][0] >> p[i][1];
+ i++;
+ }
+ i = 0;
+ while (i < nedges && getline(ss, line)) {
+ std::istringstream ess(line);
+ ess >> e[i][0] >> e[i][1];
+ i++;
+ }
+ i = 0;
+ while (i < nfaces && getline(ss, line)) {
+ std::istringstream fss(line);
+ int v;
+ faces.push_back(std::vector<int>());
+ while (fss >> v) {
+ faces[i].push_back(v);
+ }
+ i++;
+ }
+ fill_input_verts(r_input, p, nverts);
+ if (nedges > 0) {
+ add_input_edges(r_input, e, nedges);
+ }
+ if (nfaces > 0) {
+ for (i = 0; i < nfaces; i++) {
+ flen[i] = (int)faces[i].size();
+ if (i == 0) {
+ fstart[i] = 0;
+ }
+ else {
+ fstart[i] = fstart[i - 1] + flen[i - 1];
+ }
+ }
+ farr = (int *)MEM_malloc_arrayN(fstart[nfaces - 1] + flen[nfaces - 1], sizeof(int), __func__);
+ for (i = 0; i < nfaces; i++) {
+ for (j = 0; j < (int)faces[i].size(); j++) {
+ farr[fstart[i] + j] = faces[i][j];
+ }
+ }
+ add_input_faces(r_input, farr, fstart, flen, nfaces);
+ }
+}
+
+static void fill_input_from_file(CDT_input *in, const char *filename)
+{
+ std::FILE *fp = std::fopen(filename, "rb");
+ if (fp) {
+ std::string contents;
+ std::fseek(fp, 0, SEEK_END);
+ contents.resize(std::ftell(fp));
+ std::rewind(fp);
+ std::fread(&contents[0], 1, contents.size(), fp);
+ std::fclose(fp);
+ fill_input_from_string(in, contents.c_str());
+ }
+ else {
+ printf("couldn't open file %s\n", filename);
+ }
+}
+
+static void free_spec_arrays(CDT_input *in)
+{
+ if (in->vert_coords) {
+ MEM_freeN(in->vert_coords);
+ }
+ if (in->edges) {
+ MEM_freeN(in->edges);
+ }
+ if (in->faces_len_table) {
+ MEM_freeN(in->faces_len_table);
+ MEM_freeN(in->faces_start_table);
+ MEM_freeN(in->faces);
+ }
+}
+
/* which output vert index goes with given input vertex? -1 if not found */
static int get_output_vert_index(const CDT_result *r, int in_index)
{
@@ -187,6 +302,7 @@ static void dump_result(CDT_result *r)
}
}
+#if DO_REGULAR_TESTS
TEST(delaunay, Empty)
{
CDT_input in;
@@ -692,7 +808,108 @@ TEST(delaunay, TriInTri)
BLI_delaunay_2d_cdt_free(out);
}
-#if 0
+TEST(delaunay, DiamondInSquare)
+{
+ CDT_input in;
+ CDT_result *out;
+ const char *spec = R"(8 0 2
+ 0.0 0.0
+ 1.0 0.0
+ 1.0 1.0
+ 0.0 1.0
+ 0.14644660940672627 0.5
+ 0.5 0.14644660940672627
+ 0.8535533905932737 0.5
+ 0.5 0.8535533905932737
+ 0 1 2 3
+ 4 5 6 7
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
+ EXPECT_EQ(out->verts_len, 8);
+ EXPECT_EQ(out->edges_len, 10);
+ EXPECT_EQ(out->faces_len, 3);
+ free_spec_arrays(&in);
+}
+
+TEST(delaunay, DiamondInSquareWire)
+{
+ CDT_input in;
+ CDT_result *out;
+ const char *spec = R"(8 8 0
+ 0.0 0.0
+ 1.0 0.0
+ 1.0 1.0
+ 0.0 1.0
+ 0.14644660940672627 0.5
+ 0.5 0.14644660940672627
+ 0.8535533905932737 0.5
+ 0.5 0.8535533905932737
+ 0 1
+ 1 2
+ 2 3
+ 3 0
+ 4 5
+ 5 6
+ 6 7
+ 7 4
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
+ EXPECT_EQ(out->verts_len, 8);
+ EXPECT_EQ(out->edges_len, 8);
+ EXPECT_EQ(out->faces_len, 2);
+ free_spec_arrays(&in);
+}
+
+TEST(delaunay, ClosePts)
+{
+ CDT_input in;
+ CDT_result *out;
+ const char *spec = R"(7 2 1
+ 0.46876350045204163 0.06087132915854454
+ 0.46865847706794739 0.03632887825369835
+ 0.49176687002182007 0.03632888197898865
+ 0.49166208505630493 0.06087132543325424
+ 0.49171400070190430 0.04841339960694313
+ 0.49171534180641174 0.04839951172471046
+ 0.49045535922050476 0.06087132915854454
+ 4 5
+ 6 4
+ 0 1 2 3
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
+ EXPECT_EQ(out->verts_len, 7);
+ EXPECT_EQ(out->edges_len, 12);
+ EXPECT_EQ(out->faces_len, 6);
+ free_spec_arrays(&in);
+}
+
+TEST(delaunay, ClosePts2)
+{
+ CDT_input in;
+ CDT_result *out;
+ const char *spec = R"(6 1 1
+ -0.17878936231136322 -0.44374340772628784
+ -0.17871695756912231 -0.45601493120193481
+ -0.17544384300708771 -0.45601493120193481
+ -0.17537136375904083 -0.44374340772628784
+ -0.17544738948345184 -0.45602506399154663
+ -0.17872454226016998 -0.45472940802574158
+ 4 5
+ 0 1 2 3
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
+ EXPECT_EQ(out->verts_len, 6);
+ EXPECT_EQ(out->edges_len, 10);
+ EXPECT_EQ(out->faces_len, 5);
+ free_spec_arrays(&in);
+}
+#endif
+
+#if DO_RANDOM_TESTS
enum {
RANDOM_PTS,
RANDOM_SEGS,
@@ -780,17 +997,17 @@ static void rand_delaunay_test(int test_kind,
TEST(delaunay, randompts)
{
- rand_delaunay_test(RANDOM_PTS, 7, 1, CDT_FULL);
+ rand_delaunay_test(RANDOM_PTS, 7, 100, CDT_FULL);
}
TEST(delaunay, randomsegs)
{
- rand_delaunay_test(RANDOM_SEGS, 7, 1, CDT_FULL);
+ rand_delaunay_test(RANDOM_SEGS, 7, 100, CDT_FULL);
}
TEST(delaunay, randompoly)
{
- rand_delaunay_test(RANDOM_POLY, 7, 1, CDT_FULL);
+ rand_delaunay_test(RANDOM_POLY, 7, 100, CDT_FULL);
}
TEST(delaunay, randompoly_inside)
@@ -809,48 +1026,36 @@ TEST(delaunay, randompoly_validbmesh)
}
#endif
-#if 0
-/* For debugging or timing large examples.
- * The given file should have one point per line, as a space-separated pair of floats
+#if DO_FILE_TESTS
+/* For timing large examples of points only.
+ * The given file should have one point per line, as a space-separated pair of floats.
*/
static void points_from_file_test(const char *filename)
{
- std::ifstream f;
- std::string line;
- struct XY {
- float x;
- float y;
- } xy;
- std::vector<XY> pts;
- int i, n;
CDT_input in;
CDT_result *out;
double tstart;
- float (*p)[2];
- f.open(filename);
- while (getline(f, line)) {
- std::istringstream iss(line);
- iss >> xy.x >> xy.y;
- pts.push_back(xy);
- }
- n = (int)pts.size();
- fprintf(stderr, "read %d points\n", (int)pts.size());
- p = (float (*)[2])MEM_malloc_arrayN(n, 2 * sizeof(float), "delaunay");
- for (i = 0; i < n; i++) {
- xy = pts[i];
- p[i][0] = xy.x;
- p[i][1] = xy.y;
- }
+ fill_input_from_file(&in, filename);
tstart = PIL_check_seconds_timer();
- fill_input_verts(&in, p, n);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
fprintf(stderr, "time to triangulate=%f seconds\n", PIL_check_seconds_timer() - tstart);
BLI_delaunay_2d_cdt_free(out);
- MEM_freeN(p);
+ free_spec_arrays(&in);
+}
+
+TEST(delaunay, debug)
+{
+ CDT_input in;
+ CDT_result *out;
+ fill_input_from_file(&in, "/tmp/cdtinput.txt");
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
+ BLI_delaunay_2d_cdt_free(out);
+ free_spec_arrays(&in);
}
-# define POINTFILEROOT "/tmp/"
+# if 0
+# define POINTFILEROOT "/tmp/"
TEST(delaunay, terrain1)
{
@@ -866,4 +1071,5 @@ TEST(delaunay, terrain3)
{
points_from_file_test(POINTFILEROOT "points3.txt");
}
+# endif
#endif
diff --git a/tests/gtests/blenlib/BLI_listbase_test.cc b/tests/gtests/blenlib/BLI_listbase_test.cc
index 76d173c9604..e5919c5dfb1 100644
--- a/tests/gtests/blenlib/BLI_listbase_test.cc
+++ b/tests/gtests/blenlib/BLI_listbase_test.cc
@@ -16,8 +16,10 @@ extern "C" {
static bool listbase_is_valid(const ListBase *listbase)
{
#define TESTFAIL(test) \
- if (!(test)) \
- goto fail;
+ if (!(test)) { \
+ goto fail; \
+ } \
+ ((void)0)
if (listbase->first) {
const Link *prev, *link;
@@ -31,14 +33,14 @@ static bool listbase_is_valid(const ListBase *listbase)
link = (Link *)listbase->first;
do {
TESTFAIL(link->prev == prev);
- } while ((prev = link), (link = link->next));
+ } while ((void)(prev = link), (link = link->next));
TESTFAIL(prev == listbase->last);
prev = NULL;
link = (Link *)listbase->last;
do {
TESTFAIL(link->next == prev);
- } while ((prev = link), (link = link->prev));
+ } while ((void)(prev = link), (link = link->prev));
TESTFAIL(prev == listbase->first);
}
else {
diff --git a/tests/gtests/blenlib/BLI_path_util_test.cc b/tests/gtests/blenlib/BLI_path_util_test.cc
index 0bdaa346428..2b47995095a 100644
--- a/tests/gtests/blenlib/BLI_path_util_test.cc
+++ b/tests/gtests/blenlib/BLI_path_util_test.cc
@@ -474,7 +474,8 @@ TEST(path_util, SplitDirfile)
BLI_path_frame_strip(path, ext); \
EXPECT_STREQ(path, expect_path); \
EXPECT_STREQ(ext, expect_ext); \
- }
+ } \
+ ((void)0)
/* BLI_path_frame_strip */
TEST(path_util, PathFrameStrip)
diff --git a/tests/gtests/blenloader/CMakeLists.txt b/tests/gtests/blenloader/CMakeLists.txt
new file mode 100644
index 00000000000..f8457e0164b
--- /dev/null
+++ b/tests/gtests/blenloader/CMakeLists.txt
@@ -0,0 +1,90 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2019 by Blender Foundation.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ..
+ ../../../source/blender/blenkernel
+ ../../../source/blender/blenlib
+ ../../../source/blender/blenloader
+ ../../../source/blender/depsgraph
+ ../../../source/blender/imbuf
+ ../../../source/blender/makesdna
+ ../../../source/blender/makesrna
+ ../../../source/blender/windowmanager
+ ../../../intern/guardedalloc
+ ${GLOG_INCLUDE_DIRS}
+ ${GFLAGS_INCLUDE_DIRS}
+ ../../../extern/gtest/include
+)
+
+set(SRC
+ blendfile_loading_base_test.cc
+ blendfile_loading_base_test.h
+)
+
+set(LIB
+)
+
+blender_add_lib(bf_blenloader_test "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+
+set(INC
+ .
+ ..
+ ../../../source/blender/blenlib
+ ../../../source/blender/blenloader
+ ../../../source/blender/blenkernel
+ ../../../source/blender/makesdna
+ ../../../source/blender/makesrna
+ ../../../source/blender/depsgraph
+ ../../../intern/guardedalloc
+)
+
+set(LIB
+ bf_blenloader_test
+ bf_blenloader
+
+ # Should not be needed but gives windows linker errors if the ocio libs are linked before this:
+ bf_intern_opencolorio
+ bf_gpu
+)
+
+include_directories(${INC})
+
+setup_libdirs()
+get_property(BLENDER_SORTED_LIBS GLOBAL PROPERTY BLENDER_SORTED_LIBS_PROP)
+
+
+set(SRC
+ blendfile_load_test.cc
+)
+if(WITH_BUILDINFO)
+ list(APPEND SRC "$<TARGET_OBJECTS:buildinfoobj>")
+endif()
+
+BLENDER_SRC_GTEST_EX(
+ NAME blenloader
+ SRC "${SRC}"
+ EXTRA_LIBS "${LIB}"
+ COMMAND_ARGS --test-assets-dir "${CMAKE_SOURCE_DIR}/../lib/tests")
+
+unset(_buildinfo_src)
+
+setup_liblinks(blenloader_test)
diff --git a/tests/gtests/blenloader/blendfile_load_test.cc b/tests/gtests/blenloader/blendfile_load_test.cc
new file mode 100644
index 00000000000..2ba3e3fcd88
--- /dev/null
+++ b/tests/gtests/blenloader/blendfile_load_test.cc
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ */
+#include "blendfile_loading_base_test.h"
+
+class BlendfileLoadingTest : public BlendfileLoadingBaseTest {
+};
+
+TEST_F(BlendfileLoadingTest, CanaryTest)
+{
+ /* Load the smallest blend file we have in the SVN lib/tests directory. */
+ if (!blendfile_load("modifier_stack/array_test.blend")) {
+ return;
+ }
+ depsgraph_create(DAG_EVAL_RENDER);
+ EXPECT_NE(nullptr, this->depsgraph);
+}
diff --git a/tests/gtests/blenloader/blendfile_loading_base_test.cc b/tests/gtests/blenloader/blendfile_loading_base_test.cc
new file mode 100644
index 00000000000..7af3293d706
--- /dev/null
+++ b/tests/gtests/blenloader/blendfile_loading_base_test.cc
@@ -0,0 +1,172 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ */
+#include "blendfile_loading_base_test.h"
+
+extern "C" {
+#include "BKE_appdir.h"
+#include "BKE_blender.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_scene.h"
+
+#include "BLI_threads.h"
+#include "BLI_path_util.h"
+
+#include "BLO_readfile.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph.h"
+
+#include "DNA_genfile.h" /* for DNA_sdna_current_init() */
+#include "DNA_windowmanager_types.h"
+
+#include "IMB_imbuf.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "wm.h"
+}
+
+DEFINE_string(test_assets_dir, "", "lib/tests directory from SVN containing the test assets.");
+
+BlendfileLoadingBaseTest::~BlendfileLoadingBaseTest()
+{
+}
+
+void BlendfileLoadingBaseTest::SetUpTestCase()
+{
+ testing::Test::SetUpTestCase();
+
+ /* Minimal code to make loading a blendfile and constructing a depsgraph not crash, copied from
+ * main() in creator.c. */
+ BLI_threadapi_init();
+
+ DNA_sdna_current_init();
+ BKE_blender_globals_init();
+ IMB_init();
+ BKE_images_init();
+ BKE_modifier_init();
+ DEG_register_node_types();
+ RNA_init();
+ init_nodesystem();
+
+ G.background = true;
+ G.factory_startup = true;
+
+ /* Allocate a dummy window manager. The real window manager will try and load Python scripts from
+ * the release directory, which it won't be able to find. */
+ ASSERT_EQ(G.main->wm.first, nullptr);
+ G.main->wm.first = MEM_callocN(sizeof(wmWindowManager), __func__);
+}
+
+void BlendfileLoadingBaseTest::TearDownTestCase()
+{
+ if (G.main->wm.first != nullptr) {
+ MEM_freeN(G.main->wm.first);
+ G.main->wm.first = nullptr;
+ }
+
+ /* Copied from WM_exit_ex() in wm_init_exit.c, and cherry-picked those lines that match the
+ * allocation/initialization done in SetUpTestCase(). */
+ BKE_blender_free();
+ RNA_exit();
+
+ DEG_free_node_types();
+ DNA_sdna_current_free();
+ BLI_threadapi_exit();
+
+ BKE_blender_atexit();
+
+ if (MEM_get_memory_blocks_in_use() != 0) {
+ size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use();
+ printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n",
+ MEM_get_memory_blocks_in_use(),
+ (double)mem_in_use / 1024 / 1024);
+ MEM_printmemlist();
+ }
+
+ BKE_tempdir_session_purge();
+
+ testing::Test::TearDownTestCase();
+}
+
+void BlendfileLoadingBaseTest::TearDown()
+{
+ depsgraph_free();
+ blendfile_free();
+
+ testing::Test::TearDown();
+}
+
+bool BlendfileLoadingBaseTest::blendfile_load(const char *filepath)
+{
+ if (FLAGS_test_assets_dir.empty()) {
+ ADD_FAILURE()
+ << "Pass the flag --test-assets-dir and point to the lib/tests directory from SVN.";
+ return false;
+ }
+
+ char abspath[FILENAME_MAX];
+ BLI_path_join(abspath, sizeof(abspath), FLAGS_test_assets_dir.c_str(), filepath, NULL);
+
+ bfile = BLO_read_from_file(abspath, BLO_READ_SKIP_NONE, NULL /* reports */);
+ if (bfile == nullptr) {
+ ADD_FAILURE() << "Unable to load file '" << filepath << "' from test assets dir '"
+ << FLAGS_test_assets_dir << "'";
+ return false;
+ }
+ return true;
+}
+
+void BlendfileLoadingBaseTest::blendfile_free()
+{
+ if (bfile == nullptr) {
+ return;
+ }
+
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bfile->main->wm.first);
+ if (wm != nullptr) {
+ wm_close_and_free(NULL, wm);
+ }
+ BLO_blendfiledata_free(bfile);
+ bfile = nullptr;
+}
+
+void BlendfileLoadingBaseTest::depsgraph_create(eEvaluationMode depsgraph_evaluation_mode)
+{
+ depsgraph = DEG_graph_new(
+ bfile->main, bfile->curscene, bfile->cur_view_layer, depsgraph_evaluation_mode);
+ DEG_graph_build_from_view_layer(depsgraph, bfile->main, bfile->curscene, bfile->cur_view_layer);
+ BKE_scene_graph_update_tagged(depsgraph, bfile->main);
+}
+
+void BlendfileLoadingBaseTest::depsgraph_free()
+{
+ if (depsgraph == nullptr) {
+ return;
+ }
+ DEG_graph_free(depsgraph);
+ depsgraph = nullptr;
+}
diff --git a/tests/gtests/blenloader/blendfile_loading_base_test.h b/tests/gtests/blenloader/blendfile_loading_base_test.h
new file mode 100644
index 00000000000..466bbcd2392
--- /dev/null
+++ b/tests/gtests/blenloader/blendfile_loading_base_test.h
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ */
+#ifndef __BLENDFILE_LOADING_BASE_TEST_H__
+#define __BLENDFILE_LOADING_BASE_TEST_H__
+
+#include "testing/testing.h"
+#include "DEG_depsgraph.h"
+
+struct BlendFileData;
+struct Depsgraph;
+
+class BlendfileLoadingBaseTest : public testing::Test {
+ protected:
+ struct BlendFileData *bfile = nullptr;
+ struct Depsgraph *depsgraph = nullptr;
+
+ public:
+ virtual ~BlendfileLoadingBaseTest();
+
+ /* Sets up Blender just enough to not crash on loading
+ * a blendfile and constructing a depsgraph. */
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+
+ protected:
+ /* Frees the depsgraph & blendfile. */
+ virtual void TearDown();
+
+ /* Loads a blend file from the lib/tests directory from SVN.
+ * Returns 'ok' flag (true=good, false=bad) and sets this->bfile.
+ * Fails the test if the file cannot be loaded (still returns though).
+ * Requires the CLI argument --test-asset-dir to point to ../../lib/tests.
+ *
+ * WARNING: only files saved with Blender 2.80+ can be loaded. Since Blender
+ * is only partially initialised (most importantly, without window manager),
+ * the space types are not registered, so any versioning code that handles
+ * those will SEGFAULT.
+ */
+ bool blendfile_load(const char *filepath);
+ /* Free bfile if it is not nullptr. */
+ void blendfile_free();
+
+ /* Create a depsgraph. Assumes a blend file has been loaded to this->bfile. */
+ void depsgraph_create(eEvaluationMode depsgraph_evaluation_mode);
+ /* Free the depsgraph if it's not nullptr. */
+ void depsgraph_free();
+};
+
+#endif /* __BLENDFILE_LOADING_BASE_TEST_H__ */
diff --git a/tests/gtests/usd/CMakeLists.txt b/tests/gtests/usd/CMakeLists.txt
new file mode 100644
index 00000000000..21bd2aba07f
--- /dev/null
+++ b/tests/gtests/usd/CMakeLists.txt
@@ -0,0 +1,101 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2019, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+# This suppresses the warning "This file includes at least one deprecated or antiquated
+# header which may be removed without further notice at a future date", which is caused
+# by the USD library including <ext/hash_set> on Linux. This has been reported at:
+# https://github.com/PixarAnimationStudios/USD/issues/1057.
+if(UNIX AND NOT APPLE)
+ add_definitions(-D_GLIBCXX_PERMIT_BACKWARD_HASH)
+endif()
+if(WIN32)
+ add_definitions(-DNOMINMAX)
+endif()
+add_definitions(-DPXR_STATIC)
+
+set(INC
+ .
+ ..
+ ../../../source/blender/blenlib
+ ../../../source/blender/blenkernel
+ ../../../source/blender/usd
+ ../../../source/blender/makesdna
+ ../../../source/blender/depsgraph
+ ${USD_INCLUDE_DIRS}
+ ${BOOST_INCLUDE_DIR}
+ ${TBB_INCLUDE_DIR}
+)
+
+set(LIB
+ bf_blenloader_test
+ bf_blenloader
+
+ # Should not be needed but gives windows linker errors if the ocio libs are linked before this:
+ bf_intern_opencolorio
+ bf_gpu
+
+ bf_usd
+)
+
+include_directories(${INC})
+
+setup_libdirs()
+get_property(BLENDER_SORTED_LIBS GLOBAL PROPERTY BLENDER_SORTED_LIBS_PROP)
+
+set(SRC
+ abstract_hierarchy_iterator_test.cc
+ hierarchy_context_order_test.cc
+)
+
+# TODO(Sybren): re-enable this unit test.
+# if(NOT APPLE)
+# # TODO(Sybren): This unit test has only been tested on Linux, and should possibly be
+# # restructured to support other platforms as well.
+# list(APPEND SRC usd_stage_creation_test.cc)
+# endif()
+
+
+if(WITH_BUILDINFO)
+ list(APPEND SRC "$<TARGET_OBJECTS:buildinfoobj>")
+endif()
+
+# get_cmake_property(_variableNames VARIABLES)
+# list (SORT _variableNames)
+# foreach (_variableName ${_variableNames})
+# message(STATUS "${_variableName}=${${_variableName}}")
+# endforeach()
+
+# Works on Linux, not on Windows:
+# set(_usd_DATAFILES_DIR "${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/datafiles/usd")
+set(_usd_DATAFILES_DIR "$<TARGET_FILE_DIR:blender>/${BLENDER_VERSION}/datafiles/usd")
+
+BLENDER_SRC_GTEST_EX(
+ NAME usd
+ SRC "${SRC}"
+ EXTRA_LIBS "${LIB}"
+ COMMAND_ARGS
+ --test-assets-dir "${CMAKE_SOURCE_DIR}/../lib/tests"
+)
+# TODO(Sybren): add the below CLI argument to the test when the usd_stage_creation_test.cc
+# test is reenabled.
+# --test-usd-datafiles-dir "${_usd_DATAFILES_DIR}"
+unset(_usd_DATAFILES_DIR)
+
+setup_liblinks(usd_test)
diff --git a/tests/gtests/usd/abstract_hierarchy_iterator_test.cc b/tests/gtests/usd/abstract_hierarchy_iterator_test.cc
new file mode 100644
index 00000000000..e87ef547052
--- /dev/null
+++ b/tests/gtests/usd/abstract_hierarchy_iterator_test.cc
@@ -0,0 +1,202 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "blenloader/blendfile_loading_base_test.h"
+#include "intern/abstract_hierarchy_iterator.h"
+
+extern "C" {
+#include "BLI_math.h"
+#include "DEG_depsgraph.h"
+#include "DNA_object_types.h"
+}
+
+#include <map>
+#include <set>
+
+/* Mapping from ID.name to set of export hierarchy path. Duplicated objects can be exported
+ * multiple times, hence the set. */
+typedef std::map<std::string, std::set<std::string>> created_writers;
+
+using namespace USD;
+
+class TestHierarchyWriter : public AbstractHierarchyWriter {
+ public:
+ created_writers &writers_map;
+
+ TestHierarchyWriter(created_writers &writers_map) : writers_map(writers_map)
+ {
+ }
+
+ void write(HierarchyContext &context) override
+ {
+ const char *id_name = context.object->id.name;
+ created_writers::mapped_type &writers = writers_map[id_name];
+
+ BLI_assert(writers.find(context.export_path) == writers.end());
+ writers.insert(context.export_path);
+ }
+};
+
+void debug_print_writers(const char *label, const created_writers &writers_map)
+{
+ printf("%s:\n", label);
+ for (auto idname_writers : writers_map) {
+ printf(" %s:\n", idname_writers.first.c_str());
+ for (const std::string &export_path : idname_writers.second) {
+ printf(" - %s\n", export_path.c_str());
+ }
+ }
+}
+
+class TestingHierarchyIterator : public AbstractHierarchyIterator {
+ public: /* Public so that the test cases can directly inspect the created writers. */
+ created_writers transform_writers;
+ created_writers data_writers;
+ created_writers hair_writers;
+ created_writers particle_writers;
+
+ public:
+ explicit TestingHierarchyIterator(Depsgraph *depsgraph) : AbstractHierarchyIterator(depsgraph)
+ {
+ }
+ virtual ~TestingHierarchyIterator()
+ {
+ }
+
+ protected:
+ AbstractHierarchyWriter *create_transform_writer(const HierarchyContext *context) override
+ {
+ return new TestHierarchyWriter(transform_writers);
+ }
+ AbstractHierarchyWriter *create_data_writer(const HierarchyContext *context) override
+ {
+ return new TestHierarchyWriter(data_writers);
+ }
+ AbstractHierarchyWriter *create_hair_writer(const HierarchyContext *context) override
+ {
+ return new TestHierarchyWriter(hair_writers);
+ }
+ AbstractHierarchyWriter *create_particle_writer(const HierarchyContext *context) override
+ {
+ return new TestHierarchyWriter(particle_writers);
+ }
+
+ void delete_object_writer(AbstractHierarchyWriter *writer) override
+ {
+ delete writer;
+ }
+};
+
+class USDHierarchyIteratorTest : public BlendfileLoadingBaseTest {
+ protected:
+ TestingHierarchyIterator *iterator;
+
+ virtual void SetUp()
+ {
+ BlendfileLoadingBaseTest::SetUp();
+ iterator = nullptr;
+ }
+
+ virtual void TearDown()
+ {
+ iterator_free();
+ BlendfileLoadingBaseTest::TearDown();
+ }
+
+ /* Create a test iterator. */
+ void iterator_create()
+ {
+ iterator = new TestingHierarchyIterator(depsgraph);
+ }
+ /* Free the test iterator if it is not nullptr. */
+ void iterator_free()
+ {
+ if (iterator == nullptr) {
+ return;
+ }
+ delete iterator;
+ iterator = nullptr;
+ }
+};
+
+TEST_F(USDHierarchyIteratorTest, ExportHierarchyTest)
+{
+ /* Load the test blend file. */
+ if (!blendfile_load("usd/usd_hierarchy_export_test.blend")) {
+ return;
+ }
+ depsgraph_create(DAG_EVAL_RENDER);
+ iterator_create();
+
+ iterator->iterate_and_write();
+
+ // Mapping from object name to set of export paths.
+ created_writers expected_transforms = {
+ {"OBCamera", {"/Camera"}},
+ {"OBDupli1", {"/Dupli1"}},
+ {"OBDupli2", {"/ParentOfDupli2/Dupli2"}},
+ {"OBGEO_Ear_L",
+ {"/Dupli1/GEO_Head-0/GEO_Ear_L-1",
+ "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_L",
+ "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_L-1"}},
+ {"OBGEO_Ear_R",
+ {"/Dupli1/GEO_Head-0/GEO_Ear_R-2",
+ "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_R",
+ "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_R-2"}},
+ {"OBGEO_Head",
+ {"/Dupli1/GEO_Head-0",
+ "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head",
+ "/ParentOfDupli2/Dupli2/GEO_Head-0"}},
+ {"OBGEO_Nose",
+ {"/Dupli1/GEO_Head-0/GEO_Nose-3",
+ "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Nose",
+ "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Nose-3"}},
+ {"OBGround plane", {"/Ground plane"}},
+ {"OBOutsideDupliGrandParent", {"/Ground plane/OutsideDupliGrandParent"}},
+ {"OBOutsideDupliParent", {"/Ground plane/OutsideDupliGrandParent/OutsideDupliParent"}},
+ {"OBParentOfDupli2", {"/ParentOfDupli2"}}};
+ EXPECT_EQ(expected_transforms, iterator->transform_writers);
+
+ created_writers expected_data = {
+ {"OBCamera", {"/Camera/Camera"}},
+ {"OBGEO_Ear_L",
+ {"/Dupli1/GEO_Head-0/GEO_Ear_L-1/Ear",
+ "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_L/Ear",
+ "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_L-1/Ear"}},
+ {"OBGEO_Ear_R",
+ {"/Dupli1/GEO_Head-0/GEO_Ear_R-2/Ear",
+ "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_R/Ear",
+ "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_R-2/Ear"}},
+ {"OBGEO_Head",
+ {"/Dupli1/GEO_Head-0/Face",
+ "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/Face",
+ "/ParentOfDupli2/Dupli2/GEO_Head-0/Face"}},
+ {"OBGEO_Nose",
+ {"/Dupli1/GEO_Head-0/GEO_Nose-3/Nose",
+ "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Nose/Nose",
+ "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Nose-3/Nose"}},
+ {"OBGround plane", {"/Ground plane/Plane"}},
+ {"OBParentOfDupli2", {"/ParentOfDupli2/Icosphere"}},
+ };
+
+ EXPECT_EQ(expected_data, iterator->data_writers);
+
+ // The scene has no hair or particle systems.
+ EXPECT_EQ(0, iterator->hair_writers.size());
+ EXPECT_EQ(0, iterator->particle_writers.size());
+}
diff --git a/tests/gtests/usd/hierarchy_context_order_test.cc b/tests/gtests/usd/hierarchy_context_order_test.cc
new file mode 100644
index 00000000000..ce3b43484e7
--- /dev/null
+++ b/tests/gtests/usd/hierarchy_context_order_test.cc
@@ -0,0 +1,123 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "intern/abstract_hierarchy_iterator.h"
+
+#include "testing/testing.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+}
+
+using namespace USD;
+
+class HierarchyContextOrderTest : public testing::Test {
+};
+
+static Object *fake_pointer(int value)
+{
+ return static_cast<Object *>(POINTER_FROM_INT(value));
+}
+
+TEST_F(HierarchyContextOrderTest, ObjectPointerTest)
+{
+ HierarchyContext ctx_a;
+ ctx_a.object = fake_pointer(1);
+ ctx_a.duplicator = nullptr;
+
+ HierarchyContext ctx_b;
+ ctx_b.object = fake_pointer(2);
+ ctx_b.duplicator = nullptr;
+
+ EXPECT_EQ(true, ctx_a < ctx_b);
+ EXPECT_EQ(false, ctx_b < ctx_a);
+ EXPECT_EQ(false, ctx_a < ctx_a);
+}
+
+TEST_F(HierarchyContextOrderTest, DuplicatorPointerTest)
+{
+ HierarchyContext ctx_a;
+ ctx_a.object = fake_pointer(1);
+ ctx_a.duplicator = fake_pointer(1);
+ ctx_a.export_name = "A";
+
+ HierarchyContext ctx_b;
+ ctx_b.object = fake_pointer(1);
+ ctx_b.duplicator = fake_pointer(1);
+ ctx_b.export_name = "B";
+
+ EXPECT_EQ(true, ctx_a < ctx_b);
+ EXPECT_EQ(false, ctx_b < ctx_a);
+ EXPECT_EQ(false, ctx_a < ctx_a);
+}
+
+TEST_F(HierarchyContextOrderTest, ExportParentTest)
+{
+ HierarchyContext ctx_a;
+ ctx_a.object = fake_pointer(1);
+ ctx_a.export_parent = fake_pointer(1);
+
+ HierarchyContext ctx_b;
+ ctx_b.object = fake_pointer(1);
+ ctx_b.export_parent = fake_pointer(2);
+
+ EXPECT_EQ(true, ctx_a < ctx_b);
+ EXPECT_EQ(false, ctx_b < ctx_a);
+ EXPECT_EQ(false, ctx_a < ctx_a);
+}
+
+TEST_F(HierarchyContextOrderTest, TransitiveTest)
+{
+ HierarchyContext ctx_a;
+ ctx_a.object = fake_pointer(1);
+ ctx_a.export_parent = fake_pointer(1);
+ ctx_a.duplicator = nullptr;
+ ctx_a.export_name = "A";
+
+ HierarchyContext ctx_b;
+ ctx_b.object = fake_pointer(2);
+ ctx_b.export_parent = nullptr;
+ ctx_b.duplicator = fake_pointer(1);
+ ctx_b.export_name = "B";
+
+ HierarchyContext ctx_c;
+ ctx_c.object = fake_pointer(2);
+ ctx_c.export_parent = fake_pointer(2);
+ ctx_c.duplicator = fake_pointer(1);
+ ctx_c.export_name = "C";
+
+ HierarchyContext ctx_d;
+ ctx_d.object = fake_pointer(2);
+ ctx_d.export_parent = fake_pointer(3);
+ ctx_d.duplicator = nullptr;
+ ctx_d.export_name = "D";
+
+ EXPECT_EQ(true, ctx_a < ctx_b);
+ EXPECT_EQ(true, ctx_a < ctx_c);
+ EXPECT_EQ(true, ctx_a < ctx_d);
+ EXPECT_EQ(true, ctx_b < ctx_c);
+ EXPECT_EQ(true, ctx_b < ctx_d);
+ EXPECT_EQ(true, ctx_c < ctx_d);
+
+ EXPECT_EQ(false, ctx_b < ctx_a);
+ EXPECT_EQ(false, ctx_c < ctx_a);
+ EXPECT_EQ(false, ctx_d < ctx_a);
+ EXPECT_EQ(false, ctx_c < ctx_b);
+ EXPECT_EQ(false, ctx_d < ctx_b);
+ EXPECT_EQ(false, ctx_d < ctx_c);
+}
diff --git a/tests/gtests/usd/usd_stage_creation_test.cc b/tests/gtests/usd/usd_stage_creation_test.cc
new file mode 100644
index 00000000000..b262e21f053
--- /dev/null
+++ b/tests/gtests/usd/usd_stage_creation_test.cc
@@ -0,0 +1,62 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "testing/testing.h"
+#include <pxr/usd/usd/stage.h>
+
+#include <string>
+
+extern "C" {
+#include "BLI_path_util.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_appdir.h"
+
+/* Workaround to make it possible to pass a path at runtime to USD. See creator.c. */
+void usd_initialise_plugin_path(const char *datafiles_usd_path);
+}
+
+DEFINE_string(test_usd_datafiles_dir, "", "The bin/{BLENDER_VERSION}/datafiles/usd directory.");
+
+class USDStageCreationTest : public testing::Test {
+};
+
+TEST_F(USDStageCreationTest, JSONFileLoadingTest)
+{
+ if (FLAGS_test_usd_datafiles_dir.empty()) {
+ FAIL() << "Pass the --test-usd-datafiles-dir flag";
+ }
+
+ usd_initialise_plugin_path(FLAGS_test_usd_datafiles_dir.c_str());
+
+ /* Simply the ability to create a USD Stage for a specific filename means that the extension
+ * has been recognised by the USD library, and that a USD plugin has been loaded to write such
+ * files. Practically, this is a test to see whether the USD JSON files can be found and
+ * loaded. */
+ std::string filename = "usd-stage-creation-test.usdc";
+ pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(filename);
+ if (usd_stage != nullptr) {
+ /* Even though we don't call usd_stage->SaveFile(), a file is still created on the filesystem
+ * when we call CreateNew(). It's immediately closed, though, so we can safely call unlink()
+ * here. */
+ unlink(filename.c_str());
+ }
+ else {
+ FAIL() << "unable to find suitable USD plugin to write " << filename;
+ }
+}
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 3036be71564..7241c26dfec 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -114,6 +114,14 @@ add_blender_test(
)
# ------------------------------------------------------------------------------
+# DATA MANAGEMENT TESTS
+
+add_blender_test(
+ id_management
+ --python ${CMAKE_CURRENT_LIST_DIR}/bl_id_management.py
+)
+
+# ------------------------------------------------------------------------------
# MODELING TESTS
add_blender_test(
bmesh_bevel
diff --git a/tests/python/alembic_tests.py b/tests/python/alembic_tests.py
index 09e9b8981e3..9de1bc06d84 100755
--- a/tests/python/alembic_tests.py
+++ b/tests/python/alembic_tests.py
@@ -170,7 +170,7 @@ class HierarchicalAndFlatExportTest(AbstractAlembicTest):
def test_hierarchical_export(self, tempdir: pathlib.Path):
abc = tempdir / 'cubes_hierarchical.abc'
script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \
- "renderable_only=True, visible_layers_only=True, flatten=False)" % abc.as_posix()
+ "renderable_only=True, visible_objects_only=True, flatten=False)" % abc.as_posix()
self.run_blender('cubes-hierarchy.blend', script)
# Now check the resulting Alembic file.
@@ -188,7 +188,7 @@ class HierarchicalAndFlatExportTest(AbstractAlembicTest):
def test_flat_export(self, tempdir: pathlib.Path):
abc = tempdir / 'cubes_flat.abc'
script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \
- "renderable_only=True, visible_layers_only=True, flatten=True)" % abc.as_posix()
+ "renderable_only=True, visible_objects_only=True, flatten=True)" % abc.as_posix()
self.run_blender('cubes-hierarchy.blend', script)
# Now check the resulting Alembic file.
@@ -209,7 +209,7 @@ class DupliGroupExportTest(AbstractAlembicTest):
def test_hierarchical_export(self, tempdir: pathlib.Path):
abc = tempdir / 'dupligroup_hierarchical.abc'
script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \
- "renderable_only=True, visible_layers_only=True, flatten=False)" % abc.as_posix()
+ "renderable_only=True, visible_objects_only=True, flatten=False)" % abc.as_posix()
self.run_blender('dupligroup-scene.blend', script)
# Now check the resulting Alembic file.
@@ -227,7 +227,7 @@ class DupliGroupExportTest(AbstractAlembicTest):
def test_flat_export(self, tempdir: pathlib.Path):
abc = tempdir / 'dupligroup_hierarchical.abc'
script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \
- "renderable_only=True, visible_layers_only=True, flatten=True)" % abc.as_posix()
+ "renderable_only=True, visible_objects_only=True, flatten=True)" % abc.as_posix()
self.run_blender('dupligroup-scene.blend', script)
# Now check the resulting Alembic file.
@@ -248,7 +248,7 @@ class CurveExportTest(AbstractAlembicTest):
def test_export_single_curve(self, tempdir: pathlib.Path):
abc = tempdir / 'single-curve.abc'
script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \
- "renderable_only=True, visible_layers_only=True, flatten=False)" % abc.as_posix()
+ "renderable_only=True, visible_objects_only=True, flatten=False)" % abc.as_posix()
self.run_blender('single-curve.blend', script)
# Now check the resulting Alembic file.
@@ -269,7 +269,7 @@ class HairParticlesExportTest(AbstractAlembicTest):
def _do_test(self, tempdir: pathlib.Path, export_hair: bool, export_particles: bool) -> pathlib.Path:
abc = tempdir / 'hair-particles.abc'
script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \
- "renderable_only=True, visible_layers_only=True, flatten=False, " \
+ "renderable_only=True, visible_objects_only=True, flatten=False, " \
"export_hair=%r, export_particles=%r, as_background_job=False)" \
% (abc.as_posix(), export_hair, export_particles)
self.run_blender('hair-particles.blend', script)
@@ -330,7 +330,7 @@ class LongNamesExportTest(AbstractAlembicTest):
def test_export_long_names(self, tempdir: pathlib.Path):
abc = tempdir / 'long-names.abc'
script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \
- "renderable_only=False, visible_layers_only=False, flatten=False)" % abc.as_posix()
+ "renderable_only=False, visible_objects_only=False, flatten=False)" % abc.as_posix()
self.run_blender('long-names.blend', script)
name_parts = [
diff --git a/tests/python/bl_id_management.py b/tests/python/bl_id_management.py
new file mode 100644
index 00000000000..938a1cab134
--- /dev/null
+++ b/tests/python/bl_id_management.py
@@ -0,0 +1,184 @@
+# Apache License, Version 2.0
+
+# ./blender.bin --background -noaudio --python tests/python/bl_id_management.py -- --verbose
+import bpy
+import unittest
+import random
+
+
+class TestHelper:
+
+ @property
+ def data_container(self):
+ return getattr(bpy.data, self.data_container_id)
+
+ def clear_container(self):
+ bpy.data.batch_remove(self.data_container)
+
+ def add_to_container(self, name=""):
+ return self.data_container.new(name)
+
+ def remove_from_container(self, data=None, name=None, index=None):
+ data_container = self.data_container
+ if not data:
+ if name:
+ data = data_container[name]
+ elif index:
+ data = data_container[index]
+ self.assertTrue(data is not None)
+ data_container.remove(data)
+
+ def add_items_with_randomized_names(self, number_items=1, name_prefix=None, name_suffix=""):
+ if name_prefix is None:
+ name_prefix = self.default_name
+ for i in range(number_items):
+ self.add_to_container(name=name_prefix + str(random.random())[2:5] + name_suffix)
+
+ def ensure_proper_order(self):
+ id_prev = None
+ for id in self.data_container:
+ if id_prev:
+ self.assertTrue(id_prev.name < id.name or id.library)
+ id_prev = id
+
+
+class TestIdAddNameManagement(TestHelper, unittest.TestCase):
+ data_container_id = 'meshes'
+ default_name = "Mesh"
+
+ def test_add_remove_single(self):
+ self.clear_container()
+ self.assertEqual(len(self.data_container), 0)
+ data = self.add_to_container()
+ self.assertEqual(len(self.data_container), 1)
+ self.ensure_proper_order()
+ self.remove_from_container(data=data)
+ self.assertEqual(len(self.data_container), 0)
+
+ def test_add_head_tail(self):
+ self.clear_container()
+ self.add_items_with_randomized_names(10)
+ self.assertEqual(len(self.data_container), 10)
+ self.ensure_proper_order()
+
+ name_head = "AAA" + self.default_name
+ data = self.add_to_container(name=name_head)
+ self.assertEqual(len(self.data_container), 11)
+ self.assertEqual(self.data_container[0].name, name_head)
+ self.ensure_proper_order()
+
+ name_tail = "ZZZ" + self.default_name
+ data = self.add_to_container(name=name_tail)
+ self.assertEqual(len(self.data_container), 12)
+ self.assertEqual(self.data_container[-1].name, name_tail)
+ self.ensure_proper_order()
+
+ def test_add_long_names(self):
+ self.clear_container()
+ self.add_items_with_randomized_names(10)
+ self.assertEqual(len(self.data_container), 10)
+ self.ensure_proper_order()
+
+ for i in range(12000):
+ self.add_to_container(name="ABCDEFGHIJKLMNOPQRSTUVWXYZ" * 3)
+ self.assertEqual(len(self.data_container), 12010)
+ self.ensure_proper_order()
+
+ self.clear_container()
+ self.add_items_with_randomized_names(100, name_prefix="", name_suffix="ABCDEFGHIJKLMNOPQRSTUVWXYZ" * 3)
+ self.assertEqual(len(self.data_container), 100)
+ self.ensure_proper_order()
+
+ def test_add_invalid_number_suffixes(self):
+ self.clear_container()
+
+ name = "%s.%.3d" % (self.default_name, 1000000000)
+ data = self.add_to_container(name=name)
+ self.assertEqual(data.name, name)
+
+ data = self.add_to_container(name=name)
+ self.assertEqual(data.name, self.default_name + ".001")
+
+ data = self.add_to_container(name=name)
+ self.assertEqual(data.name, self.default_name + ".002")
+
+ data = self.add_to_container(name=self.default_name)
+ self.assertEqual(data.name, self.default_name)
+
+ data = self.add_to_container(name="%s.%.3d" % (self.default_name, 0))
+ self.assertEqual(data.name, self.default_name + ".000")
+
+ data = self.add_to_container(name="%s.%.3d" % (self.default_name, 0))
+ self.assertEqual(data.name, self.default_name + ".003")
+
+ self.assertEqual(len(self.data_container), 6)
+ self.ensure_proper_order()
+
+ def test_add_use_smallest_free_number(self):
+ self.clear_container()
+
+ data = self.add_to_container(name="%s.%.3d" % (self.default_name, 2))
+ self.assertEqual(data.name, self.default_name + ".002")
+
+ data = self.add_to_container(name="%s.%.3d" % (self.default_name, 2))
+ self.assertEqual(data.name, self.default_name + ".001")
+
+ data = self.add_to_container(name="%s.%.3d" % (self.default_name, 2))
+ self.assertEqual(data.name, self.default_name + ".003")
+
+ for i in range(5, 1111):
+ name = "%s.%.3d" % (self.default_name, i)
+ data = self.add_to_container(name=name)
+ self.assertEqual(data.name, name)
+
+ for i in range(1112, 1200):
+ name = "%s.%.3d" % (self.default_name, i)
+ data = self.add_to_container(name=name)
+ self.assertEqual(data.name, name)
+
+ # Only slot available below 1024: 004.
+ data = self.add_to_container(name="%s.%.3d" % (self.default_name, 2))
+ self.assertEqual(data.name, self.default_name + ".004")
+
+ # Slot available at 1111 is not 'found' and we get first highest free number, 1200.
+ data = self.add_to_container(name="%s.%.3d" % (self.default_name, 2))
+ self.assertEqual(data.name, self.default_name + ".1200")
+
+ self.assertEqual(len(self.data_container), 1199)
+ self.ensure_proper_order()
+
+
+class TestIdRename(TestHelper, unittest.TestCase):
+ data_container_id = 'meshes'
+ default_name = "Mesh"
+
+ def test_rename(self):
+ self.clear_container()
+ self.add_items_with_randomized_names(100)
+ self.ensure_proper_order()
+
+ data = self.data_container[0]
+ data.name = "ZZZ" + data.name
+ self.assertEqual(self.data_container[-1], data)
+ self.ensure_proper_order()
+ data.name = "AAA" + data.name
+ self.assertEqual(self.data_container[0], data)
+ self.ensure_proper_order()
+
+ name = "%s.%.3d" % (self.default_name, 1000000000)
+ data.name = name
+ self.assertEqual(data.name, name)
+ for dt in self.data_container:
+ if dt is not data:
+ data = dt
+ break
+ data.name = name
+ # This can fail currently, see T71244.
+ # ~ self.assertEqual(data.name, self.default_name + ".001")
+ self.ensure_proper_order()
+
+
+if __name__ == '__main__':
+ import sys
+ sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
+ unittest.main()